aboutsummaryrefslogtreecommitdiffstats
path: root/mediagoblin
diff options
context:
space:
mode:
Diffstat (limited to 'mediagoblin')
-rw-r--r--mediagoblin/_version.py2
-rw-r--r--mediagoblin/app.py48
-rw-r--r--mediagoblin/auth/__init__.py29
-rw-r--r--mediagoblin/auth/forms.py60
-rw-r--r--mediagoblin/auth/tools.py210
-rw-r--r--mediagoblin/auth/views.py208
-rw-r--r--mediagoblin/config_spec.ini33
-rw-r--r--mediagoblin/db/base.py12
-rw-r--r--mediagoblin/db/migration_tools.py3
-rw-r--r--mediagoblin/db/migrations.py132
-rw-r--r--mediagoblin/db/mixin.py144
-rw-r--r--mediagoblin/db/models.py145
-rw-r--r--mediagoblin/db/models_v0.py23
-rw-r--r--mediagoblin/db/open.py20
-rw-r--r--mediagoblin/db/util.py4
-rw-r--r--mediagoblin/decorators.py57
-rw-r--r--mediagoblin/edit/forms.py38
-rw-r--r--mediagoblin/edit/routing.py4
-rw-r--r--mediagoblin/edit/views.py215
-rw-r--r--mediagoblin/gmg_commands/__init__.py14
-rw-r--r--mediagoblin/gmg_commands/assetlink.py151
-rw-r--r--mediagoblin/gmg_commands/dbupdate.py30
-rw-r--r--mediagoblin/gmg_commands/import_export.py4
-rw-r--r--mediagoblin/gmg_commands/theme.py122
-rw-r--r--mediagoblin/gmg_commands/users.py18
-rw-r--r--mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.mobin24638 -> 28177 bytes
-rw-r--r--mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.po700
-rw-r--r--mediagoblin/i18n/ca/LC_MESSAGES/mediagoblin.mobin24163 -> 25199 bytes
-rw-r--r--mediagoblin/i18n/ca/LC_MESSAGES/mediagoblin.po417
-rw-r--r--mediagoblin/i18n/da/LC_MESSAGES/mediagoblin.mobin23311 -> 24330 bytes
-rw-r--r--mediagoblin/i18n/da/LC_MESSAGES/mediagoblin.po413
-rw-r--r--mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mobin24819 -> 25811 bytes
-rw-r--r--mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po441
-rw-r--r--mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po417
-rw-r--r--mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mobin24144 -> 25211 bytes
-rw-r--r--mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po421
-rw-r--r--mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mobin24884 -> 25994 bytes
-rw-r--r--mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po437
-rw-r--r--mediagoblin/i18n/fa/LC_MESSAGES/mediagoblin.mobin24126 -> 25146 bytes
-rw-r--r--mediagoblin/i18n/fa/LC_MESSAGES/mediagoblin.po409
-rw-r--r--mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mobin25195 -> 26152 bytes
-rw-r--r--mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po429
-rw-r--r--mediagoblin/i18n/he/LC_MESSAGES/mediagoblin.mobin25897 -> 27529 bytes
-rw-r--r--mediagoblin/i18n/he/LC_MESSAGES/mediagoblin.po476
-rw-r--r--mediagoblin/i18n/ia/LC_MESSAGES/mediagoblin.mobin23302 -> 24326 bytes
-rw-r--r--mediagoblin/i18n/ia/LC_MESSAGES/mediagoblin.po411
-rw-r--r--mediagoblin/i18n/is_IS/LC_MESSAGES/mediagoblin.mobin25008 -> 26342 bytes
-rw-r--r--mediagoblin/i18n/is_IS/LC_MESSAGES/mediagoblin.po468
-rw-r--r--mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.mobin24263 -> 25279 bytes
-rw-r--r--mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.po422
-rw-r--r--mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.mobin23923 -> 24944 bytes
-rw-r--r--mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po411
-rw-r--r--mediagoblin/i18n/ko_KR/LC_MESSAGES/mediagoblin.mobin25185 -> 26202 bytes
-rw-r--r--mediagoblin/i18n/ko_KR/LC_MESSAGES/mediagoblin.po413
-rw-r--r--mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.mobin23774 -> 24753 bytes
-rw-r--r--mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po415
-rw-r--r--mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.mobin22783 -> 23771 bytes
-rw-r--r--mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po413
-rw-r--r--mediagoblin/i18n/pl/LC_MESSAGES/mediagoblin.mobin24051 -> 25584 bytes
-rw-r--r--mediagoblin/i18n/pl/LC_MESSAGES/mediagoblin.po506
-rw-r--r--mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.mobin24133 -> 25166 bytes
-rw-r--r--mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po434
-rw-r--r--mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mobin24857 -> 25911 bytes
-rw-r--r--mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po413
-rw-r--r--mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mobin31085 -> 32200 bytes
-rw-r--r--mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po415
-rw-r--r--mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.mobin24563 -> 25686 bytes
-rw-r--r--mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.po427
-rw-r--r--mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.mobin23482 -> 24504 bytes
-rw-r--r--mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po409
-rw-r--r--mediagoblin/i18n/sq/LC_MESSAGES/mediagoblin.mobin24623 -> 25789 bytes
-rw-r--r--mediagoblin/i18n/sq/LC_MESSAGES/mediagoblin.po471
-rw-r--r--mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.mobin23398 -> 24362 bytes
-rw-r--r--mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po401
-rw-r--r--mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.mobin23628 -> 24592 bytes
-rw-r--r--mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po409
-rw-r--r--mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.mobin23544 -> 24563 bytes
-rw-r--r--mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.po409
-rw-r--r--mediagoblin/i18n/tr_TR/LC_MESSAGES/mediagoblin.mobin0 -> 24771 bytes
-rw-r--r--mediagoblin/i18n/tr_TR/LC_MESSAGES/mediagoblin.po1252
-rw-r--r--mediagoblin/i18n/zh_CN/LC_MESSAGES/mediagoblin.mobin0 -> 23615 bytes
-rw-r--r--mediagoblin/i18n/zh_CN/LC_MESSAGES/mediagoblin.po1256
-rw-r--r--mediagoblin/i18n/zh_TW.Big5/LC_MESSAGES/mediagoblin.mobin23342 -> 24306 bytes
-rw-r--r--mediagoblin/i18n/zh_TW.Big5/LC_MESSAGES/mediagoblin.po401
-rw-r--r--mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.mobin22667 -> 23703 bytes
-rw-r--r--mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po493
-rw-r--r--mediagoblin/init/__init__.py36
-rw-r--r--mediagoblin/init/celery/__init__.py23
-rw-r--r--mediagoblin/init/celery/from_celery.py6
-rw-r--r--mediagoblin/init/config.py42
-rw-r--r--mediagoblin/init/plugins/__init__.py4
-rw-r--r--mediagoblin/listings/views.py17
-rw-r--r--mediagoblin/meddleware/csrf.py2
-rw-r--r--mediagoblin/media_types/__init__.py64
-rw-r--r--mediagoblin/media_types/ascii/__init__.py36
-rw-r--r--mediagoblin/media_types/ascii/asciitoimage.py11
-rw-r--r--mediagoblin/media_types/ascii/processing.py21
-rw-r--r--mediagoblin/media_types/audio/__init__.py33
-rw-r--r--mediagoblin/media_types/audio/processing.py17
-rw-r--r--mediagoblin/media_types/audio/spectrogram.py5
-rw-r--r--mediagoblin/media_types/audio/transcoders.py5
-rw-r--r--mediagoblin/media_types/image/__init__.py60
-rw-r--r--mediagoblin/media_types/image/processing.py106
-rw-r--r--mediagoblin/media_types/pdf/__init__.py47
-rw-r--r--mediagoblin/media_types/pdf/migrations.py17
-rw-r--r--mediagoblin/media_types/pdf/models.py58
-rw-r--r--mediagoblin/media_types/pdf/processing.py280
-rw-r--r--mediagoblin/media_types/stl/__init__.py33
-rw-r--r--mediagoblin/media_types/stl/model_loader.py3
-rw-r--r--mediagoblin/media_types/stl/processing.py18
-rw-r--r--mediagoblin/media_types/tools.py27
-rw-r--r--mediagoblin/media_types/video/__init__.py39
-rw-r--r--mediagoblin/media_types/video/models.py2
-rw-r--r--mediagoblin/media_types/video/processing.py13
-rw-r--r--mediagoblin/media_types/video/transcoders.py359
-rw-r--r--mediagoblin/messages.py14
-rw-r--r--mediagoblin/mg_globals.py3
-rw-r--r--mediagoblin/notifications/__init__.py141
-rw-r--r--mediagoblin/notifications/routing.py25
-rw-r--r--mediagoblin/notifications/task.py46
-rw-r--r--mediagoblin/notifications/tools.py55
-rw-r--r--mediagoblin/notifications/views.py54
-rw-r--r--mediagoblin/plugins/api/__init__.py4
-rw-r--r--mediagoblin/plugins/api/views.py12
-rw-r--r--mediagoblin/plugins/basic_auth/__init__.py88
-rw-r--r--mediagoblin/plugins/basic_auth/forms.py46
-rw-r--r--mediagoblin/plugins/basic_auth/tools.py (renamed from mediagoblin/auth/lib.py)73
-rw-r--r--mediagoblin/plugins/httpapiauth/__init__.py10
-rw-r--r--mediagoblin/plugins/oauth/__init__.py2
-rw-r--r--mediagoblin/plugins/oauth/forms.py2
-rw-r--r--mediagoblin/plugins/oauth/migrations.py34
-rw-r--r--mediagoblin/plugins/oauth/models.py87
-rw-r--r--mediagoblin/plugins/oauth/tools.py73
-rw-r--r--mediagoblin/plugins/oauth/views.py158
-rw-r--r--mediagoblin/plugins/openid/__init__.py123
-rw-r--r--mediagoblin/plugins/openid/forms.py41
-rw-r--r--mediagoblin/plugins/openid/models.py65
-rw-r--r--mediagoblin/plugins/openid/store.py127
-rw-r--r--mediagoblin/plugins/openid/templates/mediagoblin/plugins/openid/add.html44
-rw-r--r--mediagoblin/plugins/openid/templates/mediagoblin/plugins/openid/delete.html43
-rw-r--r--mediagoblin/plugins/openid/templates/mediagoblin/plugins/openid/edit_link.html25
-rw-r--r--mediagoblin/plugins/openid/templates/mediagoblin/plugins/openid/login.html65
-rw-r--r--mediagoblin/plugins/openid/templates/mediagoblin/plugins/openid/login_link.html25
-rw-r--r--mediagoblin/plugins/openid/templates/mediagoblin/plugins/openid/register_link.html27
-rw-r--r--mediagoblin/plugins/openid/templates/mediagoblin/plugins/openid/request_form.html24
-rw-r--r--mediagoblin/plugins/openid/views.py404
-rw-r--r--mediagoblin/plugins/piwigo/README.rst23
-rw-r--r--mediagoblin/plugins/piwigo/__init__.py42
-rw-r--r--mediagoblin/plugins/piwigo/forms.py44
-rw-r--r--mediagoblin/plugins/piwigo/tools.py165
-rw-r--r--mediagoblin/plugins/piwigo/views.py249
-rw-r--r--mediagoblin/plugins/raven/README.rst2
-rw-r--r--mediagoblin/processing/__init__.py27
-rw-r--r--mediagoblin/processing/task.py2
-rw-r--r--mediagoblin/routing.py1
-rw-r--r--mediagoblin/static/css/base.css98
l---------mediagoblin/static/extlib/pdf.js1
-rw-r--r--mediagoblin/static/js/notifications.js36
-rw-r--r--mediagoblin/storage/__init__.py16
-rw-r--r--mediagoblin/storage/cloudfiles.py2
-rw-r--r--mediagoblin/storage/filestorage.py26
-rw-r--r--mediagoblin/submit/forms.py2
-rw-r--r--mediagoblin/submit/lib.py24
-rw-r--r--mediagoblin/submit/views.py78
-rw-r--r--mediagoblin/templates/mediagoblin/admin/panel.html2
-rw-r--r--mediagoblin/templates/mediagoblin/auth/change_fp.html3
-rw-r--r--mediagoblin/templates/mediagoblin/auth/forgot_password.html2
-rw-r--r--mediagoblin/templates/mediagoblin/auth/login.html18
-rw-r--r--mediagoblin/templates/mediagoblin/auth/register.html7
-rw-r--r--mediagoblin/templates/mediagoblin/base.html33
-rw-r--r--mediagoblin/templates/mediagoblin/bits/above_content.html (renamed from mediagoblin/templates/mediagoblin/bits/above-content.html)0
-rw-r--r--mediagoblin/templates/mediagoblin/bits/base_footer.html28
-rw-r--r--mediagoblin/templates/mediagoblin/bits/body_end.html (renamed from mediagoblin/templates/mediagoblin/bits/body-end.html)0
-rw-r--r--mediagoblin/templates/mediagoblin/bits/body_start.html (renamed from mediagoblin/templates/mediagoblin/bits/body-start.html)0
-rw-r--r--mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html41
-rw-r--r--mediagoblin/templates/mediagoblin/edit/change_pass.html52
-rw-r--r--mediagoblin/templates/mediagoblin/edit/edit_account.html20
-rw-r--r--mediagoblin/templates/mediagoblin/edit/verification.txt29
-rw-r--r--mediagoblin/templates/mediagoblin/fragments/header_notifications.html40
-rw-r--r--mediagoblin/templates/mediagoblin/media_displays/image.html17
-rw-r--r--mediagoblin/templates/mediagoblin/media_displays/pdf.html86
-rw-r--r--mediagoblin/templates/mediagoblin/media_displays/stl.html16
-rw-r--r--mediagoblin/templates/mediagoblin/root.html19
-rw-r--r--mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html7
-rw-r--r--mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html7
-rw-r--r--mediagoblin/templates/mediagoblin/user_pages/collection_list.html12
-rw-r--r--mediagoblin/templates/mediagoblin/user_pages/media.html55
-rw-r--r--mediagoblin/templates/mediagoblin/utils/comment-subscription.html34
-rw-r--r--mediagoblin/templates/mediagoblin/utils/exif.html39
-rw-r--r--mediagoblin/templates/mediagoblin/utils/wtforms.html62
-rw-r--r--mediagoblin/tests/__init__.py14
-rw-r--r--mediagoblin/tests/appconfig_context_modified.ini27
-rw-r--r--mediagoblin/tests/appconfig_plugin_specs.ini21
-rw-r--r--mediagoblin/tests/appconfig_static_plugin.ini27
-rw-r--r--mediagoblin/tests/auth_configs/__init__.py0
-rw-r--r--mediagoblin/tests/auth_configs/authentication_disabled_appconfig.ini25
-rw-r--r--mediagoblin/tests/auth_configs/openid_appconfig.ini41
-rw-r--r--mediagoblin/tests/conftest.py41
-rw-r--r--mediagoblin/tests/pytest.ini2
-rw-r--r--mediagoblin/tests/resources.py41
-rw-r--r--mediagoblin/tests/test_api.py42
-rw-r--r--mediagoblin/tests/test_auth.py193
-rw-r--r--mediagoblin/tests/test_basic_auth.py59
-rw-r--r--mediagoblin/tests/test_cache.py52
-rw-r--r--mediagoblin/tests/test_celery_setup.py2
-rw-r--r--mediagoblin/tests/test_collections.py11
-rw-r--r--mediagoblin/tests/test_csrf_middleware.py20
-rw-r--r--mediagoblin/tests/test_edit.py147
-rw-r--r--mediagoblin/tests/test_exif.py404
-rw-r--r--mediagoblin/tests/test_globals.py10
-rw-r--r--mediagoblin/tests/test_http_callback.py18
-rw-r--r--mediagoblin/tests/test_messages.py21
-rw-r--r--mediagoblin/tests/test_mgoblin_app.ini27
-rw-r--r--mediagoblin/tests/test_misc.py34
-rw-r--r--mediagoblin/tests/test_modelmethods.py98
-rw-r--r--mediagoblin/tests/test_notifications.py151
-rw-r--r--mediagoblin/tests/test_oauth.py84
-rw-r--r--mediagoblin/tests/test_openid.py373
-rw-r--r--mediagoblin/tests/test_paste.ini23
-rw-r--r--mediagoblin/tests/test_pdf.py39
-rw-r--r--mediagoblin/tests/test_piwigo.py71
-rw-r--r--mediagoblin/tests/test_pluginapi.py313
-rw-r--r--mediagoblin/tests/test_processing.py4
-rw-r--r--mediagoblin/tests/test_session.py30
-rw-r--r--mediagoblin/tests/test_storage.py63
-rw-r--r--mediagoblin/tests/test_submission.py91
-rw-r--r--mediagoblin/tests/test_submission/good.pdfbin0 -> 194007 bytes
-rw-r--r--mediagoblin/tests/test_tags.py4
-rw-r--r--mediagoblin/tests/test_timesince.py57
-rw-r--r--mediagoblin/tests/test_util.py22
-rw-r--r--mediagoblin/tests/test_workbench.py17
-rw-r--r--mediagoblin/tests/testplugins/__init__.py15
-rw-r--r--mediagoblin/tests/testplugins/callables1/__init__.py (renamed from mediagoblin/tests/test_tests.py)37
-rw-r--r--mediagoblin/tests/testplugins/callables2/__init__.py41
-rw-r--r--mediagoblin/tests/testplugins/callables3/__init__.py41
-rw-r--r--mediagoblin/tests/testplugins/modify_context/__init__.py55
-rw-r--r--mediagoblin/tests/testplugins/modify_context/templates/contextplugin/general.html5
-rw-r--r--mediagoblin/tests/testplugins/modify_context/templates/contextplugin/specific.html6
-rw-r--r--mediagoblin/tests/testplugins/modify_context/views.py (renamed from mediagoblin/init/celery/from_tests.py)26
-rw-r--r--mediagoblin/tests/testplugins/pluginspec/__init__.py22
-rw-r--r--mediagoblin/tests/testplugins/pluginspec/config_spec.ini4
-rw-r--r--mediagoblin/tests/testplugins/staticstuff/__init__.py36
-rw-r--r--mediagoblin/tests/testplugins/staticstuff/static/css/bunnify.css4
-rw-r--r--mediagoblin/tests/testplugins/staticstuff/views.py28
-rw-r--r--mediagoblin/tests/tools.py187
-rw-r--r--mediagoblin/tools/crypto.py113
-rw-r--r--mediagoblin/tools/exif.py2
-rw-r--r--mediagoblin/tools/mail.py22
-rw-r--r--mediagoblin/tools/pluginapi.py93
-rw-r--r--mediagoblin/tools/processing.py2
-rw-r--r--mediagoblin/tools/request.py2
-rw-r--r--mediagoblin/tools/response.py9
-rw-r--r--mediagoblin/tools/routing.py3
-rw-r--r--mediagoblin/tools/session.py75
-rw-r--r--mediagoblin/tools/staticdirect.py38
-rw-r--r--mediagoblin/tools/template.py30
-rw-r--r--mediagoblin/tools/timesince.py95
-rw-r--r--mediagoblin/tools/translate.py45
-rw-r--r--mediagoblin/user_pages/forms.py2
-rw-r--r--mediagoblin/user_pages/lib.py20
-rw-r--r--mediagoblin/user_pages/views.py78
261 files changed, 18346 insertions, 7235 deletions
diff --git a/mediagoblin/_version.py b/mediagoblin/_version.py
index 8437be8b..94629775 100644
--- a/mediagoblin/_version.py
+++ b/mediagoblin/_version.py
@@ -23,4 +23,4 @@
# see http://www.python.org/dev/peps/pep-0386/
-__version__ = "0.4.0.dev"
+__version__ = "0.5.0.dev"
diff --git a/mediagoblin/app.py b/mediagoblin/app.py
index bb6be4d4..57e09e49 100644
--- a/mediagoblin/app.py
+++ b/mediagoblin/app.py
@@ -25,17 +25,21 @@ from werkzeug.exceptions import HTTPException
from werkzeug.routing import RequestRedirect
from mediagoblin import meddleware, __version__
-from mediagoblin.tools import common, translate, template
+from mediagoblin.tools import common, session, translate, template
from mediagoblin.tools.response import render_http_exception
from mediagoblin.tools.theme import register_themes
from mediagoblin.tools import request as mg_request
+from mediagoblin.media_types.tools import media_type_warning
from mediagoblin.mg_globals import setup_globals
from mediagoblin.init.celery import setup_celery_from_config
from mediagoblin.init.plugins import setup_plugins
from mediagoblin.init import (get_jinja_loader, get_staticdirector,
setup_global_and_app_config, setup_locales, setup_workbench, setup_database,
- setup_storage, setup_beaker_cache)
-from mediagoblin.tools.pluginapi import PluginManager
+ setup_storage)
+from mediagoblin.tools.pluginapi import PluginManager, hook_transform
+from mediagoblin.tools.crypto import setup_crypto
+from mediagoblin.auth.tools import check_auth_enabled, no_auth_logout
+from mediagoblin import notifications
_log = logging.getLogger(__name__)
@@ -66,10 +70,17 @@ class MediaGoblinApp(object):
# Open and setup the config
global_config, app_config = setup_global_and_app_config(config_path)
+ media_type_warning()
+
+ setup_crypto()
+
##########################################
# Setup other connections / useful objects
##########################################
+ # Setup Session Manager, not needed in celery
+ self.session_manager = session.SessionManager()
+
# load all available locales
setup_locales()
@@ -79,7 +90,7 @@ class MediaGoblinApp(object):
setup_plugins()
# Set up the database
- self.db = setup_database()
+ self.db = setup_database(app_config['run_migrations'])
# Register themes
self.theme_registry, self.current_theme = register_themes(app_config)
@@ -91,6 +102,11 @@ class MediaGoblinApp(object):
PluginManager().get_template_paths()
)
+ # Check if authentication plugin is enabled and respond accordingly.
+ self.auth = check_auth_enabled()
+ if not self.auth:
+ app_config['allow_comments'] = False
+
# Set up storage systems
self.public_store, self.queue_store = setup_storage()
@@ -100,9 +116,6 @@ class MediaGoblinApp(object):
# set up staticdirector tool
self.staticdirector = get_staticdirector(app_config)
- # set up caching
- self.cache = setup_beaker_cache()
-
# Setup celery, if appropriate
if setup_celery and not app_config.get('celery_setup_elsewhere'):
if os.environ.get('CELERY_ALWAYS_EAGER', 'false').lower() == 'true':
@@ -157,7 +170,8 @@ class MediaGoblinApp(object):
## Attach utilities to the request object
# Do we really want to load this via middleware? Maybe?
- request.session = request.environ['beaker.session']
+ session_manager = self.session_manager
+ request.session = session_manager.load_session_from_cookie(request)
# Attach self as request.app
# Also attach a few utilities from request.app for convenience?
request.app = self
@@ -182,8 +196,14 @@ class MediaGoblinApp(object):
request.urlgen = build_proxy
+ # Log user out if authentication_disabled
+ no_auth_logout(request)
+
+ request.notifications = notifications
+
mg_request.setup_user_in_request(request)
+ request.controller_name = None
try:
found_rule, url_values = map_adapter.match(return_rule=True)
request.matchdict = url_values
@@ -197,6 +217,9 @@ class MediaGoblinApp(object):
exc.get_description(environ))(environ, start_response)
controller = endpoint_to_controller(found_rule)
+ # Make a reference to the controller's symbolic name on the request...
+ # used for lazy context modification
+ request.controller_name = found_rule.endpoint
# pass the request through our meddleware classes
try:
@@ -223,9 +246,12 @@ class MediaGoblinApp(object):
for m in self.meddleware[::-1]:
m.process_response(request, response)
except HTTPException as e:
- response = render_http_exeption(
+ response = render_http_exception(
request, e, e.get_description(environ))
+ session_manager.save_session_to_cookie(request.session,
+ request, response)
+
return response(environ, start_response)
def __call__(self, environ, start_response):
@@ -252,8 +278,6 @@ def paste_app_factory(global_config, **app_config):
raise IOError("Usable mediagoblin config not found.")
mgoblin_app = MediaGoblinApp(mediagoblin_config)
-
- for callable_hook in PluginManager().get_hook_callables('wrap_wsgi'):
- mgoblin_app = callable_hook(mgoblin_app)
+ mgoblin_app = hook_transform('wrap_wsgi', mgoblin_app)
return mgoblin_app
diff --git a/mediagoblin/auth/__init__.py b/mediagoblin/auth/__init__.py
index 621845ba..be5d0eed 100644
--- a/mediagoblin/auth/__init__.py
+++ b/mediagoblin/auth/__init__.py
@@ -13,3 +13,32 @@
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
+from mediagoblin.tools.pluginapi import hook_handle, hook_runall
+
+
+def get_user(**kwargs):
+ """ Takes a kwarg such as username and returns a user object """
+ return hook_handle("auth_get_user", **kwargs)
+
+
+def create_user(register_form):
+ results = hook_runall("auth_create_user", register_form)
+ return results[0]
+
+
+def extra_validation(register_form):
+ from mediagoblin.auth.tools import basic_extra_validation
+
+ extra_validation_passes = basic_extra_validation(register_form)
+ if False in hook_runall("auth_extra_validation", register_form):
+ extra_validation_passes = False
+ return extra_validation_passes
+
+
+def gen_password_hash(raw_pass, extra_salt=None):
+ return hook_handle("auth_gen_password_hash", raw_pass, extra_salt)
+
+
+def check_password(raw_pass, stored_hash, extra_salt=None):
+ return hook_handle("auth_check_password",
+ raw_pass, stored_hash, extra_salt)
diff --git a/mediagoblin/auth/forms.py b/mediagoblin/auth/forms.py
index 8f091d21..865502e9 100644
--- a/mediagoblin/auth/forms.py
+++ b/mediagoblin/auth/forms.py
@@ -16,61 +16,8 @@
import wtforms
-from mediagoblin.tools.mail import normalize_email
-from mediagoblin.tools.translate import fake_ugettext_passthrough as _
-
-def normalize_user_or_email_field(allow_email=True, allow_user=True):
- """Check if we were passed a field that matches a username and/or email pattern
-
- This is useful for fields that can take either a username or email
- address. Use the parameters if you want to only allow a username for
- instance"""
- message = _(u'Invalid User name or email address.')
- nomail_msg = _(u"This field does not take email addresses.")
- nouser_msg = _(u"This field requires an email address.")
-
- def _normalize_field(form, field):
- email = u'@' in field.data
- if email: # normalize email address casing
- if not allow_email:
- raise wtforms.ValidationError(nomail_msg)
- wtforms.validators.Email()(form, field)
- field.data = normalize_email(field.data)
- else: # lower case user names
- if not allow_user:
- raise wtforms.ValidationError(nouser_msg)
- wtforms.validators.Length(min=3, max=30)(form, field)
- wtforms.validators.Regexp(r'^\w+$')(form, field)
- field.data = field.data.lower()
- if field.data is None: # should not happen, but be cautious anyway
- raise wtforms.ValidationError(message)
- return _normalize_field
-
-
-class RegistrationForm(wtforms.Form):
- username = wtforms.TextField(
- _('Username'),
- [wtforms.validators.Required(),
- normalize_user_or_email_field(allow_email=False)])
- password = wtforms.PasswordField(
- _('Password'),
- [wtforms.validators.Required(),
- wtforms.validators.Length(min=5, max=1024)])
- email = wtforms.TextField(
- _('Email address'),
- [wtforms.validators.Required(),
- normalize_user_or_email_field(allow_user=False)])
-
-
-class LoginForm(wtforms.Form):
- username = wtforms.TextField(
- _('Username'),
- [wtforms.validators.Required(),
- normalize_user_or_email_field(allow_email=False)])
- password = wtforms.PasswordField(
- _('Password'),
- [wtforms.validators.Required(),
- wtforms.validators.Length(min=5, max=1024)])
+from mediagoblin.tools.translate import lazy_pass_to_ugettext as _
+from mediagoblin.auth.tools import normalize_user_or_email_field
class ForgotPassForm(wtforms.Form):
@@ -85,9 +32,6 @@ class ChangePassForm(wtforms.Form):
'Password',
[wtforms.validators.Required(),
wtforms.validators.Length(min=5, max=1024)])
- userid = wtforms.HiddenField(
- '',
- [wtforms.validators.Required()])
token = wtforms.HiddenField(
'',
[wtforms.validators.Required()])
diff --git a/mediagoblin/auth/tools.py b/mediagoblin/auth/tools.py
new file mode 100644
index 00000000..579775ff
--- /dev/null
+++ b/mediagoblin/auth/tools.py
@@ -0,0 +1,210 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import logging
+import wtforms
+
+from mediagoblin import mg_globals
+from mediagoblin.tools.crypto import get_timed_signer_url
+from mediagoblin.db.models import User
+from mediagoblin.tools.mail import (normalize_email, send_email,
+ email_debug_message)
+from mediagoblin.tools.template import render_template
+from mediagoblin.tools.translate import lazy_pass_to_ugettext as _
+from mediagoblin.tools.pluginapi import hook_handle
+from mediagoblin import auth
+
+_log = logging.getLogger(__name__)
+
+
+def normalize_user_or_email_field(allow_email=True, allow_user=True):
+ """
+ Check if we were passed a field that matches a username and/or email
+ pattern.
+
+ This is useful for fields that can take either a username or email
+ address. Use the parameters if you want to only allow a username for
+ instance"""
+ message = _(u'Invalid User name or email address.')
+ nomail_msg = _(u"This field does not take email addresses.")
+ nouser_msg = _(u"This field requires an email address.")
+
+ def _normalize_field(form, field):
+ email = u'@' in field.data
+ if email: # normalize email address casing
+ if not allow_email:
+ raise wtforms.ValidationError(nomail_msg)
+ wtforms.validators.Email()(form, field)
+ field.data = normalize_email(field.data)
+ else: # lower case user names
+ if not allow_user:
+ raise wtforms.ValidationError(nouser_msg)
+ wtforms.validators.Length(min=3, max=30)(form, field)
+ wtforms.validators.Regexp(r'^\w+$')(form, field)
+ field.data = field.data.lower()
+ if field.data is None: # should not happen, but be cautious anyway
+ raise wtforms.ValidationError(message)
+ return _normalize_field
+
+
+EMAIL_VERIFICATION_TEMPLATE = (
+ u"{uri}?"
+ u"token={verification_key}")
+
+
+def send_verification_email(user, request, email=None,
+ rendered_email=None):
+ """
+ Send the verification email to users to activate their accounts.
+
+ Args:
+ - user: a user object
+ - request: the request
+ """
+ if not email:
+ email = user.email
+
+ if not rendered_email:
+ verification_key = get_timed_signer_url('mail_verification_token') \
+ .dumps(user.id)
+ rendered_email = render_template(
+ request, 'mediagoblin/auth/verification_email.txt',
+ {'username': user.username,
+ 'verification_url': EMAIL_VERIFICATION_TEMPLATE.format(
+ uri=request.urlgen('mediagoblin.auth.verify_email',
+ qualified=True),
+ verification_key=verification_key)})
+
+ # TODO: There is no error handling in place
+ send_email(
+ mg_globals.app_config['email_sender_address'],
+ [email],
+ # TODO
+ # Due to the distributed nature of GNU MediaGoblin, we should
+ # find a way to send some additional information about the
+ # specific GNU MediaGoblin instance in the subject line. For
+ # example "GNU MediaGoblin @ Wandborg - [...]".
+ 'GNU MediaGoblin - Verify your email!',
+ rendered_email)
+
+
+EMAIL_FP_VERIFICATION_TEMPLATE = (
+ u"{uri}?"
+ u"token={fp_verification_key}")
+
+
+def send_fp_verification_email(user, request):
+ """
+ Send the verification email to users to change their password.
+
+ Args:
+ - user: a user object
+ - request: the request
+ """
+ fp_verification_key = get_timed_signer_url('mail_verification_token') \
+ .dumps(user.id)
+
+ rendered_email = render_template(
+ request, 'mediagoblin/auth/fp_verification_email.txt',
+ {'username': user.username,
+ 'verification_url': EMAIL_FP_VERIFICATION_TEMPLATE.format(
+ uri=request.urlgen('mediagoblin.auth.verify_forgot_password',
+ qualified=True),
+ fp_verification_key=fp_verification_key)})
+
+ # TODO: There is no error handling in place
+ send_email(
+ mg_globals.app_config['email_sender_address'],
+ [user.email],
+ 'GNU MediaGoblin - Change forgotten password!',
+ rendered_email)
+
+
+def basic_extra_validation(register_form, *args):
+ users_with_username = User.query.filter_by(
+ username=register_form.username.data).count()
+ users_with_email = User.query.filter_by(
+ email=register_form.email.data).count()
+
+ extra_validation_passes = True
+
+ if users_with_username:
+ register_form.username.errors.append(
+ _(u'Sorry, a user with that name already exists.'))
+ extra_validation_passes = False
+ if users_with_email:
+ register_form.email.errors.append(
+ _(u'Sorry, a user with that email address already exists.'))
+ extra_validation_passes = False
+
+ return extra_validation_passes
+
+
+def register_user(request, register_form):
+ """ Handle user registration """
+ extra_validation_passes = auth.extra_validation(register_form)
+
+ if extra_validation_passes:
+ # Create the user
+ user = auth.create_user(register_form)
+
+ # log the user in
+ request.session['user_id'] = unicode(user.id)
+ request.session.save()
+
+ # send verification email
+ email_debug_message(request)
+ send_verification_email(user, request)
+
+ return user
+
+ return None
+
+
+def check_login_simple(username, password):
+ user = auth.get_user(username=username)
+ if not user:
+ _log.info("User %r not found", username)
+ hook_handle("auth_fake_login_attempt")
+ return None
+ if not auth.check_password(password, user.pw_hash):
+ _log.warn("Wrong password for %r", username)
+ return None
+ _log.info("Logging %r in", username)
+ return user
+
+
+def check_auth_enabled():
+ if not hook_handle('authentication'):
+ _log.warning('No authentication is enabled')
+ return False
+ else:
+ return True
+
+
+def no_auth_logout(request):
+ """Log out the user if authentication_disabled, but don't delete the messages"""
+ if not mg_globals.app.auth and 'user_id' in request.session:
+ del request.session['user_id']
+ request.session.save()
+
+
+def create_basic_user(form):
+ user = User()
+ user.username = form.username.data
+ user.email = form.email.data
+ user.save()
+ return user
diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py
index d8ad7b51..d54762b0 100644
--- a/mediagoblin/auth/views.py
+++ b/mediagoblin/auth/views.py
@@ -14,82 +14,43 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-import uuid
-import datetime
+from itsdangerous import BadSignature
from mediagoblin import messages, mg_globals
from mediagoblin.db.models import User
+from mediagoblin.tools.crypto import get_timed_signer_url
+from mediagoblin.decorators import auth_enabled, allow_registration
from mediagoblin.tools.response import render_to_response, redirect, render_404
from mediagoblin.tools.translate import pass_to_ugettext as _
-from mediagoblin.auth import lib as auth_lib
+from mediagoblin.tools.mail import email_debug_message
+from mediagoblin.tools.pluginapi import hook_handle
from mediagoblin.auth import forms as auth_forms
-from mediagoblin.auth.lib import send_verification_email, \
- send_fp_verification_email
-
-
-def email_debug_message(request):
- """
- If the server is running in email debug mode (which is
- the current default), give a debug message to the user
- so that they have an idea where to find their email.
- """
- if mg_globals.app_config['email_debug_mode']:
- # DEBUG message, no need to translate
- messages.add_message(request, messages.DEBUG,
- u"This instance is running in email debug mode. "
- u"The email will be on the console of the server process.")
+from mediagoblin.auth.tools import (send_verification_email, register_user,
+ send_fp_verification_email,
+ check_login_simple)
+from mediagoblin import auth
+@allow_registration
+@auth_enabled
def register(request):
"""The registration view.
Note that usernames will always be lowercased. Email domains are lowercased while
the first part remains case-sensitive.
"""
- # Redirects to indexpage if registrations are disabled
- if not mg_globals.app_config["allow_registration"]:
- messages.add_message(
- request,
- messages.WARNING,
- _('Sorry, registration is disabled on this instance.'))
- return redirect(request, "index")
+ if 'pass_auth' not in request.template_env.globals:
+ redirect_name = hook_handle('auth_no_pass_redirect')
+ return redirect(request, 'mediagoblin.plugins.{0}.register'.format(
+ redirect_name))
- register_form = auth_forms.RegistrationForm(request.form)
+ register_form = hook_handle("auth_get_registration_form", request)
if request.method == 'POST' and register_form.validate():
# TODO: Make sure the user doesn't exist already
- users_with_username = User.query.filter_by(username=register_form.data['username']).count()
- users_with_email = User.query.filter_by(email=register_form.data['email']).count()
-
- extra_validation_passes = True
-
- if users_with_username:
- register_form.username.errors.append(
- _(u'Sorry, a user with that name already exists.'))
- extra_validation_passes = False
- if users_with_email:
- register_form.email.errors.append(
- _(u'Sorry, a user with that email address already exists.'))
- extra_validation_passes = False
-
- if extra_validation_passes:
- # Create the user
- user = User()
- user.username = register_form.data['username']
- user.email = register_form.data['email']
- user.pw_hash = auth_lib.bcrypt_gen_password_hash(
- request.form['password'])
- user.verification_key = unicode(uuid.uuid4())
- user.save()
-
- # log the user in
- request.session['user_id'] = unicode(user.id)
- request.session.save()
-
- # send verification email
- email_debug_message(request)
- send_verification_email(user, request)
+ user = register_user(request, register_form)
+ if user:
# redirect the user to their homepage... there will be a
# message waiting for them to verify their email
return redirect(
@@ -99,25 +60,36 @@ def register(request):
return render_to_response(
request,
'mediagoblin/auth/register.html',
- {'register_form': register_form})
+ {'register_form': register_form,
+ 'post_url': request.urlgen('mediagoblin.auth.register')})
+@auth_enabled
def login(request):
"""
MediaGoblin login view.
If you provide the POST with 'next', it'll redirect to that view.
"""
- login_form = auth_forms.LoginForm(request.form)
+ if 'pass_auth' not in request.template_env.globals:
+ redirect_name = hook_handle('auth_no_pass_redirect')
+ return redirect(request, 'mediagoblin.plugins.{0}.login'.format(
+ redirect_name))
+
+ login_form = hook_handle("auth_get_login_form", request)
login_failed = False
if request.method == 'POST':
+ username = login_form.username.data
+
if login_form.validate():
- user = User.query.filter_by(username=login_form.data['username']).first()
+ user = check_login_simple(username, login_form.password.data)
- if user and user.check_login(request.form['password']):
+ if user:
# set up login in session
+ if login_form.stay_logged_in.data:
+ request.session['stay_logged_in'] = True
request.session['user_id'] = unicode(user.id)
request.session.save()
@@ -126,10 +98,6 @@ def login(request):
else:
return redirect(request, "index")
- # Some failure during login occured if we are here!
- # Prevent detecting who's on this system by testing login
- # attempt timings
- auth_lib.fake_login_attempt()
login_failed = True
return render_to_response(
@@ -138,6 +106,7 @@ def login(request):
{'login_form': login_form,
'next': request.GET.get('next') or request.form.get('next'),
'login_failed': login_failed,
+ 'post_url': request.urlgen('mediagoblin.auth.login'),
'allow_registration': mg_globals.app_config["allow_registration"]})
@@ -156,16 +125,28 @@ def verify_email(request):
you are lucky :)
"""
# If we don't have userid and token parameters, we can't do anything; 404
- if not 'userid' in request.GET or not 'token' in request.GET:
+ if not 'token' in request.GET:
return render_404(request)
- user = User.query.filter_by(id=request.args['userid']).first()
+ # Catch error if token is faked or expired
+ try:
+ token = get_timed_signer_url("mail_verification_token") \
+ .loads(request.GET['token'], max_age=10*24*3600)
+ except BadSignature:
+ messages.add_message(
+ request,
+ messages.ERROR,
+ _('The verification key or user id is incorrect.'))
+
+ return redirect(
+ request,
+ 'index')
+
+ user = User.query.filter_by(id=int(token)).first()
- if user and user.verification_key == unicode(request.GET['token']):
+ if user and user.email_verified is False:
user.status = u'active'
user.email_verified = True
- user.verification_key = None
-
user.save()
messages.add_message(
@@ -196,7 +177,7 @@ def resend_activation(request):
request,
messages.ERROR,
_('You must be logged in so we know who to send the email to!'))
-
+
return redirect(request, 'mediagoblin.auth.login')
if request.user.email_verified:
@@ -204,12 +185,9 @@ def resend_activation(request):
request,
messages.ERROR,
_("You've already verified your email address!"))
-
+
return redirect(request, "mediagoblin.user_pages.user_home", user=request.user['username'])
- request.user.verification_key = unicode(uuid.uuid4())
- request.user.save()
-
email_debug_message(request)
send_verification_email(request.user, request)
@@ -229,23 +207,26 @@ def forgot_password(request):
Sends an email with an url to renew forgotten password.
Use GET querystring parameter 'username' to pre-populate the input field
"""
+ if not 'pass_auth' in request.template_env.globals:
+ return redirect(request, 'index')
+
fp_form = auth_forms.ForgotPassForm(request.form,
username=request.args.get('username'))
if not (request.method == 'POST' and fp_form.validate()):
# Either GET request, or invalid form submitted. Display the template
return render_to_response(request,
- 'mediagoblin/auth/forgot_password.html', {'fp_form': fp_form})
+ 'mediagoblin/auth/forgot_password.html', {'fp_form': fp_form,})
# If we are here: method == POST and form is valid. username casing
# has been sanitized. Store if a user was found by email. We should
# not reveal if the operation was successful then as we don't want to
# leak if an email address exists in the system.
- found_by_email = '@' in request.form['username']
+ found_by_email = '@' in fp_form.username.data
if found_by_email:
user = User.query.filter_by(
- email = request.form['username']).first()
+ email = fp_form.username.data).first()
# Don't reveal success in case the lookup happened by email address.
success_message=_("If that email address (case sensitive!) is "
"registered an email has been sent with instructions "
@@ -253,7 +234,7 @@ def forgot_password(request):
else: # found by username
user = User.query.filter_by(
- username = request.form['username']).first()
+ username = fp_form.username.data).first()
if user is None:
messages.add_message(request,
@@ -276,11 +257,6 @@ def forgot_password(request):
# SUCCESS. Send reminder and return to login page
if user:
- user.fp_verification_key = unicode(uuid.uuid4())
- user.fp_token_expire = datetime.datetime.now() + \
- datetime.timedelta(days=10)
- user.save()
-
email_debug_message(request)
send_fp_verification_email(user, request)
@@ -295,31 +271,44 @@ def verify_forgot_password(request):
"""
# get form data variables, and specifically check for presence of token
formdata = _process_for_token(request)
- if not formdata['has_userid_and_token']:
+ if not formdata['has_token']:
return render_404(request)
- formdata_token = formdata['vars']['token']
- formdata_userid = formdata['vars']['userid']
formdata_vars = formdata['vars']
+ # Catch error if token is faked or expired
+ try:
+ token = get_timed_signer_url("mail_verification_token") \
+ .loads(formdata_vars['token'], max_age=10*24*3600)
+ except BadSignature:
+ messages.add_message(
+ request,
+ messages.ERROR,
+ _('The verification key or user id is incorrect.'))
+
+ return redirect(
+ request,
+ 'index')
+
# check if it's a valid user id
- user = User.query.filter_by(id=formdata_userid).first()
+ user = User.query.filter_by(id=int(token)).first()
+
+ # no user in db
if not user:
- return render_404(request)
+ messages.add_message(
+ request, messages.ERROR,
+ _('The user id is incorrect.'))
+ return redirect(
+ request, 'index')
- # check if we have a real user and correct token
- if ((user and user.fp_verification_key and
- user.fp_verification_key == unicode(formdata_token) and
- datetime.datetime.now() < user.fp_token_expire
- and user.email_verified and user.status == 'active')):
+ # check if user active and has email verified
+ if user.email_verified and user.status == 'active':
cp_form = auth_forms.ChangePassForm(formdata_vars)
if request.method == 'POST' and cp_form.validate():
- user.pw_hash = auth_lib.bcrypt_gen_password_hash(
- request.form['password'])
- user.fp_verification_key = None
- user.fp_token_expire = None
+ user.pw_hash = auth.gen_password_hash(
+ cp_form.password.data)
user.save()
messages.add_message(
@@ -331,12 +320,22 @@ def verify_forgot_password(request):
return render_to_response(
request,
'mediagoblin/auth/change_fp.html',
- {'cp_form': cp_form})
+ {'cp_form': cp_form,})
- # in case there is a valid id but no user with that id in the db
- # or the token expired
- else:
- return render_404(request)
+ if not user.email_verified:
+ messages.add_message(
+ request, messages.ERROR,
+ _('You need to verify your email before you can reset your'
+ ' password.'))
+
+ if not user.status == 'active':
+ messages.add_message(
+ request, messages.ERROR,
+ _('You are no longer an active user. Please contact the system'
+ ' admin to reactivate your accoutn.'))
+
+ return redirect(
+ request, 'index')
def _process_for_token(request):
@@ -354,7 +353,6 @@ def _process_for_token(request):
formdata = {
'vars': formdata_vars,
- 'has_userid_and_token':
- 'userid' in formdata_vars and 'token' in formdata_vars}
+ 'has_token': 'token' in formdata_vars}
return formdata
diff --git a/mediagoblin/config_spec.ini b/mediagoblin/config_spec.ini
index 44f6a68f..d2ada163 100644
--- a/mediagoblin/config_spec.ini
+++ b/mediagoblin/config_spec.ini
@@ -5,23 +5,28 @@ html_title = string(default="GNU MediaGoblin")
# link to source for this MediaGoblin site
source_link = string(default="https://gitorious.org/mediagoblin/mediagoblin")
-# Enabled media types
-media_types = string_list(default=list("mediagoblin.media_types.image"))
-
# database stuff
sql_engine = string(default="sqlite:///%(here)s/mediagoblin.db")
+# This flag is used during testing to allow use of in-memory SQLite
+# databases. It is not recommended to be used on a running instance.
+run_migrations = boolean(default=False)
+
# Where temporary files used in processing and etc are kept
workbench_path = string(default="%(here)s/user_dev/media/workbench")
+# Where to store cryptographic sensible data
+crypto_path = string(default="%(here)s/user_dev/crypto")
+
# Where mediagoblin-builtin static assets are kept
direct_remote_path = string(default="/mgoblin_static/")
# set to false to enable sending notices
email_debug_mode = boolean(default=True)
+email_smtp_use_ssl = boolean(default=False)
email_sender_address = string(default="notice@mediagoblin.example.org")
email_smtp_host = string(default='')
-email_smtp_port = integer(default=25)
+email_smtp_port = integer(default=0)
email_smtp_user = string(default=None)
email_smtp_pass = string(default=None)
@@ -29,7 +34,10 @@ email_smtp_pass = string(default=None)
allow_registration = boolean(default=True)
# tag parsing
-tags_max_length = integer(default=50)
+tags_max_length = integer(default=255)
+
+# Enable/disable comments
+allow_comments = boolean(default=True)
# Whether comments are ascending or descending
comments_ascending = boolean(default=True)
@@ -55,6 +63,7 @@ csrf_cookie_name = string(default='mediagoblin_csrftoken')
push_urls = string_list(default=list())
exif_visible = boolean(default=False)
+original_date_visible = boolean(default=False)
# Theming stuff
theme_install_dir = string(default="%(here)s/user_dev/themes/")
@@ -62,6 +71,10 @@ theme_web_path = string(default="/theme_static/")
theme_linked_assets_dir = string(default="%(here)s/user_dev/theme_static/")
theme = string()
+# plugin default assets directory
+plugin_web_path = string(default="/plugin_static/")
+plugin_linked_assets_dir = string(default="%(here)s/user_dev/plugin_static/")
+
[storage:publicstore]
storage_class = string(default="mediagoblin.storage.filestorage:BasicFileStorage")
@@ -88,6 +101,8 @@ max_height = integer(default=180)
[media_type:mediagoblin.media_types.image]
# One of BICUBIC, BILINEAR, NEAREST, ANTIALIAS
resize_filter = string(default="ANTIALIAS")
+#level of compression used when resizing images
+quality = integer(default=90)
[media_type:mediagoblin.media_types.video]
# Should we keep the original file?
@@ -110,7 +125,6 @@ video_codecs = string_list(default=list("VP8 video"))
audio_codecs = string_list(default=list("Vorbis"))
dimensions_match = boolean(default=True)
-
[media_type:mediagoblin.media_types.audio]
keep_original = boolean(default=True)
# vorbisenc quality
@@ -118,14 +132,11 @@ quality = float(default=0.3)
create_spectrogram = boolean(default=True)
spectrogram_fft_size = integer(default=4096)
-
[media_type:mediagoblin.media_types.ascii]
thumbnail_font = string(default=None)
-[beaker.cache]
-type = string(default="file")
-data_dir = string(default="%(here)s/user_dev/beaker/cache/data")
-lock_dir = string(default="%(here)s/user_dev/beaker/cache/lock")
+[media_type:mediagoblin.media_types.pdf]
+pdf_js = boolean(default=True)
[celery]
diff --git a/mediagoblin/db/base.py b/mediagoblin/db/base.py
index 699a503a..c0cefdc2 100644
--- a/mediagoblin/db/base.py
+++ b/mediagoblin/db/base.py
@@ -24,18 +24,6 @@ Session = scoped_session(sessionmaker())
class GMGTableBase(object):
query = Session.query_property()
- @classmethod
- def find(cls, query_dict):
- return cls.query.filter_by(**query_dict)
-
- @classmethod
- def find_one(cls, query_dict):
- return cls.query.filter_by(**query_dict).first()
-
- @classmethod
- def one(cls, query_dict):
- return cls.find(query_dict).one()
-
def get(self, key):
return getattr(self, key)
diff --git a/mediagoblin/db/migration_tools.py b/mediagoblin/db/migration_tools.py
index c0c7e998..aa22ef94 100644
--- a/mediagoblin/db/migration_tools.py
+++ b/mediagoblin/db/migration_tools.py
@@ -175,8 +175,7 @@ class MigrationManager(object):
if self.name == u'__main__':
return u"main mediagoblin tables"
else:
- # TODO: Use the friendlier media manager "human readable" name
- return u'media type "%s"' % self.name
+ return u'plugin "%s"' % self.name
def init_or_migrate(self):
"""
diff --git a/mediagoblin/db/migrations.py b/mediagoblin/db/migrations.py
index 167c4f87..fe4ffb3e 100644
--- a/mediagoblin/db/migrations.py
+++ b/mediagoblin/db/migrations.py
@@ -15,6 +15,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import datetime
+import uuid
from sqlalchemy import (MetaData, Table, Column, Boolean, SmallInteger,
Integer, Unicode, UnicodeText, DateTime,
@@ -25,7 +26,7 @@ from sqlalchemy.sql import and_
from migrate.changeset.constraint import UniqueConstraint
from mediagoblin.db.migration_tools import RegisterMigration, inspect_table
-from mediagoblin.db.models import MediaEntry, Collection, User
+from mediagoblin.db.models import MediaEntry, Collection, User, MediaComment
MIGRATIONS = {}
@@ -212,7 +213,6 @@ def mediaentry_new_slug_era(db):
- slugs with = (or also : which is now also not allowed) to have those
stripped out (small possibility of breakage here sadly)
"""
- import uuid
def slug_and_user_combo_exists(slug, uploader):
return db.execute(
@@ -251,3 +251,131 @@ def mediaentry_new_slug_era(db):
row, row.slug.replace(u"=", u"-").replace(u":", u"-"))
db.commit()
+
+
+@RegisterMigration(10, MIGRATIONS)
+def unique_collections_slug(db):
+ """Add unique constraint to collection slug"""
+ metadata = MetaData(bind=db.bind)
+ collection_table = inspect_table(metadata, "core__collections")
+ existing_slugs = {}
+ slugs_to_change = []
+
+ for row in db.execute(collection_table.select()):
+ # if duplicate slug, generate a unique slug
+ if row.creator in existing_slugs and row.slug in \
+ existing_slugs[row.creator]:
+ slugs_to_change.append(row.id)
+ else:
+ if not row.creator in existing_slugs:
+ existing_slugs[row.creator] = [row.slug]
+ else:
+ existing_slugs[row.creator].append(row.slug)
+
+ for row_id in slugs_to_change:
+ new_slug = unicode(uuid.uuid4())
+ db.execute(collection_table.update().
+ where(collection_table.c.id == row_id).
+ values(slug=new_slug))
+ # sqlite does not like to change the schema when a transaction(update) is
+ # not yet completed
+ db.commit()
+
+ constraint = UniqueConstraint('creator', 'slug',
+ name='core__collection_creator_slug_key',
+ table=collection_table)
+ constraint.create()
+
+ db.commit()
+
+@RegisterMigration(11, MIGRATIONS)
+def drop_token_related_User_columns(db):
+ """
+ Drop unneeded columns from the User table after switching to using
+ itsdangerous tokens for email and forgot password verification.
+ """
+ metadata = MetaData(bind=db.bind)
+ user_table = inspect_table(metadata, 'core__users')
+
+ verification_key = user_table.columns['verification_key']
+ fp_verification_key = user_table.columns['fp_verification_key']
+ fp_token_expire = user_table.columns['fp_token_expire']
+
+ verification_key.drop()
+ fp_verification_key.drop()
+ fp_token_expire.drop()
+
+ db.commit()
+
+
+class CommentSubscription_v0(declarative_base()):
+ __tablename__ = 'core__comment_subscriptions'
+ id = Column(Integer, primary_key=True)
+
+ created = Column(DateTime, nullable=False, default=datetime.datetime.now)
+
+ media_entry_id = Column(Integer, ForeignKey(MediaEntry.id), nullable=False)
+
+ user_id = Column(Integer, ForeignKey(User.id), nullable=False)
+
+ notify = Column(Boolean, nullable=False, default=True)
+ send_email = Column(Boolean, nullable=False, default=True)
+
+
+class Notification_v0(declarative_base()):
+ __tablename__ = 'core__notifications'
+ id = Column(Integer, primary_key=True)
+ type = Column(Unicode)
+
+ created = Column(DateTime, nullable=False, default=datetime.datetime.now)
+
+ user_id = Column(Integer, ForeignKey(User.id), nullable=False,
+ index=True)
+ seen = Column(Boolean, default=lambda: False, index=True)
+
+
+class CommentNotification_v0(Notification_v0):
+ __tablename__ = 'core__comment_notifications'
+ id = Column(Integer, ForeignKey(Notification_v0.id), primary_key=True)
+
+ subject_id = Column(Integer, ForeignKey(MediaComment.id))
+
+
+class ProcessingNotification_v0(Notification_v0):
+ __tablename__ = 'core__processing_notifications'
+
+ id = Column(Integer, ForeignKey(Notification_v0.id), primary_key=True)
+
+ subject_id = Column(Integer, ForeignKey(MediaEntry.id))
+
+
+@RegisterMigration(12, MIGRATIONS)
+def add_new_notification_tables(db):
+ metadata = MetaData(bind=db.bind)
+
+ user_table = inspect_table(metadata, 'core__users')
+ mediaentry_table = inspect_table(metadata, 'core__media_entries')
+ mediacomment_table = inspect_table(metadata, 'core__media_comments')
+
+ CommentSubscription_v0.__table__.create(db.bind)
+
+ Notification_v0.__table__.create(db.bind)
+ CommentNotification_v0.__table__.create(db.bind)
+ ProcessingNotification_v0.__table__.create(db.bind)
+
+
+@RegisterMigration(13, MIGRATIONS)
+def pw_hash_nullable(db):
+ """Make pw_hash column nullable"""
+ metadata = MetaData(bind=db.bind)
+ user_table = inspect_table(metadata, "core__users")
+
+ user_table.c.pw_hash.alter(nullable=True)
+
+ # sqlite+sqlalchemy seems to drop this constraint during the
+ # migration, so we add it back here for now a bit manually.
+ if db.bind.url.drivername == 'sqlite':
+ constraint = UniqueConstraint('username', table=user_table)
+ constraint.create()
+
+ db.commit()
diff --git a/mediagoblin/db/mixin.py b/mediagoblin/db/mixin.py
index fdf61e8d..57b27d83 100644
--- a/mediagoblin/db/mixin.py
+++ b/mediagoblin/db/mixin.py
@@ -28,34 +28,37 @@ real objects.
"""
import uuid
+import re
+from datetime import datetime
from werkzeug.utils import cached_property
from mediagoblin import mg_globals
-from mediagoblin.auth import lib as auth_lib
-from mediagoblin.media_types import get_media_managers, FileTypeNotSupported
+from mediagoblin.media_types import FileTypeNotSupported
from mediagoblin.tools import common, licenses
+from mediagoblin.tools.pluginapi import hook_handle
from mediagoblin.tools.text import cleaned_markdown_conversion
from mediagoblin.tools.url import slugify
class UserMixin(object):
- def check_login(self, password):
- """
- See if a user can login with this password
- """
- return auth_lib.bcrypt_check_password(
- password, self.pw_hash)
-
@property
def bio_html(self):
return cleaned_markdown_conversion(self.bio)
-class MediaEntryMixin(object):
+class GenerateSlugMixin(object):
+ """
+ Mixin to add a generate_slug method to objects.
+
+ Depends on:
+ - self.slug
+ - self.title
+ - self.check_slug_used(new_slug)
+ """
def generate_slug(self):
"""
- Generate a unique slug for this MediaEntry.
+ Generate a unique slug for this object.
This one does not *force* slugs, but usually it will probably result
in a niceish one.
@@ -76,19 +79,15 @@ class MediaEntryMixin(object):
generated bits until it's unique. That'll be a little bit of junk,
but at least it has the basis of a nice slug.
"""
- # import this here due to a cyclic import issue
- # (db.models -> db.mixin -> db.util -> db.models)
- from mediagoblin.db.util import check_media_slug_used
-
#Is already a slug assigned? Check if it is valid
if self.slug:
self.slug = slugify(self.slug)
-
+
# otherwise, try to use the title.
elif self.title:
# assign slug based on title
self.slug = slugify(self.title)
-
+
# We don't want any empty string slugs
if self.slug == u"":
self.slug = None
@@ -98,26 +97,34 @@ class MediaEntryMixin(object):
# so just return... we're not going to force one.
if not self.slug:
return # giving up!
-
+
# Otherwise, let's see if this is unique.
- if check_media_slug_used(self.uploader, self.slug, self.id):
+ if self.check_slug_used(self.slug):
# It looks like it's being used... lame.
-
+
# Can we just append the object's id to the end?
if self.id:
slug_with_id = u"%s-%s" % (self.slug, self.id)
- if not check_media_slug_used(self.uploader,
- slug_with_id, self.id):
+ if not self.check_slug_used(slug_with_id):
self.slug = slug_with_id
return # success!
-
+
# okay, still no success;
# let's whack junk on there till it's unique.
self.slug += '-' + uuid.uuid4().hex[:4]
# keep going if necessary!
- while check_media_slug_used(self.uploader, self.slug, self.id):
+ while self.check_slug_used(self.slug):
self.slug += uuid.uuid4().hex[:4]
+
+class MediaEntryMixin(GenerateSlugMixin):
+ def check_slug_used(self, slug):
+ # import this here due to a cyclic import issue
+ # (db.models -> db.mixin -> db.util -> db.models)
+ from mediagoblin.db.util import check_media_slug_used
+
+ return check_media_slug_used(self.uploader, slug, self.id)
+
@property
def description_html(self):
"""
@@ -137,7 +144,7 @@ class MediaEntryMixin(object):
or, if not found, None.
"""
- fetch_order = self.media_manager.get("media_fetch_order")
+ fetch_order = self.media_manager.media_fetch_order
# No fetching order found? well, give up!
if not fetch_order:
@@ -196,14 +203,14 @@ class MediaEntryMixin(object):
Raises FileTypeNotSupported in case no such manager is enabled
"""
- # TODO, we should be able to make this a simple lookup rather
- # than iterating through all media managers.
- for media_type, manager in get_media_managers():
- if media_type == self.media_type:
- return manager
+ manager = hook_handle(('media_manager', self.media_type))
+ if manager:
+ return manager(self)
+
# Not found? Then raise an error
raise FileTypeNotSupported(
- "MediaManager not in enabled types. Check media_types in config?")
+ "MediaManager not in enabled types. Check media_type plugins are"
+ " enabled in config?")
def get_fail_exception(self):
"""
@@ -217,15 +224,60 @@ class MediaEntryMixin(object):
return licenses.get_license_by_url(self.license or "")
def exif_display_iter(self):
- from mediagoblin.tools.exif import USEFUL_TAGS
+ if not self.media_data:
+ return
+ exif_all = self.media_data.get("exif_all")
+
+ for key in exif_all:
+ label = re.sub('(.)([A-Z][a-z]+)', r'\1 \2', key)
+ yield label.replace('EXIF', '').replace('Image', ''), exif_all[key]
+ def exif_display_data_short(self):
+ """Display a very short practical version of exif info"""
if not self.media_data:
return
+
exif_all = self.media_data.get("exif_all")
- for key in USEFUL_TAGS:
- if key in exif_all:
- yield key, exif_all[key]
+ exif_short = {}
+
+ if 'Image DateTimeOriginal' in exif_all:
+ # format date taken
+ takendate = datetime.datetime.strptime(
+ exif_all['Image DateTimeOriginal']['printable'],
+ '%Y:%m:%d %H:%M:%S').date()
+ taken = takendate.strftime('%B %d %Y')
+
+ exif_short.update({'Date Taken': taken})
+
+ aperture = None
+ if 'EXIF FNumber' in exif_all:
+ fnum = str(exif_all['EXIF FNumber']['printable']).split('/')
+
+ # calculate aperture
+ if len(fnum) == 2:
+ aperture = "f/%.1f" % (float(fnum[0])/float(fnum[1]))
+ elif fnum[0] != 'None':
+ aperture = "f/%s" % (fnum[0])
+
+ if aperture:
+ exif_short.update({'Aperture': aperture})
+
+ short_keys = [
+ ('Camera', 'Image Model', None),
+ ('Exposure', 'EXIF ExposureTime', lambda x: '%s sec' % x),
+ ('ISO Speed', 'EXIF ISOSpeedRatings', None),
+ ('Focal Length', 'EXIF FocalLength', lambda x: '%s mm' % x)]
+
+ for label, key, fmt_func in short_keys:
+ try:
+ val = fmt_func(exif_all[key]['printable']) if fmt_func \
+ else exif_all[key]['printable']
+ exif_short.update({label: val})
+ except KeyError:
+ pass
+
+ return exif_short
class MediaCommentMixin(object):
@@ -237,23 +289,21 @@ class MediaCommentMixin(object):
"""
return cleaned_markdown_conversion(self.content)
+ def __repr__(self):
+ return '<{klass} #{id} {author} "{comment}">'.format(
+ klass=self.__class__.__name__,
+ id=self.id,
+ author=self.get_author,
+ comment=self.content)
-class CollectionMixin(object):
- def generate_slug(self):
+
+class CollectionMixin(GenerateSlugMixin):
+ def check_slug_used(self, slug):
# import this here due to a cyclic import issue
# (db.models -> db.mixin -> db.util -> db.models)
from mediagoblin.db.util import check_collection_slug_used
- self.slug = slugify(self.title)
-
- duplicate = check_collection_slug_used(mg_globals.database,
- self.creator, self.slug, self.id)
-
- if duplicate:
- if self.id is not None:
- self.slug = u"%s-%s" % (self.id, self.slug)
- else:
- self.slug = None
+ return check_collection_slug_used(self.creator, slug, self.id)
@property
def description_html(self):
diff --git a/mediagoblin/db/models.py b/mediagoblin/db/models.py
index 2f58503f..826d47ba 100644
--- a/mediagoblin/db/models.py
+++ b/mediagoblin/db/models.py
@@ -24,15 +24,17 @@ import datetime
from sqlalchemy import Column, Integer, Unicode, UnicodeText, DateTime, \
Boolean, ForeignKey, UniqueConstraint, PrimaryKeyConstraint, \
SmallInteger
-from sqlalchemy.orm import relationship, backref
+from sqlalchemy.orm import relationship, backref, with_polymorphic
from sqlalchemy.orm.collections import attribute_mapped_collection
from sqlalchemy.sql.expression import desc
from sqlalchemy.ext.associationproxy import association_proxy
from sqlalchemy.util import memoized_property
+
from mediagoblin.db.extratypes import PathTupleWithSlashes, JSONEncoded
from mediagoblin.db.base import Base, DictReadAttrProxy
-from mediagoblin.db.mixin import UserMixin, MediaEntryMixin, MediaCommentMixin, CollectionMixin, CollectionItemMixin
+from mediagoblin.db.mixin import UserMixin, MediaEntryMixin, \
+ MediaCommentMixin, CollectionMixin, CollectionItemMixin
from mediagoblin.tools.files import delete_media_files
from mediagoblin.tools.common import import_component
@@ -55,21 +57,22 @@ class User(Base, UserMixin):
id = Column(Integer, primary_key=True)
username = Column(Unicode, nullable=False, unique=True)
+ # Note: no db uniqueness constraint on email because it's not
+ # reliable (many email systems case insensitive despite against
+ # the RFC) and because it would be a mess to implement at this
+ # point.
email = Column(Unicode, nullable=False)
- created = Column(DateTime, nullable=False, default=datetime.datetime.now)
- pw_hash = Column(Unicode, nullable=False)
+ pw_hash = Column(Unicode)
email_verified = Column(Boolean, default=False)
+ created = Column(DateTime, nullable=False, default=datetime.datetime.now)
status = Column(Unicode, default=u"needs_email_verification", nullable=False)
# Intented to be nullable=False, but migrations would not work for it
# set to nullable=True implicitly.
wants_comment_notification = Column(Boolean, default=True)
license_preference = Column(Unicode)
- verification_key = Column(Unicode)
is_admin = Column(Boolean, default=False, nullable=False)
url = Column(Unicode)
bio = Column(UnicodeText) # ??
- fp_verification_key = Column(Unicode)
- fp_token_expire = Column(DateTime)
## TODO
# plugin data would be in a separate model
@@ -172,8 +175,7 @@ class MediaEntry(Base, MediaEntryMixin):
order_col = MediaComment.created
if not ascending:
order_col = desc(order_col)
- return MediaComment.query.filter_by(
- media_entry=self.id).order_by(order_col)
+ return self.all_comments.order_by(order_col)
def url_to_prev(self, urlgen):
"""get the next 'newer' entry by this user"""
@@ -238,9 +240,7 @@ class MediaEntry(Base, MediaEntryMixin):
:param del_orphan_tags: True/false if we delete unused Tags too
:param commit: True/False if this should end the db transaction"""
# User's CollectionItems are automatically deleted via "cascade".
- # Delete all the associated comments
- for comment in self.get_comments():
- comment.delete(commit=False)
+ # Comments on this Media are deleted by cascade, hopefully.
# Delete all related files/attachments
try:
@@ -385,12 +385,25 @@ class MediaComment(Base, MediaCommentMixin):
content = Column(UnicodeText, nullable=False)
# Cascade: Comments are owned by their creator. So do the full thing.
- # lazy=dynamic: People might post a *lot* of comments, so make
- # the "posted_comments" a query-like thing.
+ # lazy=dynamic: People might post a *lot* of comments,
+ # so make the "posted_comments" a query-like thing.
get_author = relationship(User,
backref=backref("posted_comments",
lazy="dynamic",
cascade="all, delete-orphan"))
+ get_entry = relationship(MediaEntry,
+ backref=backref("comments",
+ lazy="dynamic",
+ cascade="all, delete-orphan"))
+
+ # Cascade: Comments are somewhat owned by their MediaEntry.
+ # So do the full thing.
+ # lazy=dynamic: MediaEntries might have many comments,
+ # so make the "all_comments" a query-like thing.
+ get_media_entry = relationship(MediaEntry,
+ backref=backref("all_comments",
+ lazy="dynamic",
+ cascade="all, delete-orphan"))
class Collection(Base, CollectionMixin):
@@ -404,7 +417,7 @@ class Collection(Base, CollectionMixin):
title = Column(Unicode, nullable=False)
slug = Column(Unicode)
created = Column(DateTime, nullable=False, default=datetime.datetime.now,
- index=True)
+ index=True)
description = Column(UnicodeText)
creator = Column(Integer, ForeignKey(User.id), nullable=False)
# TODO: No of items in Collection. Badly named, can we migrate to num_items?
@@ -415,6 +428,10 @@ class Collection(Base, CollectionMixin):
backref=backref("collections",
cascade="all, delete-orphan"))
+ __table_args__ = (
+ UniqueConstraint('creator', 'slug'),
+ {})
+
def get_collection_items(self, ascending=False):
#TODO, is this still needed with self.collection_items being available?
order_col = CollectionItem.position
@@ -470,9 +487,103 @@ class ProcessingMetaData(Base):
return DictReadAttrProxy(self)
+class CommentSubscription(Base):
+ __tablename__ = 'core__comment_subscriptions'
+ id = Column(Integer, primary_key=True)
+
+ created = Column(DateTime, nullable=False, default=datetime.datetime.now)
+
+ media_entry_id = Column(Integer, ForeignKey(MediaEntry.id), nullable=False)
+ media_entry = relationship(MediaEntry,
+ backref=backref('comment_subscriptions',
+ cascade='all, delete-orphan'))
+
+ user_id = Column(Integer, ForeignKey(User.id), nullable=False)
+ user = relationship(User,
+ backref=backref('comment_subscriptions',
+ cascade='all, delete-orphan'))
+
+ notify = Column(Boolean, nullable=False, default=True)
+ send_email = Column(Boolean, nullable=False, default=True)
+
+ def __repr__(self):
+ return ('<{classname} #{id}: {user} {media} notify: '
+ '{notify} email: {email}>').format(
+ id=self.id,
+ classname=self.__class__.__name__,
+ user=self.user,
+ media=self.media_entry,
+ notify=self.notify,
+ email=self.send_email)
+
+
+class Notification(Base):
+ __tablename__ = 'core__notifications'
+ id = Column(Integer, primary_key=True)
+ type = Column(Unicode)
+
+ created = Column(DateTime, nullable=False, default=datetime.datetime.now)
+
+ user_id = Column(Integer, ForeignKey('core__users.id'), nullable=False,
+ index=True)
+ seen = Column(Boolean, default=lambda: False, index=True)
+ user = relationship(
+ User,
+ backref=backref('notifications', cascade='all, delete-orphan'))
+
+ __mapper_args__ = {
+ 'polymorphic_identity': 'notification',
+ 'polymorphic_on': type
+ }
+
+ def __repr__(self):
+ return '<{klass} #{id}: {user}: {subject} ({seen})>'.format(
+ id=self.id,
+ klass=self.__class__.__name__,
+ user=self.user,
+ subject=getattr(self, 'subject', None),
+ seen='unseen' if not self.seen else 'seen')
+
+
+class CommentNotification(Notification):
+ __tablename__ = 'core__comment_notifications'
+ id = Column(Integer, ForeignKey(Notification.id), primary_key=True)
+
+ subject_id = Column(Integer, ForeignKey(MediaComment.id))
+ subject = relationship(
+ MediaComment,
+ backref=backref('comment_notifications', cascade='all, delete-orphan'))
+
+ __mapper_args__ = {
+ 'polymorphic_identity': 'comment_notification'
+ }
+
+
+class ProcessingNotification(Notification):
+ __tablename__ = 'core__processing_notifications'
+
+ id = Column(Integer, ForeignKey(Notification.id), primary_key=True)
+
+ subject_id = Column(Integer, ForeignKey(MediaEntry.id))
+ subject = relationship(
+ MediaEntry,
+ backref=backref('processing_notifications',
+ cascade='all, delete-orphan'))
+
+ __mapper_args__ = {
+ 'polymorphic_identity': 'processing_notification'
+ }
+
+
+with_polymorphic(
+ Notification,
+ [ProcessingNotification, CommentNotification])
+
MODELS = [
- User, MediaEntry, Tag, MediaTag, MediaComment, Collection, CollectionItem, MediaFile, FileKeynames,
- MediaAttachmentFile, ProcessingMetaData]
+ User, MediaEntry, Tag, MediaTag, MediaComment, Collection, CollectionItem,
+ MediaFile, FileKeynames, MediaAttachmentFile, ProcessingMetaData,
+ Notification, CommentNotification, ProcessingNotification,
+ CommentSubscription]
######################################################
diff --git a/mediagoblin/db/models_v0.py b/mediagoblin/db/models_v0.py
index ec51a1f5..bdedec2e 100644
--- a/mediagoblin/db/models_v0.py
+++ b/mediagoblin/db/models_v0.py
@@ -18,6 +18,29 @@
TODO: indexes on foreignkeys, where useful.
"""
+###########################################################################
+# WHAT IS THIS FILE?
+# ------------------
+#
+# Upon occasion, someone runs into this file and wonders why we have
+# both a models.py and a models_v0.py.
+#
+# The short of it is: you can ignore this file.
+#
+# The long version is, in two parts:
+#
+# - We used to use MongoDB, then we switched to SQL and SQLAlchemy.
+# We needed to convert peoples' databases; the script we had would
+# switch them to the first version right after Mongo, convert over
+# all their tables, then run any migrations that were added after.
+#
+# - That script is now removed, but there is some discussion of
+# writing a test that would set us at the first SQL migration and
+# run everything after. If we wrote that, this file would still be
+# useful. But for now, it's legacy!
+#
+###########################################################################
+
import datetime
import sys
diff --git a/mediagoblin/db/open.py b/mediagoblin/db/open.py
index 5fd5ed03..4ff0945f 100644
--- a/mediagoblin/db/open.py
+++ b/mediagoblin/db/open.py
@@ -52,10 +52,6 @@ class DatabaseMaster(object):
def load_models(app_config):
import mediagoblin.db.models
- for media_type in app_config['media_types']:
- _log.debug("Loading %s.models", media_type)
- __import__(media_type + ".models")
-
for plugin in mg_globals.global_config.get('plugins', {}).keys():
_log.debug("Loading %s.models", plugin)
try:
@@ -71,12 +67,24 @@ def _sqlite_fk_pragma_on_connect(dbapi_con, con_record):
dbapi_con.execute('pragma foreign_keys=on')
-def setup_connection_and_db_from_config(app_config):
+def _sqlite_disable_fk_pragma_on_connect(dbapi_con, con_record):
+ """
+ Disable foreign key checking on each new sqlite connection
+ (Good for migrations!)
+ """
+ dbapi_con.execute('pragma foreign_keys=off')
+
+
+def setup_connection_and_db_from_config(app_config, migrations=False):
engine = create_engine(app_config['sql_engine'])
# Enable foreign key checking for sqlite
if app_config['sql_engine'].startswith('sqlite://'):
- event.listen(engine, 'connect', _sqlite_fk_pragma_on_connect)
+ if migrations:
+ event.listen(engine, 'connect',
+ _sqlite_disable_fk_pragma_on_connect)
+ else:
+ event.listen(engine, 'connect', _sqlite_fk_pragma_on_connect)
# logging.getLogger('sqlalchemy.engine').setLevel(logging.INFO)
diff --git a/mediagoblin/db/util.py b/mediagoblin/db/util.py
index 529ef8b9..8431361a 100644
--- a/mediagoblin/db/util.py
+++ b/mediagoblin/db/util.py
@@ -24,7 +24,7 @@ from mediagoblin.db.models import MediaEntry, Tag, MediaTag, Collection
def atomic_update(table, query_dict, update_values):
- table.find(query_dict).update(update_values,
+ table.query.filter_by(**query_dict).update(update_values,
synchronize_session=False)
Session.commit()
@@ -59,7 +59,7 @@ def clean_orphan_tags(commit=True):
Session.commit()
-def check_collection_slug_used(dummy_db, creator_id, slug, ignore_c_id):
+def check_collection_slug_used(creator_id, slug, ignore_c_id):
filt = (Collection.creator == creator_id) \
& (Collection.slug == slug)
if ignore_c_id is not None:
diff --git a/mediagoblin/decorators.py b/mediagoblin/decorators.py
index f3535fcf..ca7be53c 100644
--- a/mediagoblin/decorators.py
+++ b/mediagoblin/decorators.py
@@ -18,11 +18,12 @@ from functools import wraps
from urlparse import urljoin
from werkzeug.exceptions import Forbidden, NotFound
-from werkzeug.urls import url_quote
from mediagoblin import mg_globals as mgg
+from mediagoblin import messages
from mediagoblin.db.models import MediaEntry, User
from mediagoblin.tools.response import redirect, render_404
+from mediagoblin.tools.translate import pass_to_ugettext as _
def require_active_login(controller):
@@ -86,8 +87,8 @@ def user_may_alter_collection(controller):
"""
@wraps(controller)
def wrapper(request, *args, **kwargs):
- creator_id = request.db.User.find_one(
- {'username': request.matchdict['user']}).id
+ creator_id = request.db.User.query.filter_by(
+ username=request.matchdict['user']).first().id
if not (request.user.is_admin or
request.user.id == creator_id):
raise Forbidden()
@@ -161,15 +162,15 @@ def get_user_collection(controller):
"""
@wraps(controller)
def wrapper(request, *args, **kwargs):
- user = request.db.User.find_one(
- {'username': request.matchdict['user']})
+ user = request.db.User.query.filter_by(
+ username=request.matchdict['user']).first()
if not user:
return render_404(request)
- collection = request.db.Collection.find_one(
- {'slug': request.matchdict['collection'],
- 'creator': user.id})
+ collection = request.db.Collection.query.filter_by(
+ slug=request.matchdict['collection'],
+ creator=user.id).first()
# Still no collection? Okay, 404.
if not collection:
@@ -186,14 +187,14 @@ def get_user_collection_item(controller):
"""
@wraps(controller)
def wrapper(request, *args, **kwargs):
- user = request.db.User.find_one(
- {'username': request.matchdict['user']})
+ user = request.db.User.query.filter_by(
+ username=request.matchdict['user']).first()
if not user:
return render_404(request)
- collection_item = request.db.CollectionItem.find_one(
- {'id': request.matchdict['collection_item'] })
+ collection_item = request.db.CollectionItem.query.filter_by(
+ id=request.matchdict['collection_item']).first()
# Still no collection item? Okay, 404.
if not collection_item:
@@ -235,3 +236,35 @@ def get_workbench(func):
return func(*args, workbench=workbench, **kwargs)
return new_func
+
+
+def allow_registration(controller):
+ """ Decorator for if registration is enabled"""
+ @wraps(controller)
+ def wrapper(request, *args, **kwargs):
+ if not mgg.app_config["allow_registration"]:
+ messages.add_message(
+ request,
+ messages.WARNING,
+ _('Sorry, registration is disabled on this instance.'))
+ return redirect(request, "index")
+
+ return controller(request, *args, **kwargs)
+
+ return wrapper
+
+
+def auth_enabled(controller):
+ """Decorator for if an auth plugin is enabled"""
+ @wraps(controller)
+ def wrapper(request, *args, **kwargs):
+ if not mgg.app.auth:
+ messages.add_message(
+ request,
+ messages.WARNING,
+ _('Sorry, authentication is disabled on this instance.'))
+ return redirect(request, 'index')
+
+ return controller(request, *args, **kwargs)
+
+ return wrapper
diff --git a/mediagoblin/edit/forms.py b/mediagoblin/edit/forms.py
index 2673967b..85c243a0 100644
--- a/mediagoblin/edit/forms.py
+++ b/mediagoblin/edit/forms.py
@@ -16,9 +16,11 @@
import wtforms
-from mediagoblin.tools.text import tag_length_validator, TOO_LONG_TAG_WARNING
-from mediagoblin.tools.translate import fake_ugettext_passthrough as _
+from mediagoblin.tools.text import tag_length_validator
+from mediagoblin.tools.translate import lazy_pass_to_ugettext as _
from mediagoblin.tools.licenses import licenses_as_choices
+from mediagoblin.auth.forms import normalize_user_or_email_field
+
class EditForm(wtforms.Form):
title = wtforms.TextField(
@@ -59,17 +61,12 @@ class EditProfileForm(wtforms.Form):
class EditAccountForm(wtforms.Form):
- old_password = wtforms.PasswordField(
- _('Old password'),
- description=_(
- "Enter your old password to prove you own this account."))
- new_password = wtforms.PasswordField(
- _('New password'),
- [
- wtforms.validators.Optional(),
- wtforms.validators.Length(min=6, max=30)
- ],
- id="password")
+ new_email = wtforms.TextField(
+ _('New email address'),
+ [wtforms.validators.Optional(),
+ normalize_user_or_email_field(allow_user=False)])
+ wants_comment_notification = wtforms.BooleanField(
+ description=_("Email me when others comment on my media"))
license_preference = wtforms.SelectField(
_('License preference'),
[
@@ -78,8 +75,6 @@ class EditAccountForm(wtforms.Form):
],
choices=licenses_as_choices(),
description=_('This will be your default license on upload forms.'))
- wants_comment_notification = wtforms.BooleanField(
- label=_("Email me when others comment on my media"))
class EditAttachmentsForm(wtforms.Form):
@@ -103,3 +98,16 @@ class EditCollectionForm(wtforms.Form):
description=_(
"The title part of this collection's address. "
"You usually don't need to change this."))
+
+
+class ChangePassForm(wtforms.Form):
+ old_password = wtforms.PasswordField(
+ _('Old password'),
+ [wtforms.validators.Required()],
+ description=_(
+ "Enter your old password to prove you own this account."))
+ new_password = wtforms.PasswordField(
+ _('New password'),
+ [wtforms.validators.Required(),
+ wtforms.validators.Length(min=6, max=30)],
+ id="password")
diff --git a/mediagoblin/edit/routing.py b/mediagoblin/edit/routing.py
index 035a766f..3592f708 100644
--- a/mediagoblin/edit/routing.py
+++ b/mediagoblin/edit/routing.py
@@ -24,3 +24,7 @@ add_route('mediagoblin.edit.account', '/edit/account/',
'mediagoblin.edit.views:edit_account')
add_route('mediagoblin.edit.delete_account', '/edit/account/delete/',
'mediagoblin.edit.views:delete_account')
+add_route('mediagoblin.edit.pass', '/edit/password/',
+ 'mediagoblin.edit.views:change_pass')
+add_route('mediagoblin.edit.verify_email', '/edit/verify_email/',
+ 'mediagoblin.edit.views:verify_email')
diff --git a/mediagoblin/edit/views.py b/mediagoblin/edit/views.py
index cdb5c713..6aa2acd9 100644
--- a/mediagoblin/edit/views.py
+++ b/mediagoblin/edit/views.py
@@ -16,24 +16,31 @@
from datetime import datetime
+from itsdangerous import BadSignature
from werkzeug.exceptions import Forbidden
from werkzeug.utils import secure_filename
from mediagoblin import messages
from mediagoblin import mg_globals
-from mediagoblin.auth import lib as auth_lib
+from mediagoblin import auth
+from mediagoblin.auth import tools as auth_tools
from mediagoblin.edit import forms
from mediagoblin.edit.lib import may_edit_media
from mediagoblin.decorators import (require_active_login, active_user_from_url,
- get_media_entry_by_id,
- user_may_alter_collection, get_user_collection)
-from mediagoblin.tools.response import render_to_response, redirect
+ get_media_entry_by_id, user_may_alter_collection,
+ get_user_collection)
+from mediagoblin.tools.crypto import get_timed_signer_url
+from mediagoblin.tools.mail import email_debug_message
+from mediagoblin.tools.response import (render_to_response,
+ redirect, redirect_obj, render_404)
from mediagoblin.tools.translate import pass_to_ugettext as _
+from mediagoblin.tools.template import render_template
from mediagoblin.tools.text import (
convert_to_tag_list_of_dicts, media_tags_as_string)
from mediagoblin.tools.url import slugify
from mediagoblin.db.util import check_media_slug_used, check_collection_slug_used
+from mediagoblin.db.models import User
import mimetypes
@@ -58,24 +65,23 @@ def edit_media(request, media):
if request.method == 'POST' and form.validate():
# Make sure there isn't already a MediaEntry with such a slug
# and userid.
- slug = slugify(request.form['slug'])
+ slug = slugify(form.slug.data)
slug_used = check_media_slug_used(media.uploader, slug, media.id)
if slug_used:
form.slug.errors.append(
_(u'An entry with that slug already exists for this user.'))
else:
- media.title = request.form['title']
- media.description = request.form.get('description')
+ media.title = form.title.data
+ media.description = form.description.data
media.tags = convert_to_tag_list_of_dicts(
- request.form.get('tags'))
+ form.tags.data)
- media.license = unicode(request.form.get('license', '')) or None
+ media.license = unicode(form.license.data) or None
media.slug = slug
media.save()
- return redirect(request,
- location=media.url_for_self(request.urlgen))
+ return redirect_obj(request, media)
if request.user.is_admin \
and media.uploader != request.user.id \
@@ -142,7 +148,7 @@ def edit_attachments(request, media):
request.files['attachment_file'].stream.close()
media.attachment_files.append(dict(
- name=request.form['attachment_name'] \
+ name=form.attachment_name.data \
or request.files['attachment_file'].filename,
filepath=attachment_public_filepath,
created=datetime.utcnow(),
@@ -153,7 +159,7 @@ def edit_attachments(request, media):
messages.add_message(
request, messages.SUCCESS,
_("You added the attachment %s!") \
- % (request.form['attachment_name']
+ % (form.attachment_name.data
or request.files['attachment_file'].filename))
return redirect(request,
@@ -194,8 +200,8 @@ def edit_profile(request, url_user=None):
bio=user.bio)
if request.method == 'POST' and form.validate():
- user.url = unicode(request.form['url'])
- user.bio = unicode(request.form['bio'])
+ user.url = unicode(form.url.data)
+ user.bio = unicode(form.bio.data)
user.save()
@@ -212,6 +218,10 @@ def edit_profile(request, url_user=None):
{'user': user,
'form': form})
+EMAIL_VERIFICATION_TEMPLATE = (
+ u'{uri}?'
+ u'token={verification_key}')
+
@require_active_login
def edit_account(request):
@@ -220,39 +230,22 @@ def edit_account(request):
wants_comment_notification=user.wants_comment_notification,
license_preference=user.license_preference)
- if request.method == 'POST':
- form_validated = form.validate()
-
- if form_validated and \
- form.wants_comment_notification.validate(form):
- user.wants_comment_notification = \
- form.wants_comment_notification.data
-
- if form_validated and \
- form.new_password.data or form.old_password.data:
- password_matches = auth_lib.bcrypt_check_password(
- form.old_password.data,
- user.pw_hash)
- if password_matches:
- #the entire form validates and the password matches
- user.pw_hash = auth_lib.bcrypt_gen_password_hash(
- form.new_password.data)
- else:
- form.old_password.errors.append(_('Wrong password'))
+ if request.method == 'POST' and form.validate():
+ user.wants_comment_notification = form.wants_comment_notification.data
+
+ user.license_preference = form.license_preference.data
- if form_validated and \
- form.license_preference.validate(form):
- user.license_preference = \
- form.license_preference.data
+ if form.new_email.data:
+ _update_email(request, form, user)
- if form_validated and not form.errors:
+ if not form.errors:
user.save()
messages.add_message(request,
- messages.SUCCESS,
- _("Account settings saved"))
+ messages.SUCCESS,
+ _("Account settings saved"))
return redirect(request,
- 'mediagoblin.user_pages.user_home',
- user=user.username)
+ 'mediagoblin.user_pages.user_home',
+ user=user.username)
return render_to_response(
request,
@@ -308,32 +301,30 @@ def edit_collection(request, collection):
if request.method == 'POST' and form.validate():
# Make sure there isn't already a Collection with such a slug
# and userid.
- slug_used = check_collection_slug_used(request.db, collection.creator,
- request.form['slug'], collection.id)
+ slug_used = check_collection_slug_used(collection.creator,
+ form.slug.data, collection.id)
# Make sure there isn't already a Collection with this title
- existing_collection = request.db.Collection.find_one({
- 'creator': request.user.id,
- 'title':request.form['title']})
+ existing_collection = request.db.Collection.query.filter_by(
+ creator=request.user.id,
+ title=form.title.data).first()
if existing_collection and existing_collection.id != collection.id:
messages.add_message(
request, messages.ERROR,
_('You already have a collection called "%s"!') % \
- request.form['title'])
+ form.title.data)
elif slug_used:
form.slug.errors.append(
_(u'A collection with that slug already exists for this user.'))
else:
- collection.title = unicode(request.form['title'])
- collection.description = unicode(request.form.get('description'))
- collection.slug = unicode(request.form['slug'])
+ collection.title = unicode(form.title.data)
+ collection.description = unicode(form.description.data)
+ collection.slug = unicode(form.slug.data)
collection.save()
- return redirect(request, "mediagoblin.user_pages.user_collection",
- user=collection.get_creator.username,
- collection=collection.slug)
+ return redirect_obj(request, collection)
if request.user.is_admin \
and collection.creator != request.user.id \
@@ -347,3 +338,117 @@ def edit_collection(request, collection):
'mediagoblin/edit/edit_collection.html',
{'collection': collection,
'form': form})
+
+
+@require_active_login
+def change_pass(request):
+ # If no password authentication, no need to change your password
+ if 'pass_auth' not in request.template_env.globals:
+ return redirect(request, 'index')
+
+ form = forms.ChangePassForm(request.form)
+ user = request.user
+
+ if request.method == 'POST' and form.validate():
+
+ if not auth.check_password(
+ form.old_password.data, user.pw_hash):
+ form.old_password.errors.append(
+ _('Wrong password'))
+
+ return render_to_response(
+ request,
+ 'mediagoblin/edit/change_pass.html',
+ {'form': form,
+ 'user': user})
+
+ # Password matches
+ user.pw_hash = auth.gen_password_hash(
+ form.new_password.data)
+ user.save()
+
+ messages.add_message(
+ request, messages.SUCCESS,
+ _('Your password was changed successfully'))
+
+ return redirect(request, 'mediagoblin.edit.account')
+
+ return render_to_response(
+ request,
+ 'mediagoblin/edit/change_pass.html',
+ {'form': form,
+ 'user': user})
+
+
+def verify_email(request):
+ """
+ Email verification view for changing email address
+ """
+ # If no token, we can't do anything
+ if not 'token' in request.GET:
+ return render_404(request)
+
+ # Catch error if token is faked or expired
+ token = None
+ try:
+ token = get_timed_signer_url("mail_verification_token") \
+ .loads(request.GET['token'], max_age=10*24*3600)
+ except BadSignature:
+ messages.add_message(
+ request,
+ messages.ERROR,
+ _('The verification key or user id is incorrect.'))
+
+ return redirect(
+ request,
+ 'index')
+
+ user = User.query.filter_by(id=int(token['user'])).first()
+
+ if user:
+ user.email = token['email']
+ user.save()
+
+ messages.add_message(
+ request,
+ messages.SUCCESS,
+ _('Your email address has been verified.'))
+
+ else:
+ messages.add_message(
+ request,
+ messages.ERROR,
+ _('The verification key or user id is incorrect.'))
+
+ return redirect(
+ request, 'mediagoblin.user_pages.user_home',
+ user=user.username)
+
+
+def _update_email(request, form, user):
+ new_email = form.new_email.data
+ users_with_email = User.query.filter_by(
+ email=new_email).count()
+
+ if users_with_email:
+ form.new_email.errors.append(
+ _('Sorry, a user with that email address'
+ ' already exists.'))
+
+ elif not users_with_email:
+ verification_key = get_timed_signer_url(
+ 'mail_verification_token').dumps({
+ 'user': user.id,
+ 'email': new_email})
+
+ rendered_email = render_template(
+ request, 'mediagoblin/edit/verification.txt',
+ {'username': user.username,
+ 'verification_url': EMAIL_VERIFICATION_TEMPLATE.format(
+ uri=request.urlgen('mediagoblin.edit.verify_email',
+ qualified=True),
+ verification_key=verification_key)})
+
+ email_debug_message(request)
+ auth_tools.send_verification_email(user, request, new_email,
+ rendered_email)
diff --git a/mediagoblin/gmg_commands/__init__.py b/mediagoblin/gmg_commands/__init__.py
index 6aed4f6c..d8156126 100644
--- a/mediagoblin/gmg_commands/__init__.py
+++ b/mediagoblin/gmg_commands/__init__.py
@@ -41,11 +41,15 @@ SUBCOMMAND_MAP = {
'setup': 'mediagoblin.gmg_commands.dbupdate:dbupdate_parse_setup',
'func': 'mediagoblin.gmg_commands.dbupdate:dbupdate',
'help': 'Set up or update the SQL database'},
- 'theme': {
- 'setup': 'mediagoblin.gmg_commands.theme:theme_parser_setup',
- 'func': 'mediagoblin.gmg_commands.theme:theme',
- 'help': 'Theming commands',
- }
+ 'assetlink': {
+ 'setup': 'mediagoblin.gmg_commands.assetlink:assetlink_parser_setup',
+ 'func': 'mediagoblin.gmg_commands.assetlink:assetlink',
+ 'help': 'Link assets for themes and plugins for static serving'},
+ # 'theme': {
+ # 'setup': 'mediagoblin.gmg_commands.theme:theme_parser_setup',
+ # 'func': 'mediagoblin.gmg_commands.theme:theme',
+ # 'help': 'Theming commands',
+ # }
## These might be useful, mayyyybe, but don't really work anymore
## due to mongo change and the "versatility" of sql options.
diff --git a/mediagoblin/gmg_commands/assetlink.py b/mediagoblin/gmg_commands/assetlink.py
new file mode 100644
index 00000000..148ebe9e
--- /dev/null
+++ b/mediagoblin/gmg_commands/assetlink.py
@@ -0,0 +1,151 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import os
+
+from mediagoblin import mg_globals
+from mediagoblin.init import setup_global_and_app_config
+from mediagoblin.gmg_commands import util as commands_util
+from mediagoblin.tools.theme import register_themes
+from mediagoblin.tools.translate import pass_to_ugettext as _
+from mediagoblin.tools.common import simple_printer
+from mediagoblin.tools import pluginapi
+
+
+def assetlink_parser_setup(subparser):
+ # theme_subparsers = subparser.add_subparsers(
+ # dest=u"subcommand",
+ # help=u'Assetlink options')
+
+ # # Install command
+ # install_parser = theme_subparsers.add_parser(
+ # u'install', help=u'Install a theme to this mediagoblin instance')
+ # install_parser.add_argument(
+ # u'themefile', help=u'The theme archive to be installed')
+
+ # theme_subparsers.add_parser(
+ # u'assetlink',
+ # help=(
+ # u"Link the currently installed theme's assets "
+ # u"to the served theme asset directory"))
+ pass
+
+
+###########
+# Utilities
+###########
+
+def link_theme_assets(theme, link_dir, printer=simple_printer):
+ """
+ Returns a list of string of text telling the user what we did
+ which should be printable.
+ """
+ link_dir = link_dir.rstrip(os.path.sep)
+ link_parent_dir = os.path.dirname(link_dir)
+
+ if theme is None:
+ printer(_("Cannot link theme... no theme set\n"))
+ return
+
+ def _maybe_unlink_link_dir():
+ """unlink link directory if it exists"""
+ if os.path.lexists(link_dir) \
+ and os.path.islink(link_dir):
+ os.unlink(link_dir)
+ return True
+
+ return
+
+ if theme.get('assets_dir') is None:
+ printer(_("No asset directory for this theme\n"))
+ if _maybe_unlink_link_dir():
+ printer(
+ _("However, old link directory symlink found; removed.\n"))
+ return
+
+ _maybe_unlink_link_dir()
+
+ # make the link directory parent dirs if necessary
+ if not os.path.lexists(link_parent_dir):
+ os.makedirs(link_parent_dir)
+
+ os.symlink(
+ theme['assets_dir'].rstrip(os.path.sep),
+ link_dir)
+ printer("Linked the theme's asset directory:\n %s\nto:\n %s\n" % (
+ theme['assets_dir'], link_dir))
+
+
+def link_plugin_assets(plugin_static, plugins_link_dir, printer=simple_printer):
+ """
+ Arguments:
+ - plugin_static: a mediagoblin.tools.staticdirect.PluginStatic instance
+ representing the static assets of this plugins' configuration
+ - plugins_link_dir: Base directory plugins are linked from
+ """
+ # link_dir is the final directory we'll link to, a combination of
+ # the plugin assetlink directory and plugin_static.name
+ link_dir = os.path.join(
+ plugins_link_dir.rstrip(os.path.sep), plugin_static.name)
+
+ # make the link directory parent dirs if necessary
+ if not os.path.lexists(plugins_link_dir):
+ os.makedirs(plugins_link_dir)
+
+ # See if the link_dir already exists.
+ if os.path.lexists(link_dir):
+ # if this isn't a symlink, there's something wrong... error out.
+ if not os.path.islink(link_dir):
+ printer(_('Could not link "%s": %s exists and is not a symlink\n') % (
+ plugin_static.name, link_dir))
+ return
+
+ # if this is a symlink and the path already exists, skip it.
+ if os.path.realpath(link_dir) == plugin_static.file_path:
+ # Is this comment helpful or not?
+ printer(_('Skipping "%s"; already set up.\n') % (
+ plugin_static.name))
+ return
+
+ # Otherwise, it's a link that went to something else... unlink it
+ printer(_('Old link found for "%s"; removing.\n') % (
+ plugin_static.name))
+ os.unlink(link_dir)
+
+ os.symlink(
+ plugin_static.file_path.rstrip(os.path.sep),
+ link_dir)
+ printer('Linked asset directory for plugin "%s":\n %s\nto:\n %s\n' % (
+ plugin_static.name,
+ plugin_static.file_path.rstrip(os.path.sep),
+ link_dir))
+
+
+def assetlink(args):
+ """
+ Link the asset directory of the currently installed theme and plugins
+ """
+ mgoblin_app = commands_util.setup_app(args)
+ app_config = mg_globals.app_config
+
+ # link theme
+ link_theme_assets(mgoblin_app.current_theme, app_config['theme_linked_assets_dir'])
+
+ # link plugin assets
+ ## ... probably for this we need the whole application initialized
+ for plugin_static in pluginapi.hook_runall("static_setup"):
+ link_plugin_assets(
+ plugin_static, app_config['plugin_linked_assets_dir'])
diff --git a/mediagoblin/gmg_commands/dbupdate.py b/mediagoblin/gmg_commands/dbupdate.py
index 65b3f922..00007567 100644
--- a/mediagoblin/gmg_commands/dbupdate.py
+++ b/mediagoblin/gmg_commands/dbupdate.py
@@ -42,7 +42,7 @@ class DatabaseData(object):
self.name, self.models, self.migrations, session)
-def gather_database_data(media_types, plugins):
+def gather_database_data(plugins):
"""
Gather all database data relevant to the extensions we have
installed so we can do migrations and table initialization.
@@ -59,13 +59,6 @@ def gather_database_data(media_types, plugins):
DatabaseData(
u'__main__', MAIN_MODELS, MAIN_MIGRATIONS))
- # Then get all registered media managers (eventually, plugins)
- for media_type in media_types:
- models = import_component('%s.models:MODELS' % media_type)
- migrations = import_component('%s.migrations:MIGRATIONS' % media_type)
- managed_dbdata.append(
- DatabaseData(media_type, models, migrations))
-
for plugin in plugins:
try:
models = import_component('{0}.models:MODELS'.format(plugin))
@@ -78,6 +71,7 @@ def gather_database_data(media_types, plugins):
except AttributeError as exc:
_log.warning('Could not find MODELS in {0}.models, have you \
forgotten to add it? ({1})'.format(plugin, exc))
+ models = []
try:
migrations = import_component('{0}.migrations:MIGRATIONS'.format(
@@ -91,6 +85,7 @@ forgotten to add it? ({1})'.format(plugin, exc))
except AttributeError as exc:
_log.debug('Cloud not find MIGRATIONS in {0}.migrations, have you \
forgotten to add it? ({1})'.format(plugin, exc))
+ migrations = {}
if models:
managed_dbdata.append(
@@ -108,14 +103,25 @@ def run_dbupdate(app_config, global_config):
in the future, plugins)
"""
+ # Set up the database
+ db = setup_connection_and_db_from_config(app_config, migrations=True)
+ #Run the migrations
+ run_all_migrations(db, app_config, global_config)
+
+
+def run_all_migrations(db, app_config, global_config):
+ """
+ Initializes or migrates a database that already has a
+ connection setup and also initializes or migrates all
+ extensions based on the config files.
+
+ It can be used to initialize an in-memory database for
+ testing.
+ """
# Gather information from all media managers / projects
dbdatas = gather_database_data(
- app_config['media_types'],
global_config.get('plugins', {}).keys())
- # Set up the database
- db = setup_connection_and_db_from_config(app_config)
-
Session = sessionmaker(bind=db.engine)
# Setup media managers for all dbdata, run init/migrate and print info
diff --git a/mediagoblin/gmg_commands/import_export.py b/mediagoblin/gmg_commands/import_export.py
index d51a1e3e..98ec617d 100644
--- a/mediagoblin/gmg_commands/import_export.py
+++ b/mediagoblin/gmg_commands/import_export.py
@@ -63,7 +63,7 @@ def _import_media(db, args):
# TODO: Add import of queue files
queue_cache = BasicFileStorage(args._cache_path['queue'])
- for entry in db.MediaEntry.find():
+ for entry in db.MediaEntry.query.filter_by():
for name, path in entry.media_files.items():
_log.info('Importing: {0} - {1}'.format(
entry.title.encode('ascii', 'replace'),
@@ -204,7 +204,7 @@ def _export_media(db, args):
# TODO: Add export of queue files
queue_cache = BasicFileStorage(args._cache_path['queue'])
- for entry in db.MediaEntry.find():
+ for entry in db.MediaEntry.query.filter_by():
for name, path in entry.media_files.items():
_log.info(u'Exporting {0} - {1}'.format(
entry.title,
diff --git a/mediagoblin/gmg_commands/theme.py b/mediagoblin/gmg_commands/theme.py
deleted file mode 100644
index 71abb982..00000000
--- a/mediagoblin/gmg_commands/theme.py
+++ /dev/null
@@ -1,122 +0,0 @@
-# GNU MediaGoblin -- federated, autonomous media hosting
-# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-import os
-
-from mediagoblin.init import setup_global_and_app_config
-from mediagoblin.tools.theme import register_themes
-from mediagoblin.tools.translate import pass_to_ugettext as _
-from mediagoblin.tools.common import simple_printer
-
-
-def theme_parser_setup(subparser):
- theme_subparsers = subparser.add_subparsers(
- dest=u"subcommand",
- help=u'Theme sub-commands')
-
- # Install command
- install_parser = theme_subparsers.add_parser(
- u'install', help=u'Install a theme to this mediagoblin instance')
- install_parser.add_argument(
- u'themefile', help=u'The theme archive to be installed')
-
- theme_subparsers.add_parser(
- u'assetlink',
- help=(
- u"Link the currently installed theme's assets "
- u"to the served theme asset directory"))
-
-
-###########
-# Utilities
-###########
-
-def link_assets(theme, link_dir, printer=simple_printer):
- """
- Returns a list of string of text telling the user what we did
- which should be printable.
- """
- link_dir = link_dir.rstrip(os.path.sep)
- link_parent_dir = os.path.dirname(link_dir)
-
- results = []
-
- if theme is None:
- printer(_("Cannot link theme... no theme set\n"))
- return results
-
- def _maybe_unlink_link_dir():
- """unlink link directory if it exists"""
- if os.path.lexists(link_dir) \
- and os.path.islink(link_dir):
- os.unlink(link_dir)
- return True
-
- return results
-
- if theme.get('assets_dir') is None:
- printer(_("No asset directory for this theme\n"))
- if _maybe_unlink_link_dir():
- printer(
- _("However, old link directory symlink found; removed.\n"))
- return results
-
- _maybe_unlink_link_dir()
-
- # make the link directory parent dirs if necessary
- if not os.path.lexists(link_parent_dir):
- os.makedirs(link_parent_dir)
-
- os.symlink(
- theme['assets_dir'].rstrip(os.path.sep),
- link_dir)
- printer("Linked the theme's asset directory:\n %s\nto:\n %s\n" % (
- theme['assets_dir'], link_dir))
-
-
-def install_theme(install_dir, themefile):
- pass # TODO ;)
-
-
-#############
-# Subcommands
-#############
-
-def assetlink_command(args):
- """
- Link the asset directory of the currently installed theme
- """
- global_config, app_config = setup_global_and_app_config(args.conf_file)
- theme_registry, current_theme = register_themes(app_config)
- link_assets(current_theme, app_config['theme_linked_assets_dir'])
-
-
-def install_command(args):
- """
- Handle the 'install this theme' subcommand
- """
- global_config, app_config = setup_global_and_app_config(args.conf_file)
- install_dir = app_config['theme_install_dir']
- install_theme(install_dir, args.themefile)
-
-
-SUBCOMMANDS = {
- 'assetlink': assetlink_command,
- 'install': install_command}
-
-
-def theme(args):
- SUBCOMMANDS[args.subcommand](args)
diff --git a/mediagoblin/gmg_commands/users.py b/mediagoblin/gmg_commands/users.py
index 024c8498..e44b0aa9 100644
--- a/mediagoblin/gmg_commands/users.py
+++ b/mediagoblin/gmg_commands/users.py
@@ -15,7 +15,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from mediagoblin.gmg_commands import util as commands_util
-from mediagoblin.auth import lib as auth_lib
+from mediagoblin import auth
from mediagoblin import mg_globals
def adduser_parser_setup(subparser):
@@ -40,9 +40,9 @@ def adduser(args):
db = mg_globals.database
users_with_username = \
- db.User.find({
- 'username': args.username.lower(),
- }).count()
+ db.User.query.filter_by(
+ username=args.username.lower()
+ ).count()
if users_with_username:
print u'Sorry, a user with that name already exists.'
@@ -52,7 +52,7 @@ def adduser(args):
entry = db.User()
entry.username = unicode(args.username.lower())
entry.email = unicode(args.email)
- entry.pw_hash = auth_lib.bcrypt_gen_password_hash(args.password)
+ entry.pw_hash = auth.gen_password_hash(args.password)
entry.status = u'active'
entry.email_verified = True
entry.save()
@@ -71,7 +71,8 @@ def makeadmin(args):
db = mg_globals.database
- user = db.User.one({'username': unicode(args.username.lower())})
+ user = db.User.query.filter_by(
+ username=unicode(args.username.lower())).one()
if user:
user.is_admin = True
user.save()
@@ -94,9 +95,10 @@ def changepw(args):
db = mg_globals.database
- user = db.User.one({'username': unicode(args.username.lower())})
+ user = db.User.query.filter_by(
+ username=unicode(args.username.lower())).one()
if user:
- user.pw_hash = auth_lib.bcrypt_gen_password_hash(args.password)
+ user.pw_hash = auth.gen_password_hash(args.password)
user.save()
print 'Password successfully changed'
else:
diff --git a/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.mo
index 5e69858e..543830c8 100644
--- a/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.mo
+++ b/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.mo
Binary files differ
diff --git a/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.po
index 51c71c3a..1f086613 100644
--- a/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.po
+++ b/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.po
@@ -3,18 +3,19 @@
# This file is distributed under the same license as the PROJECT project.
#
# Translators:
-# Majid Al-Dharrab <majid@aldharrab.com>, 2011.
-# Mena Rezk Eid <minaeid90@gmail.com>, 2013.
-# <Omar.w.kh@gmail.com>, 2011.
-# <osamak@gnu.org>, 2011.
+# Jiyda <jiydam@gmail.com>, 2013
+# Majid Al-Dharrab <majid@aldharrab.com>, 2011
+# minaeid90 <minaeid90@gmail.com>, 2013
+# OmarKH <Omar.w.kh@gmail.com>, 2011
+# OsamaK <osamak@gnu.org>, 2011
msgid ""
msgstr ""
"Project-Id-Version: GNU MediaGoblin\n"
"Report-Msgid-Bugs-To: http://issues.mediagoblin.org/\n"
-"POT-Creation-Date: 2013-03-04 18:04-0600\n"
-"PO-Revision-Date: 2013-03-05 00:04+0000\n"
+"POT-Creation-Date: 2013-05-27 13:54-0500\n"
+"PO-Revision-Date: 2013-05-27 18:54+0000\n"
"Last-Translator: cwebber <cwebber@dustycloud.org>\n"
-"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language-Team: Arabic (http://www.transifex.com/projects/p/mediagoblin/language/ar/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
@@ -22,34 +23,39 @@ msgstr ""
"Language: ar\n"
"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n"
-#: mediagoblin/auth/forms.py:28
-msgid "Invalid User name or email address."
-msgstr ""
-
-#: mediagoblin/auth/forms.py:29
-msgid "This field does not take email addresses."
-msgstr ""
-
-#: mediagoblin/auth/forms.py:30
-msgid "This field requires an email address."
-msgstr ""
-
-#: mediagoblin/auth/forms.py:52 mediagoblin/auth/forms.py:67
+#: mediagoblin/auth/forms.py:26
msgid "Username"
msgstr "اسم المستخدم"
-#: mediagoblin/auth/forms.py:56 mediagoblin/auth/forms.py:71
+#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:45
+#: mediagoblin/tests/test_util.py:110
msgid "Password"
msgstr "كلمة السر"
-#: mediagoblin/auth/forms.py:60
+#: mediagoblin/auth/forms.py:34
msgid "Email address"
msgstr "عنوان البريد الإلكتروني"
-#: mediagoblin/auth/forms.py:78
-msgid "Username or email"
+#: mediagoblin/auth/forms.py:41
+msgid "Username or Email"
msgstr ""
+#: mediagoblin/auth/forms.py:52
+msgid "Username or email"
+msgstr "اسم المستخدم او الايميل"
+
+#: mediagoblin/auth/tools.py:31
+msgid "Invalid User name or email address."
+msgstr "اسم مستخدم او ايميل غير صحيح."
+
+#: mediagoblin/auth/tools.py:32
+msgid "This field does not take email addresses."
+msgstr "هذا الحقل لا يأخذ ايميل."
+
+#: mediagoblin/auth/tools.py:33
+msgid "This field requires an email address."
+msgstr "هذا الحقل يحتاج ايميل."
+
#: mediagoblin/auth/views.py:54
msgid "Sorry, registration is disabled on this instance."
msgstr "عÙوًا، التسجيل غير متاح هنا."
@@ -60,56 +66,56 @@ msgstr "عذرًا، لقد اختار مستخدم آخر هذا الاسم."
#: mediagoblin/auth/views.py:72
msgid "Sorry, a user with that email address already exists."
-msgstr ""
+msgstr "عذرًا، لقد اختار مستخدم آخر هذا الايميل."
-#: mediagoblin/auth/views.py:174
+#: mediagoblin/auth/views.py:182
msgid ""
"Your email address has been verified. You may now login, edit your profile, "
"and submit images!"
msgstr "تم التحقق من بريدك الإلكتروني. يمكنك الآن الولوج، وتحرير ملÙÙƒ الشخصي، ونشر الصور!"
-#: mediagoblin/auth/views.py:180
+#: mediagoblin/auth/views.py:188
msgid "The verification key or user id is incorrect"
msgstr "Ù…ÙØªØ§Ø­ التحقق أو معر٠المستخدم خاطئ"
-#: mediagoblin/auth/views.py:198
+#: mediagoblin/auth/views.py:206
msgid "You must be logged in so we know who to send the email to!"
msgstr "يجب عليك تسجيل الدخول لإرسال بريد الكترونى لك!"
-#: mediagoblin/auth/views.py:206
+#: mediagoblin/auth/views.py:214
msgid "You've already verified your email address!"
msgstr "لقد قمت Ø¨Ø§Ù„ÙØ¹Ù„ بالتحقق من عنوان البريد الإلكتروني الخاص بك!"
-#: mediagoblin/auth/views.py:219
+#: mediagoblin/auth/views.py:227
msgid "Resent your verification email."
msgstr "أعدنا إرسال رسالة التحقق."
-#: mediagoblin/auth/views.py:250
+#: mediagoblin/auth/views.py:258
msgid ""
"If that email address (case sensitive!) is registered an email has been sent"
" with instructions on how to change your password."
-msgstr ""
+msgstr "إذا كان هذا الايميل(حساس للحرو٠الكبيرة والصغيرة!) Ù…ÙØ³Ø¬Ù„, Ùقد تم إرسال ايميل به تعليمات عن كيÙية تغيير رقمك السري."
-#: mediagoblin/auth/views.py:261
+#: mediagoblin/auth/views.py:269
msgid "Couldn't find someone with that username."
-msgstr ""
+msgstr "لم نتمكن من العثور على أحد له أسم المستخدم هذا."
-#: mediagoblin/auth/views.py:264
+#: mediagoblin/auth/views.py:272
msgid ""
"An email has been sent with instructions on how to change your password."
-msgstr ""
+msgstr "لقد تم إرسال ايميل به تعليمات عن كيÙية تغيير رقمك السري."
-#: mediagoblin/auth/views.py:271
+#: mediagoblin/auth/views.py:279
msgid ""
"Could not send password recovery email as your username is inactive or your "
"account's email address has not been verified."
msgstr "تعذر إرسال رسالة استعادة كلمة السر لأن اسم المستخدم معطل أو لأننا لم نتحقق من بريدك الإلكتروني."
-#: mediagoblin/auth/views.py:328
+#: mediagoblin/auth/views.py:336
msgid "You can now log in using your new password."
-msgstr ""
+msgstr "تستطيع الآن الدخول باستخدام رقمك السري الجديد."
-#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:93
+#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:82
#: mediagoblin/submit/forms.py:28 mediagoblin/submit/forms.py:47
#: mediagoblin/user_pages/forms.py:45
msgid "Title"
@@ -120,13 +126,13 @@ msgid "Description of this work"
msgstr "وص٠هذا العمل."
#: mediagoblin/edit/forms.py:29 mediagoblin/edit/forms.py:52
-#: mediagoblin/edit/forms.py:97 mediagoblin/submit/forms.py:32
+#: mediagoblin/edit/forms.py:86 mediagoblin/submit/forms.py:32
#: mediagoblin/submit/forms.py:51 mediagoblin/user_pages/forms.py:49
msgid ""
"You can use\n"
" <a href=\"http://daringfireball.net/projects/markdown/basics\">\n"
" Markdown</a> for formatting."
-msgstr ""
+msgstr "بامكانك استخدام âŽ\n<a href=\"http://daringfireball.net/projects/markdown/basics\">âŽ\nMarkdown</a> للإدراج."
#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:36
msgid "Tags"
@@ -134,13 +140,13 @@ msgstr "الوسوم"
#: mediagoblin/edit/forms.py:35 mediagoblin/submit/forms.py:38
msgid "Separate tags by commas."
-msgstr ""
+msgstr "قم Ø¨ÙØµÙ„ المحددات Ø¨ÙØµÙ„Ø©."
-#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:101
+#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:90
msgid "Slug"
msgstr "المسار"
-#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:102
+#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:91
msgid "The slug can't be empty"
msgstr "لا يمكن ترك المسار ÙØ§Ø±ØºÙ‹Ø§"
@@ -148,12 +154,12 @@ msgstr "لا يمكن ترك المسار ÙØ§Ø±ØºÙ‹Ø§"
msgid ""
"The title part of this media's address. You usually don't need to change "
"this."
-msgstr ""
+msgstr "مقدمة عنوان هذه الميديا, غالبا لن تحتاج لتغيره."
#: mediagoblin/edit/forms.py:44 mediagoblin/submit/forms.py:41
#: mediagoblin/templates/mediagoblin/utils/license.html:20
msgid "License"
-msgstr ""
+msgstr "ترخيص"
#: mediagoblin/edit/forms.py:50
msgid "Bio"
@@ -165,48 +171,48 @@ msgstr "الموقع الإلكتروني"
#: mediagoblin/edit/forms.py:58
msgid "This address contains errors"
-msgstr ""
+msgstr "العنوان يحتوي على اخطاء"
#: mediagoblin/edit/forms.py:63
-msgid "Old password"
-msgstr ""
-
-#: mediagoblin/edit/forms.py:64
-msgid "Enter your old password to prove you own this account."
-msgstr ""
-
-#: mediagoblin/edit/forms.py:67
-msgid "New password"
-msgstr ""
-
-#: mediagoblin/edit/forms.py:74
msgid "License preference"
-msgstr ""
+msgstr "ØªÙØ¶ÙŠÙ„ رخصة"
-#: mediagoblin/edit/forms.py:80
+#: mediagoblin/edit/forms.py:69
msgid "This will be your default license on upload forms."
-msgstr ""
+msgstr "سو٠تكون هذه رخصتك المبدئية ÙÙŠ نماذج التحميل."
-#: mediagoblin/edit/forms.py:82
+#: mediagoblin/edit/forms.py:71
msgid "Email me when others comment on my media"
-msgstr ""
+msgstr "ارسل لي رسالة عندما يقوم الاخرون بالتعليق على الميديا خاصتي"
-#: mediagoblin/edit/forms.py:94
+#: mediagoblin/edit/forms.py:83
msgid "The title can't be empty"
-msgstr ""
+msgstr "لا يمكن ترك العنوان ÙØ§Ø±ØºÙ‹Ø§"
-#: mediagoblin/edit/forms.py:96 mediagoblin/submit/forms.py:50
+#: mediagoblin/edit/forms.py:85 mediagoblin/submit/forms.py:50
#: mediagoblin/user_pages/forms.py:48
msgid "Description of this collection"
-msgstr ""
+msgstr "وص٠هذه المجموعة"
-#: mediagoblin/edit/forms.py:103
+#: mediagoblin/edit/forms.py:92
msgid ""
"The title part of this collection's address. You usually don't need to "
"change this."
-msgstr ""
+msgstr "مقدمة عنوان هذه المجموعة, غالبا لن تحتاج لتغيره."
+
+#: mediagoblin/edit/forms.py:99
+msgid "Old password"
+msgstr " كلمة السر القديمة"
-#: mediagoblin/edit/views.py:66
+#: mediagoblin/edit/forms.py:101
+msgid "Enter your old password to prove you own this account."
+msgstr "قم بإدخال رقمك السري القديم حتى تثبت انك صاحب هذا الحساب."
+
+#: mediagoblin/edit/forms.py:104
+msgid "New password"
+msgstr "رقم سري جديد"
+
+#: mediagoblin/edit/views.py:67
msgid "An entry with that slug already exists for this user."
msgstr "يوجد مل٠آخر بهذا المسار لدى هذى المستخدم."
@@ -217,11 +223,11 @@ msgstr "أنت تحرّر وسائط مستخدم آخر. كن حذرًا أثن
#: mediagoblin/edit/views.py:155
#, python-format
msgid "You added the attachment %s!"
-msgstr ""
+msgstr "لقد قمت Ø¨Ø¥Ø¶Ø§ÙØ© مرÙقة %s!"
#: mediagoblin/edit/views.py:182
msgid "You can only edit your own profile."
-msgstr ""
+msgstr "يمكنك Ùقط تعديل حسابك الخاص"
#: mediagoblin/edit/views.py:188
msgid "You are editing a user's profile. Proceed with caution."
@@ -229,44 +235,63 @@ msgstr "أنت تحرّر مل٠مستخدم آخر. كن حذرًا أثناء
#: mediagoblin/edit/views.py:204
msgid "Profile changes saved"
-msgstr ""
+msgstr "تم Ø­ÙØ¸ تغيرات حسابك"
-#: mediagoblin/edit/views.py:241
-msgid "Wrong password"
-msgstr "كلمة سر خاطئة"
-
-#: mediagoblin/edit/views.py:252
+#: mediagoblin/edit/views.py:240
msgid "Account settings saved"
-msgstr ""
+msgstr "تم Ø­ÙØ¸ خصائص حسابك"
-#: mediagoblin/edit/views.py:286
+#: mediagoblin/edit/views.py:274
msgid "You need to confirm the deletion of your account."
-msgstr ""
+msgstr "يجب عليك تأكيد إلغاء حسابك."
-#: mediagoblin/edit/views.py:322 mediagoblin/submit/views.py:142
-#: mediagoblin/user_pages/views.py:214
+#: mediagoblin/edit/views.py:310 mediagoblin/submit/views.py:138
+#: mediagoblin/user_pages/views.py:222
#, python-format
msgid "You already have a collection called \"%s\"!"
-msgstr ""
+msgstr "أنت لديك مجموعة تدعى \"%s\"!"
-#: mediagoblin/edit/views.py:326
+#: mediagoblin/edit/views.py:314
msgid "A collection with that slug already exists for this user."
-msgstr ""
+msgstr "توجد مجموعة اخرى بهذا المسار لهذا المستخدم."
-#: mediagoblin/edit/views.py:343
+#: mediagoblin/edit/views.py:329
msgid "You are editing another user's collection. Proceed with caution."
+msgstr "أنت تعدل مجموعة مستخدم آخر. كن حذرًا أثناء العملية."
+
+#: mediagoblin/edit/views.py:348
+msgid "Wrong password"
+msgstr "كلمة سر خاطئة"
+
+#: mediagoblin/edit/views.py:363
+msgid "Your password was changed successfully"
msgstr ""
-#: mediagoblin/gmg_commands/theme.py:58
+#: mediagoblin/gmg_commands/assetlink.py:60
msgid "Cannot link theme... no theme set\n"
-msgstr ""
+msgstr "لم يتم ربط الثيم... لاتوجد مجموعة ثيمات\n"
-#: mediagoblin/gmg_commands/theme.py:71
+#: mediagoblin/gmg_commands/assetlink.py:73
msgid "No asset directory for this theme\n"
-msgstr ""
+msgstr "لا يوجد مسار جيد لهذا الثيم\n"
-#: mediagoblin/gmg_commands/theme.py:74
+#: mediagoblin/gmg_commands/assetlink.py:76
msgid "However, old link directory symlink found; removed.\n"
+msgstr "ولكن, الرابط القديم للمسار الذي تم ايجاده; Ø­ÙØ°Ù.\n"
+
+#: mediagoblin/gmg_commands/assetlink.py:112
+#, python-format
+msgid "Could not link \"%s\": %s exists and is not a symlink\n"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:119
+#, python-format
+msgid "Skipping \"%s\"; already set up.\n"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:124
+#, python-format
+msgid "Old link found for \"%s\"; removing.\n"
msgstr ""
#: mediagoblin/meddleware/csrf.py:134
@@ -274,55 +299,59 @@ msgid ""
"CSRF cookie not present. This is most likely the result of a cookie blocker "
"or somesuch.<br/>Make sure to permit the settings of cookies for this "
"domain."
-msgstr ""
+msgstr "CSRF كوكيز غير موجودة, وهذا من الممكن ان يكون نتيجة لمانع الكوكيز او شئ من هذا القبيل.<br/>تأكد من أنك قمت بالسماح لخصائص الكوكيز لهذا الميدان."
-#: mediagoblin/media_types/__init__.py:61
-#: mediagoblin/media_types/__init__.py:102
+#: mediagoblin/media_types/__init__.py:111
+#: mediagoblin/media_types/__init__.py:155
msgid "Sorry, I don't support that file type :("
+msgstr "عذرا, انا لا ادعم هذا النوع من Ø§Ù„Ù…Ù„ÙØ§Øª :("
+
+#: mediagoblin/media_types/pdf/processing.py:136
+msgid "unoconv failing to run, check log file"
msgstr ""
-#: mediagoblin/media_types/video/processing.py:36
+#: mediagoblin/media_types/video/processing.py:37
msgid "Video transcoding failed"
-msgstr ""
+msgstr "ÙØ´Ù„ ÙÙŠ تحويل الÙيديو"
#: mediagoblin/plugins/geolocation/templates/mediagoblin/plugins/geolocation/map.html:24
msgid "Location"
-msgstr ""
+msgstr "المكان"
#: mediagoblin/plugins/geolocation/templates/mediagoblin/plugins/geolocation/map.html:52
#, python-format
msgid "View on <a href=\"%(osm_url)s\">OpenStreetMap</a>"
-msgstr ""
+msgstr "عرض ÙÙŠ <a href=\"%(osm_url)s\">OpenStreetMap</a>"
#: mediagoblin/plugins/oauth/forms.py:29
msgid "Allow"
-msgstr ""
+msgstr "سماح"
#: mediagoblin/plugins/oauth/forms.py:30
msgid "Deny"
-msgstr ""
+msgstr "Ø±ÙØ¶"
#: mediagoblin/plugins/oauth/forms.py:34
msgid "Name"
-msgstr ""
+msgstr "الاسم"
#: mediagoblin/plugins/oauth/forms.py:35
msgid "The name of the OAuth client"
-msgstr ""
+msgstr "اسم العميل Ø§Ù„Ù…Ù†Ø´ÙØ¦"
#: mediagoblin/plugins/oauth/forms.py:36
msgid "Description"
-msgstr ""
+msgstr "الوصÙ"
#: mediagoblin/plugins/oauth/forms.py:38
msgid ""
"This will be visible to users allowing your\n"
" application to authenticate as them."
-msgstr ""
+msgstr "سو٠يكون هذا مرئي بالنسبة للمستخدمين حتى يتاح\nللبرنامج خاصتك بالتصديق عليهم."
#: mediagoblin/plugins/oauth/forms.py:40
msgid "Type"
-msgstr ""
+msgstr "النوع"
#: mediagoblin/plugins/oauth/forms.py:45
msgid ""
@@ -332,88 +361,88 @@ msgid ""
" <strong>Public</strong> - The client can't make confidential\n"
" requests to the GNU MediaGoblin instance (e.g. client-side\n"
" JavaScript client)."
-msgstr ""
+msgstr "<strong>سري</strong> - يستطيع العميل\nان يقوم بطلب نسخة من GNU MediaGoblin والتي من الممكن ان \nيعترضه وكيل المستخدم (مثلا الخادم من جانب العميل).<br />\n<strong>عام</strong> - لا يستطيع العميل ارسال طلبات سرية\nلنسخة من GNU MediaGoblin (مثلا \nخادم Ø§Ù„Ø¬Ø§ÙØ§ سكريبت من جانب العميل)."
#: mediagoblin/plugins/oauth/forms.py:52
msgid "Redirect URI"
-msgstr ""
+msgstr "تحويل لينك"
#: mediagoblin/plugins/oauth/forms.py:54
msgid ""
"The redirect URI for the applications, this field\n"
" is <strong>required</strong> for public clients."
-msgstr ""
+msgstr "الرابط الموجه للبرنامج, هذا الحقل\n<strong>مطلوب</strong> لجمهور العملاء."
#: mediagoblin/plugins/oauth/forms.py:66
msgid "This field is required for public clients"
-msgstr ""
+msgstr "هذا الحقل مطلوب لجمهور العملاء"
-#: mediagoblin/plugins/oauth/views.py:59
+#: mediagoblin/plugins/oauth/views.py:56
msgid "The client {0} has been registered!"
-msgstr ""
+msgstr "العميل {0} تم تسجيله!"
#: mediagoblin/plugins/oauth/templates/oauth/client/connections.html:22
msgid "OAuth client connections"
-msgstr ""
+msgstr "ارتباطات العميل المنشئ"
#: mediagoblin/plugins/oauth/templates/oauth/client/list.html:22
msgid "Your OAuth clients"
-msgstr ""
+msgstr "عميلك المنشئ"
#: mediagoblin/plugins/oauth/templates/oauth/client/register.html:29
#: mediagoblin/templates/mediagoblin/submit/collection.html:30
#: mediagoblin/templates/mediagoblin/submit/start.html:34
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:68
msgid "Add"
-msgstr ""
+msgstr "اضÙ"
-#: mediagoblin/processing/__init__.py:172
+#: mediagoblin/processing/__init__.py:193
msgid "Invalid file given for media type."
-msgstr ""
+msgstr "المل٠المعطى لهذا النوع من الميديا غير صحيح."
#: mediagoblin/submit/forms.py:26
msgid "File"
msgstr "الملÙ"
-#: mediagoblin/submit/views.py:51
+#: mediagoblin/submit/views.py:49
msgid "You must provide a file."
msgstr "يجب أن تضع ملÙًا."
-#: mediagoblin/submit/views.py:97
+#: mediagoblin/submit/views.py:93
msgid "Woohoo! Submitted!"
msgstr "يا سلام! Ù†ÙØ´Ø±ÙŽØª!"
-#: mediagoblin/submit/views.py:146
+#: mediagoblin/submit/views.py:144
#, python-format
msgid "Collection \"%s\" added!"
-msgstr ""
+msgstr "تم Ø¥Ø¶Ø§ÙØ© المجموعة \"%s\"!"
-#: mediagoblin/templates/mediagoblin/base.html:64
+#: mediagoblin/templates/mediagoblin/base.html:67
msgid "Verify your email!"
msgstr "تأكد من بريدك الإلكترونى!"
-#: mediagoblin/templates/mediagoblin/base.html:65
+#: mediagoblin/templates/mediagoblin/base.html:68
msgid "log out"
-msgstr ""
+msgstr "تسجيل خروج"
-#: mediagoblin/templates/mediagoblin/base.html:70
+#: mediagoblin/templates/mediagoblin/base.html:73
#: mediagoblin/templates/mediagoblin/auth/login.html:28
#: mediagoblin/templates/mediagoblin/auth/login.html:36
#: mediagoblin/templates/mediagoblin/auth/login.html:54
msgid "Log in"
msgstr "تسجيل دخول"
-#: mediagoblin/templates/mediagoblin/base.html:79
+#: mediagoblin/templates/mediagoblin/base.html:82
#, python-format
msgid "<a href=\"%(user_url)s\">%(user_name)s</a>'s account"
-msgstr ""
+msgstr "<a href=\"%(user_url)s\">%(user_name)s</a>'s حساب"
-#: mediagoblin/templates/mediagoblin/base.html:86
+#: mediagoblin/templates/mediagoblin/base.html:89
msgid "Change account settings"
-msgstr ""
+msgstr "تغيير خصائص الحساب"
-#: mediagoblin/templates/mediagoblin/base.html:90
-#: mediagoblin/templates/mediagoblin/base.html:105
+#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:108
#: mediagoblin/templates/mediagoblin/admin/panel.html:21
#: mediagoblin/templates/mediagoblin/admin/panel.html:26
#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:21
@@ -421,79 +450,32 @@ msgstr ""
msgid "Media processing panel"
msgstr "لوحة معالجة الوسائط"
-#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:96
msgid "Log out"
-msgstr ""
+msgstr "تسجيل خروج"
-#: mediagoblin/templates/mediagoblin/base.html:96
+#: mediagoblin/templates/mediagoblin/base.html:99
#: mediagoblin/templates/mediagoblin/user_pages/user.html:156
msgid "Add media"
msgstr "أض٠وسائط"
-#: mediagoblin/templates/mediagoblin/base.html:99
+#: mediagoblin/templates/mediagoblin/base.html:102
#: mediagoblin/templates/mediagoblin/user_pages/collection_list.html:41
msgid "Create new collection"
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/base.html:122
-#, python-format
-msgid ""
-"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
-"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/base.html:125
-#, python-format
-msgid ""
-"Released under the <a "
-"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
-"href=\"%(source_link)s\">Source code</a> available."
-msgstr ""
+msgstr "إنشاء مجموعة جديدة"
#: mediagoblin/templates/mediagoblin/error.html:24
msgid "Image of goblin stressing out"
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:31
-msgid "Explore"
-msgstr "استكشÙ"
-
-#: mediagoblin/templates/mediagoblin/root.html:33
-msgid "Hi there, welcome to this MediaGoblin site!"
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:35
-msgid ""
-"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
-"extraordinarily great piece of media hosting software."
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:36
-msgid ""
-"To add your own media, place comments, and more, you can log in with your "
-"MediaGoblin account."
-msgstr ""
+msgstr "صورة قزم مرتبك"
-#: mediagoblin/templates/mediagoblin/root.html:38
-msgid "Don't have one yet? It's easy!"
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:39
-#, python-format
-msgid ""
-"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
-" or\n"
-" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:47
+#: mediagoblin/templates/mediagoblin/root.html:32
msgid "Most recent media"
msgstr "أحدث الوسائط"
#: mediagoblin/templates/mediagoblin/admin/panel.html:29
msgid ""
"Here you can track the state of media being processed on this instance."
-msgstr ""
+msgstr "يمكنك متابعة عملية معالجة وسائط معرضك من هنا."
#: mediagoblin/templates/mediagoblin/admin/panel.html:32
#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:32
@@ -513,34 +495,34 @@ msgstr "ÙØ´Ù„ت معالجة هذه Ø§Ù„Ù…Ù„ÙØ§Øª:"
#: mediagoblin/templates/mediagoblin/admin/panel.html:90
#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:86
msgid "No failed entries!"
-msgstr ""
+msgstr "لا توجد مداخل ÙØ§Ø´Ù„Ø©!"
#: mediagoblin/templates/mediagoblin/admin/panel.html:92
msgid "Last 10 successful uploads"
-msgstr ""
+msgstr "آخر 10 تحويلات ناجحة"
#: mediagoblin/templates/mediagoblin/admin/panel.html:112
#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:107
msgid "No processed entries, yet!"
-msgstr ""
+msgstr "لا يوجد مداخل Ù…ÙØ¹Ø§Ù„جة بعد! "
#: mediagoblin/templates/mediagoblin/auth/change_fp.html:28
#: mediagoblin/templates/mediagoblin/auth/change_fp.html:36
msgid "Set your new password"
-msgstr ""
+msgstr "قم بضبط رقمك السري الجديد"
#: mediagoblin/templates/mediagoblin/auth/change_fp.html:39
msgid "Set password"
-msgstr ""
+msgstr "قم بضبط رقم سري"
#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:23
#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:31
msgid "Recover password"
-msgstr ""
+msgstr "استعادة كلمة السر"
#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:34
msgid "Send instructions"
-msgstr ""
+msgstr "ارسل تعليمات"
#: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19
#, python-format
@@ -592,6 +574,53 @@ msgid ""
"%(verification_url)s"
msgstr "أهلًا يا %(username)sØŒ\n\nØ§ÙØªØ­ الرابط التالي\nÙÙŠ Ù…ØªØµÙØ­Ùƒ Ù„ØªÙØ¹ÙŠÙ„ حسابك ÙÙŠ غنو ميدياغوبلن:\n\n%(verification_url)s"
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:21
+#, python-format
+msgid ""
+"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
+"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
+msgstr "برعاية <a href=\"http://mediagoblin.org/\" title='Version %(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> مشروع."
+
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:24
+#, python-format
+msgid ""
+"Released under the <a "
+"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
+"href=\"%(source_link)s\">Source code</a> available."
+msgstr "تم النشر ÙˆÙقا Ù„ <a href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a href=\"%(source_link)s\">Source code</a> متاح."
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:20
+msgid "Explore"
+msgstr "استكشÙ"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:22
+msgid "Hi there, welcome to this MediaGoblin site!"
+msgstr "اهلا, مرحبا بك ÙÙŠ موقع MediaGoblin."
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:24
+msgid ""
+"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
+"extraordinarily great piece of media hosting software."
+msgstr "هذا الموقع يقوم بتشغيل <a href=\"http://mediagoblin.org\">MediaGoblin</a>, وهو برنامج Ø§Ø³ØªØ¶Ø§ÙØ© ميديا ÙØ§Ø¦Ù‚ الروعة."
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:25
+msgid ""
+"To add your own media, place comments, and more, you can log in with your "
+"MediaGoblin account."
+msgstr "لكي تضي٠الميديا خاصتك, تضع التعليقات, والمزيد, يجب عليك الدخول بحساب MediaGoblin الخاص بك."
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:27
+msgid "Don't have one yet? It's easy!"
+msgstr "ليس لديك واحد حتى الآن؟ انه سهل!"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:28
+#, python-format
+msgid ""
+"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
+" or\n"
+" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/bits/logo.html:23
#: mediagoblin/themes/airy/templates/mediagoblin/bits/logo.html:23
msgid "MediaGoblin logo"
@@ -601,18 +630,18 @@ msgstr "شعار ميدياغوبلن"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:35
#, python-format
msgid "Editing attachments for %(media_title)s"
-msgstr ""
+msgstr "تعديل المرÙقات Ù„ %(media_title)s"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:159
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:175
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:182
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:198
msgid "Attachments"
-msgstr ""
+msgstr "مرÙقات"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:57
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:181
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:204
msgid "Add attachment"
-msgstr ""
+msgstr "أض٠مرÙقة"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:61
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:42
@@ -627,26 +656,36 @@ msgstr "ألغÙ"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:63
#: mediagoblin/templates/mediagoblin/edit/edit.html:42
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:52
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:55
#: mediagoblin/templates/mediagoblin/edit/edit_collection.html:33
#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:40
msgid "Save changes"
msgstr "Ø§Ø­ÙØ¸ التغييرات"
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:28
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:38
+#, python-format
+msgid "Changing %(username)s's password"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:45
+msgid "Save"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:28
#, python-format
msgid "Really delete user '%(user_name)s' and all related media/comments?"
-msgstr ""
+msgstr "هل تريد ÙØ¹Ù„ا إلغاء المستخدم '%(user_name)s' وكل الميديا/التعليقات المتعلقة به؟"
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:35
msgid "Yes, really delete my account"
-msgstr ""
+msgstr "نعم, قم بإلغاء حسابي"
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:47
+#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:48
#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:49
msgid "Delete permanently"
-msgstr ""
+msgstr "احذ٠نهائيًا"
#: mediagoblin/templates/mediagoblin/edit/edit.html:23
#: mediagoblin/templates/mediagoblin/edit/edit.html:35
@@ -658,11 +697,15 @@ msgstr "تحرير %(media_title)s"
#: mediagoblin/templates/mediagoblin/edit/edit_account.html:40
#, python-format
msgid "Changing %(username)s's account settings"
+msgstr "نغيير %(username)s خصائص الحساب"
+
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:46
+msgid "Change your password."
msgstr ""
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:59
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:62
msgid "Delete my account"
-msgstr ""
+msgstr "إلغ٠حسابي"
#: mediagoblin/templates/mediagoblin/edit/edit_collection.html:29
#, python-format
@@ -681,42 +724,45 @@ msgstr "تحرير مل٠%(username)s الشخصي"
#: mediagoblin/templates/mediagoblin/listings/tag.html:35
#, python-format
msgid "Media tagged with: %(tag_name)s"
-msgstr ""
+msgstr "يتم تحديد الميديا ب: %(tag_name)s"
#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:56
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:65
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:136
#: mediagoblin/templates/mediagoblin/media_displays/video.html:55
msgid "Download"
-msgstr ""
+msgstr "تحميل"
#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:38
msgid "Original"
-msgstr ""
+msgstr "أصلي"
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:44
msgid ""
"Sorry, this audio will not work because \n"
"\tyour web browser does not support HTML5 \n"
"\taudio."
-msgstr ""
+msgstr "عذرا, لن يتم تشغيل الصوت لأن âŽ\nÂ»Ù…ØªØµÙØ­Ùƒ لا يدعم HTML5 âŽ\n»صوتيا."
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:47
msgid ""
"You can get a modern web browser that \n"
"\tcan play the audio at <a href=\"http://getfirefox.com\">\n"
"\t http://getfirefox.com</a>!"
-msgstr ""
+msgstr "تستطيع الحصول على Ù…ØªØµÙØ­ حديث âŽ\n»يمكنه تشغيل الصوت ÙÙŠ <a href=\"http://getfirefox.com\">âŽ\n» http://getfirefox.com</a>!"
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:60
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:71
#: mediagoblin/templates/mediagoblin/media_displays/video.html:61
msgid "Original file"
-msgstr ""
+msgstr "مل٠أصلي"
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:63
msgid "WebM file (Vorbis codec)"
-msgstr ""
+msgstr "مل٠WebM (Vorbic كوديك)"
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:59
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:87
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:93
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:99
@@ -725,65 +771,69 @@ msgstr ""
#: mediagoblin/templates/mediagoblin/user_pages/media.html:65
#, python-format
msgid "Image for %(media_title)s"
+msgstr "صورة ل%(media_title)s"
+
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:79
+msgid "PDF file"
msgstr ""
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:112
msgid "Toggle Rotate"
-msgstr ""
+msgstr "تبديل التدوير"
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:113
msgid "Perspective"
-msgstr ""
+msgstr "منظور"
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:116
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:117
msgid "Front"
-msgstr ""
+msgstr "مقدمة"
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:120
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:121
msgid "Top"
-msgstr ""
+msgstr "أعلى"
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:124
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:125
msgid "Side"
-msgstr ""
+msgstr "جانب"
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:130
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:131
msgid "WebGL"
-msgstr ""
+msgstr "WebGL"
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:138
msgid "Download model"
-msgstr ""
+msgstr "تحميل نموذج"
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:146
msgid "File Format"
-msgstr ""
+msgstr "بنية الملÙ"
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:148
msgid "Object Height"
-msgstr ""
+msgstr "طول الكائن"
#: mediagoblin/templates/mediagoblin/media_displays/video.html:44
msgid ""
"Sorry, this video will not work because\n"
" your web browser does not support HTML5 \n"
" video."
-msgstr ""
+msgstr "عذرا, لن يتم تشغيل هذا الÙيديو لأن âŽ\nÂ»Ù…ØªØµÙØ­Ùƒ لا يدعم HTML5 âŽ\n»Ùيديو."
#: mediagoblin/templates/mediagoblin/media_displays/video.html:47
msgid ""
"You can get a modern web browser that \n"
" can play this video at <a href=\"http://getfirefox.com\">\n"
" http://getfirefox.com</a>!"
-msgstr ""
+msgstr "تستطيع الحصول على Ù…ØªØµÙØ­ حديث âŽ\n»يمكنه تشغيل هذا الÙيديو ÙÙŠ <a href=\"http://getfirefox.com\">âŽ\n» http://getfirefox.com</a>!"
#: mediagoblin/templates/mediagoblin/media_displays/video.html:69
msgid "WebM file (640p; VP8/Vorbis)"
-msgstr ""
+msgstr "WebM مل٠(640p; VP8/Vorbis)"
#: mediagoblin/templates/mediagoblin/submit/collection.html:26
msgid "Add a collection"
@@ -792,27 +842,27 @@ msgstr "Ø¥Ø¶Ø§ÙØ© مجموعة"
#: mediagoblin/templates/mediagoblin/submit/start.html:23
#: mediagoblin/templates/mediagoblin/submit/start.html:30
msgid "Add your media"
-msgstr ""
+msgstr "اض٠الميديا الخاصة بك"
#: mediagoblin/templates/mediagoblin/user_pages/collection.html:30
#, python-format
msgid "%(collection_title)s (%(username)s's collection)"
-msgstr ""
+msgstr "%(collection_title)s (%(username)s's مجموعة)"
#: mediagoblin/templates/mediagoblin/user_pages/collection.html:39
#, python-format
msgid "%(collection_title)s by <a href=\"%(user_url)s\">%(username)s</a>"
-msgstr ""
+msgstr "%(collection_title)s بواسطة <a href=\"%(user_url)s\">%(username)s</a>"
#: mediagoblin/templates/mediagoblin/user_pages/collection.html:52
#: mediagoblin/templates/mediagoblin/user_pages/media.html:79
msgid "Edit"
-msgstr ""
+msgstr "تعديل"
#: mediagoblin/templates/mediagoblin/user_pages/collection.html:56
#: mediagoblin/templates/mediagoblin/user_pages/media.html:83
msgid "Delete"
-msgstr ""
+msgstr "إلغاء"
#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:30
#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30
@@ -823,40 +873,40 @@ msgstr "أتود حقًا حذ٠%(title)s?"
#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:31
#, python-format
msgid "Really remove %(media_title)s from %(collection_title)s?"
-msgstr ""
+msgstr "هل تريد ÙØ¹Ù„ا إلغاء %(media_title)s من %(collection_title)s?"
-#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:53
+#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:54
msgid "Remove"
-msgstr ""
+msgstr "إلغاء"
#: mediagoblin/templates/mediagoblin/user_pages/collection_list.html:21
#, python-format
msgid "%(username)s's collections"
-msgstr ""
+msgstr "%(username)s's مجموعات"
#: mediagoblin/templates/mediagoblin/user_pages/collection_list.html:28
#, python-format
msgid "<a href=\"%(user_url)s\">%(username)s</a>'s collections"
-msgstr ""
+msgstr "<a href=\"%(user_url)s\">%(username)s</a>'s مجموعات"
#: mediagoblin/templates/mediagoblin/user_pages/comment_email.txt:19
#, python-format
msgid ""
"Hi %(username)s,\n"
"%(comment_author)s commented on your post (%(comment_url)s) at %(instance_name)s\n"
-msgstr ""
+msgstr "اهلا, %(username)s,\n%(comment_author)s قام بالتعليق على مشاركتك (%(comment_url)s) ÙÙŠ %(instance_name)s\n"
#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30
#, python-format
msgid "%(username)s's media"
-msgstr ""
+msgstr "%(username)s ميديا"
#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:38
#, python-format
msgid ""
"<a href=\"%(user_url)s\">%(username)s</a>'s media with tag <a "
"href=\"%(tag_url)s\">%(tag)s</a>"
-msgstr ""
+msgstr "<a href=\"%(user_url)s\">\n%(username)s\n</a>\n's ميديا بالمحدد\n<a href=\"%(tag_url)s\">\n%(tag)s\n</a>"
#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:48
#, python-format
@@ -866,40 +916,44 @@ msgstr "وسائط <a href=\"%(user_url)s\">%(username)s</a>"
#: mediagoblin/templates/mediagoblin/user_pages/media.html:38
#, python-format
msgid "â– Browsing media by <a href=\"%(user_url)s\">%(username)s</a>"
-msgstr ""
+msgstr "■اختيار الميديا بواسطة <a href=\"%(user_url)s\">%(username)s</a>"
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:94
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:95
msgid "Add a comment"
-msgstr ""
+msgstr "أض٠تعليق"
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:102
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:104
msgid "Add this comment"
+msgstr "اض٠هذا التعليق"
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:132
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:152
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:164
+#, python-format
+msgid "%(formatted_time)s ago"
msgstr ""
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:123
-msgid "at"
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:150
+msgid "Added"
msgstr ""
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:144
-#, python-format
-msgid ""
-"<h3>Added on</h3>\n"
-" <p>%(date)s</p>"
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:161
+msgid "Created"
msgstr ""
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:28
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:40
#, python-format
msgid "Add “%(media_title)s†to a collection"
-msgstr ""
+msgstr "Ø¥Ø¶Ø§ÙØ© “%(media_title)s†لمجموعة"
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:54
msgid "+"
-msgstr ""
+msgstr "+"
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:58
msgid "Add a new collection"
-msgstr ""
+msgstr "Ø¥Ø¶Ø§ÙØ© مجموعة جديدة"
#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:29
msgid ""
@@ -908,7 +962,7 @@ msgstr "يمكنك متابعة عملية معالجة وسائط معرضك م
#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:89
msgid "Your last 10 successful uploads"
-msgstr ""
+msgstr "آخر 10 تحميلات ناجحة خاصة بك"
#: mediagoblin/templates/mediagoblin/user_pages/user.html:31
#: mediagoblin/templates/mediagoblin/user_pages/user.html:89
@@ -970,7 +1024,7 @@ msgstr "لم يعبئ هذا العضو بيانات ملÙÙ‡ بعد."
#: mediagoblin/templates/mediagoblin/user_pages/user.html:124
msgid "Browse collections"
-msgstr ""
+msgstr "تحديد مجموعة"
#: mediagoblin/templates/mediagoblin/user_pages/user.html:137
#, python-format
@@ -991,59 +1045,59 @@ msgstr "لا يبدو أنه توجد أي وسائط هنا حتى الآن..."
#: mediagoblin/templates/mediagoblin/utils/collection_gallery.html:49
msgid "(remove)"
-msgstr ""
+msgstr "(إلغاء)"
#: mediagoblin/templates/mediagoblin/utils/collections.html:21
msgid "Collected in"
-msgstr ""
+msgstr "تم تجميعه ÙÙŠ"
#: mediagoblin/templates/mediagoblin/utils/collections.html:40
msgid "Add to a collection"
-msgstr ""
+msgstr "Ø¥Ø¶Ø§ÙØ© مجموعة"
#: mediagoblin/templates/mediagoblin/utils/feed_link.html:21
#: mediagoblin/themes/airy/templates/mediagoblin/utils/feed_link.html:21
msgid "feed icon"
-msgstr ""
+msgstr "ايقونة تغذية"
#: mediagoblin/templates/mediagoblin/utils/feed_link.html:23
#: mediagoblin/themes/airy/templates/mediagoblin/utils/feed_link.html:23
msgid "Atom feed"
-msgstr ""
+msgstr "تغذية ذرية"
#: mediagoblin/templates/mediagoblin/utils/license.html:25
msgid "All rights reserved"
-msgstr ""
+msgstr "جميع الحقوق محÙوظة"
#: mediagoblin/templates/mediagoblin/utils/pagination.html:39
msgid "↠Newer"
-msgstr ""
+msgstr "اجددâ†"
#: mediagoblin/templates/mediagoblin/utils/pagination.html:45
msgid "Older →"
-msgstr ""
+msgstr "→اقدم"
#: mediagoblin/templates/mediagoblin/utils/pagination.html:48
msgid "Go to page:"
-msgstr ""
+msgstr "اذهب إلى ØµÙØ­Ø©:"
#: mediagoblin/templates/mediagoblin/utils/prev_next.html:28
#: mediagoblin/templates/mediagoblin/utils/prev_next.html:33
msgid "newer"
-msgstr ""
+msgstr "اجدد"
#: mediagoblin/templates/mediagoblin/utils/prev_next.html:39
#: mediagoblin/templates/mediagoblin/utils/prev_next.html:44
msgid "older"
-msgstr ""
+msgstr "اقدم"
#: mediagoblin/templates/mediagoblin/utils/tags.html:20
msgid "Tagged with"
-msgstr ""
+msgstr "تحدد ب"
-#: mediagoblin/tools/exif.py:80
+#: mediagoblin/tools/exif.py:83
msgid "Could not read the image file."
-msgstr ""
+msgstr "لم نستطيع قراءة هذه الصورة."
#: mediagoblin/tools/response.py:35
msgid "Oops!"
@@ -1051,36 +1105,60 @@ msgstr "ويحي!"
#: mediagoblin/tools/response.py:36
msgid "An error occured"
-msgstr ""
+msgstr "حدث خطأ"
#: mediagoblin/tools/response.py:51
msgid "Operation not allowed"
-msgstr ""
+msgstr "غير مسموح بهذه العملية"
#: mediagoblin/tools/response.py:52
msgid ""
"Sorry Dave, I can't let you do that!</p><p>You have tried to perform a "
"function that you are not allowed to. Have you been trying to delete all "
"user accounts again?"
-msgstr ""
+msgstr "عذرا ديÙ, لا استطيع ترك ØªÙØ¹Ù„ هذا!</p><p>لقد حاولت تشغيل خاصية ليست مسموحة لك. هل كنت تحاول إلغاء جميع حسابات المستخدمين مجددا؟"
#: mediagoblin/tools/response.py:60
msgid ""
"There doesn't seem to be a page at this address. Sorry!</p><p>If you're sure"
" the address is correct, maybe the page you're looking for has been moved or"
" deleted."
+msgstr "يبدو أنه لا توجد ØµÙØ­Ø© بهذا العنوان, عذرا</p><p>إذا كنت متأكد من صحة العنوان, من الممكن أن تكون Ø§Ù„ØµÙØ­Ø© التي تبحث عنها قد تم نقلها أو إلغاءها."
+
+#: mediagoblin/tools/timesince.py:62
+msgid "year"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:63
+msgid "month"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:64
+msgid "week"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:65
+msgid "day"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:66
+msgid "hour"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:67
+msgid "minute"
msgstr ""
#: mediagoblin/user_pages/forms.py:23
msgid "Comment"
-msgstr ""
+msgstr "تعليق"
#: mediagoblin/user_pages/forms.py:25
msgid ""
"You can use <a "
"href=\"http://daringfireball.net/projects/markdown/basics\">Markdown</a> for"
" formatting."
-msgstr ""
+msgstr "بامكانك استخدام <a href=\"http://daringfireball.net/projects/markdown/basics\">Markdown</a> للإدراج."
#: mediagoblin/user_pages/forms.py:31
msgid "I am sure I want to delete this"
@@ -1088,87 +1166,91 @@ msgstr "أنا متأكد من رغبتي بحذ٠هذا العمل"
#: mediagoblin/user_pages/forms.py:35
msgid "I am sure I want to remove this item from the collection"
-msgstr ""
+msgstr "أنا متأكد من أنني أريد إلغاء هذه المادة من المجموعة"
#: mediagoblin/user_pages/forms.py:39
msgid "Collection"
-msgstr ""
+msgstr "مجموعة"
#: mediagoblin/user_pages/forms.py:40
msgid "-- Select --"
-msgstr ""
+msgstr "-- إختار --"
#: mediagoblin/user_pages/forms.py:42
msgid "Include a note"
-msgstr ""
+msgstr "إدراج ملاحظة"
-#: mediagoblin/user_pages/lib.py:56
+#: mediagoblin/user_pages/lib.py:58
msgid "commented on your post"
+msgstr "قام بالتعليق على مشاركتك"
+
+#: mediagoblin/user_pages/views.py:169
+msgid "Sorry, comments are disabled."
msgstr ""
-#: mediagoblin/user_pages/views.py:166
+#: mediagoblin/user_pages/views.py:174
msgid "Oops, your comment was empty."
-msgstr ""
+msgstr "عذرا, لقد قمت بادخال تعليق ÙØ§Ø±Øº."
-#: mediagoblin/user_pages/views.py:172
+#: mediagoblin/user_pages/views.py:180
msgid "Your comment has been posted!"
-msgstr ""
+msgstr "لقد تم إرسال تعليقك!"
-#: mediagoblin/user_pages/views.py:197
+#: mediagoblin/user_pages/views.py:205
msgid "Please check your entries and try again."
-msgstr ""
+msgstr "من ÙØ¶Ù„Ùƒ قم Ø¨ÙØ­Øµ المداخل وقم بالمحاولة مرة أخرى."
-#: mediagoblin/user_pages/views.py:237
+#: mediagoblin/user_pages/views.py:245
msgid "You have to select or add a collection"
-msgstr ""
+msgstr "يجب عليك إختيار أو Ø¥Ø¶Ø§ÙØ© مجموعة"
-#: mediagoblin/user_pages/views.py:248
+#: mediagoblin/user_pages/views.py:256
#, python-format
msgid "\"%s\" already in collection \"%s\""
-msgstr ""
+msgstr "\"%s\" توجد Ø¨Ø§Ù„ÙØ¹Ù„ ÙÙŠ المجموعة \"%s\""
-#: mediagoblin/user_pages/views.py:264
+#: mediagoblin/user_pages/views.py:262
#, python-format
msgid "\"%s\" added to collection \"%s\""
-msgstr ""
+msgstr "\"%s\" Ø£ÙØ¶ÙŠÙت للمجموعة \"%s\""
-#: mediagoblin/user_pages/views.py:286
+#: mediagoblin/user_pages/views.py:282
msgid "You deleted the media."
-msgstr ""
+msgstr "لقد قمت بإلغاء الميديا."
-#: mediagoblin/user_pages/views.py:293
+#: mediagoblin/user_pages/views.py:289
msgid "The media was not deleted because you didn't check that you were sure."
-msgstr ""
+msgstr "لم يتم إلغاء الميديا لأنك لم تقم بإختيار انك متأكد من ذلك."
-#: mediagoblin/user_pages/views.py:301
+#: mediagoblin/user_pages/views.py:296
msgid "You are about to delete another user's media. Proceed with caution."
msgstr "أنت على وشك حذ٠وسائط مستخدم آخر. كن حذرًا أثناء العملية."
-#: mediagoblin/user_pages/views.py:375
+#: mediagoblin/user_pages/views.py:370
msgid "You deleted the item from the collection."
-msgstr ""
+msgstr "لقد قمت بإلغاء المادة من المجموعة."
-#: mediagoblin/user_pages/views.py:379
+#: mediagoblin/user_pages/views.py:374
msgid "The item was not removed because you didn't check that you were sure."
-msgstr ""
+msgstr "لم يتم إلغاء المادة لأنك لم تقم بإختيار انك متأكد من ذلك."
-#: mediagoblin/user_pages/views.py:389
+#: mediagoblin/user_pages/views.py:382
msgid ""
"You are about to delete an item from another user's collection. Proceed with"
" caution."
-msgstr ""
+msgstr "أنت على وشك حذ٠مادة من مجموعة مستخدم آخر. كن حذرا."
-#: mediagoblin/user_pages/views.py:422
+#: mediagoblin/user_pages/views.py:415
#, python-format
msgid "You deleted the collection \"%s\""
-msgstr ""
+msgstr "لقد قمت بإلغاء المجموعة \"%s\""
-#: mediagoblin/user_pages/views.py:429
+#: mediagoblin/user_pages/views.py:422
msgid ""
"The collection was not deleted because you didn't check that you were sure."
-msgstr ""
+msgstr "لم يتم إلغاء المجموعة لأنك لم تقم بإختيار انك متأكد من ذلك."
-#: mediagoblin/user_pages/views.py:439
+#: mediagoblin/user_pages/views.py:430
msgid ""
"You are about to delete another user's collection. Proceed with caution."
-msgstr ""
+msgstr "أنت على وشك حذ٠مجموعة مستخدم آخر. كن حذرا."
diff --git a/mediagoblin/i18n/ca/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ca/LC_MESSAGES/mediagoblin.mo
index 495ef726..ec01d7f7 100644
--- a/mediagoblin/i18n/ca/LC_MESSAGES/mediagoblin.mo
+++ b/mediagoblin/i18n/ca/LC_MESSAGES/mediagoblin.mo
Binary files differ
diff --git a/mediagoblin/i18n/ca/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ca/LC_MESSAGES/mediagoblin.po
index 28bdca82..9ebbdf18 100644
--- a/mediagoblin/i18n/ca/LC_MESSAGES/mediagoblin.po
+++ b/mediagoblin/i18n/ca/LC_MESSAGES/mediagoblin.po
@@ -3,17 +3,17 @@
# This file is distributed under the same license as the PROJECT project.
#
# Translators:
-# Al fred <devaleitzer@aim.com>, 2011.
-# <devaleitzer@aim.com>, 2011.
-# <skarbat@gmail.com>, 2012.
+# Al fred <devaleitzer@aim.com>, 2011
+# Al fred <devaleitzer@aim.com>, 2011
+# skarbat <skarbat@gmail.com>, 2012
msgid ""
msgstr ""
"Project-Id-Version: GNU MediaGoblin\n"
"Report-Msgid-Bugs-To: http://issues.mediagoblin.org/\n"
-"POT-Creation-Date: 2013-03-04 18:04-0600\n"
-"PO-Revision-Date: 2013-03-05 00:04+0000\n"
+"POT-Creation-Date: 2013-05-27 13:54-0500\n"
+"PO-Revision-Date: 2013-05-27 18:54+0000\n"
"Last-Translator: cwebber <cwebber@dustycloud.org>\n"
-"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language-Team: Catalan (http://www.transifex.com/projects/p/mediagoblin/language/ca/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
@@ -21,34 +21,39 @@ msgstr ""
"Language: ca\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: mediagoblin/auth/forms.py:28
-msgid "Invalid User name or email address."
-msgstr ""
-
-#: mediagoblin/auth/forms.py:29
-msgid "This field does not take email addresses."
-msgstr ""
-
-#: mediagoblin/auth/forms.py:30
-msgid "This field requires an email address."
-msgstr ""
-
-#: mediagoblin/auth/forms.py:52 mediagoblin/auth/forms.py:67
+#: mediagoblin/auth/forms.py:26
msgid "Username"
msgstr "Nom d'usuari"
-#: mediagoblin/auth/forms.py:56 mediagoblin/auth/forms.py:71
+#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:45
+#: mediagoblin/tests/test_util.py:110
msgid "Password"
msgstr "Contrasenya"
-#: mediagoblin/auth/forms.py:60
+#: mediagoblin/auth/forms.py:34
msgid "Email address"
msgstr "Adreça electrònica"
-#: mediagoblin/auth/forms.py:78
+#: mediagoblin/auth/forms.py:41
+msgid "Username or Email"
+msgstr ""
+
+#: mediagoblin/auth/forms.py:52
msgid "Username or email"
msgstr "Nom d'usuari o correu"
+#: mediagoblin/auth/tools.py:31
+msgid "Invalid User name or email address."
+msgstr ""
+
+#: mediagoblin/auth/tools.py:32
+msgid "This field does not take email addresses."
+msgstr ""
+
+#: mediagoblin/auth/tools.py:33
+msgid "This field requires an email address."
+msgstr ""
+
#: mediagoblin/auth/views.py:54
msgid "Sorry, registration is disabled on this instance."
msgstr "Ho sentim, el registre està desactivat en aquest cas."
@@ -61,54 +66,54 @@ msgstr "Lamentablement aquest usuari ja existeix."
msgid "Sorry, a user with that email address already exists."
msgstr "Perdó, ja existeix un usuari amb aquesta adreça de correu."
-#: mediagoblin/auth/views.py:174
+#: mediagoblin/auth/views.py:182
msgid ""
"Your email address has been verified. You may now login, edit your profile, "
"and submit images!"
msgstr "Ja s'ha verificat la vostra adreça electrònica. Ara podeu entrar, editar el vostre perfil i penjar imatge!"
-#: mediagoblin/auth/views.py:180
+#: mediagoblin/auth/views.py:188
msgid "The verification key or user id is incorrect"
msgstr "La clau de verificació o la identificació de l'usuari no són correctes."
-#: mediagoblin/auth/views.py:198
+#: mediagoblin/auth/views.py:206
msgid "You must be logged in so we know who to send the email to!"
msgstr "Has d'estar conectat per saber a qui hem d'enviar el correu!"
-#: mediagoblin/auth/views.py:206
+#: mediagoblin/auth/views.py:214
msgid "You've already verified your email address!"
msgstr "Ja has verificat la teva adreça de correu!"
-#: mediagoblin/auth/views.py:219
+#: mediagoblin/auth/views.py:227
msgid "Resent your verification email."
msgstr "Torna'm a enviar el correu de verificació"
-#: mediagoblin/auth/views.py:250
+#: mediagoblin/auth/views.py:258
msgid ""
"If that email address (case sensitive!) is registered an email has been sent"
" with instructions on how to change your password."
msgstr ""
-#: mediagoblin/auth/views.py:261
+#: mediagoblin/auth/views.py:269
msgid "Couldn't find someone with that username."
msgstr ""
-#: mediagoblin/auth/views.py:264
+#: mediagoblin/auth/views.py:272
msgid ""
"An email has been sent with instructions on how to change your password."
msgstr "S'ha enviat un correu amb instruccions de com cambiar la teva contrasenya"
-#: mediagoblin/auth/views.py:271
+#: mediagoblin/auth/views.py:279
msgid ""
"Could not send password recovery email as your username is inactive or your "
"account's email address has not been verified."
msgstr "No hem pogut enviar el correu de recuperació de contrasenya perquè el teu nom d'usuari és inactiu o bé l'adreça electrònica del teu compte no ha sigut verificada."
-#: mediagoblin/auth/views.py:328
+#: mediagoblin/auth/views.py:336
msgid "You can now log in using your new password."
msgstr "Ara et pots conectar amb la teva nova contrasenya."
-#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:93
+#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:82
#: mediagoblin/submit/forms.py:28 mediagoblin/submit/forms.py:47
#: mediagoblin/user_pages/forms.py:45
msgid "Title"
@@ -119,7 +124,7 @@ msgid "Description of this work"
msgstr "Descripció d'aquest treball."
#: mediagoblin/edit/forms.py:29 mediagoblin/edit/forms.py:52
-#: mediagoblin/edit/forms.py:97 mediagoblin/submit/forms.py:32
+#: mediagoblin/edit/forms.py:86 mediagoblin/submit/forms.py:32
#: mediagoblin/submit/forms.py:51 mediagoblin/user_pages/forms.py:49
msgid ""
"You can use\n"
@@ -135,11 +140,11 @@ msgstr "Etiquetes"
msgid "Separate tags by commas."
msgstr "Separa els tags amb comes."
-#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:101
+#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:90
msgid "Slug"
msgstr "Llimac"
-#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:102
+#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:91
msgid "The slug can't be empty"
msgstr "El llimac no pot ésser buit"
@@ -167,45 +172,45 @@ msgid "This address contains errors"
msgstr "Aquesta adreça conté errors"
#: mediagoblin/edit/forms.py:63
-msgid "Old password"
-msgstr "Contrasenya antiga"
-
-#: mediagoblin/edit/forms.py:64
-msgid "Enter your old password to prove you own this account."
-msgstr "Introdueix la teva contrasenya antiga per comprovar que aquest compte és teu."
-
-#: mediagoblin/edit/forms.py:67
-msgid "New password"
-msgstr "Nova contrasenya"
-
-#: mediagoblin/edit/forms.py:74
msgid "License preference"
msgstr ""
-#: mediagoblin/edit/forms.py:80
+#: mediagoblin/edit/forms.py:69
msgid "This will be your default license on upload forms."
msgstr ""
-#: mediagoblin/edit/forms.py:82
+#: mediagoblin/edit/forms.py:71
msgid "Email me when others comment on my media"
msgstr "Envia'm correu quan d'altres comentin al meu mitjà"
-#: mediagoblin/edit/forms.py:94
+#: mediagoblin/edit/forms.py:83
msgid "The title can't be empty"
msgstr "El títol no pot ser buit"
-#: mediagoblin/edit/forms.py:96 mediagoblin/submit/forms.py:50
+#: mediagoblin/edit/forms.py:85 mediagoblin/submit/forms.py:50
#: mediagoblin/user_pages/forms.py:48
msgid "Description of this collection"
msgstr "Descripció d'aquesta col.lecció"
-#: mediagoblin/edit/forms.py:103
+#: mediagoblin/edit/forms.py:92
msgid ""
"The title part of this collection's address. You usually don't need to "
"change this."
msgstr "La part del títol de l'adreça d'aquesta col.lecció. Normalment no cal que canviis això."
-#: mediagoblin/edit/views.py:66
+#: mediagoblin/edit/forms.py:99
+msgid "Old password"
+msgstr "Contrasenya antiga"
+
+#: mediagoblin/edit/forms.py:101
+msgid "Enter your old password to prove you own this account."
+msgstr "Introdueix la teva contrasenya antiga per comprovar que aquest compte és teu."
+
+#: mediagoblin/edit/forms.py:104
+msgid "New password"
+msgstr "Nova contrasenya"
+
+#: mediagoblin/edit/views.py:67
msgid "An entry with that slug already exists for this user."
msgstr "Ja existeix una entrada amb aquest llimac per aquest usuari"
@@ -230,44 +235,63 @@ msgstr "Esteu editant el perfil d'un usuari. Aneu amb compte"
msgid "Profile changes saved"
msgstr "Els canvis al perfil s'han guardat"
-#: mediagoblin/edit/views.py:241
-msgid "Wrong password"
-msgstr "Contrasenya errònia"
-
-#: mediagoblin/edit/views.py:252
+#: mediagoblin/edit/views.py:240
msgid "Account settings saved"
msgstr "Els detalls del compte s'han guardat"
-#: mediagoblin/edit/views.py:286
+#: mediagoblin/edit/views.py:274
msgid "You need to confirm the deletion of your account."
msgstr ""
-#: mediagoblin/edit/views.py:322 mediagoblin/submit/views.py:142
-#: mediagoblin/user_pages/views.py:214
+#: mediagoblin/edit/views.py:310 mediagoblin/submit/views.py:138
+#: mediagoblin/user_pages/views.py:222
#, python-format
msgid "You already have a collection called \"%s\"!"
msgstr "Ja tens una col.lecció anomenada \"%s\"!"
-#: mediagoblin/edit/views.py:326
+#: mediagoblin/edit/views.py:314
msgid "A collection with that slug already exists for this user."
msgstr ""
-#: mediagoblin/edit/views.py:343
+#: mediagoblin/edit/views.py:329
msgid "You are editing another user's collection. Proceed with caution."
msgstr "Estas editant la col.lecció d'un altre usuari. Prossegueix amb cautela."
-#: mediagoblin/gmg_commands/theme.py:58
+#: mediagoblin/edit/views.py:348
+msgid "Wrong password"
+msgstr "Contrasenya errònia"
+
+#: mediagoblin/edit/views.py:363
+msgid "Your password was changed successfully"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:60
msgid "Cannot link theme... no theme set\n"
msgstr "No es pot enllaçar el tema... no hi ha tema establert\n"
-#: mediagoblin/gmg_commands/theme.py:71
+#: mediagoblin/gmg_commands/assetlink.py:73
msgid "No asset directory for this theme\n"
msgstr ""
-#: mediagoblin/gmg_commands/theme.py:74
+#: mediagoblin/gmg_commands/assetlink.py:76
msgid "However, old link directory symlink found; removed.\n"
msgstr "Tot i així, l'enllaç antic al directori s'ha trobat; eliminat.\n"
+#: mediagoblin/gmg_commands/assetlink.py:112
+#, python-format
+msgid "Could not link \"%s\": %s exists and is not a symlink\n"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:119
+#, python-format
+msgid "Skipping \"%s\"; already set up.\n"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:124
+#, python-format
+msgid "Old link found for \"%s\"; removing.\n"
+msgstr ""
+
#: mediagoblin/meddleware/csrf.py:134
msgid ""
"CSRF cookie not present. This is most likely the result of a cookie blocker "
@@ -275,12 +299,16 @@ msgid ""
"domain."
msgstr ""
-#: mediagoblin/media_types/__init__.py:61
-#: mediagoblin/media_types/__init__.py:102
+#: mediagoblin/media_types/__init__.py:111
+#: mediagoblin/media_types/__init__.py:155
msgid "Sorry, I don't support that file type :("
msgstr "Ho sento, no puc manegar aquest tipus d'arxiu :("
-#: mediagoblin/media_types/video/processing.py:36
+#: mediagoblin/media_types/pdf/processing.py:136
+msgid "unoconv failing to run, check log file"
+msgstr ""
+
+#: mediagoblin/media_types/video/processing.py:37
msgid "Video transcoding failed"
msgstr "La transformació del vídeo ha fallat"
@@ -347,7 +375,7 @@ msgstr "La URI de redirecció per les aplicacions, aquest camp\n és
msgid "This field is required for public clients"
msgstr "Aquest camp és requeriment per a clients públics"
-#: mediagoblin/plugins/oauth/views.py:59
+#: mediagoblin/plugins/oauth/views.py:56
msgid "The client {0} has been registered!"
msgstr "El client {0} ha sigut enregistrat!"
@@ -366,7 +394,7 @@ msgstr ""
msgid "Add"
msgstr "Afegir"
-#: mediagoblin/processing/__init__.py:172
+#: mediagoblin/processing/__init__.py:193
msgid "Invalid file given for media type."
msgstr "Aquest tipus de fitxer no és vàlid."
@@ -374,45 +402,45 @@ msgstr "Aquest tipus de fitxer no és vàlid."
msgid "File"
msgstr "Fitxer"
-#: mediagoblin/submit/views.py:51
+#: mediagoblin/submit/views.py:49
msgid "You must provide a file."
msgstr "Heu d'escollir un fitxer."
-#: mediagoblin/submit/views.py:97
+#: mediagoblin/submit/views.py:93
msgid "Woohoo! Submitted!"
msgstr "Visca! S'ha enviat!"
-#: mediagoblin/submit/views.py:146
+#: mediagoblin/submit/views.py:144
#, python-format
msgid "Collection \"%s\" added!"
msgstr "S'ha afegit la col.leccio \"%s\"!"
-#: mediagoblin/templates/mediagoblin/base.html:64
+#: mediagoblin/templates/mediagoblin/base.html:67
msgid "Verify your email!"
msgstr "Verifica el teu correu electrònic"
-#: mediagoblin/templates/mediagoblin/base.html:65
+#: mediagoblin/templates/mediagoblin/base.html:68
msgid "log out"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:70
+#: mediagoblin/templates/mediagoblin/base.html:73
#: mediagoblin/templates/mediagoblin/auth/login.html:28
#: mediagoblin/templates/mediagoblin/auth/login.html:36
#: mediagoblin/templates/mediagoblin/auth/login.html:54
msgid "Log in"
msgstr "Entra"
-#: mediagoblin/templates/mediagoblin/base.html:79
+#: mediagoblin/templates/mediagoblin/base.html:82
#, python-format
msgid "<a href=\"%(user_url)s\">%(user_name)s</a>'s account"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:86
+#: mediagoblin/templates/mediagoblin/base.html:89
msgid "Change account settings"
msgstr "Modificar els ajustaments del compte"
-#: mediagoblin/templates/mediagoblin/base.html:90
-#: mediagoblin/templates/mediagoblin/base.html:105
+#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:108
#: mediagoblin/templates/mediagoblin/admin/panel.html:21
#: mediagoblin/templates/mediagoblin/admin/panel.html:26
#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:21
@@ -420,72 +448,25 @@ msgstr "Modificar els ajustaments del compte"
msgid "Media processing panel"
msgstr "Quadre de processament de fitxers"
-#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:96
msgid "Log out"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:96
+#: mediagoblin/templates/mediagoblin/base.html:99
#: mediagoblin/templates/mediagoblin/user_pages/user.html:156
msgid "Add media"
msgstr "Tots els fitxers"
-#: mediagoblin/templates/mediagoblin/base.html:99
+#: mediagoblin/templates/mediagoblin/base.html:102
#: mediagoblin/templates/mediagoblin/user_pages/collection_list.html:41
msgid "Create new collection"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:122
-#, python-format
-msgid ""
-"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
-"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/base.html:125
-#, python-format
-msgid ""
-"Released under the <a "
-"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
-"href=\"%(source_link)s\">Source code</a> available."
-msgstr "Alliberat segons la <a href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a href=\"%(source_link)s\">Codi font</a> disponible."
-
#: mediagoblin/templates/mediagoblin/error.html:24
msgid "Image of goblin stressing out"
msgstr ""
-#: mediagoblin/templates/mediagoblin/root.html:31
-msgid "Explore"
-msgstr "Explorar"
-
-#: mediagoblin/templates/mediagoblin/root.html:33
-msgid "Hi there, welcome to this MediaGoblin site!"
-msgstr "Hola, una benvinguda al MediaGoblin!"
-
-#: mediagoblin/templates/mediagoblin/root.html:35
-msgid ""
-"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
-"extraordinarily great piece of media hosting software."
-msgstr "El lloc esta usant <a href=\"http://mediagoblin.org\">MediaGoblin</a>, una gran i extraordinària peça de software per allotjar mitjans."
-
-#: mediagoblin/templates/mediagoblin/root.html:36
-msgid ""
-"To add your own media, place comments, and more, you can log in with your "
-"MediaGoblin account."
-msgstr "Per afegir el teu propi mitjà, col.locar comentaris, i més, pots conectar-te amb el teu compte MediaGoblin."
-
-#: mediagoblin/templates/mediagoblin/root.html:38
-msgid "Don't have one yet? It's easy!"
-msgstr "No en tens una encara? Es fàcil!"
-
-#: mediagoblin/templates/mediagoblin/root.html:39
-#, python-format
-msgid ""
-"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
-" or\n"
-" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
-msgstr "<a class=\"button_action_highlight\" href=\"%(register_url)s\">Crear un compte a aquest lloc</a> \no\n <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Preparar MediaGoblin al teu propi servidor</a>"
-
-#: mediagoblin/templates/mediagoblin/root.html:47
+#: mediagoblin/templates/mediagoblin/root.html:32
msgid "Most recent media"
msgstr "Mitjans més recents"
@@ -591,6 +572,53 @@ msgid ""
"%(verification_url)s"
msgstr "Hi %(username)s,\n\nto activate your GNU MediaGoblin account, open the following URL in\nyour web browser:\n\n%(verification_url)s"
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:21
+#, python-format
+msgid ""
+"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
+"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:24
+#, python-format
+msgid ""
+"Released under the <a "
+"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
+"href=\"%(source_link)s\">Source code</a> available."
+msgstr "Alliberat segons la <a href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a href=\"%(source_link)s\">Codi font</a> disponible."
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:20
+msgid "Explore"
+msgstr "Explorar"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:22
+msgid "Hi there, welcome to this MediaGoblin site!"
+msgstr "Hola, una benvinguda al MediaGoblin!"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:24
+msgid ""
+"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
+"extraordinarily great piece of media hosting software."
+msgstr "El lloc esta usant <a href=\"http://mediagoblin.org\">MediaGoblin</a>, una gran i extraordinària peça de software per allotjar mitjans."
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:25
+msgid ""
+"To add your own media, place comments, and more, you can log in with your "
+"MediaGoblin account."
+msgstr "Per afegir el teu propi mitjà, col.locar comentaris, i més, pots conectar-te amb el teu compte MediaGoblin."
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:27
+msgid "Don't have one yet? It's easy!"
+msgstr "No en tens una encara? Es fàcil!"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:28
+#, python-format
+msgid ""
+"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
+" or\n"
+" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/bits/logo.html:23
#: mediagoblin/themes/airy/templates/mediagoblin/bits/logo.html:23
msgid "MediaGoblin logo"
@@ -603,13 +631,13 @@ msgid "Editing attachments for %(media_title)s"
msgstr "Editant afegits per a %(media_title)s"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:159
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:175
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:182
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:198
msgid "Attachments"
msgstr ""
#: mediagoblin/templates/mediagoblin/edit/attachments.html:57
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:181
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:204
msgid "Add attachment"
msgstr ""
@@ -626,12 +654,22 @@ msgstr "Cancel·la"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:63
#: mediagoblin/templates/mediagoblin/edit/edit.html:42
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:52
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:55
#: mediagoblin/templates/mediagoblin/edit/edit_collection.html:33
#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:40
msgid "Save changes"
msgstr "Desa els canvis"
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:28
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:38
+#, python-format
+msgid "Changing %(username)s's password"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:45
+msgid "Save"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:28
#, python-format
msgid "Really delete user '%(user_name)s' and all related media/comments?"
@@ -642,7 +680,7 @@ msgid "Yes, really delete my account"
msgstr ""
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:47
+#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:48
#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:49
msgid "Delete permanently"
msgstr "Esborrar permanentment"
@@ -659,7 +697,11 @@ msgstr "Edició %(media_title)s "
msgid "Changing %(username)s's account settings"
msgstr "Modificant els detalls del compte de %(username)s"
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:59
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:46
+msgid "Change your password."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:62
msgid "Delete my account"
msgstr ""
@@ -684,6 +726,7 @@ msgstr "Mitjà marcat amb: %(tag_name)s"
#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:56
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:65
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:136
#: mediagoblin/templates/mediagoblin/media_displays/video.html:55
msgid "Download"
@@ -708,6 +751,7 @@ msgid ""
msgstr "Pots obtenir un navegador web modern que \n »podrà reproduir l'àudio, a <a href=\"http://getfirefox.com\">\n » http://getfirefox.com</a>!"
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:60
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:71
#: mediagoblin/templates/mediagoblin/media_displays/video.html:61
msgid "Original file"
msgstr "Arxiu original"
@@ -716,6 +760,7 @@ msgstr "Arxiu original"
msgid "WebM file (Vorbis codec)"
msgstr "Arxiu WebM (Vorbis codec)"
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:59
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:87
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:93
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:99
@@ -726,6 +771,10 @@ msgstr "Arxiu WebM (Vorbis codec)"
msgid "Image for %(media_title)s"
msgstr "Imatge per %(media_title)s"
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:79
+msgid "PDF file"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:112
msgid "Toggle Rotate"
msgstr ""
@@ -824,7 +873,7 @@ msgstr "Realment vols esborrar %(title)s?"
msgid "Really remove %(media_title)s from %(collection_title)s?"
msgstr "Relment eliminar %(media_title)s de %(collection_title)s?"
-#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:53
+#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:54
msgid "Remove"
msgstr "Eliminar"
@@ -867,24 +916,28 @@ msgstr "<a href=\"%(user_url)s\">%(username)s</a>'s media"
msgid "â– Browsing media by <a href=\"%(user_url)s\">%(username)s</a>"
msgstr "■Navegant mitjà per a <a href=\"%(user_url)s\">%(username)s</a>"
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:94
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:95
msgid "Add a comment"
msgstr "Afegeix un comentari"
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:102
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:104
msgid "Add this comment"
msgstr "Afegir aquest comentari"
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:123
-msgid "at"
-msgstr "a"
-
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:144
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:132
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:152
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:164
#, python-format
-msgid ""
-"<h3>Added on</h3>\n"
-" <p>%(date)s</p>"
-msgstr "<h3>Afegit el</h3>\n <p>%(date)s</p>"
+msgid "%(formatted_time)s ago"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:150
+msgid "Added"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:161
+msgid "Created"
+msgstr ""
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:28
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:40
@@ -1040,7 +1093,7 @@ msgstr "més antic"
msgid "Tagged with"
msgstr ""
-#: mediagoblin/tools/exif.py:80
+#: mediagoblin/tools/exif.py:83
msgid "Could not read the image file."
msgstr "No s'ha pogut llegir l'arxiu d'imatge"
@@ -1070,6 +1123,30 @@ msgid ""
" deleted."
msgstr ""
+#: mediagoblin/tools/timesince.py:62
+msgid "year"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:63
+msgid "month"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:64
+msgid "week"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:65
+msgid "day"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:66
+msgid "hour"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:67
+msgid "minute"
+msgstr ""
+
#: mediagoblin/user_pages/forms.py:23
msgid "Comment"
msgstr ""
@@ -1101,73 +1178,77 @@ msgstr "-- Sel.leccionar --"
msgid "Include a note"
msgstr "Incluir una nota"
-#: mediagoblin/user_pages/lib.py:56
+#: mediagoblin/user_pages/lib.py:58
msgid "commented on your post"
msgstr "comentat al teu post"
-#: mediagoblin/user_pages/views.py:166
+#: mediagoblin/user_pages/views.py:169
+msgid "Sorry, comments are disabled."
+msgstr ""
+
+#: mediagoblin/user_pages/views.py:174
msgid "Oops, your comment was empty."
msgstr "Uups, el teu comentari era buit."
-#: mediagoblin/user_pages/views.py:172
+#: mediagoblin/user_pages/views.py:180
msgid "Your comment has been posted!"
msgstr "El teu comentari s'ha publicat!"
-#: mediagoblin/user_pages/views.py:197
+#: mediagoblin/user_pages/views.py:205
msgid "Please check your entries and try again."
msgstr "Si et plau, comprova les teves entrades i intenta-ho de nou."
-#: mediagoblin/user_pages/views.py:237
+#: mediagoblin/user_pages/views.py:245
msgid "You have to select or add a collection"
msgstr "Has de sel.leccionar o afegir una col.lecció"
-#: mediagoblin/user_pages/views.py:248
+#: mediagoblin/user_pages/views.py:256
#, python-format
msgid "\"%s\" already in collection \"%s\""
msgstr "\"%s\" ja és a la col.lecció \"%s\""
-#: mediagoblin/user_pages/views.py:264
+#: mediagoblin/user_pages/views.py:262
#, python-format
msgid "\"%s\" added to collection \"%s\""
msgstr "\"%s\" afegir a la col.lecció \"%s\""
-#: mediagoblin/user_pages/views.py:286
+#: mediagoblin/user_pages/views.py:282
msgid "You deleted the media."
msgstr "Has esborrat el mitjà"
-#: mediagoblin/user_pages/views.py:293
+#: mediagoblin/user_pages/views.py:289
msgid "The media was not deleted because you didn't check that you were sure."
msgstr "El mitjà no s'ha esborrat perque no has marcat que n'estiguessis segur."
-#: mediagoblin/user_pages/views.py:301
+#: mediagoblin/user_pages/views.py:296
msgid "You are about to delete another user's media. Proceed with caution."
msgstr "Ets a punt d'esborrar el mitjà d'un altre usuari. Prossegueix amb cautela."
-#: mediagoblin/user_pages/views.py:375
+#: mediagoblin/user_pages/views.py:370
msgid "You deleted the item from the collection."
msgstr "Has esborrat l'element de la col.lecció"
-#: mediagoblin/user_pages/views.py:379
+#: mediagoblin/user_pages/views.py:374
msgid "The item was not removed because you didn't check that you were sure."
msgstr "L'element no s'ha eliminat perque no has marcat que n'estiguessis segur."
-#: mediagoblin/user_pages/views.py:389
+#: mediagoblin/user_pages/views.py:382
msgid ""
"You are about to delete an item from another user's collection. Proceed with"
" caution."
msgstr "Ets a punt d'esborrar un element de la col.lecció d'un altre usuari. Prossegueix amb cautela."
-#: mediagoblin/user_pages/views.py:422
+#: mediagoblin/user_pages/views.py:415
#, python-format
msgid "You deleted the collection \"%s\""
msgstr "Has esborrat la col.lecció \"%s\""
-#: mediagoblin/user_pages/views.py:429
+#: mediagoblin/user_pages/views.py:422
msgid ""
"The collection was not deleted because you didn't check that you were sure."
msgstr "La col.lecció no s'ha esborrat perquè no has marcat que n'estiguessis segur."
-#: mediagoblin/user_pages/views.py:439
+#: mediagoblin/user_pages/views.py:430
msgid ""
"You are about to delete another user's collection. Proceed with caution."
msgstr "Ets a punt d'esborrar la col.lecció d'un altre usuari. Prossegueix amb cautela."
diff --git a/mediagoblin/i18n/da/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/da/LC_MESSAGES/mediagoblin.mo
index 6b6827f0..53e3fedf 100644
--- a/mediagoblin/i18n/da/LC_MESSAGES/mediagoblin.mo
+++ b/mediagoblin/i18n/da/LC_MESSAGES/mediagoblin.mo
Binary files differ
diff --git a/mediagoblin/i18n/da/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/da/LC_MESSAGES/mediagoblin.po
index 8494aa60..c78c08ac 100644
--- a/mediagoblin/i18n/da/LC_MESSAGES/mediagoblin.po
+++ b/mediagoblin/i18n/da/LC_MESSAGES/mediagoblin.po
@@ -3,17 +3,17 @@
# This file is distributed under the same license as the PROJECT project.
#
# Translators:
-# Morten Juhl-Johansen Zölde-Fejér <morten@writtenandread.net>, 2012.
-# Olle Jonsson <olle.jonsson@gmail.com>, 2012.
-# Tanja Trudslev <tanja.trudslev@gmail.com>, 2012.
+# Morten Juhl-Johansen Zölde-Fejér <morten@writtenandread.net>, 2012
+# Olle Jonsson <olle.jonsson@gmail.com>, 2012
+# ttrudslev <tanja.trudslev@gmail.com>, 2012
msgid ""
msgstr ""
"Project-Id-Version: GNU MediaGoblin\n"
"Report-Msgid-Bugs-To: http://issues.mediagoblin.org/\n"
-"POT-Creation-Date: 2013-03-04 18:04-0600\n"
-"PO-Revision-Date: 2013-03-05 00:04+0000\n"
+"POT-Creation-Date: 2013-05-27 13:54-0500\n"
+"PO-Revision-Date: 2013-05-27 18:54+0000\n"
"Last-Translator: cwebber <cwebber@dustycloud.org>\n"
-"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language-Team: Danish (http://www.transifex.com/projects/p/mediagoblin/language/da/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
@@ -21,34 +21,39 @@ msgstr ""
"Language: da\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: mediagoblin/auth/forms.py:28
-msgid "Invalid User name or email address."
-msgstr ""
-
-#: mediagoblin/auth/forms.py:29
-msgid "This field does not take email addresses."
-msgstr ""
-
-#: mediagoblin/auth/forms.py:30
-msgid "This field requires an email address."
-msgstr ""
-
-#: mediagoblin/auth/forms.py:52 mediagoblin/auth/forms.py:67
+#: mediagoblin/auth/forms.py:26
msgid "Username"
msgstr "Brugernavn"
-#: mediagoblin/auth/forms.py:56 mediagoblin/auth/forms.py:71
+#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:45
+#: mediagoblin/tests/test_util.py:110
msgid "Password"
msgstr "Kodeord"
-#: mediagoblin/auth/forms.py:60
+#: mediagoblin/auth/forms.py:34
msgid "Email address"
msgstr "Email adresse"
-#: mediagoblin/auth/forms.py:78
+#: mediagoblin/auth/forms.py:41
+msgid "Username or Email"
+msgstr ""
+
+#: mediagoblin/auth/forms.py:52
msgid "Username or email"
msgstr "Brugernavn eller email"
+#: mediagoblin/auth/tools.py:31
+msgid "Invalid User name or email address."
+msgstr ""
+
+#: mediagoblin/auth/tools.py:32
+msgid "This field does not take email addresses."
+msgstr ""
+
+#: mediagoblin/auth/tools.py:33
+msgid "This field requires an email address."
+msgstr ""
+
#: mediagoblin/auth/views.py:54
msgid "Sorry, registration is disabled on this instance."
msgstr "Desværre, registrering er ikke muligt på denne instans"
@@ -61,54 +66,54 @@ msgstr "Desværre, det brugernavn er allerede brugt"
msgid "Sorry, a user with that email address already exists."
msgstr "Desværre, en bruger er allerede oprettet for den email"
-#: mediagoblin/auth/views.py:174
+#: mediagoblin/auth/views.py:182
msgid ""
"Your email address has been verified. You may now login, edit your profile, "
"and submit images!"
msgstr "Din email adresse er blevet bekræftet. Du kan nu logge på, ændre din profil, og indsende billeder!"
-#: mediagoblin/auth/views.py:180
+#: mediagoblin/auth/views.py:188
msgid "The verification key or user id is incorrect"
msgstr "Bekræftelsesnøglen eller brugerid er forkert"
-#: mediagoblin/auth/views.py:198
+#: mediagoblin/auth/views.py:206
msgid "You must be logged in so we know who to send the email to!"
msgstr "Du er nødt til at være logget ind, så vi ved hvem vi skal emaile!"
-#: mediagoblin/auth/views.py:206
+#: mediagoblin/auth/views.py:214
msgid "You've already verified your email address!"
msgstr "Du har allerede bekræftet din email adresse!"
-#: mediagoblin/auth/views.py:219
+#: mediagoblin/auth/views.py:227
msgid "Resent your verification email."
msgstr "Email til godkendelse sendt igen."
-#: mediagoblin/auth/views.py:250
+#: mediagoblin/auth/views.py:258
msgid ""
"If that email address (case sensitive!) is registered an email has been sent"
" with instructions on how to change your password."
msgstr ""
-#: mediagoblin/auth/views.py:261
+#: mediagoblin/auth/views.py:269
msgid "Couldn't find someone with that username."
msgstr ""
-#: mediagoblin/auth/views.py:264
+#: mediagoblin/auth/views.py:272
msgid ""
"An email has been sent with instructions on how to change your password."
msgstr "En email er blevet sendt med instruktioner til at ændre dit kodeord."
-#: mediagoblin/auth/views.py:271
+#: mediagoblin/auth/views.py:279
msgid ""
"Could not send password recovery email as your username is inactive or your "
"account's email address has not been verified."
msgstr "Vi kunne ikke sende en kodeords nulstillings email da dit brugernavn er inaktivt, eller din konto's email adresse er ikke blevet godkendt."
-#: mediagoblin/auth/views.py:328
+#: mediagoblin/auth/views.py:336
msgid "You can now log in using your new password."
msgstr "Du kan nu logge ind med dit nye kodeord."
-#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:93
+#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:82
#: mediagoblin/submit/forms.py:28 mediagoblin/submit/forms.py:47
#: mediagoblin/user_pages/forms.py:45
msgid "Title"
@@ -119,7 +124,7 @@ msgid "Description of this work"
msgstr "Beskrivelse af arbejdet"
#: mediagoblin/edit/forms.py:29 mediagoblin/edit/forms.py:52
-#: mediagoblin/edit/forms.py:97 mediagoblin/submit/forms.py:32
+#: mediagoblin/edit/forms.py:86 mediagoblin/submit/forms.py:32
#: mediagoblin/submit/forms.py:51 mediagoblin/user_pages/forms.py:49
msgid ""
"You can use\n"
@@ -135,11 +140,11 @@ msgstr "Tags"
msgid "Separate tags by commas."
msgstr "Separer tags med kommaer."
-#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:101
+#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:90
msgid "Slug"
msgstr ""
-#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:102
+#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:91
msgid "The slug can't be empty"
msgstr ""
@@ -167,45 +172,45 @@ msgid "This address contains errors"
msgstr "Denne adresse indeholder fejl"
#: mediagoblin/edit/forms.py:63
-msgid "Old password"
-msgstr "Gammelt kodeord"
-
-#: mediagoblin/edit/forms.py:64
-msgid "Enter your old password to prove you own this account."
-msgstr "Skriv dit gamle kodeord for at bevise det er din konto."
-
-#: mediagoblin/edit/forms.py:67
-msgid "New password"
-msgstr "Ny kodeord"
-
-#: mediagoblin/edit/forms.py:74
msgid "License preference"
msgstr ""
-#: mediagoblin/edit/forms.py:80
+#: mediagoblin/edit/forms.py:69
msgid "This will be your default license on upload forms."
msgstr ""
-#: mediagoblin/edit/forms.py:82
+#: mediagoblin/edit/forms.py:71
msgid "Email me when others comment on my media"
msgstr "Email mig når andre kommenterer på mine medier"
-#: mediagoblin/edit/forms.py:94
+#: mediagoblin/edit/forms.py:83
msgid "The title can't be empty"
msgstr "Titlen kan ikke være tom"
-#: mediagoblin/edit/forms.py:96 mediagoblin/submit/forms.py:50
+#: mediagoblin/edit/forms.py:85 mediagoblin/submit/forms.py:50
#: mediagoblin/user_pages/forms.py:48
msgid "Description of this collection"
msgstr "Beskrivelse af denne samling"
-#: mediagoblin/edit/forms.py:103
+#: mediagoblin/edit/forms.py:92
msgid ""
"The title part of this collection's address. You usually don't need to "
"change this."
msgstr "Titeldelen af denne samlings's adresse. Du behøver normalt ikke ændre dette."
-#: mediagoblin/edit/views.py:66
+#: mediagoblin/edit/forms.py:99
+msgid "Old password"
+msgstr "Gammelt kodeord"
+
+#: mediagoblin/edit/forms.py:101
+msgid "Enter your old password to prove you own this account."
+msgstr "Skriv dit gamle kodeord for at bevise det er din konto."
+
+#: mediagoblin/edit/forms.py:104
+msgid "New password"
+msgstr "Ny kodeord"
+
+#: mediagoblin/edit/views.py:67
msgid "An entry with that slug already exists for this user."
msgstr ""
@@ -230,44 +235,63 @@ msgstr "Du er ved at ændre en bruger's profil. Pas på."
msgid "Profile changes saved"
msgstr "Profilændringer gemt"
-#: mediagoblin/edit/views.py:241
-msgid "Wrong password"
-msgstr "Forkert kodeord"
-
-#: mediagoblin/edit/views.py:252
+#: mediagoblin/edit/views.py:240
msgid "Account settings saved"
msgstr "Kontoindstillinger gemt"
-#: mediagoblin/edit/views.py:286
+#: mediagoblin/edit/views.py:274
msgid "You need to confirm the deletion of your account."
msgstr ""
-#: mediagoblin/edit/views.py:322 mediagoblin/submit/views.py:142
-#: mediagoblin/user_pages/views.py:214
+#: mediagoblin/edit/views.py:310 mediagoblin/submit/views.py:138
+#: mediagoblin/user_pages/views.py:222
#, python-format
msgid "You already have a collection called \"%s\"!"
msgstr "Du har allerede en samling ved navn \"%s\"!"
-#: mediagoblin/edit/views.py:326
+#: mediagoblin/edit/views.py:314
msgid "A collection with that slug already exists for this user."
msgstr ""
-#: mediagoblin/edit/views.py:343
+#: mediagoblin/edit/views.py:329
msgid "You are editing another user's collection. Proceed with caution."
msgstr "Du er ved at ændre en anden bruger's samling. Pas på."
-#: mediagoblin/gmg_commands/theme.py:58
+#: mediagoblin/edit/views.py:348
+msgid "Wrong password"
+msgstr "Forkert kodeord"
+
+#: mediagoblin/edit/views.py:363
+msgid "Your password was changed successfully"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:60
msgid "Cannot link theme... no theme set\n"
msgstr "Kan ikke linke til tema... intet tema sat\n"
-#: mediagoblin/gmg_commands/theme.py:71
+#: mediagoblin/gmg_commands/assetlink.py:73
msgid "No asset directory for this theme\n"
msgstr ""
-#: mediagoblin/gmg_commands/theme.py:74
+#: mediagoblin/gmg_commands/assetlink.py:76
msgid "However, old link directory symlink found; removed.\n"
msgstr ""
+#: mediagoblin/gmg_commands/assetlink.py:112
+#, python-format
+msgid "Could not link \"%s\": %s exists and is not a symlink\n"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:119
+#, python-format
+msgid "Skipping \"%s\"; already set up.\n"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:124
+#, python-format
+msgid "Old link found for \"%s\"; removing.\n"
+msgstr ""
+
#: mediagoblin/meddleware/csrf.py:134
msgid ""
"CSRF cookie not present. This is most likely the result of a cookie blocker "
@@ -275,12 +299,16 @@ msgid ""
"domain."
msgstr ""
-#: mediagoblin/media_types/__init__.py:61
-#: mediagoblin/media_types/__init__.py:102
+#: mediagoblin/media_types/__init__.py:111
+#: mediagoblin/media_types/__init__.py:155
msgid "Sorry, I don't support that file type :("
msgstr "Desværre, jeg understøtter ikke den filtype :("
-#: mediagoblin/media_types/video/processing.py:36
+#: mediagoblin/media_types/pdf/processing.py:136
+msgid "unoconv failing to run, check log file"
+msgstr ""
+
+#: mediagoblin/media_types/video/processing.py:37
msgid "Video transcoding failed"
msgstr ""
@@ -347,7 +375,7 @@ msgstr ""
msgid "This field is required for public clients"
msgstr "Dette felt er nødvendigt for offentlige klienter"
-#: mediagoblin/plugins/oauth/views.py:59
+#: mediagoblin/plugins/oauth/views.py:56
msgid "The client {0} has been registered!"
msgstr "Klienten {0} er blevet registreret!"
@@ -366,7 +394,7 @@ msgstr ""
msgid "Add"
msgstr ""
-#: mediagoblin/processing/__init__.py:172
+#: mediagoblin/processing/__init__.py:193
msgid "Invalid file given for media type."
msgstr "Forkert fil for medietypen."
@@ -374,45 +402,45 @@ msgstr "Forkert fil for medietypen."
msgid "File"
msgstr "Fil"
-#: mediagoblin/submit/views.py:51
+#: mediagoblin/submit/views.py:49
msgid "You must provide a file."
msgstr "Du må give mig en fil"
-#: mediagoblin/submit/views.py:97
+#: mediagoblin/submit/views.py:93
msgid "Woohoo! Submitted!"
msgstr "Juhuu! Delt!"
-#: mediagoblin/submit/views.py:146
+#: mediagoblin/submit/views.py:144
#, python-format
msgid "Collection \"%s\" added!"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:64
+#: mediagoblin/templates/mediagoblin/base.html:67
msgid "Verify your email!"
msgstr "Bekræft din email!"
-#: mediagoblin/templates/mediagoblin/base.html:65
+#: mediagoblin/templates/mediagoblin/base.html:68
msgid "log out"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:70
+#: mediagoblin/templates/mediagoblin/base.html:73
#: mediagoblin/templates/mediagoblin/auth/login.html:28
#: mediagoblin/templates/mediagoblin/auth/login.html:36
#: mediagoblin/templates/mediagoblin/auth/login.html:54
msgid "Log in"
msgstr "Log ind"
-#: mediagoblin/templates/mediagoblin/base.html:79
+#: mediagoblin/templates/mediagoblin/base.html:82
#, python-format
msgid "<a href=\"%(user_url)s\">%(user_name)s</a>'s account"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:86
+#: mediagoblin/templates/mediagoblin/base.html:89
msgid "Change account settings"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:90
-#: mediagoblin/templates/mediagoblin/base.html:105
+#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:108
#: mediagoblin/templates/mediagoblin/admin/panel.html:21
#: mediagoblin/templates/mediagoblin/admin/panel.html:26
#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:21
@@ -420,72 +448,25 @@ msgstr ""
msgid "Media processing panel"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:96
msgid "Log out"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:96
+#: mediagoblin/templates/mediagoblin/base.html:99
#: mediagoblin/templates/mediagoblin/user_pages/user.html:156
msgid "Add media"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:99
+#: mediagoblin/templates/mediagoblin/base.html:102
#: mediagoblin/templates/mediagoblin/user_pages/collection_list.html:41
msgid "Create new collection"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:122
-#, python-format
-msgid ""
-"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
-"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/base.html:125
-#, python-format
-msgid ""
-"Released under the <a "
-"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
-"href=\"%(source_link)s\">Source code</a> available."
-msgstr ""
-
#: mediagoblin/templates/mediagoblin/error.html:24
msgid "Image of goblin stressing out"
msgstr ""
-#: mediagoblin/templates/mediagoblin/root.html:31
-msgid "Explore"
-msgstr "Udforsk"
-
-#: mediagoblin/templates/mediagoblin/root.html:33
-msgid "Hi there, welcome to this MediaGoblin site!"
-msgstr "Hey, velkommen til denne MediaGoblin side!"
-
-#: mediagoblin/templates/mediagoblin/root.html:35
-msgid ""
-"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
-"extraordinarily great piece of media hosting software."
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:36
-msgid ""
-"To add your own media, place comments, and more, you can log in with your "
-"MediaGoblin account."
-msgstr "For at tilføje dine egne medier, skrive kommentarer, og mere, du kan logge ind med din MediaGoblin konto."
-
-#: mediagoblin/templates/mediagoblin/root.html:38
-msgid "Don't have one yet? It's easy!"
-msgstr "Har du ikke en endnu? Det er let!"
-
-#: mediagoblin/templates/mediagoblin/root.html:39
-#, python-format
-msgid ""
-"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
-" or\n"
-" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:47
+#: mediagoblin/templates/mediagoblin/root.html:32
msgid "Most recent media"
msgstr ""
@@ -591,6 +572,53 @@ msgid ""
"%(verification_url)s"
msgstr ""
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:21
+#, python-format
+msgid ""
+"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
+"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:24
+#, python-format
+msgid ""
+"Released under the <a "
+"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
+"href=\"%(source_link)s\">Source code</a> available."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:20
+msgid "Explore"
+msgstr "Udforsk"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:22
+msgid "Hi there, welcome to this MediaGoblin site!"
+msgstr "Hey, velkommen til denne MediaGoblin side!"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:24
+msgid ""
+"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
+"extraordinarily great piece of media hosting software."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:25
+msgid ""
+"To add your own media, place comments, and more, you can log in with your "
+"MediaGoblin account."
+msgstr "For at tilføje dine egne medier, skrive kommentarer, og mere, du kan logge ind med din MediaGoblin konto."
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:27
+msgid "Don't have one yet? It's easy!"
+msgstr "Har du ikke en endnu? Det er let!"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:28
+#, python-format
+msgid ""
+"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
+" or\n"
+" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/bits/logo.html:23
#: mediagoblin/themes/airy/templates/mediagoblin/bits/logo.html:23
msgid "MediaGoblin logo"
@@ -603,13 +631,13 @@ msgid "Editing attachments for %(media_title)s"
msgstr ""
#: mediagoblin/templates/mediagoblin/edit/attachments.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:159
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:175
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:182
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:198
msgid "Attachments"
msgstr ""
#: mediagoblin/templates/mediagoblin/edit/attachments.html:57
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:181
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:204
msgid "Add attachment"
msgstr ""
@@ -626,12 +654,22 @@ msgstr "Afbryd"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:63
#: mediagoblin/templates/mediagoblin/edit/edit.html:42
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:52
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:55
#: mediagoblin/templates/mediagoblin/edit/edit_collection.html:33
#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:40
msgid "Save changes"
msgstr "Gem ændringer"
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:28
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:38
+#, python-format
+msgid "Changing %(username)s's password"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:45
+msgid "Save"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:28
#, python-format
msgid "Really delete user '%(user_name)s' and all related media/comments?"
@@ -642,7 +680,7 @@ msgid "Yes, really delete my account"
msgstr ""
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:47
+#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:48
#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:49
msgid "Delete permanently"
msgstr ""
@@ -659,7 +697,11 @@ msgstr ""
msgid "Changing %(username)s's account settings"
msgstr ""
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:59
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:46
+msgid "Change your password."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:62
msgid "Delete my account"
msgstr ""
@@ -684,6 +726,7 @@ msgstr ""
#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:56
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:65
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:136
#: mediagoblin/templates/mediagoblin/media_displays/video.html:55
msgid "Download"
@@ -708,6 +751,7 @@ msgid ""
msgstr ""
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:60
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:71
#: mediagoblin/templates/mediagoblin/media_displays/video.html:61
msgid "Original file"
msgstr ""
@@ -716,6 +760,7 @@ msgstr ""
msgid "WebM file (Vorbis codec)"
msgstr ""
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:59
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:87
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:93
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:99
@@ -726,6 +771,10 @@ msgstr ""
msgid "Image for %(media_title)s"
msgstr ""
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:79
+msgid "PDF file"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:112
msgid "Toggle Rotate"
msgstr ""
@@ -824,7 +873,7 @@ msgstr ""
msgid "Really remove %(media_title)s from %(collection_title)s?"
msgstr ""
-#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:53
+#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:54
msgid "Remove"
msgstr ""
@@ -867,23 +916,27 @@ msgstr ""
msgid "â– Browsing media by <a href=\"%(user_url)s\">%(username)s</a>"
msgstr ""
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:94
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:95
msgid "Add a comment"
msgstr ""
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:102
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:104
msgid "Add this comment"
msgstr ""
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:123
-msgid "at"
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:132
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:152
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:164
+#, python-format
+msgid "%(formatted_time)s ago"
msgstr ""
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:144
-#, python-format
-msgid ""
-"<h3>Added on</h3>\n"
-" <p>%(date)s</p>"
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:150
+msgid "Added"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:161
+msgid "Created"
msgstr ""
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:28
@@ -1040,7 +1093,7 @@ msgstr ""
msgid "Tagged with"
msgstr ""
-#: mediagoblin/tools/exif.py:80
+#: mediagoblin/tools/exif.py:83
msgid "Could not read the image file."
msgstr ""
@@ -1070,6 +1123,30 @@ msgid ""
" deleted."
msgstr ""
+#: mediagoblin/tools/timesince.py:62
+msgid "year"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:63
+msgid "month"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:64
+msgid "week"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:65
+msgid "day"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:66
+msgid "hour"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:67
+msgid "minute"
+msgstr ""
+
#: mediagoblin/user_pages/forms.py:23
msgid "Comment"
msgstr ""
@@ -1101,73 +1178,77 @@ msgstr ""
msgid "Include a note"
msgstr ""
-#: mediagoblin/user_pages/lib.py:56
+#: mediagoblin/user_pages/lib.py:58
msgid "commented on your post"
msgstr ""
-#: mediagoblin/user_pages/views.py:166
+#: mediagoblin/user_pages/views.py:169
+msgid "Sorry, comments are disabled."
+msgstr ""
+
+#: mediagoblin/user_pages/views.py:174
msgid "Oops, your comment was empty."
msgstr ""
-#: mediagoblin/user_pages/views.py:172
+#: mediagoblin/user_pages/views.py:180
msgid "Your comment has been posted!"
msgstr ""
-#: mediagoblin/user_pages/views.py:197
+#: mediagoblin/user_pages/views.py:205
msgid "Please check your entries and try again."
msgstr ""
-#: mediagoblin/user_pages/views.py:237
+#: mediagoblin/user_pages/views.py:245
msgid "You have to select or add a collection"
msgstr ""
-#: mediagoblin/user_pages/views.py:248
+#: mediagoblin/user_pages/views.py:256
#, python-format
msgid "\"%s\" already in collection \"%s\""
msgstr ""
-#: mediagoblin/user_pages/views.py:264
+#: mediagoblin/user_pages/views.py:262
#, python-format
msgid "\"%s\" added to collection \"%s\""
msgstr ""
-#: mediagoblin/user_pages/views.py:286
+#: mediagoblin/user_pages/views.py:282
msgid "You deleted the media."
msgstr ""
-#: mediagoblin/user_pages/views.py:293
+#: mediagoblin/user_pages/views.py:289
msgid "The media was not deleted because you didn't check that you were sure."
msgstr ""
-#: mediagoblin/user_pages/views.py:301
+#: mediagoblin/user_pages/views.py:296
msgid "You are about to delete another user's media. Proceed with caution."
msgstr ""
-#: mediagoblin/user_pages/views.py:375
+#: mediagoblin/user_pages/views.py:370
msgid "You deleted the item from the collection."
msgstr ""
-#: mediagoblin/user_pages/views.py:379
+#: mediagoblin/user_pages/views.py:374
msgid "The item was not removed because you didn't check that you were sure."
msgstr ""
-#: mediagoblin/user_pages/views.py:389
+#: mediagoblin/user_pages/views.py:382
msgid ""
"You are about to delete an item from another user's collection. Proceed with"
" caution."
msgstr ""
-#: mediagoblin/user_pages/views.py:422
+#: mediagoblin/user_pages/views.py:415
#, python-format
msgid "You deleted the collection \"%s\""
msgstr ""
-#: mediagoblin/user_pages/views.py:429
+#: mediagoblin/user_pages/views.py:422
msgid ""
"The collection was not deleted because you didn't check that you were sure."
msgstr ""
-#: mediagoblin/user_pages/views.py:439
+#: mediagoblin/user_pages/views.py:430
msgid ""
"You are about to delete another user's collection. Proceed with caution."
msgstr ""
diff --git a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo
index 5ae794fa..e2fcf85d 100644
--- a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo
+++ b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo
Binary files differ
diff --git a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po
index b3d82ee9..e2147070 100644
--- a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po
+++ b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po
@@ -3,26 +3,26 @@
# This file is distributed under the same license as the PROJECT project.
#
# Translators:
-# <benjamin@lebsanft.org>, 2011.
-# <cwebber@dustycloud.org>, 2011.
-# Elrond <elrond+mediagoblin.org@samba-tng.org>, 2011-2012.
-# Elrond <elrond+mediagoblin.org@samba-tng.org>, 2013.
-# <jakob.kramer@gmx.de>, 2011, 2012.
-# Jakob Kramer <jakob.kramer@gmx.de>, 2012-2013.
-# Jan-Christoph Borchardt <JanCBorchardt@fsfe.org>, 2011.
-# Jan-Christoph Borchardt <jan@unhosted.org>, 2011, 2012.
-# <kyoo@kyoo.ch>, 2011.
-# <mediagoblin.org@samba-tng.org>, 2011.
-# Rafael Maguiña <rafael.maguina@gmail.com>, 2011.
-# <sebastian@sspaeth.de>, 2012.
-# Vinzenz Vietzke <vietzke@b1-systems.de>, 2012.
-# Vinzenz Vietzke <vinz@fedoraproject.org>, 2011.
+# piratenpanda <benjamin@lebsanft.org>, 2011
+# cwebber <cwebber@dustycloud.org>, 2011
+# Elrond <elrond+mediagoblin.org@samba-tng.org>, 2011-2012
+# Elrond <elrond+mediagoblin.org@samba-tng.org>, 2013
+# Jakob Kramer <jakob.kramer@gmx.de>, 2011, 2012
+# Jakob Kramer <jakob.kramer@gmx.de>, 2012-2013
+# Jan-Christoph Borchardt <hey@jancborchardt.net>, 2011
+# Jan-Christoph Borchardt <hey@jancborchardt.net>, 2011, 2012
+# Keyzo <kyoo@kyoo.ch>, 2011
+# Elrond <elrond+mediagoblin.org@samba-tng.org>, 2011
+# Art O. Pal <artopal@fastmail.fm>, 2011
+# spaetz <sebastian@sspaeth.de>, 2012
+# Vinzenz Vietzke <vinz@vinzv.de>, 2012
+# Vinzenz Vietzke <vinz@vinzv.de>, 2011
msgid ""
msgstr ""
"Project-Id-Version: GNU MediaGoblin\n"
"Report-Msgid-Bugs-To: http://issues.mediagoblin.org/\n"
-"POT-Creation-Date: 2013-03-04 18:04-0600\n"
-"PO-Revision-Date: 2013-03-07 13:16+0000\n"
+"POT-Creation-Date: 2013-05-27 13:54-0500\n"
+"PO-Revision-Date: 2013-05-28 10:43+0000\n"
"Last-Translator: Elrond <elrond+mediagoblin.org@samba-tng.org>\n"
"Language-Team: German (http://www.transifex.com/projects/p/mediagoblin/language/de/)\n"
"MIME-Version: 1.0\n"
@@ -32,34 +32,39 @@ msgstr ""
"Language: de\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: mediagoblin/auth/forms.py:28
-msgid "Invalid User name or email address."
-msgstr "Ungültiger Benutzername oder E-Mail-Adresse."
-
-#: mediagoblin/auth/forms.py:29
-msgid "This field does not take email addresses."
-msgstr "Dieses Feld akzeptiert keine E-Mail-Adressen."
-
-#: mediagoblin/auth/forms.py:30
-msgid "This field requires an email address."
-msgstr "Dieses Feld benötigt eine E-Mail-Adresse."
-
-#: mediagoblin/auth/forms.py:52 mediagoblin/auth/forms.py:67
+#: mediagoblin/auth/forms.py:26
msgid "Username"
msgstr "Benutzername"
-#: mediagoblin/auth/forms.py:56 mediagoblin/auth/forms.py:71
+#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:45
+#: mediagoblin/tests/test_util.py:110
msgid "Password"
msgstr "Passwort"
-#: mediagoblin/auth/forms.py:60
+#: mediagoblin/auth/forms.py:34
msgid "Email address"
msgstr "E-Mail-Adresse"
-#: mediagoblin/auth/forms.py:78
+#: mediagoblin/auth/forms.py:41
+msgid "Username or Email"
+msgstr "Benutzername oder E-Mail-Adresse"
+
+#: mediagoblin/auth/forms.py:52
msgid "Username or email"
msgstr "Benutzername oder E-Mail-Adresse"
+#: mediagoblin/auth/tools.py:31
+msgid "Invalid User name or email address."
+msgstr "Ungültiger Benutzername oder E-Mail-Adresse."
+
+#: mediagoblin/auth/tools.py:32
+msgid "This field does not take email addresses."
+msgstr "Dieses Feld akzeptiert keine E-Mail-Adressen."
+
+#: mediagoblin/auth/tools.py:33
+msgid "This field requires an email address."
+msgstr "Dieses Feld benötigt eine E-Mail-Adresse."
+
#: mediagoblin/auth/views.py:54
msgid "Sorry, registration is disabled on this instance."
msgstr "Benutzerregistrierung ist auf diesem Server leider deaktiviert."
@@ -72,54 +77,54 @@ msgstr "Leider gibt es bereits einen Benutzer mit diesem Namen."
msgid "Sorry, a user with that email address already exists."
msgstr "Leider gibt es bereits einen Benutzer mit dieser E-Mail-Adresse."
-#: mediagoblin/auth/views.py:174
+#: mediagoblin/auth/views.py:182
msgid ""
"Your email address has been verified. You may now login, edit your profile, "
"and submit images!"
msgstr "Dein GNU MediaGoblin Konto wurde hiermit aktiviert. Du kannst dich jetzt anmelden, dein Profil bearbeiten und Medien hochladen."
-#: mediagoblin/auth/views.py:180
+#: mediagoblin/auth/views.py:188
msgid "The verification key or user id is incorrect"
msgstr "Der Aktivierungsschlüssel oder die Nutzerkennung ist falsch."
-#: mediagoblin/auth/views.py:198
+#: mediagoblin/auth/views.py:206
msgid "You must be logged in so we know who to send the email to!"
msgstr "Du musst angemeldet sein, damit wir wissen, wer die Email bekommt."
-#: mediagoblin/auth/views.py:206
+#: mediagoblin/auth/views.py:214
msgid "You've already verified your email address!"
msgstr "Deine E-Mail-Adresse wurde bereits aktiviert."
-#: mediagoblin/auth/views.py:219
+#: mediagoblin/auth/views.py:227
msgid "Resent your verification email."
msgstr "Aktivierungsmail wurde erneut versandt."
-#: mediagoblin/auth/views.py:250
+#: mediagoblin/auth/views.py:258
msgid ""
"If that email address (case sensitive!) is registered an email has been sent"
" with instructions on how to change your password."
msgstr "Falls jemand mit dieser E-Mail-Adresse (Groß- und Kleinschreibung wird unterschieden!) registriert ist, wurde eine E-Mail mit Anleitungen verschickt, wie Du Dein Passwort ändern kannst."
-#: mediagoblin/auth/views.py:261
+#: mediagoblin/auth/views.py:269
msgid "Couldn't find someone with that username."
msgstr "Es konnte niemand mit diesem Benutzernamen gefunden werden."
-#: mediagoblin/auth/views.py:264
+#: mediagoblin/auth/views.py:272
msgid ""
"An email has been sent with instructions on how to change your password."
msgstr "Es wurde eine E-Mail mit der Anleitung zur Änderung des Passwortes an Dich gesendet."
-#: mediagoblin/auth/views.py:271
+#: mediagoblin/auth/views.py:279
msgid ""
"Could not send password recovery email as your username is inactive or your "
"account's email address has not been verified."
msgstr "Die E-Mail zur Wiederherstellung des Passworts konnte nicht verschickt werden, weil dein Benutzername inaktiv oder deine E-Mail-Adresse noch nicht aktiviert wurde."
-#: mediagoblin/auth/views.py:328
+#: mediagoblin/auth/views.py:336
msgid "You can now log in using your new password."
msgstr "Du kannst dich jetzt mit deinem neuen Passwort anmelden."
-#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:93
+#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:82
#: mediagoblin/submit/forms.py:28 mediagoblin/submit/forms.py:47
#: mediagoblin/user_pages/forms.py:45
msgid "Title"
@@ -130,7 +135,7 @@ msgid "Description of this work"
msgstr "Beschreibung des Werkes"
#: mediagoblin/edit/forms.py:29 mediagoblin/edit/forms.py:52
-#: mediagoblin/edit/forms.py:97 mediagoblin/submit/forms.py:32
+#: mediagoblin/edit/forms.py:86 mediagoblin/submit/forms.py:32
#: mediagoblin/submit/forms.py:51 mediagoblin/user_pages/forms.py:49
msgid ""
"You can use\n"
@@ -146,11 +151,11 @@ msgstr "Schlagwörter"
msgid "Separate tags by commas."
msgstr "Kommaseparierte Schlagwörter"
-#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:101
+#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:90
msgid "Slug"
msgstr "Kurztitel"
-#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:102
+#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:91
msgid "The slug can't be empty"
msgstr "Bitte gib einen Kurztitel ein"
@@ -178,45 +183,45 @@ msgid "This address contains errors"
msgstr "Diese Adresse ist fehlerhaft"
#: mediagoblin/edit/forms.py:63
-msgid "Old password"
-msgstr "Altes Passwort"
-
-#: mediagoblin/edit/forms.py:64
-msgid "Enter your old password to prove you own this account."
-msgstr "Gib dein altes Passwort ein, um zu bestätigen, dass du dieses Konto besitzt."
-
-#: mediagoblin/edit/forms.py:67
-msgid "New password"
-msgstr "Neues Passwort"
-
-#: mediagoblin/edit/forms.py:74
msgid "License preference"
msgstr "Bevorzugte Lizenz"
-#: mediagoblin/edit/forms.py:80
+#: mediagoblin/edit/forms.py:69
msgid "This will be your default license on upload forms."
msgstr "Dies wird Deine Standardlizenz in den Upload-Forumularen sein."
-#: mediagoblin/edit/forms.py:82
+#: mediagoblin/edit/forms.py:71
msgid "Email me when others comment on my media"
msgstr "Mir eine E-Mail schicken, wenn andere meine Medien kommentieren"
-#: mediagoblin/edit/forms.py:94
+#: mediagoblin/edit/forms.py:83
msgid "The title can't be empty"
msgstr "Der Titel kann nicht leer sein"
-#: mediagoblin/edit/forms.py:96 mediagoblin/submit/forms.py:50
+#: mediagoblin/edit/forms.py:85 mediagoblin/submit/forms.py:50
#: mediagoblin/user_pages/forms.py:48
msgid "Description of this collection"
msgstr "Beschreibung dieser Sammlung"
-#: mediagoblin/edit/forms.py:103
+#: mediagoblin/edit/forms.py:92
msgid ""
"The title part of this collection's address. You usually don't need to "
"change this."
msgstr "Der Titelteil dieser Sammlungsadresse. Du musst ihn normalerweise nicht ändern."
-#: mediagoblin/edit/views.py:66
+#: mediagoblin/edit/forms.py:99
+msgid "Old password"
+msgstr "Altes Passwort"
+
+#: mediagoblin/edit/forms.py:101
+msgid "Enter your old password to prove you own this account."
+msgstr "Gib dein altes Passwort ein, um zu bestätigen, dass du dieses Konto besitzt."
+
+#: mediagoblin/edit/forms.py:104
+msgid "New password"
+msgstr "Neues Passwort"
+
+#: mediagoblin/edit/views.py:67
msgid "An entry with that slug already exists for this user."
msgstr "Diesen Kurztitel hast du bereits vergeben."
@@ -241,44 +246,63 @@ msgstr "Du bearbeitest das Profil eines anderen Nutzers. Sei bitte vorsichtig."
msgid "Profile changes saved"
msgstr "Das Profil wurde aktualisiert"
-#: mediagoblin/edit/views.py:241
-msgid "Wrong password"
-msgstr "Falsches Passwort"
-
-#: mediagoblin/edit/views.py:252
+#: mediagoblin/edit/views.py:240
msgid "Account settings saved"
msgstr "Kontoeinstellungen gespeichert"
-#: mediagoblin/edit/views.py:286
+#: mediagoblin/edit/views.py:274
msgid "You need to confirm the deletion of your account."
msgstr "Du musst die Löschung deines Kontos bestätigen."
-#: mediagoblin/edit/views.py:322 mediagoblin/submit/views.py:142
-#: mediagoblin/user_pages/views.py:214
+#: mediagoblin/edit/views.py:310 mediagoblin/submit/views.py:138
+#: mediagoblin/user_pages/views.py:222
#, python-format
msgid "You already have a collection called \"%s\"!"
msgstr "Du hast bereits eine Sammlung mit Namen »%s«!"
-#: mediagoblin/edit/views.py:326
+#: mediagoblin/edit/views.py:314
msgid "A collection with that slug already exists for this user."
msgstr "Eine Sammlung mit diesem Kurztitel existiert bereits für diesen Benutzer."
-#: mediagoblin/edit/views.py:343
+#: mediagoblin/edit/views.py:329
msgid "You are editing another user's collection. Proceed with caution."
msgstr "Du bearbeitest die Sammlung eines anderen Benutzers. Sei vorsichtig."
-#: mediagoblin/gmg_commands/theme.py:58
+#: mediagoblin/edit/views.py:348
+msgid "Wrong password"
+msgstr "Falsches Passwort"
+
+#: mediagoblin/edit/views.py:363
+msgid "Your password was changed successfully"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:60
msgid "Cannot link theme... no theme set\n"
msgstr "Theme kann nicht verknüpft werden … Kein Theme gesetzt\n"
-#: mediagoblin/gmg_commands/theme.py:71
+#: mediagoblin/gmg_commands/assetlink.py:73
msgid "No asset directory for this theme\n"
msgstr "Für dieses Theme gibt es kein asset-Verzeichnis\n"
-#: mediagoblin/gmg_commands/theme.py:74
+#: mediagoblin/gmg_commands/assetlink.py:76
msgid "However, old link directory symlink found; removed.\n"
msgstr "Trotzdem wurde eine alte Verknüpfung gefunden; sie wurde entfernt\n"
+#: mediagoblin/gmg_commands/assetlink.py:112
+#, python-format
+msgid "Could not link \"%s\": %s exists and is not a symlink\n"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:119
+#, python-format
+msgid "Skipping \"%s\"; already set up.\n"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:124
+#, python-format
+msgid "Old link found for \"%s\"; removing.\n"
+msgstr ""
+
#: mediagoblin/meddleware/csrf.py:134
msgid ""
"CSRF cookie not present. This is most likely the result of a cookie blocker "
@@ -286,12 +310,16 @@ msgid ""
"domain."
msgstr "Das CSRF cookie ist nicht vorhanden. Das liegt vermutlich an einem Cookie-Blocker oder ähnlichem.<br/>Bitte stelle sicher, dass Cookies von dieser Domäne erlaubt sind."
-#: mediagoblin/media_types/__init__.py:61
-#: mediagoblin/media_types/__init__.py:102
+#: mediagoblin/media_types/__init__.py:111
+#: mediagoblin/media_types/__init__.py:155
msgid "Sorry, I don't support that file type :("
msgstr "Entschuldigung, dieser Dateityp wird nicht unterstützt."
-#: mediagoblin/media_types/video/processing.py:36
+#: mediagoblin/media_types/pdf/processing.py:136
+msgid "unoconv failing to run, check log file"
+msgstr ""
+
+#: mediagoblin/media_types/video/processing.py:37
msgid "Video transcoding failed"
msgstr "Videokonvertierung fehlgeschlagen"
@@ -358,17 +386,17 @@ msgstr "Die Weiterleitungs-URI für die Anwendung, dieses Feld\n ist
msgid "This field is required for public clients"
msgstr "Dieses Feld ist Pflicht für öffentliche Clients"
-#: mediagoblin/plugins/oauth/views.py:59
+#: mediagoblin/plugins/oauth/views.py:56
msgid "The client {0} has been registered!"
msgstr "Client {0} wurde registriert!"
#: mediagoblin/plugins/oauth/templates/oauth/client/connections.html:22
msgid "OAuth client connections"
-msgstr ""
+msgstr "OAuth-Client-Verbindungen"
#: mediagoblin/plugins/oauth/templates/oauth/client/list.html:22
msgid "Your OAuth clients"
-msgstr ""
+msgstr "Deine OAuth-Clients"
#: mediagoblin/plugins/oauth/templates/oauth/client/register.html:29
#: mediagoblin/templates/mediagoblin/submit/collection.html:30
@@ -377,7 +405,7 @@ msgstr ""
msgid "Add"
msgstr "Hinzufügen"
-#: mediagoblin/processing/__init__.py:172
+#: mediagoblin/processing/__init__.py:193
msgid "Invalid file given for media type."
msgstr "Die Datei stimmt nicht mit dem gewählten Medientyp überein."
@@ -385,45 +413,45 @@ msgstr "Die Datei stimmt nicht mit dem gewählten Medientyp überein."
msgid "File"
msgstr "Datei"
-#: mediagoblin/submit/views.py:51
+#: mediagoblin/submit/views.py:49
msgid "You must provide a file."
msgstr "Du musst eine Datei angeben."
-#: mediagoblin/submit/views.py:97
+#: mediagoblin/submit/views.py:93
msgid "Woohoo! Submitted!"
msgstr "JAAA! Geschafft!"
-#: mediagoblin/submit/views.py:146
+#: mediagoblin/submit/views.py:144
#, python-format
msgid "Collection \"%s\" added!"
msgstr "Sammlung »%s« hinzugefügt!"
-#: mediagoblin/templates/mediagoblin/base.html:64
+#: mediagoblin/templates/mediagoblin/base.html:67
msgid "Verify your email!"
msgstr "Bitte bestätige Deine E-Mail-Adresse!"
-#: mediagoblin/templates/mediagoblin/base.html:65
+#: mediagoblin/templates/mediagoblin/base.html:68
msgid "log out"
msgstr "abmelden"
-#: mediagoblin/templates/mediagoblin/base.html:70
+#: mediagoblin/templates/mediagoblin/base.html:73
#: mediagoblin/templates/mediagoblin/auth/login.html:28
#: mediagoblin/templates/mediagoblin/auth/login.html:36
#: mediagoblin/templates/mediagoblin/auth/login.html:54
msgid "Log in"
msgstr "Anmelden"
-#: mediagoblin/templates/mediagoblin/base.html:79
+#: mediagoblin/templates/mediagoblin/base.html:82
#, python-format
msgid "<a href=\"%(user_url)s\">%(user_name)s</a>'s account"
msgstr "<a href=\"%(user_url)s\">%(user_name)s</a>s Konto"
-#: mediagoblin/templates/mediagoblin/base.html:86
+#: mediagoblin/templates/mediagoblin/base.html:89
msgid "Change account settings"
msgstr "Kontoeinstellungen ändern"
-#: mediagoblin/templates/mediagoblin/base.html:90
-#: mediagoblin/templates/mediagoblin/base.html:105
+#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:108
#: mediagoblin/templates/mediagoblin/admin/panel.html:21
#: mediagoblin/templates/mediagoblin/admin/panel.html:26
#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:21
@@ -431,72 +459,25 @@ msgstr "Kontoeinstellungen ändern"
msgid "Media processing panel"
msgstr "Medienverarbeitung"
-#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:96
msgid "Log out"
msgstr "Abmelden"
-#: mediagoblin/templates/mediagoblin/base.html:96
+#: mediagoblin/templates/mediagoblin/base.html:99
#: mediagoblin/templates/mediagoblin/user_pages/user.html:156
msgid "Add media"
msgstr "Medien hinzufügen"
-#: mediagoblin/templates/mediagoblin/base.html:99
+#: mediagoblin/templates/mediagoblin/base.html:102
#: mediagoblin/templates/mediagoblin/user_pages/collection_list.html:41
msgid "Create new collection"
msgstr "Neues Album erstellen"
-#: mediagoblin/templates/mediagoblin/base.html:122
-#, python-format
-msgid ""
-"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
-"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
-msgstr "Läuft mit <a href=\"http://mediagoblin.org/\" title='Version %(version)s'>MediaGoblin</a>, einem <a href=\"http://gnu.org/\">GNU</a>-Projekt."
-
-#: mediagoblin/templates/mediagoblin/base.html:125
-#, python-format
-msgid ""
-"Released under the <a "
-"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
-"href=\"%(source_link)s\">Source code</a> available."
-msgstr "Veröffentlicht unter der <a href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a> (<a href=\"%(source_link)s\">Quellcode</a>)."
-
#: mediagoblin/templates/mediagoblin/error.html:24
msgid "Image of goblin stressing out"
msgstr "Bild eines gestressten Goblins"
-#: mediagoblin/templates/mediagoblin/root.html:31
-msgid "Explore"
-msgstr "Entdecken"
-
-#: mediagoblin/templates/mediagoblin/root.html:33
-msgid "Hi there, welcome to this MediaGoblin site!"
-msgstr "Hallo du, willkommen auf dieser MediaGoblin-Seite!"
-
-#: mediagoblin/templates/mediagoblin/root.html:35
-msgid ""
-"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
-"extraordinarily great piece of media hosting software."
-msgstr "Diese Webseite setzt <a href=\"http://mediagoblin.org\">MediaGoblin</a> ein, eine großartige Software für Medienhosting."
-
-#: mediagoblin/templates/mediagoblin/root.html:36
-msgid ""
-"To add your own media, place comments, and more, you can log in with your "
-"MediaGoblin account."
-msgstr "Melde Dich mit Deinem MediaGoblin-Konto an, um eigene Medien hinzuzufügen, andere zu kommentieren und vieles mehr."
-
-#: mediagoblin/templates/mediagoblin/root.html:38
-msgid "Don't have one yet? It's easy!"
-msgstr "Hast du noch keinen? Das geht ganz einfach!"
-
-#: mediagoblin/templates/mediagoblin/root.html:39
-#, python-format
-msgid ""
-"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
-" or\n"
-" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
-msgstr "<a class=\"button_action_highlight\" href=\"%(register_url)s\">Registriere dich auf dieser Seite</a> oder <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Installiere MediaGoblin auf deinem eigenen Server</a>"
-
-#: mediagoblin/templates/mediagoblin/root.html:47
+#: mediagoblin/templates/mediagoblin/root.html:32
msgid "Most recent media"
msgstr "Neuste Medien"
@@ -602,6 +583,53 @@ msgid ""
"%(verification_url)s"
msgstr "Hallo %(username)s,\n\num deinNutzerkonto bei GNU MediaGoblin zu aktivieren, musst du folgende Adresse in deinem Webbrowser öffnen:\n\n%(verification_url)s"
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:21
+#, python-format
+msgid ""
+"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
+"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
+msgstr "Läuft mit <a href=\"http://mediagoblin.org/\" title='Version %(version)s'>MediaGoblin</a>, einem <a href=\"http://gnu.org/\">GNU</a>-Projekt."
+
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:24
+#, python-format
+msgid ""
+"Released under the <a "
+"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
+"href=\"%(source_link)s\">Source code</a> available."
+msgstr "Veröffentlicht unter der <a href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a> (<a href=\"%(source_link)s\">Quellcode</a>)."
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:20
+msgid "Explore"
+msgstr "Entdecken"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:22
+msgid "Hi there, welcome to this MediaGoblin site!"
+msgstr "Hallo du, willkommen auf dieser MediaGoblin-Seite!"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:24
+msgid ""
+"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
+"extraordinarily great piece of media hosting software."
+msgstr "Diese Webseite setzt <a href=\"http://mediagoblin.org\">MediaGoblin</a> ein, eine großartige Software für Medienhosting."
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:25
+msgid ""
+"To add your own media, place comments, and more, you can log in with your "
+"MediaGoblin account."
+msgstr "Melde Dich mit Deinem MediaGoblin-Konto an, um eigene Medien hinzuzufügen, andere zu kommentieren und vieles mehr."
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:27
+msgid "Don't have one yet? It's easy!"
+msgstr "Hast du noch keinen? Das geht ganz einfach!"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:28
+#, python-format
+msgid ""
+"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
+" or\n"
+" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
+msgstr "<a class=\"button_action_highlight\" href=\"%(register_url)s\">Registriere dich auf dieser Seite</a> oder <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Installiere MediaGoblin auf deinem eigenen Server</a>"
+
#: mediagoblin/templates/mediagoblin/bits/logo.html:23
#: mediagoblin/themes/airy/templates/mediagoblin/bits/logo.html:23
msgid "MediaGoblin logo"
@@ -614,13 +642,13 @@ msgid "Editing attachments for %(media_title)s"
msgstr "Bearbeite Anhänge von %(media_title)s"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:159
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:175
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:182
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:198
msgid "Attachments"
msgstr "Anhänge"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:57
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:181
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:204
msgid "Add attachment"
msgstr "Anhang hinzufügen"
@@ -637,12 +665,22 @@ msgstr "Abbrechen"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:63
#: mediagoblin/templates/mediagoblin/edit/edit.html:42
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:52
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:55
#: mediagoblin/templates/mediagoblin/edit/edit_collection.html:33
#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:40
msgid "Save changes"
msgstr "Änderungen speichern"
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:28
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:38
+#, python-format
+msgid "Changing %(username)s's password"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:45
+msgid "Save"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:28
#, python-format
msgid "Really delete user '%(user_name)s' and all related media/comments?"
@@ -653,7 +691,7 @@ msgid "Yes, really delete my account"
msgstr "Ja, ich möchte mein Konto wirklich löschen"
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:47
+#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:48
#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:49
msgid "Delete permanently"
msgstr "Dauerhaft löschen"
@@ -670,7 +708,11 @@ msgstr "%(media_title)s bearbeiten"
msgid "Changing %(username)s's account settings"
msgstr "%(username)ss Kontoeinstellungen ändern"
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:59
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:46
+msgid "Change your password."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:62
msgid "Delete my account"
msgstr "Mein Konto löschen"
@@ -695,6 +737,7 @@ msgstr "Medien mit Schlagwort: %(tag_name)s"
#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:56
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:65
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:136
#: mediagoblin/templates/mediagoblin/media_displays/video.html:55
msgid "Download"
@@ -719,6 +762,7 @@ msgid ""
msgstr "Hol dir auf <a href=\"http://getfirefox.com\">http://getfirefox.com</a> einen modernen Webbrowser, der dieses Audiostück abspielen kann!"
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:60
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:71
#: mediagoblin/templates/mediagoblin/media_displays/video.html:61
msgid "Original file"
msgstr "Originaldatei"
@@ -727,6 +771,7 @@ msgstr "Originaldatei"
msgid "WebM file (Vorbis codec)"
msgstr "WebM-Datei (Vorbis-Codec)"
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:59
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:87
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:93
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:99
@@ -737,6 +782,10 @@ msgstr "WebM-Datei (Vorbis-Codec)"
msgid "Image for %(media_title)s"
msgstr "Bild für %(media_title)s"
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:79
+msgid "PDF file"
+msgstr "PDF-Datei"
+
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:112
msgid "Toggle Rotate"
msgstr ""
@@ -835,7 +884,7 @@ msgstr "Möchtest du %(title)s wirklich löschen?"
msgid "Really remove %(media_title)s from %(collection_title)s?"
msgstr "Wirklich »%(media_title)s« aus »%(collection_title)s« entfernen?"
-#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:53
+#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:54
msgid "Remove"
msgstr "Entfernen"
@@ -878,24 +927,28 @@ msgstr "<a href=\"%(user_url)s\">%(username)s</a>s Medien"
msgid "â– Browsing media by <a href=\"%(user_url)s\">%(username)s</a>"
msgstr "â– Medien von <a href=\"%(user_url)s\">%(username)s</a>"
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:94
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:95
msgid "Add a comment"
msgstr "Einen Kommentar schreiben"
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:102
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:104
msgid "Add this comment"
msgstr "Kommentar absenden"
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:123
-msgid "at"
-msgstr "um"
-
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:144
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:132
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:152
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:164
#, python-format
-msgid ""
-"<h3>Added on</h3>\n"
-" <p>%(date)s</p>"
-msgstr "<h3>Veröffentlicht am</h3>\n <p>%(date)s</p>"
+msgid "%(formatted_time)s ago"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:150
+msgid "Added"
+msgstr "Hinzugefügt"
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:161
+msgid "Created"
+msgstr "Originaldatum"
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:28
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:40
@@ -1051,7 +1104,7 @@ msgstr "älter"
msgid "Tagged with"
msgstr "Schlagwörter"
-#: mediagoblin/tools/exif.py:80
+#: mediagoblin/tools/exif.py:83
msgid "Could not read the image file."
msgstr "Die Bilddatei konnte nicht gelesen werden."
@@ -1081,6 +1134,30 @@ msgid ""
" deleted."
msgstr "Tut uns Leid, aber unter der angegebenen Adresse gibt es keine Seite!</p><p>Wenn du sicher bist, dass die Adresse stimmt, wurde die Seite eventuell verschoben oder gelöscht."
+#: mediagoblin/tools/timesince.py:62
+msgid "year"
+msgstr "Jahr"
+
+#: mediagoblin/tools/timesince.py:63
+msgid "month"
+msgstr "Monat"
+
+#: mediagoblin/tools/timesince.py:64
+msgid "week"
+msgstr "Woche"
+
+#: mediagoblin/tools/timesince.py:65
+msgid "day"
+msgstr "Tag"
+
+#: mediagoblin/tools/timesince.py:66
+msgid "hour"
+msgstr "Stunde"
+
+#: mediagoblin/tools/timesince.py:67
+msgid "minute"
+msgstr "Minute"
+
#: mediagoblin/user_pages/forms.py:23
msgid "Comment"
msgstr "Kommentar"
@@ -1112,73 +1189,77 @@ msgstr "-- Auswählen --"
msgid "Include a note"
msgstr "Notiz anfügen"
-#: mediagoblin/user_pages/lib.py:56
+#: mediagoblin/user_pages/lib.py:58
msgid "commented on your post"
msgstr "hat dein Medium kommentiert"
-#: mediagoblin/user_pages/views.py:166
+#: mediagoblin/user_pages/views.py:169
+msgid "Sorry, comments are disabled."
+msgstr ""
+
+#: mediagoblin/user_pages/views.py:174
msgid "Oops, your comment was empty."
msgstr "Hoppla, der Kommentartext fehlte."
-#: mediagoblin/user_pages/views.py:172
+#: mediagoblin/user_pages/views.py:180
msgid "Your comment has been posted!"
msgstr "Dein Kommentar wurde angenommen!"
-#: mediagoblin/user_pages/views.py:197
+#: mediagoblin/user_pages/views.py:205
msgid "Please check your entries and try again."
msgstr "Bitte prüfe deinen Einträge und versuche erneut."
-#: mediagoblin/user_pages/views.py:237
+#: mediagoblin/user_pages/views.py:245
msgid "You have to select or add a collection"
msgstr "Du musst eine Sammlung auswählen oder hinzufügen"
-#: mediagoblin/user_pages/views.py:248
+#: mediagoblin/user_pages/views.py:256
#, python-format
msgid "\"%s\" already in collection \"%s\""
msgstr "»%s« ist bereits in der Sammlung »%s«"
-#: mediagoblin/user_pages/views.py:264
+#: mediagoblin/user_pages/views.py:262
#, python-format
msgid "\"%s\" added to collection \"%s\""
msgstr "»%s« zur Sammlung »%s« hinzugefügt"
-#: mediagoblin/user_pages/views.py:286
+#: mediagoblin/user_pages/views.py:282
msgid "You deleted the media."
msgstr "Du hast das Medium gelöscht."
-#: mediagoblin/user_pages/views.py:293
+#: mediagoblin/user_pages/views.py:289
msgid "The media was not deleted because you didn't check that you were sure."
msgstr "Das Medium wurde nicht gelöscht, da nicht angekreuzt hast, dass du es wirklich löschen möchtest."
-#: mediagoblin/user_pages/views.py:301
+#: mediagoblin/user_pages/views.py:296
msgid "You are about to delete another user's media. Proceed with caution."
msgstr "Du versuchst Medien eines anderen Nutzers zu löschen. Sei bitte vorsichtig."
-#: mediagoblin/user_pages/views.py:375
+#: mediagoblin/user_pages/views.py:370
msgid "You deleted the item from the collection."
msgstr "Du hast das Objekt aus der Sammlung gelöscht."
-#: mediagoblin/user_pages/views.py:379
+#: mediagoblin/user_pages/views.py:374
msgid "The item was not removed because you didn't check that you were sure."
msgstr "Das Objekt wurde nicht aus der Sammlung entfernt, weil du nicht bestätigt hast, dass du dir sicher bist."
-#: mediagoblin/user_pages/views.py:389
+#: mediagoblin/user_pages/views.py:382
msgid ""
"You are about to delete an item from another user's collection. Proceed with"
" caution."
msgstr "Du bist dabei ein Objekt aus der Sammlung eines anderen Nutzers zu entfernen. Sei vorsichtig."
-#: mediagoblin/user_pages/views.py:422
+#: mediagoblin/user_pages/views.py:415
#, python-format
msgid "You deleted the collection \"%s\""
msgstr "Du hast die Sammlung »%s« gelöscht"
-#: mediagoblin/user_pages/views.py:429
+#: mediagoblin/user_pages/views.py:422
msgid ""
"The collection was not deleted because you didn't check that you were sure."
msgstr "Die Sammlung wurde nicht gelöscht, weil du nicht bestätigt hast, dass du dir sicher bist."
-#: mediagoblin/user_pages/views.py:439
+#: mediagoblin/user_pages/views.py:430
msgid ""
"You are about to delete another user's collection. Proceed with caution."
msgstr "Du bist dabei eine Sammlung eines anderen Nutzers zu entfernen. Sei vorsichtig."
diff --git a/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po
index 6950f515..1b22b786 100644
--- a/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po
+++ b/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
-"POT-Creation-Date: 2013-03-11 17:21-0500\n"
+"POT-Creation-Date: 2013-06-16 20:06-0500\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"
@@ -17,93 +17,98 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 0.9.6\n"
-#: mediagoblin/auth/forms.py:28
-msgid "Invalid User name or email address."
+#: mediagoblin/auth/forms.py:25
+msgid "Username"
msgstr ""
-#: mediagoblin/auth/forms.py:29
-msgid "This field does not take email addresses."
+#: mediagoblin/auth/forms.py:29 mediagoblin/auth/forms.py:44
+#: mediagoblin/tests/test_util.py:110
+msgid "Password"
msgstr ""
-#: mediagoblin/auth/forms.py:30
-msgid "This field requires an email address."
+#: mediagoblin/auth/forms.py:33
+msgid "Email address"
msgstr ""
-#: mediagoblin/auth/forms.py:52 mediagoblin/auth/forms.py:67
-msgid "Username"
+#: mediagoblin/auth/forms.py:40
+msgid "Username or Email"
msgstr ""
-#: mediagoblin/auth/forms.py:56 mediagoblin/auth/forms.py:71
-msgid "Password"
+#: mediagoblin/auth/forms.py:51
+msgid "Username or email"
msgstr ""
-#: mediagoblin/auth/forms.py:60
-msgid "Email address"
+#: mediagoblin/auth/tools.py:42
+msgid "Invalid User name or email address."
msgstr ""
-#: mediagoblin/auth/forms.py:78
-msgid "Username or email"
+#: mediagoblin/auth/tools.py:43
+msgid "This field does not take email addresses."
msgstr ""
-#: mediagoblin/auth/views.py:54
-msgid "Sorry, registration is disabled on this instance."
+#: mediagoblin/auth/tools.py:44
+msgid "This field requires an email address."
msgstr ""
-#: mediagoblin/auth/views.py:68
+#: mediagoblin/auth/tools.py:109
msgid "Sorry, a user with that name already exists."
msgstr ""
-#: mediagoblin/auth/views.py:72
+#: mediagoblin/auth/tools.py:113
msgid "Sorry, a user with that email address already exists."
msgstr ""
-#: mediagoblin/auth/views.py:174
+#: mediagoblin/auth/views.py:43
+msgid "Sorry, registration is disabled on this instance."
+msgstr ""
+
+#: mediagoblin/auth/views.py:133
msgid ""
"Your email address has been verified. You may now login, edit your "
"profile, and submit images!"
msgstr ""
-#: mediagoblin/auth/views.py:180
+#: mediagoblin/auth/views.py:139
msgid "The verification key or user id is incorrect"
msgstr ""
-#: mediagoblin/auth/views.py:198
+#: mediagoblin/auth/views.py:157
msgid "You must be logged in so we know who to send the email to!"
msgstr ""
-#: mediagoblin/auth/views.py:206
+#: mediagoblin/auth/views.py:165
msgid "You've already verified your email address!"
msgstr ""
-#: mediagoblin/auth/views.py:219
+#: mediagoblin/auth/views.py:178
msgid "Resent your verification email."
msgstr ""
-#: mediagoblin/auth/views.py:250
+#: mediagoblin/auth/views.py:209
msgid ""
"If that email address (case sensitive!) is registered an email has been "
"sent with instructions on how to change your password."
msgstr ""
-#: mediagoblin/auth/views.py:261
+#: mediagoblin/auth/views.py:220
msgid "Couldn't find someone with that username."
msgstr ""
-#: mediagoblin/auth/views.py:264
+#: mediagoblin/auth/views.py:223
msgid "An email has been sent with instructions on how to change your password."
msgstr ""
-#: mediagoblin/auth/views.py:271
+#: mediagoblin/auth/views.py:230
msgid ""
"Could not send password recovery email as your username is inactive or "
"your account's email address has not been verified."
msgstr ""
-#: mediagoblin/auth/views.py:328
+#: mediagoblin/auth/views.py:287
msgid "You can now log in using your new password."
msgstr ""
-#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:93
+#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:82
#: mediagoblin/submit/forms.py:28 mediagoblin/submit/forms.py:47
#: mediagoblin/user_pages/forms.py:45
msgid "Title"
@@ -114,7 +119,7 @@ msgid "Description of this work"
msgstr ""
#: mediagoblin/edit/forms.py:29 mediagoblin/edit/forms.py:52
-#: mediagoblin/edit/forms.py:97 mediagoblin/submit/forms.py:32
+#: mediagoblin/edit/forms.py:86 mediagoblin/submit/forms.py:32
#: mediagoblin/submit/forms.py:51 mediagoblin/user_pages/forms.py:49
msgid ""
"You can use\n"
@@ -131,11 +136,11 @@ msgstr ""
msgid "Separate tags by commas."
msgstr ""
-#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:101
+#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:90
msgid "Slug"
msgstr ""
-#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:102
+#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:91
msgid "The slug can't be empty"
msgstr ""
@@ -163,45 +168,45 @@ msgid "This address contains errors"
msgstr ""
#: mediagoblin/edit/forms.py:63
-msgid "Old password"
-msgstr ""
-
-#: mediagoblin/edit/forms.py:64
-msgid "Enter your old password to prove you own this account."
-msgstr ""
-
-#: mediagoblin/edit/forms.py:67
-msgid "New password"
-msgstr ""
-
-#: mediagoblin/edit/forms.py:74
msgid "License preference"
msgstr ""
-#: mediagoblin/edit/forms.py:80
+#: mediagoblin/edit/forms.py:69
msgid "This will be your default license on upload forms."
msgstr ""
-#: mediagoblin/edit/forms.py:82
+#: mediagoblin/edit/forms.py:71
msgid "Email me when others comment on my media"
msgstr ""
-#: mediagoblin/edit/forms.py:94
+#: mediagoblin/edit/forms.py:83
msgid "The title can't be empty"
msgstr ""
-#: mediagoblin/edit/forms.py:96 mediagoblin/submit/forms.py:50
+#: mediagoblin/edit/forms.py:85 mediagoblin/submit/forms.py:50
#: mediagoblin/user_pages/forms.py:48
msgid "Description of this collection"
msgstr ""
-#: mediagoblin/edit/forms.py:103
+#: mediagoblin/edit/forms.py:92
msgid ""
"The title part of this collection's address. You usually don't need to "
"change this."
msgstr ""
-#: mediagoblin/edit/views.py:66
+#: mediagoblin/edit/forms.py:99
+msgid "Old password"
+msgstr ""
+
+#: mediagoblin/edit/forms.py:101
+msgid "Enter your old password to prove you own this account."
+msgstr ""
+
+#: mediagoblin/edit/forms.py:104
+msgid "New password"
+msgstr ""
+
+#: mediagoblin/edit/views.py:67
msgid "An entry with that slug already exists for this user."
msgstr ""
@@ -226,44 +231,63 @@ msgstr ""
msgid "Profile changes saved"
msgstr ""
-#: mediagoblin/edit/views.py:241
-msgid "Wrong password"
-msgstr ""
-
-#: mediagoblin/edit/views.py:252
+#: mediagoblin/edit/views.py:240
msgid "Account settings saved"
msgstr ""
-#: mediagoblin/edit/views.py:286
+#: mediagoblin/edit/views.py:274
msgid "You need to confirm the deletion of your account."
msgstr ""
-#: mediagoblin/edit/views.py:322 mediagoblin/submit/views.py:142
-#: mediagoblin/user_pages/views.py:214
+#: mediagoblin/edit/views.py:310 mediagoblin/submit/views.py:138
+#: mediagoblin/user_pages/views.py:222
#, python-format
msgid "You already have a collection called \"%s\"!"
msgstr ""
-#: mediagoblin/edit/views.py:326
+#: mediagoblin/edit/views.py:314
msgid "A collection with that slug already exists for this user."
msgstr ""
-#: mediagoblin/edit/views.py:343
+#: mediagoblin/edit/views.py:329
msgid "You are editing another user's collection. Proceed with caution."
msgstr ""
-#: mediagoblin/gmg_commands/theme.py:58
+#: mediagoblin/edit/views.py:348
+msgid "Wrong password"
+msgstr ""
+
+#: mediagoblin/edit/views.py:363
+msgid "Your password was changed successfully"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:60
msgid "Cannot link theme... no theme set\n"
msgstr ""
-#: mediagoblin/gmg_commands/theme.py:71
+#: mediagoblin/gmg_commands/assetlink.py:73
msgid "No asset directory for this theme\n"
msgstr ""
-#: mediagoblin/gmg_commands/theme.py:74
+#: mediagoblin/gmg_commands/assetlink.py:76
msgid "However, old link directory symlink found; removed.\n"
msgstr ""
+#: mediagoblin/gmg_commands/assetlink.py:112
+#, python-format
+msgid "Could not link \"%s\": %s exists and is not a symlink\n"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:119
+#, python-format
+msgid "Skipping \"%s\"; already set up.\n"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:124
+#, python-format
+msgid "Old link found for \"%s\"; removing.\n"
+msgstr ""
+
#: mediagoblin/meddleware/csrf.py:134
msgid ""
"CSRF cookie not present. This is most likely the result of a cookie "
@@ -271,11 +295,15 @@ msgid ""
"this domain."
msgstr ""
-#: mediagoblin/media_types/__init__.py:61
-#: mediagoblin/media_types/__init__.py:102
+#: mediagoblin/media_types/__init__.py:111
+#: mediagoblin/media_types/__init__.py:155
msgid "Sorry, I don't support that file type :("
msgstr ""
+#: mediagoblin/media_types/pdf/processing.py:136
+msgid "unoconv failing to run, check log file"
+msgstr ""
+
#: mediagoblin/media_types/video/processing.py:37
msgid "Video transcoding failed"
msgstr ""
@@ -347,7 +375,7 @@ msgstr ""
msgid "This field is required for public clients"
msgstr ""
-#: mediagoblin/plugins/oauth/views.py:59
+#: mediagoblin/plugins/oauth/views.py:56
msgid "The client {0} has been registered!"
msgstr ""
@@ -366,7 +394,7 @@ msgstr ""
msgid "Add"
msgstr ""
-#: mediagoblin/processing/__init__.py:172
+#: mediagoblin/processing/__init__.py:193
msgid "Invalid file given for media type."
msgstr ""
@@ -374,45 +402,45 @@ msgstr ""
msgid "File"
msgstr ""
-#: mediagoblin/submit/views.py:51
+#: mediagoblin/submit/views.py:49
msgid "You must provide a file."
msgstr ""
-#: mediagoblin/submit/views.py:97
+#: mediagoblin/submit/views.py:93
msgid "Woohoo! Submitted!"
msgstr ""
-#: mediagoblin/submit/views.py:146
+#: mediagoblin/submit/views.py:144
#, python-format
msgid "Collection \"%s\" added!"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:64
+#: mediagoblin/templates/mediagoblin/base.html:67
msgid "Verify your email!"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:65
+#: mediagoblin/templates/mediagoblin/base.html:68
msgid "log out"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:70
+#: mediagoblin/templates/mediagoblin/base.html:73
#: mediagoblin/templates/mediagoblin/auth/login.html:28
#: mediagoblin/templates/mediagoblin/auth/login.html:36
#: mediagoblin/templates/mediagoblin/auth/login.html:54
msgid "Log in"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:79
+#: mediagoblin/templates/mediagoblin/base.html:82
#, python-format
msgid "<a href=\"%(user_url)s\">%(user_name)s</a>'s account"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:86
+#: mediagoblin/templates/mediagoblin/base.html:89
msgid "Change account settings"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:90
-#: mediagoblin/templates/mediagoblin/base.html:105
+#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:108
#: mediagoblin/templates/mediagoblin/admin/panel.html:21
#: mediagoblin/templates/mediagoblin/admin/panel.html:26
#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:21
@@ -420,76 +448,25 @@ msgstr ""
msgid "Media processing panel"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:96
msgid "Log out"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:96
+#: mediagoblin/templates/mediagoblin/base.html:99
#: mediagoblin/templates/mediagoblin/user_pages/user.html:156
msgid "Add media"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:99
+#: mediagoblin/templates/mediagoblin/base.html:102
#: mediagoblin/templates/mediagoblin/user_pages/collection_list.html:41
msgid "Create new collection"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:122
-#, python-format
-msgid ""
-"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
-"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> "
-"project."
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/base.html:125
-#, python-format
-msgid ""
-"Released under the <a "
-"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a"
-" href=\"%(source_link)s\">Source code</a> available."
-msgstr ""
-
#: mediagoblin/templates/mediagoblin/error.html:24
msgid "Image of goblin stressing out"
msgstr ""
-#: mediagoblin/templates/mediagoblin/root.html:31
-msgid "Explore"
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:33
-msgid "Hi there, welcome to this MediaGoblin site!"
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:35
-msgid ""
-"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, "
-"an extraordinarily great piece of media hosting software."
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:36
-msgid ""
-"To add your own media, place comments, and more, you can log in with your"
-" MediaGoblin account."
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:38
-msgid "Don't have one yet? It's easy!"
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:39
-#, python-format
-msgid ""
-"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an "
-"account at this site</a>\n"
-" or\n"
-" <a class=\"button_action\" "
-"href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on "
-"your own server</a>"
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:47
+#: mediagoblin/templates/mediagoblin/root.html:32
msgid "Most recent media"
msgstr ""
@@ -594,6 +571,57 @@ msgid ""
"%(verification_url)s"
msgstr ""
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:21
+#, python-format
+msgid ""
+"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
+"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> "
+"project."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:24
+#, python-format
+msgid ""
+"Released under the <a "
+"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a"
+" href=\"%(source_link)s\">Source code</a> available."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:20
+msgid "Explore"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:22
+msgid "Hi there, welcome to this MediaGoblin site!"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:24
+msgid ""
+"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, "
+"an extraordinarily great piece of media hosting software."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:25
+msgid ""
+"To add your own media, place comments, and more, you can log in with your"
+" MediaGoblin account."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:27
+msgid "Don't have one yet? It's easy!"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:28
+#, python-format
+msgid ""
+"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an "
+"account at this site</a>\n"
+" or\n"
+" <a class=\"button_action\" "
+"href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on "
+"your own server</a>"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/bits/logo.html:23
#: mediagoblin/themes/airy/templates/mediagoblin/bits/logo.html:23
msgid "MediaGoblin logo"
@@ -606,13 +634,13 @@ msgid "Editing attachments for %(media_title)s"
msgstr ""
#: mediagoblin/templates/mediagoblin/edit/attachments.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:159
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:175
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:171
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:187
msgid "Attachments"
msgstr ""
#: mediagoblin/templates/mediagoblin/edit/attachments.html:57
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:181
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:193
msgid "Add attachment"
msgstr ""
@@ -629,12 +657,22 @@ msgstr ""
#: mediagoblin/templates/mediagoblin/edit/attachments.html:63
#: mediagoblin/templates/mediagoblin/edit/edit.html:42
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:52
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:55
#: mediagoblin/templates/mediagoblin/edit/edit_collection.html:33
#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:40
msgid "Save changes"
msgstr ""
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:28
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:38
+#, python-format
+msgid "Changing %(username)s's password"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:45
+msgid "Save"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:28
#, python-format
msgid "Really delete user '%(user_name)s' and all related media/comments?"
@@ -645,7 +683,7 @@ msgid "Yes, really delete my account"
msgstr ""
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:47
+#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:48
#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:49
msgid "Delete permanently"
msgstr ""
@@ -662,7 +700,11 @@ msgstr ""
msgid "Changing %(username)s's account settings"
msgstr ""
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:59
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:46
+msgid "Change your password."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:62
msgid "Delete my account"
msgstr ""
@@ -687,6 +729,7 @@ msgstr ""
#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:56
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:65
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:136
#: mediagoblin/templates/mediagoblin/media_displays/video.html:55
msgid "Download"
@@ -711,6 +754,7 @@ msgid ""
msgstr ""
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:60
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:71
#: mediagoblin/templates/mediagoblin/media_displays/video.html:61
msgid "Original file"
msgstr ""
@@ -719,6 +763,18 @@ msgstr ""
msgid "WebM file (Vorbis codec)"
msgstr ""
+#: mediagoblin/templates/mediagoblin/media_displays/image.html:36
+msgid "Created"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/media_displays/image.html:39
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:132
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:152
+#, python-format
+msgid "%(formatted_time)s ago"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:59
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:87
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:93
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:99
@@ -729,6 +785,10 @@ msgstr ""
msgid "Image for %(media_title)s"
msgstr ""
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:79
+msgid "PDF file"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:112
msgid "Toggle Rotate"
msgstr ""
@@ -827,7 +887,7 @@ msgstr ""
msgid "Really remove %(media_title)s from %(collection_title)s?"
msgstr ""
-#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:53
+#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:54
msgid "Remove"
msgstr ""
@@ -871,23 +931,16 @@ msgstr ""
msgid "â– Browsing media by <a href=\"%(user_url)s\">%(username)s</a>"
msgstr ""
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:94
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:95
msgid "Add a comment"
msgstr ""
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:102
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:104
msgid "Add this comment"
msgstr ""
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:123
-msgid "at"
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:144
-#, python-format
-msgid ""
-"<h3>Added on</h3>\n"
-" <p>%(date)s</p>"
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:150
+msgid "Added"
msgstr ""
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:28
@@ -1042,7 +1095,7 @@ msgstr ""
msgid "Tagged with"
msgstr ""
-#: mediagoblin/tools/exif.py:80
+#: mediagoblin/tools/exif.py:83
msgid "Could not read the image file."
msgstr ""
@@ -1072,6 +1125,30 @@ msgid ""
"moved or deleted."
msgstr ""
+#: mediagoblin/tools/timesince.py:62
+msgid "year"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:63
+msgid "month"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:64
+msgid "week"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:65
+msgid "day"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:66
+msgid "hour"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:67
+msgid "minute"
+msgstr ""
+
#: mediagoblin/user_pages/forms.py:23
msgid "Comment"
msgstr ""
@@ -1103,74 +1180,78 @@ msgstr ""
msgid "Include a note"
msgstr ""
-#: mediagoblin/user_pages/lib.py:56
+#: mediagoblin/user_pages/lib.py:58
msgid "commented on your post"
msgstr ""
-#: mediagoblin/user_pages/views.py:166
+#: mediagoblin/user_pages/views.py:169
+msgid "Sorry, comments are disabled."
+msgstr ""
+
+#: mediagoblin/user_pages/views.py:174
msgid "Oops, your comment was empty."
msgstr ""
-#: mediagoblin/user_pages/views.py:172
+#: mediagoblin/user_pages/views.py:180
msgid "Your comment has been posted!"
msgstr ""
-#: mediagoblin/user_pages/views.py:197
+#: mediagoblin/user_pages/views.py:205
msgid "Please check your entries and try again."
msgstr ""
-#: mediagoblin/user_pages/views.py:237
+#: mediagoblin/user_pages/views.py:245
msgid "You have to select or add a collection"
msgstr ""
-#: mediagoblin/user_pages/views.py:248
+#: mediagoblin/user_pages/views.py:256
#, python-format
msgid "\"%s\" already in collection \"%s\""
msgstr ""
-#: mediagoblin/user_pages/views.py:264
+#: mediagoblin/user_pages/views.py:262
#, python-format
msgid "\"%s\" added to collection \"%s\""
msgstr ""
-#: mediagoblin/user_pages/views.py:286
+#: mediagoblin/user_pages/views.py:282
msgid "You deleted the media."
msgstr ""
-#: mediagoblin/user_pages/views.py:293
+#: mediagoblin/user_pages/views.py:289
msgid "The media was not deleted because you didn't check that you were sure."
msgstr ""
-#: mediagoblin/user_pages/views.py:301
+#: mediagoblin/user_pages/views.py:296
msgid "You are about to delete another user's media. Proceed with caution."
msgstr ""
-#: mediagoblin/user_pages/views.py:375
+#: mediagoblin/user_pages/views.py:370
msgid "You deleted the item from the collection."
msgstr ""
-#: mediagoblin/user_pages/views.py:379
+#: mediagoblin/user_pages/views.py:374
msgid "The item was not removed because you didn't check that you were sure."
msgstr ""
-#: mediagoblin/user_pages/views.py:389
+#: mediagoblin/user_pages/views.py:382
msgid ""
"You are about to delete an item from another user's collection. Proceed "
"with caution."
msgstr ""
-#: mediagoblin/user_pages/views.py:422
+#: mediagoblin/user_pages/views.py:415
#, python-format
msgid "You deleted the collection \"%s\""
msgstr ""
-#: mediagoblin/user_pages/views.py:429
+#: mediagoblin/user_pages/views.py:422
msgid ""
"The collection was not deleted because you didn't check that you were "
"sure."
msgstr ""
-#: mediagoblin/user_pages/views.py:439
+#: mediagoblin/user_pages/views.py:430
msgid "You are about to delete another user's collection. Proceed with caution."
msgstr ""
diff --git a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo
index ac74a68b..645af16b 100644
--- a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo
+++ b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo
Binary files differ
diff --git a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po
index e7785d73..873869f0 100644
--- a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po
+++ b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po
@@ -3,18 +3,18 @@
# This file is distributed under the same license as the PROJECT project.
#
# Translators:
-# <deletesoftware@yandex.ru>, 2013.
-# <deletesoftware@yandex.ru>, 2011-2012.
-# Fernando Inocencio <faigos@gmail.com>, 2011.
-# <john_w1954@fastmail.fm>, 2011.
+# aleksejrs <deletesoftware@yandex.ru>, 2013
+# aleksejrs <deletesoftware@yandex.ru>, 2011-2012
+# Fernando Inocencio <faigos@gmail.com>, 2011
+# tiguliano <john_w1954@fastmail.fm>, 2011
msgid ""
msgstr ""
"Project-Id-Version: GNU MediaGoblin\n"
"Report-Msgid-Bugs-To: http://issues.mediagoblin.org/\n"
-"POT-Creation-Date: 2013-03-04 18:04-0600\n"
-"PO-Revision-Date: 2013-03-10 16:50+0000\n"
+"POT-Creation-Date: 2013-05-27 13:54-0500\n"
+"PO-Revision-Date: 2013-06-01 21:16+0000\n"
"Last-Translator: aleksejrs <deletesoftware@yandex.ru>\n"
-"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language-Team: Esperanto (http://www.transifex.com/projects/p/mediagoblin/language/eo/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
@@ -22,34 +22,39 @@ msgstr ""
"Language: eo\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: mediagoblin/auth/forms.py:28
-msgid "Invalid User name or email address."
-msgstr "Nevalida ensalutnomo aÅ­ retpoÅtadreso."
-
-#: mediagoblin/auth/forms.py:29
-msgid "This field does not take email addresses."
-msgstr "Ĉi tiu kampo ne akceptas retpoÅtadresojn."
-
-#: mediagoblin/auth/forms.py:30
-msgid "This field requires an email address."
-msgstr "Ĉi tiu kampo postulas retpoÅtadreson."
-
-#: mediagoblin/auth/forms.py:52 mediagoblin/auth/forms.py:67
+#: mediagoblin/auth/forms.py:26
msgid "Username"
msgstr "Uzantnomo"
-#: mediagoblin/auth/forms.py:56 mediagoblin/auth/forms.py:71
+#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:45
+#: mediagoblin/tests/test_util.py:110
msgid "Password"
msgstr "Pasvorto"
-#: mediagoblin/auth/forms.py:60
+#: mediagoblin/auth/forms.py:34
msgid "Email address"
msgstr "RetpoÅtadreso"
-#: mediagoblin/auth/forms.py:78
+#: mediagoblin/auth/forms.py:41
+msgid "Username or Email"
+msgstr "Uzantonomo aÅ­ retpoÅtadreso"
+
+#: mediagoblin/auth/forms.py:52
msgid "Username or email"
msgstr "Salutnomo aÅ­ retpoÅtadreso"
+#: mediagoblin/auth/tools.py:31
+msgid "Invalid User name or email address."
+msgstr "Nevalida ensalutnomo aÅ­ retpoÅtadreso."
+
+#: mediagoblin/auth/tools.py:32
+msgid "This field does not take email addresses."
+msgstr "Ĉi tiu kampo ne akceptas retpoÅtadresojn."
+
+#: mediagoblin/auth/tools.py:33
+msgid "This field requires an email address."
+msgstr "Ĉi tiu kampo postulas retpoÅtadreson."
+
#: mediagoblin/auth/views.py:54
msgid "Sorry, registration is disabled on this instance."
msgstr "Bedaŭrinde, registrado estas malaktivigita en tiu ĉi instalaĵo."
@@ -62,54 +67,54 @@ msgstr "BedaÅ­rinde, uzanto kun tiu nomo jam ekzistas."
msgid "Sorry, a user with that email address already exists."
msgstr "Ni bedaÅ­ras, sed konto kun tiu retpoÅtadreso jam ekzistas."
-#: mediagoblin/auth/views.py:174
+#: mediagoblin/auth/views.py:182
msgid ""
"Your email address has been verified. You may now login, edit your profile, "
"and submit images!"
msgstr "Via retpoÅtadreso estas konfirmita. Vi povas nun ensaluti, redakti vian profilon, kaj alÅuti bildojn!"
-#: mediagoblin/auth/views.py:180
+#: mediagoblin/auth/views.py:188
msgid "The verification key or user id is incorrect"
msgstr "La kontrol-kodo aÅ­ la uzantonomo ne estas korekta"
-#: mediagoblin/auth/views.py:198
+#: mediagoblin/auth/views.py:206
msgid "You must be logged in so we know who to send the email to!"
msgstr "Vi devas esti ensalutita, por ke ni sciu, al kiu sendi la retleteron!"
-#: mediagoblin/auth/views.py:206
+#: mediagoblin/auth/views.py:214
msgid "You've already verified your email address!"
msgstr "Vi jam konfirmis vian retpoÅtadreson!"
-#: mediagoblin/auth/views.py:219
+#: mediagoblin/auth/views.py:227
msgid "Resent your verification email."
msgstr "Resendi vian kontrol-mesaÄon."
-#: mediagoblin/auth/views.py:250
+#: mediagoblin/auth/views.py:258
msgid ""
"If that email address (case sensitive!) is registered an email has been sent"
" with instructions on how to change your password."
msgstr "Se tiu retpoÅtadreso (majuskloj gravas!) estas registrita, tien senditas retletero kun instrukcio pri kiel ÅanÄi vian pasvorton."
-#: mediagoblin/auth/views.py:261
+#: mediagoblin/auth/views.py:269
msgid "Couldn't find someone with that username."
msgstr "Trovitas neniu kun tiu ensalutnomo."
-#: mediagoblin/auth/views.py:264
+#: mediagoblin/auth/views.py:272
msgid ""
"An email has been sent with instructions on how to change your password."
msgstr "Senditas retletero kun instrukcio pri kiel ÅanÄi vian pasvorton."
-#: mediagoblin/auth/views.py:271
+#: mediagoblin/auth/views.py:279
msgid ""
"Could not send password recovery email as your username is inactive or your "
"account's email address has not been verified."
msgstr "Ni ne povas sendi pasvortsavan retleteron, ĉar aÅ­ via konto estas neaktiva, aÅ­ Äia retpoÅtadreso ne estis konfirmita."
-#: mediagoblin/auth/views.py:328
+#: mediagoblin/auth/views.py:336
msgid "You can now log in using your new password."
msgstr "Nun vi povas ensaluti per via nova pasvorto."
-#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:93
+#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:82
#: mediagoblin/submit/forms.py:28 mediagoblin/submit/forms.py:47
#: mediagoblin/user_pages/forms.py:45
msgid "Title"
@@ -120,7 +125,7 @@ msgid "Description of this work"
msgstr "Priskribo de ĉi tiu verko"
#: mediagoblin/edit/forms.py:29 mediagoblin/edit/forms.py:52
-#: mediagoblin/edit/forms.py:97 mediagoblin/submit/forms.py:32
+#: mediagoblin/edit/forms.py:86 mediagoblin/submit/forms.py:32
#: mediagoblin/submit/forms.py:51 mediagoblin/user_pages/forms.py:49
msgid ""
"You can use\n"
@@ -136,11 +141,11 @@ msgstr "Etikedoj"
msgid "Separate tags by commas."
msgstr "Dividu la etikedojn per komoj."
-#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:101
+#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:90
msgid "Slug"
msgstr "La distingiga adresparto"
-#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:102
+#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:91
msgid "The slug can't be empty"
msgstr "La distingiga adresparto ne povas esti malplena"
@@ -168,45 +173,45 @@ msgid "This address contains errors"
msgstr "Ĉi tiu adreso enhavas erarojn"
#: mediagoblin/edit/forms.py:63
-msgid "Old password"
-msgstr "La malnova pasvorto"
-
-#: mediagoblin/edit/forms.py:64
-msgid "Enter your old password to prove you own this account."
-msgstr "Enigu vian malnovan pasvorton por pruvi, ke ĉi tiu konto estas via."
-
-#: mediagoblin/edit/forms.py:67
-msgid "New password"
-msgstr "La nova pasvorto"
-
-#: mediagoblin/edit/forms.py:74
msgid "License preference"
msgstr "Permesila prefero"
-#: mediagoblin/edit/forms.py:80
+#: mediagoblin/edit/forms.py:69
msgid "This will be your default license on upload forms."
-msgstr ""
+msgstr "Tiu ĉi permesilo estos antaÅ­elektita en la alÅutformularoj."
-#: mediagoblin/edit/forms.py:82
+#: mediagoblin/edit/forms.py:71
msgid "Email me when others comment on my media"
msgstr "RetpoÅtu min kiam aliaj komentas pri miaj alÅutaĵoj."
-#: mediagoblin/edit/forms.py:94
+#: mediagoblin/edit/forms.py:83
msgid "The title can't be empty"
msgstr "La titolo ne povas malpleni."
-#: mediagoblin/edit/forms.py:96 mediagoblin/submit/forms.py:50
+#: mediagoblin/edit/forms.py:85 mediagoblin/submit/forms.py:50
#: mediagoblin/user_pages/forms.py:48
msgid "Description of this collection"
msgstr "Priskribo de la kolekto"
-#: mediagoblin/edit/forms.py:103
+#: mediagoblin/edit/forms.py:92
msgid ""
"The title part of this collection's address. You usually don't need to "
"change this."
msgstr "La distingiga adresparto de ĉi tiu kolekto. Ordinare ne necesas Äin ÅanÄi."
-#: mediagoblin/edit/views.py:66
+#: mediagoblin/edit/forms.py:99
+msgid "Old password"
+msgstr "La malnova pasvorto"
+
+#: mediagoblin/edit/forms.py:101
+msgid "Enter your old password to prove you own this account."
+msgstr "Enigu vian malnovan pasvorton por pruvi, ke ĉi tiu konto estas via."
+
+#: mediagoblin/edit/forms.py:104
+msgid "New password"
+msgstr "La nova pasvorto"
+
+#: mediagoblin/edit/views.py:67
msgid "An entry with that slug already exists for this user."
msgstr "Ĉi tiu uzanto jam havas dosieron kun tiu distingiga adresparto."
@@ -231,44 +236,63 @@ msgstr "Vi redaktas profilon de alia uzanto. Agu singardeme."
msgid "Profile changes saved"
msgstr "ProfilÅanÄoj estis konservitaj"
-#: mediagoblin/edit/views.py:241
-msgid "Wrong password"
-msgstr "MalÄusta pasvorto"
-
-#: mediagoblin/edit/views.py:252
+#: mediagoblin/edit/views.py:240
msgid "Account settings saved"
msgstr "Kontagordoj estis konservitaj"
-#: mediagoblin/edit/views.py:286
+#: mediagoblin/edit/views.py:274
msgid "You need to confirm the deletion of your account."
msgstr "Vi bezonas konfirmi la forigon de via konto."
-#: mediagoblin/edit/views.py:322 mediagoblin/submit/views.py:142
-#: mediagoblin/user_pages/views.py:214
+#: mediagoblin/edit/views.py:310 mediagoblin/submit/views.py:138
+#: mediagoblin/user_pages/views.py:222
#, python-format
msgid "You already have a collection called \"%s\"!"
msgstr "Vi jam havas kolekton kun la nomo «%s»!"
-#: mediagoblin/edit/views.py:326
+#: mediagoblin/edit/views.py:314
msgid "A collection with that slug already exists for this user."
msgstr "Ĉi tiu uzanto jam havas kolekton kun tiu distingiga adresparto."
-#: mediagoblin/edit/views.py:343
+#: mediagoblin/edit/views.py:329
msgid "You are editing another user's collection. Proceed with caution."
msgstr "Vi redaktas kolekton de alia uzanto. Agu singardeme."
-#: mediagoblin/gmg_commands/theme.py:58
+#: mediagoblin/edit/views.py:348
+msgid "Wrong password"
+msgstr "MalÄusta pasvorto"
+
+#: mediagoblin/edit/views.py:363
+msgid "Your password was changed successfully"
+msgstr "Via pasvorto estas sukcese ÅanÄita"
+
+#: mediagoblin/gmg_commands/assetlink.py:60
msgid "Cannot link theme... no theme set\n"
msgstr "Alligo de etoso ne eblas… ne estas elektita ekzistanta etoso\n"
-#: mediagoblin/gmg_commands/theme.py:71
+#: mediagoblin/gmg_commands/assetlink.py:73
msgid "No asset directory for this theme\n"
msgstr "Mankas dosierujo kun aspektiloj por la etoso\n"
-#: mediagoblin/gmg_commands/theme.py:74
+#: mediagoblin/gmg_commands/assetlink.py:76
msgid "However, old link directory symlink found; removed.\n"
msgstr "Tamen trovitas — kaj forigitas — malnova simbola ligilo al dosierujo.\n"
+#: mediagoblin/gmg_commands/assetlink.py:112
+#, python-format
+msgid "Could not link \"%s\": %s exists and is not a symlink\n"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:119
+#, python-format
+msgid "Skipping \"%s\"; already set up.\n"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:124
+#, python-format
+msgid "Old link found for \"%s\"; removing.\n"
+msgstr ""
+
#: mediagoblin/meddleware/csrf.py:134
msgid ""
"CSRF cookie not present. This is most likely the result of a cookie blocker "
@@ -276,12 +300,16 @@ msgid ""
"domain."
msgstr ""
-#: mediagoblin/media_types/__init__.py:61
-#: mediagoblin/media_types/__init__.py:102
+#: mediagoblin/media_types/__init__.py:111
+#: mediagoblin/media_types/__init__.py:155
msgid "Sorry, I don't support that file type :("
msgstr "Mi pardonpetas, mi ne subtenas tiun dosiertipon :("
-#: mediagoblin/media_types/video/processing.py:36
+#: mediagoblin/media_types/pdf/processing.py:136
+msgid "unoconv failing to run, check log file"
+msgstr ""
+
+#: mediagoblin/media_types/video/processing.py:37
msgid "Video transcoding failed"
msgstr "Malsukcesis transkodado de filmo"
@@ -348,7 +376,7 @@ msgstr ""
msgid "This field is required for public clients"
msgstr ""
-#: mediagoblin/plugins/oauth/views.py:59
+#: mediagoblin/plugins/oauth/views.py:56
msgid "The client {0} has been registered!"
msgstr ""
@@ -367,7 +395,7 @@ msgstr ""
msgid "Add"
msgstr "Aldoni"
-#: mediagoblin/processing/__init__.py:172
+#: mediagoblin/processing/__init__.py:193
msgid "Invalid file given for media type."
msgstr "La provizita dosiero ne konformas al la informtipo."
@@ -375,45 +403,45 @@ msgstr "La provizita dosiero ne konformas al la informtipo."
msgid "File"
msgstr "Dosiero"
-#: mediagoblin/submit/views.py:51
+#: mediagoblin/submit/views.py:49
msgid "You must provide a file."
msgstr "Vi devas provizi dosieron."
-#: mediagoblin/submit/views.py:97
+#: mediagoblin/submit/views.py:93
msgid "Woohoo! Submitted!"
msgstr "Hura! AlÅutitas!"
-#: mediagoblin/submit/views.py:146
+#: mediagoblin/submit/views.py:144
#, python-format
msgid "Collection \"%s\" added!"
msgstr "Kolekto «%s» aldonitas!"
-#: mediagoblin/templates/mediagoblin/base.html:64
+#: mediagoblin/templates/mediagoblin/base.html:67
msgid "Verify your email!"
msgstr "Konfirmu viecon de la retpoÅtadreso!"
-#: mediagoblin/templates/mediagoblin/base.html:65
+#: mediagoblin/templates/mediagoblin/base.html:68
msgid "log out"
msgstr "elsaluti"
-#: mediagoblin/templates/mediagoblin/base.html:70
+#: mediagoblin/templates/mediagoblin/base.html:73
#: mediagoblin/templates/mediagoblin/auth/login.html:28
#: mediagoblin/templates/mediagoblin/auth/login.html:36
#: mediagoblin/templates/mediagoblin/auth/login.html:54
msgid "Log in"
msgstr "Ensaluti"
-#: mediagoblin/templates/mediagoblin/base.html:79
+#: mediagoblin/templates/mediagoblin/base.html:82
#, python-format
msgid "<a href=\"%(user_url)s\">%(user_name)s</a>'s account"
msgstr "Konto de <a href=\"%(user_url)s\">%(user_name)s</a>"
-#: mediagoblin/templates/mediagoblin/base.html:86
+#: mediagoblin/templates/mediagoblin/base.html:89
msgid "Change account settings"
msgstr "ÅœanÄi kontagordojn"
-#: mediagoblin/templates/mediagoblin/base.html:90
-#: mediagoblin/templates/mediagoblin/base.html:105
+#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:108
#: mediagoblin/templates/mediagoblin/admin/panel.html:21
#: mediagoblin/templates/mediagoblin/admin/panel.html:26
#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:21
@@ -421,72 +449,25 @@ msgstr "ÅœanÄi kontagordojn"
msgid "Media processing panel"
msgstr "Kontrolejo pri dosierpreparado."
-#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:96
msgid "Log out"
msgstr "Elsaluti"
-#: mediagoblin/templates/mediagoblin/base.html:96
+#: mediagoblin/templates/mediagoblin/base.html:99
#: mediagoblin/templates/mediagoblin/user_pages/user.html:156
msgid "Add media"
msgstr "Aldoni dosieron"
-#: mediagoblin/templates/mediagoblin/base.html:99
+#: mediagoblin/templates/mediagoblin/base.html:102
#: mediagoblin/templates/mediagoblin/user_pages/collection_list.html:41
msgid "Create new collection"
msgstr "Krei novan kolekton"
-#: mediagoblin/templates/mediagoblin/base.html:122
-#, python-format
-msgid ""
-"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
-"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
-msgstr "Funkcias per <a href=\"http://mediagoblin.org/\" title='Versio %(version)s'>MediaGoblin</a>, unu el la <a href=\"http://gnu.org/\">projektoj de GNU</a>."
-
-#: mediagoblin/templates/mediagoblin/base.html:125
-#, python-format
-msgid ""
-"Released under the <a "
-"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
-"href=\"%(source_link)s\">Source code</a> available."
-msgstr "Disponigita laÅ­ la permesilo <a href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. Haveblas<a href=\"%(source_link)s\">fontotekstaro</a>."
-
#: mediagoblin/templates/mediagoblin/error.html:24
msgid "Image of goblin stressing out"
msgstr "Bildo de zorgigita koboldo"
-#: mediagoblin/templates/mediagoblin/root.html:31
-msgid "Explore"
-msgstr "Ĉirkaŭrigardi"
-
-#: mediagoblin/templates/mediagoblin/root.html:33
-msgid "Hi there, welcome to this MediaGoblin site!"
-msgstr "Saluton, kaj bonvenon al ĉi tiu MediaGoblina retpaÄaro!"
-
-#: mediagoblin/templates/mediagoblin/root.html:35
-msgid ""
-"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
-"extraordinarily great piece of media hosting software."
-msgstr "Ĉi tiu retpaÄaro funkcias per <a href=\"http://mediagoblin.org\">MediaGoblin</a>, eksterordinare bonega programaro por gastigado de aÅ­dâ€vidâ€dosieroj."
-
-#: mediagoblin/templates/mediagoblin/root.html:36
-msgid ""
-"To add your own media, place comments, and more, you can log in with your "
-"MediaGoblin account."
-msgstr "Por aldoni viajn proprajn dosierojn, afiÅi komentariojn ktp, vi povas ensaluti je via MediaGoblina konto."
-
-#: mediagoblin/templates/mediagoblin/root.html:38
-msgid "Don't have one yet? It's easy!"
-msgstr "Ĉu vi ankoraÅ­ ne havas tian? Ne malÄoju!"
-
-#: mediagoblin/templates/mediagoblin/root.html:39
-#, python-format
-msgid ""
-"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
-" or\n"
-" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
-msgstr "<a class=\"button_action_highlight\" href=\"%(register_url)s\">Kreu konton en ĉi tiu retejo</a>\n aŭ\n <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">ekfunkciigu MediaGoblin’on en via propra servilo</a>"
-
-#: mediagoblin/templates/mediagoblin/root.html:47
+#: mediagoblin/templates/mediagoblin/root.html:32
msgid "Most recent media"
msgstr "Laste aldonitaj dosieroj"
@@ -592,6 +573,53 @@ msgid ""
"%(verification_url)s"
msgstr "Sal %(username)s,\n\npor aktivigi vian GNU MediaGoblin konton, malfermu la sekvantan URLon en via retumilo:\n\n%(verification_url)s"
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:21
+#, python-format
+msgid ""
+"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
+"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
+msgstr "Funkcias per <a href=\"http://mediagoblin.org/\" title='Versio %(version)s'>MediaGoblin</a>, unu el la <a href=\"http://gnu.org/\">projektoj de GNU</a>."
+
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:24
+#, python-format
+msgid ""
+"Released under the <a "
+"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
+"href=\"%(source_link)s\">Source code</a> available."
+msgstr "Disponigita laÅ­ la permesilo <a href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. Haveblas<a href=\"%(source_link)s\">fontotekstaro</a>."
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:20
+msgid "Explore"
+msgstr "Ĉirkaŭrigardi"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:22
+msgid "Hi there, welcome to this MediaGoblin site!"
+msgstr "Saluton, kaj bonvenon al ĉi tiu MediaGoblina retpaÄaro!"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:24
+msgid ""
+"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
+"extraordinarily great piece of media hosting software."
+msgstr "Ĉi tiu retpaÄaro funkcias per <a href=\"http://mediagoblin.org\">MediaGoblin</a>, eksterordinare bonega programaro por gastigado de aÅ­dâ€vidâ€dosieroj."
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:25
+msgid ""
+"To add your own media, place comments, and more, you can log in with your "
+"MediaGoblin account."
+msgstr "Por aldoni viajn proprajn dosierojn, afiÅi komentariojn ktp, vi povas ensaluti je via MediaGoblina konto."
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:27
+msgid "Don't have one yet? It's easy!"
+msgstr "Ĉu vi ankoraÅ­ ne havas tian? Ne malÄoju!"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:28
+#, python-format
+msgid ""
+"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
+" or\n"
+" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/bits/logo.html:23
#: mediagoblin/themes/airy/templates/mediagoblin/bits/logo.html:23
msgid "MediaGoblin logo"
@@ -604,13 +632,13 @@ msgid "Editing attachments for %(media_title)s"
msgstr "Aldoni kundosierojn por %(media_title)s"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:159
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:175
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:182
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:198
msgid "Attachments"
msgstr "Kundosieroj"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:57
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:181
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:204
msgid "Add attachment"
msgstr "Aldoni kundosieron"
@@ -627,12 +655,22 @@ msgstr "Nuligi"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:63
#: mediagoblin/templates/mediagoblin/edit/edit.html:42
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:52
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:55
#: mediagoblin/templates/mediagoblin/edit/edit_collection.html:33
#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:40
msgid "Save changes"
msgstr "Konservi ÅanÄojn"
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:28
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:38
+#, python-format
+msgid "Changing %(username)s's password"
+msgstr "ÅœanÄado de pasvorto de %(username)s"
+
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:45
+msgid "Save"
+msgstr "Konservi"
+
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:28
#, python-format
msgid "Really delete user '%(user_name)s' and all related media/comments?"
@@ -643,7 +681,7 @@ msgid "Yes, really delete my account"
msgstr "Jes, efektive forigi mian konton"
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:47
+#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:48
#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:49
msgid "Delete permanently"
msgstr "Forigi senrevene"
@@ -660,7 +698,11 @@ msgstr "Priredaktado de %(media_title)s"
msgid "Changing %(username)s's account settings"
msgstr "ÅœanÄado de kontagordoj de %(username)s"
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:59
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:46
+msgid "Change your password."
+msgstr "ÅœanÄi la pasvorton"
+
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:62
msgid "Delete my account"
msgstr "Forigi mian konton."
@@ -685,6 +727,7 @@ msgstr "Dosieroj kun etikedo: %(tag_name)s"
#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:56
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:65
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:136
#: mediagoblin/templates/mediagoblin/media_displays/video.html:55
msgid "Download"
@@ -709,6 +752,7 @@ msgid ""
msgstr "Vi povas akiri modernan TTT-legilon, kapablan \n\tsonigi la registraĵon ĉe <a href=\"http://getfirefox.com\">\n\t http://getfirefox.com</a>!"
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:60
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:71
#: mediagoblin/templates/mediagoblin/media_displays/video.html:61
msgid "Original file"
msgstr "originalan dosieron"
@@ -717,6 +761,7 @@ msgstr "originalan dosieron"
msgid "WebM file (Vorbis codec)"
msgstr "WebMan dosieron (kun Vorbisa kodaĵo)"
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:59
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:87
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:93
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:99
@@ -727,6 +772,10 @@ msgstr "WebMan dosieron (kun Vorbisa kodaĵo)"
msgid "Image for %(media_title)s"
msgstr "Bildo de «%(media_title)s»"
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:79
+msgid "PDF file"
+msgstr "PDF-dosiero"
+
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:112
msgid "Toggle Rotate"
msgstr ""
@@ -825,7 +874,7 @@ msgstr "Ĉu vere forigi %(title)s?"
msgid "Really remove %(media_title)s from %(collection_title)s?"
msgstr "Ĉu vere forigi %(media_title)s el %(collection_title)s?"
-#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:53
+#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:54
msgid "Remove"
msgstr "Forigi"
@@ -868,24 +917,28 @@ msgstr "Dosieroj de <a href=\"%(user_url)s\">%(username)s</a>"
msgid "â– Browsing media by <a href=\"%(user_url)s\">%(username)s</a>"
msgstr "■ПроÑмотр файлов Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ <a href=\"%(user_url)s\">%(username)s</a>"
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:94
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:95
msgid "Add a comment"
msgstr "Aldoni komenton"
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:102
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:104
msgid "Add this comment"
msgstr "Aldoni ĉi tiun komenton"
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:123
-msgid "at"
-msgstr "je"
-
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:144
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:132
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:152
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:164
#, python-format
-msgid ""
-"<h3>Added on</h3>\n"
-" <p>%(date)s</p>"
-msgstr "<h3>Aldonita je</h3>\n <p>la %(date)s</p>"
+msgid "%(formatted_time)s ago"
+msgstr "antaÅ­ %(formatted_time)s"
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:150
+msgid "Added"
+msgstr "Aldonita"
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:161
+msgid "Created"
+msgstr "Kreita"
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:28
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:40
@@ -1041,7 +1094,7 @@ msgstr "malpli nova"
msgid "Tagged with"
msgstr "Markita per"
-#: mediagoblin/tools/exif.py:80
+#: mediagoblin/tools/exif.py:83
msgid "Could not read the image file."
msgstr "Malsukcesis lego de la bildodosiero"
@@ -1071,6 +1124,30 @@ msgid ""
" deleted."
msgstr ""
+#: mediagoblin/tools/timesince.py:62
+msgid "year"
+msgstr "jaro(j)"
+
+#: mediagoblin/tools/timesince.py:63
+msgid "month"
+msgstr "monato(j)"
+
+#: mediagoblin/tools/timesince.py:64
+msgid "week"
+msgstr "semajno(j)"
+
+#: mediagoblin/tools/timesince.py:65
+msgid "day"
+msgstr "tago(j)"
+
+#: mediagoblin/tools/timesince.py:66
+msgid "hour"
+msgstr "horo(j)"
+
+#: mediagoblin/tools/timesince.py:67
+msgid "minute"
+msgstr "minuto(j)"
+
#: mediagoblin/user_pages/forms.py:23
msgid "Comment"
msgstr "Komenti"
@@ -1102,73 +1179,77 @@ msgstr "-- Elektu --"
msgid "Include a note"
msgstr "Rimarko"
-#: mediagoblin/user_pages/lib.py:56
+#: mediagoblin/user_pages/lib.py:58
msgid "commented on your post"
msgstr "komentis je via afiÅo"
-#: mediagoblin/user_pages/views.py:166
+#: mediagoblin/user_pages/views.py:169
+msgid "Sorry, comments are disabled."
+msgstr "Ve, komentado estas malebligita."
+
+#: mediagoblin/user_pages/views.py:174
msgid "Oops, your comment was empty."
msgstr "Oj, via komento estis malplena."
-#: mediagoblin/user_pages/views.py:172
+#: mediagoblin/user_pages/views.py:180
msgid "Your comment has been posted!"
msgstr "Via komento estis afiÅita!"
-#: mediagoblin/user_pages/views.py:197
+#: mediagoblin/user_pages/views.py:205
msgid "Please check your entries and try again."
msgstr "Bonvolu kontroli vian enigitaĵon kaj reprovi."
-#: mediagoblin/user_pages/views.py:237
+#: mediagoblin/user_pages/views.py:245
msgid "You have to select or add a collection"
msgstr "Necesas elekti aÅ­ aldoni kolekton"
-#: mediagoblin/user_pages/views.py:248
+#: mediagoblin/user_pages/views.py:256
#, python-format
msgid "\"%s\" already in collection \"%s\""
msgstr "«%s» jam estas en la kolekto «%s»"
-#: mediagoblin/user_pages/views.py:264
+#: mediagoblin/user_pages/views.py:262
#, python-format
msgid "\"%s\" added to collection \"%s\""
msgstr "«%s» estis aldonita al la kolekto «%s»"
-#: mediagoblin/user_pages/views.py:286
+#: mediagoblin/user_pages/views.py:282
msgid "You deleted the media."
msgstr "Vi forigis la dosieron."
-#: mediagoblin/user_pages/views.py:293
+#: mediagoblin/user_pages/views.py:289
msgid "The media was not deleted because you didn't check that you were sure."
msgstr "La dosiero ne estis forigita, ĉar vi ne konfirmis vian certecon per la markilo."
-#: mediagoblin/user_pages/views.py:301
+#: mediagoblin/user_pages/views.py:296
msgid "You are about to delete another user's media. Proceed with caution."
msgstr "Vi estas forigonta dosieron de alia uzanto. Estu singardema."
-#: mediagoblin/user_pages/views.py:375
+#: mediagoblin/user_pages/views.py:370
msgid "You deleted the item from the collection."
msgstr "Vi forigis la dosieron el la kolekto."
-#: mediagoblin/user_pages/views.py:379
+#: mediagoblin/user_pages/views.py:374
msgid "The item was not removed because you didn't check that you were sure."
msgstr "La dosiero ne estis forigita, ĉar vi ne konfirmis vian certecon per la markilo."
-#: mediagoblin/user_pages/views.py:389
+#: mediagoblin/user_pages/views.py:382
msgid ""
"You are about to delete an item from another user's collection. Proceed with"
" caution."
msgstr "Vi estas forigonta dosieron el kolekto de alia uzanto. Agu singardeme."
-#: mediagoblin/user_pages/views.py:422
+#: mediagoblin/user_pages/views.py:415
#, python-format
msgid "You deleted the collection \"%s\""
msgstr "Vi forigis la kolekton «%s»"
-#: mediagoblin/user_pages/views.py:429
+#: mediagoblin/user_pages/views.py:422
msgid ""
"The collection was not deleted because you didn't check that you were sure."
msgstr "La kolekto ne estis forigita, ĉar vi ne konfirmis vian certecon per la markilo."
-#: mediagoblin/user_pages/views.py:439
+#: mediagoblin/user_pages/views.py:430
msgid ""
"You are about to delete another user's collection. Proceed with caution."
msgstr "Vi estas forigonta kolekton de alia uzanto. Agu singardeme."
diff --git a/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo
index e2df0731..c5e50f53 100644
--- a/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo
+++ b/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo
Binary files differ
diff --git a/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po
index 21dce0b1..8c2f046f 100644
--- a/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po
+++ b/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po
@@ -3,25 +3,25 @@
# This file is distributed under the same license as the PROJECT project.
#
# Translators:
-# <deletesoftware@yandex.ru>, 2011, 2012.
-# <ekenbrand@hotmail.com>, 2011.
-# <jacobo@gnu.org>, 2011-2012.
-# Javier Di Mauro <javierdimauro@gmail.com>, 2011.
-# <juangsub@gmail.com>, 2011.
-# <juanma@kde.org.ar>, 2011, 2012.
-# <larjona99@gmail.com>, 2012.
-# Laura Arjona Reina <larjona99@gmail.com>, 2013.
-# Mario Rodriguez <msrodriguez00@gmail.com>, 2011.
-# <mu@member.fsf.org>, 2011.
-# <shackra@riseup.net>, 2012.
-# <stardustprincess17@hotmail.com>, 2012.
+# aleksejrs <deletesoftware@yandex.ru>, 2011, 2012
+# ekenbrand <ekenbrand@hotmail.com>, 2011
+# nvjacobo <jacobo@gnu.org>, 2011-2012
+# Javier Di Mauro <javierdimauro@gmail.com>, 2011
+# case <juangsub@gmail.com>, 2011
+# juanman <juanma@kde.org.ar>, 2011, 2012
+# larjona <larjona99@gmail.com>, 2012
+# larjona <larjona99@gmail.com>, 2013
+# Mario Rodriguez <msrodriguez00@gmail.com>, 2011
+# Manuel Urbano Santos <mu@member.fsf.org>, 2011
+# shackra <shackra@riseup.net>, 2012
+# Elesa <stardustprincess17@hotmail.com>, 2012
msgid ""
msgstr ""
"Project-Id-Version: GNU MediaGoblin\n"
"Report-Msgid-Bugs-To: http://issues.mediagoblin.org/\n"
-"POT-Creation-Date: 2013-03-04 18:04-0600\n"
-"PO-Revision-Date: 2013-03-05 00:04+0000\n"
-"Last-Translator: cwebber <cwebber@dustycloud.org>\n"
+"POT-Creation-Date: 2013-05-27 13:54-0500\n"
+"PO-Revision-Date: 2013-06-02 21:23+0000\n"
+"Last-Translator: larjona <larjona99@gmail.com>\n"
"Language-Team: Spanish (http://www.transifex.com/projects/p/mediagoblin/language/es/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -30,34 +30,39 @@ msgstr ""
"Language: es\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: mediagoblin/auth/forms.py:28
-msgid "Invalid User name or email address."
-msgstr "Nombre de usuario o correo electrónico inválido."
-
-#: mediagoblin/auth/forms.py:29
-msgid "This field does not take email addresses."
-msgstr "Este campo no acepta direcciones de correo."
-
-#: mediagoblin/auth/forms.py:30
-msgid "This field requires an email address."
-msgstr "Este campo requiere una dirección de correo."
-
-#: mediagoblin/auth/forms.py:52 mediagoblin/auth/forms.py:67
+#: mediagoblin/auth/forms.py:26
msgid "Username"
msgstr "Nombre de usuario"
-#: mediagoblin/auth/forms.py:56 mediagoblin/auth/forms.py:71
+#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:45
+#: mediagoblin/tests/test_util.py:110
msgid "Password"
msgstr "Contraseña"
-#: mediagoblin/auth/forms.py:60
+#: mediagoblin/auth/forms.py:34
msgid "Email address"
msgstr "Dirección de correo electrónico"
-#: mediagoblin/auth/forms.py:78
+#: mediagoblin/auth/forms.py:41
+msgid "Username or Email"
+msgstr "Nombre de usuario o correo electrónico"
+
+#: mediagoblin/auth/forms.py:52
msgid "Username or email"
msgstr "Nombre de usuario o email"
+#: mediagoblin/auth/tools.py:31
+msgid "Invalid User name or email address."
+msgstr "Nombre de usuario o correo electrónico inválido."
+
+#: mediagoblin/auth/tools.py:32
+msgid "This field does not take email addresses."
+msgstr "Este campo no acepta direcciones de correo."
+
+#: mediagoblin/auth/tools.py:33
+msgid "This field requires an email address."
+msgstr "Este campo requiere una dirección de correo."
+
#: mediagoblin/auth/views.py:54
msgid "Sorry, registration is disabled on this instance."
msgstr "Lo sentimos, el registro está deshabilitado en este momento."
@@ -70,54 +75,54 @@ msgstr "Lo sentimos, ya existe un usuario con ese nombre."
msgid "Sorry, a user with that email address already exists."
msgstr "Lo sentimos, ya existe un usuario con esa dirección de email."
-#: mediagoblin/auth/views.py:174
+#: mediagoblin/auth/views.py:182
msgid ""
"Your email address has been verified. You may now login, edit your profile, "
"and submit images!"
msgstr "Tu dirección de correo electrónico ha sido verificada. ¡Ahora puedes iniciar sesión, editar tu perfil, y enviar imágenes!"
-#: mediagoblin/auth/views.py:180
+#: mediagoblin/auth/views.py:188
msgid "The verification key or user id is incorrect"
msgstr "La clave de verificación o la identificación de usuario son incorrectas"
-#: mediagoblin/auth/views.py:198
+#: mediagoblin/auth/views.py:206
msgid "You must be logged in so we know who to send the email to!"
msgstr "¡Debes iniciar sesión para que podamos saber a quién le enviamos el correo electrónico!"
-#: mediagoblin/auth/views.py:206
+#: mediagoblin/auth/views.py:214
msgid "You've already verified your email address!"
msgstr "¡Ya has verificado tu dirección de correo!"
-#: mediagoblin/auth/views.py:219
+#: mediagoblin/auth/views.py:227
msgid "Resent your verification email."
msgstr "Se reenvió tu correo electrónico de verificación."
-#: mediagoblin/auth/views.py:250
+#: mediagoblin/auth/views.py:258
msgid ""
"If that email address (case sensitive!) is registered an email has been sent"
" with instructions on how to change your password."
msgstr "Si esa dirección de correo (¡sensible a mayúsculas y minúsculas!) está registrada, se ha enviado un correo con instrucciones para cambiar la contraseña."
-#: mediagoblin/auth/views.py:261
+#: mediagoblin/auth/views.py:269
msgid "Couldn't find someone with that username."
msgstr "No se ha podido encontrar a nadie con ese nombre de usuario."
-#: mediagoblin/auth/views.py:264
+#: mediagoblin/auth/views.py:272
msgid ""
"An email has been sent with instructions on how to change your password."
msgstr "Un correo electrónico ha sido enviado con instrucciones sobre cómo cambiar tu contraseña."
-#: mediagoblin/auth/views.py:271
+#: mediagoblin/auth/views.py:279
msgid ""
"Could not send password recovery email as your username is inactive or your "
"account's email address has not been verified."
msgstr "No se pudo enviar un correo electrónico de recuperación de contraseñas porque tu nombre de usuario está inactivo o la dirección de su cuenta de correo electrónico no ha sido verificada."
-#: mediagoblin/auth/views.py:328
+#: mediagoblin/auth/views.py:336
msgid "You can now log in using your new password."
msgstr "Ahora tu puedes iniciar sesión usando tu nueva contraseña."
-#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:93
+#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:82
#: mediagoblin/submit/forms.py:28 mediagoblin/submit/forms.py:47
#: mediagoblin/user_pages/forms.py:45
msgid "Title"
@@ -128,7 +133,7 @@ msgid "Description of this work"
msgstr "Descripción de esta obra"
#: mediagoblin/edit/forms.py:29 mediagoblin/edit/forms.py:52
-#: mediagoblin/edit/forms.py:97 mediagoblin/submit/forms.py:32
+#: mediagoblin/edit/forms.py:86 mediagoblin/submit/forms.py:32
#: mediagoblin/submit/forms.py:51 mediagoblin/user_pages/forms.py:49
msgid ""
"You can use\n"
@@ -144,11 +149,11 @@ msgstr "Etiquetas"
msgid "Separate tags by commas."
msgstr "Separa las etiquetas por comas."
-#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:101
+#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:90
msgid "Slug"
msgstr "Ficha"
-#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:102
+#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:91
msgid "The slug can't be empty"
msgstr "La ficha no puede estar vacía"
@@ -176,45 +181,45 @@ msgid "This address contains errors"
msgstr "La dirección contiene errores"
#: mediagoblin/edit/forms.py:63
-msgid "Old password"
-msgstr "Vieja contraseña"
-
-#: mediagoblin/edit/forms.py:64
-msgid "Enter your old password to prove you own this account."
-msgstr "Escriba la anterior contraseña para demostrar que esta cuenta te pertenece."
-
-#: mediagoblin/edit/forms.py:67
-msgid "New password"
-msgstr "Nueva contraseña"
-
-#: mediagoblin/edit/forms.py:74
msgid "License preference"
msgstr "Preferencias de licencia"
-#: mediagoblin/edit/forms.py:80
+#: mediagoblin/edit/forms.py:69
msgid "This will be your default license on upload forms."
msgstr "Ésta será tu licencia predeterminada en los formularios de subida."
-#: mediagoblin/edit/forms.py:82
+#: mediagoblin/edit/forms.py:71
msgid "Email me when others comment on my media"
msgstr "Envíame un correo cuando otros escriban comentarios sobre mi contenido"
-#: mediagoblin/edit/forms.py:94
+#: mediagoblin/edit/forms.py:83
msgid "The title can't be empty"
msgstr "El título no puede estar vacío"
-#: mediagoblin/edit/forms.py:96 mediagoblin/submit/forms.py:50
+#: mediagoblin/edit/forms.py:85 mediagoblin/submit/forms.py:50
#: mediagoblin/user_pages/forms.py:48
msgid "Description of this collection"
msgstr "Descripción de esta colección"
-#: mediagoblin/edit/forms.py:103
+#: mediagoblin/edit/forms.py:92
msgid ""
"The title part of this collection's address. You usually don't need to "
"change this."
msgstr "El título de la dirección de esta colección. Generalmente no necesitas cambiar esto."
-#: mediagoblin/edit/views.py:66
+#: mediagoblin/edit/forms.py:99
+msgid "Old password"
+msgstr "Vieja contraseña"
+
+#: mediagoblin/edit/forms.py:101
+msgid "Enter your old password to prove you own this account."
+msgstr "Escriba la anterior contraseña para demostrar que esta cuenta te pertenece."
+
+#: mediagoblin/edit/forms.py:104
+msgid "New password"
+msgstr "Nueva contraseña"
+
+#: mediagoblin/edit/views.py:67
msgid "An entry with that slug already exists for this user."
msgstr "Una entrada con esa ficha ya existe para este usuario."
@@ -239,44 +244,63 @@ msgstr "Estás editando un perfil de usuario. Procede con precaución."
msgid "Profile changes saved"
msgstr "Los cambios de perfil fueron salvados"
-#: mediagoblin/edit/views.py:241
-msgid "Wrong password"
-msgstr "Contraseña incorrecta"
-
-#: mediagoblin/edit/views.py:252
+#: mediagoblin/edit/views.py:240
msgid "Account settings saved"
msgstr "las configuraciones de cuenta fueron salvadas"
-#: mediagoblin/edit/views.py:286
+#: mediagoblin/edit/views.py:274
msgid "You need to confirm the deletion of your account."
msgstr "Necesitas confirmar el borrado de tu cuenta."
-#: mediagoblin/edit/views.py:322 mediagoblin/submit/views.py:142
-#: mediagoblin/user_pages/views.py:214
+#: mediagoblin/edit/views.py:310 mediagoblin/submit/views.py:138
+#: mediagoblin/user_pages/views.py:222
#, python-format
msgid "You already have a collection called \"%s\"!"
msgstr "¡Ya tienes una colección llamada \"%s\"!"
-#: mediagoblin/edit/views.py:326
+#: mediagoblin/edit/views.py:314
msgid "A collection with that slug already exists for this user."
msgstr "Una colección con esa ficha ya existe para este usuario/a."
-#: mediagoblin/edit/views.py:343
+#: mediagoblin/edit/views.py:329
msgid "You are editing another user's collection. Proceed with caution."
msgstr "Estás editando la colección de otro usuario/a. Ten cuidado."
-#: mediagoblin/gmg_commands/theme.py:58
+#: mediagoblin/edit/views.py:348
+msgid "Wrong password"
+msgstr "Contraseña incorrecta"
+
+#: mediagoblin/edit/views.py:363
+msgid "Your password was changed successfully"
+msgstr "Se ha cambiado la contraseña correctamente"
+
+#: mediagoblin/gmg_commands/assetlink.py:60
msgid "Cannot link theme... no theme set\n"
msgstr "No se puede enlazar al tema... no hay un tema seleccionado\n"
-#: mediagoblin/gmg_commands/theme.py:71
+#: mediagoblin/gmg_commands/assetlink.py:73
msgid "No asset directory for this theme\n"
msgstr "No hay directorio activo para este tema\n\n\n"
-#: mediagoblin/gmg_commands/theme.py:74
+#: mediagoblin/gmg_commands/assetlink.py:76
msgid "However, old link directory symlink found; removed.\n"
msgstr "Sin embargo, se encontró un enlace simbólico de un directorio antiguo; ha sido borrado.\n"
+#: mediagoblin/gmg_commands/assetlink.py:112
+#, python-format
+msgid "Could not link \"%s\": %s exists and is not a symlink\n"
+msgstr "No se pudo enlazar \"%s\": %s existe y no es un enlace simbólico\n"
+
+#: mediagoblin/gmg_commands/assetlink.py:119
+#, python-format
+msgid "Skipping \"%s\"; already set up.\n"
+msgstr "Omitiendo \"%s\"; ya está establecido.\n"
+
+#: mediagoblin/gmg_commands/assetlink.py:124
+#, python-format
+msgid "Old link found for \"%s\"; removing.\n"
+msgstr "Se encontró un enlace antiguo para \"%s\"; se eliminará.\n"
+
#: mediagoblin/meddleware/csrf.py:134
msgid ""
"CSRF cookie not present. This is most likely the result of a cookie blocker "
@@ -284,12 +308,16 @@ msgid ""
"domain."
msgstr "No se encuentra la cookie CSRF. Esto suele ser debido a un bloqueador de cookies o similar.<br/> Por favor asegúrate de permitir las cookies para este dominio."
-#: mediagoblin/media_types/__init__.py:61
-#: mediagoblin/media_types/__init__.py:102
+#: mediagoblin/media_types/__init__.py:111
+#: mediagoblin/media_types/__init__.py:155
msgid "Sorry, I don't support that file type :("
msgstr "Lo sentidos, No soportamos ese tipo de archivo :("
-#: mediagoblin/media_types/video/processing.py:36
+#: mediagoblin/media_types/pdf/processing.py:136
+msgid "unoconv failing to run, check log file"
+msgstr "ha fallado la ejecución de unoconv, comprueba el fichero de registro (log)"
+
+#: mediagoblin/media_types/video/processing.py:37
msgid "Video transcoding failed"
msgstr "Ha fallado la conversión de vídeo"
@@ -356,7 +384,7 @@ msgstr "La URI para redireccionar las aplicaciones, este campo es <strong>requer
msgid "This field is required for public clients"
msgstr "Este campo es requerido para los clientes públicos"
-#: mediagoblin/plugins/oauth/views.py:59
+#: mediagoblin/plugins/oauth/views.py:56
msgid "The client {0} has been registered!"
msgstr "¡El cliente {0} ha sido registrado!"
@@ -375,7 +403,7 @@ msgstr "Tus clientes OAuth"
msgid "Add"
msgstr "Añadir "
-#: mediagoblin/processing/__init__.py:172
+#: mediagoblin/processing/__init__.py:193
msgid "Invalid file given for media type."
msgstr "Archivo inválido para el formato seleccionado."
@@ -383,45 +411,45 @@ msgstr "Archivo inválido para el formato seleccionado."
msgid "File"
msgstr "Archivo"
-#: mediagoblin/submit/views.py:51
+#: mediagoblin/submit/views.py:49
msgid "You must provide a file."
msgstr "Debes proporcionar un archivo."
-#: mediagoblin/submit/views.py:97
+#: mediagoblin/submit/views.py:93
msgid "Woohoo! Submitted!"
msgstr "¡Yuju! ¡Enviado!"
-#: mediagoblin/submit/views.py:146
+#: mediagoblin/submit/views.py:144
#, python-format
msgid "Collection \"%s\" added!"
msgstr "¡Colección \"%s\" añadida!"
-#: mediagoblin/templates/mediagoblin/base.html:64
+#: mediagoblin/templates/mediagoblin/base.html:67
msgid "Verify your email!"
msgstr "¡Verifica tu email!"
-#: mediagoblin/templates/mediagoblin/base.html:65
+#: mediagoblin/templates/mediagoblin/base.html:68
msgid "log out"
msgstr "cerrar sesión"
-#: mediagoblin/templates/mediagoblin/base.html:70
+#: mediagoblin/templates/mediagoblin/base.html:73
#: mediagoblin/templates/mediagoblin/auth/login.html:28
#: mediagoblin/templates/mediagoblin/auth/login.html:36
#: mediagoblin/templates/mediagoblin/auth/login.html:54
msgid "Log in"
msgstr "Iniciar sesión"
-#: mediagoblin/templates/mediagoblin/base.html:79
+#: mediagoblin/templates/mediagoblin/base.html:82
#, python-format
msgid "<a href=\"%(user_url)s\">%(user_name)s</a>'s account"
msgstr "Cuenta de <a href=\"%(user_url)s\">%(user_name)s</a>"
-#: mediagoblin/templates/mediagoblin/base.html:86
+#: mediagoblin/templates/mediagoblin/base.html:89
msgid "Change account settings"
msgstr "Cambiar la configuración de la cuenta"
-#: mediagoblin/templates/mediagoblin/base.html:90
-#: mediagoblin/templates/mediagoblin/base.html:105
+#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:108
#: mediagoblin/templates/mediagoblin/admin/panel.html:21
#: mediagoblin/templates/mediagoblin/admin/panel.html:26
#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:21
@@ -429,72 +457,25 @@ msgstr "Cambiar la configuración de la cuenta"
msgid "Media processing panel"
msgstr "Panel de procesamiento de contenido"
-#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:96
msgid "Log out"
-msgstr ""
+msgstr "Cerrar sesión"
-#: mediagoblin/templates/mediagoblin/base.html:96
+#: mediagoblin/templates/mediagoblin/base.html:99
#: mediagoblin/templates/mediagoblin/user_pages/user.html:156
msgid "Add media"
msgstr "Añadir contenido"
-#: mediagoblin/templates/mediagoblin/base.html:99
+#: mediagoblin/templates/mediagoblin/base.html:102
#: mediagoblin/templates/mediagoblin/user_pages/collection_list.html:41
msgid "Create new collection"
msgstr "Crear nueva colección"
-#: mediagoblin/templates/mediagoblin/base.html:122
-#, python-format
-msgid ""
-"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
-"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
-msgstr "Funciona con <a href=\"http://mediagoblin.org/\" title='Version %(version)s'>MediaGoblin</a>, un proyecto <a href=\"http://gnu.org/\">GNU</a>."
-
-#: mediagoblin/templates/mediagoblin/base.html:125
-#, python-format
-msgid ""
-"Released under the <a "
-"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
-"href=\"%(source_link)s\">Source code</a> available."
-msgstr "Publicado bajo la <a href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a href=\"%(source_link)s\"> Código fuente</a> disponible."
-
#: mediagoblin/templates/mediagoblin/error.html:24
msgid "Image of goblin stressing out"
msgstr "Imagen de un goblin estresándose"
-#: mediagoblin/templates/mediagoblin/root.html:31
-msgid "Explore"
-msgstr "Explorar"
-
-#: mediagoblin/templates/mediagoblin/root.html:33
-msgid "Hi there, welcome to this MediaGoblin site!"
-msgstr "Hola, ¡bienvenido a este sitio de MediaGoblin!"
-
-#: mediagoblin/templates/mediagoblin/root.html:35
-msgid ""
-"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
-"extraordinarily great piece of media hosting software."
-msgstr "Este sitio está montado con <a href=\"http://mediagoblin.org\">MediaGoblin</a>, un extraordinario programa libre para alojar, gestionar y compartir contenido multimedia."
-
-#: mediagoblin/templates/mediagoblin/root.html:36
-msgid ""
-"To add your own media, place comments, and more, you can log in with your "
-"MediaGoblin account."
-msgstr "Para añadir tus propios contenidos, dejar comentarios y más, puedes iniciar sesión con tu cuenta de MediaGoblin."
-
-#: mediagoblin/templates/mediagoblin/root.html:38
-msgid "Don't have one yet? It's easy!"
-msgstr "¿Aún no tienes una? ¡Es fácil!"
-
-#: mediagoblin/templates/mediagoblin/root.html:39
-#, python-format
-msgid ""
-"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
-" or\n"
-" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
-msgstr "<a class=\"button_action_highlight\" href=\"%(register_url)s\">Crea una cuenta en este sitio</a>\n o\n <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Instala Mediagoblin en tu propio servidor</a>"
-
-#: mediagoblin/templates/mediagoblin/root.html:47
+#: mediagoblin/templates/mediagoblin/root.html:32
msgid "Most recent media"
msgstr "El contenido más reciente"
@@ -600,6 +581,53 @@ msgid ""
"%(verification_url)s"
msgstr "Hola %(username)s,\n\npara activar tu cuenta de GNU MediaGoblin, abre la siguiente URL en tu navegador:\n\n%(verification_url)s "
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:21
+#, python-format
+msgid ""
+"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
+"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
+msgstr "Funciona con <a href=\"http://mediagoblin.org/\" title='Version %(version)s'>MediaGoblin</a>, un proyecto <a href=\"http://gnu.org/\">GNU</a>."
+
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:24
+#, python-format
+msgid ""
+"Released under the <a "
+"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
+"href=\"%(source_link)s\">Source code</a> available."
+msgstr "Publicado bajo la <a href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a href=\"%(source_link)s\"> Código fuente</a> disponible."
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:20
+msgid "Explore"
+msgstr "Explorar"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:22
+msgid "Hi there, welcome to this MediaGoblin site!"
+msgstr "Hola, ¡bienvenido a este sitio de MediaGoblin!"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:24
+msgid ""
+"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
+"extraordinarily great piece of media hosting software."
+msgstr "Este sitio está montado con <a href=\"http://mediagoblin.org\">MediaGoblin</a>, un extraordinario programa libre para alojar, gestionar y compartir contenido multimedia."
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:25
+msgid ""
+"To add your own media, place comments, and more, you can log in with your "
+"MediaGoblin account."
+msgstr "Para añadir tus propios contenidos, dejar comentarios y más, puedes iniciar sesión con tu cuenta de MediaGoblin."
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:27
+msgid "Don't have one yet? It's easy!"
+msgstr "¿Aún no tienes una? ¡Es fácil!"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:28
+#, python-format
+msgid ""
+"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
+" or\n"
+" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
+msgstr "<a class=\"button_action_highlight\" href=\"%(register_url)s\">Crear una cuenta en este sitio</a>\n o\n <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Instalar MediaGoblin en tu propio servidor</a>"
+
#: mediagoblin/templates/mediagoblin/bits/logo.html:23
#: mediagoblin/themes/airy/templates/mediagoblin/bits/logo.html:23
msgid "MediaGoblin logo"
@@ -612,13 +640,13 @@ msgid "Editing attachments for %(media_title)s"
msgstr "Editando archivos adjuntos a %(media_title)s"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:159
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:175
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:182
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:198
msgid "Attachments"
msgstr "Adjuntos"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:57
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:181
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:204
msgid "Add attachment"
msgstr "Agregar adjunto"
@@ -635,12 +663,22 @@ msgstr "Cancelar"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:63
#: mediagoblin/templates/mediagoblin/edit/edit.html:42
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:52
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:55
#: mediagoblin/templates/mediagoblin/edit/edit_collection.html:33
#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:40
msgid "Save changes"
msgstr "Guardar cambios"
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:28
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:38
+#, python-format
+msgid "Changing %(username)s's password"
+msgstr "Cambiando la contraseña de %(username)s"
+
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:45
+msgid "Save"
+msgstr "Guardar"
+
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:28
#, python-format
msgid "Really delete user '%(user_name)s' and all related media/comments?"
@@ -651,7 +689,7 @@ msgid "Yes, really delete my account"
msgstr "Sí, borrar mi cuenta"
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:47
+#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:48
#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:49
msgid "Delete permanently"
msgstr "Eliminar permanentemente"
@@ -668,7 +706,11 @@ msgstr "Editando %(media_title)s "
msgid "Changing %(username)s's account settings"
msgstr "Cambio de %(username)s la configuración de la cuenta "
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:59
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:46
+msgid "Change your password."
+msgstr "Cambiar tu contraseña."
+
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:62
msgid "Delete my account"
msgstr "Borrar mi cuenta"
@@ -693,6 +735,7 @@ msgstr "Contenido etiquetado con: %(tag_name)s"
#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:56
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:65
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:136
#: mediagoblin/templates/mediagoblin/media_displays/video.html:55
msgid "Download"
@@ -717,6 +760,7 @@ msgid ""
msgstr "Tú puedes obtener un navegador más moderno que \n\tpueda reproducir el audio <a href=\"http://getfirefox.com\">\n\t http://getfirefox.com</a>!"
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:60
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:71
#: mediagoblin/templates/mediagoblin/media_displays/video.html:61
msgid "Original file"
msgstr "Archivo original"
@@ -725,6 +769,7 @@ msgstr "Archivo original"
msgid "WebM file (Vorbis codec)"
msgstr "Archivo WebM (códec Vorbis)"
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:59
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:87
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:93
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:99
@@ -735,6 +780,10 @@ msgstr "Archivo WebM (códec Vorbis)"
msgid "Image for %(media_title)s"
msgstr "Imágenes para %(media_title)s"
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:79
+msgid "PDF file"
+msgstr "Fichero PDF"
+
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:112
msgid "Toggle Rotate"
msgstr "Alternar Rotar"
@@ -833,7 +882,7 @@ msgstr "¿Realmente deseas eliminar %(title)s?"
msgid "Really remove %(media_title)s from %(collection_title)s?"
msgstr "¿Realmente quieres quitar %(media_title)s de %(collection_title)s?"
-#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:53
+#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:54
msgid "Remove"
msgstr "Quitar"
@@ -876,24 +925,28 @@ msgstr "Contenido de <a href=\"%(user_url)s\">%(username)s</a>"
msgid "â– Browsing media by <a href=\"%(user_url)s\">%(username)s</a>"
msgstr "â– Explorando contenido de <a href=\"%(user_url)s\">%(username)s</a>"
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:94
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:95
msgid "Add a comment"
msgstr "Añadir un comentario"
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:102
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:104
msgid "Add this comment"
msgstr "Añade un comentario "
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:123
-msgid "at"
-msgstr "en"
-
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:144
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:132
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:152
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:164
#, python-format
-msgid ""
-"<h3>Added on</h3>\n"
-" <p>%(date)s</p>"
-msgstr "<h3>Añadido en</h3>\n <p>%(date)s</p>"
+msgid "%(formatted_time)s ago"
+msgstr "hace %(formatted_time)s"
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:150
+msgid "Added"
+msgstr "Agregado"
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:161
+msgid "Created"
+msgstr "Creado"
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:28
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:40
@@ -1049,7 +1102,7 @@ msgstr "Más viejo"
msgid "Tagged with"
msgstr "Marcado con"
-#: mediagoblin/tools/exif.py:80
+#: mediagoblin/tools/exif.py:83
msgid "Could not read the image file."
msgstr "No se pudo leer el archivo de imagen."
@@ -1079,6 +1132,30 @@ msgid ""
" deleted."
msgstr "Parece que no hay ninguna página en esta dirección. ¡Lo siento!</p><p>Si estás seguro de que la dirección es correcta, quizá han borrado o movido la página que estás buscando."
+#: mediagoblin/tools/timesince.py:62
+msgid "year"
+msgstr "año"
+
+#: mediagoblin/tools/timesince.py:63
+msgid "month"
+msgstr "mes"
+
+#: mediagoblin/tools/timesince.py:64
+msgid "week"
+msgstr "semana"
+
+#: mediagoblin/tools/timesince.py:65
+msgid "day"
+msgstr "día"
+
+#: mediagoblin/tools/timesince.py:66
+msgid "hour"
+msgstr "hora"
+
+#: mediagoblin/tools/timesince.py:67
+msgid "minute"
+msgstr "minuto"
+
#: mediagoblin/user_pages/forms.py:23
msgid "Comment"
msgstr "Comentario"
@@ -1110,73 +1187,77 @@ msgstr "-- Selecciona --"
msgid "Include a note"
msgstr "Incluir una nota"
-#: mediagoblin/user_pages/lib.py:56
+#: mediagoblin/user_pages/lib.py:58
msgid "commented on your post"
msgstr "comentó tu publicación"
-#: mediagoblin/user_pages/views.py:166
+#: mediagoblin/user_pages/views.py:169
+msgid "Sorry, comments are disabled."
+msgstr "Lo siento, los comentarios están desactivados."
+
+#: mediagoblin/user_pages/views.py:174
msgid "Oops, your comment was empty."
msgstr "Ups, tu comentario estaba vacío."
-#: mediagoblin/user_pages/views.py:172
+#: mediagoblin/user_pages/views.py:180
msgid "Your comment has been posted!"
msgstr "¡Tu comentario ha sido publicado!"
-#: mediagoblin/user_pages/views.py:197
+#: mediagoblin/user_pages/views.py:205
msgid "Please check your entries and try again."
msgstr "Por favor, revisa tus entradas e inténtalo de nuevo."
-#: mediagoblin/user_pages/views.py:237
+#: mediagoblin/user_pages/views.py:245
msgid "You have to select or add a collection"
msgstr "Tienes que seleccionar o añadir una colección"
-#: mediagoblin/user_pages/views.py:248
+#: mediagoblin/user_pages/views.py:256
#, python-format
msgid "\"%s\" already in collection \"%s\""
msgstr "%s\" ya está en la colección \"%s\""
-#: mediagoblin/user_pages/views.py:264
+#: mediagoblin/user_pages/views.py:262
#, python-format
msgid "\"%s\" added to collection \"%s\""
msgstr "\"%s\" añadido a la colección \"%s\""
-#: mediagoblin/user_pages/views.py:286
+#: mediagoblin/user_pages/views.py:282
msgid "You deleted the media."
msgstr "Eliminaste el contenido"
-#: mediagoblin/user_pages/views.py:293
+#: mediagoblin/user_pages/views.py:289
msgid "The media was not deleted because you didn't check that you were sure."
msgstr "El contenido no se eliminó porque no marcaste que estabas seguro."
-#: mediagoblin/user_pages/views.py:301
+#: mediagoblin/user_pages/views.py:296
msgid "You are about to delete another user's media. Proceed with caution."
msgstr "Estás a punto de eliminar un contenido de otro usuario. Procede con precaución."
-#: mediagoblin/user_pages/views.py:375
+#: mediagoblin/user_pages/views.py:370
msgid "You deleted the item from the collection."
msgstr "Borraste el ítem de la colección."
-#: mediagoblin/user_pages/views.py:379
+#: mediagoblin/user_pages/views.py:374
msgid "The item was not removed because you didn't check that you were sure."
msgstr "El ítem no fue removido porque no confirmaste que estuvieras seguro/a."
-#: mediagoblin/user_pages/views.py:389
+#: mediagoblin/user_pages/views.py:382
msgid ""
"You are about to delete an item from another user's collection. Proceed with"
" caution."
msgstr "Estás a punto de borrar un ítem de la colección de otro usuario. Procede con cuidado."
-#: mediagoblin/user_pages/views.py:422
+#: mediagoblin/user_pages/views.py:415
#, python-format
msgid "You deleted the collection \"%s\""
msgstr "Borraste la colección \"%s\""
-#: mediagoblin/user_pages/views.py:429
+#: mediagoblin/user_pages/views.py:422
msgid ""
"The collection was not deleted because you didn't check that you were sure."
msgstr "La colección no fue borrada porque no confirmaste que estuvieras seguro/a."
-#: mediagoblin/user_pages/views.py:439
+#: mediagoblin/user_pages/views.py:430
msgid ""
"You are about to delete another user's collection. Proceed with caution."
msgstr "Estás a punto de borrar la colección de otro usuario. Procede con cuidado."
diff --git a/mediagoblin/i18n/fa/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/fa/LC_MESSAGES/mediagoblin.mo
index 4b319ebd..3422ad97 100644
--- a/mediagoblin/i18n/fa/LC_MESSAGES/mediagoblin.mo
+++ b/mediagoblin/i18n/fa/LC_MESSAGES/mediagoblin.mo
Binary files differ
diff --git a/mediagoblin/i18n/fa/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/fa/LC_MESSAGES/mediagoblin.po
index 028ab5d4..08e73e1a 100644
--- a/mediagoblin/i18n/fa/LC_MESSAGES/mediagoblin.po
+++ b/mediagoblin/i18n/fa/LC_MESSAGES/mediagoblin.po
@@ -3,15 +3,15 @@
# This file is distributed under the same license as the PROJECT project.
#
# Translators:
-# <amir007ag@gmail.com>, 2012.
+# Numb <amir007ag@gmail.com>, 2012
msgid ""
msgstr ""
"Project-Id-Version: GNU MediaGoblin\n"
"Report-Msgid-Bugs-To: http://issues.mediagoblin.org/\n"
-"POT-Creation-Date: 2013-03-04 18:04-0600\n"
-"PO-Revision-Date: 2013-03-05 00:04+0000\n"
+"POT-Creation-Date: 2013-05-27 13:54-0500\n"
+"PO-Revision-Date: 2013-05-27 18:54+0000\n"
"Last-Translator: cwebber <cwebber@dustycloud.org>\n"
-"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language-Team: Persian (http://www.transifex.com/projects/p/mediagoblin/language/fa/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
@@ -19,34 +19,39 @@ msgstr ""
"Language: fa\n"
"Plural-Forms: nplurals=1; plural=0;\n"
-#: mediagoblin/auth/forms.py:28
-msgid "Invalid User name or email address."
-msgstr ""
-
-#: mediagoblin/auth/forms.py:29
-msgid "This field does not take email addresses."
-msgstr ""
-
-#: mediagoblin/auth/forms.py:30
-msgid "This field requires an email address."
-msgstr ""
-
-#: mediagoblin/auth/forms.py:52 mediagoblin/auth/forms.py:67
+#: mediagoblin/auth/forms.py:26
msgid "Username"
msgstr "نام کاربری"
-#: mediagoblin/auth/forms.py:56 mediagoblin/auth/forms.py:71
+#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:45
+#: mediagoblin/tests/test_util.py:110
msgid "Password"
msgstr "گذرواٰژه"
-#: mediagoblin/auth/forms.py:60
+#: mediagoblin/auth/forms.py:34
msgid "Email address"
msgstr "آدرس ایمیل"
-#: mediagoblin/auth/forms.py:78
+#: mediagoblin/auth/forms.py:41
+msgid "Username or Email"
+msgstr ""
+
+#: mediagoblin/auth/forms.py:52
msgid "Username or email"
msgstr ""
+#: mediagoblin/auth/tools.py:31
+msgid "Invalid User name or email address."
+msgstr ""
+
+#: mediagoblin/auth/tools.py:32
+msgid "This field does not take email addresses."
+msgstr ""
+
+#: mediagoblin/auth/tools.py:33
+msgid "This field requires an email address."
+msgstr ""
+
#: mediagoblin/auth/views.py:54
msgid "Sorry, registration is disabled on this instance."
msgstr "Ù…ØªØ§Ø³ÙØ§Ù†Ù‡ØŒØ«Ø¨ØªÙ†Ø§Ù… به طور موقت غیر ÙØ¹Ø§Ù„ است."
@@ -59,54 +64,54 @@ msgstr "Ù…ØªØ§Ø³ÙØ§Ù†Ù‡ کاربری با این نام کاربری وجود Ø
msgid "Sorry, a user with that email address already exists."
msgstr ""
-#: mediagoblin/auth/views.py:174
+#: mediagoblin/auth/views.py:182
msgid ""
"Your email address has been verified. You may now login, edit your profile, "
"and submit images!"
msgstr "ایمیل شما تایید شد.شما می توانید حالا وارد شوید،نمایه خود را ویرایش کنید و تصاویر خود را ثبت کنید!"
-#: mediagoblin/auth/views.py:180
+#: mediagoblin/auth/views.py:188
msgid "The verification key or user id is incorrect"
msgstr "این کد تاییدیه یا شناسه کاربری صحیح نیست."
-#: mediagoblin/auth/views.py:198
+#: mediagoblin/auth/views.py:206
msgid "You must be logged in so we know who to send the email to!"
msgstr ""
-#: mediagoblin/auth/views.py:206
+#: mediagoblin/auth/views.py:214
msgid "You've already verified your email address!"
msgstr ""
-#: mediagoblin/auth/views.py:219
+#: mediagoblin/auth/views.py:227
msgid "Resent your verification email."
msgstr "ایمیل تاییدیه باز ارسال شد."
-#: mediagoblin/auth/views.py:250
+#: mediagoblin/auth/views.py:258
msgid ""
"If that email address (case sensitive!) is registered an email has been sent"
" with instructions on how to change your password."
msgstr ""
-#: mediagoblin/auth/views.py:261
+#: mediagoblin/auth/views.py:269
msgid "Couldn't find someone with that username."
msgstr ""
-#: mediagoblin/auth/views.py:264
+#: mediagoblin/auth/views.py:272
msgid ""
"An email has been sent with instructions on how to change your password."
msgstr ""
-#: mediagoblin/auth/views.py:271
+#: mediagoblin/auth/views.py:279
msgid ""
"Could not send password recovery email as your username is inactive or your "
"account's email address has not been verified."
msgstr ""
-#: mediagoblin/auth/views.py:328
+#: mediagoblin/auth/views.py:336
msgid "You can now log in using your new password."
msgstr ""
-#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:93
+#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:82
#: mediagoblin/submit/forms.py:28 mediagoblin/submit/forms.py:47
#: mediagoblin/user_pages/forms.py:45
msgid "Title"
@@ -117,7 +122,7 @@ msgid "Description of this work"
msgstr ""
#: mediagoblin/edit/forms.py:29 mediagoblin/edit/forms.py:52
-#: mediagoblin/edit/forms.py:97 mediagoblin/submit/forms.py:32
+#: mediagoblin/edit/forms.py:86 mediagoblin/submit/forms.py:32
#: mediagoblin/submit/forms.py:51 mediagoblin/user_pages/forms.py:49
msgid ""
"You can use\n"
@@ -133,11 +138,11 @@ msgstr "برچسب"
msgid "Separate tags by commas."
msgstr ""
-#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:101
+#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:90
msgid "Slug"
msgstr ""
-#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:102
+#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:91
msgid "The slug can't be empty"
msgstr ""
@@ -165,45 +170,45 @@ msgid "This address contains errors"
msgstr ""
#: mediagoblin/edit/forms.py:63
-msgid "Old password"
-msgstr ""
-
-#: mediagoblin/edit/forms.py:64
-msgid "Enter your old password to prove you own this account."
-msgstr ""
-
-#: mediagoblin/edit/forms.py:67
-msgid "New password"
-msgstr ""
-
-#: mediagoblin/edit/forms.py:74
msgid "License preference"
msgstr ""
-#: mediagoblin/edit/forms.py:80
+#: mediagoblin/edit/forms.py:69
msgid "This will be your default license on upload forms."
msgstr ""
-#: mediagoblin/edit/forms.py:82
+#: mediagoblin/edit/forms.py:71
msgid "Email me when others comment on my media"
msgstr ""
-#: mediagoblin/edit/forms.py:94
+#: mediagoblin/edit/forms.py:83
msgid "The title can't be empty"
msgstr ""
-#: mediagoblin/edit/forms.py:96 mediagoblin/submit/forms.py:50
+#: mediagoblin/edit/forms.py:85 mediagoblin/submit/forms.py:50
#: mediagoblin/user_pages/forms.py:48
msgid "Description of this collection"
msgstr ""
-#: mediagoblin/edit/forms.py:103
+#: mediagoblin/edit/forms.py:92
msgid ""
"The title part of this collection's address. You usually don't need to "
"change this."
msgstr ""
-#: mediagoblin/edit/views.py:66
+#: mediagoblin/edit/forms.py:99
+msgid "Old password"
+msgstr ""
+
+#: mediagoblin/edit/forms.py:101
+msgid "Enter your old password to prove you own this account."
+msgstr ""
+
+#: mediagoblin/edit/forms.py:104
+msgid "New password"
+msgstr ""
+
+#: mediagoblin/edit/views.py:67
msgid "An entry with that slug already exists for this user."
msgstr ""
@@ -228,44 +233,63 @@ msgstr "شما در حال ویرایش نمایه کاربر دیگری هستÛ
msgid "Profile changes saved"
msgstr ""
-#: mediagoblin/edit/views.py:241
-msgid "Wrong password"
-msgstr ""
-
-#: mediagoblin/edit/views.py:252
+#: mediagoblin/edit/views.py:240
msgid "Account settings saved"
msgstr ""
-#: mediagoblin/edit/views.py:286
+#: mediagoblin/edit/views.py:274
msgid "You need to confirm the deletion of your account."
msgstr ""
-#: mediagoblin/edit/views.py:322 mediagoblin/submit/views.py:142
-#: mediagoblin/user_pages/views.py:214
+#: mediagoblin/edit/views.py:310 mediagoblin/submit/views.py:138
+#: mediagoblin/user_pages/views.py:222
#, python-format
msgid "You already have a collection called \"%s\"!"
msgstr ""
-#: mediagoblin/edit/views.py:326
+#: mediagoblin/edit/views.py:314
msgid "A collection with that slug already exists for this user."
msgstr ""
-#: mediagoblin/edit/views.py:343
+#: mediagoblin/edit/views.py:329
msgid "You are editing another user's collection. Proceed with caution."
msgstr ""
-#: mediagoblin/gmg_commands/theme.py:58
+#: mediagoblin/edit/views.py:348
+msgid "Wrong password"
+msgstr ""
+
+#: mediagoblin/edit/views.py:363
+msgid "Your password was changed successfully"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:60
msgid "Cannot link theme... no theme set\n"
msgstr ""
-#: mediagoblin/gmg_commands/theme.py:71
+#: mediagoblin/gmg_commands/assetlink.py:73
msgid "No asset directory for this theme\n"
msgstr ""
-#: mediagoblin/gmg_commands/theme.py:74
+#: mediagoblin/gmg_commands/assetlink.py:76
msgid "However, old link directory symlink found; removed.\n"
msgstr ""
+#: mediagoblin/gmg_commands/assetlink.py:112
+#, python-format
+msgid "Could not link \"%s\": %s exists and is not a symlink\n"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:119
+#, python-format
+msgid "Skipping \"%s\"; already set up.\n"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:124
+#, python-format
+msgid "Old link found for \"%s\"; removing.\n"
+msgstr ""
+
#: mediagoblin/meddleware/csrf.py:134
msgid ""
"CSRF cookie not present. This is most likely the result of a cookie blocker "
@@ -273,12 +297,16 @@ msgid ""
"domain."
msgstr ""
-#: mediagoblin/media_types/__init__.py:61
-#: mediagoblin/media_types/__init__.py:102
+#: mediagoblin/media_types/__init__.py:111
+#: mediagoblin/media_types/__init__.py:155
msgid "Sorry, I don't support that file type :("
msgstr ""
-#: mediagoblin/media_types/video/processing.py:36
+#: mediagoblin/media_types/pdf/processing.py:136
+msgid "unoconv failing to run, check log file"
+msgstr ""
+
+#: mediagoblin/media_types/video/processing.py:37
msgid "Video transcoding failed"
msgstr ""
@@ -345,7 +373,7 @@ msgstr ""
msgid "This field is required for public clients"
msgstr ""
-#: mediagoblin/plugins/oauth/views.py:59
+#: mediagoblin/plugins/oauth/views.py:56
msgid "The client {0} has been registered!"
msgstr ""
@@ -364,7 +392,7 @@ msgstr ""
msgid "Add"
msgstr ""
-#: mediagoblin/processing/__init__.py:172
+#: mediagoblin/processing/__init__.py:193
msgid "Invalid file given for media type."
msgstr "ÙØ§ÛŒÙ„ÛŒ نا معتبر برای نوع رسانه داده شده."
@@ -372,45 +400,45 @@ msgstr "ÙØ§ÛŒÙ„ÛŒ نا معتبر برای نوع رسانه داده شده."
msgid "File"
msgstr "ÙØ§ÛŒÙ„"
-#: mediagoblin/submit/views.py:51
+#: mediagoblin/submit/views.py:49
msgid "You must provide a file."
msgstr "شما باید ÙØ§ÛŒÙ„ÛŒ ارايه بدهید."
-#: mediagoblin/submit/views.py:97
+#: mediagoblin/submit/views.py:93
msgid "Woohoo! Submitted!"
msgstr "هورا!ثبت شد!"
-#: mediagoblin/submit/views.py:146
+#: mediagoblin/submit/views.py:144
#, python-format
msgid "Collection \"%s\" added!"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:64
+#: mediagoblin/templates/mediagoblin/base.html:67
msgid "Verify your email!"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:65
+#: mediagoblin/templates/mediagoblin/base.html:68
msgid "log out"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:70
+#: mediagoblin/templates/mediagoblin/base.html:73
#: mediagoblin/templates/mediagoblin/auth/login.html:28
#: mediagoblin/templates/mediagoblin/auth/login.html:36
#: mediagoblin/templates/mediagoblin/auth/login.html:54
msgid "Log in"
msgstr "ورود"
-#: mediagoblin/templates/mediagoblin/base.html:79
+#: mediagoblin/templates/mediagoblin/base.html:82
#, python-format
msgid "<a href=\"%(user_url)s\">%(user_name)s</a>'s account"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:86
+#: mediagoblin/templates/mediagoblin/base.html:89
msgid "Change account settings"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:90
-#: mediagoblin/templates/mediagoblin/base.html:105
+#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:108
#: mediagoblin/templates/mediagoblin/admin/panel.html:21
#: mediagoblin/templates/mediagoblin/admin/panel.html:26
#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:21
@@ -418,72 +446,25 @@ msgstr ""
msgid "Media processing panel"
msgstr "پنل رسیدگی به رسانه ها"
-#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:96
msgid "Log out"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:96
+#: mediagoblin/templates/mediagoblin/base.html:99
#: mediagoblin/templates/mediagoblin/user_pages/user.html:156
msgid "Add media"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:99
+#: mediagoblin/templates/mediagoblin/base.html:102
#: mediagoblin/templates/mediagoblin/user_pages/collection_list.html:41
msgid "Create new collection"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:122
-#, python-format
-msgid ""
-"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
-"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/base.html:125
-#, python-format
-msgid ""
-"Released under the <a "
-"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
-"href=\"%(source_link)s\">Source code</a> available."
-msgstr ""
-
#: mediagoblin/templates/mediagoblin/error.html:24
msgid "Image of goblin stressing out"
msgstr ""
-#: mediagoblin/templates/mediagoblin/root.html:31
-msgid "Explore"
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:33
-msgid "Hi there, welcome to this MediaGoblin site!"
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:35
-msgid ""
-"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
-"extraordinarily great piece of media hosting software."
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:36
-msgid ""
-"To add your own media, place comments, and more, you can log in with your "
-"MediaGoblin account."
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:38
-msgid "Don't have one yet? It's easy!"
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:39
-#, python-format
-msgid ""
-"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
-" or\n"
-" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:47
+#: mediagoblin/templates/mediagoblin/root.html:32
msgid "Most recent media"
msgstr ""
@@ -589,6 +570,53 @@ msgid ""
"%(verification_url)s"
msgstr "سلام %(username)s,\n\nبرای ÙØ¹Ø§Ù„ سازی شناسه کاربری گنو مدیاگوبلین خود ،پیوند زیر را در مرورگر خود باز کنید.\n\n%(verification_url)s"
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:21
+#, python-format
+msgid ""
+"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
+"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:24
+#, python-format
+msgid ""
+"Released under the <a "
+"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
+"href=\"%(source_link)s\">Source code</a> available."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:20
+msgid "Explore"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:22
+msgid "Hi there, welcome to this MediaGoblin site!"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:24
+msgid ""
+"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
+"extraordinarily great piece of media hosting software."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:25
+msgid ""
+"To add your own media, place comments, and more, you can log in with your "
+"MediaGoblin account."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:27
+msgid "Don't have one yet? It's easy!"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:28
+#, python-format
+msgid ""
+"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
+" or\n"
+" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/bits/logo.html:23
#: mediagoblin/themes/airy/templates/mediagoblin/bits/logo.html:23
msgid "MediaGoblin logo"
@@ -601,13 +629,13 @@ msgid "Editing attachments for %(media_title)s"
msgstr ""
#: mediagoblin/templates/mediagoblin/edit/attachments.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:159
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:175
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:182
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:198
msgid "Attachments"
msgstr ""
#: mediagoblin/templates/mediagoblin/edit/attachments.html:57
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:181
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:204
msgid "Add attachment"
msgstr ""
@@ -624,12 +652,22 @@ msgstr "انصراÙ"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:63
#: mediagoblin/templates/mediagoblin/edit/edit.html:42
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:52
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:55
#: mediagoblin/templates/mediagoblin/edit/edit_collection.html:33
#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:40
msgid "Save changes"
msgstr "ذخیره تغییرات"
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:28
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:38
+#, python-format
+msgid "Changing %(username)s's password"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:45
+msgid "Save"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:28
#, python-format
msgid "Really delete user '%(user_name)s' and all related media/comments?"
@@ -640,7 +678,7 @@ msgid "Yes, really delete my account"
msgstr ""
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:47
+#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:48
#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:49
msgid "Delete permanently"
msgstr ""
@@ -657,7 +695,11 @@ msgstr "ویرایش %(media_title)s"
msgid "Changing %(username)s's account settings"
msgstr ""
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:59
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:46
+msgid "Change your password."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:62
msgid "Delete my account"
msgstr ""
@@ -682,6 +724,7 @@ msgstr ""
#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:56
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:65
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:136
#: mediagoblin/templates/mediagoblin/media_displays/video.html:55
msgid "Download"
@@ -706,6 +749,7 @@ msgid ""
msgstr ""
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:60
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:71
#: mediagoblin/templates/mediagoblin/media_displays/video.html:61
msgid "Original file"
msgstr ""
@@ -714,6 +758,7 @@ msgstr ""
msgid "WebM file (Vorbis codec)"
msgstr ""
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:59
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:87
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:93
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:99
@@ -724,6 +769,10 @@ msgstr ""
msgid "Image for %(media_title)s"
msgstr ""
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:79
+msgid "PDF file"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:112
msgid "Toggle Rotate"
msgstr ""
@@ -822,7 +871,7 @@ msgstr ""
msgid "Really remove %(media_title)s from %(collection_title)s?"
msgstr ""
-#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:53
+#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:54
msgid "Remove"
msgstr ""
@@ -865,23 +914,27 @@ msgstr "<a href=\"%(user_url)s\">%(username)s</a>'s رسانه های"
msgid "â– Browsing media by <a href=\"%(user_url)s\">%(username)s</a>"
msgstr ""
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:94
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:95
msgid "Add a comment"
msgstr ""
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:102
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:104
msgid "Add this comment"
msgstr ""
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:123
-msgid "at"
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:132
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:152
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:164
+#, python-format
+msgid "%(formatted_time)s ago"
msgstr ""
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:144
-#, python-format
-msgid ""
-"<h3>Added on</h3>\n"
-" <p>%(date)s</p>"
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:150
+msgid "Added"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:161
+msgid "Created"
msgstr ""
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:28
@@ -1038,7 +1091,7 @@ msgstr ""
msgid "Tagged with"
msgstr ""
-#: mediagoblin/tools/exif.py:80
+#: mediagoblin/tools/exif.py:83
msgid "Could not read the image file."
msgstr ""
@@ -1068,6 +1121,30 @@ msgid ""
" deleted."
msgstr ""
+#: mediagoblin/tools/timesince.py:62
+msgid "year"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:63
+msgid "month"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:64
+msgid "week"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:65
+msgid "day"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:66
+msgid "hour"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:67
+msgid "minute"
+msgstr ""
+
#: mediagoblin/user_pages/forms.py:23
msgid "Comment"
msgstr ""
@@ -1099,73 +1176,77 @@ msgstr ""
msgid "Include a note"
msgstr ""
-#: mediagoblin/user_pages/lib.py:56
+#: mediagoblin/user_pages/lib.py:58
msgid "commented on your post"
msgstr ""
-#: mediagoblin/user_pages/views.py:166
+#: mediagoblin/user_pages/views.py:169
+msgid "Sorry, comments are disabled."
+msgstr ""
+
+#: mediagoblin/user_pages/views.py:174
msgid "Oops, your comment was empty."
msgstr ""
-#: mediagoblin/user_pages/views.py:172
+#: mediagoblin/user_pages/views.py:180
msgid "Your comment has been posted!"
msgstr ""
-#: mediagoblin/user_pages/views.py:197
+#: mediagoblin/user_pages/views.py:205
msgid "Please check your entries and try again."
msgstr ""
-#: mediagoblin/user_pages/views.py:237
+#: mediagoblin/user_pages/views.py:245
msgid "You have to select or add a collection"
msgstr ""
-#: mediagoblin/user_pages/views.py:248
+#: mediagoblin/user_pages/views.py:256
#, python-format
msgid "\"%s\" already in collection \"%s\""
msgstr ""
-#: mediagoblin/user_pages/views.py:264
+#: mediagoblin/user_pages/views.py:262
#, python-format
msgid "\"%s\" added to collection \"%s\""
msgstr ""
-#: mediagoblin/user_pages/views.py:286
+#: mediagoblin/user_pages/views.py:282
msgid "You deleted the media."
msgstr ""
-#: mediagoblin/user_pages/views.py:293
+#: mediagoblin/user_pages/views.py:289
msgid "The media was not deleted because you didn't check that you were sure."
msgstr ""
-#: mediagoblin/user_pages/views.py:301
+#: mediagoblin/user_pages/views.py:296
msgid "You are about to delete another user's media. Proceed with caution."
msgstr ""
-#: mediagoblin/user_pages/views.py:375
+#: mediagoblin/user_pages/views.py:370
msgid "You deleted the item from the collection."
msgstr ""
-#: mediagoblin/user_pages/views.py:379
+#: mediagoblin/user_pages/views.py:374
msgid "The item was not removed because you didn't check that you were sure."
msgstr ""
-#: mediagoblin/user_pages/views.py:389
+#: mediagoblin/user_pages/views.py:382
msgid ""
"You are about to delete an item from another user's collection. Proceed with"
" caution."
msgstr ""
-#: mediagoblin/user_pages/views.py:422
+#: mediagoblin/user_pages/views.py:415
#, python-format
msgid "You deleted the collection \"%s\""
msgstr ""
-#: mediagoblin/user_pages/views.py:429
+#: mediagoblin/user_pages/views.py:422
msgid ""
"The collection was not deleted because you didn't check that you were sure."
msgstr ""
-#: mediagoblin/user_pages/views.py:439
+#: mediagoblin/user_pages/views.py:430
msgid ""
"You are about to delete another user's collection. Proceed with caution."
msgstr ""
diff --git a/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo
index ada992ce..7bc860a0 100644
--- a/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo
+++ b/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo
Binary files differ
diff --git a/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po
index b4c76bd2..6103c439 100644
--- a/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po
+++ b/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po
@@ -3,22 +3,22 @@
# This file is distributed under the same license as the PROJECT project.
#
# Translators:
-# <a5565930@nepwk.com>, 2011.
-# <alexispay@gmail.com>, 2012.
-# <chesuidayeur@yahoo.fr>, 2011.
-# <crash_bibit@hotmail.com>, 2013.
-# <joehillen@gmail.com>, 2011.
-# Laurent Pointecouteau <hell_pe@no-log.org>, 2013.
-# <marktraceur@gmail.com>, 2011.
-# <maxineb@members.fsf.org>, 2011.
-# <transifex@wandborg.se>, 2011.
-# Valentin Villenave <valentin@villenave.net>, 2011.
+# ianux <a5565930@nepwk.com>, 2011
+# alcazar <alexispay@gmail.com>, 2012
+# chesuidayeur <chesuidayeur@yahoo.fr>, 2011
+# Bibit <crash_bibit@hotmail.com>, 2013
+# joehillen <joehillen@gmail.com>, 2011
+# hellpe <hell_pe@no-log.org>, 2013
+# MarkTraceur <marktraceur@gmail.com>, 2011
+# maxineb <maxineb@members.fsf.org>, 2011
+# joar <transifex@wandborg.se>, 2011
+# Valentin Villenave <valentin@villenave.net>, 2011
msgid ""
msgstr ""
"Project-Id-Version: GNU MediaGoblin\n"
"Report-Msgid-Bugs-To: http://issues.mediagoblin.org/\n"
-"POT-Creation-Date: 2013-03-04 18:04-0600\n"
-"PO-Revision-Date: 2013-03-05 00:04+0000\n"
+"POT-Creation-Date: 2013-05-27 13:54-0500\n"
+"PO-Revision-Date: 2013-05-27 18:54+0000\n"
"Last-Translator: cwebber <cwebber@dustycloud.org>\n"
"Language-Team: French (http://www.transifex.com/projects/p/mediagoblin/language/fr/)\n"
"MIME-Version: 1.0\n"
@@ -28,34 +28,39 @@ msgstr ""
"Language: fr\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
-#: mediagoblin/auth/forms.py:28
-msgid "Invalid User name or email address."
-msgstr "Nom d'utilisateur ou adresse de courriel invalide."
-
-#: mediagoblin/auth/forms.py:29
-msgid "This field does not take email addresses."
-msgstr ""
-
-#: mediagoblin/auth/forms.py:30
-msgid "This field requires an email address."
-msgstr ""
-
-#: mediagoblin/auth/forms.py:52 mediagoblin/auth/forms.py:67
+#: mediagoblin/auth/forms.py:26
msgid "Username"
msgstr "Nom d'utilisateur"
-#: mediagoblin/auth/forms.py:56 mediagoblin/auth/forms.py:71
+#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:45
+#: mediagoblin/tests/test_util.py:110
msgid "Password"
msgstr "Mot de passe"
-#: mediagoblin/auth/forms.py:60
+#: mediagoblin/auth/forms.py:34
msgid "Email address"
msgstr "Adresse e-mail"
-#: mediagoblin/auth/forms.py:78
+#: mediagoblin/auth/forms.py:41
+msgid "Username or Email"
+msgstr ""
+
+#: mediagoblin/auth/forms.py:52
msgid "Username or email"
msgstr "Nom d'utilisateur ou email"
+#: mediagoblin/auth/tools.py:31
+msgid "Invalid User name or email address."
+msgstr "Nom d'utilisateur ou adresse de courriel invalide."
+
+#: mediagoblin/auth/tools.py:32
+msgid "This field does not take email addresses."
+msgstr ""
+
+#: mediagoblin/auth/tools.py:33
+msgid "This field requires an email address."
+msgstr ""
+
#: mediagoblin/auth/views.py:54
msgid "Sorry, registration is disabled on this instance."
msgstr "L'inscription n'est pas activée sur ce serveur, désolé."
@@ -68,54 +73,54 @@ msgstr "Un utilisateur existe déjà avec ce nom, désolé."
msgid "Sorry, a user with that email address already exists."
msgstr "Désolé, il existe déjà un utilisateur ayant cette adresse e-mail."
-#: mediagoblin/auth/views.py:174
+#: mediagoblin/auth/views.py:182
msgid ""
"Your email address has been verified. You may now login, edit your profile, "
"and submit images!"
msgstr "Votre adresse e-mail a bien été vérifiée. Vous pouvez maintenant vous identifier, modifier votre profil, et soumettre des images !"
-#: mediagoblin/auth/views.py:180
+#: mediagoblin/auth/views.py:188
msgid "The verification key or user id is incorrect"
msgstr "La clé de vérification ou le nom d'utilisateur est incorrect."
-#: mediagoblin/auth/views.py:198
+#: mediagoblin/auth/views.py:206
msgid "You must be logged in so we know who to send the email to!"
msgstr "Vous devez être authentifié afin que nous sachions à qui envoyer l'e-mail !"
-#: mediagoblin/auth/views.py:206
+#: mediagoblin/auth/views.py:214
msgid "You've already verified your email address!"
msgstr "Votre adresse e-mail a déjà été vérifiée !"
-#: mediagoblin/auth/views.py:219
+#: mediagoblin/auth/views.py:227
msgid "Resent your verification email."
msgstr "E-mail de vérification renvoyé."
-#: mediagoblin/auth/views.py:250
+#: mediagoblin/auth/views.py:258
msgid ""
"If that email address (case sensitive!) is registered an email has been sent"
" with instructions on how to change your password."
msgstr ""
-#: mediagoblin/auth/views.py:261
+#: mediagoblin/auth/views.py:269
msgid "Couldn't find someone with that username."
msgstr "Nom d'utilisateur introuvable."
-#: mediagoblin/auth/views.py:264
+#: mediagoblin/auth/views.py:272
msgid ""
"An email has been sent with instructions on how to change your password."
msgstr "Un email contenant les instructions pour changer votre mot de passe viens de vous être envoyé"
-#: mediagoblin/auth/views.py:271
+#: mediagoblin/auth/views.py:279
msgid ""
"Could not send password recovery email as your username is inactive or your "
"account's email address has not been verified."
msgstr "Impossible d'envoyer un email de récupération de mot de passe : votre compte est inactif ou bien l'email de votre compte n'a pas été vérifiée."
-#: mediagoblin/auth/views.py:328
+#: mediagoblin/auth/views.py:336
msgid "You can now log in using your new password."
msgstr "Vous pouvez maintenant vous connecter avec votre nouveau mot de passe."
-#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:93
+#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:82
#: mediagoblin/submit/forms.py:28 mediagoblin/submit/forms.py:47
#: mediagoblin/user_pages/forms.py:45
msgid "Title"
@@ -126,7 +131,7 @@ msgid "Description of this work"
msgstr "Descriptif pour ce travail"
#: mediagoblin/edit/forms.py:29 mediagoblin/edit/forms.py:52
-#: mediagoblin/edit/forms.py:97 mediagoblin/submit/forms.py:32
+#: mediagoblin/edit/forms.py:86 mediagoblin/submit/forms.py:32
#: mediagoblin/submit/forms.py:51 mediagoblin/user_pages/forms.py:49
msgid ""
"You can use\n"
@@ -142,11 +147,11 @@ msgstr "Tags"
msgid "Separate tags by commas."
msgstr "Séparez les champs avec des virgules."
-#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:101
+#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:90
msgid "Slug"
msgstr "Légende"
-#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:102
+#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:91
msgid "The slug can't be empty"
msgstr "La légende ne peut pas être laissée vide."
@@ -174,45 +179,45 @@ msgid "This address contains errors"
msgstr "Cette adresse contiens des erreurs"
#: mediagoblin/edit/forms.py:63
-msgid "Old password"
-msgstr "Ancien mot de passe."
-
-#: mediagoblin/edit/forms.py:64
-msgid "Enter your old password to prove you own this account."
-msgstr "Entrez votre ancien mot de passe pour prouver que vous êtes bien le propriétaire de ce compte."
-
-#: mediagoblin/edit/forms.py:67
-msgid "New password"
-msgstr "Nouveau mot de passe"
-
-#: mediagoblin/edit/forms.py:74
msgid "License preference"
msgstr ""
-#: mediagoblin/edit/forms.py:80
+#: mediagoblin/edit/forms.py:69
msgid "This will be your default license on upload forms."
msgstr ""
-#: mediagoblin/edit/forms.py:82
+#: mediagoblin/edit/forms.py:71
msgid "Email me when others comment on my media"
msgstr "Me prévenir par email lorsque d'autres commentent mes médias"
-#: mediagoblin/edit/forms.py:94
+#: mediagoblin/edit/forms.py:83
msgid "The title can't be empty"
msgstr "Le titre ne peut être vide"
-#: mediagoblin/edit/forms.py:96 mediagoblin/submit/forms.py:50
+#: mediagoblin/edit/forms.py:85 mediagoblin/submit/forms.py:50
#: mediagoblin/user_pages/forms.py:48
msgid "Description of this collection"
msgstr "Description de cette collection"
-#: mediagoblin/edit/forms.py:103
+#: mediagoblin/edit/forms.py:92
msgid ""
"The title part of this collection's address. You usually don't need to "
"change this."
msgstr "Le titre affiché dans l'URL de la collection. Vous n'avez généralement pas besoin d'y toucher."
-#: mediagoblin/edit/views.py:66
+#: mediagoblin/edit/forms.py:99
+msgid "Old password"
+msgstr "Ancien mot de passe."
+
+#: mediagoblin/edit/forms.py:101
+msgid "Enter your old password to prove you own this account."
+msgstr "Entrez votre ancien mot de passe pour prouver que vous êtes bien le propriétaire de ce compte."
+
+#: mediagoblin/edit/forms.py:104
+msgid "New password"
+msgstr "Nouveau mot de passe"
+
+#: mediagoblin/edit/views.py:67
msgid "An entry with that slug already exists for this user."
msgstr "Une entrée existe déjà pour cet utilisateur avec la même légende."
@@ -237,44 +242,63 @@ msgstr "Vous vous apprêtez à modifier le profil d'un utilisateur. Veuillez pre
msgid "Profile changes saved"
msgstr "Les changements apportés au profile ont étés sauvegardés"
-#: mediagoblin/edit/views.py:241
-msgid "Wrong password"
-msgstr "Mauvais mot de passe"
-
-#: mediagoblin/edit/views.py:252
+#: mediagoblin/edit/views.py:240
msgid "Account settings saved"
msgstr "Les changements des préférences du compte ont étés sauvegardés"
-#: mediagoblin/edit/views.py:286
+#: mediagoblin/edit/views.py:274
msgid "You need to confirm the deletion of your account."
msgstr "Vous devez confirmer la suppression de votre compte."
-#: mediagoblin/edit/views.py:322 mediagoblin/submit/views.py:142
-#: mediagoblin/user_pages/views.py:214
+#: mediagoblin/edit/views.py:310 mediagoblin/submit/views.py:138
+#: mediagoblin/user_pages/views.py:222
#, python-format
msgid "You already have a collection called \"%s\"!"
msgstr "Vous avez déjà une collection appelée \"%s\" !"
-#: mediagoblin/edit/views.py:326
+#: mediagoblin/edit/views.py:314
msgid "A collection with that slug already exists for this user."
msgstr ""
-#: mediagoblin/edit/views.py:343
+#: mediagoblin/edit/views.py:329
msgid "You are editing another user's collection. Proceed with caution."
msgstr "Vous éditez la collection d'un autre utilisateurs. Faites attention."
-#: mediagoblin/gmg_commands/theme.py:58
+#: mediagoblin/edit/views.py:348
+msgid "Wrong password"
+msgstr "Mauvais mot de passe"
+
+#: mediagoblin/edit/views.py:363
+msgid "Your password was changed successfully"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:60
msgid "Cannot link theme... no theme set\n"
msgstr "Impossible de lier le thème... Aucun thème associé\n"
-#: mediagoblin/gmg_commands/theme.py:71
+#: mediagoblin/gmg_commands/assetlink.py:73
msgid "No asset directory for this theme\n"
msgstr "Aucun répertoire \"asset\" pour ce thème\n"
-#: mediagoblin/gmg_commands/theme.py:74
+#: mediagoblin/gmg_commands/assetlink.py:76
msgid "However, old link directory symlink found; removed.\n"
msgstr ""
+#: mediagoblin/gmg_commands/assetlink.py:112
+#, python-format
+msgid "Could not link \"%s\": %s exists and is not a symlink\n"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:119
+#, python-format
+msgid "Skipping \"%s\"; already set up.\n"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:124
+#, python-format
+msgid "Old link found for \"%s\"; removing.\n"
+msgstr ""
+
#: mediagoblin/meddleware/csrf.py:134
msgid ""
"CSRF cookie not present. This is most likely the result of a cookie blocker "
@@ -282,12 +306,16 @@ msgid ""
"domain."
msgstr ""
-#: mediagoblin/media_types/__init__.py:61
-#: mediagoblin/media_types/__init__.py:102
+#: mediagoblin/media_types/__init__.py:111
+#: mediagoblin/media_types/__init__.py:155
msgid "Sorry, I don't support that file type :("
msgstr "Désolé, mais je ne prends pas en charge cette extension de fichier :("
-#: mediagoblin/media_types/video/processing.py:36
+#: mediagoblin/media_types/pdf/processing.py:136
+msgid "unoconv failing to run, check log file"
+msgstr ""
+
+#: mediagoblin/media_types/video/processing.py:37
msgid "Video transcoding failed"
msgstr "L'encodage de la vidéo à échoué"
@@ -354,7 +382,7 @@ msgstr "L'URI de redirection pour l'application, ce champ est <strong>requis</st
msgid "This field is required for public clients"
msgstr "Ce champ est requis pour les clients publics"
-#: mediagoblin/plugins/oauth/views.py:59
+#: mediagoblin/plugins/oauth/views.py:56
msgid "The client {0} has been registered!"
msgstr "Le client {0} as été enregistré !"
@@ -373,7 +401,7 @@ msgstr ""
msgid "Add"
msgstr "Ajouter"
-#: mediagoblin/processing/__init__.py:172
+#: mediagoblin/processing/__init__.py:193
msgid "Invalid file given for media type."
msgstr "Le fichier envoyé ne correspond pas au type de média."
@@ -381,45 +409,45 @@ msgstr "Le fichier envoyé ne correspond pas au type de média."
msgid "File"
msgstr "Fichier"
-#: mediagoblin/submit/views.py:51
+#: mediagoblin/submit/views.py:49
msgid "You must provide a file."
msgstr "Il vous faut fournir un fichier."
-#: mediagoblin/submit/views.py:97
+#: mediagoblin/submit/views.py:93
msgid "Woohoo! Submitted!"
msgstr "Youhou, c'est envoyé !"
-#: mediagoblin/submit/views.py:146
+#: mediagoblin/submit/views.py:144
#, python-format
msgid "Collection \"%s\" added!"
msgstr "Collection \"%s\" ajoutée !"
-#: mediagoblin/templates/mediagoblin/base.html:64
+#: mediagoblin/templates/mediagoblin/base.html:67
msgid "Verify your email!"
msgstr "Vérifiez votre adresse e-mail !"
-#: mediagoblin/templates/mediagoblin/base.html:65
+#: mediagoblin/templates/mediagoblin/base.html:68
msgid "log out"
msgstr "Déconnexion"
-#: mediagoblin/templates/mediagoblin/base.html:70
+#: mediagoblin/templates/mediagoblin/base.html:73
#: mediagoblin/templates/mediagoblin/auth/login.html:28
#: mediagoblin/templates/mediagoblin/auth/login.html:36
#: mediagoblin/templates/mediagoblin/auth/login.html:54
msgid "Log in"
msgstr "S'identifier"
-#: mediagoblin/templates/mediagoblin/base.html:79
+#: mediagoblin/templates/mediagoblin/base.html:82
#, python-format
msgid "<a href=\"%(user_url)s\">%(user_name)s</a>'s account"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:86
+#: mediagoblin/templates/mediagoblin/base.html:89
msgid "Change account settings"
msgstr "Changer les paramètres du compte"
-#: mediagoblin/templates/mediagoblin/base.html:90
-#: mediagoblin/templates/mediagoblin/base.html:105
+#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:108
#: mediagoblin/templates/mediagoblin/admin/panel.html:21
#: mediagoblin/templates/mediagoblin/admin/panel.html:26
#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:21
@@ -427,72 +455,25 @@ msgstr "Changer les paramètres du compte"
msgid "Media processing panel"
msgstr "Panneau pour le traitement des médias"
-#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:96
msgid "Log out"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:96
+#: mediagoblin/templates/mediagoblin/base.html:99
#: mediagoblin/templates/mediagoblin/user_pages/user.html:156
msgid "Add media"
msgstr "Ajouter des médias"
-#: mediagoblin/templates/mediagoblin/base.html:99
+#: mediagoblin/templates/mediagoblin/base.html:102
#: mediagoblin/templates/mediagoblin/user_pages/collection_list.html:41
msgid "Create new collection"
msgstr "Créer une nouvelle collection"
-#: mediagoblin/templates/mediagoblin/base.html:122
-#, python-format
-msgid ""
-"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
-"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/base.html:125
-#, python-format
-msgid ""
-"Released under the <a "
-"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
-"href=\"%(source_link)s\">Source code</a> available."
-msgstr "Disponible sous la licence <a href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a href=\"%(source_link)s\">Code source</a> disponible."
-
#: mediagoblin/templates/mediagoblin/error.html:24
msgid "Image of goblin stressing out"
msgstr ""
-#: mediagoblin/templates/mediagoblin/root.html:31
-msgid "Explore"
-msgstr "Explorer"
-
-#: mediagoblin/templates/mediagoblin/root.html:33
-msgid "Hi there, welcome to this MediaGoblin site!"
-msgstr "Bonjour, et bienvenue sur ce site MediaGoblin !"
-
-#: mediagoblin/templates/mediagoblin/root.html:35
-msgid ""
-"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
-"extraordinarily great piece of media hosting software."
-msgstr "Ce site fait tourner <a href=\"http://mediagoblin.org\">MediaGoblin</a>, un logiciel d'hébergement de média extraordinairement génial."
-
-#: mediagoblin/templates/mediagoblin/root.html:36
-msgid ""
-"To add your own media, place comments, and more, you can log in with your "
-"MediaGoblin account."
-msgstr "Pour ajouter vos propres médias, commenter, et bien plus encore, vous pouvez vous connecter avec votre compte MediaGoblin"
-
-#: mediagoblin/templates/mediagoblin/root.html:38
-msgid "Don't have one yet? It's easy!"
-msgstr "Vous n'en avez pas ? C'est facile !"
-
-#: mediagoblin/templates/mediagoblin/root.html:39
-#, python-format
-msgid ""
-"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
-" or\n"
-" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
-msgstr "<a class=\"button_action_highlight\" href=\"%(register_url)s\">Créez un compte sur ce site</a>\n ou\n <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Déployez MediaGoblin sur votre propre serveur</a>"
-
-#: mediagoblin/templates/mediagoblin/root.html:47
+#: mediagoblin/templates/mediagoblin/root.html:32
msgid "Most recent media"
msgstr "Tout derniers media"
@@ -598,6 +579,53 @@ msgid ""
"%(verification_url)s"
msgstr "Bonjour %(username)s,\n\npour activer votre compte sur GNU MediaGoblin, veuillez vous rendre à l'adresse suivante avec votre navigateur web:\n\n%(verification_url)s"
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:21
+#, python-format
+msgid ""
+"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
+"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:24
+#, python-format
+msgid ""
+"Released under the <a "
+"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
+"href=\"%(source_link)s\">Source code</a> available."
+msgstr "Disponible sous la licence <a href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a href=\"%(source_link)s\">Code source</a> disponible."
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:20
+msgid "Explore"
+msgstr "Explorer"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:22
+msgid "Hi there, welcome to this MediaGoblin site!"
+msgstr "Bonjour, et bienvenue sur ce site MediaGoblin !"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:24
+msgid ""
+"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
+"extraordinarily great piece of media hosting software."
+msgstr "Ce site fait tourner <a href=\"http://mediagoblin.org\">MediaGoblin</a>, un logiciel d'hébergement de média extraordinairement génial."
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:25
+msgid ""
+"To add your own media, place comments, and more, you can log in with your "
+"MediaGoblin account."
+msgstr "Pour ajouter vos propres médias, commenter, et bien plus encore, vous pouvez vous connecter avec votre compte MediaGoblin"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:27
+msgid "Don't have one yet? It's easy!"
+msgstr "Vous n'en avez pas ? C'est facile !"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:28
+#, python-format
+msgid ""
+"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
+" or\n"
+" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/bits/logo.html:23
#: mediagoblin/themes/airy/templates/mediagoblin/bits/logo.html:23
msgid "MediaGoblin logo"
@@ -610,13 +638,13 @@ msgid "Editing attachments for %(media_title)s"
msgstr "Éditer les pièces jointes de %(media_title)s"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:159
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:175
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:182
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:198
msgid "Attachments"
msgstr "Pièces jointes"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:57
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:181
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:204
msgid "Add attachment"
msgstr "Ajouter une pièce jointe"
@@ -633,12 +661,22 @@ msgstr "Annuler"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:63
#: mediagoblin/templates/mediagoblin/edit/edit.html:42
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:52
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:55
#: mediagoblin/templates/mediagoblin/edit/edit_collection.html:33
#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:40
msgid "Save changes"
msgstr "Enregistrer les modifications"
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:28
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:38
+#, python-format
+msgid "Changing %(username)s's password"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:45
+msgid "Save"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:28
#, python-format
msgid "Really delete user '%(user_name)s' and all related media/comments?"
@@ -649,7 +687,7 @@ msgid "Yes, really delete my account"
msgstr ""
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:47
+#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:48
#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:49
msgid "Delete permanently"
msgstr "Supprimer définitivement"
@@ -666,7 +704,11 @@ msgstr "Modification de %(media_title)s"
msgid "Changing %(username)s's account settings"
msgstr "Changement des préférences du compte de %(username)s"
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:59
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:46
+msgid "Change your password."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:62
msgid "Delete my account"
msgstr ""
@@ -691,6 +733,7 @@ msgstr "Médias taggés avec : %(tag_name)s "
#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:56
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:65
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:136
#: mediagoblin/templates/mediagoblin/media_displays/video.html:55
msgid "Download"
@@ -715,6 +758,7 @@ msgid ""
msgstr "Vous pouvez obtenir un navigateur à jour capable de lire cette vidéo sur <a href=\"http://getfirefox.com\">\n\t http://getfirefox.com</a>!"
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:60
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:71
#: mediagoblin/templates/mediagoblin/media_displays/video.html:61
msgid "Original file"
msgstr "Fichier original"
@@ -723,6 +767,7 @@ msgstr "Fichier original"
msgid "WebM file (Vorbis codec)"
msgstr "fichier WebM (codec Vorbis)"
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:59
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:87
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:93
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:99
@@ -733,6 +778,10 @@ msgstr "fichier WebM (codec Vorbis)"
msgid "Image for %(media_title)s"
msgstr "Image de %(media_title)s"
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:79
+msgid "PDF file"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:112
msgid "Toggle Rotate"
msgstr ""
@@ -831,7 +880,7 @@ msgstr "Voulez-vous vraiment supprimer %(title)s ?"
msgid "Really remove %(media_title)s from %(collection_title)s?"
msgstr "Voulez vous vraiment retirer %(media_title)s de %(collection_title)s ?"
-#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:53
+#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:54
msgid "Remove"
msgstr "Retirer"
@@ -874,24 +923,28 @@ msgstr "Médias de <a href=\"%(user_url)s\">%(username)s</a>"
msgid "â– Browsing media by <a href=\"%(user_url)s\">%(username)s</a>"
msgstr "■Parcourir les médias de <a href=\"%(user_url)s\">%(username)s</a>"
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:94
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:95
msgid "Add a comment"
msgstr "Ajouter un commentaire"
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:102
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:104
msgid "Add this comment"
msgstr "Ajouter ce commentaire"
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:123
-msgid "at"
-msgstr "à"
-
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:144
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:132
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:152
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:164
#, python-format
-msgid ""
-"<h3>Added on</h3>\n"
-" <p>%(date)s</p>"
-msgstr "<h3>Ajouté le</h3>\n<p>%(date)s</p>"
+msgid "%(formatted_time)s ago"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:150
+msgid "Added"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:161
+msgid "Created"
+msgstr ""
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:28
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:40
@@ -1047,7 +1100,7 @@ msgstr "le plus vieux"
msgid "Tagged with"
msgstr "Taggé avec"
-#: mediagoblin/tools/exif.py:80
+#: mediagoblin/tools/exif.py:83
msgid "Could not read the image file."
msgstr "Impossible de lire l'image."
@@ -1077,6 +1130,30 @@ msgid ""
" deleted."
msgstr "Il ne semble pas y avoir de page à cette adresse. Désolé ! </p><p>Si vous êtes sûr que l'adresse est correcte, peut-être que la page que vous recherchez a été déplacée ou supprimée."
+#: mediagoblin/tools/timesince.py:62
+msgid "year"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:63
+msgid "month"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:64
+msgid "week"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:65
+msgid "day"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:66
+msgid "hour"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:67
+msgid "minute"
+msgstr ""
+
#: mediagoblin/user_pages/forms.py:23
msgid "Comment"
msgstr ""
@@ -1108,73 +1185,77 @@ msgstr "-- Sélectionner --"
msgid "Include a note"
msgstr "Inclure une note"
-#: mediagoblin/user_pages/lib.py:56
+#: mediagoblin/user_pages/lib.py:58
msgid "commented on your post"
msgstr "a commenté votre post"
-#: mediagoblin/user_pages/views.py:166
+#: mediagoblin/user_pages/views.py:169
+msgid "Sorry, comments are disabled."
+msgstr ""
+
+#: mediagoblin/user_pages/views.py:174
msgid "Oops, your comment was empty."
msgstr "Oups, votre commentaire était vide."
-#: mediagoblin/user_pages/views.py:172
+#: mediagoblin/user_pages/views.py:180
msgid "Your comment has been posted!"
msgstr "Votre commentaire a été posté !"
-#: mediagoblin/user_pages/views.py:197
+#: mediagoblin/user_pages/views.py:205
msgid "Please check your entries and try again."
msgstr "Veuillez vérifier vos entrées et réessayer."
-#: mediagoblin/user_pages/views.py:237
+#: mediagoblin/user_pages/views.py:245
msgid "You have to select or add a collection"
msgstr "Vous devez sélectionner ou ajouter une collection"
-#: mediagoblin/user_pages/views.py:248
+#: mediagoblin/user_pages/views.py:256
#, python-format
msgid "\"%s\" already in collection \"%s\""
msgstr "\"%s\" est déjà dans la collection \"%s\""
-#: mediagoblin/user_pages/views.py:264
+#: mediagoblin/user_pages/views.py:262
#, python-format
msgid "\"%s\" added to collection \"%s\""
msgstr "\"%s\" as été ajouté à la collection \"%s\""
-#: mediagoblin/user_pages/views.py:286
+#: mediagoblin/user_pages/views.py:282
msgid "You deleted the media."
msgstr "Vous avez supprimé le media."
-#: mediagoblin/user_pages/views.py:293
+#: mediagoblin/user_pages/views.py:289
msgid "The media was not deleted because you didn't check that you were sure."
msgstr "Ce media n'a pas été supprimé car vous n'avez pas confirmer que vous étiez sur."
-#: mediagoblin/user_pages/views.py:301
+#: mediagoblin/user_pages/views.py:296
msgid "You are about to delete another user's media. Proceed with caution."
msgstr "Vous êtes sur le point de supprimer des médias d'un autre utilisateur. Procédez avec prudence."
-#: mediagoblin/user_pages/views.py:375
+#: mediagoblin/user_pages/views.py:370
msgid "You deleted the item from the collection."
msgstr "Vous avez supprimé cet élément de la collection."
-#: mediagoblin/user_pages/views.py:379
+#: mediagoblin/user_pages/views.py:374
msgid "The item was not removed because you didn't check that you were sure."
msgstr "L'élément n'as pas été supprimé car vous n'avez pas confirmé votre certitude."
-#: mediagoblin/user_pages/views.py:389
+#: mediagoblin/user_pages/views.py:382
msgid ""
"You are about to delete an item from another user's collection. Proceed with"
" caution."
msgstr "Vous vous apprêtez à supprimer un élément de la collection d'un autre utilisateur. Procédez avec attention."
-#: mediagoblin/user_pages/views.py:422
+#: mediagoblin/user_pages/views.py:415
#, python-format
msgid "You deleted the collection \"%s\""
msgstr "Vous avez supprimé la collection \"%s\""
-#: mediagoblin/user_pages/views.py:429
+#: mediagoblin/user_pages/views.py:422
msgid ""
"The collection was not deleted because you didn't check that you were sure."
msgstr "La collection n'as pas été supprimée car vous n'avez pas confirmé votre certitude"
-#: mediagoblin/user_pages/views.py:439
+#: mediagoblin/user_pages/views.py:430
msgid ""
"You are about to delete another user's collection. Proceed with caution."
msgstr "Vous vous apprêtez à supprimer la collection d'un autre utilisateur. Procédez avec attention."
diff --git a/mediagoblin/i18n/he/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/he/LC_MESSAGES/mediagoblin.mo
index ce2963f7..09412b0a 100644
--- a/mediagoblin/i18n/he/LC_MESSAGES/mediagoblin.mo
+++ b/mediagoblin/i18n/he/LC_MESSAGES/mediagoblin.mo
Binary files differ
diff --git a/mediagoblin/i18n/he/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/he/LC_MESSAGES/mediagoblin.po
index 12d932c8..4a5c2b52 100644
--- a/mediagoblin/i18n/he/LC_MESSAGES/mediagoblin.po
+++ b/mediagoblin/i18n/he/LC_MESSAGES/mediagoblin.po
@@ -3,16 +3,17 @@
# This file is distributed under the same license as the PROJECT project.
#
# Translators:
-# <genghiskhan@gmx.ca>, 2012.
-# Isratine Citizen <genghiskhan@gmx.ca>, 2012.
+# GenghisKhan <genghiskhan@gmx.ca>, 2013
+# GenghisKhan <genghiskhan@gmx.ca>, 2012
+# GenghisKhan <genghiskhan@gmx.ca>, 2012
msgid ""
msgstr ""
"Project-Id-Version: GNU MediaGoblin\n"
"Report-Msgid-Bugs-To: http://issues.mediagoblin.org/\n"
-"POT-Creation-Date: 2013-03-04 18:04-0600\n"
-"PO-Revision-Date: 2013-03-05 00:04+0000\n"
-"Last-Translator: cwebber <cwebber@dustycloud.org>\n"
-"Language-Team: LANGUAGE <LL@li.org>\n"
+"POT-Creation-Date: 2013-05-27 13:54-0500\n"
+"PO-Revision-Date: 2013-06-01 07:11+0000\n"
+"Last-Translator: GenghisKhan <genghiskhan@gmx.ca>\n"
+"Language-Team: Hebrew (http://www.transifex.com/projects/p/mediagoblin/language/he/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
@@ -20,34 +21,39 @@ msgstr ""
"Language: he\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: mediagoblin/auth/forms.py:28
-msgid "Invalid User name or email address."
-msgstr ""
-
-#: mediagoblin/auth/forms.py:29
-msgid "This field does not take email addresses."
-msgstr ""
-
-#: mediagoblin/auth/forms.py:30
-msgid "This field requires an email address."
-msgstr ""
-
-#: mediagoblin/auth/forms.py:52 mediagoblin/auth/forms.py:67
+#: mediagoblin/auth/forms.py:26
msgid "Username"
msgstr "×©× ×ž×©×ª×ž×©"
-#: mediagoblin/auth/forms.py:56 mediagoblin/auth/forms.py:71
+#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:45
+#: mediagoblin/tests/test_util.py:110
msgid "Password"
msgstr "סיסמה"
-#: mediagoblin/auth/forms.py:60
+#: mediagoblin/auth/forms.py:34
msgid "Email address"
msgstr "כתובת דו×״ל"
-#: mediagoblin/auth/forms.py:78
+#: mediagoblin/auth/forms.py:41
+msgid "Username or Email"
+msgstr "×©× ×ž×©×ª×ž×© ×ו דו×״ל"
+
+#: mediagoblin/auth/forms.py:52
msgid "Username or email"
msgstr "×©× ×ž×©×ª×ž×© ×ו דו×״ל"
+#: mediagoblin/auth/tools.py:31
+msgid "Invalid User name or email address."
+msgstr "×©× ×ž×©×ª×ž×© ×ו דו×״ל שגוי."
+
+#: mediagoblin/auth/tools.py:32
+msgid "This field does not take email addresses."
+msgstr "שדה ×–×” ×œ× ×œ×•×§×— כתובות דו×״ל."
+
+#: mediagoblin/auth/tools.py:33
+msgid "This field requires an email address."
+msgstr "שדה ×–×” מצריך כתובת דו×״ל."
+
#: mediagoblin/auth/views.py:54
msgid "Sorry, registration is disabled on this instance."
msgstr "צר לי, ×¨×™×©×•× ×”×™× ×• מנוטרל על שרת ×–×”."
@@ -60,54 +66,54 @@ msgstr "צר לי, משתמש ×¢× ×©× ×–×” כבר ×§×™×™×."
msgid "Sorry, a user with that email address already exists."
msgstr "צר לי, משתמש ×¢× ×“×•×״ל ×–×” כבר ×§×™×™×."
-#: mediagoblin/auth/views.py:174
+#: mediagoblin/auth/views.py:182
msgid ""
"Your email address has been verified. You may now login, edit your profile, "
"and submit images!"
msgstr "כתובת הדו×״ל שלך ×ומתה. כעת ב×פשרותך להתחבר, לערוך ×ת דיוקנך, ולשלוח תמונות!"
-#: mediagoblin/auth/views.py:180
+#: mediagoblin/auth/views.py:188
msgid "The verification key or user id is incorrect"
msgstr "מפתח ×”×ימות ×ו זהות משתמש ×”×™× × ×©×’×•×™×™×"
-#: mediagoblin/auth/views.py:198
+#: mediagoblin/auth/views.py:206
msgid "You must be logged in so we know who to send the email to!"
msgstr "עליך להתחבר על מנת שנדע ×ל מי לשלוח ×ת הדו×״ל!"
-#: mediagoblin/auth/views.py:206
+#: mediagoblin/auth/views.py:214
msgid "You've already verified your email address!"
msgstr "כבר ×ימתת ×ת כתובת הדו×״ל שלך!"
-#: mediagoblin/auth/views.py:219
+#: mediagoblin/auth/views.py:227
msgid "Resent your verification email."
msgstr "שלח שוב ×ת דו×״ל ×”×ימות שלך."
-#: mediagoblin/auth/views.py:250
+#: mediagoblin/auth/views.py:258
msgid ""
"If that email address (case sensitive!) is registered an email has been sent"
" with instructions on how to change your password."
-msgstr ""
+msgstr "במידה וכתובת הדו×״ל הזו (תלוי רישיות!) רשומה דו×״ל נשלח ×¢× ×”×•×¨×ות בנוגע לכיצד לשנות ×ת סיסמתך."
-#: mediagoblin/auth/views.py:261
+#: mediagoblin/auth/views.py:269
msgid "Couldn't find someone with that username."
-msgstr ""
+msgstr "×œ× ×”×™×” ניתן ×œ×ž×¦×•× ×ž×™×©×”×• ×¢× ×©× ×ž×©×ª×ž×© ×–×”."
-#: mediagoblin/auth/views.py:264
+#: mediagoblin/auth/views.py:272
msgid ""
"An email has been sent with instructions on how to change your password."
msgstr "דו×״ל נשלח בצירוף הור×ות בנוגע לכיצד ניתן לשנות ×ת סיסמתך."
-#: mediagoblin/auth/views.py:271
+#: mediagoblin/auth/views.py:279
msgid ""
"Could not send password recovery email as your username is inactive or your "
"account's email address has not been verified."
msgstr "×œ× ×”×™×” ניתן לשלוח דו×״ל לשחזור סיסמה מ×חר ×•×©× ×”×ž×©×ª×ž×© שלך ×ינו פעיל ×ו שכתובת הדו×״ל של חשבונך ×œ× ×ומתה."
-#: mediagoblin/auth/views.py:328
+#: mediagoblin/auth/views.py:336
msgid "You can now log in using your new password."
msgstr "כעת ביכולתך להתחבר ב×מצעות סיסמתך החדשה."
-#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:93
+#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:82
#: mediagoblin/submit/forms.py:28 mediagoblin/submit/forms.py:47
#: mediagoblin/user_pages/forms.py:45
msgid "Title"
@@ -118,7 +124,7 @@ msgid "Description of this work"
msgstr "תי×ור של מל××›×” זו"
#: mediagoblin/edit/forms.py:29 mediagoblin/edit/forms.py:52
-#: mediagoblin/edit/forms.py:97 mediagoblin/submit/forms.py:32
+#: mediagoblin/edit/forms.py:86 mediagoblin/submit/forms.py:32
#: mediagoblin/submit/forms.py:51 mediagoblin/user_pages/forms.py:49
msgid ""
"You can use\n"
@@ -134,11 +140,11 @@ msgstr "תגיות"
msgid "Separate tags by commas."
msgstr "הפרד תגיות בעזרת פסיקי×."
-#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:101
+#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:90
msgid "Slug"
msgstr "חשופית"
-#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:102
+#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:91
msgid "The slug can't be empty"
msgstr "החשופית ×œ× ×™×›×•×œ×” להיות ריקה"
@@ -166,45 +172,45 @@ msgid "This address contains errors"
msgstr "כתובת זו מכילה שגי×ות"
#: mediagoblin/edit/forms.py:63
-msgid "Old password"
-msgstr "סיסמה ישנה"
-
-#: mediagoblin/edit/forms.py:64
-msgid "Enter your old password to prove you own this account."
-msgstr "הזן ×ת סיסמתך הישנה כדי להוכיח ש×תה ×”×‘×¢×œ×™× ×©×œ חשבון ×–×”."
-
-#: mediagoblin/edit/forms.py:67
-msgid "New password"
-msgstr "סיסמה חדשה"
-
-#: mediagoblin/edit/forms.py:74
msgid "License preference"
-msgstr ""
+msgstr "עדיפות רשיון"
-#: mediagoblin/edit/forms.py:80
+#: mediagoblin/edit/forms.py:69
msgid "This will be your default license on upload forms."
-msgstr ""
+msgstr "×–×” ×™×”×™×” הרשיוןן המשתמט (ברירת מחדל) שלך בטופסי העל××”."
-#: mediagoblin/edit/forms.py:82
+#: mediagoblin/edit/forms.py:71
msgid "Email me when others comment on my media"
msgstr "שלח לי דו×״ל ×›×שר ××—×¨×™× ×ž×’×™×‘×™× ×¢×œ המדיה שלי"
-#: mediagoblin/edit/forms.py:94
+#: mediagoblin/edit/forms.py:83
msgid "The title can't be empty"
msgstr "הכותרת ×œ× ×™×›×•×œ×” להיות ריקה"
-#: mediagoblin/edit/forms.py:96 mediagoblin/submit/forms.py:50
+#: mediagoblin/edit/forms.py:85 mediagoblin/submit/forms.py:50
#: mediagoblin/user_pages/forms.py:48
msgid "Description of this collection"
msgstr "תי×ור ×וסף ×–×”"
-#: mediagoblin/edit/forms.py:103
+#: mediagoblin/edit/forms.py:92
msgid ""
"The title part of this collection's address. You usually don't need to "
"change this."
msgstr "×זור הכותרת של כתובת ×וסף ×–×”. לרוב ×ין הכרח לשנות ×ת חלק ×–×”."
-#: mediagoblin/edit/views.py:66
+#: mediagoblin/edit/forms.py:99
+msgid "Old password"
+msgstr "סיסמה ישנה"
+
+#: mediagoblin/edit/forms.py:101
+msgid "Enter your old password to prove you own this account."
+msgstr "הזן ×ת סיסמתך הישנה כדי להוכיח ש×תה ×”×‘×¢×œ×™× ×©×œ חשבון ×–×”."
+
+#: mediagoblin/edit/forms.py:104
+msgid "New password"
+msgstr "סיסמה חדשה"
+
+#: mediagoblin/edit/views.py:67
msgid "An entry with that slug already exists for this user."
msgstr "רשומה ×¢× ×—×©×•×¤×™×ª זו כבר קיימת עבור משתמש ×–×”."
@@ -219,7 +225,7 @@ msgstr "הוספת ×ת התצריף %s!"
#: mediagoblin/edit/views.py:182
msgid "You can only edit your own profile."
-msgstr ""
+msgstr "ב×פשרותך לערוך רק ×ת הדיוקן שלך."
#: mediagoblin/edit/views.py:188
msgid "You are editing a user's profile. Proceed with caution."
@@ -229,57 +235,80 @@ msgstr "×תה עורך דיוקן של משתמש. המשך בזהירות."
msgid "Profile changes saved"
msgstr "שינויי דיוקן נשמרו"
-#: mediagoblin/edit/views.py:241
-msgid "Wrong password"
-msgstr "סיסמה שגויה"
-
-#: mediagoblin/edit/views.py:252
+#: mediagoblin/edit/views.py:240
msgid "Account settings saved"
msgstr "הגדרות חשבון נשמרו"
-#: mediagoblin/edit/views.py:286
+#: mediagoblin/edit/views.py:274
msgid "You need to confirm the deletion of your account."
-msgstr ""
+msgstr "עליך ל×מת ×ת המחיקה של חשבונך."
-#: mediagoblin/edit/views.py:322 mediagoblin/submit/views.py:142
-#: mediagoblin/user_pages/views.py:214
+#: mediagoblin/edit/views.py:310 mediagoblin/submit/views.py:138
+#: mediagoblin/user_pages/views.py:222
#, python-format
msgid "You already have a collection called \"%s\"!"
msgstr "כבר יש לך ×וסף שקרוי ×‘×©× \"%s\"!"
-#: mediagoblin/edit/views.py:326
+#: mediagoblin/edit/views.py:314
msgid "A collection with that slug already exists for this user."
msgstr "×וסף ×¢× ×—×©×•×¤×™×ª זו כבר ×§×™×™× ×¢×‘×•×¨ משתמש ×–×”."
-#: mediagoblin/edit/views.py:343
+#: mediagoblin/edit/views.py:329
msgid "You are editing another user's collection. Proceed with caution."
msgstr "×תה עורך ×וסף של משתמש ×חר. המשך בזהירות."
-#: mediagoblin/gmg_commands/theme.py:58
+#: mediagoblin/edit/views.py:348
+msgid "Wrong password"
+msgstr "סיסמה שגויה"
+
+#: mediagoblin/edit/views.py:363
+msgid "Your password was changed successfully"
+msgstr "סיסמתך שונתה בהצלחה"
+
+#: mediagoblin/gmg_commands/assetlink.py:60
msgid "Cannot link theme... no theme set\n"
msgstr "×œ× × ×™×ª×Ÿ לקשר ×ל מוטיב... ×œ× ×”×•×’×“×¨ מוטיב\n"
-#: mediagoblin/gmg_commands/theme.py:71
+#: mediagoblin/gmg_commands/assetlink.py:73
msgid "No asset directory for this theme\n"
msgstr "×ין מדור נכס עבור מוטיב ×–×”\n"
-#: mediagoblin/gmg_commands/theme.py:74
+#: mediagoblin/gmg_commands/assetlink.py:76
msgid "However, old link directory symlink found; removed.\n"
msgstr "בכל ×ופן, קישור מדור symlink נמצ×; הוסר.\n"
+#: mediagoblin/gmg_commands/assetlink.py:112
+#, python-format
+msgid "Could not link \"%s\": %s exists and is not a symlink\n"
+msgstr "×œ× ×”×™×ª×” ×פשרות לקשר ×ת \"%s\": %s ×§×™×™× ×•×ינו קישור סמלי (symlink)\n"
+
+#: mediagoblin/gmg_commands/assetlink.py:119
+#, python-format
+msgid "Skipping \"%s\"; already set up.\n"
+msgstr "מדלג על \"%s\"; כבר מוגדר.\n"
+
+#: mediagoblin/gmg_commands/assetlink.py:124
+#, python-format
+msgid "Old link found for \"%s\"; removing.\n"
+msgstr "קישור ישן × ×ž×¦× ×¢×‘×•×¨ \"%s\"; מסיר כעת.\n"
+
#: mediagoblin/meddleware/csrf.py:134
msgid ""
"CSRF cookie not present. This is most likely the result of a cookie blocker "
"or somesuch.<br/>Make sure to permit the settings of cookies for this "
"domain."
-msgstr ""
+msgstr "עוגיית CSRF ×œ× × ×•×›×—×ª. ×–×” קרוב לווד××™ נובע ×ž×©×•× ×—×•×¡× ×¢×•×’×™×™×” ×ו משהו בסגנון.<br/>הבטח קביעה של עוגיות עבור ×ª×—×•× ×–×”."
-#: mediagoblin/media_types/__init__.py:61
-#: mediagoblin/media_types/__init__.py:102
+#: mediagoblin/media_types/__init__.py:111
+#: mediagoblin/media_types/__init__.py:155
msgid "Sorry, I don't support that file type :("
msgstr "צר לי, ××™× × ×™ תומך בטיפוס קובץ ×–×” :("
-#: mediagoblin/media_types/video/processing.py:36
+#: mediagoblin/media_types/pdf/processing.py:136
+msgid "unoconv failing to run, check log file"
+msgstr "unoconv נכשל לפעול, בדוק קובץ יומן"
+
+#: mediagoblin/media_types/video/processing.py:37
msgid "Video transcoding failed"
msgstr "המרת ויד×ו נכשלה"
@@ -316,7 +345,7 @@ msgstr "תי×ור"
msgid ""
"This will be visible to users allowing your\n"
" application to authenticate as them."
-msgstr ""
+msgstr "×–×” יר××” ×œ×ž×©×ª×ž×©×™× ×©×ž×ª×™×¨×™×\n ×œ×™×™×©×•×ž×™× ×©×œ×š ל×מת ×ות×."
#: mediagoblin/plugins/oauth/forms.py:40
msgid "Type"
@@ -346,17 +375,17 @@ msgstr ""
msgid "This field is required for public clients"
msgstr "שדה ×–×” הינו דרוש עבור לקוחות פומביי×"
-#: mediagoblin/plugins/oauth/views.py:59
+#: mediagoblin/plugins/oauth/views.py:56
msgid "The client {0} has been registered!"
msgstr "הלקוח {0} נרש×!"
#: mediagoblin/plugins/oauth/templates/oauth/client/connections.html:22
msgid "OAuth client connections"
-msgstr ""
+msgstr "חיבורי לקוח OAuth"
#: mediagoblin/plugins/oauth/templates/oauth/client/list.html:22
msgid "Your OAuth clients"
-msgstr ""
+msgstr "לקוחות OAuth שלך"
#: mediagoblin/plugins/oauth/templates/oauth/client/register.html:29
#: mediagoblin/templates/mediagoblin/submit/collection.html:30
@@ -365,7 +394,7 @@ msgstr ""
msgid "Add"
msgstr "הוסף"
-#: mediagoblin/processing/__init__.py:172
+#: mediagoblin/processing/__init__.py:193
msgid "Invalid file given for media type."
msgstr "ניתן קובץ שגוי עבור טיפוס מדיה."
@@ -373,45 +402,45 @@ msgstr "ניתן קובץ שגוי עבור טיפוס מדיה."
msgid "File"
msgstr "קובץ"
-#: mediagoblin/submit/views.py:51
+#: mediagoblin/submit/views.py:49
msgid "You must provide a file."
msgstr "עליך לספק קובץ."
-#: mediagoblin/submit/views.py:97
+#: mediagoblin/submit/views.py:93
msgid "Woohoo! Submitted!"
msgstr "הידד! נשלח!"
-#: mediagoblin/submit/views.py:146
+#: mediagoblin/submit/views.py:144
#, python-format
msgid "Collection \"%s\" added!"
msgstr "×וסף \"%s\" התווסף!"
-#: mediagoblin/templates/mediagoblin/base.html:64
+#: mediagoblin/templates/mediagoblin/base.html:67
msgid "Verify your email!"
msgstr "×מת ×ת הדו×״ל שלך!"
-#: mediagoblin/templates/mediagoblin/base.html:65
+#: mediagoblin/templates/mediagoblin/base.html:68
msgid "log out"
msgstr "התנתקות"
-#: mediagoblin/templates/mediagoblin/base.html:70
+#: mediagoblin/templates/mediagoblin/base.html:73
#: mediagoblin/templates/mediagoblin/auth/login.html:28
#: mediagoblin/templates/mediagoblin/auth/login.html:36
#: mediagoblin/templates/mediagoblin/auth/login.html:54
msgid "Log in"
msgstr "התחברות"
-#: mediagoblin/templates/mediagoblin/base.html:79
+#: mediagoblin/templates/mediagoblin/base.html:82
#, python-format
msgid "<a href=\"%(user_url)s\">%(user_name)s</a>'s account"
msgstr "החשבון של <a href=\"%(user_url)s\">%(user_name)s</a>"
-#: mediagoblin/templates/mediagoblin/base.html:86
+#: mediagoblin/templates/mediagoblin/base.html:89
msgid "Change account settings"
msgstr "שנה הגדרות חשבון"
-#: mediagoblin/templates/mediagoblin/base.html:90
-#: mediagoblin/templates/mediagoblin/base.html:105
+#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:108
#: mediagoblin/templates/mediagoblin/admin/panel.html:21
#: mediagoblin/templates/mediagoblin/admin/panel.html:26
#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:21
@@ -419,72 +448,25 @@ msgstr "שנה הגדרות חשבון"
msgid "Media processing panel"
msgstr "לוח עיבוד מדיה"
-#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:96
msgid "Log out"
-msgstr ""
+msgstr "התנתקות"
-#: mediagoblin/templates/mediagoblin/base.html:96
+#: mediagoblin/templates/mediagoblin/base.html:99
#: mediagoblin/templates/mediagoblin/user_pages/user.html:156
msgid "Add media"
msgstr "הוספת מדיה"
-#: mediagoblin/templates/mediagoblin/base.html:99
+#: mediagoblin/templates/mediagoblin/base.html:102
#: mediagoblin/templates/mediagoblin/user_pages/collection_list.html:41
msgid "Create new collection"
msgstr "צור ×וסף חדש"
-#: mediagoblin/templates/mediagoblin/base.html:122
-#, python-format
-msgid ""
-"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
-"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/base.html:125
-#, python-format
-msgid ""
-"Released under the <a "
-"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
-"href=\"%(source_link)s\">Source code</a> available."
-msgstr "משוחרר תחת הרשיון <a href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a href=\"%(source_link)s\">קוד מקור</a> זמין."
-
#: mediagoblin/templates/mediagoblin/error.html:24
msgid "Image of goblin stressing out"
msgstr "תמונה של גובלין מת×מץ יתר על המידה"
-#: mediagoblin/templates/mediagoblin/root.html:31
-msgid "Explore"
-msgstr "לחקור"
-
-#: mediagoblin/templates/mediagoblin/root.html:33
-msgid "Hi there, welcome to this MediaGoblin site!"
-msgstr "×©×œ×•× ×œ×š, ברוך בו×ך ×ל ×תר MediaGoblin ×–×”!"
-
-#: mediagoblin/templates/mediagoblin/root.html:35
-msgid ""
-"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
-"extraordinarily great piece of media hosting software."
-msgstr "×תר ×–×” מריץ <a href=\"http://mediagoblin.org\">MediaGoblin</a>, חתיכת תוכנת ×ירוח מדיה יוצ×ת מן הכלל."
-
-#: mediagoblin/templates/mediagoblin/root.html:36
-msgid ""
-"To add your own media, place comments, and more, you can log in with your "
-"MediaGoblin account."
-msgstr "בכדי להוסיף ×ת המדיה שלך, ×œ×”×©×™× ×ª×’×•×‘×•×ª, ועוד, ביכולתך להתחבר ×¢× ×—×©×‘×•×Ÿ MediaGoblin."
-
-#: mediagoblin/templates/mediagoblin/root.html:38
-msgid "Don't have one yet? It's easy!"
-msgstr "×ין ברשותך חשבון עדיין? ×–×” קל!"
-
-#: mediagoblin/templates/mediagoblin/root.html:39
-#, python-format
-msgid ""
-"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
-" or\n"
-" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
-msgstr "<a class=\"button_action_highlight\" href=\"%(register_url)s\">יצירת חשבון ×צל ×תר ×–×”</a>\n ×ו\n <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">להתקין ×ת MediaGoblin על שרתך</a>"
-
-#: mediagoblin/templates/mediagoblin/root.html:47
+#: mediagoblin/templates/mediagoblin/root.html:32
msgid "Most recent media"
msgstr "המדיה ×”×חרונה ביותר"
@@ -573,11 +555,11 @@ msgstr "שכחת ×ת סיסמתך?"
#: mediagoblin/templates/mediagoblin/auth/register.html:28
#: mediagoblin/templates/mediagoblin/auth/register.html:36
msgid "Create an account!"
-msgstr "יצירת חשבון!"
+msgstr "צור חשבון!"
#: mediagoblin/templates/mediagoblin/auth/register.html:40
msgid "Create"
-msgstr "יצירה"
+msgstr "צור"
#: mediagoblin/templates/mediagoblin/auth/verification_email.txt:19
#, python-format
@@ -590,6 +572,53 @@ msgid ""
"%(verification_url)s"
msgstr "×©×œ×•× %(username)s,\n\nבכדי להפעיל ×ת חשבונך ×צל GNU MediaGoblin, עליך לפתוח ×ת הכתובת הב××”\nבתוך דפדפן הרשת שלך:\n\n%(verification_url)s"
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:21
+#, python-format
+msgid ""
+"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
+"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
+msgstr "ממונע על ידי <a href=\"http://mediagoblin.org/\" title='גירסה %(version)s'>MediaGoblin</a>, פרויקט <a href=\"http://gnu.org/\">GNU</a>."
+
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:24
+#, python-format
+msgid ""
+"Released under the <a "
+"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
+"href=\"%(source_link)s\">Source code</a> available."
+msgstr "משוחרר תחת הרשיון <a href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a href=\"%(source_link)s\">קוד מקור</a> זמין."
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:20
+msgid "Explore"
+msgstr "לחקור"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:22
+msgid "Hi there, welcome to this MediaGoblin site!"
+msgstr "×©×œ×•× ×œ×š, ברוך בו×ך ×ל ×תר MediaGoblin ×–×”!"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:24
+msgid ""
+"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
+"extraordinarily great piece of media hosting software."
+msgstr "×תר ×–×” מריץ <a href=\"http://mediagoblin.org\">MediaGoblin</a>, חתיכת תוכנת ×ירוח מדיה יוצ×ת מן הכלל."
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:25
+msgid ""
+"To add your own media, place comments, and more, you can log in with your "
+"MediaGoblin account."
+msgstr "בכדי להוסיף ×ת המדיה שלך, ×œ×”×©×™× ×ª×’×•×‘×•×ª, ועוד, ביכולתך להתחבר ×¢× ×—×©×‘×•×Ÿ MediaGoblin."
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:27
+msgid "Don't have one yet? It's easy!"
+msgstr "×ין ברשותך חשבון עדיין? ×–×” קל!"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:28
+#, python-format
+msgid ""
+"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
+" or\n"
+" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
+msgstr "<a class=\"button_action_highlight\" href=\"%(register_url)s\">צור חשבון ב×תר ×–×”</a>\n ×ו\n <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">התקן ×ת MediaGoblin על שרתך</a>"
+
#: mediagoblin/templates/mediagoblin/bits/logo.html:23
#: mediagoblin/themes/airy/templates/mediagoblin/bits/logo.html:23
msgid "MediaGoblin logo"
@@ -602,13 +631,13 @@ msgid "Editing attachments for %(media_title)s"
msgstr "עריכת ×ª×¦×¨×™×¤×™× ×¢×‘×•×¨ %(media_title)s"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:159
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:175
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:182
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:198
msgid "Attachments"
msgstr "תצריפי×"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:57
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:181
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:204
msgid "Add attachment"
msgstr "הוספת תצריף"
@@ -625,23 +654,33 @@ msgstr "ביטול"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:63
#: mediagoblin/templates/mediagoblin/edit/edit.html:42
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:52
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:55
#: mediagoblin/templates/mediagoblin/edit/edit_collection.html:33
#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:40
msgid "Save changes"
msgstr "שמור שינויי×"
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:28
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:38
+#, python-format
+msgid "Changing %(username)s's password"
+msgstr "משנה כעת ×ת הסיסמה של %(username)s'"
+
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:45
+msgid "Save"
+msgstr "שמור"
+
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:28
#, python-format
msgid "Really delete user '%(user_name)s' and all related media/comments?"
-msgstr ""
+msgstr "ב×מת למחוק ×ת המשתמש '%(user_name)s' ו×ת כל המדיה/התגובות הקשורות?"
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:35
msgid "Yes, really delete my account"
-msgstr ""
+msgstr "כן, ב×מת למחוק ×ת חשבוני"
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:47
+#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:48
#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:49
msgid "Delete permanently"
msgstr "מחק לצמיתות"
@@ -658,9 +697,13 @@ msgstr "ערוך %(media_title)s"
msgid "Changing %(username)s's account settings"
msgstr "שינוי הגדרות חשבון עבור %(username)s"
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:59
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:46
+msgid "Change your password."
+msgstr "שנה ×ת סיסמתך."
+
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:62
msgid "Delete my account"
-msgstr ""
+msgstr "מחק ×ת החשבון שלי"
#: mediagoblin/templates/mediagoblin/edit/edit_collection.html:29
#, python-format
@@ -683,6 +726,7 @@ msgstr "מדיה מתויגת ×¢×: %(tag_name)s"
#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:56
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:65
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:136
#: mediagoblin/templates/mediagoblin/media_displays/video.html:55
msgid "Download"
@@ -704,9 +748,10 @@ msgid ""
"You can get a modern web browser that \n"
"\tcan play the audio at <a href=\"http://getfirefox.com\">\n"
"\t http://getfirefox.com</a>!"
-msgstr "ביכולתך להשיג דפדפן רשת מודרני שכן \n\tמסוגל לנגן ×ת ×ודיו ×–×” ×צל <a href=\"http://getfirefox.com\">\n\t http://getfirefox.com</a>!"
+msgstr "ביכולתך להשיג דפדפן רשת מודרני \n\tשכן מסוגל לנגן ×ת ×ודיו ×–×” ×צל <a href=\"http://getfirefox.com\">\n\t http://getfirefox.com</a>!"
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:60
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:71
#: mediagoblin/templates/mediagoblin/media_displays/video.html:61
msgid "Original file"
msgstr "קובץ מקורי"
@@ -715,6 +760,7 @@ msgstr "קובץ מקורי"
msgid "WebM file (Vorbis codec)"
msgstr "קובץ WebM (קודק Vorbis)"
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:59
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:87
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:93
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:99
@@ -725,9 +771,13 @@ msgstr "קובץ WebM (קודק Vorbis)"
msgid "Image for %(media_title)s"
msgstr "תמונה עבור %(media_title)s"
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:79
+msgid "PDF file"
+msgstr "קובץ PDF"
+
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:112
msgid "Toggle Rotate"
-msgstr ""
+msgstr "החלף סיבוב"
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:113
msgid "Perspective"
@@ -755,7 +805,7 @@ msgstr ""
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:138
msgid "Download model"
-msgstr ""
+msgstr "הורד מודל"
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:146
msgid "File Format"
@@ -770,14 +820,14 @@ msgid ""
"Sorry, this video will not work because\n"
" your web browser does not support HTML5 \n"
" video."
-msgstr ""
+msgstr "צר לי, ויד×ו ×–×” ×œ× ×™×¢×‘×•×“ מכיוון \n שדפדפן הרשת שלך ×œ× ×ª×•×ž×š \n ויד×ו של HTML5."
#: mediagoblin/templates/mediagoblin/media_displays/video.html:47
msgid ""
"You can get a modern web browser that \n"
" can play this video at <a href=\"http://getfirefox.com\">\n"
" http://getfirefox.com</a>!"
-msgstr ""
+msgstr "ביכולתך להשיג דפדפן רשת מודרני \n שכן מסוגל לנגן ×ת ויד×ו ×–×” ×צל <a href=\"http://getfirefox.com\">\n http://getfirefox.com</a>!"
#: mediagoblin/templates/mediagoblin/media_displays/video.html:69
msgid "WebM file (640p; VP8/Vorbis)"
@@ -823,19 +873,19 @@ msgstr "ב×מת למחוק ×ת %(title)s?"
msgid "Really remove %(media_title)s from %(collection_title)s?"
msgstr "ב×מת להסיר ×ת %(media_title)s מן %(collection_title)s?"
-#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:53
+#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:54
msgid "Remove"
msgstr "הסר"
#: mediagoblin/templates/mediagoblin/user_pages/collection_list.html:21
#, python-format
msgid "%(username)s's collections"
-msgstr ""
+msgstr "××•×¡×¤×™× ×©×œ %(username)s"
#: mediagoblin/templates/mediagoblin/user_pages/collection_list.html:28
#, python-format
msgid "<a href=\"%(user_url)s\">%(username)s</a>'s collections"
-msgstr ""
+msgstr "××•×¡×¤×™× ×©×œ <a href=\"%(user_url)s\">%(username)s</a>"
#: mediagoblin/templates/mediagoblin/user_pages/comment_email.txt:19
#, python-format
@@ -854,7 +904,7 @@ msgstr "המדיה של %(username)s"
msgid ""
"<a href=\"%(user_url)s\">%(username)s</a>'s media with tag <a "
"href=\"%(tag_url)s\">%(tag)s</a>"
-msgstr ""
+msgstr "מדיה משתמש <a href=\"%(user_url)s\">%(username)s</a> ×¢× ×ª×’×™×ª <a href=\"%(tag_url)s\">%(tag)s</a>"
#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:48
#, python-format
@@ -866,30 +916,34 @@ msgstr "המדיה של <a href=\"%(user_url)s\">%(username)s</a>"
msgid "â– Browsing media by <a href=\"%(user_url)s\">%(username)s</a>"
msgstr "■עיון במדיה מ×ת <a href=\"%(user_url)s\">%(username)s</a>"
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:94
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:95
msgid "Add a comment"
msgstr "הוסף תגובה"
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:102
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:104
msgid "Add this comment"
msgstr "הוסף ×ת תגובה זו"
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:123
-msgid "at"
-msgstr "×צל"
-
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:144
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:132
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:152
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:164
#, python-format
-msgid ""
-"<h3>Added on</h3>\n"
-" <p>%(date)s</p>"
-msgstr "<h3>הוסף בת×ריך</h3>\n <p>%(date)s</p>"
+msgid "%(formatted_time)s ago"
+msgstr "מלפני %(formatted_time)s"
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:150
+msgid "Added"
+msgstr "התווסף"
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:161
+msgid "Created"
+msgstr "נוצר"
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:28
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:40
#, python-format
msgid "Add “%(media_title)s†to a collection"
-msgstr ""
+msgstr "הוסף ×ת “%(media_title)s†×ל ×וסף"
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:54
msgid "+"
@@ -968,7 +1022,7 @@ msgstr "משתמש ×–×” ×œ× ×ž×™×œ× ×“×™×•×§×Ÿ (עדיין)."
#: mediagoblin/templates/mediagoblin/user_pages/user.html:124
msgid "Browse collections"
-msgstr ""
+msgstr "עיון ב×וספי×"
#: mediagoblin/templates/mediagoblin/user_pages/user.html:137
#, python-format
@@ -997,7 +1051,7 @@ msgstr ""
#: mediagoblin/templates/mediagoblin/utils/collections.html:40
msgid "Add to a collection"
-msgstr ""
+msgstr "הוסף ×ל ×וסף"
#: mediagoblin/templates/mediagoblin/utils/feed_link.html:21
#: mediagoblin/themes/airy/templates/mediagoblin/utils/feed_link.html:21
@@ -1039,7 +1093,7 @@ msgstr "ישן יותר"
msgid "Tagged with"
msgstr "מתויגת ×¢×"
-#: mediagoblin/tools/exif.py:80
+#: mediagoblin/tools/exif.py:83
msgid "Could not read the image file."
msgstr "×œ× ×”×™×” ניתן ×œ×§×¨×•× ×ת קובץ התמונה."
@@ -1069,9 +1123,33 @@ msgid ""
" deleted."
msgstr "×œ× × ×¨××” ×©×§×™×™× ×¢×ž×•×“ בכתובת זו. צר לי!</p><p>×× ×תה בטוח שהכתובת ×”×™× ×” מדויקת, ייתכן שהעמוד ש×תה מחפש כעת הועבר ×ו נמחק."
+#: mediagoblin/tools/timesince.py:62
+msgid "year"
+msgstr "שנה"
+
+#: mediagoblin/tools/timesince.py:63
+msgid "month"
+msgstr "חודש"
+
+#: mediagoblin/tools/timesince.py:64
+msgid "week"
+msgstr "שבוע"
+
+#: mediagoblin/tools/timesince.py:65
+msgid "day"
+msgstr "יו×"
+
+#: mediagoblin/tools/timesince.py:66
+msgid "hour"
+msgstr "שעה"
+
+#: mediagoblin/tools/timesince.py:67
+msgid "minute"
+msgstr "דקה"
+
#: mediagoblin/user_pages/forms.py:23
msgid "Comment"
-msgstr ""
+msgstr "תגובה"
#: mediagoblin/user_pages/forms.py:25
msgid ""
@@ -1090,7 +1168,7 @@ msgstr "×× ×™ בטוח שברצוני להסיר ×ת פריט ×–×” מן ×”×ו
#: mediagoblin/user_pages/forms.py:39
msgid "Collection"
-msgstr ""
+msgstr "×וסף"
#: mediagoblin/user_pages/forms.py:40
msgid "-- Select --"
@@ -1100,73 +1178,77 @@ msgstr "-- בחר --"
msgid "Include a note"
msgstr "הכללת פתק"
-#: mediagoblin/user_pages/lib.py:56
+#: mediagoblin/user_pages/lib.py:58
msgid "commented on your post"
msgstr "הגיב/ה על פרסומך"
-#: mediagoblin/user_pages/views.py:166
+#: mediagoblin/user_pages/views.py:169
+msgid "Sorry, comments are disabled."
+msgstr "מצטערי×, תגובות מנוטרלות."
+
+#: mediagoblin/user_pages/views.py:174
msgid "Oops, your comment was empty."
msgstr "×ופס, תגובתך היתה ריקה."
-#: mediagoblin/user_pages/views.py:172
+#: mediagoblin/user_pages/views.py:180
msgid "Your comment has been posted!"
msgstr "תגובתך פורסמה!"
-#: mediagoblin/user_pages/views.py:197
+#: mediagoblin/user_pages/views.py:205
msgid "Please check your entries and try again."
msgstr "×× × ×‘×“×•×§ ×ת רשומותיך ונסה שוב."
-#: mediagoblin/user_pages/views.py:237
+#: mediagoblin/user_pages/views.py:245
msgid "You have to select or add a collection"
msgstr "עליך לבחור ×ו להוסיף ×וסף"
-#: mediagoblin/user_pages/views.py:248
+#: mediagoblin/user_pages/views.py:256
#, python-format
msgid "\"%s\" already in collection \"%s\""
msgstr "\"%s\" כבר ×§×™×™× ×‘×וסף \"%s\""
-#: mediagoblin/user_pages/views.py:264
+#: mediagoblin/user_pages/views.py:262
#, python-format
msgid "\"%s\" added to collection \"%s\""
msgstr "\"%s\" התווסף ×ל ×”×וסף \"%s\""
-#: mediagoblin/user_pages/views.py:286
+#: mediagoblin/user_pages/views.py:282
msgid "You deleted the media."
msgstr "מחקת ×ת מדיה זו."
-#: mediagoblin/user_pages/views.py:293
+#: mediagoblin/user_pages/views.py:289
msgid "The media was not deleted because you didn't check that you were sure."
msgstr "המדיה ×œ× × ×ž×—×§×” מכיוון ×©×œ× ×¡×™×ž× ×ª ש×תה בטוח."
-#: mediagoblin/user_pages/views.py:301
+#: mediagoblin/user_pages/views.py:296
msgid "You are about to delete another user's media. Proceed with caution."
msgstr "בחרת למחוק מדיה של משתמש ×חר. המשך בזהירות."
-#: mediagoblin/user_pages/views.py:375
+#: mediagoblin/user_pages/views.py:370
msgid "You deleted the item from the collection."
msgstr "מחקת ×ת הפריט מן ×וסף ×–×”."
-#: mediagoblin/user_pages/views.py:379
+#: mediagoblin/user_pages/views.py:374
msgid "The item was not removed because you didn't check that you were sure."
msgstr "הפריט ×œ× ×”×•×¡×¨ מכיוון ×©×œ× ×¡×™×ž× ×ª ש×תה בטוח."
-#: mediagoblin/user_pages/views.py:389
+#: mediagoblin/user_pages/views.py:382
msgid ""
"You are about to delete an item from another user's collection. Proceed with"
" caution."
msgstr "בחרת למחוק פריט מן ×וסף של משתמש ×חר. המשך בזהירות."
-#: mediagoblin/user_pages/views.py:422
+#: mediagoblin/user_pages/views.py:415
#, python-format
msgid "You deleted the collection \"%s\""
msgstr "מחקת ×ת ×”×וסף \"%s\""
-#: mediagoblin/user_pages/views.py:429
+#: mediagoblin/user_pages/views.py:422
msgid ""
"The collection was not deleted because you didn't check that you were sure."
msgstr "×”×וסף ×œ× ×”×•×¡×¨ מכיוון ×©×œ× ×¡×™×ž× ×ª ש×תה בטוח."
-#: mediagoblin/user_pages/views.py:439
+#: mediagoblin/user_pages/views.py:430
msgid ""
"You are about to delete another user's collection. Proceed with caution."
msgstr "בחרת למחוק ×וסף של משתמש ×חר. המשך בזהירות."
diff --git a/mediagoblin/i18n/ia/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ia/LC_MESSAGES/mediagoblin.mo
index d9addaa6..d22f6ee6 100644
--- a/mediagoblin/i18n/ia/LC_MESSAGES/mediagoblin.mo
+++ b/mediagoblin/i18n/ia/LC_MESSAGES/mediagoblin.mo
Binary files differ
diff --git a/mediagoblin/i18n/ia/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ia/LC_MESSAGES/mediagoblin.po
index 73180e86..c9f814fc 100644
--- a/mediagoblin/i18n/ia/LC_MESSAGES/mediagoblin.po
+++ b/mediagoblin/i18n/ia/LC_MESSAGES/mediagoblin.po
@@ -3,16 +3,16 @@
# This file is distributed under the same license as the PROJECT project.
#
# Translators:
-# Aleksandr Brezhnev <abrezhnev@gmail.com>, 2012.
-# Emilio Sepúlveda <djfunkinmixer@gmail.com>, 2011.
+# Aleksandr Brezhnev <abrezhnev@gmail.com>, 2012
+# Emilio Sepúlveda <emisepulvedam@gmail.com>, 2011
msgid ""
msgstr ""
"Project-Id-Version: GNU MediaGoblin\n"
"Report-Msgid-Bugs-To: http://issues.mediagoblin.org/\n"
-"POT-Creation-Date: 2013-03-04 18:04-0600\n"
-"PO-Revision-Date: 2013-03-05 00:04+0000\n"
+"POT-Creation-Date: 2013-05-27 13:54-0500\n"
+"PO-Revision-Date: 2013-05-27 18:54+0000\n"
"Last-Translator: cwebber <cwebber@dustycloud.org>\n"
-"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language-Team: Interlingua (http://www.transifex.com/projects/p/mediagoblin/language/ia/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
@@ -20,34 +20,39 @@ msgstr ""
"Language: ia\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: mediagoblin/auth/forms.py:28
-msgid "Invalid User name or email address."
-msgstr ""
-
-#: mediagoblin/auth/forms.py:29
-msgid "This field does not take email addresses."
-msgstr ""
-
-#: mediagoblin/auth/forms.py:30
-msgid "This field requires an email address."
-msgstr ""
-
-#: mediagoblin/auth/forms.py:52 mediagoblin/auth/forms.py:67
+#: mediagoblin/auth/forms.py:26
msgid "Username"
msgstr "Nomine de usator"
-#: mediagoblin/auth/forms.py:56 mediagoblin/auth/forms.py:71
+#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:45
+#: mediagoblin/tests/test_util.py:110
msgid "Password"
msgstr "Contrasigno"
-#: mediagoblin/auth/forms.py:60
+#: mediagoblin/auth/forms.py:34
msgid "Email address"
msgstr "Adresse de e-posta"
-#: mediagoblin/auth/forms.py:78
+#: mediagoblin/auth/forms.py:41
+msgid "Username or Email"
+msgstr ""
+
+#: mediagoblin/auth/forms.py:52
msgid "Username or email"
msgstr ""
+#: mediagoblin/auth/tools.py:31
+msgid "Invalid User name or email address."
+msgstr ""
+
+#: mediagoblin/auth/tools.py:32
+msgid "This field does not take email addresses."
+msgstr ""
+
+#: mediagoblin/auth/tools.py:33
+msgid "This field requires an email address."
+msgstr ""
+
#: mediagoblin/auth/views.py:54
msgid "Sorry, registration is disabled on this instance."
msgstr ""
@@ -60,54 +65,54 @@ msgstr ""
msgid "Sorry, a user with that email address already exists."
msgstr ""
-#: mediagoblin/auth/views.py:174
+#: mediagoblin/auth/views.py:182
msgid ""
"Your email address has been verified. You may now login, edit your profile, "
"and submit images!"
msgstr ""
-#: mediagoblin/auth/views.py:180
+#: mediagoblin/auth/views.py:188
msgid "The verification key or user id is incorrect"
msgstr ""
-#: mediagoblin/auth/views.py:198
+#: mediagoblin/auth/views.py:206
msgid "You must be logged in so we know who to send the email to!"
msgstr ""
-#: mediagoblin/auth/views.py:206
+#: mediagoblin/auth/views.py:214
msgid "You've already verified your email address!"
msgstr ""
-#: mediagoblin/auth/views.py:219
+#: mediagoblin/auth/views.py:227
msgid "Resent your verification email."
msgstr ""
-#: mediagoblin/auth/views.py:250
+#: mediagoblin/auth/views.py:258
msgid ""
"If that email address (case sensitive!) is registered an email has been sent"
" with instructions on how to change your password."
msgstr ""
-#: mediagoblin/auth/views.py:261
+#: mediagoblin/auth/views.py:269
msgid "Couldn't find someone with that username."
msgstr ""
-#: mediagoblin/auth/views.py:264
+#: mediagoblin/auth/views.py:272
msgid ""
"An email has been sent with instructions on how to change your password."
msgstr ""
-#: mediagoblin/auth/views.py:271
+#: mediagoblin/auth/views.py:279
msgid ""
"Could not send password recovery email as your username is inactive or your "
"account's email address has not been verified."
msgstr ""
-#: mediagoblin/auth/views.py:328
+#: mediagoblin/auth/views.py:336
msgid "You can now log in using your new password."
msgstr ""
-#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:93
+#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:82
#: mediagoblin/submit/forms.py:28 mediagoblin/submit/forms.py:47
#: mediagoblin/user_pages/forms.py:45
msgid "Title"
@@ -118,7 +123,7 @@ msgid "Description of this work"
msgstr ""
#: mediagoblin/edit/forms.py:29 mediagoblin/edit/forms.py:52
-#: mediagoblin/edit/forms.py:97 mediagoblin/submit/forms.py:32
+#: mediagoblin/edit/forms.py:86 mediagoblin/submit/forms.py:32
#: mediagoblin/submit/forms.py:51 mediagoblin/user_pages/forms.py:49
msgid ""
"You can use\n"
@@ -134,11 +139,11 @@ msgstr "Etiquettas"
msgid "Separate tags by commas."
msgstr ""
-#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:101
+#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:90
msgid "Slug"
msgstr ""
-#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:102
+#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:91
msgid "The slug can't be empty"
msgstr ""
@@ -166,45 +171,45 @@ msgid "This address contains errors"
msgstr ""
#: mediagoblin/edit/forms.py:63
-msgid "Old password"
-msgstr ""
-
-#: mediagoblin/edit/forms.py:64
-msgid "Enter your old password to prove you own this account."
-msgstr ""
-
-#: mediagoblin/edit/forms.py:67
-msgid "New password"
-msgstr ""
-
-#: mediagoblin/edit/forms.py:74
msgid "License preference"
msgstr ""
-#: mediagoblin/edit/forms.py:80
+#: mediagoblin/edit/forms.py:69
msgid "This will be your default license on upload forms."
msgstr ""
-#: mediagoblin/edit/forms.py:82
+#: mediagoblin/edit/forms.py:71
msgid "Email me when others comment on my media"
msgstr ""
-#: mediagoblin/edit/forms.py:94
+#: mediagoblin/edit/forms.py:83
msgid "The title can't be empty"
msgstr ""
-#: mediagoblin/edit/forms.py:96 mediagoblin/submit/forms.py:50
+#: mediagoblin/edit/forms.py:85 mediagoblin/submit/forms.py:50
#: mediagoblin/user_pages/forms.py:48
msgid "Description of this collection"
msgstr ""
-#: mediagoblin/edit/forms.py:103
+#: mediagoblin/edit/forms.py:92
msgid ""
"The title part of this collection's address. You usually don't need to "
"change this."
msgstr ""
-#: mediagoblin/edit/views.py:66
+#: mediagoblin/edit/forms.py:99
+msgid "Old password"
+msgstr ""
+
+#: mediagoblin/edit/forms.py:101
+msgid "Enter your old password to prove you own this account."
+msgstr ""
+
+#: mediagoblin/edit/forms.py:104
+msgid "New password"
+msgstr ""
+
+#: mediagoblin/edit/views.py:67
msgid "An entry with that slug already exists for this user."
msgstr ""
@@ -229,44 +234,63 @@ msgstr ""
msgid "Profile changes saved"
msgstr ""
-#: mediagoblin/edit/views.py:241
-msgid "Wrong password"
-msgstr ""
-
-#: mediagoblin/edit/views.py:252
+#: mediagoblin/edit/views.py:240
msgid "Account settings saved"
msgstr ""
-#: mediagoblin/edit/views.py:286
+#: mediagoblin/edit/views.py:274
msgid "You need to confirm the deletion of your account."
msgstr ""
-#: mediagoblin/edit/views.py:322 mediagoblin/submit/views.py:142
-#: mediagoblin/user_pages/views.py:214
+#: mediagoblin/edit/views.py:310 mediagoblin/submit/views.py:138
+#: mediagoblin/user_pages/views.py:222
#, python-format
msgid "You already have a collection called \"%s\"!"
msgstr ""
-#: mediagoblin/edit/views.py:326
+#: mediagoblin/edit/views.py:314
msgid "A collection with that slug already exists for this user."
msgstr ""
-#: mediagoblin/edit/views.py:343
+#: mediagoblin/edit/views.py:329
msgid "You are editing another user's collection. Proceed with caution."
msgstr ""
-#: mediagoblin/gmg_commands/theme.py:58
+#: mediagoblin/edit/views.py:348
+msgid "Wrong password"
+msgstr ""
+
+#: mediagoblin/edit/views.py:363
+msgid "Your password was changed successfully"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:60
msgid "Cannot link theme... no theme set\n"
msgstr ""
-#: mediagoblin/gmg_commands/theme.py:71
+#: mediagoblin/gmg_commands/assetlink.py:73
msgid "No asset directory for this theme\n"
msgstr ""
-#: mediagoblin/gmg_commands/theme.py:74
+#: mediagoblin/gmg_commands/assetlink.py:76
msgid "However, old link directory symlink found; removed.\n"
msgstr ""
+#: mediagoblin/gmg_commands/assetlink.py:112
+#, python-format
+msgid "Could not link \"%s\": %s exists and is not a symlink\n"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:119
+#, python-format
+msgid "Skipping \"%s\"; already set up.\n"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:124
+#, python-format
+msgid "Old link found for \"%s\"; removing.\n"
+msgstr ""
+
#: mediagoblin/meddleware/csrf.py:134
msgid ""
"CSRF cookie not present. This is most likely the result of a cookie blocker "
@@ -274,12 +298,16 @@ msgid ""
"domain."
msgstr ""
-#: mediagoblin/media_types/__init__.py:61
-#: mediagoblin/media_types/__init__.py:102
+#: mediagoblin/media_types/__init__.py:111
+#: mediagoblin/media_types/__init__.py:155
msgid "Sorry, I don't support that file type :("
msgstr ""
-#: mediagoblin/media_types/video/processing.py:36
+#: mediagoblin/media_types/pdf/processing.py:136
+msgid "unoconv failing to run, check log file"
+msgstr ""
+
+#: mediagoblin/media_types/video/processing.py:37
msgid "Video transcoding failed"
msgstr ""
@@ -346,7 +374,7 @@ msgstr ""
msgid "This field is required for public clients"
msgstr ""
-#: mediagoblin/plugins/oauth/views.py:59
+#: mediagoblin/plugins/oauth/views.py:56
msgid "The client {0} has been registered!"
msgstr ""
@@ -365,7 +393,7 @@ msgstr ""
msgid "Add"
msgstr ""
-#: mediagoblin/processing/__init__.py:172
+#: mediagoblin/processing/__init__.py:193
msgid "Invalid file given for media type."
msgstr ""
@@ -373,45 +401,45 @@ msgstr ""
msgid "File"
msgstr "File"
-#: mediagoblin/submit/views.py:51
+#: mediagoblin/submit/views.py:49
msgid "You must provide a file."
msgstr ""
-#: mediagoblin/submit/views.py:97
+#: mediagoblin/submit/views.py:93
msgid "Woohoo! Submitted!"
msgstr ""
-#: mediagoblin/submit/views.py:146
+#: mediagoblin/submit/views.py:144
#, python-format
msgid "Collection \"%s\" added!"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:64
+#: mediagoblin/templates/mediagoblin/base.html:67
msgid "Verify your email!"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:65
+#: mediagoblin/templates/mediagoblin/base.html:68
msgid "log out"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:70
+#: mediagoblin/templates/mediagoblin/base.html:73
#: mediagoblin/templates/mediagoblin/auth/login.html:28
#: mediagoblin/templates/mediagoblin/auth/login.html:36
#: mediagoblin/templates/mediagoblin/auth/login.html:54
msgid "Log in"
msgstr "Initiar session"
-#: mediagoblin/templates/mediagoblin/base.html:79
+#: mediagoblin/templates/mediagoblin/base.html:82
#, python-format
msgid "<a href=\"%(user_url)s\">%(user_name)s</a>'s account"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:86
+#: mediagoblin/templates/mediagoblin/base.html:89
msgid "Change account settings"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:90
-#: mediagoblin/templates/mediagoblin/base.html:105
+#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:108
#: mediagoblin/templates/mediagoblin/admin/panel.html:21
#: mediagoblin/templates/mediagoblin/admin/panel.html:26
#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:21
@@ -419,72 +447,25 @@ msgstr ""
msgid "Media processing panel"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:96
msgid "Log out"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:96
+#: mediagoblin/templates/mediagoblin/base.html:99
#: mediagoblin/templates/mediagoblin/user_pages/user.html:156
msgid "Add media"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:99
+#: mediagoblin/templates/mediagoblin/base.html:102
#: mediagoblin/templates/mediagoblin/user_pages/collection_list.html:41
msgid "Create new collection"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:122
-#, python-format
-msgid ""
-"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
-"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/base.html:125
-#, python-format
-msgid ""
-"Released under the <a "
-"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
-"href=\"%(source_link)s\">Source code</a> available."
-msgstr ""
-
#: mediagoblin/templates/mediagoblin/error.html:24
msgid "Image of goblin stressing out"
msgstr ""
-#: mediagoblin/templates/mediagoblin/root.html:31
-msgid "Explore"
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:33
-msgid "Hi there, welcome to this MediaGoblin site!"
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:35
-msgid ""
-"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
-"extraordinarily great piece of media hosting software."
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:36
-msgid ""
-"To add your own media, place comments, and more, you can log in with your "
-"MediaGoblin account."
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:38
-msgid "Don't have one yet? It's easy!"
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:39
-#, python-format
-msgid ""
-"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
-" or\n"
-" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:47
+#: mediagoblin/templates/mediagoblin/root.html:32
msgid "Most recent media"
msgstr ""
@@ -590,6 +571,53 @@ msgid ""
"%(verification_url)s"
msgstr ""
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:21
+#, python-format
+msgid ""
+"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
+"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:24
+#, python-format
+msgid ""
+"Released under the <a "
+"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
+"href=\"%(source_link)s\">Source code</a> available."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:20
+msgid "Explore"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:22
+msgid "Hi there, welcome to this MediaGoblin site!"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:24
+msgid ""
+"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
+"extraordinarily great piece of media hosting software."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:25
+msgid ""
+"To add your own media, place comments, and more, you can log in with your "
+"MediaGoblin account."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:27
+msgid "Don't have one yet? It's easy!"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:28
+#, python-format
+msgid ""
+"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
+" or\n"
+" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/bits/logo.html:23
#: mediagoblin/themes/airy/templates/mediagoblin/bits/logo.html:23
msgid "MediaGoblin logo"
@@ -602,13 +630,13 @@ msgid "Editing attachments for %(media_title)s"
msgstr ""
#: mediagoblin/templates/mediagoblin/edit/attachments.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:159
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:175
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:182
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:198
msgid "Attachments"
msgstr ""
#: mediagoblin/templates/mediagoblin/edit/attachments.html:57
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:181
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:204
msgid "Add attachment"
msgstr ""
@@ -625,12 +653,22 @@ msgstr "Cancellar"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:63
#: mediagoblin/templates/mediagoblin/edit/edit.html:42
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:52
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:55
#: mediagoblin/templates/mediagoblin/edit/edit_collection.html:33
#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:40
msgid "Save changes"
msgstr ""
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:28
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:38
+#, python-format
+msgid "Changing %(username)s's password"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:45
+msgid "Save"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:28
#, python-format
msgid "Really delete user '%(user_name)s' and all related media/comments?"
@@ -641,7 +679,7 @@ msgid "Yes, really delete my account"
msgstr ""
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:47
+#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:48
#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:49
msgid "Delete permanently"
msgstr ""
@@ -658,7 +696,11 @@ msgstr ""
msgid "Changing %(username)s's account settings"
msgstr ""
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:59
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:46
+msgid "Change your password."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:62
msgid "Delete my account"
msgstr ""
@@ -683,6 +725,7 @@ msgstr ""
#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:56
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:65
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:136
#: mediagoblin/templates/mediagoblin/media_displays/video.html:55
msgid "Download"
@@ -707,6 +750,7 @@ msgid ""
msgstr ""
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:60
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:71
#: mediagoblin/templates/mediagoblin/media_displays/video.html:61
msgid "Original file"
msgstr ""
@@ -715,6 +759,7 @@ msgstr ""
msgid "WebM file (Vorbis codec)"
msgstr ""
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:59
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:87
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:93
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:99
@@ -725,6 +770,10 @@ msgstr ""
msgid "Image for %(media_title)s"
msgstr ""
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:79
+msgid "PDF file"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:112
msgid "Toggle Rotate"
msgstr ""
@@ -823,7 +872,7 @@ msgstr ""
msgid "Really remove %(media_title)s from %(collection_title)s?"
msgstr ""
-#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:53
+#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:54
msgid "Remove"
msgstr ""
@@ -866,23 +915,27 @@ msgstr ""
msgid "â– Browsing media by <a href=\"%(user_url)s\">%(username)s</a>"
msgstr ""
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:94
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:95
msgid "Add a comment"
msgstr ""
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:102
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:104
msgid "Add this comment"
msgstr ""
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:123
-msgid "at"
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:132
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:152
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:164
+#, python-format
+msgid "%(formatted_time)s ago"
msgstr ""
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:144
-#, python-format
-msgid ""
-"<h3>Added on</h3>\n"
-" <p>%(date)s</p>"
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:150
+msgid "Added"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:161
+msgid "Created"
msgstr ""
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:28
@@ -1039,7 +1092,7 @@ msgstr ""
msgid "Tagged with"
msgstr ""
-#: mediagoblin/tools/exif.py:80
+#: mediagoblin/tools/exif.py:83
msgid "Could not read the image file."
msgstr ""
@@ -1069,6 +1122,30 @@ msgid ""
" deleted."
msgstr ""
+#: mediagoblin/tools/timesince.py:62
+msgid "year"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:63
+msgid "month"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:64
+msgid "week"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:65
+msgid "day"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:66
+msgid "hour"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:67
+msgid "minute"
+msgstr ""
+
#: mediagoblin/user_pages/forms.py:23
msgid "Comment"
msgstr ""
@@ -1100,73 +1177,77 @@ msgstr ""
msgid "Include a note"
msgstr ""
-#: mediagoblin/user_pages/lib.py:56
+#: mediagoblin/user_pages/lib.py:58
msgid "commented on your post"
msgstr ""
-#: mediagoblin/user_pages/views.py:166
+#: mediagoblin/user_pages/views.py:169
+msgid "Sorry, comments are disabled."
+msgstr ""
+
+#: mediagoblin/user_pages/views.py:174
msgid "Oops, your comment was empty."
msgstr ""
-#: mediagoblin/user_pages/views.py:172
+#: mediagoblin/user_pages/views.py:180
msgid "Your comment has been posted!"
msgstr ""
-#: mediagoblin/user_pages/views.py:197
+#: mediagoblin/user_pages/views.py:205
msgid "Please check your entries and try again."
msgstr ""
-#: mediagoblin/user_pages/views.py:237
+#: mediagoblin/user_pages/views.py:245
msgid "You have to select or add a collection"
msgstr ""
-#: mediagoblin/user_pages/views.py:248
+#: mediagoblin/user_pages/views.py:256
#, python-format
msgid "\"%s\" already in collection \"%s\""
msgstr ""
-#: mediagoblin/user_pages/views.py:264
+#: mediagoblin/user_pages/views.py:262
#, python-format
msgid "\"%s\" added to collection \"%s\""
msgstr ""
-#: mediagoblin/user_pages/views.py:286
+#: mediagoblin/user_pages/views.py:282
msgid "You deleted the media."
msgstr ""
-#: mediagoblin/user_pages/views.py:293
+#: mediagoblin/user_pages/views.py:289
msgid "The media was not deleted because you didn't check that you were sure."
msgstr ""
-#: mediagoblin/user_pages/views.py:301
+#: mediagoblin/user_pages/views.py:296
msgid "You are about to delete another user's media. Proceed with caution."
msgstr ""
-#: mediagoblin/user_pages/views.py:375
+#: mediagoblin/user_pages/views.py:370
msgid "You deleted the item from the collection."
msgstr ""
-#: mediagoblin/user_pages/views.py:379
+#: mediagoblin/user_pages/views.py:374
msgid "The item was not removed because you didn't check that you were sure."
msgstr ""
-#: mediagoblin/user_pages/views.py:389
+#: mediagoblin/user_pages/views.py:382
msgid ""
"You are about to delete an item from another user's collection. Proceed with"
" caution."
msgstr ""
-#: mediagoblin/user_pages/views.py:422
+#: mediagoblin/user_pages/views.py:415
#, python-format
msgid "You deleted the collection \"%s\""
msgstr ""
-#: mediagoblin/user_pages/views.py:429
+#: mediagoblin/user_pages/views.py:422
msgid ""
"The collection was not deleted because you didn't check that you were sure."
msgstr ""
-#: mediagoblin/user_pages/views.py:439
+#: mediagoblin/user_pages/views.py:430
msgid ""
"You are about to delete another user's collection. Proceed with caution."
msgstr ""
diff --git a/mediagoblin/i18n/is_IS/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/is_IS/LC_MESSAGES/mediagoblin.mo
index 376aace4..596ab843 100644
--- a/mediagoblin/i18n/is_IS/LC_MESSAGES/mediagoblin.mo
+++ b/mediagoblin/i18n/is_IS/LC_MESSAGES/mediagoblin.mo
Binary files differ
diff --git a/mediagoblin/i18n/is_IS/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/is_IS/LC_MESSAGES/mediagoblin.po
index 1b298a64..77896b87 100644
--- a/mediagoblin/i18n/is_IS/LC_MESSAGES/mediagoblin.po
+++ b/mediagoblin/i18n/is_IS/LC_MESSAGES/mediagoblin.po
@@ -3,15 +3,16 @@
# This file is distributed under the same license as the PROJECT project.
#
# Translators:
-# <tryggvib@fsfi.is>, 2012.
+# tryggvib <tryggvib@fsfi.is>, 2012
+# tryggvib <tryggvib@fsfi.is>, 2013
msgid ""
msgstr ""
"Project-Id-Version: GNU MediaGoblin\n"
"Report-Msgid-Bugs-To: http://issues.mediagoblin.org/\n"
-"POT-Creation-Date: 2013-03-04 18:04-0600\n"
-"PO-Revision-Date: 2013-03-05 00:04+0000\n"
-"Last-Translator: cwebber <cwebber@dustycloud.org>\n"
-"Language-Team: LANGUAGE <LL@li.org>\n"
+"POT-Creation-Date: 2013-05-27 13:54-0500\n"
+"PO-Revision-Date: 2013-06-05 22:51+0000\n"
+"Last-Translator: tryggvib <tryggvib@fsfi.is>\n"
+"Language-Team: Icelandic (Iceland) (http://www.transifex.com/projects/p/mediagoblin/language/is_IS/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
@@ -19,34 +20,39 @@ msgstr ""
"Language: is_IS\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: mediagoblin/auth/forms.py:28
-msgid "Invalid User name or email address."
-msgstr ""
-
-#: mediagoblin/auth/forms.py:29
-msgid "This field does not take email addresses."
-msgstr ""
-
-#: mediagoblin/auth/forms.py:30
-msgid "This field requires an email address."
-msgstr ""
-
-#: mediagoblin/auth/forms.py:52 mediagoblin/auth/forms.py:67
+#: mediagoblin/auth/forms.py:26
msgid "Username"
msgstr "Notandanafn"
-#: mediagoblin/auth/forms.py:56 mediagoblin/auth/forms.py:71
+#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:45
+#: mediagoblin/tests/test_util.py:110
msgid "Password"
msgstr "Lykilorð"
-#: mediagoblin/auth/forms.py:60
+#: mediagoblin/auth/forms.py:34
msgid "Email address"
msgstr "Netfang"
-#: mediagoblin/auth/forms.py:78
+#: mediagoblin/auth/forms.py:41
+msgid "Username or Email"
+msgstr "Notandanafn eða tölvupóstur"
+
+#: mediagoblin/auth/forms.py:52
msgid "Username or email"
msgstr "Notandanafn eða netfang"
+#: mediagoblin/auth/tools.py:31
+msgid "Invalid User name or email address."
+msgstr "Ógilt notandanafn eða netfang"
+
+#: mediagoblin/auth/tools.py:32
+msgid "This field does not take email addresses."
+msgstr "Þessi reitur tekur ekki við netföngum."
+
+#: mediagoblin/auth/tools.py:33
+msgid "This field requires an email address."
+msgstr "í þennan reit verður að slá inn netfang."
+
#: mediagoblin/auth/views.py:54
msgid "Sorry, registration is disabled on this instance."
msgstr "Því miður er nýskráning ekki leyfð á þessu svæði."
@@ -59,54 +65,54 @@ msgstr "Því miður er nú þegar til notandi með þetta nafn."
msgid "Sorry, a user with that email address already exists."
msgstr "Því miður þá er annar notandi í kerfinu með þetta netfang skráð."
-#: mediagoblin/auth/views.py:174
+#: mediagoblin/auth/views.py:182
msgid ""
"Your email address has been verified. You may now login, edit your profile, "
"and submit images!"
msgstr "Netfangið þitt hefur verið staðfest. Þú getur núna innskráð þig, breytt kenniskránni þinni og sent inn efni!"
-#: mediagoblin/auth/views.py:180
+#: mediagoblin/auth/views.py:188
msgid "The verification key or user id is incorrect"
msgstr "Staðfestingarlykillinn eða notendaauðkennið er rangt"
-#: mediagoblin/auth/views.py:198
+#: mediagoblin/auth/views.py:206
msgid "You must be logged in so we know who to send the email to!"
msgstr "Þú verður að hafa innskráð þig svo við vitum hvert á að senda tölvupóstinn!"
-#: mediagoblin/auth/views.py:206
+#: mediagoblin/auth/views.py:214
msgid "You've already verified your email address!"
msgstr "Þú hefur staðfest netfangið þitt!"
-#: mediagoblin/auth/views.py:219
+#: mediagoblin/auth/views.py:227
msgid "Resent your verification email."
msgstr "Endursendi staðfestingartölvupóst"
-#: mediagoblin/auth/views.py:250
+#: mediagoblin/auth/views.py:258
msgid ""
"If that email address (case sensitive!) is registered an email has been sent"
" with instructions on how to change your password."
-msgstr ""
+msgstr "Ef þetta netfang (há- og lágstafir skipta máli) er skráð hjá okkur hefur tölvupóstur verið sendur með leiðbeiningum um hvernig þú getur breytt lykilorðinu þínu."
-#: mediagoblin/auth/views.py:261
+#: mediagoblin/auth/views.py:269
msgid "Couldn't find someone with that username."
-msgstr ""
+msgstr "Gat ekki fundið neinn með þetta notandanafn."
-#: mediagoblin/auth/views.py:264
+#: mediagoblin/auth/views.py:272
msgid ""
"An email has been sent with instructions on how to change your password."
msgstr "Tölvupóstur hefur verið sendur með leiðbeiningum um hvernig þú átt að breyta lykilorðinu þínu."
-#: mediagoblin/auth/views.py:271
+#: mediagoblin/auth/views.py:279
msgid ""
"Could not send password recovery email as your username is inactive or your "
"account's email address has not been verified."
msgstr "Gat ekki sent tölvupóst um endurstillingu lykilorðs því notandanafnið þitt er óvirkt eða þá að þú hefur ekki staðfest netfangið þitt."
-#: mediagoblin/auth/views.py:328
+#: mediagoblin/auth/views.py:336
msgid "You can now log in using your new password."
msgstr "Þú getur núna innskráð þig með nýja lykilorðinu þínu."
-#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:93
+#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:82
#: mediagoblin/submit/forms.py:28 mediagoblin/submit/forms.py:47
#: mediagoblin/user_pages/forms.py:45
msgid "Title"
@@ -117,7 +123,7 @@ msgid "Description of this work"
msgstr "Lýsing á þessu efni"
#: mediagoblin/edit/forms.py:29 mediagoblin/edit/forms.py:52
-#: mediagoblin/edit/forms.py:97 mediagoblin/submit/forms.py:32
+#: mediagoblin/edit/forms.py:86 mediagoblin/submit/forms.py:32
#: mediagoblin/submit/forms.py:51 mediagoblin/user_pages/forms.py:49
msgid ""
"You can use\n"
@@ -133,11 +139,11 @@ msgstr "Efnisorð"
msgid "Separate tags by commas."
msgstr "Aðskildu efnisorðin með kommum."
-#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:101
+#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:90
msgid "Slug"
msgstr "Vefslóðarormur"
-#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:102
+#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:91
msgid "The slug can't be empty"
msgstr "Vefslóðarormurinn getur ekki verið tómur"
@@ -165,45 +171,45 @@ msgid "This address contains errors"
msgstr "Þetta netfang inniheldur villur"
#: mediagoblin/edit/forms.py:63
-msgid "Old password"
-msgstr "Gamla lykilorðið"
-
-#: mediagoblin/edit/forms.py:64
-msgid "Enter your old password to prove you own this account."
-msgstr "Skráðu gamla lykilorðið þitt til að sanna að þú átt þennan aðgang."
-
-#: mediagoblin/edit/forms.py:67
-msgid "New password"
-msgstr "Nýtt lykilorð"
-
-#: mediagoblin/edit/forms.py:74
msgid "License preference"
-msgstr ""
+msgstr "Leyfiskjörstilling"
-#: mediagoblin/edit/forms.py:80
+#: mediagoblin/edit/forms.py:69
msgid "This will be your default license on upload forms."
-msgstr ""
+msgstr "Þetta verður sjálfgefna leyfið þegar þú vilt hlaða upp efni."
-#: mediagoblin/edit/forms.py:82
+#: mediagoblin/edit/forms.py:71
msgid "Email me when others comment on my media"
msgstr "Senda mér tölvupóst þegar einhver bætir athugasemd við efnið mitt"
-#: mediagoblin/edit/forms.py:94
+#: mediagoblin/edit/forms.py:83
msgid "The title can't be empty"
msgstr "Þessi titill getur verið innihaldslaus"
-#: mediagoblin/edit/forms.py:96 mediagoblin/submit/forms.py:50
+#: mediagoblin/edit/forms.py:85 mediagoblin/submit/forms.py:50
#: mediagoblin/user_pages/forms.py:48
msgid "Description of this collection"
msgstr "Lýsing á þessu albúmi"
-#: mediagoblin/edit/forms.py:103
+#: mediagoblin/edit/forms.py:92
msgid ""
"The title part of this collection's address. You usually don't need to "
"change this."
msgstr "Titilhlutinn í vefslóð þessa albúms. Þú þarft vanalega ekki að breyta þessu."
-#: mediagoblin/edit/views.py:66
+#: mediagoblin/edit/forms.py:99
+msgid "Old password"
+msgstr "Gamla lykilorðið"
+
+#: mediagoblin/edit/forms.py:101
+msgid "Enter your old password to prove you own this account."
+msgstr "Skráðu gamla lykilorðið þitt til að sanna að þú átt þennan aðgang."
+
+#: mediagoblin/edit/forms.py:104
+msgid "New password"
+msgstr "Nýtt lykilorð"
+
+#: mediagoblin/edit/views.py:67
msgid "An entry with that slug already exists for this user."
msgstr "Efni merkt með þessum vefslóðarormi er nú þegar til fyrir þennan notanda."
@@ -218,7 +224,7 @@ msgstr "Þú bættir við viðhenginu %s!"
#: mediagoblin/edit/views.py:182
msgid "You can only edit your own profile."
-msgstr ""
+msgstr "Þú getur bara breytt þinni eigin kenniskrá."
#: mediagoblin/edit/views.py:188
msgid "You are editing a user's profile. Proceed with caution."
@@ -228,57 +234,80 @@ msgstr "Þú ert að breyta kenniskrá notanda. Farðu mjög varlega."
msgid "Profile changes saved"
msgstr "Breytingar á kenniskrá vistaðar"
-#: mediagoblin/edit/views.py:241
-msgid "Wrong password"
-msgstr "Vitlaust lykilorð"
-
-#: mediagoblin/edit/views.py:252
+#: mediagoblin/edit/views.py:240
msgid "Account settings saved"
msgstr "Aðgangsstillingar vistaðar"
-#: mediagoblin/edit/views.py:286
+#: mediagoblin/edit/views.py:274
msgid "You need to confirm the deletion of your account."
-msgstr ""
+msgstr "Þú verður að samþykkja eyðingu á notandaaðganginum þínum."
-#: mediagoblin/edit/views.py:322 mediagoblin/submit/views.py:142
-#: mediagoblin/user_pages/views.py:214
+#: mediagoblin/edit/views.py:310 mediagoblin/submit/views.py:138
+#: mediagoblin/user_pages/views.py:222
#, python-format
msgid "You already have a collection called \"%s\"!"
msgstr "Þú hefur nú þegar albúm sem kallast \"%s\"!"
-#: mediagoblin/edit/views.py:326
+#: mediagoblin/edit/views.py:314
msgid "A collection with that slug already exists for this user."
msgstr "Albúm með þessu vefslóðarormi er nú þegar til fyrir þennan notanda."
-#: mediagoblin/edit/views.py:343
+#: mediagoblin/edit/views.py:329
msgid "You are editing another user's collection. Proceed with caution."
msgstr "Þú ert að breyta albúmi annars notanda. Farðu mjög varlega."
-#: mediagoblin/gmg_commands/theme.py:58
+#: mediagoblin/edit/views.py:348
+msgid "Wrong password"
+msgstr "Vitlaust lykilorð"
+
+#: mediagoblin/edit/views.py:363
+msgid "Your password was changed successfully"
+msgstr "Það tókst að breyta lykilorðinu þínu"
+
+#: mediagoblin/gmg_commands/assetlink.py:60
msgid "Cannot link theme... no theme set\n"
msgstr "Get ekki hlekkjað í þema... ekkert þema stillt\n"
-#: mediagoblin/gmg_commands/theme.py:71
+#: mediagoblin/gmg_commands/assetlink.py:73
msgid "No asset directory for this theme\n"
msgstr "Engin eignamappa fyrir þetta þema\n"
-#: mediagoblin/gmg_commands/theme.py:74
+#: mediagoblin/gmg_commands/assetlink.py:76
msgid "However, old link directory symlink found; removed.\n"
msgstr "Fann samt gamlan táknrænan tengil á möppu; fjarlægður.\n"
+#: mediagoblin/gmg_commands/assetlink.py:112
+#, python-format
+msgid "Could not link \"%s\": %s exists and is not a symlink\n"
+msgstr "Gat ekki tengt \"%s\": %s er til og er ekki sýndartengill\n"
+
+#: mediagoblin/gmg_commands/assetlink.py:119
+#, python-format
+msgid "Skipping \"%s\"; already set up.\n"
+msgstr "Hoppa yfir \"%s\"; hefur nú þegar verið sett upp.\n"
+
+#: mediagoblin/gmg_commands/assetlink.py:124
+#, python-format
+msgid "Old link found for \"%s\"; removing.\n"
+msgstr "Gamall tengill fannst fyrir \"%s\"; fjarlægi.\n"
+
#: mediagoblin/meddleware/csrf.py:134
msgid ""
"CSRF cookie not present. This is most likely the result of a cookie blocker "
"or somesuch.<br/>Make sure to permit the settings of cookies for this "
"domain."
-msgstr ""
+msgstr "CSRF smygildi ekki til staðar. Þetta er líklegast orsakað af smygildishindrara eða einhverju þess háttar.<br/>Athugaðu hvort þú leyfir ekki alveg örugglega smygildi fyrir þetta lén."
-#: mediagoblin/media_types/__init__.py:61
-#: mediagoblin/media_types/__init__.py:102
+#: mediagoblin/media_types/__init__.py:111
+#: mediagoblin/media_types/__init__.py:155
msgid "Sorry, I don't support that file type :("
msgstr "Ég styð því miður ekki þessa gerð af skrám :("
-#: mediagoblin/media_types/video/processing.py:36
+#: mediagoblin/media_types/pdf/processing.py:136
+msgid "unoconv failing to run, check log file"
+msgstr "tekst ekki að keyra unoconv, athugaðu annálsskrá"
+
+#: mediagoblin/media_types/video/processing.py:37
msgid "Video transcoding failed"
msgstr "Myndbandsþverkótun mistókst"
@@ -345,17 +374,17 @@ msgstr "Ãframsendingarvefslóðin fyrir forritin, þessi reitur\n er
msgid "This field is required for public clients"
msgstr "Þessi reitur er nauðsynlegur fyrir opinbera biðlara"
-#: mediagoblin/plugins/oauth/views.py:59
+#: mediagoblin/plugins/oauth/views.py:56
msgid "The client {0} has been registered!"
msgstr "Biðlarinn {0} hefur verið skráður!"
#: mediagoblin/plugins/oauth/templates/oauth/client/connections.html:22
msgid "OAuth client connections"
-msgstr ""
+msgstr "Biðlarartengingar OAuth"
#: mediagoblin/plugins/oauth/templates/oauth/client/list.html:22
msgid "Your OAuth clients"
-msgstr ""
+msgstr "OAuth-biðlararnir þínir"
#: mediagoblin/plugins/oauth/templates/oauth/client/register.html:29
#: mediagoblin/templates/mediagoblin/submit/collection.html:30
@@ -364,7 +393,7 @@ msgstr ""
msgid "Add"
msgstr "Bæta við"
-#: mediagoblin/processing/__init__.py:172
+#: mediagoblin/processing/__init__.py:193
msgid "Invalid file given for media type."
msgstr "Ógild skrá gefin fyrir þessa margmiðlunartegund."
@@ -372,45 +401,45 @@ msgstr "Ógild skrá gefin fyrir þessa margmiðlunartegund."
msgid "File"
msgstr "Skrá"
-#: mediagoblin/submit/views.py:51
+#: mediagoblin/submit/views.py:49
msgid "You must provide a file."
msgstr "Þú verður að gefa upp skrá."
-#: mediagoblin/submit/views.py:97
+#: mediagoblin/submit/views.py:93
msgid "Woohoo! Submitted!"
msgstr "Jibbí jei! Það tókst að senda inn!"
-#: mediagoblin/submit/views.py:146
+#: mediagoblin/submit/views.py:144
#, python-format
msgid "Collection \"%s\" added!"
msgstr "Albúmið \"%s\" var búið til!"
-#: mediagoblin/templates/mediagoblin/base.html:64
+#: mediagoblin/templates/mediagoblin/base.html:67
msgid "Verify your email!"
msgstr "Staðfestu netfangið þitt!"
-#: mediagoblin/templates/mediagoblin/base.html:65
+#: mediagoblin/templates/mediagoblin/base.html:68
msgid "log out"
msgstr "útskrá"
-#: mediagoblin/templates/mediagoblin/base.html:70
+#: mediagoblin/templates/mediagoblin/base.html:73
#: mediagoblin/templates/mediagoblin/auth/login.html:28
#: mediagoblin/templates/mediagoblin/auth/login.html:36
#: mediagoblin/templates/mediagoblin/auth/login.html:54
msgid "Log in"
-msgstr "Innskráning"
+msgstr "Innskrá"
-#: mediagoblin/templates/mediagoblin/base.html:79
+#: mediagoblin/templates/mediagoblin/base.html:82
#, python-format
msgid "<a href=\"%(user_url)s\">%(user_name)s</a>'s account"
-msgstr "Notandaaðgangur <a href=\"%(user_url)s\">%(user_name)s</a>"
+msgstr "Notandaaðgangur: <a href=\"%(user_url)s\">%(user_name)s</a>"
-#: mediagoblin/templates/mediagoblin/base.html:86
+#: mediagoblin/templates/mediagoblin/base.html:89
msgid "Change account settings"
msgstr "Breyta stillingum notandaaðgangs"
-#: mediagoblin/templates/mediagoblin/base.html:90
-#: mediagoblin/templates/mediagoblin/base.html:105
+#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:108
#: mediagoblin/templates/mediagoblin/admin/panel.html:21
#: mediagoblin/templates/mediagoblin/admin/panel.html:26
#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:21
@@ -418,72 +447,25 @@ msgstr "Breyta stillingum notandaaðgangs"
msgid "Media processing panel"
msgstr "Margmiðlunarvinnsluskiki"
-#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:96
msgid "Log out"
-msgstr ""
+msgstr "Skrá út"
-#: mediagoblin/templates/mediagoblin/base.html:96
+#: mediagoblin/templates/mediagoblin/base.html:99
#: mediagoblin/templates/mediagoblin/user_pages/user.html:156
msgid "Add media"
msgstr "Senda inn efni"
-#: mediagoblin/templates/mediagoblin/base.html:99
+#: mediagoblin/templates/mediagoblin/base.html:102
#: mediagoblin/templates/mediagoblin/user_pages/collection_list.html:41
msgid "Create new collection"
msgstr "Búa til nýtt albúm"
-#: mediagoblin/templates/mediagoblin/base.html:122
-#, python-format
-msgid ""
-"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
-"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/base.html:125
-#, python-format
-msgid ""
-"Released under the <a "
-"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
-"href=\"%(source_link)s\">Source code</a> available."
-msgstr "Gefið út undir <a href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a href=\"%(source_link)s\">Frumkóti</a> aðgengilegur."
-
#: mediagoblin/templates/mediagoblin/error.html:24
msgid "Image of goblin stressing out"
msgstr "Mynd af durt í stresskasti"
-#: mediagoblin/templates/mediagoblin/root.html:31
-msgid "Explore"
-msgstr "Skoða"
-
-#: mediagoblin/templates/mediagoblin/root.html:33
-msgid "Hi there, welcome to this MediaGoblin site!"
-msgstr "Hæ! Gakktu í bæinn á þetta MediaGoblin vefsvæði!"
-
-#: mediagoblin/templates/mediagoblin/root.html:35
-msgid ""
-"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
-"extraordinarily great piece of media hosting software."
-msgstr "Þetta vefsvæði keyrira á <a href=\"http://mediagoblin.org\">MediaGoblin</a> sem er ótrúlega frábær hugbúnaður til að geyma margmiðlunarefni."
-
-#: mediagoblin/templates/mediagoblin/root.html:36
-msgid ""
-"To add your own media, place comments, and more, you can log in with your "
-"MediaGoblin account."
-msgstr "Til að senda inn þitt efni, gera athugasemdir og fleira getur þú skráð þig inn með þínum MediaGoblin aðgangi."
-
-#: mediagoblin/templates/mediagoblin/root.html:38
-msgid "Don't have one yet? It's easy!"
-msgstr "Ertu ekki með aðgang? Það er auðvelt að búa til!"
-
-#: mediagoblin/templates/mediagoblin/root.html:39
-#, python-format
-msgid ""
-"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
-" or\n"
-" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
-msgstr "<a class=\"button_action_highlight\" href=\"%(register_url)s\">Búa til aðgang á þessari síðu</a>\n eða\n <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Settu upp þinn eigin margmiðlunarþjón</a>"
-
-#: mediagoblin/templates/mediagoblin/root.html:47
+#: mediagoblin/templates/mediagoblin/root.html:32
msgid "Most recent media"
msgstr "Nýlegt efni"
@@ -589,6 +571,53 @@ msgid ""
"%(verification_url)s"
msgstr "Hæ %(username)s,\n\ntil að virkja GNU MediaGoblin aðganginn þinn, opnaðu þá eftirfarandi vefslóði í\nvafranum þínum:\n\n%(verification_url)s"
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:21
+#, python-format
+msgid ""
+"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
+"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
+msgstr "Keyrt af <a href=\"http://mediagoblin.org/\" title='Version %(version)s'>MediaGoblin</a>, sem er <a href=\"http://gnu.org/\">GNU</a> verkefni."
+
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:24
+#, python-format
+msgid ""
+"Released under the <a "
+"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
+"href=\"%(source_link)s\">Source code</a> available."
+msgstr "Gefið út undir <a href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a href=\"%(source_link)s\">Frumkóti</a> aðgengilegur."
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:20
+msgid "Explore"
+msgstr "Skoða"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:22
+msgid "Hi there, welcome to this MediaGoblin site!"
+msgstr "Hæ! Gakktu í bæinn á þetta MediaGoblin vefsvæði!"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:24
+msgid ""
+"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
+"extraordinarily great piece of media hosting software."
+msgstr "Þetta vefsvæði keyrir á <a href=\"http://mediagoblin.org\">MediaGoblin</a> sem er ótrúlega frábær hugbúnaður til að geyma margmiðlunarefni."
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:25
+msgid ""
+"To add your own media, place comments, and more, you can log in with your "
+"MediaGoblin account."
+msgstr "Til að senda inn þitt efni, gera athugasemdir og fleira getur þú skráð þig inn með þínum MediaGoblin aðgangi."
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:27
+msgid "Don't have one yet? It's easy!"
+msgstr "Ertu ekki með aðgang? Það er auðvelt að búa til!"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:28
+#, python-format
+msgid ""
+"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
+" or\n"
+" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
+msgstr "<a class=\"button_action_highlight\" href=\"%(register_url)s\">Búa til aðgang á þessari síðu</a>\neða\n<a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Settu upp þinn eigin margmiðlunarþjón</a>"
+
#: mediagoblin/templates/mediagoblin/bits/logo.html:23
#: mediagoblin/themes/airy/templates/mediagoblin/bits/logo.html:23
msgid "MediaGoblin logo"
@@ -601,13 +630,13 @@ msgid "Editing attachments for %(media_title)s"
msgstr "Breyti viðhengjum við: %(media_title)s"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:159
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:175
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:182
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:198
msgid "Attachments"
msgstr "Viðhengi"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:57
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:181
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:204
msgid "Add attachment"
msgstr "Bæta við viðhengi"
@@ -624,23 +653,33 @@ msgstr "Hætta við"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:63
#: mediagoblin/templates/mediagoblin/edit/edit.html:42
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:52
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:55
#: mediagoblin/templates/mediagoblin/edit/edit_collection.html:33
#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:40
msgid "Save changes"
msgstr "Vista breytingar"
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:28
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:38
+#, python-format
+msgid "Changing %(username)s's password"
+msgstr "Breyti lykilorði fyrir notandann: %(username)s"
+
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:45
+msgid "Save"
+msgstr "Vista"
+
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:28
#, python-format
msgid "Really delete user '%(user_name)s' and all related media/comments?"
-msgstr ""
+msgstr "Virkilega eyða notanda '%(user_name)s' og tengt efni/athugasemdir?"
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:35
msgid "Yes, really delete my account"
-msgstr ""
+msgstr "Já, ég vil örugglega eyða aðganginum mínum"
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:47
+#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:48
#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:49
msgid "Delete permanently"
msgstr "Eytt algjörlega"
@@ -657,9 +696,13 @@ msgstr "Breyti %(media_title)s"
msgid "Changing %(username)s's account settings"
msgstr "Breyti notandaaðgangsstillingum fyrir: %(username)s"
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:59
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:46
+msgid "Change your password."
+msgstr "Breyta lykilorðinu þínu."
+
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:62
msgid "Delete my account"
-msgstr ""
+msgstr "Eyða aðganginum mínum"
#: mediagoblin/templates/mediagoblin/edit/edit_collection.html:29
#, python-format
@@ -682,6 +725,7 @@ msgstr "Efni merkt með: %(tag_name)s"
#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:56
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:65
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:136
#: mediagoblin/templates/mediagoblin/media_displays/video.html:55
msgid "Download"
@@ -706,6 +750,7 @@ msgid ""
msgstr "Þú getur náð í nýlegan vafra sem \n\tgetur spilað hljóðskrár á <a href=\"http://getfirefox.com\">\n\t http://getfirefox.com</a>!"
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:60
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:71
#: mediagoblin/templates/mediagoblin/media_displays/video.html:61
msgid "Original file"
msgstr "Upphaflega skráin"
@@ -714,6 +759,7 @@ msgstr "Upphaflega skráin"
msgid "WebM file (Vorbis codec)"
msgstr "WebM skrá (Vorbis víxlþjöppun)"
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:59
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:87
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:93
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:99
@@ -724,6 +770,10 @@ msgstr "WebM skrá (Vorbis víxlþjöppun)"
msgid "Image for %(media_title)s"
msgstr "Mynd fyrir %(media_title)s"
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:79
+msgid "PDF file"
+msgstr "PDF skrá"
+
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:112
msgid "Toggle Rotate"
msgstr "Stilla snúning af eða á"
@@ -769,14 +819,14 @@ msgid ""
"Sorry, this video will not work because\n"
" your web browser does not support HTML5 \n"
" video."
-msgstr ""
+msgstr "Því miður mun þetta myndband ekki virka því\n vafrinn þinn styður ekki HTML5 \n myndbönd."
#: mediagoblin/templates/mediagoblin/media_displays/video.html:47
msgid ""
"You can get a modern web browser that \n"
" can play this video at <a href=\"http://getfirefox.com\">\n"
" http://getfirefox.com</a>!"
-msgstr ""
+msgstr "Þú getur náð í nýlegan vafra sem \n sem getur spilað myndbandið á <a href=\"http://getfirefox.com\">\n http://getfirefox.com</a>!"
#: mediagoblin/templates/mediagoblin/media_displays/video.html:69
msgid "WebM file (640p; VP8/Vorbis)"
@@ -822,19 +872,19 @@ msgstr "Virkilega eyða %(title)s?"
msgid "Really remove %(media_title)s from %(collection_title)s?"
msgstr "Virkilega fjarlægja %(media_title)s úr %(collection_title)s albúminu?"
-#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:53
+#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:54
msgid "Remove"
msgstr "Fjarlægja"
#: mediagoblin/templates/mediagoblin/user_pages/collection_list.html:21
#, python-format
msgid "%(username)s's collections"
-msgstr ""
+msgstr "Albúm sem %(username)s á"
#: mediagoblin/templates/mediagoblin/user_pages/collection_list.html:28
#, python-format
msgid "<a href=\"%(user_url)s\">%(username)s</a>'s collections"
-msgstr ""
+msgstr "Albúm sem <a href=\"%(user_url)s\">%(username)s</a> á"
#: mediagoblin/templates/mediagoblin/user_pages/comment_email.txt:19
#, python-format
@@ -853,7 +903,7 @@ msgstr "Efni sem %(username)s á"
msgid ""
"<a href=\"%(user_url)s\">%(username)s</a>'s media with tag <a "
"href=\"%(tag_url)s\">%(tag)s</a>"
-msgstr ""
+msgstr "Efni sem <a href=\"%(user_url)s\">%(username)s</a> á og er merkt með <a href=\"%(tag_url)s\">%(tag)s</a>"
#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:48
#, python-format
@@ -865,30 +915,34 @@ msgstr "Efni sem <a href=\"%(user_url)s\">%(username)s</a> á"
msgid "â– Browsing media by <a href=\"%(user_url)s\">%(username)s</a>"
msgstr "■Skoða efnið sem <a href=\"%(user_url)s\">%(username)s</a> setti inn"
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:94
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:95
msgid "Add a comment"
msgstr "Bæta við athugasemd"
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:102
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:104
msgid "Add this comment"
msgstr "Senda inn þessa athugasemd"
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:123
-msgid "at"
-msgstr "hjá"
-
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:144
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:132
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:152
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:164
#, python-format
-msgid ""
-"<h3>Added on</h3>\n"
-" <p>%(date)s</p>"
-msgstr "<h3>Bætt við:</h3>\n <p>%(date)s</p>"
+msgid "%(formatted_time)s ago"
+msgstr "Fyrir %(formatted_time)s"
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:150
+msgid "Added"
+msgstr "Bætt við"
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:161
+msgid "Created"
+msgstr "Skapað"
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:28
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:40
#, python-format
msgid "Add “%(media_title)s†to a collection"
-msgstr ""
+msgstr "Setja '%(media_title)s' í albúm"
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:54
msgid "+"
@@ -967,7 +1021,7 @@ msgstr "Þessi notandi hefur ekki fyllt inn í upplýsingar um sig (ennþá)."
#: mediagoblin/templates/mediagoblin/user_pages/user.html:124
msgid "Browse collections"
-msgstr ""
+msgstr "Skoða albúm"
#: mediagoblin/templates/mediagoblin/user_pages/user.html:137
#, python-format
@@ -992,11 +1046,11 @@ msgstr "(fjarlægja)"
#: mediagoblin/templates/mediagoblin/utils/collections.html:21
msgid "Collected in"
-msgstr ""
+msgstr "Sett í albúm"
#: mediagoblin/templates/mediagoblin/utils/collections.html:40
msgid "Add to a collection"
-msgstr ""
+msgstr "Setja í albúm"
#: mediagoblin/templates/mediagoblin/utils/feed_link.html:21
#: mediagoblin/themes/airy/templates/mediagoblin/utils/feed_link.html:21
@@ -1038,7 +1092,7 @@ msgstr "eldri"
msgid "Tagged with"
msgstr "Merkt með"
-#: mediagoblin/tools/exif.py:80
+#: mediagoblin/tools/exif.py:83
msgid "Could not read the image file."
msgstr "Gat ekki lesið myndskrána."
@@ -1068,9 +1122,33 @@ msgid ""
" deleted."
msgstr "Því miður! Það virðist ekki vera nein síða á þessari vefslóð.</p><p>Ef þú ert viss um að vefslóðin sé rétt hefur vefsíðan sem þú ert að leita að kannski verið flutt eða fjarlægð."
+#: mediagoblin/tools/timesince.py:62
+msgid "year"
+msgstr "ár"
+
+#: mediagoblin/tools/timesince.py:63
+msgid "month"
+msgstr "mánuður"
+
+#: mediagoblin/tools/timesince.py:64
+msgid "week"
+msgstr "vika"
+
+#: mediagoblin/tools/timesince.py:65
+msgid "day"
+msgstr "dagur"
+
+#: mediagoblin/tools/timesince.py:66
+msgid "hour"
+msgstr "klukkustund"
+
+#: mediagoblin/tools/timesince.py:67
+msgid "minute"
+msgstr "mínúta"
+
#: mediagoblin/user_pages/forms.py:23
msgid "Comment"
-msgstr ""
+msgstr "Athugasemd"
#: mediagoblin/user_pages/forms.py:25
msgid ""
@@ -1089,7 +1167,7 @@ msgstr "Ég er viss um að ég vilji fjarlægja þetta efni úr albúminu"
#: mediagoblin/user_pages/forms.py:39
msgid "Collection"
-msgstr ""
+msgstr "Albúm"
#: mediagoblin/user_pages/forms.py:40
msgid "-- Select --"
@@ -1099,73 +1177,77 @@ msgstr "-- Velja --"
msgid "Include a note"
msgstr "Bæta við minnispunktum"
-#: mediagoblin/user_pages/lib.py:56
+#: mediagoblin/user_pages/lib.py:58
msgid "commented on your post"
msgstr "skrifaði athugasemd við færsluna þína"
-#: mediagoblin/user_pages/views.py:166
+#: mediagoblin/user_pages/views.py:169
+msgid "Sorry, comments are disabled."
+msgstr "Því miður, athugasemdir eru óvirkar."
+
+#: mediagoblin/user_pages/views.py:174
msgid "Oops, your comment was empty."
msgstr "Obbosí! Athugasemdin þín var innihaldslaus."
-#: mediagoblin/user_pages/views.py:172
+#: mediagoblin/user_pages/views.py:180
msgid "Your comment has been posted!"
msgstr "Athugasemdin þín var skráð!"
-#: mediagoblin/user_pages/views.py:197
+#: mediagoblin/user_pages/views.py:205
msgid "Please check your entries and try again."
msgstr "Vinsamlegast kíktu á innsendingarnar þínar og reyndu aftur."
-#: mediagoblin/user_pages/views.py:237
+#: mediagoblin/user_pages/views.py:245
msgid "You have to select or add a collection"
msgstr "Þú verður að velja eða búa til albúm"
-#: mediagoblin/user_pages/views.py:248
+#: mediagoblin/user_pages/views.py:256
#, python-format
msgid "\"%s\" already in collection \"%s\""
msgstr "\"%s\" er nú þegar í albúminu \"%s\""
-#: mediagoblin/user_pages/views.py:264
+#: mediagoblin/user_pages/views.py:262
#, python-format
msgid "\"%s\" added to collection \"%s\""
msgstr "\"%s\" sett í albúmið \"%s\""
-#: mediagoblin/user_pages/views.py:286
+#: mediagoblin/user_pages/views.py:282
msgid "You deleted the media."
msgstr "Þú eyddir þessu efni."
-#: mediagoblin/user_pages/views.py:293
+#: mediagoblin/user_pages/views.py:289
msgid "The media was not deleted because you didn't check that you were sure."
msgstr "Efninu var ekki eytt þar sem þú merktir ekki við að þú værir viss."
-#: mediagoblin/user_pages/views.py:301
+#: mediagoblin/user_pages/views.py:296
msgid "You are about to delete another user's media. Proceed with caution."
msgstr "Þú ert í þann mund að fara að eyða efni frá öðrum notanda. Farðu mjög varlega."
-#: mediagoblin/user_pages/views.py:375
+#: mediagoblin/user_pages/views.py:370
msgid "You deleted the item from the collection."
msgstr "Þú tókst þetta efni úr albúminu."
-#: mediagoblin/user_pages/views.py:379
+#: mediagoblin/user_pages/views.py:374
msgid "The item was not removed because you didn't check that you were sure."
msgstr "Þetta efni var ekki fjarlægt af því að þú merktir ekki við að þú værir viss."
-#: mediagoblin/user_pages/views.py:389
+#: mediagoblin/user_pages/views.py:382
msgid ""
"You are about to delete an item from another user's collection. Proceed with"
" caution."
msgstr "Þú ert í þann mund að fara að eyða efni úr albúmi annars notanda. Farðu mjög varlega."
-#: mediagoblin/user_pages/views.py:422
+#: mediagoblin/user_pages/views.py:415
#, python-format
msgid "You deleted the collection \"%s\""
msgstr "Þú eyddir albúminu \"%s\""
-#: mediagoblin/user_pages/views.py:429
+#: mediagoblin/user_pages/views.py:422
msgid ""
"The collection was not deleted because you didn't check that you were sure."
msgstr "Þessu albúmi var ekki eytt vegna þess að þu merktir ekki við að þú værir viss."
-#: mediagoblin/user_pages/views.py:439
+#: mediagoblin/user_pages/views.py:430
msgid ""
"You are about to delete another user's collection. Proceed with caution."
msgstr "Þú ert í þann mund að fara að eyða albúmi annars notanda. Farðu mjög varlega."
diff --git a/mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.mo
index 62451511..62575b62 100644
--- a/mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.mo
+++ b/mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.mo
Binary files differ
diff --git a/mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.po
index e13345a7..c782fc62 100644
--- a/mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.po
+++ b/mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.po
@@ -3,18 +3,19 @@
# This file is distributed under the same license as the PROJECT project.
#
# Translators:
-# Francesco Apruzzese <cescoap@gmail.com>, 2012.
-# <pikappa469@alice.it>, 2011.
-# <robi@nunnisoft.ch>, 2011.
-# <sun_lion@live.com>, 2012.
+# Francesco Apruzzese <cescoap@gmail.com>, 2012
+# gdb <gaedeb01@gmail.com>, 2013
+# pikappa469 <pikappa469@alice.it>, 2011
+# nunni <robi@nunnisoft.ch>, 2011
+# Damtux <sun_lion@live.com>, 2012
msgid ""
msgstr ""
"Project-Id-Version: GNU MediaGoblin\n"
"Report-Msgid-Bugs-To: http://issues.mediagoblin.org/\n"
-"POT-Creation-Date: 2013-03-04 18:04-0600\n"
-"PO-Revision-Date: 2013-03-05 00:04+0000\n"
+"POT-Creation-Date: 2013-05-27 13:54-0500\n"
+"PO-Revision-Date: 2013-05-27 18:54+0000\n"
"Last-Translator: cwebber <cwebber@dustycloud.org>\n"
-"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language-Team: Italian (http://www.transifex.com/projects/p/mediagoblin/language/it/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
@@ -22,34 +23,39 @@ msgstr ""
"Language: it\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: mediagoblin/auth/forms.py:28
-msgid "Invalid User name or email address."
-msgstr ""
-
-#: mediagoblin/auth/forms.py:29
-msgid "This field does not take email addresses."
-msgstr ""
-
-#: mediagoblin/auth/forms.py:30
-msgid "This field requires an email address."
-msgstr ""
-
-#: mediagoblin/auth/forms.py:52 mediagoblin/auth/forms.py:67
+#: mediagoblin/auth/forms.py:26
msgid "Username"
msgstr "Nome utente"
-#: mediagoblin/auth/forms.py:56 mediagoblin/auth/forms.py:71
+#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:45
+#: mediagoblin/tests/test_util.py:110
msgid "Password"
msgstr "Password"
-#: mediagoblin/auth/forms.py:60
+#: mediagoblin/auth/forms.py:34
msgid "Email address"
msgstr "Indirizzo email"
-#: mediagoblin/auth/forms.py:78
+#: mediagoblin/auth/forms.py:41
+msgid "Username or Email"
+msgstr ""
+
+#: mediagoblin/auth/forms.py:52
msgid "Username or email"
msgstr "Nome utente o indirizzo email"
+#: mediagoblin/auth/tools.py:31
+msgid "Invalid User name or email address."
+msgstr ""
+
+#: mediagoblin/auth/tools.py:32
+msgid "This field does not take email addresses."
+msgstr ""
+
+#: mediagoblin/auth/tools.py:33
+msgid "This field requires an email address."
+msgstr ""
+
#: mediagoblin/auth/views.py:54
msgid "Sorry, registration is disabled on this instance."
msgstr "Spiacente, la registrazione è disabilitata su questa istanza."
@@ -62,54 +68,54 @@ msgstr "Spiacente, esiste già un utente con quel nome."
msgid "Sorry, a user with that email address already exists."
msgstr "Siamo spiacenti, un utente con quell'indirizzo email esiste già."
-#: mediagoblin/auth/views.py:174
+#: mediagoblin/auth/views.py:182
msgid ""
"Your email address has been verified. You may now login, edit your profile, "
"and submit images!"
msgstr "Il tuo indirizzo email è stato verificato. Ora puoi accedere, modificare il tuo profilo e caricare immagini!"
-#: mediagoblin/auth/views.py:180
+#: mediagoblin/auth/views.py:188
msgid "The verification key or user id is incorrect"
msgstr "La chiave di verifica o l'id utente è sbagliato"
-#: mediagoblin/auth/views.py:198
+#: mediagoblin/auth/views.py:206
msgid "You must be logged in so we know who to send the email to!"
msgstr "Devi effettuare l'accesso così possiamo sapere a chi inviare l'email!"
-#: mediagoblin/auth/views.py:206
+#: mediagoblin/auth/views.py:214
msgid "You've already verified your email address!"
msgstr "Hai già verificato il tuo indirizzo email!"
-#: mediagoblin/auth/views.py:219
+#: mediagoblin/auth/views.py:227
msgid "Resent your verification email."
msgstr "Rispedisci email di verifica"
-#: mediagoblin/auth/views.py:250
+#: mediagoblin/auth/views.py:258
msgid ""
"If that email address (case sensitive!) is registered an email has been sent"
" with instructions on how to change your password."
msgstr ""
-#: mediagoblin/auth/views.py:261
+#: mediagoblin/auth/views.py:269
msgid "Couldn't find someone with that username."
msgstr ""
-#: mediagoblin/auth/views.py:264
+#: mediagoblin/auth/views.py:272
msgid ""
"An email has been sent with instructions on how to change your password."
msgstr "Ti è stata inviata un'email con le istruzioni per cambiare la tua password."
-#: mediagoblin/auth/views.py:271
+#: mediagoblin/auth/views.py:279
msgid ""
"Could not send password recovery email as your username is inactive or your "
"account's email address has not been verified."
msgstr "Impossibile inviare l'email di recupero password perchè il tuo nome utente è inattivo o il tuo indirizzo email non è stato verificato."
-#: mediagoblin/auth/views.py:328
+#: mediagoblin/auth/views.py:336
msgid "You can now log in using your new password."
msgstr "Ora puoi effettuare l'accesso con la nuova password."
-#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:93
+#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:82
#: mediagoblin/submit/forms.py:28 mediagoblin/submit/forms.py:47
#: mediagoblin/user_pages/forms.py:45
msgid "Title"
@@ -120,7 +126,7 @@ msgid "Description of this work"
msgstr "Descrizione di questo lavoro"
#: mediagoblin/edit/forms.py:29 mediagoblin/edit/forms.py:52
-#: mediagoblin/edit/forms.py:97 mediagoblin/submit/forms.py:32
+#: mediagoblin/edit/forms.py:86 mediagoblin/submit/forms.py:32
#: mediagoblin/submit/forms.py:51 mediagoblin/user_pages/forms.py:49
msgid ""
"You can use\n"
@@ -136,11 +142,11 @@ msgstr "Tags"
msgid "Separate tags by commas."
msgstr "Separa le tags con la virgola."
-#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:101
+#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:90
msgid "Slug"
msgstr ""
-#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:102
+#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:91
msgid "The slug can't be empty"
msgstr ""
@@ -168,45 +174,45 @@ msgid "This address contains errors"
msgstr "Questo indirizzo contiene errori"
#: mediagoblin/edit/forms.py:63
-msgid "Old password"
-msgstr "Password vecchia"
-
-#: mediagoblin/edit/forms.py:64
-msgid "Enter your old password to prove you own this account."
-msgstr "Inserisci la vecchia password per dimostrare di essere il proprietario dell'account."
-
-#: mediagoblin/edit/forms.py:67
-msgid "New password"
-msgstr "Nuova password"
-
-#: mediagoblin/edit/forms.py:74
msgid "License preference"
msgstr ""
-#: mediagoblin/edit/forms.py:80
+#: mediagoblin/edit/forms.py:69
msgid "This will be your default license on upload forms."
msgstr ""
-#: mediagoblin/edit/forms.py:82
+#: mediagoblin/edit/forms.py:71
msgid "Email me when others comment on my media"
msgstr "Inviami messaggi email quando altre persone commentano i miei files multimediali"
-#: mediagoblin/edit/forms.py:94
+#: mediagoblin/edit/forms.py:83
msgid "The title can't be empty"
msgstr ""
-#: mediagoblin/edit/forms.py:96 mediagoblin/submit/forms.py:50
+#: mediagoblin/edit/forms.py:85 mediagoblin/submit/forms.py:50
#: mediagoblin/user_pages/forms.py:48
msgid "Description of this collection"
msgstr ""
-#: mediagoblin/edit/forms.py:103
+#: mediagoblin/edit/forms.py:92
msgid ""
"The title part of this collection's address. You usually don't need to "
"change this."
msgstr ""
-#: mediagoblin/edit/views.py:66
+#: mediagoblin/edit/forms.py:99
+msgid "Old password"
+msgstr "Password vecchia"
+
+#: mediagoblin/edit/forms.py:101
+msgid "Enter your old password to prove you own this account."
+msgstr "Inserisci la vecchia password per dimostrare di essere il proprietario dell'account."
+
+#: mediagoblin/edit/forms.py:104
+msgid "New password"
+msgstr "Nuova password"
+
+#: mediagoblin/edit/views.py:67
msgid "An entry with that slug already exists for this user."
msgstr ""
@@ -231,44 +237,63 @@ msgstr "Stai modificando il profilo di un utente. Procedi con attenzione."
msgid "Profile changes saved"
msgstr "Cambiamenti del profilo salvati"
-#: mediagoblin/edit/views.py:241
-msgid "Wrong password"
-msgstr "Password errata"
-
-#: mediagoblin/edit/views.py:252
+#: mediagoblin/edit/views.py:240
msgid "Account settings saved"
msgstr "Impostazioni del profilo salvate"
-#: mediagoblin/edit/views.py:286
+#: mediagoblin/edit/views.py:274
msgid "You need to confirm the deletion of your account."
msgstr ""
-#: mediagoblin/edit/views.py:322 mediagoblin/submit/views.py:142
-#: mediagoblin/user_pages/views.py:214
+#: mediagoblin/edit/views.py:310 mediagoblin/submit/views.py:138
+#: mediagoblin/user_pages/views.py:222
#, python-format
msgid "You already have a collection called \"%s\"!"
msgstr ""
-#: mediagoblin/edit/views.py:326
+#: mediagoblin/edit/views.py:314
msgid "A collection with that slug already exists for this user."
msgstr ""
-#: mediagoblin/edit/views.py:343
+#: mediagoblin/edit/views.py:329
msgid "You are editing another user's collection. Proceed with caution."
msgstr ""
-#: mediagoblin/gmg_commands/theme.py:58
+#: mediagoblin/edit/views.py:348
+msgid "Wrong password"
+msgstr "Password errata"
+
+#: mediagoblin/edit/views.py:363
+msgid "Your password was changed successfully"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:60
msgid "Cannot link theme... no theme set\n"
msgstr ""
-#: mediagoblin/gmg_commands/theme.py:71
+#: mediagoblin/gmg_commands/assetlink.py:73
msgid "No asset directory for this theme\n"
msgstr ""
-#: mediagoblin/gmg_commands/theme.py:74
+#: mediagoblin/gmg_commands/assetlink.py:76
msgid "However, old link directory symlink found; removed.\n"
msgstr ""
+#: mediagoblin/gmg_commands/assetlink.py:112
+#, python-format
+msgid "Could not link \"%s\": %s exists and is not a symlink\n"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:119
+#, python-format
+msgid "Skipping \"%s\"; already set up.\n"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:124
+#, python-format
+msgid "Old link found for \"%s\"; removing.\n"
+msgstr ""
+
#: mediagoblin/meddleware/csrf.py:134
msgid ""
"CSRF cookie not present. This is most likely the result of a cookie blocker "
@@ -276,12 +301,16 @@ msgid ""
"domain."
msgstr ""
-#: mediagoblin/media_types/__init__.py:61
-#: mediagoblin/media_types/__init__.py:102
+#: mediagoblin/media_types/__init__.py:111
+#: mediagoblin/media_types/__init__.py:155
msgid "Sorry, I don't support that file type :("
msgstr "Mi dispiace, non supporto questo tipo di file :("
-#: mediagoblin/media_types/video/processing.py:36
+#: mediagoblin/media_types/pdf/processing.py:136
+msgid "unoconv failing to run, check log file"
+msgstr ""
+
+#: mediagoblin/media_types/video/processing.py:37
msgid "Video transcoding failed"
msgstr "Transcodifica video fallita"
@@ -348,7 +377,7 @@ msgstr ""
msgid "This field is required for public clients"
msgstr ""
-#: mediagoblin/plugins/oauth/views.py:59
+#: mediagoblin/plugins/oauth/views.py:56
msgid "The client {0} has been registered!"
msgstr ""
@@ -367,7 +396,7 @@ msgstr ""
msgid "Add"
msgstr "Aggiungi"
-#: mediagoblin/processing/__init__.py:172
+#: mediagoblin/processing/__init__.py:193
msgid "Invalid file given for media type."
msgstr "File non valido per il tipo di file multimediale indicato."
@@ -375,45 +404,45 @@ msgstr "File non valido per il tipo di file multimediale indicato."
msgid "File"
msgstr "File"
-#: mediagoblin/submit/views.py:51
+#: mediagoblin/submit/views.py:49
msgid "You must provide a file."
msgstr "Devi specificare un file."
-#: mediagoblin/submit/views.py:97
+#: mediagoblin/submit/views.py:93
msgid "Woohoo! Submitted!"
msgstr "Evviva! Caricato!"
-#: mediagoblin/submit/views.py:146
+#: mediagoblin/submit/views.py:144
#, python-format
msgid "Collection \"%s\" added!"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:64
+#: mediagoblin/templates/mediagoblin/base.html:67
msgid "Verify your email!"
msgstr "Verifica la tua email!"
-#: mediagoblin/templates/mediagoblin/base.html:65
+#: mediagoblin/templates/mediagoblin/base.html:68
msgid "log out"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:70
+#: mediagoblin/templates/mediagoblin/base.html:73
#: mediagoblin/templates/mediagoblin/auth/login.html:28
#: mediagoblin/templates/mediagoblin/auth/login.html:36
#: mediagoblin/templates/mediagoblin/auth/login.html:54
msgid "Log in"
msgstr "Accedi"
-#: mediagoblin/templates/mediagoblin/base.html:79
+#: mediagoblin/templates/mediagoblin/base.html:82
#, python-format
msgid "<a href=\"%(user_url)s\">%(user_name)s</a>'s account"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:86
+#: mediagoblin/templates/mediagoblin/base.html:89
msgid "Change account settings"
msgstr "Cambia le impostazioni dell'account"
-#: mediagoblin/templates/mediagoblin/base.html:90
-#: mediagoblin/templates/mediagoblin/base.html:105
+#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:108
#: mediagoblin/templates/mediagoblin/admin/panel.html:21
#: mediagoblin/templates/mediagoblin/admin/panel.html:26
#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:21
@@ -421,72 +450,25 @@ msgstr "Cambia le impostazioni dell'account"
msgid "Media processing panel"
msgstr "Pannello di elaborazione files multimediali"
-#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:96
msgid "Log out"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:96
+#: mediagoblin/templates/mediagoblin/base.html:99
#: mediagoblin/templates/mediagoblin/user_pages/user.html:156
msgid "Add media"
msgstr "Aggiungi files multimediali"
-#: mediagoblin/templates/mediagoblin/base.html:99
+#: mediagoblin/templates/mediagoblin/base.html:102
#: mediagoblin/templates/mediagoblin/user_pages/collection_list.html:41
msgid "Create new collection"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:122
-#, python-format
-msgid ""
-"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
-"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/base.html:125
-#, python-format
-msgid ""
-"Released under the <a "
-"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
-"href=\"%(source_link)s\">Source code</a> available."
-msgstr "Rilasciato con licenza <a href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a href=\"%(source_link)s\">Codice sorgente</a> disponibile."
-
#: mediagoblin/templates/mediagoblin/error.html:24
msgid "Image of goblin stressing out"
msgstr ""
-#: mediagoblin/templates/mediagoblin/root.html:31
-msgid "Explore"
-msgstr "Esplora"
-
-#: mediagoblin/templates/mediagoblin/root.html:33
-msgid "Hi there, welcome to this MediaGoblin site!"
-msgstr "Ciao, benvenuto in questo sito MediaGoblin!"
-
-#: mediagoblin/templates/mediagoblin/root.html:35
-msgid ""
-"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
-"extraordinarily great piece of media hosting software."
-msgstr "Questo sito sta utilizzando <a href=\"http://mediagoblin.org\">Mediagoblin</a>, un ottimo programma per caricare e condividere files multimediali."
-
-#: mediagoblin/templates/mediagoblin/root.html:36
-msgid ""
-"To add your own media, place comments, and more, you can log in with your "
-"MediaGoblin account."
-msgstr "Per aggiungere i tuoi file multimediali, scrivere commenti e altro puoi accedere con il tuo account MediaGoblin."
-
-#: mediagoblin/templates/mediagoblin/root.html:38
-msgid "Don't have one yet? It's easy!"
-msgstr "Non ne hai già uno? E' semplice!"
-
-#: mediagoblin/templates/mediagoblin/root.html:39
-#, python-format
-msgid ""
-"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
-" or\n"
-" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
-msgstr "<a class=\"button_action_highlight\" href=\"%(register_url)s\">Crea un account in questo sito</a>\n oppure\n <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Installa MediaGoblin sul tuo server</a>"
-
-#: mediagoblin/templates/mediagoblin/root.html:47
+#: mediagoblin/templates/mediagoblin/root.html:32
msgid "Most recent media"
msgstr "Files multimediali più recenti"
@@ -592,6 +574,53 @@ msgid ""
"%(verification_url)s"
msgstr "Ciao %(username)s,\n\nper attivare il tuo account GNU MediaGoblin, apri il seguente URL nel \ntuo navigatore web.\n\n%(verification_url)s"
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:21
+#, python-format
+msgid ""
+"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
+"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:24
+#, python-format
+msgid ""
+"Released under the <a "
+"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
+"href=\"%(source_link)s\">Source code</a> available."
+msgstr "Rilasciato con licenza <a href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a href=\"%(source_link)s\">Codice sorgente</a> disponibile."
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:20
+msgid "Explore"
+msgstr "Esplora"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:22
+msgid "Hi there, welcome to this MediaGoblin site!"
+msgstr "Ciao, benvenuto in questo sito MediaGoblin!"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:24
+msgid ""
+"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
+"extraordinarily great piece of media hosting software."
+msgstr "Questo sito sta utilizzando <a href=\"http://mediagoblin.org\">Mediagoblin</a>, un ottimo programma per caricare e condividere files multimediali."
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:25
+msgid ""
+"To add your own media, place comments, and more, you can log in with your "
+"MediaGoblin account."
+msgstr "Per aggiungere i tuoi file multimediali, scrivere commenti e altro puoi accedere con il tuo account MediaGoblin."
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:27
+msgid "Don't have one yet? It's easy!"
+msgstr "Non ne hai già uno? E' semplice!"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:28
+#, python-format
+msgid ""
+"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
+" or\n"
+" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/bits/logo.html:23
#: mediagoblin/themes/airy/templates/mediagoblin/bits/logo.html:23
msgid "MediaGoblin logo"
@@ -604,13 +633,13 @@ msgid "Editing attachments for %(media_title)s"
msgstr "Stai modificando gli allegati di %(media_title)s"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:159
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:175
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:182
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:198
msgid "Attachments"
msgstr "Allegati"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:57
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:181
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:204
msgid "Add attachment"
msgstr "Aggiungi allegato"
@@ -627,12 +656,22 @@ msgstr "Annulla"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:63
#: mediagoblin/templates/mediagoblin/edit/edit.html:42
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:52
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:55
#: mediagoblin/templates/mediagoblin/edit/edit_collection.html:33
#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:40
msgid "Save changes"
msgstr "Salva i cambiamenti"
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:28
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:38
+#, python-format
+msgid "Changing %(username)s's password"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:45
+msgid "Save"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:28
#, python-format
msgid "Really delete user '%(user_name)s' and all related media/comments?"
@@ -643,7 +682,7 @@ msgid "Yes, really delete my account"
msgstr ""
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:47
+#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:48
#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:49
msgid "Delete permanently"
msgstr "Elimina definitivamente"
@@ -660,7 +699,11 @@ msgstr "Stai modificando %(media_title)s"
msgid "Changing %(username)s's account settings"
msgstr "Stai cambiando le impostazioni dell'account di %(username)s"
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:59
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:46
+msgid "Change your password."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:62
msgid "Delete my account"
msgstr ""
@@ -685,6 +728,7 @@ msgstr "File taggato con: %(tag_name)s"
#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:56
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:65
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:136
#: mediagoblin/templates/mediagoblin/media_displays/video.html:55
msgid "Download"
@@ -709,6 +753,7 @@ msgid ""
msgstr "Puoi scaricare un browser web moderno,\n\t in grado di leggere questo file audio, qui <a href=\"http://getfirefox.com\">\n\t http://getfirefox.com</a>!"
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:60
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:71
#: mediagoblin/templates/mediagoblin/media_displays/video.html:61
msgid "Original file"
msgstr "File originario"
@@ -717,6 +762,7 @@ msgstr "File originario"
msgid "WebM file (Vorbis codec)"
msgstr "File WebM (codec Vorbis)"
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:59
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:87
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:93
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:99
@@ -727,6 +773,10 @@ msgstr "File WebM (codec Vorbis)"
msgid "Image for %(media_title)s"
msgstr ""
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:79
+msgid "PDF file"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:112
msgid "Toggle Rotate"
msgstr ""
@@ -753,7 +803,7 @@ msgstr ""
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:130
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:131
msgid "WebGL"
-msgstr ""
+msgstr "WebGL"
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:138
msgid "Download model"
@@ -825,7 +875,7 @@ msgstr "Vuoi davvero eliminare %(title)s?"
msgid "Really remove %(media_title)s from %(collection_title)s?"
msgstr ""
-#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:53
+#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:54
msgid "Remove"
msgstr ""
@@ -868,24 +918,28 @@ msgstr "Files multimediali di <a href=\"%(user_url)s\">%(username)s</a>"
msgid "â– Browsing media by <a href=\"%(user_url)s\">%(username)s</a>"
msgstr "â– Stai guardando i files multimediali di <a href=\"%(user_url)s\">%(username)s</a>"
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:94
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:95
msgid "Add a comment"
msgstr "Aggiungi un commento"
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:102
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:104
msgid "Add this comment"
msgstr "Aggiungi questo commento"
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:123
-msgid "at"
-msgstr "a"
-
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:144
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:132
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:152
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:164
#, python-format
-msgid ""
-"<h3>Added on</h3>\n"
-" <p>%(date)s</p>"
-msgstr "<h3>Aggiunto il</h3>\n <p>%(date)s</p>"
+msgid "%(formatted_time)s ago"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:150
+msgid "Added"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:161
+msgid "Created"
+msgstr ""
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:28
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:40
@@ -1041,7 +1095,7 @@ msgstr "più vecchio"
msgid "Tagged with"
msgstr "Taggato con"
-#: mediagoblin/tools/exif.py:80
+#: mediagoblin/tools/exif.py:83
msgid "Could not read the image file."
msgstr "Impossibile leggere il file immagine."
@@ -1071,6 +1125,30 @@ msgid ""
" deleted."
msgstr ""
+#: mediagoblin/tools/timesince.py:62
+msgid "year"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:63
+msgid "month"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:64
+msgid "week"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:65
+msgid "day"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:66
+msgid "hour"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:67
+msgid "minute"
+msgstr ""
+
#: mediagoblin/user_pages/forms.py:23
msgid "Comment"
msgstr ""
@@ -1102,73 +1180,77 @@ msgstr ""
msgid "Include a note"
msgstr ""
-#: mediagoblin/user_pages/lib.py:56
+#: mediagoblin/user_pages/lib.py:58
msgid "commented on your post"
msgstr "ha commentato il tuo post"
-#: mediagoblin/user_pages/views.py:166
+#: mediagoblin/user_pages/views.py:169
+msgid "Sorry, comments are disabled."
+msgstr ""
+
+#: mediagoblin/user_pages/views.py:174
msgid "Oops, your comment was empty."
msgstr "Oops, il tuo commento era vuoto."
-#: mediagoblin/user_pages/views.py:172
+#: mediagoblin/user_pages/views.py:180
msgid "Your comment has been posted!"
msgstr "Il tuo commento è stato aggiunto!"
-#: mediagoblin/user_pages/views.py:197
+#: mediagoblin/user_pages/views.py:205
msgid "Please check your entries and try again."
msgstr ""
-#: mediagoblin/user_pages/views.py:237
+#: mediagoblin/user_pages/views.py:245
msgid "You have to select or add a collection"
msgstr ""
-#: mediagoblin/user_pages/views.py:248
+#: mediagoblin/user_pages/views.py:256
#, python-format
msgid "\"%s\" already in collection \"%s\""
msgstr ""
-#: mediagoblin/user_pages/views.py:264
+#: mediagoblin/user_pages/views.py:262
#, python-format
msgid "\"%s\" added to collection \"%s\""
msgstr ""
-#: mediagoblin/user_pages/views.py:286
+#: mediagoblin/user_pages/views.py:282
msgid "You deleted the media."
msgstr "Hai eliminato il file."
-#: mediagoblin/user_pages/views.py:293
+#: mediagoblin/user_pages/views.py:289
msgid "The media was not deleted because you didn't check that you were sure."
msgstr "Il file non è stato eliminato perchè non hai confermato di essere sicuro."
-#: mediagoblin/user_pages/views.py:301
+#: mediagoblin/user_pages/views.py:296
msgid "You are about to delete another user's media. Proceed with caution."
msgstr "Stai eliminando un file multimediale di un altro utente. Procedi con attenzione."
-#: mediagoblin/user_pages/views.py:375
+#: mediagoblin/user_pages/views.py:370
msgid "You deleted the item from the collection."
msgstr ""
-#: mediagoblin/user_pages/views.py:379
+#: mediagoblin/user_pages/views.py:374
msgid "The item was not removed because you didn't check that you were sure."
msgstr ""
-#: mediagoblin/user_pages/views.py:389
+#: mediagoblin/user_pages/views.py:382
msgid ""
"You are about to delete an item from another user's collection. Proceed with"
" caution."
msgstr ""
-#: mediagoblin/user_pages/views.py:422
+#: mediagoblin/user_pages/views.py:415
#, python-format
msgid "You deleted the collection \"%s\""
msgstr ""
-#: mediagoblin/user_pages/views.py:429
+#: mediagoblin/user_pages/views.py:422
msgid ""
"The collection was not deleted because you didn't check that you were sure."
msgstr ""
-#: mediagoblin/user_pages/views.py:439
+#: mediagoblin/user_pages/views.py:430
msgid ""
"You are about to delete another user's collection. Proceed with caution."
msgstr ""
diff --git a/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.mo
index 1344c9bd..3c82d1ff 100644
--- a/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.mo
+++ b/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.mo
Binary files differ
diff --git a/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po
index 008a6d27..97d68127 100644
--- a/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po
+++ b/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po
@@ -3,16 +3,16 @@
# This file is distributed under the same license as the PROJECT project.
#
# Translators:
-# <averym@gmail.com>, 2011.
-# <parlegon@gmail.com>, 2013.
+# Avery <averym@gmail.com>, 2011
+# parlegon <parlegon@gmail.com>, 2013
msgid ""
msgstr ""
"Project-Id-Version: GNU MediaGoblin\n"
"Report-Msgid-Bugs-To: http://issues.mediagoblin.org/\n"
-"POT-Creation-Date: 2013-03-04 18:04-0600\n"
-"PO-Revision-Date: 2013-03-05 00:04+0000\n"
+"POT-Creation-Date: 2013-05-27 13:54-0500\n"
+"PO-Revision-Date: 2013-05-27 18:54+0000\n"
"Last-Translator: cwebber <cwebber@dustycloud.org>\n"
-"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language-Team: Japanese (http://www.transifex.com/projects/p/mediagoblin/language/ja/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
@@ -20,34 +20,39 @@ msgstr ""
"Language: ja\n"
"Plural-Forms: nplurals=1; plural=0;\n"
-#: mediagoblin/auth/forms.py:28
-msgid "Invalid User name or email address."
-msgstr ""
-
-#: mediagoblin/auth/forms.py:29
-msgid "This field does not take email addresses."
-msgstr ""
-
-#: mediagoblin/auth/forms.py:30
-msgid "This field requires an email address."
-msgstr ""
-
-#: mediagoblin/auth/forms.py:52 mediagoblin/auth/forms.py:67
+#: mediagoblin/auth/forms.py:26
msgid "Username"
msgstr "ユーザãƒãƒ¼ãƒ "
-#: mediagoblin/auth/forms.py:56 mediagoblin/auth/forms.py:71
+#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:45
+#: mediagoblin/tests/test_util.py:110
msgid "Password"
msgstr "パスワード"
-#: mediagoblin/auth/forms.py:60
+#: mediagoblin/auth/forms.py:34
msgid "Email address"
msgstr "メールアドレス"
-#: mediagoblin/auth/forms.py:78
+#: mediagoblin/auth/forms.py:41
+msgid "Username or Email"
+msgstr ""
+
+#: mediagoblin/auth/forms.py:52
msgid "Username or email"
msgstr ""
+#: mediagoblin/auth/tools.py:31
+msgid "Invalid User name or email address."
+msgstr ""
+
+#: mediagoblin/auth/tools.py:32
+msgid "This field does not take email addresses."
+msgstr ""
+
+#: mediagoblin/auth/tools.py:33
+msgid "This field requires an email address."
+msgstr ""
+
#: mediagoblin/auth/views.py:54
msgid "Sorry, registration is disabled on this instance."
msgstr "申ã—訳ã‚りã¾ã›ã‚“ãŒã€ã“ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ã§ç™»éŒ²ã¯ç„¡åйã«ãªã£ã¦ã„ã¾ã™ã€‚"
@@ -60,54 +65,54 @@ msgstr "申ã—訳ã‚りã¾ã›ã‚“ãŒã€ãã®åå‰ã‚’æŒã¤ãƒ¦ãƒ¼ã‚¶ãƒ¼ãŒã™ã§
msgid "Sorry, a user with that email address already exists."
msgstr ""
-#: mediagoblin/auth/views.py:174
+#: mediagoblin/auth/views.py:182
msgid ""
"Your email address has been verified. You may now login, edit your profile, "
"and submit images!"
msgstr "メアドãŒç¢ºèªã•れã¦ã„ã¾ã™ã€‚ã“れã§ã€ãƒ­ã‚°ã‚¤ãƒ³ã—ã¦ãƒ—ロファイルを編集ã—ã€ç”»åƒã‚’æå‡ºã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ï¼"
-#: mediagoblin/auth/views.py:180
+#: mediagoblin/auth/views.py:188
msgid "The verification key or user id is incorrect"
msgstr "検証キーã¾ãŸã¯ãƒ¦ãƒ¼ã‚¶ãƒ¼IDãŒé–“é•ã£ã¦ã„ã¾ã™"
-#: mediagoblin/auth/views.py:198
+#: mediagoblin/auth/views.py:206
msgid "You must be logged in so we know who to send the email to!"
msgstr ""
-#: mediagoblin/auth/views.py:206
+#: mediagoblin/auth/views.py:214
msgid "You've already verified your email address!"
msgstr ""
-#: mediagoblin/auth/views.py:219
+#: mediagoblin/auth/views.py:227
msgid "Resent your verification email."
msgstr "検証メールをå†é€ã—ã¾ã—ãŸã€‚"
-#: mediagoblin/auth/views.py:250
+#: mediagoblin/auth/views.py:258
msgid ""
"If that email address (case sensitive!) is registered an email has been sent"
" with instructions on how to change your password."
msgstr ""
-#: mediagoblin/auth/views.py:261
+#: mediagoblin/auth/views.py:269
msgid "Couldn't find someone with that username."
msgstr ""
-#: mediagoblin/auth/views.py:264
+#: mediagoblin/auth/views.py:272
msgid ""
"An email has been sent with instructions on how to change your password."
msgstr ""
-#: mediagoblin/auth/views.py:271
+#: mediagoblin/auth/views.py:279
msgid ""
"Could not send password recovery email as your username is inactive or your "
"account's email address has not been verified."
msgstr ""
-#: mediagoblin/auth/views.py:328
+#: mediagoblin/auth/views.py:336
msgid "You can now log in using your new password."
msgstr ""
-#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:93
+#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:82
#: mediagoblin/submit/forms.py:28 mediagoblin/submit/forms.py:47
#: mediagoblin/user_pages/forms.py:45
msgid "Title"
@@ -118,7 +123,7 @@ msgid "Description of this work"
msgstr ""
#: mediagoblin/edit/forms.py:29 mediagoblin/edit/forms.py:52
-#: mediagoblin/edit/forms.py:97 mediagoblin/submit/forms.py:32
+#: mediagoblin/edit/forms.py:86 mediagoblin/submit/forms.py:32
#: mediagoblin/submit/forms.py:51 mediagoblin/user_pages/forms.py:49
msgid ""
"You can use\n"
@@ -134,11 +139,11 @@ msgstr "ã‚¿ã‚°"
msgid "Separate tags by commas."
msgstr ""
-#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:101
+#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:90
msgid "Slug"
msgstr "スラグ"
-#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:102
+#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:91
msgid "The slug can't be empty"
msgstr "スラグã¯å¿…è¦ã§ã™ã€‚"
@@ -166,45 +171,45 @@ msgid "This address contains errors"
msgstr ""
#: mediagoblin/edit/forms.py:63
-msgid "Old password"
-msgstr ""
-
-#: mediagoblin/edit/forms.py:64
-msgid "Enter your old password to prove you own this account."
-msgstr ""
-
-#: mediagoblin/edit/forms.py:67
-msgid "New password"
-msgstr ""
-
-#: mediagoblin/edit/forms.py:74
msgid "License preference"
msgstr ""
-#: mediagoblin/edit/forms.py:80
+#: mediagoblin/edit/forms.py:69
msgid "This will be your default license on upload forms."
msgstr ""
-#: mediagoblin/edit/forms.py:82
+#: mediagoblin/edit/forms.py:71
msgid "Email me when others comment on my media"
msgstr ""
-#: mediagoblin/edit/forms.py:94
+#: mediagoblin/edit/forms.py:83
msgid "The title can't be empty"
msgstr ""
-#: mediagoblin/edit/forms.py:96 mediagoblin/submit/forms.py:50
+#: mediagoblin/edit/forms.py:85 mediagoblin/submit/forms.py:50
#: mediagoblin/user_pages/forms.py:48
msgid "Description of this collection"
msgstr ""
-#: mediagoblin/edit/forms.py:103
+#: mediagoblin/edit/forms.py:92
msgid ""
"The title part of this collection's address. You usually don't need to "
"change this."
msgstr ""
-#: mediagoblin/edit/views.py:66
+#: mediagoblin/edit/forms.py:99
+msgid "Old password"
+msgstr ""
+
+#: mediagoblin/edit/forms.py:101
+msgid "Enter your old password to prove you own this account."
+msgstr ""
+
+#: mediagoblin/edit/forms.py:104
+msgid "New password"
+msgstr ""
+
+#: mediagoblin/edit/views.py:67
msgid "An entry with that slug already exists for this user."
msgstr "ãã®ã‚¹ãƒ©ã‚°ã‚’æŒã¤ã‚¨ãƒ³ãƒˆãƒªã¯ã€ã“ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã¯æ—¢ã«å­˜åœ¨ã—ã¾ã™ã€‚"
@@ -229,44 +234,63 @@ msgstr "ã‚ãªãŸã¯ã€ä»–ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã®ãƒ—ロファイルを編集ã—ã¦ã„
msgid "Profile changes saved"
msgstr ""
-#: mediagoblin/edit/views.py:241
-msgid "Wrong password"
-msgstr ""
-
-#: mediagoblin/edit/views.py:252
+#: mediagoblin/edit/views.py:240
msgid "Account settings saved"
msgstr ""
-#: mediagoblin/edit/views.py:286
+#: mediagoblin/edit/views.py:274
msgid "You need to confirm the deletion of your account."
msgstr ""
-#: mediagoblin/edit/views.py:322 mediagoblin/submit/views.py:142
-#: mediagoblin/user_pages/views.py:214
+#: mediagoblin/edit/views.py:310 mediagoblin/submit/views.py:138
+#: mediagoblin/user_pages/views.py:222
#, python-format
msgid "You already have a collection called \"%s\"!"
msgstr ""
-#: mediagoblin/edit/views.py:326
+#: mediagoblin/edit/views.py:314
msgid "A collection with that slug already exists for this user."
msgstr ""
-#: mediagoblin/edit/views.py:343
+#: mediagoblin/edit/views.py:329
msgid "You are editing another user's collection. Proceed with caution."
msgstr ""
-#: mediagoblin/gmg_commands/theme.py:58
+#: mediagoblin/edit/views.py:348
+msgid "Wrong password"
+msgstr ""
+
+#: mediagoblin/edit/views.py:363
+msgid "Your password was changed successfully"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:60
msgid "Cannot link theme... no theme set\n"
msgstr ""
-#: mediagoblin/gmg_commands/theme.py:71
+#: mediagoblin/gmg_commands/assetlink.py:73
msgid "No asset directory for this theme\n"
msgstr ""
-#: mediagoblin/gmg_commands/theme.py:74
+#: mediagoblin/gmg_commands/assetlink.py:76
msgid "However, old link directory symlink found; removed.\n"
msgstr ""
+#: mediagoblin/gmg_commands/assetlink.py:112
+#, python-format
+msgid "Could not link \"%s\": %s exists and is not a symlink\n"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:119
+#, python-format
+msgid "Skipping \"%s\"; already set up.\n"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:124
+#, python-format
+msgid "Old link found for \"%s\"; removing.\n"
+msgstr ""
+
#: mediagoblin/meddleware/csrf.py:134
msgid ""
"CSRF cookie not present. This is most likely the result of a cookie blocker "
@@ -274,12 +298,16 @@ msgid ""
"domain."
msgstr ""
-#: mediagoblin/media_types/__init__.py:61
-#: mediagoblin/media_types/__init__.py:102
+#: mediagoblin/media_types/__init__.py:111
+#: mediagoblin/media_types/__init__.py:155
msgid "Sorry, I don't support that file type :("
msgstr ""
-#: mediagoblin/media_types/video/processing.py:36
+#: mediagoblin/media_types/pdf/processing.py:136
+msgid "unoconv failing to run, check log file"
+msgstr ""
+
+#: mediagoblin/media_types/video/processing.py:37
msgid "Video transcoding failed"
msgstr ""
@@ -346,7 +374,7 @@ msgstr ""
msgid "This field is required for public clients"
msgstr ""
-#: mediagoblin/plugins/oauth/views.py:59
+#: mediagoblin/plugins/oauth/views.py:56
msgid "The client {0} has been registered!"
msgstr ""
@@ -365,7 +393,7 @@ msgstr ""
msgid "Add"
msgstr "追加"
-#: mediagoblin/processing/__init__.py:172
+#: mediagoblin/processing/__init__.py:193
msgid "Invalid file given for media type."
msgstr ""
@@ -373,45 +401,45 @@ msgstr ""
msgid "File"
msgstr "ファイル"
-#: mediagoblin/submit/views.py:51
+#: mediagoblin/submit/views.py:49
msgid "You must provide a file."
msgstr "ファイルをæä¾›ã™ã‚‹å¿…è¦ãŒã‚りã¾ã™ã€‚"
-#: mediagoblin/submit/views.py:97
+#: mediagoblin/submit/views.py:93
msgid "Woohoo! Submitted!"
msgstr "投稿終了ï¼"
-#: mediagoblin/submit/views.py:146
+#: mediagoblin/submit/views.py:144
#, python-format
msgid "Collection \"%s\" added!"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:64
+#: mediagoblin/templates/mediagoblin/base.html:67
msgid "Verify your email!"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:65
+#: mediagoblin/templates/mediagoblin/base.html:68
msgid "log out"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:70
+#: mediagoblin/templates/mediagoblin/base.html:73
#: mediagoblin/templates/mediagoblin/auth/login.html:28
#: mediagoblin/templates/mediagoblin/auth/login.html:36
#: mediagoblin/templates/mediagoblin/auth/login.html:54
msgid "Log in"
msgstr "ログイン"
-#: mediagoblin/templates/mediagoblin/base.html:79
+#: mediagoblin/templates/mediagoblin/base.html:82
#, python-format
msgid "<a href=\"%(user_url)s\">%(user_name)s</a>'s account"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:86
+#: mediagoblin/templates/mediagoblin/base.html:89
msgid "Change account settings"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:90
-#: mediagoblin/templates/mediagoblin/base.html:105
+#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:108
#: mediagoblin/templates/mediagoblin/admin/panel.html:21
#: mediagoblin/templates/mediagoblin/admin/panel.html:26
#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:21
@@ -419,72 +447,25 @@ msgstr ""
msgid "Media processing panel"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:96
msgid "Log out"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:96
+#: mediagoblin/templates/mediagoblin/base.html:99
#: mediagoblin/templates/mediagoblin/user_pages/user.html:156
msgid "Add media"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:99
+#: mediagoblin/templates/mediagoblin/base.html:102
#: mediagoblin/templates/mediagoblin/user_pages/collection_list.html:41
msgid "Create new collection"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:122
-#, python-format
-msgid ""
-"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
-"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/base.html:125
-#, python-format
-msgid ""
-"Released under the <a "
-"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
-"href=\"%(source_link)s\">Source code</a> available."
-msgstr ""
-
#: mediagoblin/templates/mediagoblin/error.html:24
msgid "Image of goblin stressing out"
msgstr ""
-#: mediagoblin/templates/mediagoblin/root.html:31
-msgid "Explore"
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:33
-msgid "Hi there, welcome to this MediaGoblin site!"
-msgstr "ã“ã‚“ã«ã¡ã¯ã€ã“ã®MediaGoblinサイトã¸ã‚ˆã†ã“ãï¼"
-
-#: mediagoblin/templates/mediagoblin/root.html:35
-msgid ""
-"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
-"extraordinarily great piece of media hosting software."
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:36
-msgid ""
-"To add your own media, place comments, and more, you can log in with your "
-"MediaGoblin account."
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:38
-msgid "Don't have one yet? It's easy!"
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:39
-#, python-format
-msgid ""
-"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
-" or\n"
-" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:47
+#: mediagoblin/templates/mediagoblin/root.html:32
msgid "Most recent media"
msgstr ""
@@ -590,6 +571,53 @@ msgid ""
"%(verification_url)s"
msgstr "%(username)s様ã¸\n\nGNU MediaGoblinアカウントを検証ã«ã™ã‚‹ã«ã¯ã€ã“ã®URLã‚’é–‹ã„ã¦ãã ã•ã„。\n\n%(verification_url)s"
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:21
+#, python-format
+msgid ""
+"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
+"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:24
+#, python-format
+msgid ""
+"Released under the <a "
+"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
+"href=\"%(source_link)s\">Source code</a> available."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:20
+msgid "Explore"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:22
+msgid "Hi there, welcome to this MediaGoblin site!"
+msgstr "ã“ã‚“ã«ã¡ã¯ã€ã“ã®MediaGoblinサイトã¸ã‚ˆã†ã“ãï¼"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:24
+msgid ""
+"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
+"extraordinarily great piece of media hosting software."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:25
+msgid ""
+"To add your own media, place comments, and more, you can log in with your "
+"MediaGoblin account."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:27
+msgid "Don't have one yet? It's easy!"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:28
+#, python-format
+msgid ""
+"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
+" or\n"
+" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/bits/logo.html:23
#: mediagoblin/themes/airy/templates/mediagoblin/bits/logo.html:23
msgid "MediaGoblin logo"
@@ -602,13 +630,13 @@ msgid "Editing attachments for %(media_title)s"
msgstr ""
#: mediagoblin/templates/mediagoblin/edit/attachments.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:159
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:175
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:182
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:198
msgid "Attachments"
msgstr ""
#: mediagoblin/templates/mediagoblin/edit/attachments.html:57
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:181
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:204
msgid "Add attachment"
msgstr ""
@@ -625,12 +653,22 @@ msgstr "キャンセル"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:63
#: mediagoblin/templates/mediagoblin/edit/edit.html:42
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:52
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:55
#: mediagoblin/templates/mediagoblin/edit/edit_collection.html:33
#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:40
msgid "Save changes"
msgstr "投稿ã™ã‚‹"
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:28
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:38
+#, python-format
+msgid "Changing %(username)s's password"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:45
+msgid "Save"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:28
#, python-format
msgid "Really delete user '%(user_name)s' and all related media/comments?"
@@ -641,7 +679,7 @@ msgid "Yes, really delete my account"
msgstr ""
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:47
+#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:48
#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:49
msgid "Delete permanently"
msgstr ""
@@ -658,7 +696,11 @@ msgstr "%(media_title)sを編集中"
msgid "Changing %(username)s's account settings"
msgstr ""
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:59
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:46
+msgid "Change your password."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:62
msgid "Delete my account"
msgstr ""
@@ -683,6 +725,7 @@ msgstr ""
#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:56
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:65
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:136
#: mediagoblin/templates/mediagoblin/media_displays/video.html:55
msgid "Download"
@@ -707,6 +750,7 @@ msgid ""
msgstr ""
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:60
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:71
#: mediagoblin/templates/mediagoblin/media_displays/video.html:61
msgid "Original file"
msgstr ""
@@ -715,6 +759,7 @@ msgstr ""
msgid "WebM file (Vorbis codec)"
msgstr ""
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:59
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:87
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:93
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:99
@@ -725,6 +770,10 @@ msgstr ""
msgid "Image for %(media_title)s"
msgstr ""
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:79
+msgid "PDF file"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:112
msgid "Toggle Rotate"
msgstr ""
@@ -823,7 +872,7 @@ msgstr ""
msgid "Really remove %(media_title)s from %(collection_title)s?"
msgstr ""
-#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:53
+#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:54
msgid "Remove"
msgstr ""
@@ -866,23 +915,27 @@ msgstr "<a href=\"%(user_url)s\">%(username)s</a>ã•ã‚“ã®ã‚³ãƒ³ãƒ†ãƒ³ãƒ„"
msgid "â– Browsing media by <a href=\"%(user_url)s\">%(username)s</a>"
msgstr ""
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:94
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:95
msgid "Add a comment"
msgstr ""
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:102
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:104
msgid "Add this comment"
msgstr ""
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:123
-msgid "at"
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:132
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:152
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:164
+#, python-format
+msgid "%(formatted_time)s ago"
msgstr ""
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:144
-#, python-format
-msgid ""
-"<h3>Added on</h3>\n"
-" <p>%(date)s</p>"
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:150
+msgid "Added"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:161
+msgid "Created"
msgstr ""
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:28
@@ -1039,7 +1092,7 @@ msgstr ""
msgid "Tagged with"
msgstr ""
-#: mediagoblin/tools/exif.py:80
+#: mediagoblin/tools/exif.py:83
msgid "Could not read the image file."
msgstr ""
@@ -1069,6 +1122,30 @@ msgid ""
" deleted."
msgstr ""
+#: mediagoblin/tools/timesince.py:62
+msgid "year"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:63
+msgid "month"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:64
+msgid "week"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:65
+msgid "day"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:66
+msgid "hour"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:67
+msgid "minute"
+msgstr ""
+
#: mediagoblin/user_pages/forms.py:23
msgid "Comment"
msgstr ""
@@ -1100,73 +1177,77 @@ msgstr ""
msgid "Include a note"
msgstr ""
-#: mediagoblin/user_pages/lib.py:56
+#: mediagoblin/user_pages/lib.py:58
msgid "commented on your post"
msgstr ""
-#: mediagoblin/user_pages/views.py:166
+#: mediagoblin/user_pages/views.py:169
+msgid "Sorry, comments are disabled."
+msgstr ""
+
+#: mediagoblin/user_pages/views.py:174
msgid "Oops, your comment was empty."
msgstr ""
-#: mediagoblin/user_pages/views.py:172
+#: mediagoblin/user_pages/views.py:180
msgid "Your comment has been posted!"
msgstr ""
-#: mediagoblin/user_pages/views.py:197
+#: mediagoblin/user_pages/views.py:205
msgid "Please check your entries and try again."
msgstr ""
-#: mediagoblin/user_pages/views.py:237
+#: mediagoblin/user_pages/views.py:245
msgid "You have to select or add a collection"
msgstr ""
-#: mediagoblin/user_pages/views.py:248
+#: mediagoblin/user_pages/views.py:256
#, python-format
msgid "\"%s\" already in collection \"%s\""
msgstr ""
-#: mediagoblin/user_pages/views.py:264
+#: mediagoblin/user_pages/views.py:262
#, python-format
msgid "\"%s\" added to collection \"%s\""
msgstr ""
-#: mediagoblin/user_pages/views.py:286
+#: mediagoblin/user_pages/views.py:282
msgid "You deleted the media."
msgstr ""
-#: mediagoblin/user_pages/views.py:293
+#: mediagoblin/user_pages/views.py:289
msgid "The media was not deleted because you didn't check that you were sure."
msgstr ""
-#: mediagoblin/user_pages/views.py:301
+#: mediagoblin/user_pages/views.py:296
msgid "You are about to delete another user's media. Proceed with caution."
msgstr ""
-#: mediagoblin/user_pages/views.py:375
+#: mediagoblin/user_pages/views.py:370
msgid "You deleted the item from the collection."
msgstr ""
-#: mediagoblin/user_pages/views.py:379
+#: mediagoblin/user_pages/views.py:374
msgid "The item was not removed because you didn't check that you were sure."
msgstr ""
-#: mediagoblin/user_pages/views.py:389
+#: mediagoblin/user_pages/views.py:382
msgid ""
"You are about to delete an item from another user's collection. Proceed with"
" caution."
msgstr ""
-#: mediagoblin/user_pages/views.py:422
+#: mediagoblin/user_pages/views.py:415
#, python-format
msgid "You deleted the collection \"%s\""
msgstr ""
-#: mediagoblin/user_pages/views.py:429
+#: mediagoblin/user_pages/views.py:422
msgid ""
"The collection was not deleted because you didn't check that you were sure."
msgstr ""
-#: mediagoblin/user_pages/views.py:439
+#: mediagoblin/user_pages/views.py:430
msgid ""
"You are about to delete another user's collection. Proceed with caution."
msgstr ""
diff --git a/mediagoblin/i18n/ko_KR/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ko_KR/LC_MESSAGES/mediagoblin.mo
index 69bf72bc..7d37ab7c 100644
--- a/mediagoblin/i18n/ko_KR/LC_MESSAGES/mediagoblin.mo
+++ b/mediagoblin/i18n/ko_KR/LC_MESSAGES/mediagoblin.mo
Binary files differ
diff --git a/mediagoblin/i18n/ko_KR/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ko_KR/LC_MESSAGES/mediagoblin.po
index ac87c90f..5333de02 100644
--- a/mediagoblin/i18n/ko_KR/LC_MESSAGES/mediagoblin.po
+++ b/mediagoblin/i18n/ko_KR/LC_MESSAGES/mediagoblin.po
@@ -3,15 +3,15 @@
# This file is distributed under the same license as the PROJECT project.
#
# Translators:
-# <newvgund@gmail.com>, 2012.
+# Jin-hoon Kim <newvgund@gmail.com>, 2012
msgid ""
msgstr ""
"Project-Id-Version: GNU MediaGoblin\n"
"Report-Msgid-Bugs-To: http://issues.mediagoblin.org/\n"
-"POT-Creation-Date: 2013-03-04 18:04-0600\n"
-"PO-Revision-Date: 2013-03-05 00:04+0000\n"
+"POT-Creation-Date: 2013-05-27 13:54-0500\n"
+"PO-Revision-Date: 2013-05-27 18:54+0000\n"
"Last-Translator: cwebber <cwebber@dustycloud.org>\n"
-"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language-Team: Korean (Korea) (http://www.transifex.com/projects/p/mediagoblin/language/ko_KR/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
@@ -19,34 +19,39 @@ msgstr ""
"Language: ko_KR\n"
"Plural-Forms: nplurals=1; plural=0;\n"
-#: mediagoblin/auth/forms.py:28
-msgid "Invalid User name or email address."
-msgstr ""
-
-#: mediagoblin/auth/forms.py:29
-msgid "This field does not take email addresses."
-msgstr ""
-
-#: mediagoblin/auth/forms.py:30
-msgid "This field requires an email address."
-msgstr ""
-
-#: mediagoblin/auth/forms.py:52 mediagoblin/auth/forms.py:67
+#: mediagoblin/auth/forms.py:26
msgid "Username"
msgstr "ì‚¬ìš©ìž ì´ë¦„"
-#: mediagoblin/auth/forms.py:56 mediagoblin/auth/forms.py:71
+#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:45
+#: mediagoblin/tests/test_util.py:110
msgid "Password"
msgstr "비밀번호"
-#: mediagoblin/auth/forms.py:60
+#: mediagoblin/auth/forms.py:34
msgid "Email address"
msgstr "email 주소"
-#: mediagoblin/auth/forms.py:78
+#: mediagoblin/auth/forms.py:41
+msgid "Username or Email"
+msgstr ""
+
+#: mediagoblin/auth/forms.py:52
msgid "Username or email"
msgstr "ì‚¬ìš©ìž ì´ë¦„ ë˜ëŠ” email"
+#: mediagoblin/auth/tools.py:31
+msgid "Invalid User name or email address."
+msgstr ""
+
+#: mediagoblin/auth/tools.py:32
+msgid "This field does not take email addresses."
+msgstr ""
+
+#: mediagoblin/auth/tools.py:33
+msgid "This field requires an email address."
+msgstr ""
+
#: mediagoblin/auth/views.py:54
msgid "Sorry, registration is disabled on this instance."
msgstr "죄송합니다. ì§€ê¸ˆì€ ê°€ìž… 하실 수 없습니다."
@@ -59,54 +64,54 @@ msgstr "죄송합니다. 해당 ì‚¬ìš©ìž ì´ë¦„ì´ ì´ë¯¸ 존재 합니다."
msgid "Sorry, a user with that email address already exists."
msgstr "죄송합니다. 사용ìžì™€ 해당 ì´ë©”ì¼ì€ ì´ë¯¸ 등ë¡ë˜ì–´ 있습니다."
-#: mediagoblin/auth/views.py:174
+#: mediagoblin/auth/views.py:182
msgid ""
"Your email address has been verified. You may now login, edit your profile, "
"and submit images!"
msgstr "해당 email 주소가 ì´ë¯¸ ì¸ì¦ ë˜ì–´ 있습니다. 지금 로그ì¸í•˜ì‹œê³  계정 정보를 수정하고 ì‚¬ì§„ì„ ì „ì†¡í•´ 보세요!"
-#: mediagoblin/auth/views.py:180
+#: mediagoblin/auth/views.py:188
msgid "The verification key or user id is incorrect"
msgstr "ì¸ì¦ 키 ë˜ëŠ” ì‚¬ìš©ìž IDê°€ 올바르지 않습니다."
-#: mediagoblin/auth/views.py:198
+#: mediagoblin/auth/views.py:206
msgid "You must be logged in so we know who to send the email to!"
msgstr "로그ì¸ì„ 하셔야 고블린ì—서 ë©”ì¼ì„ 보낼 수 있습니다!"
-#: mediagoblin/auth/views.py:206
+#: mediagoblin/auth/views.py:214
msgid "You've already verified your email address!"
msgstr "ì´ë¯¸ ì¸ì¦ë°›ì€ email 주소를 가지고 있습니다!"
-#: mediagoblin/auth/views.py:219
+#: mediagoblin/auth/views.py:227
msgid "Resent your verification email."
msgstr "ì¸ì¦ ë©”ì¼ì„ 다시 ë³´ë‚´ 주세요."
-#: mediagoblin/auth/views.py:250
+#: mediagoblin/auth/views.py:258
msgid ""
"If that email address (case sensitive!) is registered an email has been sent"
" with instructions on how to change your password."
msgstr ""
-#: mediagoblin/auth/views.py:261
+#: mediagoblin/auth/views.py:269
msgid "Couldn't find someone with that username."
msgstr ""
-#: mediagoblin/auth/views.py:264
+#: mediagoblin/auth/views.py:272
msgid ""
"An email has been sent with instructions on how to change your password."
msgstr "비밀번호를 변경하는 ë°©ë²•ì— ëŒ€í•œ 설명서가 ë©”ì¼ë¡œ 전송 ë˜ì—ˆìŠµë‹ˆë‹¤."
-#: mediagoblin/auth/views.py:271
+#: mediagoblin/auth/views.py:279
msgid ""
"Could not send password recovery email as your username is inactive or your "
"account's email address has not been verified."
msgstr "사용ìžì˜ ì´ë¦„ì´ ì¡´ìž¬í•˜ì§€ 않거나, 사용ìžì˜ email 주소가 ì¸ì¦ë˜ì§€ 않아 비밀번호 복구 ë©”ì¼ì„ 보낼 수 없습니다."
-#: mediagoblin/auth/views.py:328
+#: mediagoblin/auth/views.py:336
msgid "You can now log in using your new password."
msgstr "ì´ì œ 새로운 비밀번호로 ë¡œê·¸ì¸ í•˜ì‹¤ 수 있습니다."
-#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:93
+#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:82
#: mediagoblin/submit/forms.py:28 mediagoblin/submit/forms.py:47
#: mediagoblin/user_pages/forms.py:45
msgid "Title"
@@ -117,7 +122,7 @@ msgid "Description of this work"
msgstr "ì´ ìž‘ì—…ì— ëŒ€í•œ 설명"
#: mediagoblin/edit/forms.py:29 mediagoblin/edit/forms.py:52
-#: mediagoblin/edit/forms.py:97 mediagoblin/submit/forms.py:32
+#: mediagoblin/edit/forms.py:86 mediagoblin/submit/forms.py:32
#: mediagoblin/submit/forms.py:51 mediagoblin/user_pages/forms.py:49
msgid ""
"You can use\n"
@@ -133,11 +138,11 @@ msgstr "태그"
msgid "Separate tags by commas."
msgstr "태그는 , 로 구분 ë©ë‹ˆë‹¤."
-#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:101
+#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:90
msgid "Slug"
msgstr "'슬러그'"
-#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:102
+#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:91
msgid "The slug can't be empty"
msgstr "'슬러그'는 ê³µë°±ì¼ ìˆ˜ 없습니다."
@@ -165,45 +170,45 @@ msgid "This address contains errors"
msgstr "ì£¼ì†Œì— ì—러가 있습니다."
#: mediagoblin/edit/forms.py:63
-msgid "Old password"
-msgstr "예전 비밀번호"
-
-#: mediagoblin/edit/forms.py:64
-msgid "Enter your old password to prove you own this account."
-msgstr "계정 확ì¸ì„ 위해, ì´ì „ 비밀 번호를 입력해 주세요."
-
-#: mediagoblin/edit/forms.py:67
-msgid "New password"
-msgstr "새로운 비밀번호"
-
-#: mediagoblin/edit/forms.py:74
msgid "License preference"
msgstr ""
-#: mediagoblin/edit/forms.py:80
+#: mediagoblin/edit/forms.py:69
msgid "This will be your default license on upload forms."
msgstr ""
-#: mediagoblin/edit/forms.py:82
+#: mediagoblin/edit/forms.py:71
msgid "Email me when others comment on my media"
msgstr "ì œ ë¯¸ë””ì–´ì— ëŒ€í•œ 컨í…ì„ ì›í•œë‹¤ë©´, ë©”ì¼ì„ 보내주세요."
-#: mediagoblin/edit/forms.py:94
+#: mediagoblin/edit/forms.py:83
msgid "The title can't be empty"
msgstr "ì œëª©ì€ ê³µë°±ì¼ ìˆ˜ 없습니다."
-#: mediagoblin/edit/forms.py:96 mediagoblin/submit/forms.py:50
+#: mediagoblin/edit/forms.py:85 mediagoblin/submit/forms.py:50
#: mediagoblin/user_pages/forms.py:48
msgid "Description of this collection"
msgstr "모ìŒì§‘ì— ëŒ€í•œ 설명"
-#: mediagoblin/edit/forms.py:103
+#: mediagoblin/edit/forms.py:92
msgid ""
"The title part of this collection's address. You usually don't need to "
"change this."
msgstr ""
-#: mediagoblin/edit/views.py:66
+#: mediagoblin/edit/forms.py:99
+msgid "Old password"
+msgstr "예전 비밀번호"
+
+#: mediagoblin/edit/forms.py:101
+msgid "Enter your old password to prove you own this account."
+msgstr "계정 확ì¸ì„ 위해, ì´ì „ 비밀 번호를 입력해 주세요."
+
+#: mediagoblin/edit/forms.py:104
+msgid "New password"
+msgstr "새로운 비밀번호"
+
+#: mediagoblin/edit/views.py:67
msgid "An entry with that slug already exists for this user."
msgstr "해당 ìœ ì €ì— ëŒ€í•œ '슬러그'ê°€ ì´ë¯¸ 존재합니다."
@@ -228,44 +233,63 @@ msgstr "사용ìžì˜ 계정 정보를 수정하고 있습니다. 조심해서 ìˆ
msgid "Profile changes saved"
msgstr "계정 ì •ë³´ê°€ 저장 ë˜ì—ˆìŠµë‹ˆë‹¤."
-#: mediagoblin/edit/views.py:241
-msgid "Wrong password"
-msgstr "ìž˜ëª»ëœ ë¹„ë°€ë²ˆí˜¸"
-
-#: mediagoblin/edit/views.py:252
+#: mediagoblin/edit/views.py:240
msgid "Account settings saved"
msgstr "계정 ì„¤ì •ì´ ì €ìž¥ ë˜ì—ˆìŠµë‹ˆë‹¤."
-#: mediagoblin/edit/views.py:286
+#: mediagoblin/edit/views.py:274
msgid "You need to confirm the deletion of your account."
msgstr ""
-#: mediagoblin/edit/views.py:322 mediagoblin/submit/views.py:142
-#: mediagoblin/user_pages/views.py:214
+#: mediagoblin/edit/views.py:310 mediagoblin/submit/views.py:138
+#: mediagoblin/user_pages/views.py:222
#, python-format
msgid "You already have a collection called \"%s\"!"
msgstr "\"%s\" 모ìŒì§‘ì„ ì´ë¯¸ 가지고 있습니다!"
-#: mediagoblin/edit/views.py:326
+#: mediagoblin/edit/views.py:314
msgid "A collection with that slug already exists for this user."
msgstr ""
-#: mediagoblin/edit/views.py:343
+#: mediagoblin/edit/views.py:329
msgid "You are editing another user's collection. Proceed with caution."
msgstr "다른 ìœ ì €ì˜ ëª¨ìŒì§‘ì„ ìˆ˜ì • 중 입니다. 주ì˜í•˜ì„¸ìš”."
-#: mediagoblin/gmg_commands/theme.py:58
+#: mediagoblin/edit/views.py:348
+msgid "Wrong password"
+msgstr "ìž˜ëª»ëœ ë¹„ë°€ë²ˆí˜¸"
+
+#: mediagoblin/edit/views.py:363
+msgid "Your password was changed successfully"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:60
msgid "Cannot link theme... no theme set\n"
msgstr "í…Œë§ˆì— ì—°ê²°í•  수 없습니다... 테마 ì…‹ì´ ì—†ìŠµë‹ˆë‹¤.\n"
-#: mediagoblin/gmg_commands/theme.py:71
+#: mediagoblin/gmg_commands/assetlink.py:73
msgid "No asset directory for this theme\n"
msgstr "ì´ í…Œë§ˆë¥¼ 위한 ì—ì…‹ 디렉토리가 없습니다.\n"
-#: mediagoblin/gmg_commands/theme.py:74
+#: mediagoblin/gmg_commands/assetlink.py:76
msgid "However, old link directory symlink found; removed.\n"
msgstr "그런ë°, ì˜¤ëž˜ëœ ë””ë ‰í† ë¦¬ 심볼릭 ë§í¬ë¥¼ 찾았습니다; 지워졌습니다.\n"
+#: mediagoblin/gmg_commands/assetlink.py:112
+#, python-format
+msgid "Could not link \"%s\": %s exists and is not a symlink\n"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:119
+#, python-format
+msgid "Skipping \"%s\"; already set up.\n"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:124
+#, python-format
+msgid "Old link found for \"%s\"; removing.\n"
+msgstr ""
+
#: mediagoblin/meddleware/csrf.py:134
msgid ""
"CSRF cookie not present. This is most likely the result of a cookie blocker "
@@ -273,12 +297,16 @@ msgid ""
"domain."
msgstr ""
-#: mediagoblin/media_types/__init__.py:61
-#: mediagoblin/media_types/__init__.py:102
+#: mediagoblin/media_types/__init__.py:111
+#: mediagoblin/media_types/__init__.py:155
msgid "Sorry, I don't support that file type :("
msgstr "죄송합니다. 해당 íƒ€ìž…ì˜ íŒŒì¼ì€ ì§€ì›í•˜ì§€ 않아요 :("
-#: mediagoblin/media_types/video/processing.py:36
+#: mediagoblin/media_types/pdf/processing.py:136
+msgid "unoconv failing to run, check log file"
+msgstr ""
+
+#: mediagoblin/media_types/video/processing.py:37
msgid "Video transcoding failed"
msgstr "비디오 ë³€í™˜ì— ì‹¤íŒ¨ 했습니다."
@@ -345,7 +373,7 @@ msgstr ""
msgid "This field is required for public clients"
msgstr "ì´ í•­ëª©ì€ ê³µê°œ 사용ìžë“¤ì„ 위해 ê¼­ í•„ìš” 합니다."
-#: mediagoblin/plugins/oauth/views.py:59
+#: mediagoblin/plugins/oauth/views.py:56
msgid "The client {0} has been registered!"
msgstr "ì‚¬ìš©ìž {0}ë‹˜ì´ ë“±ë¡ ë˜ì—ˆìŠµë‹ˆë‹¤!"
@@ -364,7 +392,7 @@ msgstr ""
msgid "Add"
msgstr "추가"
-#: mediagoblin/processing/__init__.py:172
+#: mediagoblin/processing/__init__.py:193
msgid "Invalid file given for media type."
msgstr "알수없는 미디어 íŒŒì¼ ìž…ë‹ˆë‹¤."
@@ -372,45 +400,45 @@ msgstr "알수없는 미디어 íŒŒì¼ ìž…ë‹ˆë‹¤."
msgid "File"
msgstr "파ì¼"
-#: mediagoblin/submit/views.py:51
+#: mediagoblin/submit/views.py:49
msgid "You must provide a file."
msgstr "파ì¼ì„ 등ë¡í•˜ì…”야 합니다."
-#: mediagoblin/submit/views.py:97
+#: mediagoblin/submit/views.py:93
msgid "Woohoo! Submitted!"
msgstr "ì´í–!! 등ë¡í–ˆìŠµë‹ˆë‹¤!"
-#: mediagoblin/submit/views.py:146
+#: mediagoblin/submit/views.py:144
#, python-format
msgid "Collection \"%s\" added!"
msgstr "\"%s\" 모ìŒì§‘ì´ ì¶”ê°€ë˜ì—ˆìŠµë‹ˆë‹¤!"
-#: mediagoblin/templates/mediagoblin/base.html:64
+#: mediagoblin/templates/mediagoblin/base.html:67
msgid "Verify your email!"
msgstr "ë©”ì¼ì„ 확ì¸í•˜ì„¸ìš”!"
-#: mediagoblin/templates/mediagoblin/base.html:65
+#: mediagoblin/templates/mediagoblin/base.html:68
msgid "log out"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:70
+#: mediagoblin/templates/mediagoblin/base.html:73
#: mediagoblin/templates/mediagoblin/auth/login.html:28
#: mediagoblin/templates/mediagoblin/auth/login.html:36
#: mediagoblin/templates/mediagoblin/auth/login.html:54
msgid "Log in"
msgstr "로그ì¸"
-#: mediagoblin/templates/mediagoblin/base.html:79
+#: mediagoblin/templates/mediagoblin/base.html:82
#, python-format
msgid "<a href=\"%(user_url)s\">%(user_name)s</a>'s account"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:86
+#: mediagoblin/templates/mediagoblin/base.html:89
msgid "Change account settings"
msgstr "계정 설정 변경"
-#: mediagoblin/templates/mediagoblin/base.html:90
-#: mediagoblin/templates/mediagoblin/base.html:105
+#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:108
#: mediagoblin/templates/mediagoblin/admin/panel.html:21
#: mediagoblin/templates/mediagoblin/admin/panel.html:26
#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:21
@@ -418,72 +446,25 @@ msgstr "계정 설정 변경"
msgid "Media processing panel"
msgstr "미디어 작업 패ë„"
-#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:96
msgid "Log out"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:96
+#: mediagoblin/templates/mediagoblin/base.html:99
#: mediagoblin/templates/mediagoblin/user_pages/user.html:156
msgid "Add media"
msgstr "미디어 추가"
-#: mediagoblin/templates/mediagoblin/base.html:99
+#: mediagoblin/templates/mediagoblin/base.html:102
#: mediagoblin/templates/mediagoblin/user_pages/collection_list.html:41
msgid "Create new collection"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:122
-#, python-format
-msgid ""
-"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
-"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/base.html:125
-#, python-format
-msgid ""
-"Released under the <a "
-"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
-"href=\"%(source_link)s\">Source code</a> available."
-msgstr "Released under the <a href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a href=\"%(source_link)s\">Source code</a> available."
-
#: mediagoblin/templates/mediagoblin/error.html:24
msgid "Image of goblin stressing out"
msgstr ""
-#: mediagoblin/templates/mediagoblin/root.html:31
-msgid "Explore"
-msgstr "íƒìƒ‰"
-
-#: mediagoblin/templates/mediagoblin/root.html:33
-msgid "Hi there, welcome to this MediaGoblin site!"
-msgstr "안녕하세요! 미디어 고블린 사ì´íŠ¸ì— ì˜¨ê±¸ í™˜ì˜ í•©ë‹ˆë‹¤!"
-
-#: mediagoblin/templates/mediagoblin/root.html:35
-msgid ""
-"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
-"extraordinarily great piece of media hosting software."
-msgstr "ì´ì‚¬ì´íŠ¸ëŠ” <a href=\"http://mediagoblin.org\">MediaGoblin</a>으로 ìž‘ë™ ì¤‘ìž…ë‹ˆë‹¤. ì´ëŠ” 특ì´í•œ 미디어 호스팅 소프트웨어중 하나 입니다."
-
-#: mediagoblin/templates/mediagoblin/root.html:36
-msgid ""
-"To add your own media, place comments, and more, you can log in with your "
-"MediaGoblin account."
-msgstr "ìžì‹ ì˜ 미디어를 추가하고, ëŒ“ê¸€ì„ ë‚¨ê¸°ì„¸ìš”! 미디어 고블린 계정으로 ë‚´ì—­ì„ í™•ì¸ í•˜ì‹¤ 수 있습니다!"
-
-#: mediagoblin/templates/mediagoblin/root.html:38
-msgid "Don't have one yet? It's easy!"
-msgstr "ì•„ì§ ì•„ë¬´ê²ƒë„ ì—†ìœ¼ì‹œë‹¤êµ¬ìš”? 매우 쉽습니다!"
-
-#: mediagoblin/templates/mediagoblin/root.html:39
-#, python-format
-msgid ""
-"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
-" or\n"
-" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
-msgstr "<a class=\"button_action_highlight\" href=\"%(register_url)s\">ì‚¬ìš©ìž ê³„ì • 만들기</a>\n ë˜ëŠ”\n <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">서버를 위한 MediaGoblin 설정하기</a>"
-
-#: mediagoblin/templates/mediagoblin/root.html:47
+#: mediagoblin/templates/mediagoblin/root.html:32
msgid "Most recent media"
msgstr "가장 ìµœê·¼ì— ë“±ë¡ëœ 미디어"
@@ -589,6 +570,53 @@ msgid ""
"%(verification_url)s"
msgstr "안녕하세요 %(username)s님,\n\nGNU MediaGoblin ê³„ì •ì„ í™œì„±í™” 하시려면, ì•„ëž˜ì˜ URL 주소를 브ë¼ìš°ì ¸ë¡œ ì ‘ì†í•˜ì„¸ìš”.\n\n%(verification_url)s"
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:21
+#, python-format
+msgid ""
+"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
+"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:24
+#, python-format
+msgid ""
+"Released under the <a "
+"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
+"href=\"%(source_link)s\">Source code</a> available."
+msgstr "Released under the <a href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a href=\"%(source_link)s\">Source code</a> available."
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:20
+msgid "Explore"
+msgstr "íƒìƒ‰"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:22
+msgid "Hi there, welcome to this MediaGoblin site!"
+msgstr "안녕하세요! 미디어 고블린 사ì´íŠ¸ì— ì˜¨ê±¸ í™˜ì˜ í•©ë‹ˆë‹¤!"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:24
+msgid ""
+"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
+"extraordinarily great piece of media hosting software."
+msgstr "ì´ì‚¬ì´íŠ¸ëŠ” <a href=\"http://mediagoblin.org\">MediaGoblin</a>으로 ìž‘ë™ ì¤‘ìž…ë‹ˆë‹¤. ì´ëŠ” 특ì´í•œ 미디어 호스팅 소프트웨어중 하나 입니다."
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:25
+msgid ""
+"To add your own media, place comments, and more, you can log in with your "
+"MediaGoblin account."
+msgstr "ìžì‹ ì˜ 미디어를 추가하고, ëŒ“ê¸€ì„ ë‚¨ê¸°ì„¸ìš”! 미디어 고블린 계정으로 ë‚´ì—­ì„ í™•ì¸ í•˜ì‹¤ 수 있습니다!"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:27
+msgid "Don't have one yet? It's easy!"
+msgstr "ì•„ì§ ì•„ë¬´ê²ƒë„ ì—†ìœ¼ì‹œë‹¤êµ¬ìš”? 매우 쉽습니다!"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:28
+#, python-format
+msgid ""
+"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
+" or\n"
+" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/bits/logo.html:23
#: mediagoblin/themes/airy/templates/mediagoblin/bits/logo.html:23
msgid "MediaGoblin logo"
@@ -601,13 +629,13 @@ msgid "Editing attachments for %(media_title)s"
msgstr "%(media_title)sì˜ ì²¨ë¶€ 수정 중..."
#: mediagoblin/templates/mediagoblin/edit/attachments.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:159
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:175
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:182
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:198
msgid "Attachments"
msgstr "첨부"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:57
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:181
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:204
msgid "Add attachment"
msgstr "첨부 추가"
@@ -624,12 +652,22 @@ msgstr "취소"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:63
#: mediagoblin/templates/mediagoblin/edit/edit.html:42
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:52
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:55
#: mediagoblin/templates/mediagoblin/edit/edit_collection.html:33
#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:40
msgid "Save changes"
msgstr "저장"
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:28
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:38
+#, python-format
+msgid "Changing %(username)s's password"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:45
+msgid "Save"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:28
#, python-format
msgid "Really delete user '%(user_name)s' and all related media/comments?"
@@ -640,7 +678,7 @@ msgid "Yes, really delete my account"
msgstr ""
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:47
+#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:48
#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:49
msgid "Delete permanently"
msgstr "ì˜êµ¬ì ìœ¼ë¡œ ì‚­ì œ"
@@ -657,7 +695,11 @@ msgstr "%(media_title)s 편집중..."
msgid "Changing %(username)s's account settings"
msgstr "%(username)s'ì˜ ê³„ì • 설정 변경중..."
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:59
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:46
+msgid "Change your password."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:62
msgid "Delete my account"
msgstr ""
@@ -682,6 +724,7 @@ msgstr "미디어는 다ìŒìœ¼ë¡œ 태그 ë˜ì—ˆìŠµë‹ˆë‹¤.: %(tag_name)s"
#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:56
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:65
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:136
#: mediagoblin/templates/mediagoblin/media_displays/video.html:55
msgid "Download"
@@ -706,6 +749,7 @@ msgid ""
msgstr "사운드 파ì¼ì„ ìž¬ìƒ í•˜ì‹œë ¤ë©´\n\tì´ê³³ì—서 ìµœì‹ ì˜ ë¸Œë¼ìš°ì ¸ë¥¼ 다운받으세요! <a href=\"http://getfirefox.com\">\n\t http://getfirefox.com</a>!"
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:60
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:71
#: mediagoblin/templates/mediagoblin/media_displays/video.html:61
msgid "Original file"
msgstr "ì›ë³¸ 파ì¼"
@@ -714,6 +758,7 @@ msgstr "ì›ë³¸ 파ì¼"
msgid "WebM file (Vorbis codec)"
msgstr "WebM íŒŒì¼ (Vorbis ì½”ë±)"
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:59
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:87
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:93
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:99
@@ -724,6 +769,10 @@ msgstr "WebM íŒŒì¼ (Vorbis ì½”ë±)"
msgid "Image for %(media_title)s"
msgstr "%(media_title)s ì´ë¯¸ì§€"
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:79
+msgid "PDF file"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:112
msgid "Toggle Rotate"
msgstr ""
@@ -822,7 +871,7 @@ msgstr "%(title)s ì„ ì§€ìš°ì‹œê² ìŠµë‹ˆê¹Œ?"
msgid "Really remove %(media_title)s from %(collection_title)s?"
msgstr "%(collection_title)sì˜ %(media_title)sì„ ì‚­ì œ 하시겠습니까?"
-#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:53
+#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:54
msgid "Remove"
msgstr "지우기"
@@ -865,24 +914,28 @@ msgstr "<a href=\"%(user_url)s\">%(username)s</a>ì˜ ë¯¸ë””ì–´"
msgid "â– Browsing media by <a href=\"%(user_url)s\">%(username)s</a>"
msgstr "â– <a href=\"%(user_url)s\">%(username)s</a>ì˜ ë¯¸ë””ì–´ë¥¼ ë³´ê³  있습니다."
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:94
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:95
msgid "Add a comment"
msgstr "ë§ê¸€ 달기"
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:102
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:104
msgid "Add this comment"
msgstr "ë§ê¸€ 추가"
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:123
-msgid "at"
-msgstr "ì—"
-
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:144
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:132
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:152
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:164
#, python-format
-msgid ""
-"<h3>Added on</h3>\n"
-" <p>%(date)s</p>"
-msgstr "<h3>부가 기능</h3>\n <p>%(date)s</p>"
+msgid "%(formatted_time)s ago"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:150
+msgid "Added"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:161
+msgid "Created"
+msgstr ""
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:28
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:40
@@ -1038,7 +1091,7 @@ msgstr "ì´ì „"
msgid "Tagged with"
msgstr "태그 정보"
-#: mediagoblin/tools/exif.py:80
+#: mediagoblin/tools/exif.py:83
msgid "Could not read the image file."
msgstr "ì´ë¯¸ì§€ 파ì¼ì„ ì½ì„ 수 없습니다."
@@ -1068,6 +1121,30 @@ msgid ""
" deleted."
msgstr ""
+#: mediagoblin/tools/timesince.py:62
+msgid "year"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:63
+msgid "month"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:64
+msgid "week"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:65
+msgid "day"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:66
+msgid "hour"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:67
+msgid "minute"
+msgstr ""
+
#: mediagoblin/user_pages/forms.py:23
msgid "Comment"
msgstr ""
@@ -1099,73 +1176,77 @@ msgstr "-- ì„ íƒ --"
msgid "Include a note"
msgstr "노트 추가"
-#: mediagoblin/user_pages/lib.py:56
+#: mediagoblin/user_pages/lib.py:58
msgid "commented on your post"
msgstr "ê²Œì‹œë¬¼ì— ë§ê¸€ì´ 달렸습니다."
-#: mediagoblin/user_pages/views.py:166
+#: mediagoblin/user_pages/views.py:169
+msgid "Sorry, comments are disabled."
+msgstr ""
+
+#: mediagoblin/user_pages/views.py:174
msgid "Oops, your comment was empty."
msgstr "오우, ëŒ“ê¸€ì´ ë¹„ì—ˆìŠµë‹ˆë‹¤."
-#: mediagoblin/user_pages/views.py:172
+#: mediagoblin/user_pages/views.py:180
msgid "Your comment has been posted!"
msgstr "ëŒ“ê¸€ì´ ë“±ë¡ ë˜ì—ˆìŠµë‹ˆë‹¤!"
-#: mediagoblin/user_pages/views.py:197
+#: mediagoblin/user_pages/views.py:205
msgid "Please check your entries and try again."
msgstr "확ì¸ì„ 하시고 다시 시ë„하세요."
-#: mediagoblin/user_pages/views.py:237
+#: mediagoblin/user_pages/views.py:245
msgid "You have to select or add a collection"
msgstr "모ìŒì§‘ì„ ì¶”ê°€í•˜ê±°ë‚˜ 기존 모ìŒì§‘ì„ ì„ íƒí•˜ì„¸ìš”."
-#: mediagoblin/user_pages/views.py:248
+#: mediagoblin/user_pages/views.py:256
#, python-format
msgid "\"%s\" already in collection \"%s\""
msgstr "\"%s\" 모ìŒì§‘ì´ ì´ë¯¸ 존재 합니다. \"%s\""
-#: mediagoblin/user_pages/views.py:264
+#: mediagoblin/user_pages/views.py:262
#, python-format
msgid "\"%s\" added to collection \"%s\""
msgstr "\"%s\" 모ìŒì§‘ì„ ì¶”ê°€í–ˆìŠµë‹ˆë‹¤. \"%s\""
-#: mediagoblin/user_pages/views.py:286
+#: mediagoblin/user_pages/views.py:282
msgid "You deleted the media."
msgstr "미디어를 삭제 했습니다."
-#: mediagoblin/user_pages/views.py:293
+#: mediagoblin/user_pages/views.py:289
msgid "The media was not deleted because you didn't check that you were sure."
msgstr "í™•ì¸ ì²´í¬ë¥¼ 하지 않았습니다. 미디어는 ì‚­ì œë˜ì§€ 않았습니다."
-#: mediagoblin/user_pages/views.py:301
+#: mediagoblin/user_pages/views.py:296
msgid "You are about to delete another user's media. Proceed with caution."
msgstr "다른 ì‚¬ëžŒì˜ ë¯¸ë””ì–´ë¥¼ 삭제하려고 합니다. 다시 한번 확ì¸í•˜ì„¸ìš”."
-#: mediagoblin/user_pages/views.py:375
+#: mediagoblin/user_pages/views.py:370
msgid "You deleted the item from the collection."
msgstr "모ìŒì§‘ì— ìžˆëŠ” í•­ëª©ì„ ì‚­ì œ 했습니다."
-#: mediagoblin/user_pages/views.py:379
+#: mediagoblin/user_pages/views.py:374
msgid "The item was not removed because you didn't check that you were sure."
msgstr "확ì¸ì„ 하지 않았습니다. í•­ëª©ì€ ì‚­ì œí•˜ì§€ 않았습니다."
-#: mediagoblin/user_pages/views.py:389
+#: mediagoblin/user_pages/views.py:382
msgid ""
"You are about to delete an item from another user's collection. Proceed with"
" caution."
msgstr "다른 사용ìžì˜ 모ìŒì§‘ì— ìžˆëŠ” í•­ëª©ì„ ì‚­ì œí•˜ì˜€ìŠµë‹ˆë‹¤. 주ì˜í•˜ì„¸ìš”."
-#: mediagoblin/user_pages/views.py:422
+#: mediagoblin/user_pages/views.py:415
#, python-format
msgid "You deleted the collection \"%s\""
msgstr "\"%s\" 모ìŒì§‘ì„ ì‚­ì œí•˜ì…¨ìŠµë‹ˆë‹¤."
-#: mediagoblin/user_pages/views.py:429
+#: mediagoblin/user_pages/views.py:422
msgid ""
"The collection was not deleted because you didn't check that you were sure."
msgstr "확ì¸ì„ 하지 않았습니다. 모ìŒì§‘ì€ ì‚­ì œí•˜ì§€ 않았습니다."
-#: mediagoblin/user_pages/views.py:439
+#: mediagoblin/user_pages/views.py:430
msgid ""
"You are about to delete another user's collection. Proceed with caution."
msgstr "다른 사용ìžì˜ 모ìŒì§‘ì„ ì‚­ì œí•˜ë ¤ê³  합니다. 주ì˜í•˜ì„¸ìš”."
diff --git a/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.mo
index fe96d40e..4e6e51ce 100644
--- a/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.mo
+++ b/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.mo
Binary files differ
diff --git a/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po
index 3fd26d23..14e4fb33 100644
--- a/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po
+++ b/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po
@@ -3,16 +3,16 @@
# This file is distributed under the same license as the PROJECT project.
#
# Translators:
-# <mail@jefvanschendel.nl>, 2011, 2012.
-# <mvanderboom@gmail.com>, 2012.
+# schendje <mail@jefvanschendel.nl>, 2011, 2012
+# mvanderboom <mvanderboom@gmail.com>, 2012
msgid ""
msgstr ""
"Project-Id-Version: GNU MediaGoblin\n"
"Report-Msgid-Bugs-To: http://issues.mediagoblin.org/\n"
-"POT-Creation-Date: 2013-03-04 18:04-0600\n"
-"PO-Revision-Date: 2013-03-05 00:04+0000\n"
+"POT-Creation-Date: 2013-05-27 13:54-0500\n"
+"PO-Revision-Date: 2013-05-27 18:54+0000\n"
"Last-Translator: cwebber <cwebber@dustycloud.org>\n"
-"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language-Team: Dutch (http://www.transifex.com/projects/p/mediagoblin/language/nl/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
@@ -20,34 +20,39 @@ msgstr ""
"Language: nl\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: mediagoblin/auth/forms.py:28
-msgid "Invalid User name or email address."
-msgstr ""
-
-#: mediagoblin/auth/forms.py:29
-msgid "This field does not take email addresses."
-msgstr ""
-
-#: mediagoblin/auth/forms.py:30
-msgid "This field requires an email address."
-msgstr ""
-
-#: mediagoblin/auth/forms.py:52 mediagoblin/auth/forms.py:67
+#: mediagoblin/auth/forms.py:26
msgid "Username"
msgstr "Gebruikersnaam"
-#: mediagoblin/auth/forms.py:56 mediagoblin/auth/forms.py:71
+#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:45
+#: mediagoblin/tests/test_util.py:110
msgid "Password"
msgstr "Wachtwoord"
-#: mediagoblin/auth/forms.py:60
+#: mediagoblin/auth/forms.py:34
msgid "Email address"
msgstr "E-mail adres"
-#: mediagoblin/auth/forms.py:78
+#: mediagoblin/auth/forms.py:41
+msgid "Username or Email"
+msgstr ""
+
+#: mediagoblin/auth/forms.py:52
msgid "Username or email"
msgstr "Gebruikersnaam of email-adres"
+#: mediagoblin/auth/tools.py:31
+msgid "Invalid User name or email address."
+msgstr ""
+
+#: mediagoblin/auth/tools.py:32
+msgid "This field does not take email addresses."
+msgstr ""
+
+#: mediagoblin/auth/tools.py:33
+msgid "This field requires an email address."
+msgstr ""
+
#: mediagoblin/auth/views.py:54
msgid "Sorry, registration is disabled on this instance."
msgstr "Sorry, registratie is uitgeschakeld op deze instantie."
@@ -60,54 +65,54 @@ msgstr "Sorry, er bestaat al een gebruiker met die naam."
msgid "Sorry, a user with that email address already exists."
msgstr "Sorry, een gebruiker met dat e-mailadres bestaat al."
-#: mediagoblin/auth/views.py:174
+#: mediagoblin/auth/views.py:182
msgid ""
"Your email address has been verified. You may now login, edit your profile, "
"and submit images!"
msgstr "Uw e-mailadres is geverifieerd. U kunt nu inloggen, uw profiel bewerken, en afbeeldingen toevoegen!"
-#: mediagoblin/auth/views.py:180
+#: mediagoblin/auth/views.py:188
msgid "The verification key or user id is incorrect"
msgstr "De verificatie sleutel of gebruikers-ID is onjuist"
-#: mediagoblin/auth/views.py:198
+#: mediagoblin/auth/views.py:206
msgid "You must be logged in so we know who to send the email to!"
msgstr "Je moet ingelogd zijn, anders weten we niet waar we de e-mail naartoe moeten sturen!"
-#: mediagoblin/auth/views.py:206
+#: mediagoblin/auth/views.py:214
msgid "You've already verified your email address!"
msgstr "Je hebt je e-mailadres al geverifieerd!"
-#: mediagoblin/auth/views.py:219
+#: mediagoblin/auth/views.py:227
msgid "Resent your verification email."
msgstr "Verificatie e-mail opnieuw opgestuurd."
-#: mediagoblin/auth/views.py:250
+#: mediagoblin/auth/views.py:258
msgid ""
"If that email address (case sensitive!) is registered an email has been sent"
" with instructions on how to change your password."
msgstr ""
-#: mediagoblin/auth/views.py:261
+#: mediagoblin/auth/views.py:269
msgid "Couldn't find someone with that username."
msgstr ""
-#: mediagoblin/auth/views.py:264
+#: mediagoblin/auth/views.py:272
msgid ""
"An email has been sent with instructions on how to change your password."
msgstr "Een e-mail met instructies om je wachtwoord te veranderen is verstuurd."
-#: mediagoblin/auth/views.py:271
+#: mediagoblin/auth/views.py:279
msgid ""
"Could not send password recovery email as your username is inactive or your "
"account's email address has not been verified."
msgstr "Email kon niet verstuurd worden omdat je gebruikersnaam inactief is of omdat je e-mailadres nog niet geverifieerd is."
-#: mediagoblin/auth/views.py:328
+#: mediagoblin/auth/views.py:336
msgid "You can now log in using your new password."
msgstr "Je kunt nu inloggen met je nieuwe wachtwoord."
-#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:93
+#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:82
#: mediagoblin/submit/forms.py:28 mediagoblin/submit/forms.py:47
#: mediagoblin/user_pages/forms.py:45
msgid "Title"
@@ -118,7 +123,7 @@ msgid "Description of this work"
msgstr "Beschrijving van dit werk"
#: mediagoblin/edit/forms.py:29 mediagoblin/edit/forms.py:52
-#: mediagoblin/edit/forms.py:97 mediagoblin/submit/forms.py:32
+#: mediagoblin/edit/forms.py:86 mediagoblin/submit/forms.py:32
#: mediagoblin/submit/forms.py:51 mediagoblin/user_pages/forms.py:49
msgid ""
"You can use\n"
@@ -134,11 +139,11 @@ msgstr "Etiket"
msgid "Separate tags by commas."
msgstr "Hou labels gescheiden met komma's."
-#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:101
+#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:90
msgid "Slug"
msgstr "Slug"
-#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:102
+#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:91
msgid "The slug can't be empty"
msgstr "De slug kan niet leeg zijn"
@@ -166,45 +171,45 @@ msgid "This address contains errors"
msgstr "Dit adres bevat fouten"
#: mediagoblin/edit/forms.py:63
-msgid "Old password"
-msgstr "Oud wachtwoord"
-
-#: mediagoblin/edit/forms.py:64
-msgid "Enter your old password to prove you own this account."
-msgstr "Vul je oude wachtwoord in om te bewijzen dat dit jouw account is"
-
-#: mediagoblin/edit/forms.py:67
-msgid "New password"
-msgstr "Nieuw wachtwoord"
-
-#: mediagoblin/edit/forms.py:74
msgid "License preference"
msgstr ""
-#: mediagoblin/edit/forms.py:80
+#: mediagoblin/edit/forms.py:69
msgid "This will be your default license on upload forms."
msgstr ""
-#: mediagoblin/edit/forms.py:82
+#: mediagoblin/edit/forms.py:71
msgid "Email me when others comment on my media"
msgstr ""
-#: mediagoblin/edit/forms.py:94
+#: mediagoblin/edit/forms.py:83
msgid "The title can't be empty"
msgstr ""
-#: mediagoblin/edit/forms.py:96 mediagoblin/submit/forms.py:50
+#: mediagoblin/edit/forms.py:85 mediagoblin/submit/forms.py:50
#: mediagoblin/user_pages/forms.py:48
msgid "Description of this collection"
msgstr ""
-#: mediagoblin/edit/forms.py:103
+#: mediagoblin/edit/forms.py:92
msgid ""
"The title part of this collection's address. You usually don't need to "
"change this."
msgstr ""
-#: mediagoblin/edit/views.py:66
+#: mediagoblin/edit/forms.py:99
+msgid "Old password"
+msgstr "Oud wachtwoord"
+
+#: mediagoblin/edit/forms.py:101
+msgid "Enter your old password to prove you own this account."
+msgstr "Vul je oude wachtwoord in om te bewijzen dat dit jouw account is"
+
+#: mediagoblin/edit/forms.py:104
+msgid "New password"
+msgstr "Nieuw wachtwoord"
+
+#: mediagoblin/edit/views.py:67
msgid "An entry with that slug already exists for this user."
msgstr "Er bestaat al een met die slug voor deze gebruiker."
@@ -229,44 +234,63 @@ msgstr "U bent een gebruikersprofiel aan het aanpassen. Ga voorzichtig te werk."
msgid "Profile changes saved"
msgstr "Profielaanpassingen opgeslagen"
-#: mediagoblin/edit/views.py:241
-msgid "Wrong password"
-msgstr "Verkeerd wachtwoord"
-
-#: mediagoblin/edit/views.py:252
+#: mediagoblin/edit/views.py:240
msgid "Account settings saved"
msgstr "Accountinstellingen opgeslagen"
-#: mediagoblin/edit/views.py:286
+#: mediagoblin/edit/views.py:274
msgid "You need to confirm the deletion of your account."
msgstr ""
-#: mediagoblin/edit/views.py:322 mediagoblin/submit/views.py:142
-#: mediagoblin/user_pages/views.py:214
+#: mediagoblin/edit/views.py:310 mediagoblin/submit/views.py:138
+#: mediagoblin/user_pages/views.py:222
#, python-format
msgid "You already have a collection called \"%s\"!"
msgstr ""
-#: mediagoblin/edit/views.py:326
+#: mediagoblin/edit/views.py:314
msgid "A collection with that slug already exists for this user."
msgstr ""
-#: mediagoblin/edit/views.py:343
+#: mediagoblin/edit/views.py:329
msgid "You are editing another user's collection. Proceed with caution."
msgstr ""
-#: mediagoblin/gmg_commands/theme.py:58
+#: mediagoblin/edit/views.py:348
+msgid "Wrong password"
+msgstr "Verkeerd wachtwoord"
+
+#: mediagoblin/edit/views.py:363
+msgid "Your password was changed successfully"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:60
msgid "Cannot link theme... no theme set\n"
msgstr ""
-#: mediagoblin/gmg_commands/theme.py:71
+#: mediagoblin/gmg_commands/assetlink.py:73
msgid "No asset directory for this theme\n"
msgstr ""
-#: mediagoblin/gmg_commands/theme.py:74
+#: mediagoblin/gmg_commands/assetlink.py:76
msgid "However, old link directory symlink found; removed.\n"
msgstr ""
+#: mediagoblin/gmg_commands/assetlink.py:112
+#, python-format
+msgid "Could not link \"%s\": %s exists and is not a symlink\n"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:119
+#, python-format
+msgid "Skipping \"%s\"; already set up.\n"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:124
+#, python-format
+msgid "Old link found for \"%s\"; removing.\n"
+msgstr ""
+
#: mediagoblin/meddleware/csrf.py:134
msgid ""
"CSRF cookie not present. This is most likely the result of a cookie blocker "
@@ -274,12 +298,16 @@ msgid ""
"domain."
msgstr ""
-#: mediagoblin/media_types/__init__.py:61
-#: mediagoblin/media_types/__init__.py:102
+#: mediagoblin/media_types/__init__.py:111
+#: mediagoblin/media_types/__init__.py:155
msgid "Sorry, I don't support that file type :("
msgstr "Sorry, dat bestandstype wordt niet ondersteunt."
-#: mediagoblin/media_types/video/processing.py:36
+#: mediagoblin/media_types/pdf/processing.py:136
+msgid "unoconv failing to run, check log file"
+msgstr ""
+
+#: mediagoblin/media_types/video/processing.py:37
msgid "Video transcoding failed"
msgstr ""
@@ -346,7 +374,7 @@ msgstr ""
msgid "This field is required for public clients"
msgstr ""
-#: mediagoblin/plugins/oauth/views.py:59
+#: mediagoblin/plugins/oauth/views.py:56
msgid "The client {0} has been registered!"
msgstr ""
@@ -365,7 +393,7 @@ msgstr ""
msgid "Add"
msgstr "Voeg toe"
-#: mediagoblin/processing/__init__.py:172
+#: mediagoblin/processing/__init__.py:193
msgid "Invalid file given for media type."
msgstr "Verkeerd bestandsformaat voor mediatype opgegeven."
@@ -373,45 +401,45 @@ msgstr "Verkeerd bestandsformaat voor mediatype opgegeven."
msgid "File"
msgstr "Bestand"
-#: mediagoblin/submit/views.py:51
+#: mediagoblin/submit/views.py:49
msgid "You must provide a file."
msgstr "U moet een bestand aangeven."
-#: mediagoblin/submit/views.py:97
+#: mediagoblin/submit/views.py:93
msgid "Woohoo! Submitted!"
msgstr "Mooizo! Toegevoegd!"
-#: mediagoblin/submit/views.py:146
+#: mediagoblin/submit/views.py:144
#, python-format
msgid "Collection \"%s\" added!"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:64
+#: mediagoblin/templates/mediagoblin/base.html:67
msgid "Verify your email!"
msgstr "Verifieer je e-mailadres!"
-#: mediagoblin/templates/mediagoblin/base.html:65
+#: mediagoblin/templates/mediagoblin/base.html:68
msgid "log out"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:70
+#: mediagoblin/templates/mediagoblin/base.html:73
#: mediagoblin/templates/mediagoblin/auth/login.html:28
#: mediagoblin/templates/mediagoblin/auth/login.html:36
#: mediagoblin/templates/mediagoblin/auth/login.html:54
msgid "Log in"
msgstr "Inloggen"
-#: mediagoblin/templates/mediagoblin/base.html:79
+#: mediagoblin/templates/mediagoblin/base.html:82
#, python-format
msgid "<a href=\"%(user_url)s\">%(user_name)s</a>'s account"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:86
+#: mediagoblin/templates/mediagoblin/base.html:89
msgid "Change account settings"
msgstr "Accountinstellingen aanpassen"
-#: mediagoblin/templates/mediagoblin/base.html:90
-#: mediagoblin/templates/mediagoblin/base.html:105
+#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:108
#: mediagoblin/templates/mediagoblin/admin/panel.html:21
#: mediagoblin/templates/mediagoblin/admin/panel.html:26
#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:21
@@ -419,72 +447,25 @@ msgstr "Accountinstellingen aanpassen"
msgid "Media processing panel"
msgstr "Mediaverwerkingspaneel"
-#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:96
msgid "Log out"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:96
+#: mediagoblin/templates/mediagoblin/base.html:99
#: mediagoblin/templates/mediagoblin/user_pages/user.html:156
msgid "Add media"
msgstr "Voeg media toe"
-#: mediagoblin/templates/mediagoblin/base.html:99
+#: mediagoblin/templates/mediagoblin/base.html:102
#: mediagoblin/templates/mediagoblin/user_pages/collection_list.html:41
msgid "Create new collection"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:122
-#, python-format
-msgid ""
-"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
-"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/base.html:125
-#, python-format
-msgid ""
-"Released under the <a "
-"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
-"href=\"%(source_link)s\">Source code</a> available."
-msgstr "Uitgegeven onder de <a href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>-licentie. <a href=\"%(source_link)s\">Broncode</a> available."
-
#: mediagoblin/templates/mediagoblin/error.html:24
msgid "Image of goblin stressing out"
msgstr ""
-#: mediagoblin/templates/mediagoblin/root.html:31
-msgid "Explore"
-msgstr "Verkennen"
-
-#: mediagoblin/templates/mediagoblin/root.html:33
-msgid "Hi there, welcome to this MediaGoblin site!"
-msgstr "Hoi, welkom op deze MediaGoblin website!"
-
-#: mediagoblin/templates/mediagoblin/root.html:35
-msgid ""
-"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
-"extraordinarily great piece of media hosting software."
-msgstr "Deze website draait <a href=\"http://mediagoblin.org\">MediaGoblin</a>, een buitengewoon goed stuk software voor mediahosting."
-
-#: mediagoblin/templates/mediagoblin/root.html:36
-msgid ""
-"To add your own media, place comments, and more, you can log in with your "
-"MediaGoblin account."
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:38
-msgid "Don't have one yet? It's easy!"
-msgstr "Heb je er nog geen? Het is heel eenvoudig!"
-
-#: mediagoblin/templates/mediagoblin/root.html:39
-#, python-format
-msgid ""
-"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
-" or\n"
-" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
-msgstr "&lt;a class=\"button_action_highlight\" href=\"%(register_url)s\"&gt;Creëer een account op deze website&lt;/a&gt;\n of\n &lt;a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\"&gt;Gebruik MediaGoblin op je eigen server&lt;/a&gt;"
-
-#: mediagoblin/templates/mediagoblin/root.html:47
+#: mediagoblin/templates/mediagoblin/root.html:32
msgid "Most recent media"
msgstr "Nieuwste media"
@@ -590,6 +571,53 @@ msgid ""
"%(verification_url)s"
msgstr "Hallo %(username)s , open de volgende URL in uw webbrowser om uw GNU MediaGoblin account te activeren: %(verification_url)s "
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:21
+#, python-format
+msgid ""
+"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
+"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:24
+#, python-format
+msgid ""
+"Released under the <a "
+"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
+"href=\"%(source_link)s\">Source code</a> available."
+msgstr "Uitgegeven onder de <a href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>-licentie. <a href=\"%(source_link)s\">Broncode</a> available."
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:20
+msgid "Explore"
+msgstr "Verkennen"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:22
+msgid "Hi there, welcome to this MediaGoblin site!"
+msgstr "Hoi, welkom op deze MediaGoblin website!"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:24
+msgid ""
+"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
+"extraordinarily great piece of media hosting software."
+msgstr "Deze website draait <a href=\"http://mediagoblin.org\">MediaGoblin</a>, een buitengewoon goed stuk software voor mediahosting."
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:25
+msgid ""
+"To add your own media, place comments, and more, you can log in with your "
+"MediaGoblin account."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:27
+msgid "Don't have one yet? It's easy!"
+msgstr "Heb je er nog geen? Het is heel eenvoudig!"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:28
+#, python-format
+msgid ""
+"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
+" or\n"
+" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/bits/logo.html:23
#: mediagoblin/themes/airy/templates/mediagoblin/bits/logo.html:23
msgid "MediaGoblin logo"
@@ -602,13 +630,13 @@ msgid "Editing attachments for %(media_title)s"
msgstr ""
#: mediagoblin/templates/mediagoblin/edit/attachments.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:159
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:175
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:182
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:198
msgid "Attachments"
msgstr ""
#: mediagoblin/templates/mediagoblin/edit/attachments.html:57
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:181
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:204
msgid "Add attachment"
msgstr ""
@@ -625,12 +653,22 @@ msgstr "Annuleren"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:63
#: mediagoblin/templates/mediagoblin/edit/edit.html:42
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:52
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:55
#: mediagoblin/templates/mediagoblin/edit/edit_collection.html:33
#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:40
msgid "Save changes"
msgstr "Wijzigingen opslaan"
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:28
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:38
+#, python-format
+msgid "Changing %(username)s's password"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:45
+msgid "Save"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:28
#, python-format
msgid "Really delete user '%(user_name)s' and all related media/comments?"
@@ -641,7 +679,7 @@ msgid "Yes, really delete my account"
msgstr ""
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:47
+#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:48
#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:49
msgid "Delete permanently"
msgstr "Permanent verwijderen"
@@ -658,7 +696,11 @@ msgstr "%(media_title)s aanpassen"
msgid "Changing %(username)s's account settings"
msgstr "%(username)ss accountinstellingen aanpassen"
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:59
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:46
+msgid "Change your password."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:62
msgid "Delete my account"
msgstr ""
@@ -683,6 +725,7 @@ msgstr "Media met het label: %(tag_name)s"
#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:56
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:65
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:136
#: mediagoblin/templates/mediagoblin/media_displays/video.html:55
msgid "Download"
@@ -707,6 +750,7 @@ msgid ""
msgstr "U kunt een moderne web-browser die \n\taudio kan afspelen vinden op <a href=\"http://getfirefox.com\">\n\t http://getfirefox.com</a>!"
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:60
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:71
#: mediagoblin/templates/mediagoblin/media_displays/video.html:61
msgid "Original file"
msgstr ""
@@ -715,6 +759,7 @@ msgstr ""
msgid "WebM file (Vorbis codec)"
msgstr ""
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:59
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:87
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:93
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:99
@@ -725,6 +770,10 @@ msgstr ""
msgid "Image for %(media_title)s"
msgstr "Afbeelding voor %(media_title)s"
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:79
+msgid "PDF file"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:112
msgid "Toggle Rotate"
msgstr ""
@@ -823,7 +872,7 @@ msgstr "Zeker weten dat je %(title)s wil verwijderen?"
msgid "Really remove %(media_title)s from %(collection_title)s?"
msgstr ""
-#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:53
+#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:54
msgid "Remove"
msgstr ""
@@ -866,24 +915,28 @@ msgstr "Media van <a href=\"%(user_url)s\"> %(username)s </a>"
msgid "â– Browsing media by <a href=\"%(user_url)s\">%(username)s</a>"
msgstr "â– Blader door media van <a href=\"%(user_url)s\">%(username)s</a>"
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:94
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:95
msgid "Add a comment"
msgstr "Geef een reactie"
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:102
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:104
msgid "Add this comment"
msgstr "Voeg dit bericht toe"
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:123
-msgid "at"
-msgstr "op"
-
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:144
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:132
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:152
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:164
#, python-format
-msgid ""
-"<h3>Added on</h3>\n"
-" <p>%(date)s</p>"
-msgstr "<h3>Toegevoegd op</h3>\n <p>%(date)s</p>"
+msgid "%(formatted_time)s ago"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:150
+msgid "Added"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:161
+msgid "Created"
+msgstr ""
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:28
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:40
@@ -1039,7 +1092,7 @@ msgstr "ouder"
msgid "Tagged with"
msgstr "Getagged met"
-#: mediagoblin/tools/exif.py:80
+#: mediagoblin/tools/exif.py:83
msgid "Could not read the image file."
msgstr "Kon het afbeeldingsbestand niet lezen."
@@ -1069,6 +1122,30 @@ msgid ""
" deleted."
msgstr ""
+#: mediagoblin/tools/timesince.py:62
+msgid "year"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:63
+msgid "month"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:64
+msgid "week"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:65
+msgid "day"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:66
+msgid "hour"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:67
+msgid "minute"
+msgstr ""
+
#: mediagoblin/user_pages/forms.py:23
msgid "Comment"
msgstr ""
@@ -1100,73 +1177,77 @@ msgstr ""
msgid "Include a note"
msgstr ""
-#: mediagoblin/user_pages/lib.py:56
+#: mediagoblin/user_pages/lib.py:58
msgid "commented on your post"
msgstr ""
-#: mediagoblin/user_pages/views.py:166
+#: mediagoblin/user_pages/views.py:169
+msgid "Sorry, comments are disabled."
+msgstr ""
+
+#: mediagoblin/user_pages/views.py:174
msgid "Oops, your comment was empty."
msgstr "Oeps, je bericht was leeg."
-#: mediagoblin/user_pages/views.py:172
+#: mediagoblin/user_pages/views.py:180
msgid "Your comment has been posted!"
msgstr "Je bericht is geplaatst!"
-#: mediagoblin/user_pages/views.py:197
+#: mediagoblin/user_pages/views.py:205
msgid "Please check your entries and try again."
msgstr ""
-#: mediagoblin/user_pages/views.py:237
+#: mediagoblin/user_pages/views.py:245
msgid "You have to select or add a collection"
msgstr ""
-#: mediagoblin/user_pages/views.py:248
+#: mediagoblin/user_pages/views.py:256
#, python-format
msgid "\"%s\" already in collection \"%s\""
msgstr ""
-#: mediagoblin/user_pages/views.py:264
+#: mediagoblin/user_pages/views.py:262
#, python-format
msgid "\"%s\" added to collection \"%s\""
msgstr ""
-#: mediagoblin/user_pages/views.py:286
+#: mediagoblin/user_pages/views.py:282
msgid "You deleted the media."
msgstr "Je hebt deze media verwijderd."
-#: mediagoblin/user_pages/views.py:293
+#: mediagoblin/user_pages/views.py:289
msgid "The media was not deleted because you didn't check that you were sure."
msgstr "Deze media was niet verwijderd omdat je niet hebt aangegeven dat je het zeker weet."
-#: mediagoblin/user_pages/views.py:301
+#: mediagoblin/user_pages/views.py:296
msgid "You are about to delete another user's media. Proceed with caution."
msgstr "Je staat op het punt de media van iemand anders te verwijderen. Pas op."
-#: mediagoblin/user_pages/views.py:375
+#: mediagoblin/user_pages/views.py:370
msgid "You deleted the item from the collection."
msgstr ""
-#: mediagoblin/user_pages/views.py:379
+#: mediagoblin/user_pages/views.py:374
msgid "The item was not removed because you didn't check that you were sure."
msgstr ""
-#: mediagoblin/user_pages/views.py:389
+#: mediagoblin/user_pages/views.py:382
msgid ""
"You are about to delete an item from another user's collection. Proceed with"
" caution."
msgstr ""
-#: mediagoblin/user_pages/views.py:422
+#: mediagoblin/user_pages/views.py:415
#, python-format
msgid "You deleted the collection \"%s\""
msgstr ""
-#: mediagoblin/user_pages/views.py:429
+#: mediagoblin/user_pages/views.py:422
msgid ""
"The collection was not deleted because you didn't check that you were sure."
msgstr ""
-#: mediagoblin/user_pages/views.py:439
+#: mediagoblin/user_pages/views.py:430
msgid ""
"You are about to delete another user's collection. Proceed with caution."
msgstr ""
diff --git a/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.mo
index f58e6a45..9cbd03b2 100644
--- a/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.mo
+++ b/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.mo
Binary files differ
diff --git a/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po
index 12d34b55..6a11d5da 100644
--- a/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po
+++ b/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po
@@ -3,14 +3,14 @@
# This file is distributed under the same license as the PROJECT project.
#
# Translators:
-# <odin.omdal@gmail.com>, 2013.
-# <odin.omdal@gmail.com>, 2011-2012.
+# velmont <odin.omdal@gmail.com>, 2013
+# velmont <odin.omdal@gmail.com>, 2011-2012
msgid ""
msgstr ""
"Project-Id-Version: GNU MediaGoblin\n"
"Report-Msgid-Bugs-To: http://issues.mediagoblin.org/\n"
-"POT-Creation-Date: 2013-03-04 18:04-0600\n"
-"PO-Revision-Date: 2013-03-10 13:31+0000\n"
+"POT-Creation-Date: 2013-05-27 13:54-0500\n"
+"PO-Revision-Date: 2013-05-31 15:40+0000\n"
"Last-Translator: velmont <odin.omdal@gmail.com>\n"
"Language-Team: Norwegian Nynorsk (Norway) (http://www.transifex.com/projects/p/mediagoblin/language/nn_NO/)\n"
"MIME-Version: 1.0\n"
@@ -20,34 +20,39 @@ msgstr ""
"Language: nn_NO\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: mediagoblin/auth/forms.py:28
-msgid "Invalid User name or email address."
-msgstr "Ugyldig brukarnamn eller passord."
-
-#: mediagoblin/auth/forms.py:29
-msgid "This field does not take email addresses."
-msgstr "Dette feltet tek ikkje epostadresser."
-
-#: mediagoblin/auth/forms.py:30
-msgid "This field requires an email address."
-msgstr "Dette feltet krev ei epostadresse."
-
-#: mediagoblin/auth/forms.py:52 mediagoblin/auth/forms.py:67
+#: mediagoblin/auth/forms.py:26
msgid "Username"
msgstr "Brukarnamn"
-#: mediagoblin/auth/forms.py:56 mediagoblin/auth/forms.py:71
+#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:45
+#: mediagoblin/tests/test_util.py:110
msgid "Password"
msgstr "Passord"
-#: mediagoblin/auth/forms.py:60
+#: mediagoblin/auth/forms.py:34
msgid "Email address"
msgstr "Epost"
-#: mediagoblin/auth/forms.py:78
+#: mediagoblin/auth/forms.py:41
+msgid "Username or Email"
+msgstr "Brukarnamn eller epost"
+
+#: mediagoblin/auth/forms.py:52
msgid "Username or email"
msgstr "Brukarnamn eller epost"
+#: mediagoblin/auth/tools.py:31
+msgid "Invalid User name or email address."
+msgstr "Ugyldig brukarnamn eller passord."
+
+#: mediagoblin/auth/tools.py:32
+msgid "This field does not take email addresses."
+msgstr "Dette feltet tek ikkje epostadresser."
+
+#: mediagoblin/auth/tools.py:33
+msgid "This field requires an email address."
+msgstr "Dette feltet krev ei epostadresse."
+
#: mediagoblin/auth/views.py:54
msgid "Sorry, registration is disabled on this instance."
msgstr "Registrering er slege av. Orsak."
@@ -60,54 +65,54 @@ msgstr "Ein konto med dette brukarnamnet finst allereide."
msgid "Sorry, a user with that email address already exists."
msgstr "Ein brukar med den epostadressa finst allereie."
-#: mediagoblin/auth/views.py:174
+#: mediagoblin/auth/views.py:182
msgid ""
"Your email address has been verified. You may now login, edit your profile, "
"and submit images!"
msgstr "Kontoen din er stadfesta. Du kan no logga inn, endra profilen din og lasta opp filer."
-#: mediagoblin/auth/views.py:180
+#: mediagoblin/auth/views.py:188
msgid "The verification key or user id is incorrect"
msgstr "Stadfestingsnykelen eller brukar-ID-en din er feil."
-#: mediagoblin/auth/views.py:198
+#: mediagoblin/auth/views.py:206
msgid "You must be logged in so we know who to send the email to!"
msgstr "Du må vera innlogga, slik me veit kven som skal ha eposten."
-#: mediagoblin/auth/views.py:206
+#: mediagoblin/auth/views.py:214
msgid "You've already verified your email address!"
msgstr "Du har allereie verifisiert epostadressa."
-#: mediagoblin/auth/views.py:219
+#: mediagoblin/auth/views.py:227
msgid "Resent your verification email."
msgstr "Send ein ny stadfestingsepost."
-#: mediagoblin/auth/views.py:250
+#: mediagoblin/auth/views.py:258
msgid ""
"If that email address (case sensitive!) is registered an email has been sent"
" with instructions on how to change your password."
msgstr "Dersom denne epostadressa er registrert, har ein epost med instruksjonar for å endra passord vorte sendt til han."
-#: mediagoblin/auth/views.py:261
+#: mediagoblin/auth/views.py:269
msgid "Couldn't find someone with that username."
msgstr "Fann ingen med det brukarnamnet."
-#: mediagoblin/auth/views.py:264
+#: mediagoblin/auth/views.py:272
msgid ""
"An email has been sent with instructions on how to change your password."
msgstr "Sender epost med instruksjonar for å endra passordet ditt."
-#: mediagoblin/auth/views.py:271
+#: mediagoblin/auth/views.py:279
msgid ""
"Could not send password recovery email as your username is inactive or your "
"account's email address has not been verified."
msgstr "Kunne ikkje senda epost. Brukarnamnet ditt er inaktivt eller uverifisert."
-#: mediagoblin/auth/views.py:328
+#: mediagoblin/auth/views.py:336
msgid "You can now log in using your new password."
msgstr "Du kan no logga inn med det nye passordet ditt."
-#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:93
+#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:82
#: mediagoblin/submit/forms.py:28 mediagoblin/submit/forms.py:47
#: mediagoblin/user_pages/forms.py:45
msgid "Title"
@@ -118,7 +123,7 @@ msgid "Description of this work"
msgstr "Skildring av verk"
#: mediagoblin/edit/forms.py:29 mediagoblin/edit/forms.py:52
-#: mediagoblin/edit/forms.py:97 mediagoblin/submit/forms.py:32
+#: mediagoblin/edit/forms.py:86 mediagoblin/submit/forms.py:32
#: mediagoblin/submit/forms.py:51 mediagoblin/user_pages/forms.py:49
msgid ""
"You can use\n"
@@ -134,11 +139,11 @@ msgstr "Merkelappar"
msgid "Separate tags by commas."
msgstr "Separer merkelappar med komma."
-#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:101
+#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:90
msgid "Slug"
msgstr "Nettnamn"
-#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:102
+#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:91
msgid "The slug can't be empty"
msgstr "Nettnamnet kan ikkje vera tomt"
@@ -166,45 +171,45 @@ msgid "This address contains errors"
msgstr "Adressa inneheld feil"
#: mediagoblin/edit/forms.py:63
-msgid "Old password"
-msgstr "Gamalt passort"
-
-#: mediagoblin/edit/forms.py:64
-msgid "Enter your old password to prove you own this account."
-msgstr "Skriv inn det gamle passordet ditt for å stadfesta at du eig denne kontoen."
-
-#: mediagoblin/edit/forms.py:67
-msgid "New password"
-msgstr "Nytt passord"
-
-#: mediagoblin/edit/forms.py:74
msgid "License preference"
msgstr "Lisens-val"
-#: mediagoblin/edit/forms.py:80
+#: mediagoblin/edit/forms.py:69
msgid "This will be your default license on upload forms."
msgstr "Dette vil vera standardvalet ditt for lisens."
-#: mediagoblin/edit/forms.py:82
+#: mediagoblin/edit/forms.py:71
msgid "Email me when others comment on my media"
msgstr "Send meg epost når andre kjem med innspel på verka mine."
-#: mediagoblin/edit/forms.py:94
+#: mediagoblin/edit/forms.py:83
msgid "The title can't be empty"
msgstr "Tittelen kjan ikkje vera tom"
-#: mediagoblin/edit/forms.py:96 mediagoblin/submit/forms.py:50
+#: mediagoblin/edit/forms.py:85 mediagoblin/submit/forms.py:50
#: mediagoblin/user_pages/forms.py:48
msgid "Description of this collection"
msgstr "Forklaringa til denne samlinga"
-#: mediagoblin/edit/forms.py:103
+#: mediagoblin/edit/forms.py:92
msgid ""
"The title part of this collection's address. You usually don't need to "
"change this."
msgstr "Tittel-delen av denne samlinga si adresse. Du treng normalt sett ikkje endra denne."
-#: mediagoblin/edit/views.py:66
+#: mediagoblin/edit/forms.py:99
+msgid "Old password"
+msgstr "Gamalt passort"
+
+#: mediagoblin/edit/forms.py:101
+msgid "Enter your old password to prove you own this account."
+msgstr "Skriv inn det gamle passordet ditt for å stadfesta at du eig denne kontoen."
+
+#: mediagoblin/edit/forms.py:104
+msgid "New password"
+msgstr "Nytt passord"
+
+#: mediagoblin/edit/views.py:67
msgid "An entry with that slug already exists for this user."
msgstr "Eit innlegg med denne adressetittelen finst allereie."
@@ -229,44 +234,63 @@ msgstr "Trå varsamt, du endrar nokon andre sin profil."
msgid "Profile changes saved"
msgstr "Lagra endring av profilen"
-#: mediagoblin/edit/views.py:241
-msgid "Wrong password"
-msgstr "Feil passord"
-
-#: mediagoblin/edit/views.py:252
+#: mediagoblin/edit/views.py:240
msgid "Account settings saved"
msgstr "Lagra kontoinstellingar"
-#: mediagoblin/edit/views.py:286
+#: mediagoblin/edit/views.py:274
msgid "You need to confirm the deletion of your account."
msgstr "Du må stadfesta slettinga av kontoen din."
-#: mediagoblin/edit/views.py:322 mediagoblin/submit/views.py:142
-#: mediagoblin/user_pages/views.py:214
+#: mediagoblin/edit/views.py:310 mediagoblin/submit/views.py:138
+#: mediagoblin/user_pages/views.py:222
#, python-format
msgid "You already have a collection called \"%s\"!"
msgstr "Du har allereie ei samling med namn «%s»."
-#: mediagoblin/edit/views.py:326
+#: mediagoblin/edit/views.py:314
msgid "A collection with that slug already exists for this user."
msgstr "Ei samling med den nettadressa finst allereie for denne brukaren."
-#: mediagoblin/edit/views.py:343
+#: mediagoblin/edit/views.py:329
msgid "You are editing another user's collection. Proceed with caution."
msgstr "Du endrar ein annan brukar si samling. Trå varsamt."
-#: mediagoblin/gmg_commands/theme.py:58
+#: mediagoblin/edit/views.py:348
+msgid "Wrong password"
+msgstr "Feil passord"
+
+#: mediagoblin/edit/views.py:363
+msgid "Your password was changed successfully"
+msgstr "Endra passord"
+
+#: mediagoblin/gmg_commands/assetlink.py:60
msgid "Cannot link theme... no theme set\n"
msgstr "Cannot link theme... no theme set\n"
-#: mediagoblin/gmg_commands/theme.py:71
+#: mediagoblin/gmg_commands/assetlink.py:73
msgid "No asset directory for this theme\n"
msgstr "No asset directory for this theme\n"
-#: mediagoblin/gmg_commands/theme.py:74
+#: mediagoblin/gmg_commands/assetlink.py:76
msgid "However, old link directory symlink found; removed.\n"
msgstr "However, old link directory symlink found; removed.\n"
+#: mediagoblin/gmg_commands/assetlink.py:112
+#, python-format
+msgid "Could not link \"%s\": %s exists and is not a symlink\n"
+msgstr "Kunne ikkje lenkja «%s»: %s eksisterer og er ikkje ei symlenkje\n"
+
+#: mediagoblin/gmg_commands/assetlink.py:119
+#, python-format
+msgid "Skipping \"%s\"; already set up.\n"
+msgstr "Hopper over «%s»: allereie satt opp.\n"
+
+#: mediagoblin/gmg_commands/assetlink.py:124
+#, python-format
+msgid "Old link found for \"%s\"; removing.\n"
+msgstr "Gamal lenkje funnen for «%s»; fjernar.\n"
+
#: mediagoblin/meddleware/csrf.py:134
msgid ""
"CSRF cookie not present. This is most likely the result of a cookie blocker "
@@ -274,12 +298,16 @@ msgid ""
"domain."
msgstr "Finn ikkje CSRF-cookien. Dette er truleg grunna ein cookie-blokkar.<br/>\nSjå til at du tillet cookies for dette domenet."
-#: mediagoblin/media_types/__init__.py:61
-#: mediagoblin/media_types/__init__.py:102
+#: mediagoblin/media_types/__init__.py:111
+#: mediagoblin/media_types/__init__.py:155
msgid "Sorry, I don't support that file type :("
msgstr "Orsak, stør ikkje den filtypen :("
-#: mediagoblin/media_types/video/processing.py:36
+#: mediagoblin/media_types/pdf/processing.py:136
+msgid "unoconv failing to run, check log file"
+msgstr "klarte ikkje køyra unoconv, sjekk logg-fil"
+
+#: mediagoblin/media_types/video/processing.py:37
msgid "Video transcoding failed"
msgstr "Skjedde noko gale med video transkodinga"
@@ -346,7 +374,7 @@ msgstr "Omdirigerings-URI-en for programmene. Denne feltet <strong>krevst</stron
msgid "This field is required for public clients"
msgstr "Dette feltet krevst for opne (public) klientar"
-#: mediagoblin/plugins/oauth/views.py:59
+#: mediagoblin/plugins/oauth/views.py:56
msgid "The client {0} has been registered!"
msgstr "Klienten {0} er registrert."
@@ -365,7 +393,7 @@ msgstr "Dine OAuth-klientar"
msgid "Add"
msgstr "Legg til"
-#: mediagoblin/processing/__init__.py:172
+#: mediagoblin/processing/__init__.py:193
msgid "Invalid file given for media type."
msgstr "Ugyldig fil for medietypen."
@@ -373,45 +401,45 @@ msgstr "Ugyldig fil for medietypen."
msgid "File"
msgstr "Fil"
-#: mediagoblin/submit/views.py:51
+#: mediagoblin/submit/views.py:49
msgid "You must provide a file."
msgstr "Du må velja ei fil."
-#: mediagoblin/submit/views.py:97
+#: mediagoblin/submit/views.py:93
msgid "Woohoo! Submitted!"
msgstr "Johoo! Opplasta!"
-#: mediagoblin/submit/views.py:146
+#: mediagoblin/submit/views.py:144
#, python-format
msgid "Collection \"%s\" added!"
msgstr "La til samlinga «%s»."
-#: mediagoblin/templates/mediagoblin/base.html:64
+#: mediagoblin/templates/mediagoblin/base.html:67
msgid "Verify your email!"
msgstr "Verifiser epostadressa di."
-#: mediagoblin/templates/mediagoblin/base.html:65
+#: mediagoblin/templates/mediagoblin/base.html:68
msgid "log out"
msgstr "Logg ut"
-#: mediagoblin/templates/mediagoblin/base.html:70
+#: mediagoblin/templates/mediagoblin/base.html:73
#: mediagoblin/templates/mediagoblin/auth/login.html:28
#: mediagoblin/templates/mediagoblin/auth/login.html:36
#: mediagoblin/templates/mediagoblin/auth/login.html:54
msgid "Log in"
msgstr "Logg inn"
-#: mediagoblin/templates/mediagoblin/base.html:79
+#: mediagoblin/templates/mediagoblin/base.html:82
#, python-format
msgid "<a href=\"%(user_url)s\">%(user_name)s</a>'s account"
msgstr "<a href=\"%(user_url)s\">%(user_name)s</a> sin konto"
-#: mediagoblin/templates/mediagoblin/base.html:86
+#: mediagoblin/templates/mediagoblin/base.html:89
msgid "Change account settings"
msgstr "Endra kontoinstellingar"
-#: mediagoblin/templates/mediagoblin/base.html:90
-#: mediagoblin/templates/mediagoblin/base.html:105
+#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:108
#: mediagoblin/templates/mediagoblin/admin/panel.html:21
#: mediagoblin/templates/mediagoblin/admin/panel.html:26
#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:21
@@ -419,72 +447,25 @@ msgstr "Endra kontoinstellingar"
msgid "Media processing panel"
msgstr "Verkprosesseringspanel"
-#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:96
msgid "Log out"
msgstr "Logg ut"
-#: mediagoblin/templates/mediagoblin/base.html:96
+#: mediagoblin/templates/mediagoblin/base.html:99
#: mediagoblin/templates/mediagoblin/user_pages/user.html:156
msgid "Add media"
msgstr "Legg til verk"
-#: mediagoblin/templates/mediagoblin/base.html:99
+#: mediagoblin/templates/mediagoblin/base.html:102
#: mediagoblin/templates/mediagoblin/user_pages/collection_list.html:41
msgid "Create new collection"
msgstr "Lag ny samling"
-#: mediagoblin/templates/mediagoblin/base.html:122
-#, python-format
-msgid ""
-"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
-"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
-msgstr "Drive av <a href=\"http://mediagoblin.org\" title='Version %(version)s'>MediaGoblin</a>, eit <a href=\"http://gnu.org/\">GNU</a>-prosjekt."
-
-#: mediagoblin/templates/mediagoblin/base.html:125
-#, python-format
-msgid ""
-"Released under the <a "
-"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
-"href=\"%(source_link)s\">Source code</a> available."
-msgstr "Lisensiert med <a href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a href=\"%(source_link)s\">Kjeldekode</a> er tilgjengeleg."
-
#: mediagoblin/templates/mediagoblin/error.html:24
msgid "Image of goblin stressing out"
msgstr "Bilete av stressa goblin"
-#: mediagoblin/templates/mediagoblin/root.html:31
-msgid "Explore"
-msgstr "Utforsk"
-
-#: mediagoblin/templates/mediagoblin/root.html:33
-msgid "Hi there, welcome to this MediaGoblin site!"
-msgstr "Heihei, velkomen til denne MediaGoblin-sida."
-
-#: mediagoblin/templates/mediagoblin/root.html:35
-msgid ""
-"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
-"extraordinarily great piece of media hosting software."
-msgstr "Denne sida køyrer <a href=\"http://mediagoblin.org\">MediaGoblin</a>, eit superbra program for å visa fram dine kreative verk."
-
-#: mediagoblin/templates/mediagoblin/root.html:36
-msgid ""
-"To add your own media, place comments, and more, you can log in with your "
-"MediaGoblin account."
-msgstr "Vil du leggja til eigne verk og innpel, so må du logga inn."
-
-#: mediagoblin/templates/mediagoblin/root.html:38
-msgid "Don't have one yet? It's easy!"
-msgstr "Har du ikkje ein enno? Det er enkelt!"
-
-#: mediagoblin/templates/mediagoblin/root.html:39
-#, python-format
-msgid ""
-"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
-" or\n"
-" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
-msgstr "<a class=\"button_action_highlight\" href=\"%(register_url)s\">Opprett ein konto på denne sida</a> eller <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">set opp MediaGoblin på eigen tenar</a>"
-
-#: mediagoblin/templates/mediagoblin/root.html:47
+#: mediagoblin/templates/mediagoblin/root.html:32
msgid "Most recent media"
msgstr "Nyaste verk"
@@ -590,6 +571,53 @@ msgid ""
"%(verification_url)s"
msgstr "Hei %(username)s,\n\nopna fylgjande netadresse i netlesaren din for å aktivera kontoen din:\n\n%(verification_url)s"
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:21
+#, python-format
+msgid ""
+"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
+"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
+msgstr "Drive av <a href=\"http://mediagoblin.org\" title='Version %(version)s'>MediaGoblin</a>, eit <a href=\"http://gnu.org/\">GNU</a>-prosjekt."
+
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:24
+#, python-format
+msgid ""
+"Released under the <a "
+"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
+"href=\"%(source_link)s\">Source code</a> available."
+msgstr "Lisensiert med <a href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a href=\"%(source_link)s\">Kjeldekode</a> er tilgjengeleg."
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:20
+msgid "Explore"
+msgstr "Utforsk"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:22
+msgid "Hi there, welcome to this MediaGoblin site!"
+msgstr "Heihei, velkomen til denne MediaGoblin-sida."
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:24
+msgid ""
+"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
+"extraordinarily great piece of media hosting software."
+msgstr "Denne sida køyrer <a href=\"http://mediagoblin.org\">MediaGoblin</a>, eit superbra program for å visa fram dine kreative verk."
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:25
+msgid ""
+"To add your own media, place comments, and more, you can log in with your "
+"MediaGoblin account."
+msgstr "Vil du leggja til eigne verk og innpel, so må du logga inn."
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:27
+msgid "Don't have one yet? It's easy!"
+msgstr "Har du ikkje ein enno? Det er enkelt!"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:28
+#, python-format
+msgid ""
+"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
+" or\n"
+" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
+msgstr "<a class=\"button_action_highlight\" href=\"%(register_url)s\">Opprett ein konto på denne sida</a>\n eller\n <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set opp din eigen MediaGoblin-server</a>"
+
#: mediagoblin/templates/mediagoblin/bits/logo.html:23
#: mediagoblin/themes/airy/templates/mediagoblin/bits/logo.html:23
msgid "MediaGoblin logo"
@@ -602,13 +630,13 @@ msgid "Editing attachments for %(media_title)s"
msgstr "Endrar vedlegg for %(media_title)s"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:159
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:175
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:182
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:198
msgid "Attachments"
msgstr "Vedlegg"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:57
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:181
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:204
msgid "Add attachment"
msgstr "Legg ved vedlegg"
@@ -625,12 +653,22 @@ msgstr "Bryt av"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:63
#: mediagoblin/templates/mediagoblin/edit/edit.html:42
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:52
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:55
#: mediagoblin/templates/mediagoblin/edit/edit_collection.html:33
#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:40
msgid "Save changes"
msgstr "Lagra"
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:28
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:38
+#, python-format
+msgid "Changing %(username)s's password"
+msgstr "Endrar passordet til %(username)s"
+
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:45
+msgid "Save"
+msgstr "Lagra"
+
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:28
#, python-format
msgid "Really delete user '%(user_name)s' and all related media/comments?"
@@ -641,7 +679,7 @@ msgid "Yes, really delete my account"
msgstr "Ja, slett kontoen min"
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:47
+#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:48
#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:49
msgid "Delete permanently"
msgstr "Slett permanent"
@@ -658,7 +696,11 @@ msgstr "Endrar %(media_title)s"
msgid "Changing %(username)s's account settings"
msgstr "Endrar kontoinnstellingane til %(username)s"
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:59
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:46
+msgid "Change your password."
+msgstr "Endra passordet ditt."
+
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:62
msgid "Delete my account"
msgstr "Slett kontoen min"
@@ -683,6 +725,7 @@ msgstr "Verk merka med: %(tag_name)s"
#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:56
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:65
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:136
#: mediagoblin/templates/mediagoblin/media_displays/video.html:55
msgid "Download"
@@ -707,6 +750,7 @@ msgid ""
msgstr "Du kan skaffa ein moderne netlesar som kan spela av dette lydklippet hjå <a href=\"http://opera.com/download\">http://opera.com/download</a>."
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:60
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:71
#: mediagoblin/templates/mediagoblin/media_displays/video.html:61
msgid "Original file"
msgstr "Opphavleg fil"
@@ -715,6 +759,7 @@ msgstr "Opphavleg fil"
msgid "WebM file (Vorbis codec)"
msgstr "WebM-fil (Vorbis-kodek)"
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:59
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:87
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:93
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:99
@@ -725,6 +770,10 @@ msgstr "WebM-fil (Vorbis-kodek)"
msgid "Image for %(media_title)s"
msgstr "Bilete for %(media_title)s"
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:79
+msgid "PDF file"
+msgstr "PDF-fil"
+
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:112
msgid "Toggle Rotate"
msgstr "Slå av/på rotering"
@@ -823,7 +872,7 @@ msgstr "Vil du verkeleg sletta %(title)s?"
msgid "Really remove %(media_title)s from %(collection_title)s?"
msgstr "Fjerna %(media_title)s frå %(collection_title)s?"
-#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:53
+#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:54
msgid "Remove"
msgstr "Fjern"
@@ -866,24 +915,28 @@ msgstr "<a href=\"%(user_url)s\">%(username)s</a> sine verk"
msgid "â– Browsing media by <a href=\"%(user_url)s\">%(username)s</a>"
msgstr "■Ser på <a href=\"%(user_url)s\">%(username)s</a> sine verk"
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:94
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:95
msgid "Add a comment"
msgstr "Legg att innspel"
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:102
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:104
msgid "Add this comment"
msgstr "Legg til dette innspelet"
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:123
-msgid "at"
-msgstr "hjå"
-
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:144
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:132
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:152
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:164
#, python-format
-msgid ""
-"<h3>Added on</h3>\n"
-" <p>%(date)s</p>"
-msgstr "<h3>Lagt til</h3>\n <p>%(date)s</p>"
+msgid "%(formatted_time)s ago"
+msgstr "%(formatted_time)s sidan"
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:150
+msgid "Added"
+msgstr "Lagt til"
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:161
+msgid "Created"
+msgstr "Oppretta"
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:28
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:40
@@ -1039,7 +1092,7 @@ msgstr "eldre"
msgid "Tagged with"
msgstr "Merka med"
-#: mediagoblin/tools/exif.py:80
+#: mediagoblin/tools/exif.py:83
msgid "Could not read the image file."
msgstr "Klarte ikkje lesa biletefila."
@@ -1069,6 +1122,30 @@ msgid ""
" deleted."
msgstr "Ser ikkje ut til å finnast noko her. Orsak.</p>\n<p>Dersom du er sikker på at adressa finst, so er ho truleg flytta eller sletta."
+#: mediagoblin/tools/timesince.py:62
+msgid "year"
+msgstr "Ã¥r"
+
+#: mediagoblin/tools/timesince.py:63
+msgid "month"
+msgstr "månad"
+
+#: mediagoblin/tools/timesince.py:64
+msgid "week"
+msgstr "veke"
+
+#: mediagoblin/tools/timesince.py:65
+msgid "day"
+msgstr "dag"
+
+#: mediagoblin/tools/timesince.py:66
+msgid "hour"
+msgstr "time"
+
+#: mediagoblin/tools/timesince.py:67
+msgid "minute"
+msgstr "minutt"
+
#: mediagoblin/user_pages/forms.py:23
msgid "Comment"
msgstr "Innspel"
@@ -1100,73 +1177,77 @@ msgstr "-- Vel --"
msgid "Include a note"
msgstr "Legg ved eit notat"
-#: mediagoblin/user_pages/lib.py:56
+#: mediagoblin/user_pages/lib.py:58
msgid "commented on your post"
msgstr "kom med innspel på innlegget ditt"
-#: mediagoblin/user_pages/views.py:166
+#: mediagoblin/user_pages/views.py:169
+msgid "Sorry, comments are disabled."
+msgstr "Innspel er avslege"
+
+#: mediagoblin/user_pages/views.py:174
msgid "Oops, your comment was empty."
msgstr "Vops, innspelet ditt var tomt."
-#: mediagoblin/user_pages/views.py:172
+#: mediagoblin/user_pages/views.py:180
msgid "Your comment has been posted!"
msgstr "Innspelet ditt er lagt til."
-#: mediagoblin/user_pages/views.py:197
+#: mediagoblin/user_pages/views.py:205
msgid "Please check your entries and try again."
msgstr "Sjekk filene dine og prøv omatt."
-#: mediagoblin/user_pages/views.py:237
+#: mediagoblin/user_pages/views.py:245
msgid "You have to select or add a collection"
msgstr "Du må velja eller laga ei samling"
-#: mediagoblin/user_pages/views.py:248
+#: mediagoblin/user_pages/views.py:256
#, python-format
msgid "\"%s\" already in collection \"%s\""
msgstr "«%s» er allereie i samling «%s»"
-#: mediagoblin/user_pages/views.py:264
+#: mediagoblin/user_pages/views.py:262
#, python-format
msgid "\"%s\" added to collection \"%s\""
msgstr "«%s» lagt til samling «%s»"
-#: mediagoblin/user_pages/views.py:286
+#: mediagoblin/user_pages/views.py:282
msgid "You deleted the media."
msgstr "Du sletta verket."
-#: mediagoblin/user_pages/views.py:293
+#: mediagoblin/user_pages/views.py:289
msgid "The media was not deleted because you didn't check that you were sure."
msgstr "Sletta ikkje verket."
-#: mediagoblin/user_pages/views.py:301
+#: mediagoblin/user_pages/views.py:296
msgid "You are about to delete another user's media. Proceed with caution."
msgstr "Du er i ferd med å sletta ein annan brukar sine verk. Trå varsamt."
-#: mediagoblin/user_pages/views.py:375
+#: mediagoblin/user_pages/views.py:370
msgid "You deleted the item from the collection."
msgstr "Du fjerna fila frå samlinga."
-#: mediagoblin/user_pages/views.py:379
+#: mediagoblin/user_pages/views.py:374
msgid "The item was not removed because you didn't check that you were sure."
msgstr "Fila var ikkje fjerna fordi du ikkje var sikker."
-#: mediagoblin/user_pages/views.py:389
+#: mediagoblin/user_pages/views.py:382
msgid ""
"You are about to delete an item from another user's collection. Proceed with"
" caution."
msgstr "Du er i ferd med å fjerna ei fil frå ein annan brukar si samling. Trå varsamt."
-#: mediagoblin/user_pages/views.py:422
+#: mediagoblin/user_pages/views.py:415
#, python-format
msgid "You deleted the collection \"%s\""
msgstr "Samlinga «%s» sletta"
-#: mediagoblin/user_pages/views.py:429
+#: mediagoblin/user_pages/views.py:422
msgid ""
"The collection was not deleted because you didn't check that you were sure."
msgstr "Sletta ikkje samlinga."
-#: mediagoblin/user_pages/views.py:439
+#: mediagoblin/user_pages/views.py:430
msgid ""
"You are about to delete another user's collection. Proceed with caution."
msgstr "Du er i ferd med å sletta ein annan brukar si samling. Trå varsamt."
diff --git a/mediagoblin/i18n/pl/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/pl/LC_MESSAGES/mediagoblin.mo
index ea905b61..8b318329 100644
--- a/mediagoblin/i18n/pl/LC_MESSAGES/mediagoblin.mo
+++ b/mediagoblin/i18n/pl/LC_MESSAGES/mediagoblin.mo
Binary files differ
diff --git a/mediagoblin/i18n/pl/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/pl/LC_MESSAGES/mediagoblin.po
index 9edf8e2b..78ab219a 100644
--- a/mediagoblin/i18n/pl/LC_MESSAGES/mediagoblin.po
+++ b/mediagoblin/i18n/pl/LC_MESSAGES/mediagoblin.po
@@ -3,15 +3,16 @@
# This file is distributed under the same license as the PROJECT project.
#
# Translators:
-# Daniel Koć <kocio@aster.pl>, 2012.
+# Daniel Koć <kocio@aster.pl>, 2012
+# Sergiusz Pawlowicz <transifex@pawlowicz.name>, 2013
msgid ""
msgstr ""
"Project-Id-Version: GNU MediaGoblin\n"
"Report-Msgid-Bugs-To: http://issues.mediagoblin.org/\n"
-"POT-Creation-Date: 2013-03-04 18:04-0600\n"
-"PO-Revision-Date: 2013-03-05 00:04+0000\n"
-"Last-Translator: cwebber <cwebber@dustycloud.org>\n"
-"Language-Team: LANGUAGE <LL@li.org>\n"
+"POT-Creation-Date: 2013-05-27 13:54-0500\n"
+"PO-Revision-Date: 2013-05-28 13:51+0000\n"
+"Last-Translator: Sergiusz Pawlowicz <transifex@pawlowicz.name>\n"
+"Language-Team: Polish (http://www.transifex.com/projects/p/mediagoblin/language/pl/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
@@ -19,34 +20,39 @@ msgstr ""
"Language: pl\n"
"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
-#: mediagoblin/auth/forms.py:28
-msgid "Invalid User name or email address."
-msgstr ""
-
-#: mediagoblin/auth/forms.py:29
-msgid "This field does not take email addresses."
-msgstr ""
-
-#: mediagoblin/auth/forms.py:30
-msgid "This field requires an email address."
-msgstr ""
-
-#: mediagoblin/auth/forms.py:52 mediagoblin/auth/forms.py:67
+#: mediagoblin/auth/forms.py:26
msgid "Username"
msgstr "Użytkownik"
-#: mediagoblin/auth/forms.py:56 mediagoblin/auth/forms.py:71
+#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:45
+#: mediagoblin/tests/test_util.py:110
msgid "Password"
msgstr "Hasło"
-#: mediagoblin/auth/forms.py:60
+#: mediagoblin/auth/forms.py:34
msgid "Email address"
msgstr "Adres e-mail"
-#: mediagoblin/auth/forms.py:78
+#: mediagoblin/auth/forms.py:41
+msgid "Username or Email"
+msgstr "Nazwa konta lub adres poczty elektronicznej"
+
+#: mediagoblin/auth/forms.py:52
msgid "Username or email"
msgstr "Użytkownik lub adres e-mail"
+#: mediagoblin/auth/tools.py:31
+msgid "Invalid User name or email address."
+msgstr "Nieprawidłowa nazwa konta albo niewłaściwy adres poczty elektronicznej."
+
+#: mediagoblin/auth/tools.py:32
+msgid "This field does not take email addresses."
+msgstr "Niniejsze pole nie jest przeznaczone na adres poczty elektronicznej."
+
+#: mediagoblin/auth/tools.py:33
+msgid "This field requires an email address."
+msgstr "Niniejsze pole wymaga podania adresu poczty elektronicznej."
+
#: mediagoblin/auth/views.py:54
msgid "Sorry, registration is disabled on this instance."
msgstr "Niestety rejestracja w tym serwisie jest wyłączona."
@@ -59,54 +65,54 @@ msgstr "Niestety użytkownik o takiej nazwie już istnieje."
msgid "Sorry, a user with that email address already exists."
msgstr "Niestety użytkownik z tym adresem e-mail już istnieje."
-#: mediagoblin/auth/views.py:174
+#: mediagoblin/auth/views.py:182
msgid ""
"Your email address has been verified. You may now login, edit your profile, "
"and submit images!"
msgstr "Twój adres e-mail został zweryfikowany. Możesz się teraz zalogować, wypełnić opis swojego profilu i wysyłać grafiki!"
-#: mediagoblin/auth/views.py:180
+#: mediagoblin/auth/views.py:188
msgid "The verification key or user id is incorrect"
msgstr "Nieprawidłowy klucz weryfikacji lub identyfikator użytkownika."
-#: mediagoblin/auth/views.py:198
+#: mediagoblin/auth/views.py:206
msgid "You must be logged in so we know who to send the email to!"
msgstr "Musisz się zalogować żebyśmy wiedzieli do kogo wysłać e-mail!"
-#: mediagoblin/auth/views.py:206
+#: mediagoblin/auth/views.py:214
msgid "You've already verified your email address!"
msgstr "Twój adres e-mail już został zweryfikowany!"
-#: mediagoblin/auth/views.py:219
+#: mediagoblin/auth/views.py:227
msgid "Resent your verification email."
msgstr "Wyślij ponownie e-mail weryfikujący."
-#: mediagoblin/auth/views.py:250
+#: mediagoblin/auth/views.py:258
msgid ""
"If that email address (case sensitive!) is registered an email has been sent"
" with instructions on how to change your password."
-msgstr ""
+msgstr "Jeśli ten adres poczty elektronicznej istnieje (uwzględniając wielkość liter!), wysłano na niego list z instrukcją, w jaki sposób możesz zmienić swoje hasło."
-#: mediagoblin/auth/views.py:261
+#: mediagoblin/auth/views.py:269
msgid "Couldn't find someone with that username."
-msgstr ""
+msgstr "Nie potrafię znaleźć nikogo o tej nazwie użytkownika."
-#: mediagoblin/auth/views.py:264
+#: mediagoblin/auth/views.py:272
msgid ""
"An email has been sent with instructions on how to change your password."
msgstr "Wysłano e-mail z instrukcjami jak zmienić hasło."
-#: mediagoblin/auth/views.py:271
+#: mediagoblin/auth/views.py:279
msgid ""
"Could not send password recovery email as your username is inactive or your "
"account's email address has not been verified."
msgstr "Nie udało się wysłać e-maila w celu odzyskania hasła, ponieważ twoje konto jest nieaktywne lub twój adres e-mail nie został zweryfikowany."
-#: mediagoblin/auth/views.py:328
+#: mediagoblin/auth/views.py:336
msgid "You can now log in using your new password."
-msgstr "Teraz możesz się zalogować używając nowe hasło."
+msgstr "Teraz możesz się zalogować używając nowego hasła."
-#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:93
+#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:82
#: mediagoblin/submit/forms.py:28 mediagoblin/submit/forms.py:47
#: mediagoblin/user_pages/forms.py:45
msgid "Title"
@@ -117,7 +123,7 @@ msgid "Description of this work"
msgstr "Opis tej pracy"
#: mediagoblin/edit/forms.py:29 mediagoblin/edit/forms.py:52
-#: mediagoblin/edit/forms.py:97 mediagoblin/submit/forms.py:32
+#: mediagoblin/edit/forms.py:86 mediagoblin/submit/forms.py:32
#: mediagoblin/submit/forms.py:51 mediagoblin/user_pages/forms.py:49
msgid ""
"You can use\n"
@@ -133,11 +139,11 @@ msgstr "Znaczniki"
msgid "Separate tags by commas."
msgstr "Rozdzielaj znaczniki przecinkami."
-#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:101
+#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:90
msgid "Slug"
msgstr "Slug"
-#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:102
+#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:91
msgid "The slug can't be empty"
msgstr "Slug nie może być pusty"
@@ -165,45 +171,45 @@ msgid "This address contains errors"
msgstr "Ten adres zawiera błędy"
#: mediagoblin/edit/forms.py:63
-msgid "Old password"
-msgstr "Stare hasło"
-
-#: mediagoblin/edit/forms.py:64
-msgid "Enter your old password to prove you own this account."
-msgstr "Wprowadź swoje stare hasło aby udowodnić, że to twoje konto."
-
-#: mediagoblin/edit/forms.py:67
-msgid "New password"
-msgstr "Nowe hasło"
-
-#: mediagoblin/edit/forms.py:74
msgid "License preference"
-msgstr ""
+msgstr "Ulubiona licencja"
-#: mediagoblin/edit/forms.py:80
+#: mediagoblin/edit/forms.py:69
msgid "This will be your default license on upload forms."
-msgstr ""
+msgstr "To będzie twoja domyślna licencja dla wgrywanych mediów."
-#: mediagoblin/edit/forms.py:82
+#: mediagoblin/edit/forms.py:71
msgid "Email me when others comment on my media"
msgstr "Powiadamiaj mnie e-mailem o komentarzach do moich mediów"
-#: mediagoblin/edit/forms.py:94
+#: mediagoblin/edit/forms.py:83
msgid "The title can't be empty"
msgstr "Tytuł nie może być pusty"
-#: mediagoblin/edit/forms.py:96 mediagoblin/submit/forms.py:50
+#: mediagoblin/edit/forms.py:85 mediagoblin/submit/forms.py:50
#: mediagoblin/user_pages/forms.py:48
msgid "Description of this collection"
msgstr "Opis tej kolekcji"
-#: mediagoblin/edit/forms.py:103
+#: mediagoblin/edit/forms.py:92
msgid ""
"The title part of this collection's address. You usually don't need to "
"change this."
msgstr "Część adresu zawierająca tytuł. Zwykle nie musisz tego zmieniać."
-#: mediagoblin/edit/views.py:66
+#: mediagoblin/edit/forms.py:99
+msgid "Old password"
+msgstr "Stare hasło"
+
+#: mediagoblin/edit/forms.py:101
+msgid "Enter your old password to prove you own this account."
+msgstr "Wprowadź swoje stare hasło aby udowodnić, że to twoje konto."
+
+#: mediagoblin/edit/forms.py:104
+msgid "New password"
+msgstr "Nowe hasło"
+
+#: mediagoblin/edit/views.py:67
msgid "An entry with that slug already exists for this user."
msgstr "Adres z tym slugiem dla tego użytkownika już istnieje."
@@ -214,11 +220,11 @@ msgstr "Edytujesz media innego użytkownika. Zachowaj ostrożność."
#: mediagoblin/edit/views.py:155
#, python-format
msgid "You added the attachment %s!"
-msgstr ""
+msgstr "Dodałeś załącznik %s!"
#: mediagoblin/edit/views.py:182
msgid "You can only edit your own profile."
-msgstr ""
+msgstr "Masz możliwość edycji tylko własnego profilu."
#: mediagoblin/edit/views.py:188
msgid "You are editing a user's profile. Proceed with caution."
@@ -228,57 +234,80 @@ msgstr "Edytujesz profil innego użytkownika. Zachowaj ostrożność."
msgid "Profile changes saved"
msgstr "Zapisano zmiany profilu"
-#: mediagoblin/edit/views.py:241
-msgid "Wrong password"
-msgstr "Nieprawidłowe hasło"
-
-#: mediagoblin/edit/views.py:252
+#: mediagoblin/edit/views.py:240
msgid "Account settings saved"
msgstr "Zapisano ustawienia konta"
-#: mediagoblin/edit/views.py:286
+#: mediagoblin/edit/views.py:274
msgid "You need to confirm the deletion of your account."
-msgstr ""
+msgstr "Musisz potwierdzić, że chcesz skasować swoje konto."
-#: mediagoblin/edit/views.py:322 mediagoblin/submit/views.py:142
-#: mediagoblin/user_pages/views.py:214
+#: mediagoblin/edit/views.py:310 mediagoblin/submit/views.py:138
+#: mediagoblin/user_pages/views.py:222
#, python-format
msgid "You already have a collection called \"%s\"!"
msgstr "Kolekcja \"%s\" już istnieje!"
-#: mediagoblin/edit/views.py:326
+#: mediagoblin/edit/views.py:314
msgid "A collection with that slug already exists for this user."
msgstr "Kolekcja tego użytkownika z takim slugiem już istnieje."
-#: mediagoblin/edit/views.py:343
+#: mediagoblin/edit/views.py:329
msgid "You are editing another user's collection. Proceed with caution."
msgstr "Edytujesz kolekcję innego użytkownika. Zachowaj ostrożność."
-#: mediagoblin/gmg_commands/theme.py:58
+#: mediagoblin/edit/views.py:348
+msgid "Wrong password"
+msgstr "Nieprawidłowe hasło"
+
+#: mediagoblin/edit/views.py:363
+msgid "Your password was changed successfully"
+msgstr "Twoje hasło zostało zmienione"
+
+#: mediagoblin/gmg_commands/assetlink.py:60
msgid "Cannot link theme... no theme set\n"
msgstr "Nie można podlinkować motywu... nie wybrano motywu\n"
-#: mediagoblin/gmg_commands/theme.py:71
+#: mediagoblin/gmg_commands/assetlink.py:73
msgid "No asset directory for this theme\n"
msgstr "Brak katalogu danych dla tego motywu\n"
-#: mediagoblin/gmg_commands/theme.py:74
+#: mediagoblin/gmg_commands/assetlink.py:76
msgid "However, old link directory symlink found; removed.\n"
msgstr "Znaleziono stary odnośnik symboliczny do katalogu; usunięto.\n"
+#: mediagoblin/gmg_commands/assetlink.py:112
+#, python-format
+msgid "Could not link \"%s\": %s exists and is not a symlink\n"
+msgstr "Nie mogę zrobić odnośnika \"%s\": %s istnieje i nie jest odnośnikiem\n"
+
+#: mediagoblin/gmg_commands/assetlink.py:119
+#, python-format
+msgid "Skipping \"%s\"; already set up.\n"
+msgstr "Opuszczam \"%s\"; już jest gotowe.\n"
+
+#: mediagoblin/gmg_commands/assetlink.py:124
+#, python-format
+msgid "Old link found for \"%s\"; removing.\n"
+msgstr "Znaleziono stary odnośnik dla \"%s\"; usuwam.\n"
+
#: mediagoblin/meddleware/csrf.py:134
msgid ""
"CSRF cookie not present. This is most likely the result of a cookie blocker "
"or somesuch.<br/>Make sure to permit the settings of cookies for this "
"domain."
-msgstr ""
+msgstr "Ciasteczko CSFR nie jest dostępne. Najprawdopodobniej stosujesz jakąś formę blokowania ciasteczek.<br/>Upewnij się, że nasz serwer może zakładać ciasteczka w twojej przeglądarce."
-#: mediagoblin/media_types/__init__.py:61
-#: mediagoblin/media_types/__init__.py:102
+#: mediagoblin/media_types/__init__.py:111
+#: mediagoblin/media_types/__init__.py:155
msgid "Sorry, I don't support that file type :("
msgstr "NIestety, nie obsługujemy tego typu plików :-("
-#: mediagoblin/media_types/video/processing.py:36
+#: mediagoblin/media_types/pdf/processing.py:136
+msgid "unoconv failing to run, check log file"
+msgstr "nie dało się uruchomić unoconv, sprawdź log"
+
+#: mediagoblin/media_types/video/processing.py:37
msgid "Video transcoding failed"
msgstr "Konwersja wideo nie powiodła się"
@@ -315,7 +344,7 @@ msgstr "Opis"
msgid ""
"This will be visible to users allowing your\n"
" application to authenticate as them."
-msgstr ""
+msgstr "To będzie widoczne dla użytkowników, pozwalając⎠twojej aplikacji uwierzytelniać się jako oni."
#: mediagoblin/plugins/oauth/forms.py:40
msgid "Type"
@@ -345,17 +374,17 @@ msgstr "Przekierowanie URI dla aplikacji, to pole\n jest <strong>wyma
msgid "This field is required for public clients"
msgstr "To pole jest wymagane dla klientów publicznych"
-#: mediagoblin/plugins/oauth/views.py:59
+#: mediagoblin/plugins/oauth/views.py:56
msgid "The client {0} has been registered!"
msgstr "Klient {0} został zarejestrowany!"
#: mediagoblin/plugins/oauth/templates/oauth/client/connections.html:22
msgid "OAuth client connections"
-msgstr ""
+msgstr "Połączenia do OAuth"
#: mediagoblin/plugins/oauth/templates/oauth/client/list.html:22
msgid "Your OAuth clients"
-msgstr ""
+msgstr "Twoi klienci OAuth"
#: mediagoblin/plugins/oauth/templates/oauth/client/register.html:29
#: mediagoblin/templates/mediagoblin/submit/collection.html:30
@@ -364,7 +393,7 @@ msgstr ""
msgid "Add"
msgstr "Dodaj"
-#: mediagoblin/processing/__init__.py:172
+#: mediagoblin/processing/__init__.py:193
msgid "Invalid file given for media type."
msgstr "Niewłaściwy plik dla tego rodzaju mediów."
@@ -372,45 +401,45 @@ msgstr "Niewłaściwy plik dla tego rodzaju mediów."
msgid "File"
msgstr "Plik"
-#: mediagoblin/submit/views.py:51
+#: mediagoblin/submit/views.py:49
msgid "You must provide a file."
msgstr "Musisz podać plik."
-#: mediagoblin/submit/views.py:97
+#: mediagoblin/submit/views.py:93
msgid "Woohoo! Submitted!"
msgstr "Hura! Wysłano!"
-#: mediagoblin/submit/views.py:146
+#: mediagoblin/submit/views.py:144
#, python-format
msgid "Collection \"%s\" added!"
msgstr "Kolekcja \"%s\" została dodana!"
-#: mediagoblin/templates/mediagoblin/base.html:64
+#: mediagoblin/templates/mediagoblin/base.html:67
msgid "Verify your email!"
msgstr "Zweryfikuj swój adres e-mail!"
-#: mediagoblin/templates/mediagoblin/base.html:65
+#: mediagoblin/templates/mediagoblin/base.html:68
msgid "log out"
-msgstr ""
+msgstr "wyloguj siÄ™"
-#: mediagoblin/templates/mediagoblin/base.html:70
+#: mediagoblin/templates/mediagoblin/base.html:73
#: mediagoblin/templates/mediagoblin/auth/login.html:28
#: mediagoblin/templates/mediagoblin/auth/login.html:36
#: mediagoblin/templates/mediagoblin/auth/login.html:54
msgid "Log in"
msgstr "Zaloguj siÄ™"
-#: mediagoblin/templates/mediagoblin/base.html:79
+#: mediagoblin/templates/mediagoblin/base.html:82
#, python-format
msgid "<a href=\"%(user_url)s\">%(user_name)s</a>'s account"
-msgstr ""
+msgstr "konto <a href=\"%(user_url)s\">%(user_name)s</a>"
-#: mediagoblin/templates/mediagoblin/base.html:86
+#: mediagoblin/templates/mediagoblin/base.html:89
msgid "Change account settings"
msgstr "Zmień ustawienia konta"
-#: mediagoblin/templates/mediagoblin/base.html:90
-#: mediagoblin/templates/mediagoblin/base.html:105
+#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:108
#: mediagoblin/templates/mediagoblin/admin/panel.html:21
#: mediagoblin/templates/mediagoblin/admin/panel.html:26
#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:21
@@ -418,72 +447,25 @@ msgstr "Zmień ustawienia konta"
msgid "Media processing panel"
msgstr "Panel przetwarzania mediów"
-#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:96
msgid "Log out"
-msgstr ""
+msgstr "Wyloguj siÄ™"
-#: mediagoblin/templates/mediagoblin/base.html:96
+#: mediagoblin/templates/mediagoblin/base.html:99
#: mediagoblin/templates/mediagoblin/user_pages/user.html:156
msgid "Add media"
msgstr "Dodaj media"
-#: mediagoblin/templates/mediagoblin/base.html:99
+#: mediagoblin/templates/mediagoblin/base.html:102
#: mediagoblin/templates/mediagoblin/user_pages/collection_list.html:41
msgid "Create new collection"
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/base.html:122
-#, python-format
-msgid ""
-"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
-"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/base.html:125
-#, python-format
-msgid ""
-"Released under the <a "
-"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
-"href=\"%(source_link)s\">Source code</a> available."
-msgstr "Opublikowane na licencji <a href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. Dostępny jest <a href=\"%(source_link)s\">kod źródłowy</a>."
+msgstr "Utwórz nową kolekcję"
#: mediagoblin/templates/mediagoblin/error.html:24
msgid "Image of goblin stressing out"
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:31
-msgid "Explore"
-msgstr "Odkrywaj"
+msgstr "Grafika zestresowanego goblina"
-#: mediagoblin/templates/mediagoblin/root.html:33
-msgid "Hi there, welcome to this MediaGoblin site!"
-msgstr "Cześć, witaj na stronie MediaGoblin!"
-
-#: mediagoblin/templates/mediagoblin/root.html:35
-msgid ""
-"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
-"extraordinarily great piece of media hosting software."
-msgstr "Ten serwis działa w oparciu o <a href=\"http://mediagoblin.org\">MediaGoblin</a>, świetne oprogramowanie do publikowania mediów."
-
-#: mediagoblin/templates/mediagoblin/root.html:36
-msgid ""
-"To add your own media, place comments, and more, you can log in with your "
-"MediaGoblin account."
-msgstr "Aby dodawać swoje pliki, komentować i wykonywać inne czynności, możesz się zalogować na swoje konto MediaGoblin."
-
-#: mediagoblin/templates/mediagoblin/root.html:38
-msgid "Don't have one yet? It's easy!"
-msgstr "Jeszcze go nie masz? To proste!"
-
-#: mediagoblin/templates/mediagoblin/root.html:39
-#, python-format
-msgid ""
-"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
-" or\n"
-" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
-msgstr "<a class=\"button_action_highlight\" href=\"%(register_url)s\">Utwórz konto w tym serwisie</a>\n lub\n <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">załóż własny serwis MediaGoblin</a>"
-
-#: mediagoblin/templates/mediagoblin/root.html:47
+#: mediagoblin/templates/mediagoblin/root.html:32
msgid "Most recent media"
msgstr "Najnowsze media"
@@ -589,6 +571,53 @@ msgid ""
"%(verification_url)s"
msgstr "Cześć %(username)s,\n\naby aktywować twoje konto GNU MediaGoblin, otwórz następującą stronę w swojej przeglądarce:\n\n%(verification_url)s"
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:21
+#, python-format
+msgid ""
+"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
+"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
+msgstr "Napędzane przez oprogramowanie <a href=\"http://mediagoblin.org/\" title='w wersji %(version)s'>MediaGoblin</a>, będące częścią projektu <a href=\"http://gnu.org/\">GNU</a>."
+
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:24
+#, python-format
+msgid ""
+"Released under the <a "
+"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
+"href=\"%(source_link)s\">Source code</a> available."
+msgstr "Opublikowane na licencji <a href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. Dostępny jest <a href=\"%(source_link)s\">kod źródłowy</a>."
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:20
+msgid "Explore"
+msgstr "Odkrywaj"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:22
+msgid "Hi there, welcome to this MediaGoblin site!"
+msgstr "Cześć, witaj na stronie MediaGoblin!"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:24
+msgid ""
+"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
+"extraordinarily great piece of media hosting software."
+msgstr "Ten serwis działa w oparciu o <a href=\"http://mediagoblin.org\">MediaGoblin</a>, świetne oprogramowanie do publikowania mediów."
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:25
+msgid ""
+"To add your own media, place comments, and more, you can log in with your "
+"MediaGoblin account."
+msgstr "Aby dodawać swoje pliki, komentować i wykonywać inne czynności, możesz się zalogować na swoje konto MediaGoblin."
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:27
+msgid "Don't have one yet? It's easy!"
+msgstr "Jeszcze go nie masz? To proste!"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:28
+#, python-format
+msgid ""
+"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
+" or\n"
+" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
+msgstr "<a class=\"button_action_highlight\" href=\"%(register_url)s\">Załóż konto na tym serwerze</a>\n albo\n <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Uruchom MediaGoblin na swoim własnym serwerze</a>"
+
#: mediagoblin/templates/mediagoblin/bits/logo.html:23
#: mediagoblin/themes/airy/templates/mediagoblin/bits/logo.html:23
msgid "MediaGoblin logo"
@@ -601,13 +630,13 @@ msgid "Editing attachments for %(media_title)s"
msgstr "Edycja załączników do %(media_title)s"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:159
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:175
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:182
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:198
msgid "Attachments"
msgstr "Załączniki"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:57
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:181
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:204
msgid "Add attachment"
msgstr "Dodaj załącznik"
@@ -624,23 +653,33 @@ msgstr "Anuluj"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:63
#: mediagoblin/templates/mediagoblin/edit/edit.html:42
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:52
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:55
#: mediagoblin/templates/mediagoblin/edit/edit_collection.html:33
#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:40
msgid "Save changes"
msgstr "Zapisz zmiany"
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:28
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:38
+#, python-format
+msgid "Changing %(username)s's password"
+msgstr "Zmieniam hasło użytkownika %(username)s"
+
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:45
+msgid "Save"
+msgstr "Zachowaj"
+
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:28
#, python-format
msgid "Really delete user '%(user_name)s' and all related media/comments?"
-msgstr ""
+msgstr "Czy naprawdę skasować użytkownika '%(user_name)s' oraz usunąć wszystkie jego pliki i komentarze?"
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:35
msgid "Yes, really delete my account"
-msgstr ""
+msgstr "Tak, naprawdę chcę skasować swoje konto"
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:47
+#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:48
#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:49
msgid "Delete permanently"
msgstr "Usuń na stałe"
@@ -657,9 +696,13 @@ msgstr "Edytowanie %(media_title)s"
msgid "Changing %(username)s's account settings"
msgstr "Zmiana ustawień konta %(username)s"
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:59
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:46
+msgid "Change your password."
+msgstr "Zmień swoje hasło."
+
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:62
msgid "Delete my account"
-msgstr ""
+msgstr "Usuń moje konto"
#: mediagoblin/templates/mediagoblin/edit/edit_collection.html:29
#, python-format
@@ -682,6 +725,7 @@ msgstr "Media ze znacznikami: %(tag_name)s"
#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:56
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:65
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:136
#: mediagoblin/templates/mediagoblin/media_displays/video.html:55
msgid "Download"
@@ -706,6 +750,7 @@ msgid ""
msgstr "Proszę pobrać przeglądarkę, która obsługuje \n\tdźwięk w HTML5, pod adresem <a href=\"http://getfirefox.com\">\n\t http://getfirefox.com</a>!"
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:60
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:71
#: mediagoblin/templates/mediagoblin/media_displays/video.html:61
msgid "Original file"
msgstr "Oryginalny plik"
@@ -714,6 +759,7 @@ msgstr "Oryginalny plik"
msgid "WebM file (Vorbis codec)"
msgstr "plik WebM (kodek Vorbis)"
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:59
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:87
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:93
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:99
@@ -724,59 +770,63 @@ msgstr "plik WebM (kodek Vorbis)"
msgid "Image for %(media_title)s"
msgstr "Grafika dla %(media_title)s"
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:79
+msgid "PDF file"
+msgstr "Plik PDF"
+
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:112
msgid "Toggle Rotate"
-msgstr ""
+msgstr "Obróć"
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:113
msgid "Perspective"
-msgstr ""
+msgstr "Perspektywa"
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:116
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:117
msgid "Front"
-msgstr ""
+msgstr "PoczÄ…tek"
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:120
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:121
msgid "Top"
-msgstr ""
+msgstr "Góra"
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:124
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:125
msgid "Side"
-msgstr ""
+msgstr "Krawędź"
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:130
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:131
msgid "WebGL"
-msgstr ""
+msgstr "WebGL"
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:138
msgid "Download model"
-msgstr ""
+msgstr "Pobierz model"
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:146
msgid "File Format"
-msgstr ""
+msgstr "Format pliku"
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:148
msgid "Object Height"
-msgstr ""
+msgstr "Wysokość obiektu"
#: mediagoblin/templates/mediagoblin/media_displays/video.html:44
msgid ""
"Sorry, this video will not work because\n"
" your web browser does not support HTML5 \n"
" video."
-msgstr ""
+msgstr "Niestety ten materiaÅ‚ nie bÄ™dzie widocznyâŽ, ponieważ twoja przeglÄ…darka nie⎠osbÅ‚uguje formatu HTML5."
#: mediagoblin/templates/mediagoblin/media_displays/video.html:47
msgid ""
"You can get a modern web browser that \n"
" can play this video at <a href=\"http://getfirefox.com\">\n"
" http://getfirefox.com</a>!"
-msgstr ""
+msgstr "Możesz pobrać porządną przeglądarkę, która jest w stanie odtworzyć ten materiał filmowy, ze strony <a href=\"http://getfirefox.com/\">⎠http://getfirefox.com</a>!"
#: mediagoblin/templates/mediagoblin/media_displays/video.html:69
msgid "WebM file (640p; VP8/Vorbis)"
@@ -822,19 +872,19 @@ msgstr "Na pewno usunąć %(title)s?"
msgid "Really remove %(media_title)s from %(collection_title)s?"
msgstr "Na pewno usunąć %(media_title)s z %(collection_title)s?"
-#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:53
+#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:54
msgid "Remove"
msgstr "Usuń"
#: mediagoblin/templates/mediagoblin/user_pages/collection_list.html:21
#, python-format
msgid "%(username)s's collections"
-msgstr ""
+msgstr "kolekcja użytkownika %(username)s"
#: mediagoblin/templates/mediagoblin/user_pages/collection_list.html:28
#, python-format
msgid "<a href=\"%(user_url)s\">%(username)s</a>'s collections"
-msgstr ""
+msgstr "kolekcje użytkownika <a href=\"%(user_url)s\">%(username)s</a>"
#: mediagoblin/templates/mediagoblin/user_pages/comment_email.txt:19
#, python-format
@@ -853,7 +903,7 @@ msgstr "Media użytkownika %(username)s"
msgid ""
"<a href=\"%(user_url)s\">%(username)s</a>'s media with tag <a "
"href=\"%(tag_url)s\">%(tag)s</a>"
-msgstr ""
+msgstr "pliki użytkownika <a href=\"%(user_url)s\">%(username)s</a> z tagiem <a href=\"%(tag_url)s\">%(tag)s</a>"
#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:48
#, python-format
@@ -865,30 +915,34 @@ msgstr "media użytkownika <a href=\"%(user_url)s\">%(username)s</a>"
msgid "â– Browsing media by <a href=\"%(user_url)s\">%(username)s</a>"
msgstr "■Przeglądanie mediów użytkownika <a href=\"%(user_url)s\">%(username)s</a>"
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:94
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:95
msgid "Add a comment"
msgstr "Dodaj komentarz"
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:102
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:104
msgid "Add this comment"
msgstr "Dodaj komentarz"
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:123
-msgid "at"
-msgstr "na"
-
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:144
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:132
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:152
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:164
#, python-format
-msgid ""
-"<h3>Added on</h3>\n"
-" <p>%(date)s</p>"
-msgstr "<h3>Dodane</h3>\n <p>%(date)s</p>"
+msgid "%(formatted_time)s ago"
+msgstr "%(formatted_time)s temu"
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:150
+msgid "Added"
+msgstr "Dodano"
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:161
+msgid "Created"
+msgstr "Utworzono"
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:28
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:40
#, python-format
msgid "Add “%(media_title)s†to a collection"
-msgstr ""
+msgstr "Dodaj “%(media_title)s†do kolekcji"
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:54
msgid "+"
@@ -967,7 +1021,7 @@ msgstr "Ten użytkownik nie wypełnił (jeszcze) opisu swojego profilu."
#: mediagoblin/templates/mediagoblin/user_pages/user.html:124
msgid "Browse collections"
-msgstr ""
+msgstr "PrzeglÄ…daj kolekcje"
#: mediagoblin/templates/mediagoblin/user_pages/user.html:137
#, python-format
@@ -988,15 +1042,15 @@ msgstr "Tu nie ma jeszcze żadnych mediów..."
#: mediagoblin/templates/mediagoblin/utils/collection_gallery.html:49
msgid "(remove)"
-msgstr ""
+msgstr "(usuń)"
#: mediagoblin/templates/mediagoblin/utils/collections.html:21
msgid "Collected in"
-msgstr ""
+msgstr "Znajduje siÄ™ w kolekcji "
#: mediagoblin/templates/mediagoblin/utils/collections.html:40
msgid "Add to a collection"
-msgstr ""
+msgstr "Dodaj do kolekcji"
#: mediagoblin/templates/mediagoblin/utils/feed_link.html:21
#: mediagoblin/themes/airy/templates/mediagoblin/utils/feed_link.html:21
@@ -1038,7 +1092,7 @@ msgstr "starsze"
msgid "Tagged with"
msgstr "Znaczniki:"
-#: mediagoblin/tools/exif.py:80
+#: mediagoblin/tools/exif.py:83
msgid "Could not read the image file."
msgstr "Nie udało się odczytać pliku grafiki."
@@ -1048,29 +1102,53 @@ msgstr "Ups!"
#: mediagoblin/tools/response.py:36
msgid "An error occured"
-msgstr ""
+msgstr "Wystąpił błąd"
#: mediagoblin/tools/response.py:51
msgid "Operation not allowed"
-msgstr ""
+msgstr "Operacja niedozwolona"
#: mediagoblin/tools/response.py:52
msgid ""
"Sorry Dave, I can't let you do that!</p><p>You have tried to perform a "
"function that you are not allowed to. Have you been trying to delete all "
"user accounts again?"
-msgstr ""
+msgstr "Misiaczku, nie możesz tego uczynić!</p><p>Próbowałeś wykonać działanie, do którego nie masz uprawnień. Czy naprawdę chciałeś skasować znowu wszystkie konta?"
#: mediagoblin/tools/response.py:60
msgid ""
"There doesn't seem to be a page at this address. Sorry!</p><p>If you're sure"
" the address is correct, maybe the page you're looking for has been moved or"
" deleted."
-msgstr ""
+msgstr "Wygląda na to, że nic tutaj nie ma!</p><p>Jeśli jesteś pewny, że adres jest prawidłowy, być może strona została skasowana lub przeniesiona."
+
+#: mediagoblin/tools/timesince.py:62
+msgid "year"
+msgstr "rok"
+
+#: mediagoblin/tools/timesince.py:63
+msgid "month"
+msgstr "miesiÄ…c"
+
+#: mediagoblin/tools/timesince.py:64
+msgid "week"
+msgstr "tydzień"
+
+#: mediagoblin/tools/timesince.py:65
+msgid "day"
+msgstr "dzień"
+
+#: mediagoblin/tools/timesince.py:66
+msgid "hour"
+msgstr "godzina"
+
+#: mediagoblin/tools/timesince.py:67
+msgid "minute"
+msgstr "minuta"
#: mediagoblin/user_pages/forms.py:23
msgid "Comment"
-msgstr ""
+msgstr "Komentarz"
#: mediagoblin/user_pages/forms.py:25
msgid ""
@@ -1089,7 +1167,7 @@ msgstr "Na pewno chcę usunąć ten element z kolekcji"
#: mediagoblin/user_pages/forms.py:39
msgid "Collection"
-msgstr ""
+msgstr "Kolekcja"
#: mediagoblin/user_pages/forms.py:40
msgid "-- Select --"
@@ -1099,73 +1177,77 @@ msgstr "-- wybierz --"
msgid "Include a note"
msgstr "Dodaj notatkÄ™"
-#: mediagoblin/user_pages/lib.py:56
+#: mediagoblin/user_pages/lib.py:58
msgid "commented on your post"
msgstr "komentarze do twojego wpisu"
-#: mediagoblin/user_pages/views.py:166
+#: mediagoblin/user_pages/views.py:169
+msgid "Sorry, comments are disabled."
+msgstr "Komentowanie jest wyłączone."
+
+#: mediagoblin/user_pages/views.py:174
msgid "Oops, your comment was empty."
msgstr "Ups, twój komentarz nie zawierał treści."
-#: mediagoblin/user_pages/views.py:172
+#: mediagoblin/user_pages/views.py:180
msgid "Your comment has been posted!"
msgstr "Twój komentarz został opublikowany!"
-#: mediagoblin/user_pages/views.py:197
+#: mediagoblin/user_pages/views.py:205
msgid "Please check your entries and try again."
msgstr "Sprawdź swoje wpisy i spróbuj ponownie."
-#: mediagoblin/user_pages/views.py:237
+#: mediagoblin/user_pages/views.py:245
msgid "You have to select or add a collection"
msgstr "Musisz wybrać lub dodać kolekcję"
-#: mediagoblin/user_pages/views.py:248
+#: mediagoblin/user_pages/views.py:256
#, python-format
msgid "\"%s\" already in collection \"%s\""
msgstr "\"%s\" już obecne w kolekcji \"%s\""
-#: mediagoblin/user_pages/views.py:264
+#: mediagoblin/user_pages/views.py:262
#, python-format
msgid "\"%s\" added to collection \"%s\""
msgstr "\"%s\" dodano do kolekcji \"%s\""
-#: mediagoblin/user_pages/views.py:286
+#: mediagoblin/user_pages/views.py:282
msgid "You deleted the media."
msgstr "Media zostały usunięte."
-#: mediagoblin/user_pages/views.py:293
+#: mediagoblin/user_pages/views.py:289
msgid "The media was not deleted because you didn't check that you were sure."
msgstr "Media nie zostały usunięte ponieważ nie potwierdziłeś, że jesteś pewien."
-#: mediagoblin/user_pages/views.py:301
+#: mediagoblin/user_pages/views.py:296
msgid "You are about to delete another user's media. Proceed with caution."
msgstr "Za chwilę usuniesz media innego użytkownika. Zachowaj ostrożność."
-#: mediagoblin/user_pages/views.py:375
+#: mediagoblin/user_pages/views.py:370
msgid "You deleted the item from the collection."
msgstr "Element został usunięty z kolekcji."
-#: mediagoblin/user_pages/views.py:379
+#: mediagoblin/user_pages/views.py:374
msgid "The item was not removed because you didn't check that you were sure."
msgstr "Ten element nie został usunięty, ponieważ nie zaznaczono, że jesteś pewien."
-#: mediagoblin/user_pages/views.py:389
+#: mediagoblin/user_pages/views.py:382
msgid ""
"You are about to delete an item from another user's collection. Proceed with"
" caution."
msgstr "Zamierzasz usunąć element z kolekcji innego użytkownika. Zachowaj ostrożność."
-#: mediagoblin/user_pages/views.py:422
+#: mediagoblin/user_pages/views.py:415
#, python-format
msgid "You deleted the collection \"%s\""
msgstr "Usunięto kolekcję \"%s\""
-#: mediagoblin/user_pages/views.py:429
+#: mediagoblin/user_pages/views.py:422
msgid ""
"The collection was not deleted because you didn't check that you were sure."
msgstr "Ta kolekcja nie została usunięta, ponieważ nie zaznaczono, że jesteś pewien."
-#: mediagoblin/user_pages/views.py:439
+#: mediagoblin/user_pages/views.py:430
msgid ""
"You are about to delete another user's collection. Proceed with caution."
msgstr "Zamierzasz usunąć kolekcję innego użytkownika. Zachowaj ostrożność."
diff --git a/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.mo
index af50e027..5e83a7f2 100644
--- a/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.mo
+++ b/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.mo
Binary files differ
diff --git a/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po
index 3b2ed203..fecb844c 100644
--- a/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po
+++ b/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po
@@ -3,16 +3,17 @@
# This file is distributed under the same license as the PROJECT project.
#
# Translators:
-# Rafael Ferreira <rafael.f.f1@gmail.com>, 2013.
-# <snd.noise@gmail.com>, 2011.
-# ufa <ufa@technotroll.org>, 2011.
-# Vinicius SM <viniciussm@rocketmail.com>, 2013.
+# osc <snd.noise@gmail.com>, 2013
+# Rafael Ferreira <rafael.f.f1@gmail.com>, 2013
+# osc <snd.noise@gmail.com>, 2011
+# ufa <ufa@technotroll.org>, 2011
+# Canopus <viniciussm@rocketmail.com>, 2013
msgid ""
msgstr ""
"Project-Id-Version: GNU MediaGoblin\n"
"Report-Msgid-Bugs-To: http://issues.mediagoblin.org/\n"
-"POT-Creation-Date: 2013-03-04 18:04-0600\n"
-"PO-Revision-Date: 2013-03-05 00:04+0000\n"
+"POT-Creation-Date: 2013-05-27 13:54-0500\n"
+"PO-Revision-Date: 2013-05-27 18:54+0000\n"
"Last-Translator: cwebber <cwebber@dustycloud.org>\n"
"Language-Team: Portuguese (Brazil) (http://www.transifex.com/projects/p/mediagoblin/language/pt_BR/)\n"
"MIME-Version: 1.0\n"
@@ -22,34 +23,39 @@ msgstr ""
"Language: pt_BR\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
-#: mediagoblin/auth/forms.py:28
-msgid "Invalid User name or email address."
-msgstr "Nome de usuário ou email inválido."
-
-#: mediagoblin/auth/forms.py:29
-msgid "This field does not take email addresses."
-msgstr "Este campo não aceita endereços de email."
-
-#: mediagoblin/auth/forms.py:30
-msgid "This field requires an email address."
-msgstr "Este campo requer um endereço de email."
-
-#: mediagoblin/auth/forms.py:52 mediagoblin/auth/forms.py:67
+#: mediagoblin/auth/forms.py:26
msgid "Username"
msgstr "Nome de Usuário"
-#: mediagoblin/auth/forms.py:56 mediagoblin/auth/forms.py:71
+#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:45
+#: mediagoblin/tests/test_util.py:110
msgid "Password"
msgstr "Senha"
-#: mediagoblin/auth/forms.py:60
+#: mediagoblin/auth/forms.py:34
msgid "Email address"
msgstr "Endereço de email"
-#: mediagoblin/auth/forms.py:78
+#: mediagoblin/auth/forms.py:41
+msgid "Username or Email"
+msgstr ""
+
+#: mediagoblin/auth/forms.py:52
msgid "Username or email"
msgstr "Nome de usuário ou email"
+#: mediagoblin/auth/tools.py:31
+msgid "Invalid User name or email address."
+msgstr "Nome de usuário ou email inválido."
+
+#: mediagoblin/auth/tools.py:32
+msgid "This field does not take email addresses."
+msgstr "Este campo não aceita endereços de email."
+
+#: mediagoblin/auth/tools.py:33
+msgid "This field requires an email address."
+msgstr "Este campo requer um endereço de email."
+
#: mediagoblin/auth/views.py:54
msgid "Sorry, registration is disabled on this instance."
msgstr "Desculpa, o registro está desativado neste momento."
@@ -62,54 +68,54 @@ msgstr "Desculpe, um usuário com este nome já existe."
msgid "Sorry, a user with that email address already exists."
msgstr "Desculpe, um usuário com esse email já está cadastrado"
-#: mediagoblin/auth/views.py:174
+#: mediagoblin/auth/views.py:182
msgid ""
"Your email address has been verified. You may now login, edit your profile, "
"and submit images!"
msgstr "O seu endereço de e-mail foi verificado. Você pode agora fazer login, editar seu perfil, e enviar imagens!"
-#: mediagoblin/auth/views.py:180
+#: mediagoblin/auth/views.py:188
msgid "The verification key or user id is incorrect"
msgstr "A chave de verificação ou nome usuário estão incorretos."
-#: mediagoblin/auth/views.py:198
+#: mediagoblin/auth/views.py:206
msgid "You must be logged in so we know who to send the email to!"
msgstr "Você precisa entrar primeiro para sabermos para quem mandar o email!"
-#: mediagoblin/auth/views.py:206
+#: mediagoblin/auth/views.py:214
msgid "You've already verified your email address!"
msgstr "Você já verificou seu email!"
-#: mediagoblin/auth/views.py:219
+#: mediagoblin/auth/views.py:227
msgid "Resent your verification email."
msgstr "O email de verificação foi enviado novamente."
-#: mediagoblin/auth/views.py:250
+#: mediagoblin/auth/views.py:258
msgid ""
"If that email address (case sensitive!) is registered an email has been sent"
" with instructions on how to change your password."
-msgstr ""
+msgstr "Se esse endereço de email (sensível a maiúsculo/minúsculo!) estiver registrado, um email será enviado com instruções para alterar sua senha."
-#: mediagoblin/auth/views.py:261
+#: mediagoblin/auth/views.py:269
msgid "Couldn't find someone with that username."
msgstr "Não foi possível encontrar alguém com esse nome de usuário."
-#: mediagoblin/auth/views.py:264
+#: mediagoblin/auth/views.py:272
msgid ""
"An email has been sent with instructions on how to change your password."
msgstr "Um email foi enviado com instruções para trocar sua senha."
-#: mediagoblin/auth/views.py:271
+#: mediagoblin/auth/views.py:279
msgid ""
"Could not send password recovery email as your username is inactive or your "
"account's email address has not been verified."
msgstr "Não foi possível enviar o email de recuperação de senha, pois seu nome de usuário está inativo ou o email da sua conta não foi confirmado."
-#: mediagoblin/auth/views.py:328
+#: mediagoblin/auth/views.py:336
msgid "You can now log in using your new password."
msgstr "Agora você pode entrar usando sua nova senha."
-#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:93
+#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:82
#: mediagoblin/submit/forms.py:28 mediagoblin/submit/forms.py:47
#: mediagoblin/user_pages/forms.py:45
msgid "Title"
@@ -120,7 +126,7 @@ msgid "Description of this work"
msgstr "Descrição desse trabalho"
#: mediagoblin/edit/forms.py:29 mediagoblin/edit/forms.py:52
-#: mediagoblin/edit/forms.py:97 mediagoblin/submit/forms.py:32
+#: mediagoblin/edit/forms.py:86 mediagoblin/submit/forms.py:32
#: mediagoblin/submit/forms.py:51 mediagoblin/user_pages/forms.py:49
msgid ""
"You can use\n"
@@ -136,11 +142,11 @@ msgstr "Etiquetas"
msgid "Separate tags by commas."
msgstr "Separe as etiquetas com vírgulas."
-#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:101
+#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:90
msgid "Slug"
msgstr "Arquivo"
-#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:102
+#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:91
msgid "The slug can't be empty"
msgstr "O arquivo não pode estar vazio"
@@ -168,45 +174,45 @@ msgid "This address contains errors"
msgstr "Este endereço contém erros"
#: mediagoblin/edit/forms.py:63
-msgid "Old password"
-msgstr "Senha antiga"
-
-#: mediagoblin/edit/forms.py:64
-msgid "Enter your old password to prove you own this account."
-msgstr "Digite sua senha antiga para provar que esta conta é sua."
-
-#: mediagoblin/edit/forms.py:67
-msgid "New password"
-msgstr "Nova senha"
-
-#: mediagoblin/edit/forms.py:74
msgid "License preference"
msgstr "Licença preferida"
-#: mediagoblin/edit/forms.py:80
+#: mediagoblin/edit/forms.py:69
msgid "This will be your default license on upload forms."
msgstr "Esta será sua licença padrão nos formulários de envio."
-#: mediagoblin/edit/forms.py:82
+#: mediagoblin/edit/forms.py:71
msgid "Email me when others comment on my media"
msgstr "Me enviar um email quando outras pessoas comentarem em minhas mídias"
-#: mediagoblin/edit/forms.py:94
+#: mediagoblin/edit/forms.py:83
msgid "The title can't be empty"
msgstr "O título não pode ficar vazio"
-#: mediagoblin/edit/forms.py:96 mediagoblin/submit/forms.py:50
+#: mediagoblin/edit/forms.py:85 mediagoblin/submit/forms.py:50
#: mediagoblin/user_pages/forms.py:48
msgid "Description of this collection"
msgstr "Descrição desta coleção"
-#: mediagoblin/edit/forms.py:103
+#: mediagoblin/edit/forms.py:92
msgid ""
"The title part of this collection's address. You usually don't need to "
"change this."
msgstr "A parte do título do endereço dessa coleção. Geralmente você não precisa mudar isso."
-#: mediagoblin/edit/views.py:66
+#: mediagoblin/edit/forms.py:99
+msgid "Old password"
+msgstr "Senha antiga"
+
+#: mediagoblin/edit/forms.py:101
+msgid "Enter your old password to prove you own this account."
+msgstr "Digite sua senha antiga para provar que esta conta é sua."
+
+#: mediagoblin/edit/forms.py:104
+msgid "New password"
+msgstr "Nova senha"
+
+#: mediagoblin/edit/views.py:67
msgid "An entry with that slug already exists for this user."
msgstr "Uma entrada com esse arquivo já existe para esse usuário"
@@ -231,44 +237,63 @@ msgstr "Você está editando um perfil de usuário. Tenha cuidado."
msgid "Profile changes saved"
msgstr "As mudanças no perfil foram salvas"
-#: mediagoblin/edit/views.py:241
-msgid "Wrong password"
-msgstr "Senha errada"
-
-#: mediagoblin/edit/views.py:252
+#: mediagoblin/edit/views.py:240
msgid "Account settings saved"
msgstr "As mudanças na conta foram salvas"
-#: mediagoblin/edit/views.py:286
+#: mediagoblin/edit/views.py:274
msgid "You need to confirm the deletion of your account."
msgstr "Você precisa confirmar a exclusão da sua conta."
-#: mediagoblin/edit/views.py:322 mediagoblin/submit/views.py:142
-#: mediagoblin/user_pages/views.py:214
+#: mediagoblin/edit/views.py:310 mediagoblin/submit/views.py:138
+#: mediagoblin/user_pages/views.py:222
#, python-format
msgid "You already have a collection called \"%s\"!"
msgstr "Você já tem uma coleção chamada \"%s\"!"
-#: mediagoblin/edit/views.py:326
+#: mediagoblin/edit/views.py:314
msgid "A collection with that slug already exists for this user."
msgstr "Já existe uma coleção com este arquivo para este usuário."
-#: mediagoblin/edit/views.py:343
+#: mediagoblin/edit/views.py:329
msgid "You are editing another user's collection. Proceed with caution."
msgstr "Você está editando a coleção de um outro usuário. Prossiga com cuidado."
-#: mediagoblin/gmg_commands/theme.py:58
+#: mediagoblin/edit/views.py:348
+msgid "Wrong password"
+msgstr "Senha errada"
+
+#: mediagoblin/edit/views.py:363
+msgid "Your password was changed successfully"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:60
msgid "Cannot link theme... no theme set\n"
msgstr "Não é possível fazer link de tema... nenhum tema definido\n"
-#: mediagoblin/gmg_commands/theme.py:71
+#: mediagoblin/gmg_commands/assetlink.py:73
msgid "No asset directory for this theme\n"
msgstr ""
-#: mediagoblin/gmg_commands/theme.py:74
+#: mediagoblin/gmg_commands/assetlink.py:76
msgid "However, old link directory symlink found; removed.\n"
msgstr ""
+#: mediagoblin/gmg_commands/assetlink.py:112
+#, python-format
+msgid "Could not link \"%s\": %s exists and is not a symlink\n"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:119
+#, python-format
+msgid "Skipping \"%s\"; already set up.\n"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:124
+#, python-format
+msgid "Old link found for \"%s\"; removing.\n"
+msgstr ""
+
#: mediagoblin/meddleware/csrf.py:134
msgid ""
"CSRF cookie not present. This is most likely the result of a cookie blocker "
@@ -276,12 +301,16 @@ msgid ""
"domain."
msgstr "Cookie CSFR não está presente. Isso é provavelmente o resultado de um bloqueador de cookies ou algo do tipo.<br/>Tenha certeza de autorizar este domínio a configurar cookies."
-#: mediagoblin/media_types/__init__.py:61
-#: mediagoblin/media_types/__init__.py:102
+#: mediagoblin/media_types/__init__.py:111
+#: mediagoblin/media_types/__init__.py:155
msgid "Sorry, I don't support that file type :("
msgstr "Desculpe, não tenho suporte a este tipo de arquivo :("
-#: mediagoblin/media_types/video/processing.py:36
+#: mediagoblin/media_types/pdf/processing.py:136
+msgid "unoconv failing to run, check log file"
+msgstr ""
+
+#: mediagoblin/media_types/video/processing.py:37
msgid "Video transcoding failed"
msgstr "Conversão do vídeo falhou"
@@ -348,7 +377,7 @@ msgstr ""
msgid "This field is required for public clients"
msgstr "Este campo é necessário para clientes públicos"
-#: mediagoblin/plugins/oauth/views.py:59
+#: mediagoblin/plugins/oauth/views.py:56
msgid "The client {0} has been registered!"
msgstr "O cliente {0} foi registrado!"
@@ -367,7 +396,7 @@ msgstr "Seus clientes OAuth"
msgid "Add"
msgstr "Adicionar"
-#: mediagoblin/processing/__init__.py:172
+#: mediagoblin/processing/__init__.py:193
msgid "Invalid file given for media type."
msgstr "Arquivo inválido para esse tipo de mídia"
@@ -375,45 +404,45 @@ msgstr "Arquivo inválido para esse tipo de mídia"
msgid "File"
msgstr "Arquivo"
-#: mediagoblin/submit/views.py:51
+#: mediagoblin/submit/views.py:49
msgid "You must provide a file."
msgstr "Você deve fornecer um arquivo."
-#: mediagoblin/submit/views.py:97
+#: mediagoblin/submit/views.py:93
msgid "Woohoo! Submitted!"
msgstr "Eba! Enviado!"
-#: mediagoblin/submit/views.py:146
+#: mediagoblin/submit/views.py:144
#, python-format
msgid "Collection \"%s\" added!"
msgstr "Coleção \"%s\" adicionada!"
-#: mediagoblin/templates/mediagoblin/base.html:64
+#: mediagoblin/templates/mediagoblin/base.html:67
msgid "Verify your email!"
msgstr "Verifique seu email!"
-#: mediagoblin/templates/mediagoblin/base.html:65
+#: mediagoblin/templates/mediagoblin/base.html:68
msgid "log out"
msgstr "sair"
-#: mediagoblin/templates/mediagoblin/base.html:70
+#: mediagoblin/templates/mediagoblin/base.html:73
#: mediagoblin/templates/mediagoblin/auth/login.html:28
#: mediagoblin/templates/mediagoblin/auth/login.html:36
#: mediagoblin/templates/mediagoblin/auth/login.html:54
msgid "Log in"
msgstr "Entrar"
-#: mediagoblin/templates/mediagoblin/base.html:79
+#: mediagoblin/templates/mediagoblin/base.html:82
#, python-format
msgid "<a href=\"%(user_url)s\">%(user_name)s</a>'s account"
msgstr "Conta de <a href=\"%(user_url)s\">%(user_name)s</a>"
-#: mediagoblin/templates/mediagoblin/base.html:86
+#: mediagoblin/templates/mediagoblin/base.html:89
msgid "Change account settings"
msgstr "Mudar configurações da conta"
-#: mediagoblin/templates/mediagoblin/base.html:90
-#: mediagoblin/templates/mediagoblin/base.html:105
+#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:108
#: mediagoblin/templates/mediagoblin/admin/panel.html:21
#: mediagoblin/templates/mediagoblin/admin/panel.html:26
#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:21
@@ -421,72 +450,25 @@ msgstr "Mudar configurações da conta"
msgid "Media processing panel"
msgstr "Painel de processamento de mídia"
-#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:96
msgid "Log out"
-msgstr ""
+msgstr "Sair"
-#: mediagoblin/templates/mediagoblin/base.html:96
+#: mediagoblin/templates/mediagoblin/base.html:99
#: mediagoblin/templates/mediagoblin/user_pages/user.html:156
msgid "Add media"
msgstr "Adicionar mídia"
-#: mediagoblin/templates/mediagoblin/base.html:99
+#: mediagoblin/templates/mediagoblin/base.html:102
#: mediagoblin/templates/mediagoblin/user_pages/collection_list.html:41
msgid "Create new collection"
msgstr "Criar nova coleção"
-#: mediagoblin/templates/mediagoblin/base.html:122
-#, python-format
-msgid ""
-"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
-"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/base.html:125
-#, python-format
-msgid ""
-"Released under the <a "
-"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
-"href=\"%(source_link)s\">Source code</a> available."
-msgstr "Lançado sob a <a href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a href=\"%(source_link)s\">Código fonte</a> disponível."
-
#: mediagoblin/templates/mediagoblin/error.html:24
msgid "Image of goblin stressing out"
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:31
-msgid "Explore"
-msgstr "Explorar"
-
-#: mediagoblin/templates/mediagoblin/root.html:33
-msgid "Hi there, welcome to this MediaGoblin site!"
-msgstr "Olá, bem-vindo a este site MediaGoblin."
-
-#: mediagoblin/templates/mediagoblin/root.html:35
-msgid ""
-"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
-"extraordinarily great piece of media hosting software."
-msgstr "Este site roda o <a href=\"http://mediagoblin.org\">MediaGoblin</a>, um programa excelente para hospedar, gerenciar e compartilhar mídia."
-
-#: mediagoblin/templates/mediagoblin/root.html:36
-msgid ""
-"To add your own media, place comments, and more, you can log in with your "
-"MediaGoblin account."
-msgstr "Para adicionar sua própria mídia, publicar comentários e mais outras coisas, você pode entrar com sua conta MediaGoblin."
-
-#: mediagoblin/templates/mediagoblin/root.html:38
-msgid "Don't have one yet? It's easy!"
-msgstr " Ainda não tem uma conta? É facil!"
-
-#: mediagoblin/templates/mediagoblin/root.html:39
-#, python-format
-msgid ""
-"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
-" or\n"
-" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
-msgstr "<a class=\"button_action_highlight\" href=\"%(register_url)s\">Criar uma conta neste site</a>\nou\n<a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Configurar MediaGoblin em seu próprio servidor</a>"
+msgstr "Imagem do goblin se estressando"
-#: mediagoblin/templates/mediagoblin/root.html:47
+#: mediagoblin/templates/mediagoblin/root.html:32
msgid "Most recent media"
msgstr "Mídia mais recente"
@@ -592,6 +574,53 @@ msgid ""
"%(verification_url)s"
msgstr "Olá %(username)s,\n\nPara ativar sua conta GNU MediaGoblin, visite este endereço no seu navegador:\n\n%(verification_url)s"
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:21
+#, python-format
+msgid ""
+"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
+"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
+msgstr "Fornecido pelo <a href=\"http://mediagoblin.org/\" title='Version %(version)s'>MediaGoblin</a>, um projeto <a href=\"http://gnu.org/\">GNU</a>."
+
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:24
+#, python-format
+msgid ""
+"Released under the <a "
+"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
+"href=\"%(source_link)s\">Source code</a> available."
+msgstr "Lançado sob a <a href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a href=\"%(source_link)s\">Código fonte</a> disponível."
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:20
+msgid "Explore"
+msgstr "Explorar"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:22
+msgid "Hi there, welcome to this MediaGoblin site!"
+msgstr "Olá, bem-vindo a este site MediaGoblin."
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:24
+msgid ""
+"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
+"extraordinarily great piece of media hosting software."
+msgstr "Este site roda o <a href=\"http://mediagoblin.org\">MediaGoblin</a>, um programa excelente para hospedar, gerenciar e compartilhar mídia."
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:25
+msgid ""
+"To add your own media, place comments, and more, you can log in with your "
+"MediaGoblin account."
+msgstr "Para adicionar sua própria mídia, publicar comentários e mais outras coisas, você pode entrar com sua conta MediaGoblin."
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:27
+msgid "Don't have one yet? It's easy!"
+msgstr " Ainda não tem uma conta? É facil!"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:28
+#, python-format
+msgid ""
+"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
+" or\n"
+" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/bits/logo.html:23
#: mediagoblin/themes/airy/templates/mediagoblin/bits/logo.html:23
msgid "MediaGoblin logo"
@@ -604,13 +633,13 @@ msgid "Editing attachments for %(media_title)s"
msgstr "Editando os anexos de %(media_title)s"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:159
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:175
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:182
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:198
msgid "Attachments"
msgstr "Anexos"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:57
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:181
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:204
msgid "Add attachment"
msgstr "Adicionar anexo"
@@ -627,12 +656,22 @@ msgstr "Cancelar"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:63
#: mediagoblin/templates/mediagoblin/edit/edit.html:42
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:52
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:55
#: mediagoblin/templates/mediagoblin/edit/edit_collection.html:33
#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:40
msgid "Save changes"
msgstr "Salvar mudanças"
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:28
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:38
+#, python-format
+msgid "Changing %(username)s's password"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:45
+msgid "Save"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:28
#, python-format
msgid "Really delete user '%(user_name)s' and all related media/comments?"
@@ -643,7 +682,7 @@ msgid "Yes, really delete my account"
msgstr "Sim, realmente deletar minha conta"
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:47
+#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:48
#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:49
msgid "Delete permanently"
msgstr "Deletar permanentemente"
@@ -660,7 +699,11 @@ msgstr "Editando %(media_title)s"
msgid "Changing %(username)s's account settings"
msgstr "Alterando as configurações da conta de %(username)s"
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:59
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:46
+msgid "Change your password."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:62
msgid "Delete my account"
msgstr "Deletar minha conta"
@@ -685,6 +728,7 @@ msgstr "Etiquetas desta mídia: %(tag_name)s"
#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:56
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:65
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:136
#: mediagoblin/templates/mediagoblin/media_displays/video.html:55
msgid "Download"
@@ -709,6 +753,7 @@ msgid ""
msgstr "Você pode obter um navegador moderno\n »capaz de reproduzir o áudio em <a href=\"http://getfirefox.com\">\n » http://getfirefox.com</a>!"
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:60
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:71
#: mediagoblin/templates/mediagoblin/media_displays/video.html:61
msgid "Original file"
msgstr "Arquivo original"
@@ -717,6 +762,7 @@ msgstr "Arquivo original"
msgid "WebM file (Vorbis codec)"
msgstr "Arquivo WebM (codec Vorbis)"
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:59
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:87
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:93
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:99
@@ -727,6 +773,10 @@ msgstr "Arquivo WebM (codec Vorbis)"
msgid "Image for %(media_title)s"
msgstr "Imagem para %(media_title)s"
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:79
+msgid "PDF file"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:112
msgid "Toggle Rotate"
msgstr "Alternar Rotação"
@@ -825,7 +875,7 @@ msgstr "Realmente apagar %(title)s ?"
msgid "Really remove %(media_title)s from %(collection_title)s?"
msgstr "Realmente remover %(media_title)s de %(collection_title)s?"
-#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:53
+#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:54
msgid "Remove"
msgstr "Apagar"
@@ -856,7 +906,7 @@ msgstr "Mídia de %(username)s's"
msgid ""
"<a href=\"%(user_url)s\">%(username)s</a>'s media with tag <a "
"href=\"%(tag_url)s\">%(tag)s</a>"
-msgstr ""
+msgstr "Mídias de <a href=\"%(user_url)s\">%(username)s</a> com a etiqueta <a href=\"%(tag_url)s\">%(tag)s</a>"
#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:48
#, python-format
@@ -868,24 +918,28 @@ msgstr "Mídia de <a href=\"%(user_url)s\"> %(username)s </a> "
msgid "â– Browsing media by <a href=\"%(user_url)s\">%(username)s</a>"
msgstr "■Vendo mídia de <a href=\"%(user_url)s\">%(username)s</a>"
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:94
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:95
msgid "Add a comment"
msgstr "Adicionar um comentário"
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:102
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:104
msgid "Add this comment"
msgstr "Adicionar este comentário"
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:123
-msgid "at"
-msgstr "em"
-
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:144
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:132
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:152
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:164
#, python-format
-msgid ""
-"<h3>Added on</h3>\n"
-" <p>%(date)s</p>"
-msgstr "<h3>Adicionado em</h3>\n<p>%(date)s</p>"
+msgid "%(formatted_time)s ago"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:150
+msgid "Added"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:161
+msgid "Created"
+msgstr ""
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:28
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:40
@@ -987,7 +1041,7 @@ msgstr "Aqui é onde sua mídia vai aparecer, mas parece que você não adiciono
#: mediagoblin/templates/mediagoblin/utils/collection_gallery.html:84
#: mediagoblin/templates/mediagoblin/utils/object_gallery.html:70
msgid "There doesn't seem to be any media here yet..."
-msgstr "Aparentemente não há nenhuma mídia aqui ainda..."
+msgstr "Parece que ainda não há nenhuma mídia por aqui..."
#: mediagoblin/templates/mediagoblin/utils/collection_gallery.html:49
msgid "(remove)"
@@ -999,7 +1053,7 @@ msgstr ""
#: mediagoblin/templates/mediagoblin/utils/collections.html:40
msgid "Add to a collection"
-msgstr ""
+msgstr "Adicionar a uma coleção"
#: mediagoblin/templates/mediagoblin/utils/feed_link.html:21
#: mediagoblin/themes/airy/templates/mediagoblin/utils/feed_link.html:21
@@ -1041,7 +1095,7 @@ msgstr "mais antiga"
msgid "Tagged with"
msgstr "Etiquetas"
-#: mediagoblin/tools/exif.py:80
+#: mediagoblin/tools/exif.py:83
msgid "Could not read the image file."
msgstr "Não foi possível ler o arquivo de imagem."
@@ -1071,6 +1125,30 @@ msgid ""
" deleted."
msgstr "Parece que não há uma página com este endereço. Desculpe!</p><p>Se você tem certeza que este endereço está correto, talvez a página que esteja procurando tenha sido movida ou deletada."
+#: mediagoblin/tools/timesince.py:62
+msgid "year"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:63
+msgid "month"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:64
+msgid "week"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:65
+msgid "day"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:66
+msgid "hour"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:67
+msgid "minute"
+msgstr ""
+
#: mediagoblin/user_pages/forms.py:23
msgid "Comment"
msgstr "Comentário"
@@ -1096,79 +1174,83 @@ msgstr "Coleção"
#: mediagoblin/user_pages/forms.py:40
msgid "-- Select --"
-msgstr ""
+msgstr "-- Selecionar --"
#: mediagoblin/user_pages/forms.py:42
msgid "Include a note"
msgstr "Incluir uma nota"
-#: mediagoblin/user_pages/lib.py:56
+#: mediagoblin/user_pages/lib.py:58
msgid "commented on your post"
msgstr "comentou na sua publicação"
-#: mediagoblin/user_pages/views.py:166
+#: mediagoblin/user_pages/views.py:169
+msgid "Sorry, comments are disabled."
+msgstr ""
+
+#: mediagoblin/user_pages/views.py:174
msgid "Oops, your comment was empty."
msgstr "Ops, seu comentário estava vazio."
-#: mediagoblin/user_pages/views.py:172
+#: mediagoblin/user_pages/views.py:180
msgid "Your comment has been posted!"
msgstr "Seu comentário foi postado!"
-#: mediagoblin/user_pages/views.py:197
+#: mediagoblin/user_pages/views.py:205
msgid "Please check your entries and try again."
-msgstr ""
+msgstr "Por favor, verifique suas entradas e tente novamente."
-#: mediagoblin/user_pages/views.py:237
+#: mediagoblin/user_pages/views.py:245
msgid "You have to select or add a collection"
msgstr "Você deve selecionar ou adicionar uma coleção"
-#: mediagoblin/user_pages/views.py:248
+#: mediagoblin/user_pages/views.py:256
#, python-format
msgid "\"%s\" already in collection \"%s\""
msgstr "\"%s\" já está na coleção \"%s\""
-#: mediagoblin/user_pages/views.py:264
+#: mediagoblin/user_pages/views.py:262
#, python-format
msgid "\"%s\" added to collection \"%s\""
msgstr "\"%s\" adicionado à coleção \"%s\""
-#: mediagoblin/user_pages/views.py:286
+#: mediagoblin/user_pages/views.py:282
msgid "You deleted the media."
msgstr "Você deletou a mídia."
-#: mediagoblin/user_pages/views.py:293
+#: mediagoblin/user_pages/views.py:289
msgid "The media was not deleted because you didn't check that you were sure."
msgstr "A mídia não foi apagada porque você não marcou que tinha certeza."
-#: mediagoblin/user_pages/views.py:301
+#: mediagoblin/user_pages/views.py:296
msgid "You are about to delete another user's media. Proceed with caution."
msgstr "Você vai apagar uma mídia de outro usuário. Tenha cuidado."
-#: mediagoblin/user_pages/views.py:375
+#: mediagoblin/user_pages/views.py:370
msgid "You deleted the item from the collection."
msgstr "Você deletou o item da coleção."
-#: mediagoblin/user_pages/views.py:379
+#: mediagoblin/user_pages/views.py:374
msgid "The item was not removed because you didn't check that you were sure."
msgstr "O item não foi apagado porque você não marcou que tinha certeza."
-#: mediagoblin/user_pages/views.py:389
+#: mediagoblin/user_pages/views.py:382
msgid ""
"You are about to delete an item from another user's collection. Proceed with"
" caution."
msgstr "Você está prestes a remover um item da coleção de um outro usuário. Prossiga com cuidado."
-#: mediagoblin/user_pages/views.py:422
+#: mediagoblin/user_pages/views.py:415
#, python-format
msgid "You deleted the collection \"%s\""
msgstr "Você deletou a coleção \"%s\""
-#: mediagoblin/user_pages/views.py:429
+#: mediagoblin/user_pages/views.py:422
msgid ""
"The collection was not deleted because you didn't check that you were sure."
msgstr "A coleção não foi apagada porque você não marcou que tinha certeza."
-#: mediagoblin/user_pages/views.py:439
+#: mediagoblin/user_pages/views.py:430
msgid ""
"You are about to delete another user's collection. Proceed with caution."
msgstr "Você está prestes a deletar a coleção de um outro usuário. Prossiga com cuidado."
diff --git a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo
index 62cbf028..8cfdf339 100644
--- a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo
+++ b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo
Binary files differ
diff --git a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po
index da585d5c..af2d94d6 100644
--- a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po
+++ b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po
@@ -3,14 +3,14 @@
# This file is distributed under the same license as the PROJECT project.
#
# Translators:
-# <gapop@hotmail.com>, 2011.
-# George Pop <gapop@hotmail.com>, 2011-2013.
+# George Pop <gapop@hotmail.com>, 2011
+# George Pop <gapop@hotmail.com>, 2011-2013
msgid ""
msgstr ""
"Project-Id-Version: GNU MediaGoblin\n"
"Report-Msgid-Bugs-To: http://issues.mediagoblin.org/\n"
-"POT-Creation-Date: 2013-03-04 18:04-0600\n"
-"PO-Revision-Date: 2013-03-10 04:13+0000\n"
+"POT-Creation-Date: 2013-05-27 13:54-0500\n"
+"PO-Revision-Date: 2013-05-27 20:40+0000\n"
"Last-Translator: George Pop <gapop@hotmail.com>\n"
"Language-Team: Romanian (http://www.transifex.com/projects/p/mediagoblin/language/ro/)\n"
"MIME-Version: 1.0\n"
@@ -20,34 +20,39 @@ msgstr ""
"Language: ro\n"
"Plural-Forms: nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?2:1));\n"
-#: mediagoblin/auth/forms.py:28
-msgid "Invalid User name or email address."
-msgstr "Nume de utilizator sau adresă de e-mail nevalidă."
-
-#: mediagoblin/auth/forms.py:29
-msgid "This field does not take email addresses."
-msgstr "Această rubrică nu este pentru adrese de e-mail."
-
-#: mediagoblin/auth/forms.py:30
-msgid "This field requires an email address."
-msgstr "Această rubrică trebuie completată cu o adresă de e-mail."
-
-#: mediagoblin/auth/forms.py:52 mediagoblin/auth/forms.py:67
+#: mediagoblin/auth/forms.py:26
msgid "Username"
msgstr "Nume de utilizator"
-#: mediagoblin/auth/forms.py:56 mediagoblin/auth/forms.py:71
+#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:45
+#: mediagoblin/tests/test_util.py:110
msgid "Password"
msgstr "Parolă"
-#: mediagoblin/auth/forms.py:60
+#: mediagoblin/auth/forms.py:34
msgid "Email address"
msgstr "Adresa de e-mail"
-#: mediagoblin/auth/forms.py:78
+#: mediagoblin/auth/forms.py:41
+msgid "Username or Email"
+msgstr "Numele de utilizator sau adresa de e-mail"
+
+#: mediagoblin/auth/forms.py:52
msgid "Username or email"
msgstr "Numele de utilizator sau adresa de e-mail"
+#: mediagoblin/auth/tools.py:31
+msgid "Invalid User name or email address."
+msgstr "Nume de utilizator sau adresă de e-mail nevalidă."
+
+#: mediagoblin/auth/tools.py:32
+msgid "This field does not take email addresses."
+msgstr "Această rubrică nu este pentru adrese de e-mail."
+
+#: mediagoblin/auth/tools.py:33
+msgid "This field requires an email address."
+msgstr "Această rubrică trebuie completată cu o adresă de e-mail."
+
#: mediagoblin/auth/views.py:54
msgid "Sorry, registration is disabled on this instance."
msgstr "Ne pare rău, dar înscrierile sunt dezactivate pe acest server."
@@ -60,54 +65,54 @@ msgstr "Ne pare rău, există deja un utilizator cu același nume."
msgid "Sorry, a user with that email address already exists."
msgstr "Există deja un utilizator înregistrat cu această adresă de e-mail."
-#: mediagoblin/auth/views.py:174
+#: mediagoblin/auth/views.py:182
msgid ""
"Your email address has been verified. You may now login, edit your profile, "
"and submit images!"
msgstr "Adresa ta de e-mail a fost verificată. Poți să te autentifici, să îți completezi profilul și să trimiți imagini!"
-#: mediagoblin/auth/views.py:180
+#: mediagoblin/auth/views.py:188
msgid "The verification key or user id is incorrect"
msgstr "Cheie de verificare sau user ID incorect."
-#: mediagoblin/auth/views.py:198
+#: mediagoblin/auth/views.py:206
msgid "You must be logged in so we know who to send the email to!"
msgstr "Trebuie să fii autentificat ca să știm cui să trimitem mesajul!"
-#: mediagoblin/auth/views.py:206
+#: mediagoblin/auth/views.py:214
msgid "You've already verified your email address!"
msgstr "Adresa ta de e-mail a fost deja verificată!"
-#: mediagoblin/auth/views.py:219
+#: mediagoblin/auth/views.py:227
msgid "Resent your verification email."
msgstr "E-mail-ul de verificare a fost retrimis."
-#: mediagoblin/auth/views.py:250
+#: mediagoblin/auth/views.py:258
msgid ""
"If that email address (case sensitive!) is registered an email has been sent"
" with instructions on how to change your password."
msgstr "Dacă adresa de e-mail este în baza noastră de date, atunci se va trimite imediat un mesaj cu instrucțiuni pentru schimbarea parolei. Țineți cont de litere mari / litere mici la introducerea adresei!"
-#: mediagoblin/auth/views.py:261
+#: mediagoblin/auth/views.py:269
msgid "Couldn't find someone with that username."
msgstr "Nu există nimeni cu acest nume de utilizator."
-#: mediagoblin/auth/views.py:264
+#: mediagoblin/auth/views.py:272
msgid ""
"An email has been sent with instructions on how to change your password."
msgstr "S-a trimis un e-mail cu instrucțiuni pentru schimbarea parolei."
-#: mediagoblin/auth/views.py:271
+#: mediagoblin/auth/views.py:279
msgid ""
"Could not send password recovery email as your username is inactive or your "
"account's email address has not been verified."
msgstr "E-mailul pentru recuperarea parolei nu a putut fi trimis deoarece contul tău e inactiv sau adresa ta de e-mail nu a fost verificată."
-#: mediagoblin/auth/views.py:328
+#: mediagoblin/auth/views.py:336
msgid "You can now log in using your new password."
msgstr "Acum te poți autentifica cu noua parolă."
-#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:93
+#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:82
#: mediagoblin/submit/forms.py:28 mediagoblin/submit/forms.py:47
#: mediagoblin/user_pages/forms.py:45
msgid "Title"
@@ -118,7 +123,7 @@ msgid "Description of this work"
msgstr "Descrierea acestui fișier"
#: mediagoblin/edit/forms.py:29 mediagoblin/edit/forms.py:52
-#: mediagoblin/edit/forms.py:97 mediagoblin/submit/forms.py:32
+#: mediagoblin/edit/forms.py:86 mediagoblin/submit/forms.py:32
#: mediagoblin/submit/forms.py:51 mediagoblin/user_pages/forms.py:49
msgid ""
"You can use\n"
@@ -134,11 +139,11 @@ msgstr "Cuvinte-cheie"
msgid "Separate tags by commas."
msgstr "Desparte cuvintele-cheie prin virgulă."
-#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:101
+#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:90
msgid "Slug"
msgstr "Identificator"
-#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:102
+#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:91
msgid "The slug can't be empty"
msgstr "Identificatorul nu poate să lipsească"
@@ -166,45 +171,45 @@ msgid "This address contains errors"
msgstr "Această adresă prezintă erori"
#: mediagoblin/edit/forms.py:63
-msgid "Old password"
-msgstr "Vechea parolă"
-
-#: mediagoblin/edit/forms.py:64
-msgid "Enter your old password to prove you own this account."
-msgstr "Introdu vechea parolă pentru a demonstra că ești titularul acestui cont."
-
-#: mediagoblin/edit/forms.py:67
-msgid "New password"
-msgstr "Noua parolă"
-
-#: mediagoblin/edit/forms.py:74
msgid "License preference"
msgstr "Licența preferată"
-#: mediagoblin/edit/forms.py:80
+#: mediagoblin/edit/forms.py:69
msgid "This will be your default license on upload forms."
msgstr "Aceasta va fi licența implicită pe formularele de upload."
-#: mediagoblin/edit/forms.py:82
+#: mediagoblin/edit/forms.py:71
msgid "Email me when others comment on my media"
msgstr "Trimite-mi un e-mail când alții comentează fișierele mele"
-#: mediagoblin/edit/forms.py:94
+#: mediagoblin/edit/forms.py:83
msgid "The title can't be empty"
msgstr "Titlul nu poate să fie gol"
-#: mediagoblin/edit/forms.py:96 mediagoblin/submit/forms.py:50
+#: mediagoblin/edit/forms.py:85 mediagoblin/submit/forms.py:50
#: mediagoblin/user_pages/forms.py:48
msgid "Description of this collection"
msgstr "Descriere pentru această colecție"
-#: mediagoblin/edit/forms.py:103
+#: mediagoblin/edit/forms.py:92
msgid ""
"The title part of this collection's address. You usually don't need to "
"change this."
msgstr "Partea din adresa acestei colecții care corespunde titlului. De regulă nu e necesar să faci o modificare."
-#: mediagoblin/edit/views.py:66
+#: mediagoblin/edit/forms.py:99
+msgid "Old password"
+msgstr "Vechea parolă"
+
+#: mediagoblin/edit/forms.py:101
+msgid "Enter your old password to prove you own this account."
+msgstr "Introdu vechea parolă pentru a demonstra că ești titularul acestui cont."
+
+#: mediagoblin/edit/forms.py:104
+msgid "New password"
+msgstr "Noua parolă"
+
+#: mediagoblin/edit/views.py:67
msgid "An entry with that slug already exists for this user."
msgstr "Există deja un entry cu același identificator pentru acest utilizator."
@@ -229,44 +234,63 @@ msgstr "Editezi profilul unui utilizator. Se recomandă prudență."
msgid "Profile changes saved"
msgstr "Modificările profilului au fost salvate"
-#: mediagoblin/edit/views.py:241
-msgid "Wrong password"
-msgstr "Parolă incorectă"
-
-#: mediagoblin/edit/views.py:252
+#: mediagoblin/edit/views.py:240
msgid "Account settings saved"
msgstr "Setările pentru acest cont au fost salvate"
-#: mediagoblin/edit/views.py:286
+#: mediagoblin/edit/views.py:274
msgid "You need to confirm the deletion of your account."
msgstr "Trebuie să confirmi ștergerea contului tău."
-#: mediagoblin/edit/views.py:322 mediagoblin/submit/views.py:142
-#: mediagoblin/user_pages/views.py:214
+#: mediagoblin/edit/views.py:310 mediagoblin/submit/views.py:138
+#: mediagoblin/user_pages/views.py:222
#, python-format
msgid "You already have a collection called \"%s\"!"
msgstr "Ai deja o colecție numită \"%s\"!"
-#: mediagoblin/edit/views.py:326
+#: mediagoblin/edit/views.py:314
msgid "A collection with that slug already exists for this user."
msgstr "O colecție cu același slug există deja pentru acest utilizator."
-#: mediagoblin/edit/views.py:343
+#: mediagoblin/edit/views.py:329
msgid "You are editing another user's collection. Proceed with caution."
msgstr "Lucrezi pe colecția unui alt utilizator. Se recomandă prudență."
-#: mediagoblin/gmg_commands/theme.py:58
+#: mediagoblin/edit/views.py:348
+msgid "Wrong password"
+msgstr "Parolă incorectă"
+
+#: mediagoblin/edit/views.py:363
+msgid "Your password was changed successfully"
+msgstr "Parola a fost schimbată cu succes"
+
+#: mediagoblin/gmg_commands/assetlink.py:60
msgid "Cannot link theme... no theme set\n"
msgstr "Tema nu poate fi atașată... nu există o temă selectată\n"
-#: mediagoblin/gmg_commands/theme.py:71
+#: mediagoblin/gmg_commands/assetlink.py:73
msgid "No asset directory for this theme\n"
msgstr "Nu există un folder de elemente pentru această temă\n"
-#: mediagoblin/gmg_commands/theme.py:74
+#: mediagoblin/gmg_commands/assetlink.py:76
msgid "However, old link directory symlink found; removed.\n"
msgstr "A fost însă găsit un symlink către vechiul folder; s-a șters.\n"
+#: mediagoblin/gmg_commands/assetlink.py:112
+#, python-format
+msgid "Could not link \"%s\": %s exists and is not a symlink\n"
+msgstr "Nu s-a putut crea link pentru \"%s\": %s există deja și nu este symlink\n"
+
+#: mediagoblin/gmg_commands/assetlink.py:119
+#, python-format
+msgid "Skipping \"%s\"; already set up.\n"
+msgstr "S-a omis \"%s\"; configurat deja.\n"
+
+#: mediagoblin/gmg_commands/assetlink.py:124
+#, python-format
+msgid "Old link found for \"%s\"; removing.\n"
+msgstr "Există deja un link pentru \"%s\"; va fi șters.\n"
+
#: mediagoblin/meddleware/csrf.py:134
msgid ""
"CSRF cookie not present. This is most likely the result of a cookie blocker "
@@ -274,12 +298,16 @@ msgid ""
"domain."
msgstr "Lipsește cookie-ul CSRF. Probabil că blocați cookie-urile.<br/>Asigurați-vă că există permisiunea setării cookie-urilor pentru acest domeniu."
-#: mediagoblin/media_types/__init__.py:61
-#: mediagoblin/media_types/__init__.py:102
+#: mediagoblin/media_types/__init__.py:111
+#: mediagoblin/media_types/__init__.py:155
msgid "Sorry, I don't support that file type :("
msgstr "Scuze, nu recunosc acest tip de fișier :("
-#: mediagoblin/media_types/video/processing.py:36
+#: mediagoblin/media_types/pdf/processing.py:136
+msgid "unoconv failing to run, check log file"
+msgstr "unoconv nu poate fi executat; verificați log-ul"
+
+#: mediagoblin/media_types/video/processing.py:37
msgid "Video transcoding failed"
msgstr "Transcodarea video a eșuat"
@@ -346,7 +374,7 @@ msgstr "URI-ul de redirectare pentru aplicații, această rubrică\n
msgid "This field is required for public clients"
msgstr "Această rubrică este obligatorie pentru clienții publici"
-#: mediagoblin/plugins/oauth/views.py:59
+#: mediagoblin/plugins/oauth/views.py:56
msgid "The client {0} has been registered!"
msgstr "Clientul {0} a fost înregistrat!"
@@ -365,7 +393,7 @@ msgstr "Clienții tăi OAuth"
msgid "Add"
msgstr "Adaugă"
-#: mediagoblin/processing/__init__.py:172
+#: mediagoblin/processing/__init__.py:193
msgid "Invalid file given for media type."
msgstr "Formatul fișierului nu corespunde cu tipul de media selectat."
@@ -373,45 +401,45 @@ msgstr "Formatul fișierului nu corespunde cu tipul de media selectat."
msgid "File"
msgstr "Fișier"
-#: mediagoblin/submit/views.py:51
+#: mediagoblin/submit/views.py:49
msgid "You must provide a file."
msgstr "Trebuie să selectezi un fișier."
-#: mediagoblin/submit/views.py:97
+#: mediagoblin/submit/views.py:93
msgid "Woohoo! Submitted!"
msgstr "Ura! Trimis!"
-#: mediagoblin/submit/views.py:146
+#: mediagoblin/submit/views.py:144
#, python-format
msgid "Collection \"%s\" added!"
msgstr "Colecția \"%s\" a fost creată!"
-#: mediagoblin/templates/mediagoblin/base.html:64
+#: mediagoblin/templates/mediagoblin/base.html:67
msgid "Verify your email!"
msgstr "Verifică adresa de e-mail!"
-#: mediagoblin/templates/mediagoblin/base.html:65
+#: mediagoblin/templates/mediagoblin/base.html:68
msgid "log out"
msgstr "Ieșire"
-#: mediagoblin/templates/mediagoblin/base.html:70
+#: mediagoblin/templates/mediagoblin/base.html:73
#: mediagoblin/templates/mediagoblin/auth/login.html:28
#: mediagoblin/templates/mediagoblin/auth/login.html:36
#: mediagoblin/templates/mediagoblin/auth/login.html:54
msgid "Log in"
msgstr "Autentificare"
-#: mediagoblin/templates/mediagoblin/base.html:79
+#: mediagoblin/templates/mediagoblin/base.html:82
#, python-format
msgid "<a href=\"%(user_url)s\">%(user_name)s</a>'s account"
msgstr "Contul lui <a href=\"%(user_url)s\">%(user_name)s</a>"
-#: mediagoblin/templates/mediagoblin/base.html:86
+#: mediagoblin/templates/mediagoblin/base.html:89
msgid "Change account settings"
msgstr "Modifică setările contului"
-#: mediagoblin/templates/mediagoblin/base.html:90
-#: mediagoblin/templates/mediagoblin/base.html:105
+#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:108
#: mediagoblin/templates/mediagoblin/admin/panel.html:21
#: mediagoblin/templates/mediagoblin/admin/panel.html:26
#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:21
@@ -419,72 +447,25 @@ msgstr "Modifică setările contului"
msgid "Media processing panel"
msgstr "Panou de procesare media"
-#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:96
msgid "Log out"
msgstr "Ieșire"
-#: mediagoblin/templates/mediagoblin/base.html:96
+#: mediagoblin/templates/mediagoblin/base.html:99
#: mediagoblin/templates/mediagoblin/user_pages/user.html:156
msgid "Add media"
msgstr "Trimite fișier"
-#: mediagoblin/templates/mediagoblin/base.html:99
+#: mediagoblin/templates/mediagoblin/base.html:102
#: mediagoblin/templates/mediagoblin/user_pages/collection_list.html:41
msgid "Create new collection"
msgstr "Creează colecție nouă"
-#: mediagoblin/templates/mediagoblin/base.html:122
-#, python-format
-msgid ""
-"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
-"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
-msgstr "Construit cu <a href=\"http://mediagoblin.org/\" title='Versiunea %(version)s'>MediaGoblin</a>, un proiect <a href=\"http://gnu.org/\">GNU</a>."
-
-#: mediagoblin/templates/mediagoblin/base.html:125
-#, python-format
-msgid ""
-"Released under the <a "
-"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
-"href=\"%(source_link)s\">Source code</a> available."
-msgstr "Publicat sub licența <a href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a href=\"%(source_link)s\">Codul sursă</a> este disponibil."
-
#: mediagoblin/templates/mediagoblin/error.html:24
msgid "Image of goblin stressing out"
msgstr "Imagine cu un goblin stresat"
-#: mediagoblin/templates/mediagoblin/root.html:31
-msgid "Explore"
-msgstr "Explorează"
-
-#: mediagoblin/templates/mediagoblin/root.html:33
-msgid "Hi there, welcome to this MediaGoblin site!"
-msgstr "Salut, bine ai venit pe acest site MediaGoblin!"
-
-#: mediagoblin/templates/mediagoblin/root.html:35
-msgid ""
-"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
-"extraordinarily great piece of media hosting software."
-msgstr "Acest site folosește <a href=\"http://mediagoblin.org\">MediaGoblin</a>, un software excepțional pentru găzduirea fișierelor media."
-
-#: mediagoblin/templates/mediagoblin/root.html:36
-msgid ""
-"To add your own media, place comments, and more, you can log in with your "
-"MediaGoblin account."
-msgstr "Pentru a adăuga fișierele tale și pentru a comenta te poți autentifica cu contul tău MediaGoblin."
-
-#: mediagoblin/templates/mediagoblin/root.html:38
-msgid "Don't have one yet? It's easy!"
-msgstr "Încă nu ai unul? E simplu!"
-
-#: mediagoblin/templates/mediagoblin/root.html:39
-#, python-format
-msgid ""
-"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
-" or\n"
-" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
-msgstr "<a class=\"button_action_highlight\" href=\"%(register_url)s\">Creează un cont pe acest site</a>\n sau\n <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Instalează MediaGoblin pe serverul tău</a>"
-
-#: mediagoblin/templates/mediagoblin/root.html:47
+#: mediagoblin/templates/mediagoblin/root.html:32
msgid "Most recent media"
msgstr "Cele mai recente fișiere"
@@ -590,6 +571,53 @@ msgid ""
"%(verification_url)s"
msgstr "Bună, %(username)s,\n\npentru activarea contului tău la GNU MediaGoblin, accesează adresa următoare:\n\n%(verification_url)s"
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:21
+#, python-format
+msgid ""
+"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
+"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
+msgstr "Construit cu <a href=\"http://mediagoblin.org/\" title='Versiunea %(version)s'>MediaGoblin</a>, un proiect <a href=\"http://gnu.org/\">GNU</a>."
+
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:24
+#, python-format
+msgid ""
+"Released under the <a "
+"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
+"href=\"%(source_link)s\">Source code</a> available."
+msgstr "Publicat sub licența <a href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a href=\"%(source_link)s\">Codul sursă</a> este disponibil."
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:20
+msgid "Explore"
+msgstr "Explorează"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:22
+msgid "Hi there, welcome to this MediaGoblin site!"
+msgstr "Salut, bine ai venit pe acest site MediaGoblin!"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:24
+msgid ""
+"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
+"extraordinarily great piece of media hosting software."
+msgstr "Acest site folosește <a href=\"http://mediagoblin.org\">MediaGoblin</a>, un software excepțional pentru găzduirea fișierelor media."
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:25
+msgid ""
+"To add your own media, place comments, and more, you can log in with your "
+"MediaGoblin account."
+msgstr "Pentru a adăuga fișierele tale și pentru a comenta te poți autentifica cu contul tău MediaGoblin."
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:27
+msgid "Don't have one yet? It's easy!"
+msgstr "Încă nu ai unul? E simplu!"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:28
+#, python-format
+msgid ""
+"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
+" or\n"
+" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
+msgstr "<a class=\"button_action_highlight\" href=\"%(register_url)s\">Creați un cont pe acest site</a>\n sau\n <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Instalați MediaGoblin pe serverul dvs.</a>"
+
#: mediagoblin/templates/mediagoblin/bits/logo.html:23
#: mediagoblin/themes/airy/templates/mediagoblin/bits/logo.html:23
msgid "MediaGoblin logo"
@@ -602,13 +630,13 @@ msgid "Editing attachments for %(media_title)s"
msgstr "Editare anexe la %(media_title)s"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:159
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:175
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:182
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:198
msgid "Attachments"
msgstr "Anexe"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:57
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:181
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:204
msgid "Add attachment"
msgstr "Atașează"
@@ -625,12 +653,22 @@ msgstr "Anulare"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:63
#: mediagoblin/templates/mediagoblin/edit/edit.html:42
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:52
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:55
#: mediagoblin/templates/mediagoblin/edit/edit_collection.html:33
#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:40
msgid "Save changes"
msgstr "Salvează modificările"
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:28
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:38
+#, python-format
+msgid "Changing %(username)s's password"
+msgstr "Se modifică parola pentru %(username)s"
+
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:45
+msgid "Save"
+msgstr "Salvează"
+
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:28
#, python-format
msgid "Really delete user '%(user_name)s' and all related media/comments?"
@@ -641,7 +679,7 @@ msgid "Yes, really delete my account"
msgstr "Da, doresc ștergerea contului meu"
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:47
+#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:48
#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:49
msgid "Delete permanently"
msgstr "Șterge definitiv"
@@ -658,7 +696,11 @@ msgstr "Editare %(media_title)s"
msgid "Changing %(username)s's account settings"
msgstr "Se modifică setările contului pentru userul %(username)s"
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:59
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:46
+msgid "Change your password."
+msgstr "Modifică parolă."
+
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:62
msgid "Delete my account"
msgstr "Șterge contul meu"
@@ -683,6 +725,7 @@ msgstr "Fișier etichetat cu cuvintele-cheie: %(tag_name)s"
#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:56
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:65
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:136
#: mediagoblin/templates/mediagoblin/media_displays/video.html:55
msgid "Download"
@@ -707,6 +750,7 @@ msgid ""
msgstr "Poți lua un browser modern \n\tcapabil să redea această înregistrare de la <a href=\"http://getfirefox.com\">\n\t http://getfirefox.com</a>!"
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:60
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:71
#: mediagoblin/templates/mediagoblin/media_displays/video.html:61
msgid "Original file"
msgstr "Fișierul original"
@@ -715,6 +759,7 @@ msgstr "Fișierul original"
msgid "WebM file (Vorbis codec)"
msgstr "Fișier WebM (codec Vorbis)"
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:59
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:87
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:93
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:99
@@ -725,6 +770,10 @@ msgstr "Fișier WebM (codec Vorbis)"
msgid "Image for %(media_title)s"
msgstr "Imagine pentru %(media_title)s"
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:79
+msgid "PDF file"
+msgstr "Fișier PDF"
+
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:112
msgid "Toggle Rotate"
msgstr "Rotire"
@@ -823,7 +872,7 @@ msgstr "Sigur dorești să ștergi %(title)s?"
msgid "Really remove %(media_title)s from %(collection_title)s?"
msgstr "Sigur dorești să ștergi %(media_title)s din %(collection_title)s?"
-#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:53
+#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:54
msgid "Remove"
msgstr "Șterge"
@@ -866,24 +915,28 @@ msgstr "Fișierele media ale lui <a href=\"%(user_url)s\">%(username)s</a>"
msgid "â– Browsing media by <a href=\"%(user_url)s\">%(username)s</a>"
msgstr "<p>■Fișierele media ale lui <a href=\"%(user_url)s\">%(username)s</a></p>"
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:94
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:95
msgid "Add a comment"
msgstr "Adaugă un comentariu"
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:102
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:104
msgid "Add this comment"
msgstr "Trimite acest comentariu"
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:123
-msgid "at"
-msgstr "la"
-
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:144
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:132
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:152
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:164
#, python-format
-msgid ""
-"<h3>Added on</h3>\n"
-" <p>%(date)s</p>"
-msgstr "<h3>Adăugat la</h3>\n <p>%(date)s</p>"
+msgid "%(formatted_time)s ago"
+msgstr "în urmă cu %(formatted_time)s"
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:150
+msgid "Added"
+msgstr "Adăugat"
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:161
+msgid "Created"
+msgstr "Creat"
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:28
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:40
@@ -1039,7 +1092,7 @@ msgstr "mai vechi"
msgid "Tagged with"
msgstr "Etichetat cu cuvintele-cheie"
-#: mediagoblin/tools/exif.py:80
+#: mediagoblin/tools/exif.py:83
msgid "Could not read the image file."
msgstr "Fișierul cu imaginea nu a putut fi citit."
@@ -1069,6 +1122,30 @@ msgid ""
" deleted."
msgstr "Nu există nicio pagină la această adresă.</p><p>Dacă sunteți sigur că adresa este corectă, poate că pagina pe care o căutați a fost mutată sau ștearsă."
+#: mediagoblin/tools/timesince.py:62
+msgid "year"
+msgstr "anul"
+
+#: mediagoblin/tools/timesince.py:63
+msgid "month"
+msgstr "luna"
+
+#: mediagoblin/tools/timesince.py:64
+msgid "week"
+msgstr "săptămâna"
+
+#: mediagoblin/tools/timesince.py:65
+msgid "day"
+msgstr "ziua"
+
+#: mediagoblin/tools/timesince.py:66
+msgid "hour"
+msgstr "ora"
+
+#: mediagoblin/tools/timesince.py:67
+msgid "minute"
+msgstr "minutul"
+
#: mediagoblin/user_pages/forms.py:23
msgid "Comment"
msgstr "Comentariu"
@@ -1100,73 +1177,77 @@ msgstr "-- Selectează --"
msgid "Include a note"
msgstr "Adaugă o notiță"
-#: mediagoblin/user_pages/lib.py:56
+#: mediagoblin/user_pages/lib.py:58
msgid "commented on your post"
msgstr "a făcut un comentariu la postarea ta"
-#: mediagoblin/user_pages/views.py:166
+#: mediagoblin/user_pages/views.py:169
+msgid "Sorry, comments are disabled."
+msgstr "Comentariile sunt dezactivate."
+
+#: mediagoblin/user_pages/views.py:174
msgid "Oops, your comment was empty."
msgstr "Hopa, ai uitat să scrii comentariul."
-#: mediagoblin/user_pages/views.py:172
+#: mediagoblin/user_pages/views.py:180
msgid "Your comment has been posted!"
msgstr "Comentariul tău a fost trimis!"
-#: mediagoblin/user_pages/views.py:197
+#: mediagoblin/user_pages/views.py:205
msgid "Please check your entries and try again."
msgstr "Verifică datele și încearcă din nou."
-#: mediagoblin/user_pages/views.py:237
+#: mediagoblin/user_pages/views.py:245
msgid "You have to select or add a collection"
msgstr "Trebuie să alegi sau să creezi o colecție"
-#: mediagoblin/user_pages/views.py:248
+#: mediagoblin/user_pages/views.py:256
#, python-format
msgid "\"%s\" already in collection \"%s\""
msgstr "\"%s\" este deja în colecția \"%s\""
-#: mediagoblin/user_pages/views.py:264
+#: mediagoblin/user_pages/views.py:262
#, python-format
msgid "\"%s\" added to collection \"%s\""
msgstr "\"%s\" a fost adăugat la colecția \"%s\""
-#: mediagoblin/user_pages/views.py:286
+#: mediagoblin/user_pages/views.py:282
msgid "You deleted the media."
msgstr "Ai șters acest fișier"
-#: mediagoblin/user_pages/views.py:293
+#: mediagoblin/user_pages/views.py:289
msgid "The media was not deleted because you didn't check that you were sure."
msgstr "Fișierul nu a fost șters deoarece nu ai confirmat că ești sigur."
-#: mediagoblin/user_pages/views.py:301
+#: mediagoblin/user_pages/views.py:296
msgid "You are about to delete another user's media. Proceed with caution."
msgstr "Urmează să ștergi fișierele media ale unui alt utilizator. Se recomandă prudență."
-#: mediagoblin/user_pages/views.py:375
+#: mediagoblin/user_pages/views.py:370
msgid "You deleted the item from the collection."
msgstr "Ai șters acest articol din colecție."
-#: mediagoblin/user_pages/views.py:379
+#: mediagoblin/user_pages/views.py:374
msgid "The item was not removed because you didn't check that you were sure."
msgstr "Articolul nu a fost șters pentru că nu ai confirmat că ești sigur(ă)."
-#: mediagoblin/user_pages/views.py:389
+#: mediagoblin/user_pages/views.py:382
msgid ""
"You are about to delete an item from another user's collection. Proceed with"
" caution."
msgstr "Urmează să ștergi un articol din colecția unui alt utilizator. Se recomandă prudență."
-#: mediagoblin/user_pages/views.py:422
+#: mediagoblin/user_pages/views.py:415
#, python-format
msgid "You deleted the collection \"%s\""
msgstr "Ai șters colecția \"%s\""
-#: mediagoblin/user_pages/views.py:429
+#: mediagoblin/user_pages/views.py:422
msgid ""
"The collection was not deleted because you didn't check that you were sure."
msgstr "Colecția nu a fost ștearsă pentru că nu ai confirmat că ești sigur(ă)."
-#: mediagoblin/user_pages/views.py:439
+#: mediagoblin/user_pages/views.py:430
msgid ""
"You are about to delete another user's collection. Proceed with caution."
msgstr "Urmează să ștergi colecția unui alt utilizator. Se recomandă prudență."
diff --git a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo
index 759f5337..ed28ff43 100644
--- a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo
+++ b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo
Binary files differ
diff --git a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po
index 0dc099ed..d0ff7bdd 100644
--- a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po
+++ b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po
@@ -3,16 +3,16 @@
# This file is distributed under the same license as the PROJECT project.
#
# Translators:
-# <deletesoftware@yandex.ru>, 2013.
-# <deletesoftware@yandex.ru>, 2011-2012.
+# aleksejrs <deletesoftware@yandex.ru>, 2013
+# aleksejrs <deletesoftware@yandex.ru>, 2011-2012
msgid ""
msgstr ""
"Project-Id-Version: GNU MediaGoblin\n"
"Report-Msgid-Bugs-To: http://issues.mediagoblin.org/\n"
-"POT-Creation-Date: 2013-03-04 18:04-0600\n"
-"PO-Revision-Date: 2013-03-10 15:35+0000\n"
+"POT-Creation-Date: 2013-05-27 13:54-0500\n"
+"PO-Revision-Date: 2013-06-01 21:08+0000\n"
"Last-Translator: aleksejrs <deletesoftware@yandex.ru>\n"
-"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language-Team: Russian (http://www.transifex.com/projects/p/mediagoblin/language/ru/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
@@ -20,34 +20,39 @@ msgstr ""
"Language: ru\n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
-#: mediagoblin/auth/forms.py:28
-msgid "Invalid User name or email address."
-msgstr ""
-
-#: mediagoblin/auth/forms.py:29
-msgid "This field does not take email addresses."
-msgstr "Это поле не Ð´Ð»Ñ Ð°Ð´Ñ€ÐµÑа Ñлектронной почты."
-
-#: mediagoblin/auth/forms.py:30
-msgid "This field requires an email address."
-msgstr "Это поле — Ð´Ð»Ñ Ð°Ð´Ñ€ÐµÑа Ñлектронной почты."
-
-#: mediagoblin/auth/forms.py:52 mediagoblin/auth/forms.py:67
+#: mediagoblin/auth/forms.py:26
msgid "Username"
msgstr "Логин"
-#: mediagoblin/auth/forms.py:56 mediagoblin/auth/forms.py:71
+#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:45
+#: mediagoblin/tests/test_util.py:110
msgid "Password"
msgstr "Пароль"
-#: mediagoblin/auth/forms.py:60
+#: mediagoblin/auth/forms.py:34
msgid "Email address"
msgstr "ÐÐ´Ñ€ÐµÑ Ñлектронной почты"
-#: mediagoblin/auth/forms.py:78
+#: mediagoblin/auth/forms.py:41
+msgid "Username or Email"
+msgstr "Ð˜Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð¸Ð»Ð¸ Ð°Ð´Ñ€ÐµÑ Ñлектронной почты"
+
+#: mediagoblin/auth/forms.py:52
msgid "Username or email"
msgstr "Ð˜Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð¸Ð»Ð¸ Ð°Ð´Ñ€ÐµÑ Ñлектронной почты"
+#: mediagoblin/auth/tools.py:31
+msgid "Invalid User name or email address."
+msgstr ""
+
+#: mediagoblin/auth/tools.py:32
+msgid "This field does not take email addresses."
+msgstr "Это поле не Ð´Ð»Ñ Ð°Ð´Ñ€ÐµÑа Ñлектронной почты."
+
+#: mediagoblin/auth/tools.py:33
+msgid "This field requires an email address."
+msgstr "Это поле — Ð´Ð»Ñ Ð°Ð´Ñ€ÐµÑа Ñлектронной почты."
+
#: mediagoblin/auth/views.py:54
msgid "Sorry, registration is disabled on this instance."
msgstr "Извините, на Ñтом Ñайте региÑÑ‚Ñ€Ð°Ñ†Ð¸Ñ Ð·Ð°Ð¿Ñ€ÐµÑ‰ÐµÐ½Ð°."
@@ -60,54 +65,54 @@ msgstr "Извините, пользователь Ñ Ñтим именем уж
msgid "Sorry, a user with that email address already exists."
msgstr "Сожалеем, но на Ñтот Ð°Ð´Ñ€ÐµÑ Ñлектронной почты уже зарегиÑтрирована Ð´Ñ€ÑƒÐ³Ð°Ñ ÑƒÑ‡Ñ‘Ñ‚Ð½Ð°Ñ Ð·Ð°Ð¿Ð¸ÑÑŒ."
-#: mediagoblin/auth/views.py:174
+#: mediagoblin/auth/views.py:182
msgid ""
"Your email address has been verified. You may now login, edit your profile, "
"and submit images!"
msgstr "Ваш Ð°Ð´Ñ€ÐµÑ Ñлектронной почты потвержден. Ð’Ñ‹ теперь можете войти и начать редактировать Ñвой профиль и загружать новые изображениÑ!"
-#: mediagoblin/auth/views.py:180
+#: mediagoblin/auth/views.py:188
msgid "The verification key or user id is incorrect"
msgstr "Ðеверный ключ проверки или идентификатор пользователÑ"
-#: mediagoblin/auth/views.py:198
+#: mediagoblin/auth/views.py:206
msgid "You must be logged in so we know who to send the email to!"
msgstr "Вам надо предÑтавитьÑÑ, чтобы мы знали, кому отправлÑть Ñообщение!"
-#: mediagoblin/auth/views.py:206
+#: mediagoblin/auth/views.py:214
msgid "You've already verified your email address!"
msgstr "Ð’Ñ‹ уже потвердили Ñвой Ð°Ð´Ñ€ÐµÑ Ñлектронной почты!"
-#: mediagoblin/auth/views.py:219
+#: mediagoblin/auth/views.py:227
msgid "Resent your verification email."
msgstr "ПереÑлать Ñообщение Ñ Ð¿Ð¾Ð´Ñ‚Ð²ÐµÑ€Ð¶Ð´ÐµÐ½Ð¸ÐµÐ¼ аккаунта."
-#: mediagoblin/auth/views.py:250
+#: mediagoblin/auth/views.py:258
msgid ""
"If that email address (case sensitive!) is registered an email has been sent"
" with instructions on how to change your password."
msgstr "ЕÑли Ñ Ñтим адреÑом Ñлектронной почты (Ñравниваемым чувÑтвительно к региÑтру Ñимволов!) еÑть ÑƒÑ‡Ñ‘Ñ‚Ð½Ð°Ñ Ð·Ð°Ð¿Ð¸ÑÑŒ, то на него отправлено Ñообщение Ñ ÑƒÐºÐ°Ð·Ð°Ð½Ð¸Ñми о том, как Ñменить пароль."
-#: mediagoblin/auth/views.py:261
+#: mediagoblin/auth/views.py:269
msgid "Couldn't find someone with that username."
msgstr "Ðе найдено никого Ñ Ñ‚Ð°ÐºÐ¸Ð¼ именем пользователÑ."
-#: mediagoblin/auth/views.py:264
+#: mediagoblin/auth/views.py:272
msgid ""
"An email has been sent with instructions on how to change your password."
msgstr "Вам отправлено Ñлектронное пиÑьмо Ñ Ð¸Ð½ÑтрукциÑми по Ñмене паролÑ."
-#: mediagoblin/auth/views.py:271
+#: mediagoblin/auth/views.py:279
msgid ""
"Could not send password recovery email as your username is inactive or your "
"account's email address has not been verified."
msgstr "Мы не можем отправить Ñообщение Ð´Ð»Ñ Ð²Ð¾ÑÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ð¿Ð°Ñ€Ð¾Ð»Ñ, потому что ваша ÑƒÑ‡Ñ‘Ñ‚Ð½Ð°Ñ Ð·Ð°Ð¿Ð¸ÑÑŒ неактивна, либо указанный в ней Ð°Ð´Ñ€ÐµÑ Ñлектронной почты не был подтверждён."
-#: mediagoblin/auth/views.py:328
+#: mediagoblin/auth/views.py:336
msgid "You can now log in using your new password."
msgstr "Теперь вы можете войти, иÑÐ¿Ð¾Ð»ÑŒÐ·ÑƒÑ Ð²Ð°Ñˆ новый пароль."
-#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:93
+#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:82
#: mediagoblin/submit/forms.py:28 mediagoblin/submit/forms.py:47
#: mediagoblin/user_pages/forms.py:45
msgid "Title"
@@ -118,7 +123,7 @@ msgid "Description of this work"
msgstr "ОпиÑание Ñтого произведениÑ"
#: mediagoblin/edit/forms.py:29 mediagoblin/edit/forms.py:52
-#: mediagoblin/edit/forms.py:97 mediagoblin/submit/forms.py:32
+#: mediagoblin/edit/forms.py:86 mediagoblin/submit/forms.py:32
#: mediagoblin/submit/forms.py:51 mediagoblin/user_pages/forms.py:49
msgid ""
"You can use\n"
@@ -134,11 +139,11 @@ msgstr "Метки"
msgid "Separate tags by commas."
msgstr "(через запÑтую)"
-#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:101
+#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:90
msgid "Slug"
msgstr "ÐžÑ‚Ð»Ð¸Ñ‡Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð°Ñ Ñ‡Ð°Ñть адреÑа"
-#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:102
+#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:91
msgid "The slug can't be empty"
msgstr "ÐžÑ‚Ð»Ð¸Ñ‡Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð°Ñ Ñ‡Ð°Ñть адреÑа необходима"
@@ -166,45 +171,45 @@ msgid "This address contains errors"
msgstr "Этот Ð°Ð´Ñ€ÐµÑ Ñодержит ошибки"
#: mediagoblin/edit/forms.py:63
-msgid "Old password"
-msgstr "Старый пароль"
-
-#: mediagoblin/edit/forms.py:64
-msgid "Enter your old password to prove you own this account."
-msgstr "Введите Ñвой Ñтарый пароль в качеÑтве доказательÑтва, что Ñто ваша ÑƒÑ‡Ñ‘Ñ‚Ð½Ð°Ñ Ð·Ð°Ð¿Ð¸ÑÑŒ."
-
-#: mediagoblin/edit/forms.py:67
-msgid "New password"
-msgstr "Ðовый пароль"
-
-#: mediagoblin/edit/forms.py:74
msgid "License preference"
msgstr "ÐŸÑ€ÐµÐ´Ð¿Ð¾Ñ‡Ð¸Ñ‚Ð°ÐµÐ¼Ð°Ñ Ð»Ð¸Ñ†ÐµÐ½Ð·Ð¸Ñ"
-#: mediagoblin/edit/forms.py:80
+#: mediagoblin/edit/forms.py:69
msgid "This will be your default license on upload forms."
msgstr "Она будет лицензией по умолчанию Ð´Ð»Ñ Ð²Ð°ÑˆÐ¸Ñ… загрузок"
-#: mediagoblin/edit/forms.py:82
+#: mediagoblin/edit/forms.py:71
msgid "Email me when others comment on my media"
msgstr "УведомлÑть Ð¼ÐµÐ½Ñ Ð¿Ð¾ e-mail о комментариÑÑ… к моим файлам"
-#: mediagoblin/edit/forms.py:94
+#: mediagoblin/edit/forms.py:83
msgid "The title can't be empty"
msgstr "Ðазвание не может быть пуÑтым"
-#: mediagoblin/edit/forms.py:96 mediagoblin/submit/forms.py:50
+#: mediagoblin/edit/forms.py:85 mediagoblin/submit/forms.py:50
#: mediagoblin/user_pages/forms.py:48
msgid "Description of this collection"
msgstr "ОпиÑание Ñтой коллекции"
-#: mediagoblin/edit/forms.py:103
+#: mediagoblin/edit/forms.py:92
msgid ""
"The title part of this collection's address. You usually don't need to "
"change this."
msgstr "ÐžÑ‚Ð»Ð¸Ñ‡Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð°Ñ Ñ‡Ð°Ñть адреÑа Ñтой коллекции, оÑÐ½Ð¾Ð²Ð°Ð½Ð½Ð°Ñ Ð½Ð° названии. Обычно не нужно её изменÑть."
-#: mediagoblin/edit/views.py:66
+#: mediagoblin/edit/forms.py:99
+msgid "Old password"
+msgstr "Старый пароль"
+
+#: mediagoblin/edit/forms.py:101
+msgid "Enter your old password to prove you own this account."
+msgstr "Введите Ñвой Ñтарый пароль в качеÑтве доказательÑтва, что Ñто ваша ÑƒÑ‡Ñ‘Ñ‚Ð½Ð°Ñ Ð·Ð°Ð¿Ð¸ÑÑŒ."
+
+#: mediagoblin/edit/forms.py:104
+msgid "New password"
+msgstr "Ðовый пароль"
+
+#: mediagoblin/edit/views.py:67
msgid "An entry with that slug already exists for this user."
msgstr "У Ñтого Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ ÑƒÐ¶Ðµ еÑть файл Ñ Ñ‚Ð°ÐºÐ¾Ð¹ отличительной чаÑтью адреÑа."
@@ -229,44 +234,63 @@ msgstr "Ð’Ñ‹ редактируете профиль пользователÑ. Ð
msgid "Profile changes saved"
msgstr "Ð˜Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¾Ñ„Ð¸Ð»Ñ Ñохранены"
-#: mediagoblin/edit/views.py:241
-msgid "Wrong password"
-msgstr "Ðеправильный пароль"
-
-#: mediagoblin/edit/views.py:252
+#: mediagoblin/edit/views.py:240
msgid "Account settings saved"
msgstr "ÐаÑтройки учётной запиÑи запиÑаны"
-#: mediagoblin/edit/views.py:286
+#: mediagoblin/edit/views.py:274
msgid "You need to confirm the deletion of your account."
msgstr "Вам нужно подтвердить, что вы хотите удалить Ñвою учётную запиÑÑŒ."
-#: mediagoblin/edit/views.py:322 mediagoblin/submit/views.py:142
-#: mediagoblin/user_pages/views.py:214
+#: mediagoblin/edit/views.py:310 mediagoblin/submit/views.py:138
+#: mediagoblin/user_pages/views.py:222
#, python-format
msgid "You already have a collection called \"%s\"!"
msgstr "У Ð²Ð°Ñ ÑƒÐ¶Ðµ еÑть ÐºÐ¾Ð»Ð»ÐµÐºÑ†Ð¸Ñ Ñ Ð½Ð°Ð·Ð²Ð°Ð½Ð¸ÐµÐ¼ «%s»!"
-#: mediagoblin/edit/views.py:326
+#: mediagoblin/edit/views.py:314
msgid "A collection with that slug already exists for this user."
msgstr "У Ñтого Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ ÑƒÐ¶Ðµ еÑть ÐºÐ¾Ð»Ð»ÐµÐºÑ†Ð¸Ñ Ñ Ñ‚Ð°ÐºÐ¾Ð¹ отличительной чаÑтью адреÑа."
-#: mediagoblin/edit/views.py:343
+#: mediagoblin/edit/views.py:329
msgid "You are editing another user's collection. Proceed with caution."
msgstr "Ð’Ñ‹ редактируете коллекцию другого пользователÑ. Будьте оÑторожны."
-#: mediagoblin/gmg_commands/theme.py:58
+#: mediagoblin/edit/views.py:348
+msgid "Wrong password"
+msgstr "Ðеправильный пароль"
+
+#: mediagoblin/edit/views.py:363
+msgid "Your password was changed successfully"
+msgstr "Ваш пароль Ñменён уÑпешно"
+
+#: mediagoblin/gmg_commands/assetlink.py:60
msgid "Cannot link theme... no theme set\n"
msgstr "Ðевозможно привÑзать тему… не выбрано ÑущеÑтвующей темы\n"
-#: mediagoblin/gmg_commands/theme.py:71
+#: mediagoblin/gmg_commands/assetlink.py:73
msgid "No asset directory for this theme\n"
msgstr "У Ñтой темы отÑутÑтвует каталог Ñ Ñлементами оформлениÑ\n"
-#: mediagoblin/gmg_commands/theme.py:74
+#: mediagoblin/gmg_commands/assetlink.py:76
msgid "However, old link directory symlink found; removed.\n"
msgstr "Однако найдена (и удалена) ÑÑ‚Ð°Ñ€Ð°Ñ ÑимволичеÑÐºÐ°Ñ ÑÑылка на каталог.\n"
+#: mediagoblin/gmg_commands/assetlink.py:112
+#, python-format
+msgid "Could not link \"%s\": %s exists and is not a symlink\n"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:119
+#, python-format
+msgid "Skipping \"%s\"; already set up.\n"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:124
+#, python-format
+msgid "Old link found for \"%s\"; removing.\n"
+msgstr ""
+
#: mediagoblin/meddleware/csrf.py:134
msgid ""
"CSRF cookie not present. This is most likely the result of a cookie blocker "
@@ -274,12 +298,16 @@ msgid ""
"domain."
msgstr ""
-#: mediagoblin/media_types/__init__.py:61
-#: mediagoblin/media_types/__init__.py:102
+#: mediagoblin/media_types/__init__.py:111
+#: mediagoblin/media_types/__init__.py:155
msgid "Sorry, I don't support that file type :("
msgstr "Увы, Ñ Ð½Ðµ поддерживаю Ñтот тип файлов :("
-#: mediagoblin/media_types/video/processing.py:36
+#: mediagoblin/media_types/pdf/processing.py:136
+msgid "unoconv failing to run, check log file"
+msgstr ""
+
+#: mediagoblin/media_types/video/processing.py:37
msgid "Video transcoding failed"
msgstr "Перекодировка видео не удалаÑÑŒ"
@@ -346,7 +374,7 @@ msgstr ""
msgid "This field is required for public clients"
msgstr ""
-#: mediagoblin/plugins/oauth/views.py:59
+#: mediagoblin/plugins/oauth/views.py:56
msgid "The client {0} has been registered!"
msgstr "Клиент {0} зарегиÑтрирован!"
@@ -365,7 +393,7 @@ msgstr ""
msgid "Add"
msgstr "Добавить"
-#: mediagoblin/processing/__init__.py:172
+#: mediagoblin/processing/__init__.py:193
msgid "Invalid file given for media type."
msgstr "Ðеправильный формат файла."
@@ -373,45 +401,45 @@ msgstr "Ðеправильный формат файла."
msgid "File"
msgstr "Файл"
-#: mediagoblin/submit/views.py:51
+#: mediagoblin/submit/views.py:49
msgid "You must provide a file."
msgstr "Вы должны загрузить файл."
-#: mediagoblin/submit/views.py:97
+#: mediagoblin/submit/views.py:93
msgid "Woohoo! Submitted!"
msgstr "Ура! Файл загружен!"
-#: mediagoblin/submit/views.py:146
+#: mediagoblin/submit/views.py:144
#, python-format
msgid "Collection \"%s\" added!"
msgstr "ÐšÐ¾Ð»Ð»ÐµÐºÑ†Ð¸Ñ Â«%s» добавлена!"
-#: mediagoblin/templates/mediagoblin/base.html:64
+#: mediagoblin/templates/mediagoblin/base.html:67
msgid "Verify your email!"
msgstr "Подтвердите ваш Ð°Ð´Ñ€ÐµÑ Ñлектронной почты!"
-#: mediagoblin/templates/mediagoblin/base.html:65
+#: mediagoblin/templates/mediagoblin/base.html:68
msgid "log out"
msgstr "завершение ÑеанÑа"
-#: mediagoblin/templates/mediagoblin/base.html:70
+#: mediagoblin/templates/mediagoblin/base.html:73
#: mediagoblin/templates/mediagoblin/auth/login.html:28
#: mediagoblin/templates/mediagoblin/auth/login.html:36
#: mediagoblin/templates/mediagoblin/auth/login.html:54
msgid "Log in"
msgstr "Войти"
-#: mediagoblin/templates/mediagoblin/base.html:79
+#: mediagoblin/templates/mediagoblin/base.html:82
#, python-format
msgid "<a href=\"%(user_url)s\">%(user_name)s</a>'s account"
msgstr "Ð£Ñ‡Ñ‘Ñ‚Ð½Ð°Ñ Ð·Ð°Ð¿Ð¸ÑÑŒ <a href=\"%(user_url)s\">%(user_name)s</a>"
-#: mediagoblin/templates/mediagoblin/base.html:86
+#: mediagoblin/templates/mediagoblin/base.html:89
msgid "Change account settings"
msgstr "Изменить наÑтройки учётной запиÑи"
-#: mediagoblin/templates/mediagoblin/base.html:90
-#: mediagoblin/templates/mediagoblin/base.html:105
+#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:108
#: mediagoblin/templates/mediagoblin/admin/panel.html:21
#: mediagoblin/templates/mediagoblin/admin/panel.html:26
#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:21
@@ -419,72 +447,25 @@ msgstr "Изменить наÑтройки учётной запиÑи"
msgid "Media processing panel"
msgstr "Панель обработки файлов"
-#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:96
msgid "Log out"
msgstr "Завершение ÑеанÑа"
-#: mediagoblin/templates/mediagoblin/base.html:96
+#: mediagoblin/templates/mediagoblin/base.html:99
#: mediagoblin/templates/mediagoblin/user_pages/user.html:156
msgid "Add media"
msgstr "Добавить файлы"
-#: mediagoblin/templates/mediagoblin/base.html:99
+#: mediagoblin/templates/mediagoblin/base.html:102
#: mediagoblin/templates/mediagoblin/user_pages/collection_list.html:41
msgid "Create new collection"
msgstr "Создать новую коллекцию"
-#: mediagoblin/templates/mediagoblin/base.html:122
-#, python-format
-msgid ""
-"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
-"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
-msgstr "Работает на <a href=\"http://mediagoblin.org/\" title='ВерÑии %(version)s'>MediaGoblin</a>, проекте <a href=\"http://gnu.org/\">GNU</a>."
-
-#: mediagoblin/templates/mediagoblin/base.html:125
-#, python-format
-msgid ""
-"Released under the <a "
-"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
-"href=\"%(source_link)s\">Source code</a> available."
-msgstr "Он опубликован на уÑловиÑÑ… <a href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. ДоÑтупны <a href=\"%(source_link)s\">иÑходные текÑты</a>."
-
#: mediagoblin/templates/mediagoblin/error.html:24
msgid "Image of goblin stressing out"
msgstr "Изображение нервничающего гоблина"
-#: mediagoblin/templates/mediagoblin/root.html:31
-msgid "Explore"
-msgstr "Смотреть"
-
-#: mediagoblin/templates/mediagoblin/root.html:33
-msgid "Hi there, welcome to this MediaGoblin site!"
-msgstr "Привет! Добро пожаловать на наш MediaGoblin’овый Ñайт!"
-
-#: mediagoblin/templates/mediagoblin/root.html:35
-msgid ""
-"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
-"extraordinarily great piece of media hosting software."
-msgstr "Этот Ñайт работает на <a href=\"http://mediagoblin.org\">MediaGoblin</a>, необыкновенно замечательном ПО Ð´Ð»Ñ Ñ…Ð¾Ñтинга мультимедийных файлов."
-
-#: mediagoblin/templates/mediagoblin/root.html:36
-msgid ""
-"To add your own media, place comments, and more, you can log in with your "
-"MediaGoblin account."
-msgstr "Ð”Ð»Ñ Ð´Ð¾Ð±Ð°Ð²Ð»ÐµÐ½Ð¸Ñ ÑобÑтвенных файлов, ÐºÐ¾Ð¼Ð¼ÐµÐ½Ñ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¸ Ñ‚. п. вы можете предÑтавитьÑÑ Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ вашей MediaGoblin’овой учётной запиÑи."
-
-#: mediagoblin/templates/mediagoblin/root.html:38
-msgid "Don't have one yet? It's easy!"
-msgstr "У Ð²Ð°Ñ ÐµÑ‘ ещё нет? Ðе проблема!"
-
-#: mediagoblin/templates/mediagoblin/root.html:39
-#, python-format
-msgid ""
-"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
-" or\n"
-" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
-msgstr "<a class=\"button_action_highlight\" href=\"%(register_url)s\">Создайте учётную запиÑÑŒ на Ñтом Ñайте</a>\n или\n <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">уÑтановите MediaGoblin на ÑобÑтвенный Ñервер</a>"
-
-#: mediagoblin/templates/mediagoblin/root.html:47
+#: mediagoblin/templates/mediagoblin/root.html:32
msgid "Most recent media"
msgstr "Самые новые файлы"
@@ -590,6 +571,53 @@ msgid ""
"%(verification_url)s"
msgstr "Привет, %(username)s!\n\nЧтобы активировать Ñвой аккаунт в GNU MediaGoblin, откройте в Ñвоём вебâ€Ð±Ñ€Ð°ÑƒÐ·ÐµÑ€Ðµ Ñледующую ÑÑылку:\n\n%(verification_url)s"
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:21
+#, python-format
+msgid ""
+"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
+"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
+msgstr "Работает на <a href=\"http://mediagoblin.org/\" title='ВерÑии %(version)s'>MediaGoblin</a>, проекте <a href=\"http://gnu.org/\">GNU</a>."
+
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:24
+#, python-format
+msgid ""
+"Released under the <a "
+"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
+"href=\"%(source_link)s\">Source code</a> available."
+msgstr "Он опубликован на уÑловиÑÑ… <a href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. ДоÑтупны <a href=\"%(source_link)s\">иÑходные текÑты</a>."
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:20
+msgid "Explore"
+msgstr "Смотреть"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:22
+msgid "Hi there, welcome to this MediaGoblin site!"
+msgstr "Привет! Добро пожаловать на наш MediaGoblin’овый Ñайт!"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:24
+msgid ""
+"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
+"extraordinarily great piece of media hosting software."
+msgstr "Этот Ñайт работает на <a href=\"http://mediagoblin.org\">MediaGoblin</a>, необыкновенно замечательном ПО Ð´Ð»Ñ Ñ…Ð¾Ñтинга мультимедийных файлов."
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:25
+msgid ""
+"To add your own media, place comments, and more, you can log in with your "
+"MediaGoblin account."
+msgstr "Ð”Ð»Ñ Ð´Ð¾Ð±Ð°Ð²Ð»ÐµÐ½Ð¸Ñ ÑобÑтвенных файлов, ÐºÐ¾Ð¼Ð¼ÐµÐ½Ñ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¸ Ñ‚. п. вы можете предÑтавитьÑÑ Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ вашей MediaGoblin’овой учётной запиÑи."
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:27
+msgid "Don't have one yet? It's easy!"
+msgstr "У Ð²Ð°Ñ ÐµÑ‘ ещё нет? Ðе проблема!"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:28
+#, python-format
+msgid ""
+"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
+" or\n"
+" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/bits/logo.html:23
#: mediagoblin/themes/airy/templates/mediagoblin/bits/logo.html:23
msgid "MediaGoblin logo"
@@ -602,13 +630,13 @@ msgid "Editing attachments for %(media_title)s"
msgstr "Добавление ÑопутÑтвующего файла Ð´Ð»Ñ %(media_title)s"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:159
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:175
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:182
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:198
msgid "Attachments"
msgstr "СопутÑтвующие файлы"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:57
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:181
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:204
msgid "Add attachment"
msgstr "Добавить ÑопутÑтвующий файл"
@@ -625,12 +653,22 @@ msgstr "Отмена"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:63
#: mediagoblin/templates/mediagoblin/edit/edit.html:42
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:52
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:55
#: mediagoblin/templates/mediagoblin/edit/edit_collection.html:33
#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:40
msgid "Save changes"
msgstr "Сохранить изменениÑ"
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:28
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:38
+#, python-format
+msgid "Changing %(username)s's password"
+msgstr "Смена Ð¿Ð°Ñ€Ð¾Ð»Ñ %(username)s"
+
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:45
+msgid "Save"
+msgstr "Сохранить"
+
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:28
#, python-format
msgid "Really delete user '%(user_name)s' and all related media/comments?"
@@ -641,7 +679,7 @@ msgid "Yes, really delete my account"
msgstr "Да, на Ñамом деле удалить мою учётную запиÑÑŒ"
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:47
+#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:48
#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:49
msgid "Delete permanently"
msgstr "Удалить безвозвратно"
@@ -658,7 +696,11 @@ msgstr "Редактирование %(media_title)s"
msgid "Changing %(username)s's account settings"
msgstr "ÐаÑтройка учётной запиÑи %(username)s"
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:59
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:46
+msgid "Change your password."
+msgstr "Сменить пароль"
+
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:62
msgid "Delete my account"
msgstr "Удалить мою учётную запиÑÑŒ"
@@ -683,6 +725,7 @@ msgstr "Файлы Ñ Ð¼ÐµÑ‚ÐºÐ¾Ð¹: %(tag_name)s"
#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:56
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:65
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:136
#: mediagoblin/templates/mediagoblin/media_displays/video.html:55
msgid "Download"
@@ -707,6 +750,7 @@ msgid ""
msgstr "Ð’Ñ‹ можете Ñкачать Ñовременный браузер, \n\tÑпоÑобный проиграть Ñто аудио, Ñ <a href=\"http://getfirefox.com\">\n\t http://getfirefox.com</a>!"
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:60
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:71
#: mediagoblin/templates/mediagoblin/media_displays/video.html:61
msgid "Original file"
msgstr "ИÑходный файл"
@@ -715,6 +759,7 @@ msgstr "ИÑходный файл"
msgid "WebM file (Vorbis codec)"
msgstr "WebMâ€Ñ„айл (кодек — Vorbis)"
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:59
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:87
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:93
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:99
@@ -725,6 +770,10 @@ msgstr "WebMâ€Ñ„айл (кодек — Vorbis)"
msgid "Image for %(media_title)s"
msgstr "Изображение «%(media_title)s»"
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:79
+msgid "PDF file"
+msgstr "PDF-файл"
+
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:112
msgid "Toggle Rotate"
msgstr ""
@@ -823,7 +872,7 @@ msgstr "Удалить %(title)s?"
msgid "Really remove %(media_title)s from %(collection_title)s?"
msgstr "Ð’ Ñамом деле иÑключить %(media_title)s из %(collection_title)s?"
-#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:53
+#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:54
msgid "Remove"
msgstr "ИÑключить"
@@ -866,24 +915,28 @@ msgstr "Файлы Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ <a href=\"%(user_url)s\">%(username)
msgid "â– Browsing media by <a href=\"%(user_url)s\">%(username)s</a>"
msgstr "■ПроÑмотр файлов Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ <a href=\"%(user_url)s\">%(username)s</a>"
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:94
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:95
msgid "Add a comment"
msgstr "Добавить комментарий"
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:102
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:104
msgid "Add this comment"
msgstr "Добавить Ñтот комментарий"
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:123
-msgid "at"
-msgstr "в"
-
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:144
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:132
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:152
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:164
#, python-format
-msgid ""
-"<h3>Added on</h3>\n"
-" <p>%(date)s</p>"
-msgstr "<h3>Добавлено</h3>\n <p>%(date)s</p>"
+msgid "%(formatted_time)s ago"
+msgstr "%(formatted_time)s назад"
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:150
+msgid "Added"
+msgstr "Добавлен"
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:161
+msgid "Created"
+msgstr "Создан"
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:28
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:40
@@ -1039,7 +1092,7 @@ msgstr "более Ñтарые"
msgid "Tagged with"
msgstr "Метки"
-#: mediagoblin/tools/exif.py:80
+#: mediagoblin/tools/exif.py:83
msgid "Could not read the image file."
msgstr "Ðе удалоÑÑŒ прочитать файл Ñ Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸ÐµÐ¼."
@@ -1069,6 +1122,30 @@ msgid ""
" deleted."
msgstr ""
+#: mediagoblin/tools/timesince.py:62
+msgid "year"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:63
+msgid "month"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:64
+msgid "week"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:65
+msgid "day"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:66
+msgid "hour"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:67
+msgid "minute"
+msgstr "мин"
+
#: mediagoblin/user_pages/forms.py:23
msgid "Comment"
msgstr "Комментировать"
@@ -1100,73 +1177,77 @@ msgstr "-- Выберите --"
msgid "Include a note"
msgstr "Примечание"
-#: mediagoblin/user_pages/lib.py:56
+#: mediagoblin/user_pages/lib.py:58
msgid "commented on your post"
msgstr "оÑтавил комментарий к вашему файлу"
-#: mediagoblin/user_pages/views.py:166
+#: mediagoblin/user_pages/views.py:169
+msgid "Sorry, comments are disabled."
+msgstr "Сожалеем: возможноÑть ÐºÐ¾Ð¼Ð¼ÐµÐ½Ñ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¾Ñ‚ÐºÐ»ÑŽÑ‡ÐµÐ½Ð°."
+
+#: mediagoblin/user_pages/views.py:174
msgid "Oops, your comment was empty."
msgstr "Ой, ваш комментарий был пуÑÑ‚."
-#: mediagoblin/user_pages/views.py:172
+#: mediagoblin/user_pages/views.py:180
msgid "Your comment has been posted!"
msgstr "Ваш комментарий размещён!"
-#: mediagoblin/user_pages/views.py:197
+#: mediagoblin/user_pages/views.py:205
msgid "Please check your entries and try again."
msgstr "ПожалуйÑта, проверьте введённое и попробуйте ещё раз."
-#: mediagoblin/user_pages/views.py:237
+#: mediagoblin/user_pages/views.py:245
msgid "You have to select or add a collection"
msgstr "Ðеобходимо выбрать или добавить коллекцию"
-#: mediagoblin/user_pages/views.py:248
+#: mediagoblin/user_pages/views.py:256
#, python-format
msgid "\"%s\" already in collection \"%s\""
msgstr "«%s» — уже в коллекции «%s»"
-#: mediagoblin/user_pages/views.py:264
+#: mediagoblin/user_pages/views.py:262
#, python-format
msgid "\"%s\" added to collection \"%s\""
msgstr "«%s» добавлено в коллекцию «%s»"
-#: mediagoblin/user_pages/views.py:286
+#: mediagoblin/user_pages/views.py:282
msgid "You deleted the media."
msgstr "Вы удалили файл."
-#: mediagoblin/user_pages/views.py:293
+#: mediagoblin/user_pages/views.py:289
msgid "The media was not deleted because you didn't check that you were sure."
msgstr "Файл не удалён, так как вы не подтвердили Ñвою уверенноÑть галочкой."
-#: mediagoblin/user_pages/views.py:301
+#: mediagoblin/user_pages/views.py:296
msgid "You are about to delete another user's media. Proceed with caution."
msgstr "Ð’Ñ‹ на пороге ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ Ñ„Ð°Ð¹Ð»Ð° другого пользователÑ. Будьте оÑторожны."
-#: mediagoblin/user_pages/views.py:375
+#: mediagoblin/user_pages/views.py:370
msgid "You deleted the item from the collection."
msgstr "Ð’Ñ‹ иÑключили файл из коллекции."
-#: mediagoblin/user_pages/views.py:379
+#: mediagoblin/user_pages/views.py:374
msgid "The item was not removed because you didn't check that you were sure."
msgstr "Файл не иÑключён из коллекции, так как вы не подтвердили Ñвоё намерение отметкой."
-#: mediagoblin/user_pages/views.py:389
+#: mediagoblin/user_pages/views.py:382
msgid ""
"You are about to delete an item from another user's collection. Proceed with"
" caution."
msgstr "Ð’Ñ‹ на пороге иÑÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ñ„Ð°Ð¹Ð»Ð° из коллекции другого пользователÑ. Будьте оÑторожны."
-#: mediagoblin/user_pages/views.py:422
+#: mediagoblin/user_pages/views.py:415
#, python-format
msgid "You deleted the collection \"%s\""
msgstr "Вы удалили коллекцию «%s»"
-#: mediagoblin/user_pages/views.py:429
+#: mediagoblin/user_pages/views.py:422
msgid ""
"The collection was not deleted because you didn't check that you were sure."
msgstr "ÐšÐ¾Ð»Ð»ÐµÐºÑ†Ð¸Ñ Ð½Ðµ удалена, так как вы не подтвердили Ñвоё намерение отметкой."
-#: mediagoblin/user_pages/views.py:439
+#: mediagoblin/user_pages/views.py:430
msgid ""
"You are about to delete another user's collection. Proceed with caution."
msgstr "Ð’Ñ‹ на пороге ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ ÐºÐ¾Ð»Ð»ÐµÐºÑ†Ð¸Ð¸ другого пользователÑ. Будьте оÑторожны."
diff --git a/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.mo
index bc92bb13..fd48a37f 100644
--- a/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.mo
+++ b/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.mo
Binary files differ
diff --git a/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.po
index 07932b77..e4d1bacc 100644
--- a/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.po
+++ b/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.po
@@ -3,20 +3,20 @@
# This file is distributed under the same license as the PROJECT project.
#
# Translators:
-# Martin <zatroch.martin@gmail.com>, 2013.
-# Martin Zatroch <zatroch.martin@gmail.com>, 2012.
-# Morten Juhl-Johansen Zölde-Fejér <morten@writtenandread.net>, 2012.
-# Olle Jonsson <olle.jonsson@gmail.com>, 2012.
-# Tanja Trudslev <tanja.trudslev@gmail.com>, 2012.
-# <zatroch.martin@gmail.com>, 2011-2012.
+# martin <zatroch.martin@gmail.com>, 2013
+# martin <zatroch.martin@gmail.com>, 2012-2013
+# Morten Juhl-Johansen Zölde-Fejér <morten@writtenandread.net>, 2012
+# Olle Jonsson <olle.jonsson@gmail.com>, 2012
+# ttrudslev <tanja.trudslev@gmail.com>, 2012
+# martin <zatroch.martin@gmail.com>, 2011-2012
msgid ""
msgstr ""
"Project-Id-Version: GNU MediaGoblin\n"
"Report-Msgid-Bugs-To: http://issues.mediagoblin.org/\n"
-"POT-Creation-Date: 2013-03-04 18:04-0600\n"
-"PO-Revision-Date: 2013-03-05 00:04+0000\n"
-"Last-Translator: cwebber <cwebber@dustycloud.org>\n"
-"Language-Team: LANGUAGE <LL@li.org>\n"
+"POT-Creation-Date: 2013-05-27 13:54-0500\n"
+"PO-Revision-Date: 2013-05-28 07:47+0000\n"
+"Last-Translator: martin <zatroch.martin@gmail.com>\n"
+"Language-Team: Slovak (http://www.transifex.com/projects/p/mediagoblin/language/sk/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
@@ -24,34 +24,39 @@ msgstr ""
"Language: sk\n"
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
-#: mediagoblin/auth/forms.py:28
-msgid "Invalid User name or email address."
-msgstr "Nesprávne používateľské meno alebo e-mailová adresa."
-
-#: mediagoblin/auth/forms.py:29
-msgid "This field does not take email addresses."
-msgstr "Toto pole neakceptuje e-mailové adresy."
-
-#: mediagoblin/auth/forms.py:30
-msgid "This field requires an email address."
-msgstr "Toto pole vyžaduje e-mailovú adresu."
-
-#: mediagoblin/auth/forms.py:52 mediagoblin/auth/forms.py:67
+#: mediagoblin/auth/forms.py:26
msgid "Username"
msgstr "Používateľské meno"
-#: mediagoblin/auth/forms.py:56 mediagoblin/auth/forms.py:71
+#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:45
+#: mediagoblin/tests/test_util.py:110
msgid "Password"
msgstr "Heslo"
-#: mediagoblin/auth/forms.py:60
+#: mediagoblin/auth/forms.py:34
msgid "Email address"
msgstr "Email adresse"
-#: mediagoblin/auth/forms.py:78
+#: mediagoblin/auth/forms.py:41
+msgid "Username or Email"
+msgstr "Použivateľské meno alebo e-mail"
+
+#: mediagoblin/auth/forms.py:52
msgid "Username or email"
msgstr "Používateľské meno alebo e-mailová adresa"
+#: mediagoblin/auth/tools.py:31
+msgid "Invalid User name or email address."
+msgstr "Nesprávne používateľské meno alebo e-mailová adresa."
+
+#: mediagoblin/auth/tools.py:32
+msgid "This field does not take email addresses."
+msgstr "Toto pole neakceptuje e-mailové adresy."
+
+#: mediagoblin/auth/tools.py:33
+msgid "This field requires an email address."
+msgstr "Toto pole vyžaduje e-mailovú adresu."
+
#: mediagoblin/auth/views.py:54
msgid "Sorry, registration is disabled on this instance."
msgstr "PrepáÄ, registrácia na danej inÅ¡tancii nie je povolená."
@@ -64,54 +69,54 @@ msgstr "PrepáÄ, rovnaké používateľské meno už existuje."
msgid "Sorry, a user with that email address already exists."
msgstr "PrepáÄ, rovnaká e-mailová adresa už bola použitá na vytvorenie úÄtu."
-#: mediagoblin/auth/views.py:174
+#: mediagoblin/auth/views.py:182
msgid ""
"Your email address has been verified. You may now login, edit your profile, "
"and submit images!"
msgstr "Tvoja e-mailová adresa bola overená. Teraz sa môžeš prihlásiť, upravovať profil a vkladať výtvory!"
-#: mediagoblin/auth/views.py:180
+#: mediagoblin/auth/views.py:188
msgid "The verification key or user id is incorrect"
msgstr "Overovací kľúÄ, prípadne používateľské meno je nesprávne."
-#: mediagoblin/auth/views.py:198
+#: mediagoblin/auth/views.py:206
msgid "You must be logged in so we know who to send the email to!"
msgstr "Je potrebné prihlásiť sa, aby sme vedeli kam máme e-mail zaslať!"
-#: mediagoblin/auth/views.py:206
+#: mediagoblin/auth/views.py:214
msgid "You've already verified your email address!"
msgstr "Už máš overenú e-mailovú adresu!"
-#: mediagoblin/auth/views.py:219
+#: mediagoblin/auth/views.py:227
msgid "Resent your verification email."
msgstr "Opätovne zaslať overovací e-mail."
-#: mediagoblin/auth/views.py:250
+#: mediagoblin/auth/views.py:258
msgid ""
"If that email address (case sensitive!) is registered an email has been sent"
" with instructions on how to change your password."
msgstr "Pokiaľ daná e-mailová adresa (citlivá na veľkosť písma!) je registrovaná, e-mail z inštrukciami pre zmenu tvojho hesla bol zaslaný."
-#: mediagoblin/auth/views.py:261
+#: mediagoblin/auth/views.py:269
msgid "Couldn't find someone with that username."
msgstr "Nemožno nájsť nikoho z daným používateľským menom."
-#: mediagoblin/auth/views.py:264
+#: mediagoblin/auth/views.py:272
msgid ""
"An email has been sent with instructions on how to change your password."
msgstr "E-mailová správa z inštrukciami na zmenu tvojho hesla bola zaslaná."
-#: mediagoblin/auth/views.py:271
+#: mediagoblin/auth/views.py:279
msgid ""
"Could not send password recovery email as your username is inactive or your "
"account's email address has not been verified."
msgstr "Nebolo možné zaslať e-mail na opätovné získanie zabudnutého hesla, nakoľko tvoje používateľské meno je neaktívne, prípadne e-mailová adresa nebola úspešne overená."
-#: mediagoblin/auth/views.py:328
+#: mediagoblin/auth/views.py:336
msgid "You can now log in using your new password."
msgstr "Už môžeš použiť nové heslo pri prihlasovaní."
-#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:93
+#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:82
#: mediagoblin/submit/forms.py:28 mediagoblin/submit/forms.py:47
#: mediagoblin/user_pages/forms.py:45
msgid "Title"
@@ -122,7 +127,7 @@ msgid "Description of this work"
msgstr "Popis výtvoru"
#: mediagoblin/edit/forms.py:29 mediagoblin/edit/forms.py:52
-#: mediagoblin/edit/forms.py:97 mediagoblin/submit/forms.py:32
+#: mediagoblin/edit/forms.py:86 mediagoblin/submit/forms.py:32
#: mediagoblin/submit/forms.py:51 mediagoblin/user_pages/forms.py:49
msgid ""
"You can use\n"
@@ -138,11 +143,11 @@ msgstr "Štítky"
msgid "Separate tags by commas."
msgstr "Oddeľ Å¡títky pomocou Äiarky."
-#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:101
+#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:90
msgid "Slug"
msgstr "Unikátna ÄasÅ¥ adresy"
-#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:102
+#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:91
msgid "The slug can't be empty"
msgstr "Unikátna ÄasÅ¥ adresy nesmie byÅ¥ prázdna"
@@ -170,45 +175,45 @@ msgid "This address contains errors"
msgstr "Daná adresa obsahuje chybu"
#: mediagoblin/edit/forms.py:63
-msgid "Old password"
-msgstr "Staré heslo"
-
-#: mediagoblin/edit/forms.py:64
-msgid "Enter your old password to prove you own this account."
-msgstr "Vlož svoje staré heslo na dôkaz toho, že vlastníš daný úÄet."
-
-#: mediagoblin/edit/forms.py:67
-msgid "New password"
-msgstr "Nové heslo"
-
-#: mediagoblin/edit/forms.py:74
msgid "License preference"
msgstr "Preferencia licencie"
-#: mediagoblin/edit/forms.py:80
+#: mediagoblin/edit/forms.py:69
msgid "This will be your default license on upload forms."
msgstr "Nasledovná licencia bude použitá ako východzia pre všetky tvoje výtvory."
-#: mediagoblin/edit/forms.py:82
+#: mediagoblin/edit/forms.py:71
msgid "Email me when others comment on my media"
msgstr "ZaÅ¡li mi e-mail keÄ ostatní okomentujú môj výtvor"
-#: mediagoblin/edit/forms.py:94
+#: mediagoblin/edit/forms.py:83
msgid "The title can't be empty"
msgstr "Titulok nesmie byť prázdny."
-#: mediagoblin/edit/forms.py:96 mediagoblin/submit/forms.py:50
+#: mediagoblin/edit/forms.py:85 mediagoblin/submit/forms.py:50
#: mediagoblin/user_pages/forms.py:48
msgid "Description of this collection"
msgstr "Popis danej kolekcie"
-#: mediagoblin/edit/forms.py:103
+#: mediagoblin/edit/forms.py:92
msgid ""
"The title part of this collection's address. You usually don't need to "
"change this."
msgstr "Titulná ÄasÅ¥ adresy danej kolekcie. Zmena poľa nepovinná."
-#: mediagoblin/edit/views.py:66
+#: mediagoblin/edit/forms.py:99
+msgid "Old password"
+msgstr "Staré heslo"
+
+#: mediagoblin/edit/forms.py:101
+msgid "Enter your old password to prove you own this account."
+msgstr "Vlož svoje staré heslo na dôkaz toho, že vlastníš daný úÄet."
+
+#: mediagoblin/edit/forms.py:104
+msgid "New password"
+msgstr "Nové heslo"
+
+#: mediagoblin/edit/views.py:67
msgid "An entry with that slug already exists for this user."
msgstr "Položku s rovnakou unikátnou ÄasÅ¥ou adresy už niekde máš."
@@ -233,44 +238,63 @@ msgstr "Upravuješ profil iného používateľa. Pristupuj zodpovedne. "
msgid "Profile changes saved"
msgstr "Zmeny v profile uložené"
-#: mediagoblin/edit/views.py:241
-msgid "Wrong password"
-msgstr "Nesprávne heslo"
-
-#: mediagoblin/edit/views.py:252
+#: mediagoblin/edit/views.py:240
msgid "Account settings saved"
msgstr "Nastavenia úÄtu uložené"
-#: mediagoblin/edit/views.py:286
+#: mediagoblin/edit/views.py:274
msgid "You need to confirm the deletion of your account."
msgstr "PotrebujeÅ¡ potvrdiÅ¥ odstránenie svojho úÄtu."
-#: mediagoblin/edit/views.py:322 mediagoblin/submit/views.py:142
-#: mediagoblin/user_pages/views.py:214
+#: mediagoblin/edit/views.py:310 mediagoblin/submit/views.py:138
+#: mediagoblin/user_pages/views.py:222
#, python-format
msgid "You already have a collection called \"%s\"!"
msgstr "Už máš kolekciu nazvanú ako \"%s\"!"
-#: mediagoblin/edit/views.py:326
+#: mediagoblin/edit/views.py:314
msgid "A collection with that slug already exists for this user."
msgstr "Kolekcia s týmto štítkom už máš."
-#: mediagoblin/edit/views.py:343
+#: mediagoblin/edit/views.py:329
msgid "You are editing another user's collection. Proceed with caution."
msgstr "Upravuješ kolekciu iného používateľa. Pristupuj zodpovedne. "
-#: mediagoblin/gmg_commands/theme.py:58
+#: mediagoblin/edit/views.py:348
+msgid "Wrong password"
+msgstr "Nesprávne heslo"
+
+#: mediagoblin/edit/views.py:363
+msgid "Your password was changed successfully"
+msgstr "Tvoje heslo bolo úspešne zmenené"
+
+#: mediagoblin/gmg_commands/assetlink.py:60
msgid "Cannot link theme... no theme set\n"
msgstr "Nemožno pripojiť tému... téma nenastavená\n"
-#: mediagoblin/gmg_commands/theme.py:71
+#: mediagoblin/gmg_commands/assetlink.py:73
msgid "No asset directory for this theme\n"
msgstr "Žiadny prieÄinok položiek pre túto tému\n"
-#: mediagoblin/gmg_commands/theme.py:74
+#: mediagoblin/gmg_commands/assetlink.py:76
msgid "However, old link directory symlink found; removed.\n"
msgstr "Odstránené; hoci bol pôvodný symbolický odkaz adresára nájdený.\n"
+#: mediagoblin/gmg_commands/assetlink.py:112
+#, python-format
+msgid "Could not link \"%s\": %s exists and is not a symlink\n"
+msgstr "Nemožno odkazovať na \"%s\": %s existuje a nie je symbolickým odkazom\n"
+
+#: mediagoblin/gmg_commands/assetlink.py:119
+#, python-format
+msgid "Skipping \"%s\"; already set up.\n"
+msgstr "Preskakujem \"%s\"; opakovane nastavené.\n"
+
+#: mediagoblin/gmg_commands/assetlink.py:124
+#, python-format
+msgid "Old link found for \"%s\"; removing.\n"
+msgstr "Nájdený starý odkaz pre \"%s\"; odstraňujem.\n"
+
#: mediagoblin/meddleware/csrf.py:134
msgid ""
"CSRF cookie not present. This is most likely the result of a cookie blocker "
@@ -278,12 +302,16 @@ msgid ""
"domain."
msgstr "CSRF \"cookie\" neprítomný. Toto vidíš najskôr ako výsledok blokovania \"cookie\" súborov a pod.<br/>Uisti sa, že máš povolené ukladanie \"cookies\" pre danú doménu."
-#: mediagoblin/media_types/__init__.py:61
-#: mediagoblin/media_types/__init__.py:102
+#: mediagoblin/media_types/__init__.py:111
+#: mediagoblin/media_types/__init__.py:155
msgid "Sorry, I don't support that file type :("
msgstr "PrepáÄ, nepodporujem tento typ súborov =("
-#: mediagoblin/media_types/video/processing.py:36
+#: mediagoblin/media_types/pdf/processing.py:136
+msgid "unoconv failing to run, check log file"
+msgstr "beh unoconv zlyhal, preskúmajte log záznam"
+
+#: mediagoblin/media_types/video/processing.py:37
msgid "Video transcoding failed"
msgstr "Konvertovanie videa zlyhalo"
@@ -350,7 +378,7 @@ msgstr "Presmerovacie URI pre aplikácie, toto pole\nje <strong>požadované</st
msgid "This field is required for public clients"
msgstr "Dané pole je požadované pre verejných klientov."
-#: mediagoblin/plugins/oauth/views.py:59
+#: mediagoblin/plugins/oauth/views.py:56
msgid "The client {0} has been registered!"
msgstr "Klient {0} bol registrovaný!"
@@ -369,7 +397,7 @@ msgstr "Tvoji autorizovaní OAuth klienti"
msgid "Add"
msgstr "Pridať"
-#: mediagoblin/processing/__init__.py:172
+#: mediagoblin/processing/__init__.py:193
msgid "Invalid file given for media type."
msgstr "Nesprávny typ súboru pre dané médium."
@@ -377,45 +405,45 @@ msgstr "Nesprávny typ súboru pre dané médium."
msgid "File"
msgstr "Súbor"
-#: mediagoblin/submit/views.py:51
+#: mediagoblin/submit/views.py:49
msgid "You must provide a file."
msgstr "Musíš poskytnúť súbor."
-#: mediagoblin/submit/views.py:97
+#: mediagoblin/submit/views.py:93
msgid "Woohoo! Submitted!"
msgstr "Skvelé! Pridané!"
-#: mediagoblin/submit/views.py:146
+#: mediagoblin/submit/views.py:144
#, python-format
msgid "Collection \"%s\" added!"
msgstr "Kolekcia \"%s\" pridaná!"
-#: mediagoblin/templates/mediagoblin/base.html:64
+#: mediagoblin/templates/mediagoblin/base.html:67
msgid "Verify your email!"
msgstr "Over si e-mailovú adresu!"
-#: mediagoblin/templates/mediagoblin/base.html:65
+#: mediagoblin/templates/mediagoblin/base.html:68
msgid "log out"
msgstr "odhlásiť sa"
-#: mediagoblin/templates/mediagoblin/base.html:70
+#: mediagoblin/templates/mediagoblin/base.html:73
#: mediagoblin/templates/mediagoblin/auth/login.html:28
#: mediagoblin/templates/mediagoblin/auth/login.html:36
#: mediagoblin/templates/mediagoblin/auth/login.html:54
msgid "Log in"
msgstr "Prihlásiť sa"
-#: mediagoblin/templates/mediagoblin/base.html:79
+#: mediagoblin/templates/mediagoblin/base.html:82
#, python-format
msgid "<a href=\"%(user_url)s\">%(user_name)s</a>'s account"
msgstr "ÚÄet používateľa <a href=\"%(user_url)s\">%(user_name)s</a>"
-#: mediagoblin/templates/mediagoblin/base.html:86
+#: mediagoblin/templates/mediagoblin/base.html:89
msgid "Change account settings"
msgstr "ZmeniÅ¥ nastavenia úÄtu"
-#: mediagoblin/templates/mediagoblin/base.html:90
-#: mediagoblin/templates/mediagoblin/base.html:105
+#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:108
#: mediagoblin/templates/mediagoblin/admin/panel.html:21
#: mediagoblin/templates/mediagoblin/admin/panel.html:26
#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:21
@@ -423,72 +451,25 @@ msgstr "ZmeniÅ¥ nastavenia úÄtu"
msgid "Media processing panel"
msgstr "Sekcia spracovania výtvorov"
-#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:96
msgid "Log out"
-msgstr ""
+msgstr "Odhlásiť sa"
-#: mediagoblin/templates/mediagoblin/base.html:96
+#: mediagoblin/templates/mediagoblin/base.html:99
#: mediagoblin/templates/mediagoblin/user_pages/user.html:156
msgid "Add media"
msgstr "Pridať výtvor"
-#: mediagoblin/templates/mediagoblin/base.html:99
+#: mediagoblin/templates/mediagoblin/base.html:102
#: mediagoblin/templates/mediagoblin/user_pages/collection_list.html:41
msgid "Create new collection"
msgstr "Vytvoriť novú kolekciu"
-#: mediagoblin/templates/mediagoblin/base.html:122
-#, python-format
-msgid ""
-"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
-"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
-msgstr "Poháňa nás <a href=\"http://mediagoblin.org/\" title='Version %(version)s'>MediaGoblin</a>, súÄasÅ¥ projektu <a href=\"http://gnu.org/\">GNU</a>."
-
-#: mediagoblin/templates/mediagoblin/base.html:125
-#, python-format
-msgid ""
-"Released under the <a "
-"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
-"href=\"%(source_link)s\">Source code</a> available."
-msgstr "Uvoľnené pod <a href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a href=\"%(source_link)s\">Zdrojový kód</a> plne dostupný."
-
#: mediagoblin/templates/mediagoblin/error.html:24
msgid "Image of goblin stressing out"
msgstr "Obrázok hysterického goblina"
-#: mediagoblin/templates/mediagoblin/root.html:31
-msgid "Explore"
-msgstr "Preskúmať"
-
-#: mediagoblin/templates/mediagoblin/root.html:33
-msgid "Hi there, welcome to this MediaGoblin site!"
-msgstr "Ahoj, vitaj na tejto MediaGoblin stránke!"
-
-#: mediagoblin/templates/mediagoblin/root.html:35
-msgid ""
-"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
-"extraordinarily great piece of media hosting software."
-msgstr "Táto stránka používa <a href=\"http://mediagoblin.org\">MediaGoblin</a>, výnimoÄne skvelý kus softvéru na hostovanie médií."
-
-#: mediagoblin/templates/mediagoblin/root.html:36
-msgid ""
-"To add your own media, place comments, and more, you can log in with your "
-"MediaGoblin account."
-msgstr "Pre pridanie vlastných výtvorov, komentárov a viac.. sa prihlás zo svojim MediaGoblin úÄtom."
-
-#: mediagoblin/templates/mediagoblin/root.html:38
-msgid "Don't have one yet? It's easy!"
-msgstr "Har du ikke en endnu? Det er let!"
-
-#: mediagoblin/templates/mediagoblin/root.html:39
-#, python-format
-msgid ""
-"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
-" or\n"
-" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
-msgstr "<a class=\"button_action_highlight\" href=\"%(register_url)s\">VytvoriÅ¥ úÄet na tejto stránke</a>\n alebo\n <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">ZaložiÅ¥ MediaGoblin na vlastnom serveri</a>"
-
-#: mediagoblin/templates/mediagoblin/root.html:47
+#: mediagoblin/templates/mediagoblin/root.html:32
msgid "Most recent media"
msgstr "Aktuálne výtvory"
@@ -594,6 +575,53 @@ msgid ""
"%(verification_url)s"
msgstr "Ahoj %(username)s,\n\npre aktiváciu tvojho GNU MediaGoblin úÄtu, otvor nasledujúci odkaz vo\nsvojom prehliadaÄi:\n\n%(verification_url)s"
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:21
+#, python-format
+msgid ""
+"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
+"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
+msgstr "Poháňa nás <a href=\"http://mediagoblin.org/\" title='Version %(version)s'>MediaGoblin</a>, súÄasÅ¥ projektu <a href=\"http://gnu.org/\">GNU</a>."
+
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:24
+#, python-format
+msgid ""
+"Released under the <a "
+"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
+"href=\"%(source_link)s\">Source code</a> available."
+msgstr "Uvoľnené pod <a href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a href=\"%(source_link)s\">Zdrojový kód</a> plne dostupný."
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:20
+msgid "Explore"
+msgstr "Preskúmať"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:22
+msgid "Hi there, welcome to this MediaGoblin site!"
+msgstr "Ahoj, vitaj na tejto MediaGoblin stránke!"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:24
+msgid ""
+"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
+"extraordinarily great piece of media hosting software."
+msgstr "Táto stránka používa <a href=\"http://mediagoblin.org\">MediaGoblin</a>, výnimoÄne skvelý kus softvéru na hostovanie médií."
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:25
+msgid ""
+"To add your own media, place comments, and more, you can log in with your "
+"MediaGoblin account."
+msgstr "Pre pridanie vlastných výtvorov, komentárov a viac.. sa prihlás zo svojim MediaGoblin úÄtom."
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:27
+msgid "Don't have one yet? It's easy!"
+msgstr "Har du ikke en endnu? Det er let!"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:28
+#, python-format
+msgid ""
+"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
+" or\n"
+" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
+msgstr "<a class=\"button_action_highlight\" href=\"%(register_url)s\">VytvoriÅ¥ úÄet na tejto stránke</a>\n alebo\n <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">NastaviÅ¥ MediaGoblin na vlastnom serveri</a>"
+
#: mediagoblin/templates/mediagoblin/bits/logo.html:23
#: mediagoblin/themes/airy/templates/mediagoblin/bits/logo.html:23
msgid "MediaGoblin logo"
@@ -606,13 +634,13 @@ msgid "Editing attachments for %(media_title)s"
msgstr "Úprava príloh pre %(media_title)s"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:159
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:175
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:182
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:198
msgid "Attachments"
msgstr "Prílohy"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:57
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:181
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:204
msgid "Add attachment"
msgstr "Pridať prílohu"
@@ -629,12 +657,22 @@ msgstr "Zrušiť"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:63
#: mediagoblin/templates/mediagoblin/edit/edit.html:42
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:52
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:55
#: mediagoblin/templates/mediagoblin/edit/edit_collection.html:33
#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:40
msgid "Save changes"
msgstr "Uložiť zmeny"
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:28
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:38
+#, python-format
+msgid "Changing %(username)s's password"
+msgstr "Mením heslo používateľa %(username)s"
+
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:45
+msgid "Save"
+msgstr "Uložiť"
+
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:28
#, python-format
msgid "Really delete user '%(user_name)s' and all related media/comments?"
@@ -645,7 +683,7 @@ msgid "Yes, really delete my account"
msgstr "Ãno, skutoÄne odstrániÅ¥ môj úÄet"
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:47
+#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:48
#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:49
msgid "Delete permanently"
msgstr "Odstráňiť permanentne"
@@ -662,7 +700,11 @@ msgstr "Úprava %(media_title)s"
msgid "Changing %(username)s's account settings"
msgstr "Mením nastavenia úÄtu používateľa %(username)s"
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:59
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:46
+msgid "Change your password."
+msgstr "Zmeniť svoje heslo."
+
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:62
msgid "Delete my account"
msgstr "OdstrániÅ¥ môj úÄet"
@@ -687,6 +729,7 @@ msgstr "Výtvory oznaÄené ako: %(tag_name)s"
#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:56
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:65
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:136
#: mediagoblin/templates/mediagoblin/media_displays/video.html:55
msgid "Download"
@@ -711,6 +754,7 @@ msgid ""
msgstr "MôžeÅ¡ získaÅ¥ moderný prehliadaÄ, ktorý\n\ttento zvuk hravo prehrá <a href=\"http://getfirefox.com\">\n\t http://getfirefox.com</a>!"
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:60
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:71
#: mediagoblin/templates/mediagoblin/media_displays/video.html:61
msgid "Original file"
msgstr "Originálny súbor"
@@ -719,6 +763,7 @@ msgstr "Originálny súbor"
msgid "WebM file (Vorbis codec)"
msgstr "WebM súbor (Vorbis kodek)"
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:59
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:87
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:93
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:99
@@ -729,6 +774,10 @@ msgstr "WebM súbor (Vorbis kodek)"
msgid "Image for %(media_title)s"
msgstr "Obrázok pre %(media_title)s"
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:79
+msgid "PDF file"
+msgstr "PDF súbor"
+
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:112
msgid "Toggle Rotate"
msgstr "Zapnúť rotáciu"
@@ -827,7 +876,7 @@ msgstr "SkutoÄne odstrániÅ¥ %(title)s?"
msgid "Really remove %(media_title)s from %(collection_title)s?"
msgstr "SkutoÄne odstrániÅ¥ %(media_title)s z %(collection_title)s?"
-#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:53
+#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:54
msgid "Remove"
msgstr "Odstrániť"
@@ -870,24 +919,28 @@ msgstr "Výtvory, ktoré vlastní <a href=\"%(user_url)s\">%(username)s</a>"
msgid "â– Browsing media by <a href=\"%(user_url)s\">%(username)s</a>"
msgstr "■Prehliadanie výtvorov od <a href=\"%(user_url)s\">%(username)s</a>"
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:94
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:95
msgid "Add a comment"
msgstr "Pridať komentár"
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:102
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:104
msgid "Add this comment"
msgstr "Pridať tento komentár"
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:123
-msgid "at"
-msgstr "o"
-
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:144
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:132
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:152
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:164
#, python-format
-msgid ""
-"<h3>Added on</h3>\n"
-" <p>%(date)s</p>"
-msgstr "<h3>Pridané</h3>\n <p>%(date)s</p>"
+msgid "%(formatted_time)s ago"
+msgstr "pred %(formatted_time)s "
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:150
+msgid "Added"
+msgstr "Pridané"
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:161
+msgid "Created"
+msgstr "Vytvorené"
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:28
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:40
@@ -1043,7 +1096,7 @@ msgstr "staršie"
msgid "Tagged with"
msgstr "OznaÄené ako"
-#: mediagoblin/tools/exif.py:80
+#: mediagoblin/tools/exif.py:83
msgid "Could not read the image file."
msgstr "Nemožno preÄítaÅ¥ súbor obrázka."
@@ -1073,6 +1126,30 @@ msgid ""
" deleted."
msgstr "Zdá sa, že na tejto adrese sa niÄ nenachádza. PrepáÄ!</p><p>Pokiaľ si si istý, že adresa je správna, možno bola hľadaná stránka presunutá, respektíve odstránená."
+#: mediagoblin/tools/timesince.py:62
+msgid "year"
+msgstr "rok"
+
+#: mediagoblin/tools/timesince.py:63
+msgid "month"
+msgstr "mesiac"
+
+#: mediagoblin/tools/timesince.py:64
+msgid "week"
+msgstr "týždeň"
+
+#: mediagoblin/tools/timesince.py:65
+msgid "day"
+msgstr "deň"
+
+#: mediagoblin/tools/timesince.py:66
+msgid "hour"
+msgstr "hodina"
+
+#: mediagoblin/tools/timesince.py:67
+msgid "minute"
+msgstr "minúta"
+
#: mediagoblin/user_pages/forms.py:23
msgid "Comment"
msgstr "Komentár"
@@ -1104,73 +1181,77 @@ msgstr "-- Vybrať --"
msgid "Include a note"
msgstr "Pridať poznámku"
-#: mediagoblin/user_pages/lib.py:56
+#: mediagoblin/user_pages/lib.py:58
msgid "commented on your post"
msgstr "okmentoval tvoj príspevok"
-#: mediagoblin/user_pages/views.py:166
+#: mediagoblin/user_pages/views.py:169
+msgid "Sorry, comments are disabled."
+msgstr "PrepáÄ, komentovanie je vypnuté."
+
+#: mediagoblin/user_pages/views.py:174
msgid "Oops, your comment was empty."
msgstr "Hopla, tvoj komentár bol prázdny."
-#: mediagoblin/user_pages/views.py:172
+#: mediagoblin/user_pages/views.py:180
msgid "Your comment has been posted!"
msgstr "Tvoj komentár bol pridaný!"
-#: mediagoblin/user_pages/views.py:197
+#: mediagoblin/user_pages/views.py:205
msgid "Please check your entries and try again."
msgstr "Prosím skontroluj svoje položky a skús znova."
-#: mediagoblin/user_pages/views.py:237
+#: mediagoblin/user_pages/views.py:245
msgid "You have to select or add a collection"
msgstr "Musíš vybrať, prípadne pridať kolekciu"
-#: mediagoblin/user_pages/views.py:248
+#: mediagoblin/user_pages/views.py:256
#, python-format
msgid "\"%s\" already in collection \"%s\""
msgstr "\"%s\" sa už nachádza v kolekcii \"%s\""
-#: mediagoblin/user_pages/views.py:264
+#: mediagoblin/user_pages/views.py:262
#, python-format
msgid "\"%s\" added to collection \"%s\""
msgstr "\"%s pridané do kolekcie \"%s\""
-#: mediagoblin/user_pages/views.py:286
+#: mediagoblin/user_pages/views.py:282
msgid "You deleted the media."
msgstr "Výtvor bol tebou odstránený."
-#: mediagoblin/user_pages/views.py:293
+#: mediagoblin/user_pages/views.py:289
msgid "The media was not deleted because you didn't check that you were sure."
msgstr "Výtvor nebol odstránený, nakoľko chýbalo tvoje potvrdenie."
-#: mediagoblin/user_pages/views.py:301
+#: mediagoblin/user_pages/views.py:296
msgid "You are about to delete another user's media. Proceed with caution."
msgstr "Chystáš sa odstrániť výtvory niekoho iného. Pristupuj zodpovedne. "
-#: mediagoblin/user_pages/views.py:375
+#: mediagoblin/user_pages/views.py:370
msgid "You deleted the item from the collection."
msgstr "Položka bola z kolekcie odstránená."
-#: mediagoblin/user_pages/views.py:379
+#: mediagoblin/user_pages/views.py:374
msgid "The item was not removed because you didn't check that you were sure."
msgstr "Položka nebola odstránená, nakoľko políÄko potvrdenia nebolo oznaÄné."
-#: mediagoblin/user_pages/views.py:389
+#: mediagoblin/user_pages/views.py:382
msgid ""
"You are about to delete an item from another user's collection. Proceed with"
" caution."
msgstr "Chystáš sa odstrániť položku z kolekcie iného používateľa. Pristupuj zodpovedne. "
-#: mediagoblin/user_pages/views.py:422
+#: mediagoblin/user_pages/views.py:415
#, python-format
msgid "You deleted the collection \"%s\""
msgstr "Kolekcia \"%s\" bola úspešne odstránená."
-#: mediagoblin/user_pages/views.py:429
+#: mediagoblin/user_pages/views.py:422
msgid ""
"The collection was not deleted because you didn't check that you were sure."
msgstr "Kolekcia nebola odstránená, nakoľko políÄko potrvdenia nebolo oznaÄené."
-#: mediagoblin/user_pages/views.py:439
+#: mediagoblin/user_pages/views.py:430
msgid ""
"You are about to delete another user's collection. Proceed with caution."
msgstr "Chystáš sa odstrániť kolekciu iného používateľa. Pristupuj zodpovedne. "
diff --git a/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.mo
index dd3de81b..199e761c 100644
--- a/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.mo
+++ b/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.mo
Binary files differ
diff --git a/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po
index 98d62d59..35635acf 100644
--- a/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po
+++ b/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po
@@ -3,15 +3,15 @@
# This file is distributed under the same license as the PROJECT project.
#
# Translators:
-# Jure Repinc <jlp@holodeck1.com>, 2011.
+# Jure Repinc <jlp@holodeck1.com>, 2011
msgid ""
msgstr ""
"Project-Id-Version: GNU MediaGoblin\n"
"Report-Msgid-Bugs-To: http://issues.mediagoblin.org/\n"
-"POT-Creation-Date: 2013-03-04 18:04-0600\n"
-"PO-Revision-Date: 2013-03-05 00:04+0000\n"
+"POT-Creation-Date: 2013-05-27 13:54-0500\n"
+"PO-Revision-Date: 2013-05-27 18:54+0000\n"
"Last-Translator: cwebber <cwebber@dustycloud.org>\n"
-"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language-Team: Slovenian (http://www.transifex.com/projects/p/mediagoblin/language/sl/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
@@ -19,34 +19,39 @@ msgstr ""
"Language: sl\n"
"Plural-Forms: nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);\n"
-#: mediagoblin/auth/forms.py:28
-msgid "Invalid User name or email address."
-msgstr ""
-
-#: mediagoblin/auth/forms.py:29
-msgid "This field does not take email addresses."
-msgstr ""
-
-#: mediagoblin/auth/forms.py:30
-msgid "This field requires an email address."
-msgstr ""
-
-#: mediagoblin/auth/forms.py:52 mediagoblin/auth/forms.py:67
+#: mediagoblin/auth/forms.py:26
msgid "Username"
msgstr "Uporabniško ime"
-#: mediagoblin/auth/forms.py:56 mediagoblin/auth/forms.py:71
+#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:45
+#: mediagoblin/tests/test_util.py:110
msgid "Password"
msgstr "Geslo"
-#: mediagoblin/auth/forms.py:60
+#: mediagoblin/auth/forms.py:34
msgid "Email address"
msgstr "E-poštni naslov"
-#: mediagoblin/auth/forms.py:78
+#: mediagoblin/auth/forms.py:41
+msgid "Username or Email"
+msgstr ""
+
+#: mediagoblin/auth/forms.py:52
msgid "Username or email"
msgstr ""
+#: mediagoblin/auth/tools.py:31
+msgid "Invalid User name or email address."
+msgstr ""
+
+#: mediagoblin/auth/tools.py:32
+msgid "This field does not take email addresses."
+msgstr ""
+
+#: mediagoblin/auth/tools.py:33
+msgid "This field requires an email address."
+msgstr ""
+
#: mediagoblin/auth/views.py:54
msgid "Sorry, registration is disabled on this instance."
msgstr "Oprostite, prijava za ta izvod ni omogoÄena."
@@ -59,54 +64,54 @@ msgstr "Oprostite, uporabnik s tem imenom že obstaja."
msgid "Sorry, a user with that email address already exists."
msgstr ""
-#: mediagoblin/auth/views.py:174
+#: mediagoblin/auth/views.py:182
msgid ""
"Your email address has been verified. You may now login, edit your profile, "
"and submit images!"
msgstr "Vaš e-poštni naslov je bil potrjen. Sedaj se lahko prijavite, uredite svoj profil in pošljete slike."
-#: mediagoblin/auth/views.py:180
+#: mediagoblin/auth/views.py:188
msgid "The verification key or user id is incorrect"
msgstr "Potrditveni kljuÄ ali uporabniÅ¡ka identifikacija je napaÄna"
-#: mediagoblin/auth/views.py:198
+#: mediagoblin/auth/views.py:206
msgid "You must be logged in so we know who to send the email to!"
msgstr ""
-#: mediagoblin/auth/views.py:206
+#: mediagoblin/auth/views.py:214
msgid "You've already verified your email address!"
msgstr ""
-#: mediagoblin/auth/views.py:219
+#: mediagoblin/auth/views.py:227
msgid "Resent your verification email."
msgstr "Ponovno pošiljanje potrditvene e-pošte."
-#: mediagoblin/auth/views.py:250
+#: mediagoblin/auth/views.py:258
msgid ""
"If that email address (case sensitive!) is registered an email has been sent"
" with instructions on how to change your password."
msgstr ""
-#: mediagoblin/auth/views.py:261
+#: mediagoblin/auth/views.py:269
msgid "Couldn't find someone with that username."
msgstr ""
-#: mediagoblin/auth/views.py:264
+#: mediagoblin/auth/views.py:272
msgid ""
"An email has been sent with instructions on how to change your password."
msgstr ""
-#: mediagoblin/auth/views.py:271
+#: mediagoblin/auth/views.py:279
msgid ""
"Could not send password recovery email as your username is inactive or your "
"account's email address has not been verified."
msgstr ""
-#: mediagoblin/auth/views.py:328
+#: mediagoblin/auth/views.py:336
msgid "You can now log in using your new password."
msgstr ""
-#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:93
+#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:82
#: mediagoblin/submit/forms.py:28 mediagoblin/submit/forms.py:47
#: mediagoblin/user_pages/forms.py:45
msgid "Title"
@@ -117,7 +122,7 @@ msgid "Description of this work"
msgstr ""
#: mediagoblin/edit/forms.py:29 mediagoblin/edit/forms.py:52
-#: mediagoblin/edit/forms.py:97 mediagoblin/submit/forms.py:32
+#: mediagoblin/edit/forms.py:86 mediagoblin/submit/forms.py:32
#: mediagoblin/submit/forms.py:51 mediagoblin/user_pages/forms.py:49
msgid ""
"You can use\n"
@@ -133,11 +138,11 @@ msgstr "Oznake"
msgid "Separate tags by commas."
msgstr ""
-#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:101
+#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:90
msgid "Slug"
msgstr "Oznaka"
-#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:102
+#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:91
msgid "The slug can't be empty"
msgstr "Oznaka ne sme biti prazna"
@@ -165,45 +170,45 @@ msgid "This address contains errors"
msgstr ""
#: mediagoblin/edit/forms.py:63
-msgid "Old password"
-msgstr ""
-
-#: mediagoblin/edit/forms.py:64
-msgid "Enter your old password to prove you own this account."
-msgstr ""
-
-#: mediagoblin/edit/forms.py:67
-msgid "New password"
-msgstr ""
-
-#: mediagoblin/edit/forms.py:74
msgid "License preference"
msgstr ""
-#: mediagoblin/edit/forms.py:80
+#: mediagoblin/edit/forms.py:69
msgid "This will be your default license on upload forms."
msgstr ""
-#: mediagoblin/edit/forms.py:82
+#: mediagoblin/edit/forms.py:71
msgid "Email me when others comment on my media"
msgstr ""
-#: mediagoblin/edit/forms.py:94
+#: mediagoblin/edit/forms.py:83
msgid "The title can't be empty"
msgstr ""
-#: mediagoblin/edit/forms.py:96 mediagoblin/submit/forms.py:50
+#: mediagoblin/edit/forms.py:85 mediagoblin/submit/forms.py:50
#: mediagoblin/user_pages/forms.py:48
msgid "Description of this collection"
msgstr ""
-#: mediagoblin/edit/forms.py:103
+#: mediagoblin/edit/forms.py:92
msgid ""
"The title part of this collection's address. You usually don't need to "
"change this."
msgstr ""
-#: mediagoblin/edit/views.py:66
+#: mediagoblin/edit/forms.py:99
+msgid "Old password"
+msgstr ""
+
+#: mediagoblin/edit/forms.py:101
+msgid "Enter your old password to prove you own this account."
+msgstr ""
+
+#: mediagoblin/edit/forms.py:104
+msgid "New password"
+msgstr ""
+
+#: mediagoblin/edit/views.py:67
msgid "An entry with that slug already exists for this user."
msgstr "Vnos s to oznako za tega uporabnika že obstaja."
@@ -228,44 +233,63 @@ msgstr "Urejate uporabniški profil. Nadaljujte pazljivo."
msgid "Profile changes saved"
msgstr ""
-#: mediagoblin/edit/views.py:241
-msgid "Wrong password"
-msgstr ""
-
-#: mediagoblin/edit/views.py:252
+#: mediagoblin/edit/views.py:240
msgid "Account settings saved"
msgstr ""
-#: mediagoblin/edit/views.py:286
+#: mediagoblin/edit/views.py:274
msgid "You need to confirm the deletion of your account."
msgstr ""
-#: mediagoblin/edit/views.py:322 mediagoblin/submit/views.py:142
-#: mediagoblin/user_pages/views.py:214
+#: mediagoblin/edit/views.py:310 mediagoblin/submit/views.py:138
+#: mediagoblin/user_pages/views.py:222
#, python-format
msgid "You already have a collection called \"%s\"!"
msgstr ""
-#: mediagoblin/edit/views.py:326
+#: mediagoblin/edit/views.py:314
msgid "A collection with that slug already exists for this user."
msgstr ""
-#: mediagoblin/edit/views.py:343
+#: mediagoblin/edit/views.py:329
msgid "You are editing another user's collection. Proceed with caution."
msgstr ""
-#: mediagoblin/gmg_commands/theme.py:58
+#: mediagoblin/edit/views.py:348
+msgid "Wrong password"
+msgstr ""
+
+#: mediagoblin/edit/views.py:363
+msgid "Your password was changed successfully"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:60
msgid "Cannot link theme... no theme set\n"
msgstr ""
-#: mediagoblin/gmg_commands/theme.py:71
+#: mediagoblin/gmg_commands/assetlink.py:73
msgid "No asset directory for this theme\n"
msgstr ""
-#: mediagoblin/gmg_commands/theme.py:74
+#: mediagoblin/gmg_commands/assetlink.py:76
msgid "However, old link directory symlink found; removed.\n"
msgstr ""
+#: mediagoblin/gmg_commands/assetlink.py:112
+#, python-format
+msgid "Could not link \"%s\": %s exists and is not a symlink\n"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:119
+#, python-format
+msgid "Skipping \"%s\"; already set up.\n"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:124
+#, python-format
+msgid "Old link found for \"%s\"; removing.\n"
+msgstr ""
+
#: mediagoblin/meddleware/csrf.py:134
msgid ""
"CSRF cookie not present. This is most likely the result of a cookie blocker "
@@ -273,12 +297,16 @@ msgid ""
"domain."
msgstr ""
-#: mediagoblin/media_types/__init__.py:61
-#: mediagoblin/media_types/__init__.py:102
+#: mediagoblin/media_types/__init__.py:111
+#: mediagoblin/media_types/__init__.py:155
msgid "Sorry, I don't support that file type :("
msgstr ""
-#: mediagoblin/media_types/video/processing.py:36
+#: mediagoblin/media_types/pdf/processing.py:136
+msgid "unoconv failing to run, check log file"
+msgstr ""
+
+#: mediagoblin/media_types/video/processing.py:37
msgid "Video transcoding failed"
msgstr ""
@@ -345,7 +373,7 @@ msgstr ""
msgid "This field is required for public clients"
msgstr ""
-#: mediagoblin/plugins/oauth/views.py:59
+#: mediagoblin/plugins/oauth/views.py:56
msgid "The client {0} has been registered!"
msgstr ""
@@ -364,7 +392,7 @@ msgstr ""
msgid "Add"
msgstr ""
-#: mediagoblin/processing/__init__.py:172
+#: mediagoblin/processing/__init__.py:193
msgid "Invalid file given for media type."
msgstr "Za vrsto vsebine je bila podana napaÄna datoteka."
@@ -372,45 +400,45 @@ msgstr "Za vrsto vsebine je bila podana napaÄna datoteka."
msgid "File"
msgstr "Datoteka"
-#: mediagoblin/submit/views.py:51
+#: mediagoblin/submit/views.py:49
msgid "You must provide a file."
msgstr "Podati morate datoteko."
-#: mediagoblin/submit/views.py:97
+#: mediagoblin/submit/views.py:93
msgid "Woohoo! Submitted!"
msgstr "Juhej! Poslano."
-#: mediagoblin/submit/views.py:146
+#: mediagoblin/submit/views.py:144
#, python-format
msgid "Collection \"%s\" added!"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:64
+#: mediagoblin/templates/mediagoblin/base.html:67
msgid "Verify your email!"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:65
+#: mediagoblin/templates/mediagoblin/base.html:68
msgid "log out"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:70
+#: mediagoblin/templates/mediagoblin/base.html:73
#: mediagoblin/templates/mediagoblin/auth/login.html:28
#: mediagoblin/templates/mediagoblin/auth/login.html:36
#: mediagoblin/templates/mediagoblin/auth/login.html:54
msgid "Log in"
msgstr "Prijava"
-#: mediagoblin/templates/mediagoblin/base.html:79
+#: mediagoblin/templates/mediagoblin/base.html:82
#, python-format
msgid "<a href=\"%(user_url)s\">%(user_name)s</a>'s account"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:86
+#: mediagoblin/templates/mediagoblin/base.html:89
msgid "Change account settings"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:90
-#: mediagoblin/templates/mediagoblin/base.html:105
+#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:108
#: mediagoblin/templates/mediagoblin/admin/panel.html:21
#: mediagoblin/templates/mediagoblin/admin/panel.html:26
#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:21
@@ -418,72 +446,25 @@ msgstr ""
msgid "Media processing panel"
msgstr "Podokno obdelovanja vsebine"
-#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:96
msgid "Log out"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:96
+#: mediagoblin/templates/mediagoblin/base.html:99
#: mediagoblin/templates/mediagoblin/user_pages/user.html:156
msgid "Add media"
msgstr "Dodaj vsebino"
-#: mediagoblin/templates/mediagoblin/base.html:99
+#: mediagoblin/templates/mediagoblin/base.html:102
#: mediagoblin/templates/mediagoblin/user_pages/collection_list.html:41
msgid "Create new collection"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:122
-#, python-format
-msgid ""
-"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
-"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/base.html:125
-#, python-format
-msgid ""
-"Released under the <a "
-"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
-"href=\"%(source_link)s\">Source code</a> available."
-msgstr ""
-
#: mediagoblin/templates/mediagoblin/error.html:24
msgid "Image of goblin stressing out"
msgstr ""
-#: mediagoblin/templates/mediagoblin/root.html:31
-msgid "Explore"
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:33
-msgid "Hi there, welcome to this MediaGoblin site!"
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:35
-msgid ""
-"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
-"extraordinarily great piece of media hosting software."
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:36
-msgid ""
-"To add your own media, place comments, and more, you can log in with your "
-"MediaGoblin account."
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:38
-msgid "Don't have one yet? It's easy!"
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:39
-#, python-format
-msgid ""
-"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
-" or\n"
-" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:47
+#: mediagoblin/templates/mediagoblin/root.html:32
msgid "Most recent media"
msgstr ""
@@ -589,6 +570,53 @@ msgid ""
"%(verification_url)s"
msgstr "Pozdravljeni, %(username)s\n\nZa aktivacijo svojega raÄuna GNU MediaGoblin odprite\nnaslednji URL v svojem spletnem brskalniku:\n\n%(verification_url)s"
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:21
+#, python-format
+msgid ""
+"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
+"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:24
+#, python-format
+msgid ""
+"Released under the <a "
+"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
+"href=\"%(source_link)s\">Source code</a> available."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:20
+msgid "Explore"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:22
+msgid "Hi there, welcome to this MediaGoblin site!"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:24
+msgid ""
+"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
+"extraordinarily great piece of media hosting software."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:25
+msgid ""
+"To add your own media, place comments, and more, you can log in with your "
+"MediaGoblin account."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:27
+msgid "Don't have one yet? It's easy!"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:28
+#, python-format
+msgid ""
+"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
+" or\n"
+" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/bits/logo.html:23
#: mediagoblin/themes/airy/templates/mediagoblin/bits/logo.html:23
msgid "MediaGoblin logo"
@@ -601,13 +629,13 @@ msgid "Editing attachments for %(media_title)s"
msgstr ""
#: mediagoblin/templates/mediagoblin/edit/attachments.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:159
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:175
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:182
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:198
msgid "Attachments"
msgstr ""
#: mediagoblin/templates/mediagoblin/edit/attachments.html:57
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:181
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:204
msgid "Add attachment"
msgstr ""
@@ -624,12 +652,22 @@ msgstr "PrekliÄi"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:63
#: mediagoblin/templates/mediagoblin/edit/edit.html:42
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:52
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:55
#: mediagoblin/templates/mediagoblin/edit/edit_collection.html:33
#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:40
msgid "Save changes"
msgstr "Shrani spremembe"
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:28
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:38
+#, python-format
+msgid "Changing %(username)s's password"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:45
+msgid "Save"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:28
#, python-format
msgid "Really delete user '%(user_name)s' and all related media/comments?"
@@ -640,7 +678,7 @@ msgid "Yes, really delete my account"
msgstr ""
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:47
+#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:48
#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:49
msgid "Delete permanently"
msgstr ""
@@ -657,7 +695,11 @@ msgstr "Urejanje %(media_title)s"
msgid "Changing %(username)s's account settings"
msgstr ""
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:59
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:46
+msgid "Change your password."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:62
msgid "Delete my account"
msgstr ""
@@ -682,6 +724,7 @@ msgstr ""
#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:56
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:65
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:136
#: mediagoblin/templates/mediagoblin/media_displays/video.html:55
msgid "Download"
@@ -706,6 +749,7 @@ msgid ""
msgstr ""
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:60
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:71
#: mediagoblin/templates/mediagoblin/media_displays/video.html:61
msgid "Original file"
msgstr ""
@@ -714,6 +758,7 @@ msgstr ""
msgid "WebM file (Vorbis codec)"
msgstr ""
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:59
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:87
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:93
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:99
@@ -724,6 +769,10 @@ msgstr ""
msgid "Image for %(media_title)s"
msgstr ""
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:79
+msgid "PDF file"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:112
msgid "Toggle Rotate"
msgstr ""
@@ -822,7 +871,7 @@ msgstr ""
msgid "Really remove %(media_title)s from %(collection_title)s?"
msgstr ""
-#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:53
+#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:54
msgid "Remove"
msgstr ""
@@ -865,23 +914,27 @@ msgstr "Vsebina uporabnika <a href=\"%(user_url)s\">%(username)s</a>"
msgid "â– Browsing media by <a href=\"%(user_url)s\">%(username)s</a>"
msgstr ""
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:94
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:95
msgid "Add a comment"
msgstr ""
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:102
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:104
msgid "Add this comment"
msgstr ""
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:123
-msgid "at"
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:132
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:152
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:164
+#, python-format
+msgid "%(formatted_time)s ago"
msgstr ""
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:144
-#, python-format
-msgid ""
-"<h3>Added on</h3>\n"
-" <p>%(date)s</p>"
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:150
+msgid "Added"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:161
+msgid "Created"
msgstr ""
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:28
@@ -1038,7 +1091,7 @@ msgstr ""
msgid "Tagged with"
msgstr ""
-#: mediagoblin/tools/exif.py:80
+#: mediagoblin/tools/exif.py:83
msgid "Could not read the image file."
msgstr ""
@@ -1068,6 +1121,30 @@ msgid ""
" deleted."
msgstr ""
+#: mediagoblin/tools/timesince.py:62
+msgid "year"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:63
+msgid "month"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:64
+msgid "week"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:65
+msgid "day"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:66
+msgid "hour"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:67
+msgid "minute"
+msgstr ""
+
#: mediagoblin/user_pages/forms.py:23
msgid "Comment"
msgstr ""
@@ -1099,73 +1176,77 @@ msgstr ""
msgid "Include a note"
msgstr ""
-#: mediagoblin/user_pages/lib.py:56
+#: mediagoblin/user_pages/lib.py:58
msgid "commented on your post"
msgstr ""
-#: mediagoblin/user_pages/views.py:166
+#: mediagoblin/user_pages/views.py:169
+msgid "Sorry, comments are disabled."
+msgstr ""
+
+#: mediagoblin/user_pages/views.py:174
msgid "Oops, your comment was empty."
msgstr ""
-#: mediagoblin/user_pages/views.py:172
+#: mediagoblin/user_pages/views.py:180
msgid "Your comment has been posted!"
msgstr ""
-#: mediagoblin/user_pages/views.py:197
+#: mediagoblin/user_pages/views.py:205
msgid "Please check your entries and try again."
msgstr ""
-#: mediagoblin/user_pages/views.py:237
+#: mediagoblin/user_pages/views.py:245
msgid "You have to select or add a collection"
msgstr ""
-#: mediagoblin/user_pages/views.py:248
+#: mediagoblin/user_pages/views.py:256
#, python-format
msgid "\"%s\" already in collection \"%s\""
msgstr ""
-#: mediagoblin/user_pages/views.py:264
+#: mediagoblin/user_pages/views.py:262
#, python-format
msgid "\"%s\" added to collection \"%s\""
msgstr ""
-#: mediagoblin/user_pages/views.py:286
+#: mediagoblin/user_pages/views.py:282
msgid "You deleted the media."
msgstr ""
-#: mediagoblin/user_pages/views.py:293
+#: mediagoblin/user_pages/views.py:289
msgid "The media was not deleted because you didn't check that you were sure."
msgstr ""
-#: mediagoblin/user_pages/views.py:301
+#: mediagoblin/user_pages/views.py:296
msgid "You are about to delete another user's media. Proceed with caution."
msgstr ""
-#: mediagoblin/user_pages/views.py:375
+#: mediagoblin/user_pages/views.py:370
msgid "You deleted the item from the collection."
msgstr ""
-#: mediagoblin/user_pages/views.py:379
+#: mediagoblin/user_pages/views.py:374
msgid "The item was not removed because you didn't check that you were sure."
msgstr ""
-#: mediagoblin/user_pages/views.py:389
+#: mediagoblin/user_pages/views.py:382
msgid ""
"You are about to delete an item from another user's collection. Proceed with"
" caution."
msgstr ""
-#: mediagoblin/user_pages/views.py:422
+#: mediagoblin/user_pages/views.py:415
#, python-format
msgid "You deleted the collection \"%s\""
msgstr ""
-#: mediagoblin/user_pages/views.py:429
+#: mediagoblin/user_pages/views.py:422
msgid ""
"The collection was not deleted because you didn't check that you were sure."
msgstr ""
-#: mediagoblin/user_pages/views.py:439
+#: mediagoblin/user_pages/views.py:430
msgid ""
"You are about to delete another user's collection. Proceed with caution."
msgstr ""
diff --git a/mediagoblin/i18n/sq/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/sq/LC_MESSAGES/mediagoblin.mo
index 276f1273..0f113dcb 100644
--- a/mediagoblin/i18n/sq/LC_MESSAGES/mediagoblin.mo
+++ b/mediagoblin/i18n/sq/LC_MESSAGES/mediagoblin.mo
Binary files differ
diff --git a/mediagoblin/i18n/sq/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/sq/LC_MESSAGES/mediagoblin.po
index 5c965623..aabf18db 100644
--- a/mediagoblin/i18n/sq/LC_MESSAGES/mediagoblin.po
+++ b/mediagoblin/i18n/sq/LC_MESSAGES/mediagoblin.po
@@ -3,14 +3,14 @@
# This file is distributed under the same license as the PROJECT project.
#
# Translators:
-# Besnik Bleta <besnik@programeshqip.org>, 2012.
-# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
+# Besnik <besnik@programeshqip.org>, 2012-2013
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2012
msgid ""
msgstr ""
"Project-Id-Version: GNU MediaGoblin\n"
"Report-Msgid-Bugs-To: http://issues.mediagoblin.org/\n"
-"POT-Creation-Date: 2013-03-04 18:04-0600\n"
-"PO-Revision-Date: 2013-03-05 00:04+0000\n"
+"POT-Creation-Date: 2013-05-27 13:54-0500\n"
+"PO-Revision-Date: 2013-05-27 18:54+0000\n"
"Last-Translator: cwebber <cwebber@dustycloud.org>\n"
"Language-Team: Albanian (http://www.transifex.com/projects/p/mediagoblin/language/sq/)\n"
"MIME-Version: 1.0\n"
@@ -20,34 +20,39 @@ msgstr ""
"Language: sq\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: mediagoblin/auth/forms.py:28
-msgid "Invalid User name or email address."
-msgstr ""
-
-#: mediagoblin/auth/forms.py:29
-msgid "This field does not take email addresses."
-msgstr ""
-
-#: mediagoblin/auth/forms.py:30
-msgid "This field requires an email address."
-msgstr ""
-
-#: mediagoblin/auth/forms.py:52 mediagoblin/auth/forms.py:67
+#: mediagoblin/auth/forms.py:26
msgid "Username"
msgstr "Emër përdoruesi"
-#: mediagoblin/auth/forms.py:56 mediagoblin/auth/forms.py:71
+#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:45
+#: mediagoblin/tests/test_util.py:110
msgid "Password"
msgstr "Fjalëkalim"
-#: mediagoblin/auth/forms.py:60
+#: mediagoblin/auth/forms.py:34
msgid "Email address"
msgstr "Adresë email"
-#: mediagoblin/auth/forms.py:78
+#: mediagoblin/auth/forms.py:41
+msgid "Username or Email"
+msgstr ""
+
+#: mediagoblin/auth/forms.py:52
msgid "Username or email"
msgstr "Emër përdoruesi ose email"
+#: mediagoblin/auth/tools.py:31
+msgid "Invalid User name or email address."
+msgstr "Emër përdoruesi ose adresë email e pavlefshme."
+
+#: mediagoblin/auth/tools.py:32
+msgid "This field does not take email addresses."
+msgstr "Kjo fushë nuk është për adresa email."
+
+#: mediagoblin/auth/tools.py:33
+msgid "This field requires an email address."
+msgstr "Kjo fushë lyp një adresë email."
+
#: mediagoblin/auth/views.py:54
msgid "Sorry, registration is disabled on this instance."
msgstr "Na njdeni, regjistrimi në këtë instancë të shërbimit është i çaktivizuar."
@@ -60,54 +65,54 @@ msgstr "Na ndjeni, ka tashmë një përdorues me këtë emër."
msgid "Sorry, a user with that email address already exists."
msgstr "Na ndjeni, ka tashmë një përdorues me këtë adresë email."
-#: mediagoblin/auth/views.py:174
+#: mediagoblin/auth/views.py:182
msgid ""
"Your email address has been verified. You may now login, edit your profile, "
"and submit images!"
msgstr "Adresa juaj email u verifikua. Tani mund të bëni hyrjen, të përpunoni profilin tuaj, dhe të parashtroni figura!"
-#: mediagoblin/auth/views.py:180
+#: mediagoblin/auth/views.py:188
msgid "The verification key or user id is incorrect"
msgstr "Kyçi i verifikimit ose id-ja e përdoruesit është e pasaktë"
-#: mediagoblin/auth/views.py:198
+#: mediagoblin/auth/views.py:206
msgid "You must be logged in so we know who to send the email to!"
msgstr "Duhet të jeni i futur, që ta dimë kujt t'ia çojmë email-in!"
-#: mediagoblin/auth/views.py:206
+#: mediagoblin/auth/views.py:214
msgid "You've already verified your email address!"
msgstr "Thuajse e keni verifikuar adresën tuaj email!"
-#: mediagoblin/auth/views.py:219
+#: mediagoblin/auth/views.py:227
msgid "Resent your verification email."
msgstr "Ridërgoni email-in tuaj të verifikimit."
-#: mediagoblin/auth/views.py:250
+#: mediagoblin/auth/views.py:258
msgid ""
"If that email address (case sensitive!) is registered an email has been sent"
" with instructions on how to change your password."
-msgstr ""
+msgstr "Nëse ajo adresë email (siç është shkruajtur!) është e regjistruar, është dërguar një email me udhëzime se si të ndryshoni fjalëkalimin tuaj."
-#: mediagoblin/auth/views.py:261
+#: mediagoblin/auth/views.py:269
msgid "Couldn't find someone with that username."
-msgstr ""
+msgstr "S'u gjet dot dikush me atë emër përdoruesi."
-#: mediagoblin/auth/views.py:264
+#: mediagoblin/auth/views.py:272
msgid ""
"An email has been sent with instructions on how to change your password."
msgstr "Është dërguar një email me udhëzime se si të ndryshoni fjalëkalimin tuaj."
-#: mediagoblin/auth/views.py:271
+#: mediagoblin/auth/views.py:279
msgid ""
"Could not send password recovery email as your username is inactive or your "
"account's email address has not been verified."
msgstr "Email-i i ricaktimit të fjalëkalimit nuk u dërgua dot, ngaqë emri juaj i përdoruesit nuk është aktivizuar ose adresa email e llogarisë suaj nuk është verifikuar."
-#: mediagoblin/auth/views.py:328
+#: mediagoblin/auth/views.py:336
msgid "You can now log in using your new password."
msgstr "Tani mun të hyni duke përdorur fjalëkalimin tuaj të ri."
-#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:93
+#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:82
#: mediagoblin/submit/forms.py:28 mediagoblin/submit/forms.py:47
#: mediagoblin/user_pages/forms.py:45
msgid "Title"
@@ -118,7 +123,7 @@ msgid "Description of this work"
msgstr "Përshkrim i kësaj pune"
#: mediagoblin/edit/forms.py:29 mediagoblin/edit/forms.py:52
-#: mediagoblin/edit/forms.py:97 mediagoblin/submit/forms.py:32
+#: mediagoblin/edit/forms.py:86 mediagoblin/submit/forms.py:32
#: mediagoblin/submit/forms.py:51 mediagoblin/user_pages/forms.py:49
msgid ""
"You can use\n"
@@ -134,11 +139,11 @@ msgstr "Etiketa"
msgid "Separate tags by commas."
msgstr "Ndajini etiketat me presje."
-#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:101
+#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:90
msgid "Slug"
msgstr "Identifikues"
-#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:102
+#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:91
msgid "The slug can't be empty"
msgstr "Identifikuesi s'mund të jetë i zbrazët"
@@ -166,45 +171,45 @@ msgid "This address contains errors"
msgstr "Kjo adresë përmban gabime"
#: mediagoblin/edit/forms.py:63
-msgid "Old password"
-msgstr "Fjalëkalimi i vjetër"
-
-#: mediagoblin/edit/forms.py:64
-msgid "Enter your old password to prove you own this account."
-msgstr "Jepni fjalëkalimin tuaj të vjetër që të provohet se këtë llogari e zotëroni ju."
-
-#: mediagoblin/edit/forms.py:67
-msgid "New password"
-msgstr "Fjalëkalimi i ri"
-
-#: mediagoblin/edit/forms.py:74
msgid "License preference"
-msgstr ""
+msgstr "Parapëlqime licence"
-#: mediagoblin/edit/forms.py:80
+#: mediagoblin/edit/forms.py:69
msgid "This will be your default license on upload forms."
-msgstr ""
+msgstr "Kjo do të jetë licenca juaj parazgjedhje për forma ngarkimesh."
-#: mediagoblin/edit/forms.py:82
+#: mediagoblin/edit/forms.py:71
msgid "Email me when others comment on my media"
msgstr "Dërgomë email kur të tjerët komentojnë te media ime"
-#: mediagoblin/edit/forms.py:94
+#: mediagoblin/edit/forms.py:83
msgid "The title can't be empty"
msgstr "Titulli s'mund të jetë i zbrazët"
-#: mediagoblin/edit/forms.py:96 mediagoblin/submit/forms.py:50
+#: mediagoblin/edit/forms.py:85 mediagoblin/submit/forms.py:50
#: mediagoblin/user_pages/forms.py:48
msgid "Description of this collection"
msgstr "Përshkrim i këtij koleksioni"
-#: mediagoblin/edit/forms.py:103
+#: mediagoblin/edit/forms.py:92
msgid ""
"The title part of this collection's address. You usually don't need to "
"change this."
msgstr "Pjesa titull e adresës së këtij koleksioni. Zakonisht nuk keni pse e ndryshoni këtë."
-#: mediagoblin/edit/views.py:66
+#: mediagoblin/edit/forms.py:99
+msgid "Old password"
+msgstr "Fjalëkalimi i vjetër"
+
+#: mediagoblin/edit/forms.py:101
+msgid "Enter your old password to prove you own this account."
+msgstr "Jepni fjalëkalimin tuaj të vjetër që të provohet se këtë llogari e zotëroni ju."
+
+#: mediagoblin/edit/forms.py:104
+msgid "New password"
+msgstr "Fjalëkalimi i ri"
+
+#: mediagoblin/edit/views.py:67
msgid "An entry with that slug already exists for this user."
msgstr "Ka tashmë një zë me atë identifikues për këtë përdorues."
@@ -219,7 +224,7 @@ msgstr "Shtuat bashkangjitjen %s!"
#: mediagoblin/edit/views.py:182
msgid "You can only edit your own profile."
-msgstr ""
+msgstr "Mund të përpunoni vetëm profilin tuaj."
#: mediagoblin/edit/views.py:188
msgid "You are editing a user's profile. Proceed with caution."
@@ -229,57 +234,80 @@ msgstr "Po përpunoni profilin e një përdoruesi. Hapni sytë."
msgid "Profile changes saved"
msgstr "Ndryshimet e profilit u ruajtën"
-#: mediagoblin/edit/views.py:241
-msgid "Wrong password"
-msgstr "Fjalëkalim i gabuar"
-
-#: mediagoblin/edit/views.py:252
+#: mediagoblin/edit/views.py:240
msgid "Account settings saved"
msgstr "Rregullimet e llogarisë u ruajtën"
-#: mediagoblin/edit/views.py:286
+#: mediagoblin/edit/views.py:274
msgid "You need to confirm the deletion of your account."
-msgstr ""
+msgstr "Lypset të ripohoni fshirjen e llogarisë suaj."
-#: mediagoblin/edit/views.py:322 mediagoblin/submit/views.py:142
-#: mediagoblin/user_pages/views.py:214
+#: mediagoblin/edit/views.py:310 mediagoblin/submit/views.py:138
+#: mediagoblin/user_pages/views.py:222
#, python-format
msgid "You already have a collection called \"%s\"!"
-msgstr "Keni tashmë një koleksion të quajtur \"%s\"!"
+msgstr "Keni tashmë një koleksion të quajtur \"%s\"!"
-#: mediagoblin/edit/views.py:326
+#: mediagoblin/edit/views.py:314
msgid "A collection with that slug already exists for this user."
msgstr "Ka tashmë një koleksion me atë identifikues për këtë përdorues."
-#: mediagoblin/edit/views.py:343
+#: mediagoblin/edit/views.py:329
msgid "You are editing another user's collection. Proceed with caution."
msgstr "Po përpunoni koleksionin e një tjetër përdoruesi. Hapni sytë."
-#: mediagoblin/gmg_commands/theme.py:58
+#: mediagoblin/edit/views.py:348
+msgid "Wrong password"
+msgstr "Fjalëkalim i gabuar"
+
+#: mediagoblin/edit/views.py:363
+msgid "Your password was changed successfully"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:60
msgid "Cannot link theme... no theme set\n"
msgstr "Nuk krijohet dot lidhje për te tema... nuk ka temë të caktuar\n"
-#: mediagoblin/gmg_commands/theme.py:71
+#: mediagoblin/gmg_commands/assetlink.py:73
msgid "No asset directory for this theme\n"
msgstr "Nuk ka drejtori asetesh për këtë temë\n"
-#: mediagoblin/gmg_commands/theme.py:74
+#: mediagoblin/gmg_commands/assetlink.py:76
msgid "However, old link directory symlink found; removed.\n"
msgstr "Sidoqoftë, u gjet simlidhje e vjetër drejtorie lidhjesh; u hoq.\n"
+#: mediagoblin/gmg_commands/assetlink.py:112
+#, python-format
+msgid "Could not link \"%s\": %s exists and is not a symlink\n"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:119
+#, python-format
+msgid "Skipping \"%s\"; already set up.\n"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:124
+#, python-format
+msgid "Old link found for \"%s\"; removing.\n"
+msgstr ""
+
#: mediagoblin/meddleware/csrf.py:134
msgid ""
"CSRF cookie not present. This is most likely the result of a cookie blocker "
"or somesuch.<br/>Make sure to permit the settings of cookies for this "
"domain."
-msgstr ""
+msgstr "Pa cookie CSRF të pranishme. Ka shumë të ngjarë që të jetë punë e një bllokuesi cookie-sh ose të tillë.<br/>Sigurohuni që të lejoni depozitim cookie-sh për këtë përkatësi."
-#: mediagoblin/media_types/__init__.py:61
-#: mediagoblin/media_types/__init__.py:102
+#: mediagoblin/media_types/__init__.py:111
+#: mediagoblin/media_types/__init__.py:155
msgid "Sorry, I don't support that file type :("
msgstr "Na ndjeni, nuk e mbullojmë këtë lloj kartele :("
-#: mediagoblin/media_types/video/processing.py:36
+#: mediagoblin/media_types/pdf/processing.py:136
+msgid "unoconv failing to run, check log file"
+msgstr ""
+
+#: mediagoblin/media_types/video/processing.py:37
msgid "Video transcoding failed"
msgstr "Ndërkodimi i videos dështoi"
@@ -346,17 +374,17 @@ msgstr "URI ridrejtimi për zbatimin, kjo fushë\n është <strong>e
msgid "This field is required for public clients"
msgstr "Kjo fushë është e domosdoshme për klientë publikë"
-#: mediagoblin/plugins/oauth/views.py:59
+#: mediagoblin/plugins/oauth/views.py:56
msgid "The client {0} has been registered!"
msgstr "Klienti {0} u regjistrua!"
#: mediagoblin/plugins/oauth/templates/oauth/client/connections.html:22
msgid "OAuth client connections"
-msgstr ""
+msgstr "Lidhje klienti OAuth"
#: mediagoblin/plugins/oauth/templates/oauth/client/list.html:22
msgid "Your OAuth clients"
-msgstr ""
+msgstr "Klientët tuaj OAuth"
#: mediagoblin/plugins/oauth/templates/oauth/client/register.html:29
#: mediagoblin/templates/mediagoblin/submit/collection.html:30
@@ -365,7 +393,7 @@ msgstr ""
msgid "Add"
msgstr "Shtoni"
-#: mediagoblin/processing/__init__.py:172
+#: mediagoblin/processing/__init__.py:193
msgid "Invalid file given for media type."
msgstr "Kartelë e gabuar e dhënë për llojin e medias."
@@ -373,118 +401,71 @@ msgstr "Kartelë e gabuar e dhënë për llojin e medias."
msgid "File"
msgstr "Kartelë"
-#: mediagoblin/submit/views.py:51
+#: mediagoblin/submit/views.py:49
msgid "You must provide a file."
msgstr "Duhet të jepni një kartelë."
-#: mediagoblin/submit/views.py:97
+#: mediagoblin/submit/views.py:93
msgid "Woohoo! Submitted!"
msgstr "Yhaaaaaa! U parashtrua!"
-#: mediagoblin/submit/views.py:146
+#: mediagoblin/submit/views.py:144
#, python-format
msgid "Collection \"%s\" added!"
msgstr "U shtua koleksioni \"%s\"!"
-#: mediagoblin/templates/mediagoblin/base.html:64
+#: mediagoblin/templates/mediagoblin/base.html:67
msgid "Verify your email!"
msgstr "Verifikoni email-in tuaj!"
-#: mediagoblin/templates/mediagoblin/base.html:65
+#: mediagoblin/templates/mediagoblin/base.html:68
msgid "log out"
msgstr "dilni"
-#: mediagoblin/templates/mediagoblin/base.html:70
+#: mediagoblin/templates/mediagoblin/base.html:73
#: mediagoblin/templates/mediagoblin/auth/login.html:28
#: mediagoblin/templates/mediagoblin/auth/login.html:36
#: mediagoblin/templates/mediagoblin/auth/login.html:54
msgid "Log in"
msgstr "Hyni"
-#: mediagoblin/templates/mediagoblin/base.html:79
+#: mediagoblin/templates/mediagoblin/base.html:82
#, python-format
msgid "<a href=\"%(user_url)s\">%(user_name)s</a>'s account"
msgstr "Llogaria e <a href=\"%(user_url)s\">%(user_name)s</a>"
-#: mediagoblin/templates/mediagoblin/base.html:86
+#: mediagoblin/templates/mediagoblin/base.html:89
msgid "Change account settings"
msgstr "Ndryshoni rregullime llogarie"
-#: mediagoblin/templates/mediagoblin/base.html:90
-#: mediagoblin/templates/mediagoblin/base.html:105
+#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:108
#: mediagoblin/templates/mediagoblin/admin/panel.html:21
#: mediagoblin/templates/mediagoblin/admin/panel.html:26
#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:21
#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:26
msgid "Media processing panel"
-msgstr "Paneli i Përpunimit të Medias"
+msgstr "Paneli i përpunimit të medias"
-#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:96
msgid "Log out"
-msgstr ""
+msgstr "Dilni"
-#: mediagoblin/templates/mediagoblin/base.html:96
+#: mediagoblin/templates/mediagoblin/base.html:99
#: mediagoblin/templates/mediagoblin/user_pages/user.html:156
msgid "Add media"
msgstr "Shtoni media"
-#: mediagoblin/templates/mediagoblin/base.html:99
+#: mediagoblin/templates/mediagoblin/base.html:102
#: mediagoblin/templates/mediagoblin/user_pages/collection_list.html:41
msgid "Create new collection"
msgstr "Krijoni koleksion të ri"
-#: mediagoblin/templates/mediagoblin/base.html:122
-#, python-format
-msgid ""
-"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
-"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/base.html:125
-#, python-format
-msgid ""
-"Released under the <a "
-"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
-"href=\"%(source_link)s\">Source code</a> available."
-msgstr "Hedhur në qarkullim sipas <a href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL-së</a>. <a href=\"%(source_link)s\">Kodi burim</a> është i passhëm."
-
#: mediagoblin/templates/mediagoblin/error.html:24
msgid "Image of goblin stressing out"
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:31
-msgid "Explore"
-msgstr "Eksploroni"
-
-#: mediagoblin/templates/mediagoblin/root.html:33
-msgid "Hi there, welcome to this MediaGoblin site!"
-msgstr "Tungjatjeta juaj, mirë se vini te ky site MediaGoblin!"
-
-#: mediagoblin/templates/mediagoblin/root.html:35
-msgid ""
-"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
-"extraordinarily great piece of media hosting software."
-msgstr "Ky site përdor <a href=\"http://mediagoblin.org\">MediaGoblin</a>, një program jashtëzakonisht i shkëlqyer për strehim mediash."
-
-#: mediagoblin/templates/mediagoblin/root.html:36
-msgid ""
-"To add your own media, place comments, and more, you can log in with your "
-"MediaGoblin account."
-msgstr "Për të shtuar media tuajën, për të bërë komente, dhe të tjera, mund të hyni përmes llogarisë suaj MediaGoblin."
-
-#: mediagoblin/templates/mediagoblin/root.html:38
-msgid "Don't have one yet? It's easy!"
-msgstr "Nuk keni ende një të tillë? Është e lehtë!"
-
-#: mediagoblin/templates/mediagoblin/root.html:39
-#, python-format
-msgid ""
-"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
-" or\n"
-" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
-msgstr "<a class=\"button_action_highlight\" href=\"%(register_url)s\">Krijoni një llogarin te ky site</a>\n ose\n <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Instaloni dhe rregulloni MediaGoblin-in te shërbyesi juaj</a>"
+msgstr "Figurë e gungaçi duke bërë shtriqje"
-#: mediagoblin/templates/mediagoblin/root.html:47
+#: mediagoblin/templates/mediagoblin/root.html:32
msgid "Most recent media"
msgstr "Mediat më të reja"
@@ -515,7 +496,7 @@ msgstr "Pa zëra të dështuar!"
#: mediagoblin/templates/mediagoblin/admin/panel.html:92
msgid "Last 10 successful uploads"
-msgstr "10 Ngarkimet e Fundit të Suksesshme"
+msgstr "10 ngarkimet e fundit të suksesshme"
#: mediagoblin/templates/mediagoblin/admin/panel.html:112
#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:107
@@ -590,6 +571,53 @@ msgid ""
"%(verification_url)s"
msgstr "Njatjeta %(username)s,\n\nqë të aktivizoni llogarinë tuaj te GNU MediaGoblin hapeni URL-në vijuese te\nshfletuesi juaj web:\n\n%(verification_url)s"
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:21
+#, python-format
+msgid ""
+"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
+"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
+msgstr "Bazuar në <a href=\"http://mediagoblin.org/\" title='Version %(version)s'>MediaGoblin</a>, një projekt <a href=\"http://gnu.org/\">GNU</a>."
+
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:24
+#, python-format
+msgid ""
+"Released under the <a "
+"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
+"href=\"%(source_link)s\">Source code</a> available."
+msgstr "Hedhur në qarkullim sipas <a href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL-së</a>. <a href=\"%(source_link)s\">Kodi burim</a> është i passhëm."
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:20
+msgid "Explore"
+msgstr "Eksploroni"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:22
+msgid "Hi there, welcome to this MediaGoblin site!"
+msgstr "Tungjatjeta juaj, mirë se vini te ky site MediaGoblin!"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:24
+msgid ""
+"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
+"extraordinarily great piece of media hosting software."
+msgstr "Ky site përdor <a href=\"http://mediagoblin.org\">MediaGoblin</a>, një program jashtëzakonisht i shkëlqyer për strehim mediash."
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:25
+msgid ""
+"To add your own media, place comments, and more, you can log in with your "
+"MediaGoblin account."
+msgstr "Për të shtuar media tuajën, për të bërë komente, dhe të tjera, mund të hyni përmes llogarisë suaj MediaGoblin."
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:27
+msgid "Don't have one yet? It's easy!"
+msgstr "Nuk keni ende një të tillë? Është e lehtë!"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:28
+#, python-format
+msgid ""
+"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
+" or\n"
+" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/bits/logo.html:23
#: mediagoblin/themes/airy/templates/mediagoblin/bits/logo.html:23
msgid "MediaGoblin logo"
@@ -602,13 +630,13 @@ msgid "Editing attachments for %(media_title)s"
msgstr "Po përpunohen bashkangjitjet për %(media_title)s"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:159
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:175
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:182
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:198
msgid "Attachments"
msgstr "Bashkangjitje"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:57
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:181
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:204
msgid "Add attachment"
msgstr "Shtoni bashkangjitje"
@@ -625,23 +653,33 @@ msgstr "Anuloje"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:63
#: mediagoblin/templates/mediagoblin/edit/edit.html:42
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:52
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:55
#: mediagoblin/templates/mediagoblin/edit/edit_collection.html:33
#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:40
msgid "Save changes"
msgstr "Ruaji ndryshimet"
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:28
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:38
+#, python-format
+msgid "Changing %(username)s's password"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:45
+msgid "Save"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:28
#, python-format
msgid "Really delete user '%(user_name)s' and all related media/comments?"
-msgstr ""
+msgstr "Të fshihet vërtet përdoruesi '%(user_name)s' dhe krejt media/komentet përkatëse?"
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:35
msgid "Yes, really delete my account"
-msgstr ""
+msgstr "Po, fshijeni vërtet llogarinë time"
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:47
+#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:48
#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:49
msgid "Delete permanently"
msgstr "Fshije përgjithmonë"
@@ -658,10 +696,14 @@ msgstr "Po përpunohet %(media_title)s"
msgid "Changing %(username)s's account settings"
msgstr "Po ndryshohen rregullimet e llogarisë %(username)s"
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:59
-msgid "Delete my account"
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:46
+msgid "Change your password."
msgstr ""
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:62
+msgid "Delete my account"
+msgstr "Fshije llogarinë time"
+
#: mediagoblin/templates/mediagoblin/edit/edit_collection.html:29
#, python-format
msgid "Editing %(collection_title)s"
@@ -683,6 +725,7 @@ msgstr "Media e etiketuar me:: %(tag_name)s"
#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:56
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:65
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:136
#: mediagoblin/templates/mediagoblin/media_displays/video.html:55
msgid "Download"
@@ -707,6 +750,7 @@ msgid ""
msgstr "Një shfletues web modern që mund të luajë \n\taudion mund ta merrni te <a href=\"http://getfirefox.com\">\n\t http://getfirefox.com</a>!"
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:60
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:71
#: mediagoblin/templates/mediagoblin/media_displays/video.html:61
msgid "Original file"
msgstr "Kartela origjinale"
@@ -715,6 +759,7 @@ msgstr "Kartela origjinale"
msgid "WebM file (Vorbis codec)"
msgstr "Kartelë WebM (kodek Vorbis)"
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:59
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:87
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:93
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:99
@@ -725,9 +770,13 @@ msgstr "Kartelë WebM (kodek Vorbis)"
msgid "Image for %(media_title)s"
msgstr "Figurë për %(media_title)s"
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:79
+msgid "PDF file"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:112
msgid "Toggle Rotate"
-msgstr ""
+msgstr "Aktivizoni/Çaktivizoni Rrotullimin"
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:113
msgid "Perspective"
@@ -770,14 +819,14 @@ msgid ""
"Sorry, this video will not work because\n"
" your web browser does not support HTML5 \n"
" video."
-msgstr ""
+msgstr "Na ndjeni, kjo video nuk do të punojë ngaqë\n shfletuesi juaj web nuk mbulon videot\n HTML5."
#: mediagoblin/templates/mediagoblin/media_displays/video.html:47
msgid ""
"You can get a modern web browser that \n"
" can play this video at <a href=\"http://getfirefox.com\">\n"
" http://getfirefox.com</a>!"
-msgstr ""
+msgstr "Mund të merrni një shfletues web modern që \n është në gjendje ta shfaqë këtë video, te <a href=\"http://getfirefox.com\">\n http://getfirefox.com</a>!"
#: mediagoblin/templates/mediagoblin/media_displays/video.html:69
msgid "WebM file (640p; VP8/Vorbis)"
@@ -823,19 +872,19 @@ msgstr "Të fshihet vërtet %(title)s?"
msgid "Really remove %(media_title)s from %(collection_title)s?"
msgstr "Të hiqet vërtet %(media_title)s nga %(collection_title)s?"
-#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:53
+#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:54
msgid "Remove"
msgstr "Hiqe"
#: mediagoblin/templates/mediagoblin/user_pages/collection_list.html:21
#, python-format
msgid "%(username)s's collections"
-msgstr ""
+msgstr "Koleksione të %(username)s"
#: mediagoblin/templates/mediagoblin/user_pages/collection_list.html:28
#, python-format
msgid "<a href=\"%(user_url)s\">%(username)s</a>'s collections"
-msgstr ""
+msgstr "Koleksione të <a href=\"%(user_url)s\">%(username)s</a>"
#: mediagoblin/templates/mediagoblin/user_pages/comment_email.txt:19
#, python-format
@@ -854,7 +903,7 @@ msgstr "Media nga %(username)s"
msgid ""
"<a href=\"%(user_url)s\">%(username)s</a>'s media with tag <a "
"href=\"%(tag_url)s\">%(tag)s</a>"
-msgstr ""
+msgstr "Media të <a href=\"%(user_url)s\">%(username)s</a> me etiketën <a href=\"%(tag_url)s\">%(tag)s</a>"
#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:48
#, python-format
@@ -866,30 +915,34 @@ msgstr "Media nga <a href=\"%(user_url)s\">%(username)s</a>"
msgid "â– Browsing media by <a href=\"%(user_url)s\">%(username)s</a>"
msgstr "â– Po shfletoni media nga <a href=\"%(user_url)s\">%(username)s</a>"
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:94
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:95
msgid "Add a comment"
msgstr "Shtoni një koment"
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:102
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:104
msgid "Add this comment"
msgstr "Shtoje këtë koment"
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:123
-msgid "at"
-msgstr "te"
-
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:144
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:132
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:152
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:164
#, python-format
-msgid ""
-"<h3>Added on</h3>\n"
-" <p>%(date)s</p>"
-msgstr "<h3>Shtuar më</h3>\n <p>%(date)s</p>"
+msgid "%(formatted_time)s ago"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:150
+msgid "Added"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:161
+msgid "Created"
+msgstr ""
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:28
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:40
#, python-format
msgid "Add “%(media_title)s†to a collection"
-msgstr ""
+msgstr "Shtojeni “%(media_title)s†te një koleksion"
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:54
msgid "+"
@@ -968,7 +1021,7 @@ msgstr "Ky përdorues nuk e ka plotësuar (ende) profilin e vet."
#: mediagoblin/templates/mediagoblin/user_pages/user.html:124
msgid "Browse collections"
-msgstr ""
+msgstr "Shfletoni koleksionet"
#: mediagoblin/templates/mediagoblin/user_pages/user.html:137
#, python-format
@@ -993,11 +1046,11 @@ msgstr "(hiqe)"
#: mediagoblin/templates/mediagoblin/utils/collections.html:21
msgid "Collected in"
-msgstr ""
+msgstr "Pjesë e koleksionit"
#: mediagoblin/templates/mediagoblin/utils/collections.html:40
msgid "Add to a collection"
-msgstr ""
+msgstr "Shtoje te një koleksion"
#: mediagoblin/templates/mediagoblin/utils/feed_link.html:21
#: mediagoblin/themes/airy/templates/mediagoblin/utils/feed_link.html:21
@@ -1039,7 +1092,7 @@ msgstr "më të vjetra"
msgid "Tagged with"
msgstr "Etiketuar me"
-#: mediagoblin/tools/exif.py:80
+#: mediagoblin/tools/exif.py:83
msgid "Could not read the image file."
msgstr "Nuk lexoi dot kartelën e figurës."
@@ -1069,9 +1122,33 @@ msgid ""
" deleted."
msgstr "Nuk duket se ka ndonjë faqe në këtë adresë. Na ndjeni!</p><p>Nëse jeni i sigurt se kjo adresë është e saktë, ndoshta faqja që po kërkoni është lëvizur ose fshirë."
+#: mediagoblin/tools/timesince.py:62
+msgid "year"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:63
+msgid "month"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:64
+msgid "week"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:65
+msgid "day"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:66
+msgid "hour"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:67
+msgid "minute"
+msgstr ""
+
#: mediagoblin/user_pages/forms.py:23
msgid "Comment"
-msgstr ""
+msgstr "Koment"
#: mediagoblin/user_pages/forms.py:25
msgid ""
@@ -1090,7 +1167,7 @@ msgstr "Jam i sigurt se dua që të hiqet ky objekt prek koleksioni"
#: mediagoblin/user_pages/forms.py:39
msgid "Collection"
-msgstr ""
+msgstr "Koleksion"
#: mediagoblin/user_pages/forms.py:40
msgid "-- Select --"
@@ -1100,73 +1177,77 @@ msgstr "-- Përzgjidhni --"
msgid "Include a note"
msgstr "Përfshini një shënim"
-#: mediagoblin/user_pages/lib.py:56
+#: mediagoblin/user_pages/lib.py:58
msgid "commented on your post"
msgstr "komentoi te postimi juaj"
-#: mediagoblin/user_pages/views.py:166
+#: mediagoblin/user_pages/views.py:169
+msgid "Sorry, comments are disabled."
+msgstr ""
+
+#: mediagoblin/user_pages/views.py:174
msgid "Oops, your comment was empty."
msgstr "Hmmm, komenti juaj qe i zbrazët."
-#: mediagoblin/user_pages/views.py:172
+#: mediagoblin/user_pages/views.py:180
msgid "Your comment has been posted!"
msgstr "Komenti juaj u postua!"
-#: mediagoblin/user_pages/views.py:197
+#: mediagoblin/user_pages/views.py:205
msgid "Please check your entries and try again."
msgstr "Ju lutemi, kontrolloni zërat tuaj dhe riprovoni."
-#: mediagoblin/user_pages/views.py:237
+#: mediagoblin/user_pages/views.py:245
msgid "You have to select or add a collection"
msgstr "Duhet të përzgjidhni ose shtoni një koleksion"
-#: mediagoblin/user_pages/views.py:248
+#: mediagoblin/user_pages/views.py:256
#, python-format
msgid "\"%s\" already in collection \"%s\""
msgstr "\"%s\" gjendet tashmë te koleksioni \"%s\""
-#: mediagoblin/user_pages/views.py:264
+#: mediagoblin/user_pages/views.py:262
#, python-format
msgid "\"%s\" added to collection \"%s\""
msgstr "\"%s\" u shtua te koleksioni \"%s\""
-#: mediagoblin/user_pages/views.py:286
+#: mediagoblin/user_pages/views.py:282
msgid "You deleted the media."
msgstr "E fshitë median."
-#: mediagoblin/user_pages/views.py:293
+#: mediagoblin/user_pages/views.py:289
msgid "The media was not deleted because you didn't check that you were sure."
msgstr "Media nuk u fshi ngaqë nuk i vutë shenjë pohimit se jeni i sigurt."
-#: mediagoblin/user_pages/views.py:301
+#: mediagoblin/user_pages/views.py:296
msgid "You are about to delete another user's media. Proceed with caution."
msgstr "Ju ndan një hap nga fshirja e medias të një tjetër përdoruesi. Hapni sytë."
-#: mediagoblin/user_pages/views.py:375
+#: mediagoblin/user_pages/views.py:370
msgid "You deleted the item from the collection."
msgstr "E fshitë objektin prej koleksionit."
-#: mediagoblin/user_pages/views.py:379
+#: mediagoblin/user_pages/views.py:374
msgid "The item was not removed because you didn't check that you were sure."
msgstr "Objekti nuk u fshi ngaqë, nuk pohuat se jeni të sigurt për këtë."
-#: mediagoblin/user_pages/views.py:389
+#: mediagoblin/user_pages/views.py:382
msgid ""
"You are about to delete an item from another user's collection. Proceed with"
" caution."
msgstr "Ju ndan një hap nga fshirja e një objekti prej koleksionit të një përdoruesi tjetër. Hapni sytë."
-#: mediagoblin/user_pages/views.py:422
+#: mediagoblin/user_pages/views.py:415
#, python-format
msgid "You deleted the collection \"%s\""
msgstr "E fshitë koleksionin \"%s\""
-#: mediagoblin/user_pages/views.py:429
+#: mediagoblin/user_pages/views.py:422
msgid ""
"The collection was not deleted because you didn't check that you were sure."
msgstr "Koleksioni nuk u fshi ngaqë, nuk pohuat se jeni të sigurt për këtë."
-#: mediagoblin/user_pages/views.py:439
+#: mediagoblin/user_pages/views.py:430
msgid ""
"You are about to delete another user's collection. Proceed with caution."
msgstr "Ju ndan një hap nga fshirja e koleksionit të një përdoruesi tjetër. Hapni sytë."
diff --git a/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.mo
index f6918f71..5564d35d 100644
--- a/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.mo
+++ b/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.mo
Binary files differ
diff --git a/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po
index d482151d..fcf8a666 100644
--- a/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po
+++ b/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po
@@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: GNU MediaGoblin\n"
"Report-Msgid-Bugs-To: http://issues.mediagoblin.org/\n"
-"POT-Creation-Date: 2013-03-04 18:04-0600\n"
-"PO-Revision-Date: 2013-03-05 00:04+0000\n"
+"POT-Creation-Date: 2013-05-27 13:54-0500\n"
+"PO-Revision-Date: 2013-05-27 18:54+0000\n"
"Last-Translator: cwebber <cwebber@dustycloud.org>\n"
"Language-Team: Serbian (http://www.transifex.com/projects/p/mediagoblin/language/sr/)\n"
"MIME-Version: 1.0\n"
@@ -18,32 +18,37 @@ msgstr ""
"Language: sr\n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
-#: mediagoblin/auth/forms.py:28
-msgid "Invalid User name or email address."
+#: mediagoblin/auth/forms.py:26
+msgid "Username"
msgstr ""
-#: mediagoblin/auth/forms.py:29
-msgid "This field does not take email addresses."
+#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:45
+#: mediagoblin/tests/test_util.py:110
+msgid "Password"
msgstr ""
-#: mediagoblin/auth/forms.py:30
-msgid "This field requires an email address."
+#: mediagoblin/auth/forms.py:34
+msgid "Email address"
msgstr ""
-#: mediagoblin/auth/forms.py:52 mediagoblin/auth/forms.py:67
-msgid "Username"
+#: mediagoblin/auth/forms.py:41
+msgid "Username or Email"
msgstr ""
-#: mediagoblin/auth/forms.py:56 mediagoblin/auth/forms.py:71
-msgid "Password"
+#: mediagoblin/auth/forms.py:52
+msgid "Username or email"
msgstr ""
-#: mediagoblin/auth/forms.py:60
-msgid "Email address"
+#: mediagoblin/auth/tools.py:31
+msgid "Invalid User name or email address."
msgstr ""
-#: mediagoblin/auth/forms.py:78
-msgid "Username or email"
+#: mediagoblin/auth/tools.py:32
+msgid "This field does not take email addresses."
+msgstr ""
+
+#: mediagoblin/auth/tools.py:33
+msgid "This field requires an email address."
msgstr ""
#: mediagoblin/auth/views.py:54
@@ -58,54 +63,54 @@ msgstr ""
msgid "Sorry, a user with that email address already exists."
msgstr ""
-#: mediagoblin/auth/views.py:174
+#: mediagoblin/auth/views.py:182
msgid ""
"Your email address has been verified. You may now login, edit your profile, "
"and submit images!"
msgstr ""
-#: mediagoblin/auth/views.py:180
+#: mediagoblin/auth/views.py:188
msgid "The verification key or user id is incorrect"
msgstr ""
-#: mediagoblin/auth/views.py:198
+#: mediagoblin/auth/views.py:206
msgid "You must be logged in so we know who to send the email to!"
msgstr ""
-#: mediagoblin/auth/views.py:206
+#: mediagoblin/auth/views.py:214
msgid "You've already verified your email address!"
msgstr ""
-#: mediagoblin/auth/views.py:219
+#: mediagoblin/auth/views.py:227
msgid "Resent your verification email."
msgstr ""
-#: mediagoblin/auth/views.py:250
+#: mediagoblin/auth/views.py:258
msgid ""
"If that email address (case sensitive!) is registered an email has been sent"
" with instructions on how to change your password."
msgstr ""
-#: mediagoblin/auth/views.py:261
+#: mediagoblin/auth/views.py:269
msgid "Couldn't find someone with that username."
msgstr ""
-#: mediagoblin/auth/views.py:264
+#: mediagoblin/auth/views.py:272
msgid ""
"An email has been sent with instructions on how to change your password."
msgstr ""
-#: mediagoblin/auth/views.py:271
+#: mediagoblin/auth/views.py:279
msgid ""
"Could not send password recovery email as your username is inactive or your "
"account's email address has not been verified."
msgstr ""
-#: mediagoblin/auth/views.py:328
+#: mediagoblin/auth/views.py:336
msgid "You can now log in using your new password."
msgstr ""
-#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:93
+#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:82
#: mediagoblin/submit/forms.py:28 mediagoblin/submit/forms.py:47
#: mediagoblin/user_pages/forms.py:45
msgid "Title"
@@ -116,7 +121,7 @@ msgid "Description of this work"
msgstr ""
#: mediagoblin/edit/forms.py:29 mediagoblin/edit/forms.py:52
-#: mediagoblin/edit/forms.py:97 mediagoblin/submit/forms.py:32
+#: mediagoblin/edit/forms.py:86 mediagoblin/submit/forms.py:32
#: mediagoblin/submit/forms.py:51 mediagoblin/user_pages/forms.py:49
msgid ""
"You can use\n"
@@ -132,11 +137,11 @@ msgstr ""
msgid "Separate tags by commas."
msgstr ""
-#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:101
+#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:90
msgid "Slug"
msgstr ""
-#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:102
+#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:91
msgid "The slug can't be empty"
msgstr ""
@@ -164,45 +169,45 @@ msgid "This address contains errors"
msgstr ""
#: mediagoblin/edit/forms.py:63
-msgid "Old password"
-msgstr ""
-
-#: mediagoblin/edit/forms.py:64
-msgid "Enter your old password to prove you own this account."
-msgstr ""
-
-#: mediagoblin/edit/forms.py:67
-msgid "New password"
-msgstr ""
-
-#: mediagoblin/edit/forms.py:74
msgid "License preference"
msgstr ""
-#: mediagoblin/edit/forms.py:80
+#: mediagoblin/edit/forms.py:69
msgid "This will be your default license on upload forms."
msgstr ""
-#: mediagoblin/edit/forms.py:82
+#: mediagoblin/edit/forms.py:71
msgid "Email me when others comment on my media"
msgstr ""
-#: mediagoblin/edit/forms.py:94
+#: mediagoblin/edit/forms.py:83
msgid "The title can't be empty"
msgstr ""
-#: mediagoblin/edit/forms.py:96 mediagoblin/submit/forms.py:50
+#: mediagoblin/edit/forms.py:85 mediagoblin/submit/forms.py:50
#: mediagoblin/user_pages/forms.py:48
msgid "Description of this collection"
msgstr ""
-#: mediagoblin/edit/forms.py:103
+#: mediagoblin/edit/forms.py:92
msgid ""
"The title part of this collection's address. You usually don't need to "
"change this."
msgstr ""
-#: mediagoblin/edit/views.py:66
+#: mediagoblin/edit/forms.py:99
+msgid "Old password"
+msgstr ""
+
+#: mediagoblin/edit/forms.py:101
+msgid "Enter your old password to prove you own this account."
+msgstr ""
+
+#: mediagoblin/edit/forms.py:104
+msgid "New password"
+msgstr ""
+
+#: mediagoblin/edit/views.py:67
msgid "An entry with that slug already exists for this user."
msgstr ""
@@ -227,44 +232,63 @@ msgstr ""
msgid "Profile changes saved"
msgstr ""
-#: mediagoblin/edit/views.py:241
-msgid "Wrong password"
-msgstr ""
-
-#: mediagoblin/edit/views.py:252
+#: mediagoblin/edit/views.py:240
msgid "Account settings saved"
msgstr ""
-#: mediagoblin/edit/views.py:286
+#: mediagoblin/edit/views.py:274
msgid "You need to confirm the deletion of your account."
msgstr ""
-#: mediagoblin/edit/views.py:322 mediagoblin/submit/views.py:142
-#: mediagoblin/user_pages/views.py:214
+#: mediagoblin/edit/views.py:310 mediagoblin/submit/views.py:138
+#: mediagoblin/user_pages/views.py:222
#, python-format
msgid "You already have a collection called \"%s\"!"
msgstr ""
-#: mediagoblin/edit/views.py:326
+#: mediagoblin/edit/views.py:314
msgid "A collection with that slug already exists for this user."
msgstr ""
-#: mediagoblin/edit/views.py:343
+#: mediagoblin/edit/views.py:329
msgid "You are editing another user's collection. Proceed with caution."
msgstr ""
-#: mediagoblin/gmg_commands/theme.py:58
+#: mediagoblin/edit/views.py:348
+msgid "Wrong password"
+msgstr ""
+
+#: mediagoblin/edit/views.py:363
+msgid "Your password was changed successfully"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:60
msgid "Cannot link theme... no theme set\n"
msgstr ""
-#: mediagoblin/gmg_commands/theme.py:71
+#: mediagoblin/gmg_commands/assetlink.py:73
msgid "No asset directory for this theme\n"
msgstr ""
-#: mediagoblin/gmg_commands/theme.py:74
+#: mediagoblin/gmg_commands/assetlink.py:76
msgid "However, old link directory symlink found; removed.\n"
msgstr ""
+#: mediagoblin/gmg_commands/assetlink.py:112
+#, python-format
+msgid "Could not link \"%s\": %s exists and is not a symlink\n"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:119
+#, python-format
+msgid "Skipping \"%s\"; already set up.\n"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:124
+#, python-format
+msgid "Old link found for \"%s\"; removing.\n"
+msgstr ""
+
#: mediagoblin/meddleware/csrf.py:134
msgid ""
"CSRF cookie not present. This is most likely the result of a cookie blocker "
@@ -272,12 +296,16 @@ msgid ""
"domain."
msgstr ""
-#: mediagoblin/media_types/__init__.py:61
-#: mediagoblin/media_types/__init__.py:102
+#: mediagoblin/media_types/__init__.py:111
+#: mediagoblin/media_types/__init__.py:155
msgid "Sorry, I don't support that file type :("
msgstr ""
-#: mediagoblin/media_types/video/processing.py:36
+#: mediagoblin/media_types/pdf/processing.py:136
+msgid "unoconv failing to run, check log file"
+msgstr ""
+
+#: mediagoblin/media_types/video/processing.py:37
msgid "Video transcoding failed"
msgstr ""
@@ -344,7 +372,7 @@ msgstr ""
msgid "This field is required for public clients"
msgstr ""
-#: mediagoblin/plugins/oauth/views.py:59
+#: mediagoblin/plugins/oauth/views.py:56
msgid "The client {0} has been registered!"
msgstr ""
@@ -363,7 +391,7 @@ msgstr ""
msgid "Add"
msgstr ""
-#: mediagoblin/processing/__init__.py:172
+#: mediagoblin/processing/__init__.py:193
msgid "Invalid file given for media type."
msgstr ""
@@ -371,45 +399,45 @@ msgstr ""
msgid "File"
msgstr ""
-#: mediagoblin/submit/views.py:51
+#: mediagoblin/submit/views.py:49
msgid "You must provide a file."
msgstr ""
-#: mediagoblin/submit/views.py:97
+#: mediagoblin/submit/views.py:93
msgid "Woohoo! Submitted!"
msgstr ""
-#: mediagoblin/submit/views.py:146
+#: mediagoblin/submit/views.py:144
#, python-format
msgid "Collection \"%s\" added!"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:64
+#: mediagoblin/templates/mediagoblin/base.html:67
msgid "Verify your email!"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:65
+#: mediagoblin/templates/mediagoblin/base.html:68
msgid "log out"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:70
+#: mediagoblin/templates/mediagoblin/base.html:73
#: mediagoblin/templates/mediagoblin/auth/login.html:28
#: mediagoblin/templates/mediagoblin/auth/login.html:36
#: mediagoblin/templates/mediagoblin/auth/login.html:54
msgid "Log in"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:79
+#: mediagoblin/templates/mediagoblin/base.html:82
#, python-format
msgid "<a href=\"%(user_url)s\">%(user_name)s</a>'s account"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:86
+#: mediagoblin/templates/mediagoblin/base.html:89
msgid "Change account settings"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:90
-#: mediagoblin/templates/mediagoblin/base.html:105
+#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:108
#: mediagoblin/templates/mediagoblin/admin/panel.html:21
#: mediagoblin/templates/mediagoblin/admin/panel.html:26
#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:21
@@ -417,72 +445,25 @@ msgstr ""
msgid "Media processing panel"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:96
msgid "Log out"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:96
+#: mediagoblin/templates/mediagoblin/base.html:99
#: mediagoblin/templates/mediagoblin/user_pages/user.html:156
msgid "Add media"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:99
+#: mediagoblin/templates/mediagoblin/base.html:102
#: mediagoblin/templates/mediagoblin/user_pages/collection_list.html:41
msgid "Create new collection"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:122
-#, python-format
-msgid ""
-"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
-"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/base.html:125
-#, python-format
-msgid ""
-"Released under the <a "
-"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
-"href=\"%(source_link)s\">Source code</a> available."
-msgstr ""
-
#: mediagoblin/templates/mediagoblin/error.html:24
msgid "Image of goblin stressing out"
msgstr ""
-#: mediagoblin/templates/mediagoblin/root.html:31
-msgid "Explore"
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:33
-msgid "Hi there, welcome to this MediaGoblin site!"
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:35
-msgid ""
-"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
-"extraordinarily great piece of media hosting software."
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:36
-msgid ""
-"To add your own media, place comments, and more, you can log in with your "
-"MediaGoblin account."
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:38
-msgid "Don't have one yet? It's easy!"
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:39
-#, python-format
-msgid ""
-"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
-" or\n"
-" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:47
+#: mediagoblin/templates/mediagoblin/root.html:32
msgid "Most recent media"
msgstr ""
@@ -588,6 +569,53 @@ msgid ""
"%(verification_url)s"
msgstr ""
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:21
+#, python-format
+msgid ""
+"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
+"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:24
+#, python-format
+msgid ""
+"Released under the <a "
+"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
+"href=\"%(source_link)s\">Source code</a> available."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:20
+msgid "Explore"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:22
+msgid "Hi there, welcome to this MediaGoblin site!"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:24
+msgid ""
+"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
+"extraordinarily great piece of media hosting software."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:25
+msgid ""
+"To add your own media, place comments, and more, you can log in with your "
+"MediaGoblin account."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:27
+msgid "Don't have one yet? It's easy!"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:28
+#, python-format
+msgid ""
+"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
+" or\n"
+" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/bits/logo.html:23
#: mediagoblin/themes/airy/templates/mediagoblin/bits/logo.html:23
msgid "MediaGoblin logo"
@@ -600,13 +628,13 @@ msgid "Editing attachments for %(media_title)s"
msgstr ""
#: mediagoblin/templates/mediagoblin/edit/attachments.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:159
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:175
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:182
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:198
msgid "Attachments"
msgstr ""
#: mediagoblin/templates/mediagoblin/edit/attachments.html:57
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:181
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:204
msgid "Add attachment"
msgstr ""
@@ -623,12 +651,22 @@ msgstr ""
#: mediagoblin/templates/mediagoblin/edit/attachments.html:63
#: mediagoblin/templates/mediagoblin/edit/edit.html:42
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:52
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:55
#: mediagoblin/templates/mediagoblin/edit/edit_collection.html:33
#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:40
msgid "Save changes"
msgstr ""
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:28
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:38
+#, python-format
+msgid "Changing %(username)s's password"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:45
+msgid "Save"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:28
#, python-format
msgid "Really delete user '%(user_name)s' and all related media/comments?"
@@ -639,7 +677,7 @@ msgid "Yes, really delete my account"
msgstr ""
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:47
+#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:48
#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:49
msgid "Delete permanently"
msgstr ""
@@ -656,7 +694,11 @@ msgstr ""
msgid "Changing %(username)s's account settings"
msgstr ""
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:59
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:46
+msgid "Change your password."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:62
msgid "Delete my account"
msgstr ""
@@ -681,6 +723,7 @@ msgstr ""
#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:56
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:65
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:136
#: mediagoblin/templates/mediagoblin/media_displays/video.html:55
msgid "Download"
@@ -705,6 +748,7 @@ msgid ""
msgstr ""
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:60
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:71
#: mediagoblin/templates/mediagoblin/media_displays/video.html:61
msgid "Original file"
msgstr ""
@@ -713,6 +757,7 @@ msgstr ""
msgid "WebM file (Vorbis codec)"
msgstr ""
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:59
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:87
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:93
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:99
@@ -723,6 +768,10 @@ msgstr ""
msgid "Image for %(media_title)s"
msgstr ""
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:79
+msgid "PDF file"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:112
msgid "Toggle Rotate"
msgstr ""
@@ -821,7 +870,7 @@ msgstr ""
msgid "Really remove %(media_title)s from %(collection_title)s?"
msgstr ""
-#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:53
+#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:54
msgid "Remove"
msgstr ""
@@ -864,23 +913,27 @@ msgstr ""
msgid "â– Browsing media by <a href=\"%(user_url)s\">%(username)s</a>"
msgstr ""
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:94
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:95
msgid "Add a comment"
msgstr ""
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:102
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:104
msgid "Add this comment"
msgstr ""
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:123
-msgid "at"
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:132
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:152
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:164
+#, python-format
+msgid "%(formatted_time)s ago"
msgstr ""
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:144
-#, python-format
-msgid ""
-"<h3>Added on</h3>\n"
-" <p>%(date)s</p>"
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:150
+msgid "Added"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:161
+msgid "Created"
msgstr ""
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:28
@@ -1037,7 +1090,7 @@ msgstr ""
msgid "Tagged with"
msgstr ""
-#: mediagoblin/tools/exif.py:80
+#: mediagoblin/tools/exif.py:83
msgid "Could not read the image file."
msgstr ""
@@ -1067,6 +1120,30 @@ msgid ""
" deleted."
msgstr ""
+#: mediagoblin/tools/timesince.py:62
+msgid "year"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:63
+msgid "month"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:64
+msgid "week"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:65
+msgid "day"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:66
+msgid "hour"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:67
+msgid "minute"
+msgstr ""
+
#: mediagoblin/user_pages/forms.py:23
msgid "Comment"
msgstr ""
@@ -1098,73 +1175,77 @@ msgstr ""
msgid "Include a note"
msgstr ""
-#: mediagoblin/user_pages/lib.py:56
+#: mediagoblin/user_pages/lib.py:58
msgid "commented on your post"
msgstr ""
-#: mediagoblin/user_pages/views.py:166
+#: mediagoblin/user_pages/views.py:169
+msgid "Sorry, comments are disabled."
+msgstr ""
+
+#: mediagoblin/user_pages/views.py:174
msgid "Oops, your comment was empty."
msgstr ""
-#: mediagoblin/user_pages/views.py:172
+#: mediagoblin/user_pages/views.py:180
msgid "Your comment has been posted!"
msgstr ""
-#: mediagoblin/user_pages/views.py:197
+#: mediagoblin/user_pages/views.py:205
msgid "Please check your entries and try again."
msgstr ""
-#: mediagoblin/user_pages/views.py:237
+#: mediagoblin/user_pages/views.py:245
msgid "You have to select or add a collection"
msgstr ""
-#: mediagoblin/user_pages/views.py:248
+#: mediagoblin/user_pages/views.py:256
#, python-format
msgid "\"%s\" already in collection \"%s\""
msgstr ""
-#: mediagoblin/user_pages/views.py:264
+#: mediagoblin/user_pages/views.py:262
#, python-format
msgid "\"%s\" added to collection \"%s\""
msgstr ""
-#: mediagoblin/user_pages/views.py:286
+#: mediagoblin/user_pages/views.py:282
msgid "You deleted the media."
msgstr ""
-#: mediagoblin/user_pages/views.py:293
+#: mediagoblin/user_pages/views.py:289
msgid "The media was not deleted because you didn't check that you were sure."
msgstr ""
-#: mediagoblin/user_pages/views.py:301
+#: mediagoblin/user_pages/views.py:296
msgid "You are about to delete another user's media. Proceed with caution."
msgstr ""
-#: mediagoblin/user_pages/views.py:375
+#: mediagoblin/user_pages/views.py:370
msgid "You deleted the item from the collection."
msgstr ""
-#: mediagoblin/user_pages/views.py:379
+#: mediagoblin/user_pages/views.py:374
msgid "The item was not removed because you didn't check that you were sure."
msgstr ""
-#: mediagoblin/user_pages/views.py:389
+#: mediagoblin/user_pages/views.py:382
msgid ""
"You are about to delete an item from another user's collection. Proceed with"
" caution."
msgstr ""
-#: mediagoblin/user_pages/views.py:422
+#: mediagoblin/user_pages/views.py:415
#, python-format
msgid "You deleted the collection \"%s\""
msgstr ""
-#: mediagoblin/user_pages/views.py:429
+#: mediagoblin/user_pages/views.py:422
msgid ""
"The collection was not deleted because you didn't check that you were sure."
msgstr ""
-#: mediagoblin/user_pages/views.py:439
+#: mediagoblin/user_pages/views.py:430
msgid ""
"You are about to delete another user's collection. Proceed with caution."
msgstr ""
diff --git a/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.mo
index 28ea51f8..3b961e60 100644
--- a/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.mo
+++ b/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.mo
Binary files differ
diff --git a/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po
index 76bda505..659de21b 100644
--- a/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po
+++ b/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po
@@ -3,14 +3,14 @@
# This file is distributed under the same license as the PROJECT project.
#
# Translators:
-# <simon@ingenmansland.se>, 2011.
-# <transifex@wandborg.se>, 2011, 2012.
+# ingenman <simon@ingenmansland.se>, 2011
+# joar <transifex@wandborg.se>, 2011, 2012
msgid ""
msgstr ""
"Project-Id-Version: GNU MediaGoblin\n"
"Report-Msgid-Bugs-To: http://issues.mediagoblin.org/\n"
-"POT-Creation-Date: 2013-03-04 18:04-0600\n"
-"PO-Revision-Date: 2013-03-05 00:04+0000\n"
+"POT-Creation-Date: 2013-05-27 13:54-0500\n"
+"PO-Revision-Date: 2013-05-27 18:54+0000\n"
"Last-Translator: cwebber <cwebber@dustycloud.org>\n"
"Language-Team: Swedish (http://www.transifex.com/projects/p/mediagoblin/language/sv/)\n"
"MIME-Version: 1.0\n"
@@ -20,34 +20,39 @@ msgstr ""
"Language: sv\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: mediagoblin/auth/forms.py:28
-msgid "Invalid User name or email address."
-msgstr ""
-
-#: mediagoblin/auth/forms.py:29
-msgid "This field does not take email addresses."
-msgstr ""
-
-#: mediagoblin/auth/forms.py:30
-msgid "This field requires an email address."
-msgstr ""
-
-#: mediagoblin/auth/forms.py:52 mediagoblin/auth/forms.py:67
+#: mediagoblin/auth/forms.py:26
msgid "Username"
msgstr "Användarnamn"
-#: mediagoblin/auth/forms.py:56 mediagoblin/auth/forms.py:71
+#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:45
+#: mediagoblin/tests/test_util.py:110
msgid "Password"
msgstr "Lösenord"
-#: mediagoblin/auth/forms.py:60
+#: mediagoblin/auth/forms.py:34
msgid "Email address"
msgstr "E-postadress"
-#: mediagoblin/auth/forms.py:78
+#: mediagoblin/auth/forms.py:41
+msgid "Username or Email"
+msgstr ""
+
+#: mediagoblin/auth/forms.py:52
msgid "Username or email"
msgstr ""
+#: mediagoblin/auth/tools.py:31
+msgid "Invalid User name or email address."
+msgstr ""
+
+#: mediagoblin/auth/tools.py:32
+msgid "This field does not take email addresses."
+msgstr ""
+
+#: mediagoblin/auth/tools.py:33
+msgid "This field requires an email address."
+msgstr ""
+
#: mediagoblin/auth/views.py:54
msgid "Sorry, registration is disabled on this instance."
msgstr "Vi beklagar, registreringen är avtängd på den här instansen."
@@ -60,54 +65,54 @@ msgstr "En användare med det användarnamnet finns redan."
msgid "Sorry, a user with that email address already exists."
msgstr "Det finns redan en användare med den e-postadressen."
-#: mediagoblin/auth/views.py:174
+#: mediagoblin/auth/views.py:182
msgid ""
"Your email address has been verified. You may now login, edit your profile, "
"and submit images!"
msgstr "Din e-postadress är verifierad. Du kan nu logga in, redigera din profil och ladda upp filer!"
-#: mediagoblin/auth/views.py:180
+#: mediagoblin/auth/views.py:188
msgid "The verification key or user id is incorrect"
msgstr "Verifieringsnyckeln eller användar-IDt är fel."
-#: mediagoblin/auth/views.py:198
+#: mediagoblin/auth/views.py:206
msgid "You must be logged in so we know who to send the email to!"
msgstr "Du måste vara inloggad för att vi ska kunna skicka meddelandet till dig."
-#: mediagoblin/auth/views.py:206
+#: mediagoblin/auth/views.py:214
msgid "You've already verified your email address!"
msgstr "Du har redan verifierat din e-postadress!"
-#: mediagoblin/auth/views.py:219
+#: mediagoblin/auth/views.py:227
msgid "Resent your verification email."
msgstr "Skickade ett nytt verifierings-email."
-#: mediagoblin/auth/views.py:250
+#: mediagoblin/auth/views.py:258
msgid ""
"If that email address (case sensitive!) is registered an email has been sent"
" with instructions on how to change your password."
msgstr ""
-#: mediagoblin/auth/views.py:261
+#: mediagoblin/auth/views.py:269
msgid "Couldn't find someone with that username."
msgstr ""
-#: mediagoblin/auth/views.py:264
+#: mediagoblin/auth/views.py:272
msgid ""
"An email has been sent with instructions on how to change your password."
msgstr ""
-#: mediagoblin/auth/views.py:271
+#: mediagoblin/auth/views.py:279
msgid ""
"Could not send password recovery email as your username is inactive or your "
"account's email address has not been verified."
msgstr "Kunde inte skicka e-poståterställning av lösenord eftersom ditt användarnamn är inaktivt eller kontots e-postadress har inte verifierats."
-#: mediagoblin/auth/views.py:328
+#: mediagoblin/auth/views.py:336
msgid "You can now log in using your new password."
msgstr ""
-#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:93
+#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:82
#: mediagoblin/submit/forms.py:28 mediagoblin/submit/forms.py:47
#: mediagoblin/user_pages/forms.py:45
msgid "Title"
@@ -118,7 +123,7 @@ msgid "Description of this work"
msgstr "Beskrivning av verket"
#: mediagoblin/edit/forms.py:29 mediagoblin/edit/forms.py:52
-#: mediagoblin/edit/forms.py:97 mediagoblin/submit/forms.py:32
+#: mediagoblin/edit/forms.py:86 mediagoblin/submit/forms.py:32
#: mediagoblin/submit/forms.py:51 mediagoblin/user_pages/forms.py:49
msgid ""
"You can use\n"
@@ -134,11 +139,11 @@ msgstr "Taggar"
msgid "Separate tags by commas."
msgstr ""
-#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:101
+#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:90
msgid "Slug"
msgstr "Sökvägsnamn"
-#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:102
+#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:91
msgid "The slug can't be empty"
msgstr "Sökvägsnamnet kan inte vara tomt"
@@ -166,45 +171,45 @@ msgid "This address contains errors"
msgstr ""
#: mediagoblin/edit/forms.py:63
-msgid "Old password"
-msgstr "Tidigare lösenord"
-
-#: mediagoblin/edit/forms.py:64
-msgid "Enter your old password to prove you own this account."
-msgstr ""
-
-#: mediagoblin/edit/forms.py:67
-msgid "New password"
-msgstr ""
-
-#: mediagoblin/edit/forms.py:74
msgid "License preference"
msgstr ""
-#: mediagoblin/edit/forms.py:80
+#: mediagoblin/edit/forms.py:69
msgid "This will be your default license on upload forms."
msgstr ""
-#: mediagoblin/edit/forms.py:82
+#: mediagoblin/edit/forms.py:71
msgid "Email me when others comment on my media"
msgstr ""
-#: mediagoblin/edit/forms.py:94
+#: mediagoblin/edit/forms.py:83
msgid "The title can't be empty"
msgstr ""
-#: mediagoblin/edit/forms.py:96 mediagoblin/submit/forms.py:50
+#: mediagoblin/edit/forms.py:85 mediagoblin/submit/forms.py:50
#: mediagoblin/user_pages/forms.py:48
msgid "Description of this collection"
msgstr ""
-#: mediagoblin/edit/forms.py:103
+#: mediagoblin/edit/forms.py:92
msgid ""
"The title part of this collection's address. You usually don't need to "
"change this."
msgstr ""
-#: mediagoblin/edit/views.py:66
+#: mediagoblin/edit/forms.py:99
+msgid "Old password"
+msgstr "Tidigare lösenord"
+
+#: mediagoblin/edit/forms.py:101
+msgid "Enter your old password to prove you own this account."
+msgstr ""
+
+#: mediagoblin/edit/forms.py:104
+msgid "New password"
+msgstr ""
+
+#: mediagoblin/edit/views.py:67
msgid "An entry with that slug already exists for this user."
msgstr "Ett inlägg med det sökvägsnamnet existerar redan."
@@ -229,44 +234,63 @@ msgstr "Var försiktig, du redigerar en annan användares profil."
msgid "Profile changes saved"
msgstr ""
-#: mediagoblin/edit/views.py:241
-msgid "Wrong password"
-msgstr "Fel lösenord"
-
-#: mediagoblin/edit/views.py:252
+#: mediagoblin/edit/views.py:240
msgid "Account settings saved"
msgstr ""
-#: mediagoblin/edit/views.py:286
+#: mediagoblin/edit/views.py:274
msgid "You need to confirm the deletion of your account."
msgstr ""
-#: mediagoblin/edit/views.py:322 mediagoblin/submit/views.py:142
-#: mediagoblin/user_pages/views.py:214
+#: mediagoblin/edit/views.py:310 mediagoblin/submit/views.py:138
+#: mediagoblin/user_pages/views.py:222
#, python-format
msgid "You already have a collection called \"%s\"!"
msgstr ""
-#: mediagoblin/edit/views.py:326
+#: mediagoblin/edit/views.py:314
msgid "A collection with that slug already exists for this user."
msgstr ""
-#: mediagoblin/edit/views.py:343
+#: mediagoblin/edit/views.py:329
msgid "You are editing another user's collection. Proceed with caution."
msgstr ""
-#: mediagoblin/gmg_commands/theme.py:58
+#: mediagoblin/edit/views.py:348
+msgid "Wrong password"
+msgstr "Fel lösenord"
+
+#: mediagoblin/edit/views.py:363
+msgid "Your password was changed successfully"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:60
msgid "Cannot link theme... no theme set\n"
msgstr ""
-#: mediagoblin/gmg_commands/theme.py:71
+#: mediagoblin/gmg_commands/assetlink.py:73
msgid "No asset directory for this theme\n"
msgstr ""
-#: mediagoblin/gmg_commands/theme.py:74
+#: mediagoblin/gmg_commands/assetlink.py:76
msgid "However, old link directory symlink found; removed.\n"
msgstr ""
+#: mediagoblin/gmg_commands/assetlink.py:112
+#, python-format
+msgid "Could not link \"%s\": %s exists and is not a symlink\n"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:119
+#, python-format
+msgid "Skipping \"%s\"; already set up.\n"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:124
+#, python-format
+msgid "Old link found for \"%s\"; removing.\n"
+msgstr ""
+
#: mediagoblin/meddleware/csrf.py:134
msgid ""
"CSRF cookie not present. This is most likely the result of a cookie blocker "
@@ -274,12 +298,16 @@ msgid ""
"domain."
msgstr ""
-#: mediagoblin/media_types/__init__.py:61
-#: mediagoblin/media_types/__init__.py:102
+#: mediagoblin/media_types/__init__.py:111
+#: mediagoblin/media_types/__init__.py:155
msgid "Sorry, I don't support that file type :("
msgstr ""
-#: mediagoblin/media_types/video/processing.py:36
+#: mediagoblin/media_types/pdf/processing.py:136
+msgid "unoconv failing to run, check log file"
+msgstr ""
+
+#: mediagoblin/media_types/video/processing.py:37
msgid "Video transcoding failed"
msgstr ""
@@ -346,7 +374,7 @@ msgstr ""
msgid "This field is required for public clients"
msgstr ""
-#: mediagoblin/plugins/oauth/views.py:59
+#: mediagoblin/plugins/oauth/views.py:56
msgid "The client {0} has been registered!"
msgstr ""
@@ -365,7 +393,7 @@ msgstr ""
msgid "Add"
msgstr ""
-#: mediagoblin/processing/__init__.py:172
+#: mediagoblin/processing/__init__.py:193
msgid "Invalid file given for media type."
msgstr "Ogiltig fil för mediatypen."
@@ -373,45 +401,45 @@ msgstr "Ogiltig fil för mediatypen."
msgid "File"
msgstr "Fil"
-#: mediagoblin/submit/views.py:51
+#: mediagoblin/submit/views.py:49
msgid "You must provide a file."
msgstr "Du måste ange en fil"
-#: mediagoblin/submit/views.py:97
+#: mediagoblin/submit/views.py:93
msgid "Woohoo! Submitted!"
msgstr "Tjohoo! Upladdat!"
-#: mediagoblin/submit/views.py:146
+#: mediagoblin/submit/views.py:144
#, python-format
msgid "Collection \"%s\" added!"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:64
+#: mediagoblin/templates/mediagoblin/base.html:67
msgid "Verify your email!"
msgstr "Verifiera din e-postadress"
-#: mediagoblin/templates/mediagoblin/base.html:65
+#: mediagoblin/templates/mediagoblin/base.html:68
msgid "log out"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:70
+#: mediagoblin/templates/mediagoblin/base.html:73
#: mediagoblin/templates/mediagoblin/auth/login.html:28
#: mediagoblin/templates/mediagoblin/auth/login.html:36
#: mediagoblin/templates/mediagoblin/auth/login.html:54
msgid "Log in"
msgstr "Logga in"
-#: mediagoblin/templates/mediagoblin/base.html:79
+#: mediagoblin/templates/mediagoblin/base.html:82
#, python-format
msgid "<a href=\"%(user_url)s\">%(user_name)s</a>'s account"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:86
+#: mediagoblin/templates/mediagoblin/base.html:89
msgid "Change account settings"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:90
-#: mediagoblin/templates/mediagoblin/base.html:105
+#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:108
#: mediagoblin/templates/mediagoblin/admin/panel.html:21
#: mediagoblin/templates/mediagoblin/admin/panel.html:26
#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:21
@@ -419,72 +447,25 @@ msgstr ""
msgid "Media processing panel"
msgstr "Mediabehandlingspanel"
-#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:96
msgid "Log out"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:96
+#: mediagoblin/templates/mediagoblin/base.html:99
#: mediagoblin/templates/mediagoblin/user_pages/user.html:156
msgid "Add media"
msgstr "Lägg till media"
-#: mediagoblin/templates/mediagoblin/base.html:99
+#: mediagoblin/templates/mediagoblin/base.html:102
#: mediagoblin/templates/mediagoblin/user_pages/collection_list.html:41
msgid "Create new collection"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:122
-#, python-format
-msgid ""
-"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
-"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/base.html:125
-#, python-format
-msgid ""
-"Released under the <a "
-"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
-"href=\"%(source_link)s\">Source code</a> available."
-msgstr ""
-
#: mediagoblin/templates/mediagoblin/error.html:24
msgid "Image of goblin stressing out"
msgstr ""
-#: mediagoblin/templates/mediagoblin/root.html:31
-msgid "Explore"
-msgstr "Utforska"
-
-#: mediagoblin/templates/mediagoblin/root.html:33
-msgid "Hi there, welcome to this MediaGoblin site!"
-msgstr "Hej, välkommen till den här MediaGoblin-sidan!"
-
-#: mediagoblin/templates/mediagoblin/root.html:35
-msgid ""
-"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
-"extraordinarily great piece of media hosting software."
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:36
-msgid ""
-"To add your own media, place comments, and more, you can log in with your "
-"MediaGoblin account."
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:38
-msgid "Don't have one yet? It's easy!"
-msgstr "Har du inte ett redan?"
-
-#: mediagoblin/templates/mediagoblin/root.html:39
-#, python-format
-msgid ""
-"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
-" or\n"
-" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:47
+#: mediagoblin/templates/mediagoblin/root.html:32
msgid "Most recent media"
msgstr "Senast medier"
@@ -590,6 +571,53 @@ msgid ""
"%(verification_url)s"
msgstr "Hej %(username)s,\n\nöppna den följande webbadressen i din webbläsare för att aktivera ditt konto på GNU MediaGoblin:\n\n%(verification_url)s"
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:21
+#, python-format
+msgid ""
+"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
+"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:24
+#, python-format
+msgid ""
+"Released under the <a "
+"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
+"href=\"%(source_link)s\">Source code</a> available."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:20
+msgid "Explore"
+msgstr "Utforska"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:22
+msgid "Hi there, welcome to this MediaGoblin site!"
+msgstr "Hej, välkommen till den här MediaGoblin-sidan!"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:24
+msgid ""
+"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
+"extraordinarily great piece of media hosting software."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:25
+msgid ""
+"To add your own media, place comments, and more, you can log in with your "
+"MediaGoblin account."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:27
+msgid "Don't have one yet? It's easy!"
+msgstr "Har du inte ett redan?"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:28
+#, python-format
+msgid ""
+"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
+" or\n"
+" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/bits/logo.html:23
#: mediagoblin/themes/airy/templates/mediagoblin/bits/logo.html:23
msgid "MediaGoblin logo"
@@ -602,13 +630,13 @@ msgid "Editing attachments for %(media_title)s"
msgstr ""
#: mediagoblin/templates/mediagoblin/edit/attachments.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:159
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:175
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:182
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:198
msgid "Attachments"
msgstr ""
#: mediagoblin/templates/mediagoblin/edit/attachments.html:57
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:181
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:204
msgid "Add attachment"
msgstr ""
@@ -625,12 +653,22 @@ msgstr "Avbryt"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:63
#: mediagoblin/templates/mediagoblin/edit/edit.html:42
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:52
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:55
#: mediagoblin/templates/mediagoblin/edit/edit_collection.html:33
#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:40
msgid "Save changes"
msgstr "Spara ändringar"
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:28
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:38
+#, python-format
+msgid "Changing %(username)s's password"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:45
+msgid "Save"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:28
#, python-format
msgid "Really delete user '%(user_name)s' and all related media/comments?"
@@ -641,7 +679,7 @@ msgid "Yes, really delete my account"
msgstr ""
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:47
+#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:48
#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:49
msgid "Delete permanently"
msgstr ""
@@ -658,7 +696,11 @@ msgstr "Redigerar %(media_title)s"
msgid "Changing %(username)s's account settings"
msgstr ""
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:59
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:46
+msgid "Change your password."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:62
msgid "Delete my account"
msgstr ""
@@ -683,6 +725,7 @@ msgstr "Media taggat med: %(tag_name)s"
#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:56
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:65
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:136
#: mediagoblin/templates/mediagoblin/media_displays/video.html:55
msgid "Download"
@@ -707,6 +750,7 @@ msgid ""
msgstr ""
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:60
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:71
#: mediagoblin/templates/mediagoblin/media_displays/video.html:61
msgid "Original file"
msgstr ""
@@ -715,6 +759,7 @@ msgstr ""
msgid "WebM file (Vorbis codec)"
msgstr ""
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:59
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:87
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:93
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:99
@@ -725,6 +770,10 @@ msgstr ""
msgid "Image for %(media_title)s"
msgstr ""
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:79
+msgid "PDF file"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:112
msgid "Toggle Rotate"
msgstr ""
@@ -823,7 +872,7 @@ msgstr "Vill du verkligen radera %(title)s?"
msgid "Really remove %(media_title)s from %(collection_title)s?"
msgstr ""
-#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:53
+#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:54
msgid "Remove"
msgstr ""
@@ -866,23 +915,27 @@ msgstr "<a href=\"%(user_url)s\">%(username)s</a>s media"
msgid "â– Browsing media by <a href=\"%(user_url)s\">%(username)s</a>"
msgstr ""
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:94
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:95
msgid "Add a comment"
msgstr ""
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:102
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:104
msgid "Add this comment"
msgstr ""
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:123
-msgid "at"
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:132
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:152
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:164
+#, python-format
+msgid "%(formatted_time)s ago"
msgstr ""
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:144
-#, python-format
-msgid ""
-"<h3>Added on</h3>\n"
-" <p>%(date)s</p>"
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:150
+msgid "Added"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:161
+msgid "Created"
msgstr ""
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:28
@@ -1039,7 +1092,7 @@ msgstr ""
msgid "Tagged with"
msgstr ""
-#: mediagoblin/tools/exif.py:80
+#: mediagoblin/tools/exif.py:83
msgid "Could not read the image file."
msgstr ""
@@ -1069,6 +1122,30 @@ msgid ""
" deleted."
msgstr ""
+#: mediagoblin/tools/timesince.py:62
+msgid "year"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:63
+msgid "month"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:64
+msgid "week"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:65
+msgid "day"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:66
+msgid "hour"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:67
+msgid "minute"
+msgstr ""
+
#: mediagoblin/user_pages/forms.py:23
msgid "Comment"
msgstr ""
@@ -1100,73 +1177,77 @@ msgstr ""
msgid "Include a note"
msgstr ""
-#: mediagoblin/user_pages/lib.py:56
+#: mediagoblin/user_pages/lib.py:58
msgid "commented on your post"
msgstr ""
-#: mediagoblin/user_pages/views.py:166
+#: mediagoblin/user_pages/views.py:169
+msgid "Sorry, comments are disabled."
+msgstr ""
+
+#: mediagoblin/user_pages/views.py:174
msgid "Oops, your comment was empty."
msgstr ""
-#: mediagoblin/user_pages/views.py:172
+#: mediagoblin/user_pages/views.py:180
msgid "Your comment has been posted!"
msgstr ""
-#: mediagoblin/user_pages/views.py:197
+#: mediagoblin/user_pages/views.py:205
msgid "Please check your entries and try again."
msgstr ""
-#: mediagoblin/user_pages/views.py:237
+#: mediagoblin/user_pages/views.py:245
msgid "You have to select or add a collection"
msgstr ""
-#: mediagoblin/user_pages/views.py:248
+#: mediagoblin/user_pages/views.py:256
#, python-format
msgid "\"%s\" already in collection \"%s\""
msgstr ""
-#: mediagoblin/user_pages/views.py:264
+#: mediagoblin/user_pages/views.py:262
#, python-format
msgid "\"%s\" added to collection \"%s\""
msgstr ""
-#: mediagoblin/user_pages/views.py:286
+#: mediagoblin/user_pages/views.py:282
msgid "You deleted the media."
msgstr ""
-#: mediagoblin/user_pages/views.py:293
+#: mediagoblin/user_pages/views.py:289
msgid "The media was not deleted because you didn't check that you were sure."
msgstr ""
-#: mediagoblin/user_pages/views.py:301
+#: mediagoblin/user_pages/views.py:296
msgid "You are about to delete another user's media. Proceed with caution."
msgstr "Du tänker radera en annan användares media. Var försiktig."
-#: mediagoblin/user_pages/views.py:375
+#: mediagoblin/user_pages/views.py:370
msgid "You deleted the item from the collection."
msgstr ""
-#: mediagoblin/user_pages/views.py:379
+#: mediagoblin/user_pages/views.py:374
msgid "The item was not removed because you didn't check that you were sure."
msgstr ""
-#: mediagoblin/user_pages/views.py:389
+#: mediagoblin/user_pages/views.py:382
msgid ""
"You are about to delete an item from another user's collection. Proceed with"
" caution."
msgstr ""
-#: mediagoblin/user_pages/views.py:422
+#: mediagoblin/user_pages/views.py:415
#, python-format
msgid "You deleted the collection \"%s\""
msgstr ""
-#: mediagoblin/user_pages/views.py:429
+#: mediagoblin/user_pages/views.py:422
msgid ""
"The collection was not deleted because you didn't check that you were sure."
msgstr ""
-#: mediagoblin/user_pages/views.py:439
+#: mediagoblin/user_pages/views.py:430
msgid ""
"You are about to delete another user's collection. Proceed with caution."
msgstr ""
diff --git a/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.mo
index 8cef4593..6e7ebd21 100644
--- a/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.mo
+++ b/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.mo
Binary files differ
diff --git a/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.po
index 3586ee78..b0bf1aa1 100644
--- a/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.po
+++ b/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.po
@@ -3,15 +3,15 @@
# This file is distributed under the same license as the PROJECT project.
#
# Translators:
-# వీవెనౠ<veeven@gmail.com>, 2011.
+# వీవెనౠ<veeven@gmail.com>, 2011
msgid ""
msgstr ""
"Project-Id-Version: GNU MediaGoblin\n"
"Report-Msgid-Bugs-To: http://issues.mediagoblin.org/\n"
-"POT-Creation-Date: 2013-03-04 18:04-0600\n"
-"PO-Revision-Date: 2013-03-05 00:04+0000\n"
+"POT-Creation-Date: 2013-05-27 13:54-0500\n"
+"PO-Revision-Date: 2013-05-27 18:54+0000\n"
"Last-Translator: cwebber <cwebber@dustycloud.org>\n"
-"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language-Team: Telugu (http://www.transifex.com/projects/p/mediagoblin/language/te/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
@@ -19,34 +19,39 @@ msgstr ""
"Language: te\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: mediagoblin/auth/forms.py:28
-msgid "Invalid User name or email address."
-msgstr ""
-
-#: mediagoblin/auth/forms.py:29
-msgid "This field does not take email addresses."
-msgstr ""
-
-#: mediagoblin/auth/forms.py:30
-msgid "This field requires an email address."
-msgstr ""
-
-#: mediagoblin/auth/forms.py:52 mediagoblin/auth/forms.py:67
+#: mediagoblin/auth/forms.py:26
msgid "Username"
msgstr "వాడà±à°•à°°à°¿ పేరà±"
-#: mediagoblin/auth/forms.py:56 mediagoblin/auth/forms.py:71
+#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:45
+#: mediagoblin/tests/test_util.py:110
msgid "Password"
msgstr "సంకేతపదం"
-#: mediagoblin/auth/forms.py:60
+#: mediagoblin/auth/forms.py:34
msgid "Email address"
msgstr "ఈమెయిలౠచిరà±à°¨à°¾à°®à°¾"
-#: mediagoblin/auth/forms.py:78
+#: mediagoblin/auth/forms.py:41
+msgid "Username or Email"
+msgstr ""
+
+#: mediagoblin/auth/forms.py:52
msgid "Username or email"
msgstr ""
+#: mediagoblin/auth/tools.py:31
+msgid "Invalid User name or email address."
+msgstr ""
+
+#: mediagoblin/auth/tools.py:32
+msgid "This field does not take email addresses."
+msgstr ""
+
+#: mediagoblin/auth/tools.py:33
+msgid "This field requires an email address."
+msgstr ""
+
#: mediagoblin/auth/views.py:54
msgid "Sorry, registration is disabled on this instance."
msgstr ""
@@ -59,54 +64,54 @@ msgstr ""
msgid "Sorry, a user with that email address already exists."
msgstr ""
-#: mediagoblin/auth/views.py:174
+#: mediagoblin/auth/views.py:182
msgid ""
"Your email address has been verified. You may now login, edit your profile, "
"and submit images!"
msgstr ""
-#: mediagoblin/auth/views.py:180
+#: mediagoblin/auth/views.py:188
msgid "The verification key or user id is incorrect"
msgstr ""
-#: mediagoblin/auth/views.py:198
+#: mediagoblin/auth/views.py:206
msgid "You must be logged in so we know who to send the email to!"
msgstr ""
-#: mediagoblin/auth/views.py:206
+#: mediagoblin/auth/views.py:214
msgid "You've already verified your email address!"
msgstr ""
-#: mediagoblin/auth/views.py:219
+#: mediagoblin/auth/views.py:227
msgid "Resent your verification email."
msgstr ""
-#: mediagoblin/auth/views.py:250
+#: mediagoblin/auth/views.py:258
msgid ""
"If that email address (case sensitive!) is registered an email has been sent"
" with instructions on how to change your password."
msgstr ""
-#: mediagoblin/auth/views.py:261
+#: mediagoblin/auth/views.py:269
msgid "Couldn't find someone with that username."
msgstr ""
-#: mediagoblin/auth/views.py:264
+#: mediagoblin/auth/views.py:272
msgid ""
"An email has been sent with instructions on how to change your password."
msgstr ""
-#: mediagoblin/auth/views.py:271
+#: mediagoblin/auth/views.py:279
msgid ""
"Could not send password recovery email as your username is inactive or your "
"account's email address has not been verified."
msgstr ""
-#: mediagoblin/auth/views.py:328
+#: mediagoblin/auth/views.py:336
msgid "You can now log in using your new password."
msgstr ""
-#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:93
+#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:82
#: mediagoblin/submit/forms.py:28 mediagoblin/submit/forms.py:47
#: mediagoblin/user_pages/forms.py:45
msgid "Title"
@@ -117,7 +122,7 @@ msgid "Description of this work"
msgstr ""
#: mediagoblin/edit/forms.py:29 mediagoblin/edit/forms.py:52
-#: mediagoblin/edit/forms.py:97 mediagoblin/submit/forms.py:32
+#: mediagoblin/edit/forms.py:86 mediagoblin/submit/forms.py:32
#: mediagoblin/submit/forms.py:51 mediagoblin/user_pages/forms.py:49
msgid ""
"You can use\n"
@@ -133,11 +138,11 @@ msgstr ""
msgid "Separate tags by commas."
msgstr ""
-#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:101
+#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:90
msgid "Slug"
msgstr ""
-#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:102
+#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:91
msgid "The slug can't be empty"
msgstr ""
@@ -165,45 +170,45 @@ msgid "This address contains errors"
msgstr ""
#: mediagoblin/edit/forms.py:63
-msgid "Old password"
-msgstr ""
-
-#: mediagoblin/edit/forms.py:64
-msgid "Enter your old password to prove you own this account."
-msgstr ""
-
-#: mediagoblin/edit/forms.py:67
-msgid "New password"
-msgstr ""
-
-#: mediagoblin/edit/forms.py:74
msgid "License preference"
msgstr ""
-#: mediagoblin/edit/forms.py:80
+#: mediagoblin/edit/forms.py:69
msgid "This will be your default license on upload forms."
msgstr ""
-#: mediagoblin/edit/forms.py:82
+#: mediagoblin/edit/forms.py:71
msgid "Email me when others comment on my media"
msgstr ""
-#: mediagoblin/edit/forms.py:94
+#: mediagoblin/edit/forms.py:83
msgid "The title can't be empty"
msgstr ""
-#: mediagoblin/edit/forms.py:96 mediagoblin/submit/forms.py:50
+#: mediagoblin/edit/forms.py:85 mediagoblin/submit/forms.py:50
#: mediagoblin/user_pages/forms.py:48
msgid "Description of this collection"
msgstr ""
-#: mediagoblin/edit/forms.py:103
+#: mediagoblin/edit/forms.py:92
msgid ""
"The title part of this collection's address. You usually don't need to "
"change this."
msgstr ""
-#: mediagoblin/edit/views.py:66
+#: mediagoblin/edit/forms.py:99
+msgid "Old password"
+msgstr ""
+
+#: mediagoblin/edit/forms.py:101
+msgid "Enter your old password to prove you own this account."
+msgstr ""
+
+#: mediagoblin/edit/forms.py:104
+msgid "New password"
+msgstr ""
+
+#: mediagoblin/edit/views.py:67
msgid "An entry with that slug already exists for this user."
msgstr ""
@@ -228,44 +233,63 @@ msgstr ""
msgid "Profile changes saved"
msgstr ""
-#: mediagoblin/edit/views.py:241
-msgid "Wrong password"
-msgstr ""
-
-#: mediagoblin/edit/views.py:252
+#: mediagoblin/edit/views.py:240
msgid "Account settings saved"
msgstr ""
-#: mediagoblin/edit/views.py:286
+#: mediagoblin/edit/views.py:274
msgid "You need to confirm the deletion of your account."
msgstr ""
-#: mediagoblin/edit/views.py:322 mediagoblin/submit/views.py:142
-#: mediagoblin/user_pages/views.py:214
+#: mediagoblin/edit/views.py:310 mediagoblin/submit/views.py:138
+#: mediagoblin/user_pages/views.py:222
#, python-format
msgid "You already have a collection called \"%s\"!"
msgstr ""
-#: mediagoblin/edit/views.py:326
+#: mediagoblin/edit/views.py:314
msgid "A collection with that slug already exists for this user."
msgstr ""
-#: mediagoblin/edit/views.py:343
+#: mediagoblin/edit/views.py:329
msgid "You are editing another user's collection. Proceed with caution."
msgstr ""
-#: mediagoblin/gmg_commands/theme.py:58
+#: mediagoblin/edit/views.py:348
+msgid "Wrong password"
+msgstr ""
+
+#: mediagoblin/edit/views.py:363
+msgid "Your password was changed successfully"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:60
msgid "Cannot link theme... no theme set\n"
msgstr ""
-#: mediagoblin/gmg_commands/theme.py:71
+#: mediagoblin/gmg_commands/assetlink.py:73
msgid "No asset directory for this theme\n"
msgstr ""
-#: mediagoblin/gmg_commands/theme.py:74
+#: mediagoblin/gmg_commands/assetlink.py:76
msgid "However, old link directory symlink found; removed.\n"
msgstr ""
+#: mediagoblin/gmg_commands/assetlink.py:112
+#, python-format
+msgid "Could not link \"%s\": %s exists and is not a symlink\n"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:119
+#, python-format
+msgid "Skipping \"%s\"; already set up.\n"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:124
+#, python-format
+msgid "Old link found for \"%s\"; removing.\n"
+msgstr ""
+
#: mediagoblin/meddleware/csrf.py:134
msgid ""
"CSRF cookie not present. This is most likely the result of a cookie blocker "
@@ -273,12 +297,16 @@ msgid ""
"domain."
msgstr ""
-#: mediagoblin/media_types/__init__.py:61
-#: mediagoblin/media_types/__init__.py:102
+#: mediagoblin/media_types/__init__.py:111
+#: mediagoblin/media_types/__init__.py:155
msgid "Sorry, I don't support that file type :("
msgstr ""
-#: mediagoblin/media_types/video/processing.py:36
+#: mediagoblin/media_types/pdf/processing.py:136
+msgid "unoconv failing to run, check log file"
+msgstr ""
+
+#: mediagoblin/media_types/video/processing.py:37
msgid "Video transcoding failed"
msgstr ""
@@ -345,7 +373,7 @@ msgstr ""
msgid "This field is required for public clients"
msgstr ""
-#: mediagoblin/plugins/oauth/views.py:59
+#: mediagoblin/plugins/oauth/views.py:56
msgid "The client {0} has been registered!"
msgstr ""
@@ -364,7 +392,7 @@ msgstr ""
msgid "Add"
msgstr ""
-#: mediagoblin/processing/__init__.py:172
+#: mediagoblin/processing/__init__.py:193
msgid "Invalid file given for media type."
msgstr ""
@@ -372,45 +400,45 @@ msgstr ""
msgid "File"
msgstr ""
-#: mediagoblin/submit/views.py:51
+#: mediagoblin/submit/views.py:49
msgid "You must provide a file."
msgstr ""
-#: mediagoblin/submit/views.py:97
+#: mediagoblin/submit/views.py:93
msgid "Woohoo! Submitted!"
msgstr ""
-#: mediagoblin/submit/views.py:146
+#: mediagoblin/submit/views.py:144
#, python-format
msgid "Collection \"%s\" added!"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:64
+#: mediagoblin/templates/mediagoblin/base.html:67
msgid "Verify your email!"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:65
+#: mediagoblin/templates/mediagoblin/base.html:68
msgid "log out"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:70
+#: mediagoblin/templates/mediagoblin/base.html:73
#: mediagoblin/templates/mediagoblin/auth/login.html:28
#: mediagoblin/templates/mediagoblin/auth/login.html:36
#: mediagoblin/templates/mediagoblin/auth/login.html:54
msgid "Log in"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:79
+#: mediagoblin/templates/mediagoblin/base.html:82
#, python-format
msgid "<a href=\"%(user_url)s\">%(user_name)s</a>'s account"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:86
+#: mediagoblin/templates/mediagoblin/base.html:89
msgid "Change account settings"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:90
-#: mediagoblin/templates/mediagoblin/base.html:105
+#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:108
#: mediagoblin/templates/mediagoblin/admin/panel.html:21
#: mediagoblin/templates/mediagoblin/admin/panel.html:26
#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:21
@@ -418,72 +446,25 @@ msgstr ""
msgid "Media processing panel"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:96
msgid "Log out"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:96
+#: mediagoblin/templates/mediagoblin/base.html:99
#: mediagoblin/templates/mediagoblin/user_pages/user.html:156
msgid "Add media"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:99
+#: mediagoblin/templates/mediagoblin/base.html:102
#: mediagoblin/templates/mediagoblin/user_pages/collection_list.html:41
msgid "Create new collection"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:122
-#, python-format
-msgid ""
-"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
-"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/base.html:125
-#, python-format
-msgid ""
-"Released under the <a "
-"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
-"href=\"%(source_link)s\">Source code</a> available."
-msgstr ""
-
#: mediagoblin/templates/mediagoblin/error.html:24
msgid "Image of goblin stressing out"
msgstr ""
-#: mediagoblin/templates/mediagoblin/root.html:31
-msgid "Explore"
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:33
-msgid "Hi there, welcome to this MediaGoblin site!"
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:35
-msgid ""
-"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
-"extraordinarily great piece of media hosting software."
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:36
-msgid ""
-"To add your own media, place comments, and more, you can log in with your "
-"MediaGoblin account."
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:38
-msgid "Don't have one yet? It's easy!"
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:39
-#, python-format
-msgid ""
-"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
-" or\n"
-" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:47
+#: mediagoblin/templates/mediagoblin/root.html:32
msgid "Most recent media"
msgstr ""
@@ -589,6 +570,53 @@ msgid ""
"%(verification_url)s"
msgstr ""
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:21
+#, python-format
+msgid ""
+"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
+"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:24
+#, python-format
+msgid ""
+"Released under the <a "
+"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
+"href=\"%(source_link)s\">Source code</a> available."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:20
+msgid "Explore"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:22
+msgid "Hi there, welcome to this MediaGoblin site!"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:24
+msgid ""
+"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
+"extraordinarily great piece of media hosting software."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:25
+msgid ""
+"To add your own media, place comments, and more, you can log in with your "
+"MediaGoblin account."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:27
+msgid "Don't have one yet? It's easy!"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:28
+#, python-format
+msgid ""
+"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
+" or\n"
+" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/bits/logo.html:23
#: mediagoblin/themes/airy/templates/mediagoblin/bits/logo.html:23
msgid "MediaGoblin logo"
@@ -601,13 +629,13 @@ msgid "Editing attachments for %(media_title)s"
msgstr ""
#: mediagoblin/templates/mediagoblin/edit/attachments.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:159
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:175
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:182
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:198
msgid "Attachments"
msgstr ""
#: mediagoblin/templates/mediagoblin/edit/attachments.html:57
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:181
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:204
msgid "Add attachment"
msgstr ""
@@ -624,12 +652,22 @@ msgstr "à°°à°¦à±à°¦à±à°šà±‡à°¯à°¿"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:63
#: mediagoblin/templates/mediagoblin/edit/edit.html:42
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:52
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:55
#: mediagoblin/templates/mediagoblin/edit/edit_collection.html:33
#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:40
msgid "Save changes"
msgstr "మారà±à°ªà±à°²à°¨à± à°­à°¦à±à°°à°ªà°°à°šà±"
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:28
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:38
+#, python-format
+msgid "Changing %(username)s's password"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:45
+msgid "Save"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:28
#, python-format
msgid "Really delete user '%(user_name)s' and all related media/comments?"
@@ -640,7 +678,7 @@ msgid "Yes, really delete my account"
msgstr ""
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:47
+#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:48
#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:49
msgid "Delete permanently"
msgstr ""
@@ -657,7 +695,11 @@ msgstr ""
msgid "Changing %(username)s's account settings"
msgstr ""
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:59
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:46
+msgid "Change your password."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:62
msgid "Delete my account"
msgstr ""
@@ -682,6 +724,7 @@ msgstr ""
#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:56
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:65
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:136
#: mediagoblin/templates/mediagoblin/media_displays/video.html:55
msgid "Download"
@@ -706,6 +749,7 @@ msgid ""
msgstr ""
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:60
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:71
#: mediagoblin/templates/mediagoblin/media_displays/video.html:61
msgid "Original file"
msgstr ""
@@ -714,6 +758,7 @@ msgstr ""
msgid "WebM file (Vorbis codec)"
msgstr ""
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:59
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:87
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:93
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:99
@@ -724,6 +769,10 @@ msgstr ""
msgid "Image for %(media_title)s"
msgstr ""
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:79
+msgid "PDF file"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:112
msgid "Toggle Rotate"
msgstr ""
@@ -822,7 +871,7 @@ msgstr ""
msgid "Really remove %(media_title)s from %(collection_title)s?"
msgstr ""
-#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:53
+#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:54
msgid "Remove"
msgstr ""
@@ -865,23 +914,27 @@ msgstr ""
msgid "â– Browsing media by <a href=\"%(user_url)s\">%(username)s</a>"
msgstr ""
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:94
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:95
msgid "Add a comment"
msgstr ""
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:102
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:104
msgid "Add this comment"
msgstr ""
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:123
-msgid "at"
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:132
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:152
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:164
+#, python-format
+msgid "%(formatted_time)s ago"
msgstr ""
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:144
-#, python-format
-msgid ""
-"<h3>Added on</h3>\n"
-" <p>%(date)s</p>"
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:150
+msgid "Added"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:161
+msgid "Created"
msgstr ""
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:28
@@ -1038,7 +1091,7 @@ msgstr ""
msgid "Tagged with"
msgstr ""
-#: mediagoblin/tools/exif.py:80
+#: mediagoblin/tools/exif.py:83
msgid "Could not read the image file."
msgstr ""
@@ -1068,6 +1121,30 @@ msgid ""
" deleted."
msgstr ""
+#: mediagoblin/tools/timesince.py:62
+msgid "year"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:63
+msgid "month"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:64
+msgid "week"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:65
+msgid "day"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:66
+msgid "hour"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:67
+msgid "minute"
+msgstr ""
+
#: mediagoblin/user_pages/forms.py:23
msgid "Comment"
msgstr ""
@@ -1099,73 +1176,77 @@ msgstr ""
msgid "Include a note"
msgstr ""
-#: mediagoblin/user_pages/lib.py:56
+#: mediagoblin/user_pages/lib.py:58
msgid "commented on your post"
msgstr ""
-#: mediagoblin/user_pages/views.py:166
+#: mediagoblin/user_pages/views.py:169
+msgid "Sorry, comments are disabled."
+msgstr ""
+
+#: mediagoblin/user_pages/views.py:174
msgid "Oops, your comment was empty."
msgstr ""
-#: mediagoblin/user_pages/views.py:172
+#: mediagoblin/user_pages/views.py:180
msgid "Your comment has been posted!"
msgstr ""
-#: mediagoblin/user_pages/views.py:197
+#: mediagoblin/user_pages/views.py:205
msgid "Please check your entries and try again."
msgstr ""
-#: mediagoblin/user_pages/views.py:237
+#: mediagoblin/user_pages/views.py:245
msgid "You have to select or add a collection"
msgstr ""
-#: mediagoblin/user_pages/views.py:248
+#: mediagoblin/user_pages/views.py:256
#, python-format
msgid "\"%s\" already in collection \"%s\""
msgstr ""
-#: mediagoblin/user_pages/views.py:264
+#: mediagoblin/user_pages/views.py:262
#, python-format
msgid "\"%s\" added to collection \"%s\""
msgstr ""
-#: mediagoblin/user_pages/views.py:286
+#: mediagoblin/user_pages/views.py:282
msgid "You deleted the media."
msgstr ""
-#: mediagoblin/user_pages/views.py:293
+#: mediagoblin/user_pages/views.py:289
msgid "The media was not deleted because you didn't check that you were sure."
msgstr ""
-#: mediagoblin/user_pages/views.py:301
+#: mediagoblin/user_pages/views.py:296
msgid "You are about to delete another user's media. Proceed with caution."
msgstr ""
-#: mediagoblin/user_pages/views.py:375
+#: mediagoblin/user_pages/views.py:370
msgid "You deleted the item from the collection."
msgstr ""
-#: mediagoblin/user_pages/views.py:379
+#: mediagoblin/user_pages/views.py:374
msgid "The item was not removed because you didn't check that you were sure."
msgstr ""
-#: mediagoblin/user_pages/views.py:389
+#: mediagoblin/user_pages/views.py:382
msgid ""
"You are about to delete an item from another user's collection. Proceed with"
" caution."
msgstr ""
-#: mediagoblin/user_pages/views.py:422
+#: mediagoblin/user_pages/views.py:415
#, python-format
msgid "You deleted the collection \"%s\""
msgstr ""
-#: mediagoblin/user_pages/views.py:429
+#: mediagoblin/user_pages/views.py:422
msgid ""
"The collection was not deleted because you didn't check that you were sure."
msgstr ""
-#: mediagoblin/user_pages/views.py:439
+#: mediagoblin/user_pages/views.py:430
msgid ""
"You are about to delete another user's collection. Proceed with caution."
msgstr ""
diff --git a/mediagoblin/i18n/tr_TR/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/tr_TR/LC_MESSAGES/mediagoblin.mo
new file mode 100644
index 00000000..4341870b
--- /dev/null
+++ b/mediagoblin/i18n/tr_TR/LC_MESSAGES/mediagoblin.mo
Binary files differ
diff --git a/mediagoblin/i18n/tr_TR/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/tr_TR/LC_MESSAGES/mediagoblin.po
new file mode 100644
index 00000000..4155520f
--- /dev/null
+++ b/mediagoblin/i18n/tr_TR/LC_MESSAGES/mediagoblin.po
@@ -0,0 +1,1252 @@
+# Translations template for PROJECT.
+# Copyright (C) 2013 ORGANIZATION
+# This file is distributed under the same license as the PROJECT project.
+#
+# Translators:
+# Caner BAÅžARAN <basaran.caner@gmail.com>, 2013
+msgid ""
+msgstr ""
+"Project-Id-Version: GNU MediaGoblin\n"
+"Report-Msgid-Bugs-To: http://issues.mediagoblin.org/\n"
+"POT-Creation-Date: 2013-05-27 13:54-0500\n"
+"PO-Revision-Date: 2013-06-06 15:44+0000\n"
+"Last-Translator: Caner BAÅžARAN <basaran.caner@gmail.com>\n"
+"Language-Team: Turkish (Turkey) (http://www.transifex.com/projects/p/mediagoblin/language/tr_TR/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: Babel 0.9.6\n"
+"Language: tr_TR\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+
+#: mediagoblin/auth/forms.py:26
+msgid "Username"
+msgstr "Kullanıcı adı"
+
+#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:45
+#: mediagoblin/tests/test_util.py:110
+msgid "Password"
+msgstr "Parola"
+
+#: mediagoblin/auth/forms.py:34
+msgid "Email address"
+msgstr "E-posta adresi"
+
+#: mediagoblin/auth/forms.py:41
+msgid "Username or Email"
+msgstr "Kullanıcı adı veya E-posta"
+
+#: mediagoblin/auth/forms.py:52
+msgid "Username or email"
+msgstr "Kullanıcı adı ya da e-posta"
+
+#: mediagoblin/auth/tools.py:31
+msgid "Invalid User name or email address."
+msgstr ""
+
+#: mediagoblin/auth/tools.py:32
+msgid "This field does not take email addresses."
+msgstr ""
+
+#: mediagoblin/auth/tools.py:33
+msgid "This field requires an email address."
+msgstr ""
+
+#: mediagoblin/auth/views.py:54
+msgid "Sorry, registration is disabled on this instance."
+msgstr "Üzgünüz, bu durumda kayıt devre dışıdır."
+
+#: mediagoblin/auth/views.py:68
+msgid "Sorry, a user with that name already exists."
+msgstr "Maalesef, bu isimde bir kullanıcı mevcut."
+
+#: mediagoblin/auth/views.py:72
+msgid "Sorry, a user with that email address already exists."
+msgstr "Üzgünüz, bu e-posta adresine sahip bir kullanıcı zaten var."
+
+#: mediagoblin/auth/views.py:182
+msgid ""
+"Your email address has been verified. You may now login, edit your profile, "
+"and submit images!"
+msgstr "E-posta adresiniz doğrulandı. Şimdi giriş yapabilir, profilinizi düzenleyip ve yeni görüntüleri gönderebilirsiniz!"
+
+#: mediagoblin/auth/views.py:188
+msgid "The verification key or user id is incorrect"
+msgstr "Doğrulama anahtarı veya kullanıcı kimliği yanlış"
+
+#: mediagoblin/auth/views.py:206
+msgid "You must be logged in so we know who to send the email to!"
+msgstr ""
+
+#: mediagoblin/auth/views.py:214
+msgid "You've already verified your email address!"
+msgstr "Zaten e-posta adresinizi doğruladınız!"
+
+#: mediagoblin/auth/views.py:227
+msgid "Resent your verification email."
+msgstr "Doğrulama e-postasını tekrar yolla."
+
+#: mediagoblin/auth/views.py:258
+msgid ""
+"If that email address (case sensitive!) is registered an email has been sent"
+" with instructions on how to change your password."
+msgstr ""
+
+#: mediagoblin/auth/views.py:269
+msgid "Couldn't find someone with that username."
+msgstr ""
+
+#: mediagoblin/auth/views.py:272
+msgid ""
+"An email has been sent with instructions on how to change your password."
+msgstr "Parolanızı nasıl değiştireceğinizle ilgili adımları anlatan bir e-posta gönderildi."
+
+#: mediagoblin/auth/views.py:279
+msgid ""
+"Could not send password recovery email as your username is inactive or your "
+"account's email address has not been verified."
+msgstr ""
+
+#: mediagoblin/auth/views.py:336
+msgid "You can now log in using your new password."
+msgstr "Şimdi yeni parolanızı giriş için kullanabilirsiniz."
+
+#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:82
+#: mediagoblin/submit/forms.py:28 mediagoblin/submit/forms.py:47
+#: mediagoblin/user_pages/forms.py:45
+msgid "Title"
+msgstr "Başlık"
+
+#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31
+msgid "Description of this work"
+msgstr ""
+
+#: mediagoblin/edit/forms.py:29 mediagoblin/edit/forms.py:52
+#: mediagoblin/edit/forms.py:86 mediagoblin/submit/forms.py:32
+#: mediagoblin/submit/forms.py:51 mediagoblin/user_pages/forms.py:49
+msgid ""
+"You can use\n"
+" <a href=\"http://daringfireball.net/projects/markdown/basics\">\n"
+" Markdown</a> for formatting."
+msgstr ""
+
+#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:36
+msgid "Tags"
+msgstr "Etiketler"
+
+#: mediagoblin/edit/forms.py:35 mediagoblin/submit/forms.py:38
+msgid "Separate tags by commas."
+msgstr "Etikerleri virgül ile ayırın."
+
+#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:90
+msgid "Slug"
+msgstr ""
+
+#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:91
+msgid "The slug can't be empty"
+msgstr ""
+
+#: mediagoblin/edit/forms.py:40
+msgid ""
+"The title part of this media's address. You usually don't need to change "
+"this."
+msgstr ""
+
+#: mediagoblin/edit/forms.py:44 mediagoblin/submit/forms.py:41
+#: mediagoblin/templates/mediagoblin/utils/license.html:20
+msgid "License"
+msgstr ""
+
+#: mediagoblin/edit/forms.py:50
+msgid "Bio"
+msgstr ""
+
+#: mediagoblin/edit/forms.py:56
+msgid "Website"
+msgstr "Web sitesi"
+
+#: mediagoblin/edit/forms.py:58
+msgid "This address contains errors"
+msgstr ""
+
+#: mediagoblin/edit/forms.py:63
+msgid "License preference"
+msgstr ""
+
+#: mediagoblin/edit/forms.py:69
+msgid "This will be your default license on upload forms."
+msgstr ""
+
+#: mediagoblin/edit/forms.py:71
+msgid "Email me when others comment on my media"
+msgstr "Medyama birisi yorum yazdığında bana e-posta at"
+
+#: mediagoblin/edit/forms.py:83
+msgid "The title can't be empty"
+msgstr ""
+
+#: mediagoblin/edit/forms.py:85 mediagoblin/submit/forms.py:50
+#: mediagoblin/user_pages/forms.py:48
+msgid "Description of this collection"
+msgstr ""
+
+#: mediagoblin/edit/forms.py:92
+msgid ""
+"The title part of this collection's address. You usually don't need to "
+"change this."
+msgstr ""
+
+#: mediagoblin/edit/forms.py:99
+msgid "Old password"
+msgstr "Eski parola"
+
+#: mediagoblin/edit/forms.py:101
+msgid "Enter your old password to prove you own this account."
+msgstr ""
+
+#: mediagoblin/edit/forms.py:104
+msgid "New password"
+msgstr "Yeni parola"
+
+#: mediagoblin/edit/views.py:67
+msgid "An entry with that slug already exists for this user."
+msgstr ""
+
+#: mediagoblin/edit/views.py:85
+msgid "You are editing another user's media. Proceed with caution."
+msgstr "Başka bir kullanıcının medyasını düzenlerken dikkatli davranın."
+
+#: mediagoblin/edit/views.py:155
+#, python-format
+msgid "You added the attachment %s!"
+msgstr ""
+
+#: mediagoblin/edit/views.py:182
+msgid "You can only edit your own profile."
+msgstr ""
+
+#: mediagoblin/edit/views.py:188
+msgid "You are editing a user's profile. Proceed with caution."
+msgstr "Başka bir kullanıcının profilini düzenlerken dikkatli davranın."
+
+#: mediagoblin/edit/views.py:204
+msgid "Profile changes saved"
+msgstr "Profil deÄŸiÅŸiklikleri kaydedildi"
+
+#: mediagoblin/edit/views.py:240
+msgid "Account settings saved"
+msgstr "Hesap ayarları kaydedildi"
+
+#: mediagoblin/edit/views.py:274
+msgid "You need to confirm the deletion of your account."
+msgstr ""
+
+#: mediagoblin/edit/views.py:310 mediagoblin/submit/views.py:138
+#: mediagoblin/user_pages/views.py:222
+#, python-format
+msgid "You already have a collection called \"%s\"!"
+msgstr ""
+
+#: mediagoblin/edit/views.py:314
+msgid "A collection with that slug already exists for this user."
+msgstr ""
+
+#: mediagoblin/edit/views.py:329
+msgid "You are editing another user's collection. Proceed with caution."
+msgstr ""
+
+#: mediagoblin/edit/views.py:348
+msgid "Wrong password"
+msgstr "Yanlış parola"
+
+#: mediagoblin/edit/views.py:363
+msgid "Your password was changed successfully"
+msgstr "Parolanız başarılı bir şekilde değiştirildi"
+
+#: mediagoblin/gmg_commands/assetlink.py:60
+msgid "Cannot link theme... no theme set\n"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:73
+msgid "No asset directory for this theme\n"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:76
+msgid "However, old link directory symlink found; removed.\n"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:112
+#, python-format
+msgid "Could not link \"%s\": %s exists and is not a symlink\n"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:119
+#, python-format
+msgid "Skipping \"%s\"; already set up.\n"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:124
+#, python-format
+msgid "Old link found for \"%s\"; removing.\n"
+msgstr ""
+
+#: mediagoblin/meddleware/csrf.py:134
+msgid ""
+"CSRF cookie not present. This is most likely the result of a cookie blocker "
+"or somesuch.<br/>Make sure to permit the settings of cookies for this "
+"domain."
+msgstr ""
+
+#: mediagoblin/media_types/__init__.py:111
+#: mediagoblin/media_types/__init__.py:155
+msgid "Sorry, I don't support that file type :("
+msgstr "Üzgünüz, bu tip dosyaları desteklemiyoruz :("
+
+#: mediagoblin/media_types/pdf/processing.py:136
+msgid "unoconv failing to run, check log file"
+msgstr ""
+
+#: mediagoblin/media_types/video/processing.py:37
+msgid "Video transcoding failed"
+msgstr ""
+
+#: mediagoblin/plugins/geolocation/templates/mediagoblin/plugins/geolocation/map.html:24
+msgid "Location"
+msgstr ""
+
+#: mediagoblin/plugins/geolocation/templates/mediagoblin/plugins/geolocation/map.html:52
+#, python-format
+msgid "View on <a href=\"%(osm_url)s\">OpenStreetMap</a>"
+msgstr ""
+
+#: mediagoblin/plugins/oauth/forms.py:29
+msgid "Allow"
+msgstr ""
+
+#: mediagoblin/plugins/oauth/forms.py:30
+msgid "Deny"
+msgstr ""
+
+#: mediagoblin/plugins/oauth/forms.py:34
+msgid "Name"
+msgstr ""
+
+#: mediagoblin/plugins/oauth/forms.py:35
+msgid "The name of the OAuth client"
+msgstr ""
+
+#: mediagoblin/plugins/oauth/forms.py:36
+msgid "Description"
+msgstr ""
+
+#: mediagoblin/plugins/oauth/forms.py:38
+msgid ""
+"This will be visible to users allowing your\n"
+" application to authenticate as them."
+msgstr ""
+
+#: mediagoblin/plugins/oauth/forms.py:40
+msgid "Type"
+msgstr "Tür"
+
+#: mediagoblin/plugins/oauth/forms.py:45
+msgid ""
+"<strong>Confidential</strong> - The client can\n"
+" make requests to the GNU MediaGoblin instance that can not be\n"
+" intercepted by the user agent (e.g. server-side client).<br />\n"
+" <strong>Public</strong> - The client can't make confidential\n"
+" requests to the GNU MediaGoblin instance (e.g. client-side\n"
+" JavaScript client)."
+msgstr ""
+
+#: mediagoblin/plugins/oauth/forms.py:52
+msgid "Redirect URI"
+msgstr ""
+
+#: mediagoblin/plugins/oauth/forms.py:54
+msgid ""
+"The redirect URI for the applications, this field\n"
+" is <strong>required</strong> for public clients."
+msgstr ""
+
+#: mediagoblin/plugins/oauth/forms.py:66
+msgid "This field is required for public clients"
+msgstr ""
+
+#: mediagoblin/plugins/oauth/views.py:56
+msgid "The client {0} has been registered!"
+msgstr ""
+
+#: mediagoblin/plugins/oauth/templates/oauth/client/connections.html:22
+msgid "OAuth client connections"
+msgstr ""
+
+#: mediagoblin/plugins/oauth/templates/oauth/client/list.html:22
+msgid "Your OAuth clients"
+msgstr ""
+
+#: mediagoblin/plugins/oauth/templates/oauth/client/register.html:29
+#: mediagoblin/templates/mediagoblin/submit/collection.html:30
+#: mediagoblin/templates/mediagoblin/submit/start.html:34
+#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:68
+msgid "Add"
+msgstr "Ekle"
+
+#: mediagoblin/processing/__init__.py:193
+msgid "Invalid file given for media type."
+msgstr "Bu medya türü için geçersiz dosya türü."
+
+#: mediagoblin/submit/forms.py:26
+msgid "File"
+msgstr "Dosya"
+
+#: mediagoblin/submit/views.py:49
+msgid "You must provide a file."
+msgstr "Bir dosya sağlamanız gerekir."
+
+#: mediagoblin/submit/views.py:93
+msgid "Woohoo! Submitted!"
+msgstr "Hoooop! Gönderildi!"
+
+#: mediagoblin/submit/views.py:144
+#, python-format
+msgid "Collection \"%s\" added!"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/base.html:67
+msgid "Verify your email!"
+msgstr "E-postanızı doğrulayın!"
+
+#: mediagoblin/templates/mediagoblin/base.html:68
+msgid "log out"
+msgstr "çıkış"
+
+#: mediagoblin/templates/mediagoblin/base.html:73
+#: mediagoblin/templates/mediagoblin/auth/login.html:28
+#: mediagoblin/templates/mediagoblin/auth/login.html:36
+#: mediagoblin/templates/mediagoblin/auth/login.html:54
+msgid "Log in"
+msgstr "GiriÅŸ"
+
+#: mediagoblin/templates/mediagoblin/base.html:82
+#, python-format
+msgid "<a href=\"%(user_url)s\">%(user_name)s</a>'s account"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/base.html:89
+msgid "Change account settings"
+msgstr "Hesap ayarlarını değiştir"
+
+#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:108
+#: mediagoblin/templates/mediagoblin/admin/panel.html:21
+#: mediagoblin/templates/mediagoblin/admin/panel.html:26
+#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:21
+#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:26
+msgid "Media processing panel"
+msgstr "Madya iÅŸlem paneli"
+
+#: mediagoblin/templates/mediagoblin/base.html:96
+msgid "Log out"
+msgstr "Çıkış"
+
+#: mediagoblin/templates/mediagoblin/base.html:99
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:156
+msgid "Add media"
+msgstr "Medya ekle"
+
+#: mediagoblin/templates/mediagoblin/base.html:102
+#: mediagoblin/templates/mediagoblin/user_pages/collection_list.html:41
+msgid "Create new collection"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/error.html:24
+msgid "Image of goblin stressing out"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/root.html:32
+msgid "Most recent media"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/admin/panel.html:29
+msgid ""
+"Here you can track the state of media being processed on this instance."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/admin/panel.html:32
+#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:32
+msgid "Media in-processing"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/admin/panel.html:58
+#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:56
+msgid "No media in-processing"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/admin/panel.html:61
+#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:59
+msgid "These uploads failed to process:"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/admin/panel.html:90
+#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:86
+msgid "No failed entries!"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/admin/panel.html:92
+msgid "Last 10 successful uploads"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/admin/panel.html:112
+#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:107
+msgid "No processed entries, yet!"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/auth/change_fp.html:28
+#: mediagoblin/templates/mediagoblin/auth/change_fp.html:36
+msgid "Set your new password"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/auth/change_fp.html:39
+msgid "Set password"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:23
+#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:31
+msgid "Recover password"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:34
+msgid "Send instructions"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19
+#, python-format
+msgid ""
+"Hi %(username)s,\n"
+"\n"
+"to change your GNU MediaGoblin password, open the following URL in \n"
+"your web browser:\n"
+"\n"
+"%(verification_url)s\n"
+"\n"
+"If you think this is an error, just ignore this email and continue being\n"
+"a happy goblin!"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/auth/login.html:39
+msgid "Logging in failed!"
+msgstr "Giriş başarısız!"
+
+#: mediagoblin/templates/mediagoblin/auth/login.html:44
+msgid "Don't have an account yet?"
+msgstr "Hala hesabınız yok mu?"
+
+#: mediagoblin/templates/mediagoblin/auth/login.html:45
+msgid "Create one here!"
+msgstr "Åžimdi oluÅŸturun!"
+
+#: mediagoblin/templates/mediagoblin/auth/login.html:51
+msgid "Forgot your password?"
+msgstr "Parolanı mı unuttun?"
+
+#: mediagoblin/templates/mediagoblin/auth/register.html:28
+#: mediagoblin/templates/mediagoblin/auth/register.html:36
+msgid "Create an account!"
+msgstr "Hesap oluÅŸtur!"
+
+#: mediagoblin/templates/mediagoblin/auth/register.html:40
+msgid "Create"
+msgstr "OluÅŸtur"
+
+#: mediagoblin/templates/mediagoblin/auth/verification_email.txt:19
+#, python-format
+msgid ""
+"Hi %(username)s,\n"
+"\n"
+"to activate your GNU MediaGoblin account, open the following URL in\n"
+"your web browser:\n"
+"\n"
+"%(verification_url)s"
+msgstr "Merhaba %(username)s,\n\nGNU MediaGoblin hesabınızı etkinleştirmek için, lütfen aşağıdaki\nURL(bağlantı)'yı Web tarayıcınızda açın:\n\n%(verification_url)s"
+
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:21
+#, python-format
+msgid ""
+"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
+"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:24
+#, python-format
+msgid ""
+"Released under the <a "
+"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
+"href=\"%(source_link)s\">Source code</a> available."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:20
+msgid "Explore"
+msgstr "KeÅŸfet"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:22
+msgid "Hi there, welcome to this MediaGoblin site!"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:24
+msgid ""
+"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
+"extraordinarily great piece of media hosting software."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:25
+msgid ""
+"To add your own media, place comments, and more, you can log in with your "
+"MediaGoblin account."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:27
+msgid "Don't have one yet? It's easy!"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:28
+#, python-format
+msgid ""
+"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
+" or\n"
+" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/logo.html:23
+#: mediagoblin/themes/airy/templates/mediagoblin/bits/logo.html:23
+msgid "MediaGoblin logo"
+msgstr "MediaGoblin logo"
+
+#: mediagoblin/templates/mediagoblin/edit/attachments.html:23
+#: mediagoblin/templates/mediagoblin/edit/attachments.html:35
+#, python-format
+msgid "Editing attachments for %(media_title)s"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/edit/attachments.html:44
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:182
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:198
+msgid "Attachments"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/edit/attachments.html:57
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:204
+msgid "Add attachment"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/edit/attachments.html:61
+#: mediagoblin/templates/mediagoblin/edit/delete_account.html:42
+#: mediagoblin/templates/mediagoblin/edit/edit.html:41
+#: mediagoblin/templates/mediagoblin/edit/edit_collection.html:32
+#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:46
+#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:52
+#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:67
+#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:48
+msgid "Cancel"
+msgstr "İptal"
+
+#: mediagoblin/templates/mediagoblin/edit/attachments.html:63
+#: mediagoblin/templates/mediagoblin/edit/edit.html:42
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:55
+#: mediagoblin/templates/mediagoblin/edit/edit_collection.html:33
+#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:40
+msgid "Save changes"
+msgstr "DeÄŸiÅŸiklikleri kaydet"
+
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:28
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:38
+#, python-format
+msgid "Changing %(username)s's password"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:45
+msgid "Save"
+msgstr "Kaydet"
+
+#: mediagoblin/templates/mediagoblin/edit/delete_account.html:28
+#, python-format
+msgid "Really delete user '%(user_name)s' and all related media/comments?"
+msgstr "Gerçekten '%(user_name)s' kullanıcısını ve ilgili tüm medya/yorumları silmek istiyor musun?"
+
+#: mediagoblin/templates/mediagoblin/edit/delete_account.html:35
+msgid "Yes, really delete my account"
+msgstr "Evet, gerçekten hesabımı silmek istiyorum"
+
+#: mediagoblin/templates/mediagoblin/edit/delete_account.html:44
+#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:48
+#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:49
+msgid "Delete permanently"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/edit/edit.html:23
+#: mediagoblin/templates/mediagoblin/edit/edit.html:35
+#, python-format
+msgid "Editing %(media_title)s"
+msgstr "%(media_title)s düzenleme"
+
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:28
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:40
+#, python-format
+msgid "Changing %(username)s's account settings"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:46
+msgid "Change your password."
+msgstr "Parolanızı değiştirin."
+
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:62
+msgid "Delete my account"
+msgstr "Hesabımı sil"
+
+#: mediagoblin/templates/mediagoblin/edit/edit_collection.html:29
+#, python-format
+msgid "Editing %(collection_title)s"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:23
+#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:34
+#, python-format
+msgid "Editing %(username)s's profile"
+msgstr "%(username)s profilini düzenleme"
+
+#: mediagoblin/templates/mediagoblin/listings/collection.html:30
+#: mediagoblin/templates/mediagoblin/listings/collection.html:35
+#: mediagoblin/templates/mediagoblin/listings/tag.html:30
+#: mediagoblin/templates/mediagoblin/listings/tag.html:35
+#, python-format
+msgid "Media tagged with: %(tag_name)s"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34
+#: mediagoblin/templates/mediagoblin/media_displays/audio.html:56
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:65
+#: mediagoblin/templates/mediagoblin/media_displays/stl.html:136
+#: mediagoblin/templates/mediagoblin/media_displays/video.html:55
+msgid "Download"
+msgstr "İndir"
+
+#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:38
+msgid "Original"
+msgstr "Özgün"
+
+#: mediagoblin/templates/mediagoblin/media_displays/audio.html:44
+msgid ""
+"Sorry, this audio will not work because \n"
+"\tyour web browser does not support HTML5 \n"
+"\taudio."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/media_displays/audio.html:47
+msgid ""
+"You can get a modern web browser that \n"
+"\tcan play the audio at <a href=\"http://getfirefox.com\">\n"
+"\t http://getfirefox.com</a>!"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/media_displays/audio.html:60
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:71
+#: mediagoblin/templates/mediagoblin/media_displays/video.html:61
+msgid "Original file"
+msgstr "Özgün dosya"
+
+#: mediagoblin/templates/mediagoblin/media_displays/audio.html:63
+msgid "WebM file (Vorbis codec)"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:59
+#: mediagoblin/templates/mediagoblin/media_displays/stl.html:87
+#: mediagoblin/templates/mediagoblin/media_displays/stl.html:93
+#: mediagoblin/templates/mediagoblin/media_displays/stl.html:99
+#: mediagoblin/templates/mediagoblin/media_displays/stl.html:105
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:59
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:65
+#, python-format
+msgid "Image for %(media_title)s"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:79
+msgid "PDF file"
+msgstr "PDF dosya"
+
+#: mediagoblin/templates/mediagoblin/media_displays/stl.html:112
+msgid "Toggle Rotate"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/media_displays/stl.html:113
+msgid "Perspective"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/media_displays/stl.html:116
+#: mediagoblin/templates/mediagoblin/media_displays/stl.html:117
+msgid "Front"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/media_displays/stl.html:120
+#: mediagoblin/templates/mediagoblin/media_displays/stl.html:121
+msgid "Top"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/media_displays/stl.html:124
+#: mediagoblin/templates/mediagoblin/media_displays/stl.html:125
+msgid "Side"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/media_displays/stl.html:130
+#: mediagoblin/templates/mediagoblin/media_displays/stl.html:131
+msgid "WebGL"
+msgstr "WebGL"
+
+#: mediagoblin/templates/mediagoblin/media_displays/stl.html:138
+msgid "Download model"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/media_displays/stl.html:146
+msgid "File Format"
+msgstr "Dosya Biçimi"
+
+#: mediagoblin/templates/mediagoblin/media_displays/stl.html:148
+msgid "Object Height"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/media_displays/video.html:44
+msgid ""
+"Sorry, this video will not work because\n"
+" your web browser does not support HTML5 \n"
+" video."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/media_displays/video.html:47
+msgid ""
+"You can get a modern web browser that \n"
+" can play this video at <a href=\"http://getfirefox.com\">\n"
+" http://getfirefox.com</a>!"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/media_displays/video.html:69
+msgid "WebM file (640p; VP8/Vorbis)"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/submit/collection.html:26
+msgid "Add a collection"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/submit/start.html:23
+#: mediagoblin/templates/mediagoblin/submit/start.html:30
+msgid "Add your media"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/collection.html:30
+#, python-format
+msgid "%(collection_title)s (%(username)s's collection)"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/collection.html:39
+#, python-format
+msgid "%(collection_title)s by <a href=\"%(user_url)s\">%(username)s</a>"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/collection.html:52
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:79
+msgid "Edit"
+msgstr "Düzenle"
+
+#: mediagoblin/templates/mediagoblin/user_pages/collection.html:56
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:83
+msgid "Delete"
+msgstr "Si"
+
+#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:30
+#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30
+#, python-format
+msgid "Really delete %(title)s?"
+msgstr "Gerçekten %(title)s silmek istiyor musun?"
+
+#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:31
+#, python-format
+msgid "Really remove %(media_title)s from %(collection_title)s?"
+msgstr "Gerçekten %(collection_title)s %(media_title)s kaldırmak istiyor musun?"
+
+#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:54
+msgid "Remove"
+msgstr "Kaldır"
+
+#: mediagoblin/templates/mediagoblin/user_pages/collection_list.html:21
+#, python-format
+msgid "%(username)s's collections"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/collection_list.html:28
+#, python-format
+msgid "<a href=\"%(user_url)s\">%(username)s</a>'s collections"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/comment_email.txt:19
+#, python-format
+msgid ""
+"Hi %(username)s,\n"
+"%(comment_author)s commented on your post (%(comment_url)s) at %(instance_name)s\n"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30
+#, python-format
+msgid "%(username)s's media"
+msgstr "%(username)s medyası"
+
+#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:38
+#, python-format
+msgid ""
+"<a href=\"%(user_url)s\">%(username)s</a>'s media with tag <a "
+"href=\"%(tag_url)s\">%(tag)s</a>"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:48
+#, python-format
+msgid "<a href=\"%(user_url)s\">%(username)s</a>'s media"
+msgstr "<a href=\"%(user_url)s\">%(username)s</a> medyası"
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:38
+#, python-format
+msgid "â– Browsing media by <a href=\"%(user_url)s\">%(username)s</a>"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:95
+msgid "Add a comment"
+msgstr "Bir yorum ekle"
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:104
+msgid "Add this comment"
+msgstr "Bu yorumu ekle"
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:132
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:152
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:164
+#, python-format
+msgid "%(formatted_time)s ago"
+msgstr "%(formatted_time)s önce"
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:150
+msgid "Added"
+msgstr "Eklendi"
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:161
+msgid "Created"
+msgstr "OluÅŸturuldu"
+
+#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:28
+#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:40
+#, python-format
+msgid "Add “%(media_title)s†to a collection"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:54
+msgid "+"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:58
+msgid "Add a new collection"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:29
+msgid ""
+"You can track the state of media being processed for your gallery here."
+msgstr "Burada galerinizdeki işlenmekte olan medyanın durumunu takip edebilirsiniz."
+
+#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:89
+msgid "Your last 10 successful uploads"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:31
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:89
+#, python-format
+msgid "%(username)s's profile"
+msgstr "%(username)s profili"
+
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:43
+msgid "Sorry, no such user found."
+msgstr "Üzgünüz, böyle bir kullanıcı bulunamadı."
+
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:50
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:70
+msgid "Email verification needed"
+msgstr "E-posta doğrulaması gerekli"
+
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:53
+msgid "Almost done! Your account still needs to be activated."
+msgstr "Neredeyse bitti! Hesabınızı etkinleştirmeniz gerekiyor."
+
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:58
+msgid ""
+"An email should arrive in a few moments with instructions on how to do so."
+msgstr "Bunun nasıl yapılacağı ile ilgili talimatlar, birkaç dakika içinde size e-posta ulaşacak."
+
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:62
+msgid "In case it doesn't:"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:65
+msgid "Resend verification email"
+msgstr "Doğrulama e-postası tekrar yolla"
+
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:73
+msgid ""
+"Someone has registered an account with this username, but it still has to be"
+" activated."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:79
+#, python-format
+msgid ""
+"If you are that person but you've lost your verification email, you can <a "
+"href=\"%(login_url)s\">log in</a> and resend it."
+msgstr "Doğrulama e-postasını kaybettiyseniz, <a href=\"%(login_url)s\">giriş</a> yapabilir ve yeniden yollayabilirsiniz."
+
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:96
+msgid "Here's a spot to tell others about yourself."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:100
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:117
+msgid "Edit profile"
+msgstr "Profil düzenle"
+
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:105
+msgid "This user hasn't filled in their profile (yet)."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:124
+msgid "Browse collections"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:137
+#, python-format
+msgid "View all of %(username)s's media"
+msgstr "%(username)s tüm medyasını göster"
+
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:150
+msgid ""
+"This is where your media will appear, but you don't seem to have added "
+"anything yet."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:162
+#: mediagoblin/templates/mediagoblin/utils/collection_gallery.html:84
+#: mediagoblin/templates/mediagoblin/utils/object_gallery.html:70
+msgid "There doesn't seem to be any media here yet..."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/utils/collection_gallery.html:49
+msgid "(remove)"
+msgstr "(kaldır)"
+
+#: mediagoblin/templates/mediagoblin/utils/collections.html:21
+msgid "Collected in"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/utils/collections.html:40
+msgid "Add to a collection"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/utils/feed_link.html:21
+#: mediagoblin/themes/airy/templates/mediagoblin/utils/feed_link.html:21
+msgid "feed icon"
+msgstr "besleme simgesi"
+
+#: mediagoblin/templates/mediagoblin/utils/feed_link.html:23
+#: mediagoblin/themes/airy/templates/mediagoblin/utils/feed_link.html:23
+msgid "Atom feed"
+msgstr "Atom besleme"
+
+#: mediagoblin/templates/mediagoblin/utils/license.html:25
+msgid "All rights reserved"
+msgstr "Tüm hakları saklıdır"
+
+#: mediagoblin/templates/mediagoblin/utils/pagination.html:39
+msgid "↠Newer"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/utils/pagination.html:45
+msgid "Older →"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/utils/pagination.html:48
+msgid "Go to page:"
+msgstr "Sayfaya git:"
+
+#: mediagoblin/templates/mediagoblin/utils/prev_next.html:28
+#: mediagoblin/templates/mediagoblin/utils/prev_next.html:33
+msgid "newer"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/utils/prev_next.html:39
+#: mediagoblin/templates/mediagoblin/utils/prev_next.html:44
+msgid "older"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/utils/tags.html:20
+msgid "Tagged with"
+msgstr ""
+
+#: mediagoblin/tools/exif.py:83
+msgid "Could not read the image file."
+msgstr ""
+
+#: mediagoblin/tools/response.py:35
+msgid "Oops!"
+msgstr "Amaninnn boo!"
+
+#: mediagoblin/tools/response.py:36
+msgid "An error occured"
+msgstr ""
+
+#: mediagoblin/tools/response.py:51
+msgid "Operation not allowed"
+msgstr ""
+
+#: mediagoblin/tools/response.py:52
+msgid ""
+"Sorry Dave, I can't let you do that!</p><p>You have tried to perform a "
+"function that you are not allowed to. Have you been trying to delete all "
+"user accounts again?"
+msgstr ""
+
+#: mediagoblin/tools/response.py:60
+msgid ""
+"There doesn't seem to be a page at this address. Sorry!</p><p>If you're sure"
+" the address is correct, maybe the page you're looking for has been moved or"
+" deleted."
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:62
+msgid "year"
+msgstr "yıl"
+
+#: mediagoblin/tools/timesince.py:63
+msgid "month"
+msgstr "ay"
+
+#: mediagoblin/tools/timesince.py:64
+msgid "week"
+msgstr "hafta"
+
+#: mediagoblin/tools/timesince.py:65
+msgid "day"
+msgstr "gün"
+
+#: mediagoblin/tools/timesince.py:66
+msgid "hour"
+msgstr "saat"
+
+#: mediagoblin/tools/timesince.py:67
+msgid "minute"
+msgstr "dakika"
+
+#: mediagoblin/user_pages/forms.py:23
+msgid "Comment"
+msgstr ""
+
+#: mediagoblin/user_pages/forms.py:25
+msgid ""
+"You can use <a "
+"href=\"http://daringfireball.net/projects/markdown/basics\">Markdown</a> for"
+" formatting."
+msgstr ""
+
+#: mediagoblin/user_pages/forms.py:31
+msgid "I am sure I want to delete this"
+msgstr "Bunu silmek için eminim"
+
+#: mediagoblin/user_pages/forms.py:35
+msgid "I am sure I want to remove this item from the collection"
+msgstr ""
+
+#: mediagoblin/user_pages/forms.py:39
+msgid "Collection"
+msgstr ""
+
+#: mediagoblin/user_pages/forms.py:40
+msgid "-- Select --"
+msgstr ""
+
+#: mediagoblin/user_pages/forms.py:42
+msgid "Include a note"
+msgstr ""
+
+#: mediagoblin/user_pages/lib.py:58
+msgid "commented on your post"
+msgstr ""
+
+#: mediagoblin/user_pages/views.py:169
+msgid "Sorry, comments are disabled."
+msgstr "Maalesef, yorum devre dışı."
+
+#: mediagoblin/user_pages/views.py:174
+msgid "Oops, your comment was empty."
+msgstr "Amaninnn boo, yorumunuz boÅŸtu."
+
+#: mediagoblin/user_pages/views.py:180
+msgid "Your comment has been posted!"
+msgstr "Yorumunuz gönderildi!"
+
+#: mediagoblin/user_pages/views.py:205
+msgid "Please check your entries and try again."
+msgstr ""
+
+#: mediagoblin/user_pages/views.py:245
+msgid "You have to select or add a collection"
+msgstr ""
+
+#: mediagoblin/user_pages/views.py:256
+#, python-format
+msgid "\"%s\" already in collection \"%s\""
+msgstr ""
+
+#: mediagoblin/user_pages/views.py:262
+#, python-format
+msgid "\"%s\" added to collection \"%s\""
+msgstr ""
+
+#: mediagoblin/user_pages/views.py:282
+msgid "You deleted the media."
+msgstr "Medyayı sildiniz."
+
+#: mediagoblin/user_pages/views.py:289
+msgid "The media was not deleted because you didn't check that you were sure."
+msgstr "Medya silinmedi çünkü emin olduğunuzu onaylamadınız."
+
+#: mediagoblin/user_pages/views.py:296
+msgid "You are about to delete another user's media. Proceed with caution."
+msgstr "Başka bir kullanıcının medyasını silerken dikkatli davranın."
+
+#: mediagoblin/user_pages/views.py:370
+msgid "You deleted the item from the collection."
+msgstr ""
+
+#: mediagoblin/user_pages/views.py:374
+msgid "The item was not removed because you didn't check that you were sure."
+msgstr ""
+
+#: mediagoblin/user_pages/views.py:382
+msgid ""
+"You are about to delete an item from another user's collection. Proceed with"
+" caution."
+msgstr ""
+
+#: mediagoblin/user_pages/views.py:415
+#, python-format
+msgid "You deleted the collection \"%s\""
+msgstr ""
+
+#: mediagoblin/user_pages/views.py:422
+msgid ""
+"The collection was not deleted because you didn't check that you were sure."
+msgstr ""
+
+#: mediagoblin/user_pages/views.py:430
+msgid ""
+"You are about to delete another user's collection. Proceed with caution."
+msgstr ""
diff --git a/mediagoblin/i18n/zh_CN/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/zh_CN/LC_MESSAGES/mediagoblin.mo
new file mode 100644
index 00000000..1ed5a4f1
--- /dev/null
+++ b/mediagoblin/i18n/zh_CN/LC_MESSAGES/mediagoblin.mo
Binary files differ
diff --git a/mediagoblin/i18n/zh_CN/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/zh_CN/LC_MESSAGES/mediagoblin.po
new file mode 100644
index 00000000..4bb714fe
--- /dev/null
+++ b/mediagoblin/i18n/zh_CN/LC_MESSAGES/mediagoblin.po
@@ -0,0 +1,1256 @@
+# Translations template for PROJECT.
+# Copyright (C) 2013 ORGANIZATION
+# This file is distributed under the same license as the PROJECT project.
+#
+# Translators:
+# <chc@citi.sinica.edu.tw>, 2011
+# cwebber <cwebber@dustycloud.org>, 2013
+# m13253 <m13253@hotmail.com>, 2013
+# medicalwei <medicalwei@gmail.com>, 2012
+# m13253 <m13253@hotmail.com>, 2013
+msgid ""
+msgstr ""
+"Project-Id-Version: GNU MediaGoblin\n"
+"Report-Msgid-Bugs-To: http://issues.mediagoblin.org/\n"
+"POT-Creation-Date: 2013-05-27 13:54-0500\n"
+"PO-Revision-Date: 2013-06-16 11:06+0000\n"
+"Last-Translator: m13253 <m13253@hotmail.com>\n"
+"Language-Team: Chinese (China) (http://www.transifex.com/projects/p/mediagoblin/language/zh_CN/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: Babel 0.9.6\n"
+"Language: zh_CN\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+
+#: mediagoblin/auth/forms.py:26
+msgid "Username"
+msgstr "用户å"
+
+#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:45
+#: mediagoblin/tests/test_util.py:110
+msgid "Password"
+msgstr "密ç "
+
+#: mediagoblin/auth/forms.py:34
+msgid "Email address"
+msgstr "电å­é‚®ä»¶åœ°å€"
+
+#: mediagoblin/auth/forms.py:41
+msgid "Username or Email"
+msgstr "ç”¨æˆ·åæˆ–电å­é‚®ä»¶"
+
+#: mediagoblin/auth/forms.py:52
+msgid "Username or email"
+msgstr "ç”¨æˆ·åæˆ–电å­é‚®ä»¶"
+
+#: mediagoblin/auth/tools.py:31
+msgid "Invalid User name or email address."
+msgstr "æ— æ•ˆç”¨æˆ·åæˆ–电å­é‚®ä»¶åœ°å€ã€‚"
+
+#: mediagoblin/auth/tools.py:32
+msgid "This field does not take email addresses."
+msgstr "此字段ä¸èƒ½å¡«å†™ç”µå­é‚®ä»¶åœ°å€ã€‚"
+
+#: mediagoblin/auth/tools.py:33
+msgid "This field requires an email address."
+msgstr "此字段需填写电å­é‚®ä»¶åœ°å€ã€‚"
+
+#: mediagoblin/auth/views.py:54
+msgid "Sorry, registration is disabled on this instance."
+msgstr "æŠ±æ­‰ï¼Œæœ¬ç«™å·²æš‚åœæ³¨å†Œã€‚"
+
+#: mediagoblin/auth/views.py:68
+msgid "Sorry, a user with that name already exists."
+msgstr "抱歉,该用户å已存在。"
+
+#: mediagoblin/auth/views.py:72
+msgid "Sorry, a user with that email address already exists."
+msgstr "抱歉,已有用户用该电å­é‚®ä»¶æ³¨å†Œã€‚"
+
+#: mediagoblin/auth/views.py:182
+msgid ""
+"Your email address has been verified. You may now login, edit your profile, "
+"and submit images!"
+msgstr "您的电å­é‚®ä»¶åœ°å€å·²è®¤è¯ã€‚您现在å¯ä»¥ç™»å½•ã€ä¿®æ”¹ä¸ªäººèµ„料并上传图片了ï¼"
+
+#: mediagoblin/auth/views.py:188
+msgid "The verification key or user id is incorrect"
+msgstr "验è¯ç é”™è¯¯æˆ–用户 ID 错误"
+
+#: mediagoblin/auth/views.py:206
+msgid "You must be logged in so we know who to send the email to!"
+msgstr "您必须登录以便让我们知é“将电å­é‚®ä»¶å‘ç»™è°"
+
+#: mediagoblin/auth/views.py:214
+msgid "You've already verified your email address!"
+msgstr "您已ç»è®¤è¯è¿‡ç”µå­é‚®ä»¶åœ°å€äº†ï¼"
+
+#: mediagoblin/auth/views.py:227
+msgid "Resent your verification email."
+msgstr "é‡å‘认è¯é‚®ä»¶ã€‚"
+
+#: mediagoblin/auth/views.py:258
+msgid ""
+"If that email address (case sensitive!) is registered an email has been sent"
+" with instructions on how to change your password."
+msgstr "若该邮件地å€ï¼ˆåŒºåˆ†å¤§å°å†™ï¼‰å·²è¢«æ³¨å†Œï¼Œåˆ™å¯†ç ä¿®æ”¹è¯´æ˜Žå·²é€šè¿‡ç”µå­é‚®ä»¶é€è¾¾ã€‚"
+
+#: mediagoblin/auth/views.py:269
+msgid "Couldn't find someone with that username."
+msgstr "找ä¸åˆ°æœ‰è¯¥ç”¨æˆ·å的人。"
+
+#: mediagoblin/auth/views.py:272
+msgid ""
+"An email has been sent with instructions on how to change your password."
+msgstr "密ç ä¿®æ”¹è¯´æ˜Žå·²é€šè¿‡ç”µå­é‚®ä»¶é€è¾¾ã€‚"
+
+#: mediagoblin/auth/views.py:279
+msgid ""
+"Could not send password recovery email as your username is inactive or your "
+"account's email address has not been verified."
+msgstr "无法å‘é€å¯†ç æ‰¾å›žé‚®ä»¶ï¼Œå› ä¸ºæ‚¨çš„ç”¨æˆ·åæœªæ¿€æ´»æˆ–者您账户的电å­é‚®ä»¶åœ°å€æœªè®¤è¯ã€‚"
+
+#: mediagoblin/auth/views.py:336
+msgid "You can now log in using your new password."
+msgstr "您现在å¯ä»¥ç”¨æ–°çš„å¯†ç æ¥ç™»å½•了ï¼"
+
+#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:82
+#: mediagoblin/submit/forms.py:28 mediagoblin/submit/forms.py:47
+#: mediagoblin/user_pages/forms.py:45
+msgid "Title"
+msgstr "标题"
+
+#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31
+msgid "Description of this work"
+msgstr "该作å“çš„æè¿°"
+
+#: mediagoblin/edit/forms.py:29 mediagoblin/edit/forms.py:52
+#: mediagoblin/edit/forms.py:86 mediagoblin/submit/forms.py:32
+#: mediagoblin/submit/forms.py:51 mediagoblin/user_pages/forms.py:49
+msgid ""
+"You can use\n"
+" <a href=\"http://daringfireball.net/projects/markdown/basics\">\n"
+" Markdown</a> for formatting."
+msgstr "您å¯ä»¥ç”¨ <a href=\"http://wowubuntu.com/markdown/\">Markdown</a> æ¥æŽ’ç‰ˆã€‚"
+
+#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:36
+msgid "Tags"
+msgstr "标签"
+
+#: mediagoblin/edit/forms.py:35 mediagoblin/submit/forms.py:38
+msgid "Separate tags by commas."
+msgstr "用逗å·åˆ†é𔿠‡ç­¾ã€‚"
+
+#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:90
+msgid "Slug"
+msgstr "简称"
+
+#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:91
+msgid "The slug can't be empty"
+msgstr "简称ä¸èƒ½ä¸ºç©º"
+
+#: mediagoblin/edit/forms.py:40
+msgid ""
+"The title part of this media's address. You usually don't need to change "
+"this."
+msgstr "该媒体网å€çš„æ ‡é¢˜éƒ¨ä»½ã€‚通常ä¸éœ€è¦ä¿®æ”¹ã€‚"
+
+#: mediagoblin/edit/forms.py:44 mediagoblin/submit/forms.py:41
+#: mediagoblin/templates/mediagoblin/utils/license.html:20
+msgid "License"
+msgstr "许å¯è¯"
+
+#: mediagoblin/edit/forms.py:50
+msgid "Bio"
+msgstr "个性签å"
+
+#: mediagoblin/edit/forms.py:56
+msgid "Website"
+msgstr "网站"
+
+#: mediagoblin/edit/forms.py:58
+msgid "This address contains errors"
+msgstr "本网å€å‡ºé”™äº†"
+
+#: mediagoblin/edit/forms.py:63
+msgid "License preference"
+msgstr "许å¯è¯å好"
+
+#: mediagoblin/edit/forms.py:69
+msgid "This will be your default license on upload forms."
+msgstr "这将是您上传界é¢çš„默认许å¯è¯ã€‚"
+
+#: mediagoblin/edit/forms.py:71
+msgid "Email me when others comment on my media"
+msgstr "当有人对我的媒体评论时给我电å­é‚®ä»¶"
+
+#: mediagoblin/edit/forms.py:83
+msgid "The title can't be empty"
+msgstr "标题ä¸èƒ½æ˜¯ç©ºçš„"
+
+#: mediagoblin/edit/forms.py:85 mediagoblin/submit/forms.py:50
+#: mediagoblin/user_pages/forms.py:48
+msgid "Description of this collection"
+msgstr "这个åˆé›†çš„æè¿°"
+
+#: mediagoblin/edit/forms.py:92
+msgid ""
+"The title part of this collection's address. You usually don't need to "
+"change this."
+msgstr "æ­¤åˆé›†ç½‘å€çš„æ ‡é¢˜éƒ¨ä»½ï¼Œé€šå¸¸ä¸éœ€è¦ä¿®æ”¹ã€‚"
+
+#: mediagoblin/edit/forms.py:99
+msgid "Old password"
+msgstr "旧的密ç "
+
+#: mediagoblin/edit/forms.py:101
+msgid "Enter your old password to prove you own this account."
+msgstr "è¾“å…¥æ‚¨çš„æ—§å¯†ç æ¥è¯æ˜Žæ‚¨æ‹¥æœ‰è¿™ä¸ªè´¦æˆ·ã€‚"
+
+#: mediagoblin/edit/forms.py:104
+msgid "New password"
+msgstr "新密ç "
+
+#: mediagoblin/edit/views.py:67
+msgid "An entry with that slug already exists for this user."
+msgstr "这个简称已ç»è¢«åˆ«äººç”¨äº†"
+
+#: mediagoblin/edit/views.py:85
+msgid "You are editing another user's media. Proceed with caution."
+msgstr "您正在修改别人的媒体,请å°å¿ƒæ“作。"
+
+#: mediagoblin/edit/views.py:155
+#, python-format
+msgid "You added the attachment %s!"
+msgstr "您加上了附件“%sâ€ï¼"
+
+#: mediagoblin/edit/views.py:182
+msgid "You can only edit your own profile."
+msgstr "您åªèƒ½ä¿®æ”¹è‡ªå·±çš„个人资料"
+
+#: mediagoblin/edit/views.py:188
+msgid "You are editing a user's profile. Proceed with caution."
+msgstr "您正在修改别人的个人资料,请å°å¿ƒæ“作。"
+
+#: mediagoblin/edit/views.py:204
+msgid "Profile changes saved"
+msgstr "个人资料已修改"
+
+#: mediagoblin/edit/views.py:240
+msgid "Account settings saved"
+msgstr "账户设置已ä¿å­˜"
+
+#: mediagoblin/edit/views.py:274
+msgid "You need to confirm the deletion of your account."
+msgstr "您需è¦ç¡®è®¤åˆ é™¤æ‚¨çš„账户。"
+
+#: mediagoblin/edit/views.py:310 mediagoblin/submit/views.py:138
+#: mediagoblin/user_pages/views.py:222
+#, python-format
+msgid "You already have a collection called \"%s\"!"
+msgstr "æ‚¨å·²ç»æœ‰ä¸€ä¸ªç§°åšâ€œ%sâ€çš„åˆé›†äº†ï¼"
+
+#: mediagoblin/edit/views.py:314
+msgid "A collection with that slug already exists for this user."
+msgstr "è¯¥ç”¨æˆ·å·²ç»æœ‰ä½¿ç”¨è¯¥ç®€ç§°çš„åˆé›†äº†ã€‚"
+
+#: mediagoblin/edit/views.py:329
+msgid "You are editing another user's collection. Proceed with caution."
+msgstr "您正在修改别人的åˆé›†ï¼Œè¯·å°å¿ƒæ“作。"
+
+#: mediagoblin/edit/views.py:348
+msgid "Wrong password"
+msgstr "密ç é”™è¯¯"
+
+#: mediagoblin/edit/views.py:363
+msgid "Your password was changed successfully"
+msgstr "您的密ç å·²æˆåŠŸä¿®æ”¹"
+
+#: mediagoblin/gmg_commands/assetlink.py:60
+msgid "Cannot link theme... no theme set\n"
+msgstr "无法链接到主题……未设置主题\n"
+
+#: mediagoblin/gmg_commands/assetlink.py:73
+msgid "No asset directory for this theme\n"
+msgstr "此主题没有素æç›®å½•\n"
+
+#: mediagoblin/gmg_commands/assetlink.py:76
+msgid "However, old link directory symlink found; removed.\n"
+msgstr "ä½†æ˜¯æ—§çš„ç›®å½•é“¾æŽ¥å·²ç»æ‰¾åˆ°å¹¶ç§»é™¤ã€‚\n"
+
+#: mediagoblin/gmg_commands/assetlink.py:112
+#, python-format
+msgid "Could not link \"%s\": %s exists and is not a symlink\n"
+msgstr "无法链接到“%sâ€ï¼šâ€œ%sâ€å·²å­˜åœ¨ä¸”䏿˜¯é“¾æŽ¥\n"
+
+#: mediagoblin/gmg_commands/assetlink.py:119
+#, python-format
+msgid "Skipping \"%s\"; already set up.\n"
+msgstr "跳过“%sâ€ï¼›å·²è®¾ç½®è¿‡äº†ã€‚\n"
+
+#: mediagoblin/gmg_commands/assetlink.py:124
+#, python-format
+msgid "Old link found for \"%s\"; removing.\n"
+msgstr "“%sâ€çš„æ—§é“¾æŽ¥å·²ç»æ‰¾åˆ°å¹¶ç§»é™¤ã€‚\n"
+
+#: mediagoblin/meddleware/csrf.py:134
+msgid ""
+"CSRF cookie not present. This is most likely the result of a cookie blocker "
+"or somesuch.<br/>Make sure to permit the settings of cookies for this "
+"domain."
+msgstr "CSRF cookie ä¸å­˜åœ¨ã€‚很å¯èƒ½æ˜¯ç”±ç±»ä¼¼ cookie å±è”½å™¨é€ æˆçš„。<br />请å…许本域åçš„ cookie 设定。"
+
+#: mediagoblin/media_types/__init__.py:111
+#: mediagoblin/media_types/__init__.py:155
+msgid "Sorry, I don't support that file type :("
+msgstr "æŠ±æ­‰ï¼Œæˆ‘ä¸æ”¯æŒè¿™æ ·çš„æ–‡ä»¶æ ¼å¼ :("
+
+#: mediagoblin/media_types/pdf/processing.py:136
+msgid "unoconv failing to run, check log file"
+msgstr "无法è¿è¡Œ unoconv,请检查日志"
+
+#: mediagoblin/media_types/video/processing.py:37
+msgid "Video transcoding failed"
+msgstr "视频转ç å¤±è´¥"
+
+#: mediagoblin/plugins/geolocation/templates/mediagoblin/plugins/geolocation/map.html:24
+msgid "Location"
+msgstr "ä½ç½®"
+
+#: mediagoblin/plugins/geolocation/templates/mediagoblin/plugins/geolocation/map.html:52
+#, python-format
+msgid "View on <a href=\"%(osm_url)s\">OpenStreetMap</a>"
+msgstr "在 <a href=\"%(osm_url)s\">OpenStreetMap</a> 上观看"
+
+#: mediagoblin/plugins/oauth/forms.py:29
+msgid "Allow"
+msgstr "å…许"
+
+#: mediagoblin/plugins/oauth/forms.py:30
+msgid "Deny"
+msgstr "æ‹’ç»"
+
+#: mediagoblin/plugins/oauth/forms.py:34
+msgid "Name"
+msgstr "åç§°"
+
+#: mediagoblin/plugins/oauth/forms.py:35
+msgid "The name of the OAuth client"
+msgstr "OAuth client çš„åç§°"
+
+#: mediagoblin/plugins/oauth/forms.py:36
+msgid "Description"
+msgstr "æè¿°"
+
+#: mediagoblin/plugins/oauth/forms.py:38
+msgid ""
+"This will be visible to users allowing your\n"
+" application to authenticate as them."
+msgstr "本æè¿°å°†ä¼šè¢«è¿›è¡Œåº”用程åºè®¤è¯çš„用户看到。"
+
+#: mediagoblin/plugins/oauth/forms.py:40
+msgid "Type"
+msgstr "类型"
+
+#: mediagoblin/plugins/oauth/forms.py:45
+msgid ""
+"<strong>Confidential</strong> - The client can\n"
+" make requests to the GNU MediaGoblin instance that can not be\n"
+" intercepted by the user agent (e.g. server-side client).<br />\n"
+" <strong>Public</strong> - The client can't make confidential\n"
+" requests to the GNU MediaGoblin instance (e.g. client-side\n"
+" JavaScript client)."
+msgstr "<strong>秘密</strong> — OAuth client å¯ä»¥å¯¹ GNU MediaGoblin 站点å‘é€ä¸è¢«ç”¨æˆ·ä»£ç†æ‹¦æˆªçš„请求(例如æœåŠ¡ç«¯ä¸Šçš„ client)。\n<strong>公开</strong> — OAuth client 无法对 GNU MediaGoblin 站点å‘é€ç§˜å¯†çš„请求(例如客户端的 JavaScript client)。"
+
+#: mediagoblin/plugins/oauth/forms.py:52
+msgid "Redirect URI"
+msgstr "é‡å®šå‘ URI"
+
+#: mediagoblin/plugins/oauth/forms.py:54
+msgid ""
+"The redirect URI for the applications, this field\n"
+" is <strong>required</strong> for public clients."
+msgstr "此应用程åºçš„é‡å®šå‘ URI,本字段在公开类型的 OAuth client 为<strong>å¿…å¡«</strong>。"
+
+#: mediagoblin/plugins/oauth/forms.py:66
+msgid "This field is required for public clients"
+msgstr "本字段在公开类型的 OAuth client 为必填"
+
+#: mediagoblin/plugins/oauth/views.py:56
+msgid "The client {0} has been registered!"
+msgstr "OAuth client {0} 注册完æˆï¼"
+
+#: mediagoblin/plugins/oauth/templates/oauth/client/connections.html:22
+msgid "OAuth client connections"
+msgstr "OAuth client 连接"
+
+#: mediagoblin/plugins/oauth/templates/oauth/client/list.html:22
+msgid "Your OAuth clients"
+msgstr "您的 OAuth client"
+
+#: mediagoblin/plugins/oauth/templates/oauth/client/register.html:29
+#: mediagoblin/templates/mediagoblin/submit/collection.html:30
+#: mediagoblin/templates/mediagoblin/submit/start.html:34
+#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:68
+msgid "Add"
+msgstr "增加"
+
+#: mediagoblin/processing/__init__.py:193
+msgid "Invalid file given for media type."
+msgstr "æä¾›æ–‡ä»¶çš„媒体类型错误。"
+
+#: mediagoblin/submit/forms.py:26
+msgid "File"
+msgstr "文件"
+
+#: mediagoblin/submit/views.py:49
+msgid "You must provide a file."
+msgstr "您必须æä¾›ä¸€ä¸ªæ–‡ä»¶"
+
+#: mediagoblin/submit/views.py:93
+msgid "Woohoo! Submitted!"
+msgstr "啊哈ï¼å·²æäº¤ï¼"
+
+#: mediagoblin/submit/views.py:144
+#, python-format
+msgid "Collection \"%s\" added!"
+msgstr "åˆé›†â€œ%sâ€å·²æ–°å¢žï¼"
+
+#: mediagoblin/templates/mediagoblin/base.html:67
+msgid "Verify your email!"
+msgstr "确认您的电å­é‚®ä»¶ï¼"
+
+#: mediagoblin/templates/mediagoblin/base.html:68
+msgid "log out"
+msgstr "登出"
+
+#: mediagoblin/templates/mediagoblin/base.html:73
+#: mediagoblin/templates/mediagoblin/auth/login.html:28
+#: mediagoblin/templates/mediagoblin/auth/login.html:36
+#: mediagoblin/templates/mediagoblin/auth/login.html:54
+msgid "Log in"
+msgstr "登录"
+
+#: mediagoblin/templates/mediagoblin/base.html:82
+#, python-format
+msgid "<a href=\"%(user_url)s\">%(user_name)s</a>'s account"
+msgstr "<a href=\"%(user_url)s\">%(user_name)s</a> 的账户"
+
+#: mediagoblin/templates/mediagoblin/base.html:89
+msgid "Change account settings"
+msgstr "更改账户设置"
+
+#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:108
+#: mediagoblin/templates/mediagoblin/admin/panel.html:21
+#: mediagoblin/templates/mediagoblin/admin/panel.html:26
+#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:21
+#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:26
+msgid "Media processing panel"
+msgstr "媒体处ç†é¢æ¿"
+
+#: mediagoblin/templates/mediagoblin/base.html:96
+msgid "Log out"
+msgstr "登出"
+
+#: mediagoblin/templates/mediagoblin/base.html:99
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:156
+msgid "Add media"
+msgstr "新增媒体"
+
+#: mediagoblin/templates/mediagoblin/base.html:102
+#: mediagoblin/templates/mediagoblin/user_pages/collection_list.html:41
+msgid "Create new collection"
+msgstr "新增åˆé›†"
+
+#: mediagoblin/templates/mediagoblin/error.html:24
+msgid "Image of goblin stressing out"
+msgstr "满脸问å·çš„哥布林"
+
+#: mediagoblin/templates/mediagoblin/root.html:32
+msgid "Most recent media"
+msgstr "最新的媒体"
+
+#: mediagoblin/templates/mediagoblin/admin/panel.html:29
+msgid ""
+"Here you can track the state of media being processed on this instance."
+msgstr "此处您å¯ä»¥è¿½è¸ªæœ¬ç«™ç‚¹å¤„ç†åª’体的状æ€ã€‚"
+
+#: mediagoblin/templates/mediagoblin/admin/panel.html:32
+#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:32
+msgid "Media in-processing"
+msgstr "媒体处ç†ä¸­"
+
+#: mediagoblin/templates/mediagoblin/admin/panel.html:58
+#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:56
+msgid "No media in-processing"
+msgstr "没有正在处ç†ä¸­çš„媒体"
+
+#: mediagoblin/templates/mediagoblin/admin/panel.html:61
+#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:59
+msgid "These uploads failed to process:"
+msgstr "无法处ç†è¿™äº›ä¸Šä¼ å†…容:"
+
+#: mediagoblin/templates/mediagoblin/admin/panel.html:90
+#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:86
+msgid "No failed entries!"
+msgstr "没有失败的纪录ï¼"
+
+#: mediagoblin/templates/mediagoblin/admin/panel.html:92
+msgid "Last 10 successful uploads"
+msgstr "最近 10 次æˆåŠŸä¸Šä¼ çš„çºªå½•"
+
+#: mediagoblin/templates/mediagoblin/admin/panel.html:112
+#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:107
+msgid "No processed entries, yet!"
+msgstr "现在还没有处ç†çš„纪录ï¼"
+
+#: mediagoblin/templates/mediagoblin/auth/change_fp.html:28
+#: mediagoblin/templates/mediagoblin/auth/change_fp.html:36
+msgid "Set your new password"
+msgstr "设置您的新密ç "
+
+#: mediagoblin/templates/mediagoblin/auth/change_fp.html:39
+msgid "Set password"
+msgstr "设置新密ç "
+
+#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:23
+#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:31
+msgid "Recover password"
+msgstr "找回密ç "
+
+#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:34
+msgid "Send instructions"
+msgstr "å‘逿‰¾å›žå¯†ç è¯´æ˜Ž"
+
+#: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19
+#, python-format
+msgid ""
+"Hi %(username)s,\n"
+"\n"
+"to change your GNU MediaGoblin password, open the following URL in \n"
+"your web browser:\n"
+"\n"
+"%(verification_url)s\n"
+"\n"
+"If you think this is an error, just ignore this email and continue being\n"
+"a happy goblin!"
+msgstr "%(username)s 您好:\n\nè¦ä¿®æ”¹ GNU MediaGoblin 的密ç ï¼Œè¯·åœ¨æ‚¨çš„æµè§ˆå™¨ä¸­æ‰“å¼€ä¸‹é¢çš„网å€ï¼š\n\n%(verification_url)s\n\n如果您认为这个是个误会,请忽略此å°ä¿¡ä»¶ï¼Œç»§ç»­å½“个快ä¹çš„哥布林ï¼"
+
+#: mediagoblin/templates/mediagoblin/auth/login.html:39
+msgid "Logging in failed!"
+msgstr "登录失败ï¼"
+
+#: mediagoblin/templates/mediagoblin/auth/login.html:44
+msgid "Don't have an account yet?"
+msgstr "还没有账户å—?"
+
+#: mediagoblin/templates/mediagoblin/auth/login.html:45
+msgid "Create one here!"
+msgstr "在这里建立一个å§ï¼"
+
+#: mediagoblin/templates/mediagoblin/auth/login.html:51
+msgid "Forgot your password?"
+msgstr "忘了密ç å—?"
+
+#: mediagoblin/templates/mediagoblin/auth/register.html:28
+#: mediagoblin/templates/mediagoblin/auth/register.html:36
+msgid "Create an account!"
+msgstr "建立一个账户ï¼"
+
+#: mediagoblin/templates/mediagoblin/auth/register.html:40
+msgid "Create"
+msgstr "建立"
+
+#: mediagoblin/templates/mediagoblin/auth/verification_email.txt:19
+#, python-format
+msgid ""
+"Hi %(username)s,\n"
+"\n"
+"to activate your GNU MediaGoblin account, open the following URL in\n"
+"your web browser:\n"
+"\n"
+"%(verification_url)s"
+msgstr "%(username)s 您好:\n\nè¦å¯åЍ GNU MediaGoblin 账户,请在您的æµè§ˆå™¨ä¸­æ‰“开下é¢çš„网å€:\n\n%(verification_url)s"
+
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:21
+#, python-format
+msgid ""
+"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
+"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
+msgstr "Powered by <a href=\"http://mediagoblin.org/\" title='Version %(version)s'>MediaGoblin</a>,一个 <a href=\"http://gnu.org/\">GNU</a> 项目。"
+
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:24
+#, python-format
+msgid ""
+"Released under the <a "
+"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
+"href=\"%(source_link)s\">Source code</a> available."
+msgstr "以 <a href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a> 授æƒå‘布。备有<a href=\"%(source_link)s\">æºä»£ç </a>。"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:20
+msgid "Explore"
+msgstr "探索"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:22
+msgid "Hi there, welcome to this MediaGoblin site!"
+msgstr "å˜¿ï¼æ¬¢è¿Žæ¥åˆ° MediaGoblin ç«™ï¼ "
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:24
+msgid ""
+"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
+"extraordinarily great piece of media hosting software."
+msgstr "本站使用 <a href=\"http://mediagoblin.org\">MediaGoblin</a>——与众ä¸åŒçš„媒体分享网站。"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:25
+msgid ""
+"To add your own media, place comments, and more, you can log in with your "
+"MediaGoblin account."
+msgstr "您å¯ä»¥ç™»å½•您的 MediaGoblin 账户以上传媒体ã€å¼ è´´è¯„论等等。"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:27
+msgid "Don't have one yet? It's easy!"
+msgstr "没有账户å—?开账户很简å•ï¼"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:28
+#, python-format
+msgid ""
+"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
+" or\n"
+" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
+msgstr "<a class=\"button_action_highlight\" href=\"%(register_url)s\">åœ¨æœ¬ç«™åˆ›å»ºå¸æˆ·</a>\n 或者\n <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">在您自己的æœåŠ¡å™¨ä¸Šæ­å»º MediaGoblin</a>"
+
+#: mediagoblin/templates/mediagoblin/bits/logo.html:23
+#: mediagoblin/themes/airy/templates/mediagoblin/bits/logo.html:23
+msgid "MediaGoblin logo"
+msgstr "MediaGoblin 标志"
+
+#: mediagoblin/templates/mediagoblin/edit/attachments.html:23
+#: mediagoblin/templates/mediagoblin/edit/attachments.html:35
+#, python-format
+msgid "Editing attachments for %(media_title)s"
+msgstr "编辑 %(media_title)s 的附件"
+
+#: mediagoblin/templates/mediagoblin/edit/attachments.html:44
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:182
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:198
+msgid "Attachments"
+msgstr "附件"
+
+#: mediagoblin/templates/mediagoblin/edit/attachments.html:57
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:204
+msgid "Add attachment"
+msgstr "新增附件"
+
+#: mediagoblin/templates/mediagoblin/edit/attachments.html:61
+#: mediagoblin/templates/mediagoblin/edit/delete_account.html:42
+#: mediagoblin/templates/mediagoblin/edit/edit.html:41
+#: mediagoblin/templates/mediagoblin/edit/edit_collection.html:32
+#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:46
+#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:52
+#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:67
+#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:48
+msgid "Cancel"
+msgstr "å–æ¶ˆ"
+
+#: mediagoblin/templates/mediagoblin/edit/attachments.html:63
+#: mediagoblin/templates/mediagoblin/edit/edit.html:42
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:55
+#: mediagoblin/templates/mediagoblin/edit/edit_collection.html:33
+#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:40
+msgid "Save changes"
+msgstr "ä¿å­˜æ›´æ”¹"
+
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:28
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:38
+#, python-format
+msgid "Changing %(username)s's password"
+msgstr "修改 %(username)s 的密ç "
+
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:45
+msgid "Save"
+msgstr "ä¿å­˜"
+
+#: mediagoblin/templates/mediagoblin/edit/delete_account.html:28
+#, python-format
+msgid "Really delete user '%(user_name)s' and all related media/comments?"
+msgstr "真的è¦åˆ é™¤ç”¨æˆ· %(user_name)s åŠæ‰€æœ‰ç›¸å…³åª’体和评论å—?"
+
+#: mediagoblin/templates/mediagoblin/edit/delete_account.html:35
+msgid "Yes, really delete my account"
+msgstr "是的,真的删除我的账户"
+
+#: mediagoblin/templates/mediagoblin/edit/delete_account.html:44
+#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:48
+#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:49
+msgid "Delete permanently"
+msgstr "永久删除"
+
+#: mediagoblin/templates/mediagoblin/edit/edit.html:23
+#: mediagoblin/templates/mediagoblin/edit/edit.html:35
+#, python-format
+msgid "Editing %(media_title)s"
+msgstr "编辑 %(media_title)s"
+
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:28
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:40
+#, python-format
+msgid "Changing %(username)s's account settings"
+msgstr "æ­£åœ¨æ”¹å˜ %(username)s 的账户设置"
+
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:46
+msgid "Change your password."
+msgstr "修改您的密ç ã€‚"
+
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:62
+msgid "Delete my account"
+msgstr "åˆ é™¤æˆ‘çš„å¸æˆ·"
+
+#: mediagoblin/templates/mediagoblin/edit/edit_collection.html:29
+#, python-format
+msgid "Editing %(collection_title)s"
+msgstr "编辑 %(collection_title)s"
+
+#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:23
+#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:34
+#, python-format
+msgid "Editing %(username)s's profile"
+msgstr "编辑 %(username)s 的个人资料"
+
+#: mediagoblin/templates/mediagoblin/listings/collection.html:30
+#: mediagoblin/templates/mediagoblin/listings/collection.html:35
+#: mediagoblin/templates/mediagoblin/listings/tag.html:30
+#: mediagoblin/templates/mediagoblin/listings/tag.html:35
+#, python-format
+msgid "Media tagged with: %(tag_name)s"
+msgstr "此媒体被标记为:%(tag_name)s"
+
+#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34
+#: mediagoblin/templates/mediagoblin/media_displays/audio.html:56
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:65
+#: mediagoblin/templates/mediagoblin/media_displays/stl.html:136
+#: mediagoblin/templates/mediagoblin/media_displays/video.html:55
+msgid "Download"
+msgstr "下载"
+
+#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:38
+msgid "Original"
+msgstr "æºæ–‡ä»¶"
+
+#: mediagoblin/templates/mediagoblin/media_displays/audio.html:44
+msgid ""
+"Sorry, this audio will not work because \n"
+"\tyour web browser does not support HTML5 \n"
+"\taudio."
+msgstr "抱歉,此声音无法播放,因为您的æµè§ˆå™¨ä¸æ”¯æŒ HTML5 音频。"
+
+#: mediagoblin/templates/mediagoblin/media_displays/audio.html:47
+msgid ""
+"You can get a modern web browser that \n"
+"\tcan play the audio at <a href=\"http://getfirefox.com\">\n"
+"\t http://getfirefox.com</a>!"
+msgstr "您å¯ä»¥åœ¨ <a href=\"http://getfirefox.com\">http://getfirefox.com</a> å–å¾—å¯ä»¥æ’­æ”¾æ­¤å£°éŸ³çš„æµè§ˆå™¨ï¼"
+
+#: mediagoblin/templates/mediagoblin/media_displays/audio.html:60
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:71
+#: mediagoblin/templates/mediagoblin/media_displays/video.html:61
+msgid "Original file"
+msgstr "æºæ–‡ä»¶"
+
+#: mediagoblin/templates/mediagoblin/media_displays/audio.html:63
+msgid "WebM file (Vorbis codec)"
+msgstr "WebM 文件(Vorbis ç¼–ç ï¼‰"
+
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:59
+#: mediagoblin/templates/mediagoblin/media_displays/stl.html:87
+#: mediagoblin/templates/mediagoblin/media_displays/stl.html:93
+#: mediagoblin/templates/mediagoblin/media_displays/stl.html:99
+#: mediagoblin/templates/mediagoblin/media_displays/stl.html:105
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:59
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:65
+#, python-format
+msgid "Image for %(media_title)s"
+msgstr "%(media_title)s 的照片"
+
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:79
+msgid "PDF file"
+msgstr "PDF 文件"
+
+#: mediagoblin/templates/mediagoblin/media_displays/stl.html:112
+msgid "Toggle Rotate"
+msgstr "åˆ‡æ¢æ—‹è½¬"
+
+#: mediagoblin/templates/mediagoblin/media_displays/stl.html:113
+msgid "Perspective"
+msgstr "é€è§†"
+
+#: mediagoblin/templates/mediagoblin/media_displays/stl.html:116
+#: mediagoblin/templates/mediagoblin/media_displays/stl.html:117
+msgid "Front"
+msgstr "æ­£é¢"
+
+#: mediagoblin/templates/mediagoblin/media_displays/stl.html:120
+#: mediagoblin/templates/mediagoblin/media_displays/stl.html:121
+msgid "Top"
+msgstr "é¡¶é¢"
+
+#: mediagoblin/templates/mediagoblin/media_displays/stl.html:124
+#: mediagoblin/templates/mediagoblin/media_displays/stl.html:125
+msgid "Side"
+msgstr "ä¾§é¢"
+
+#: mediagoblin/templates/mediagoblin/media_displays/stl.html:130
+#: mediagoblin/templates/mediagoblin/media_displays/stl.html:131
+msgid "WebGL"
+msgstr "WebGL"
+
+#: mediagoblin/templates/mediagoblin/media_displays/stl.html:138
+msgid "Download model"
+msgstr "下载模型"
+
+#: mediagoblin/templates/mediagoblin/media_displays/stl.html:146
+msgid "File Format"
+msgstr "文件格å¼"
+
+#: mediagoblin/templates/mediagoblin/media_displays/stl.html:148
+msgid "Object Height"
+msgstr "对象高度"
+
+#: mediagoblin/templates/mediagoblin/media_displays/video.html:44
+msgid ""
+"Sorry, this video will not work because\n"
+" your web browser does not support HTML5 \n"
+" video."
+msgstr "抱歉,此视频无法播放,因为您的æµè§ˆå™¨ä¸æ”¯æŒ HTML5 视频。"
+
+#: mediagoblin/templates/mediagoblin/media_displays/video.html:47
+msgid ""
+"You can get a modern web browser that \n"
+" can play this video at <a href=\"http://getfirefox.com\">\n"
+" http://getfirefox.com</a>!"
+msgstr "您å¯ä»¥åœ¨ <a href=\"http://getfirefox.com\">http://getfirefox.com</a> å–å¾—å¯ä»¥æ’­æ”¾æ­¤è§†é¢‘çš„æµè§ˆå™¨ï¼"
+
+#: mediagoblin/templates/mediagoblin/media_displays/video.html:69
+msgid "WebM file (640p; VP8/Vorbis)"
+msgstr "WebM 文件(640p;VP8/Vorbis)"
+
+#: mediagoblin/templates/mediagoblin/submit/collection.html:26
+msgid "Add a collection"
+msgstr "新增åˆé›†"
+
+#: mediagoblin/templates/mediagoblin/submit/start.html:23
+#: mediagoblin/templates/mediagoblin/submit/start.html:30
+msgid "Add your media"
+msgstr "加入您的媒体"
+
+#: mediagoblin/templates/mediagoblin/user_pages/collection.html:30
+#, python-format
+msgid "%(collection_title)s (%(username)s's collection)"
+msgstr "%(collection_title)s (%(username)s çš„åˆé›†)"
+
+#: mediagoblin/templates/mediagoblin/user_pages/collection.html:39
+#, python-format
+msgid "%(collection_title)s by <a href=\"%(user_url)s\">%(username)s</a>"
+msgstr "%(collection_title)s by <a href=\"%(user_url)s\">%(username)s</a>"
+
+#: mediagoblin/templates/mediagoblin/user_pages/collection.html:52
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:79
+msgid "Edit"
+msgstr "编辑"
+
+#: mediagoblin/templates/mediagoblin/user_pages/collection.html:56
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:83
+msgid "Delete"
+msgstr "删除"
+
+#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:30
+#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30
+#, python-format
+msgid "Really delete %(title)s?"
+msgstr "真的è¦åˆ é™¤ %(title)s å—?"
+
+#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:31
+#, python-format
+msgid "Really remove %(media_title)s from %(collection_title)s?"
+msgstr "确定è¦ä»Ž %(collection_title)s 移除 %(media_title)s å—?"
+
+#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:54
+msgid "Remove"
+msgstr "移除"
+
+#: mediagoblin/templates/mediagoblin/user_pages/collection_list.html:21
+#, python-format
+msgid "%(username)s's collections"
+msgstr "%(username)s çš„åˆé›†"
+
+#: mediagoblin/templates/mediagoblin/user_pages/collection_list.html:28
+#, python-format
+msgid "<a href=\"%(user_url)s\">%(username)s</a>'s collections"
+msgstr "<a href=\"%(user_url)s\">%(username)s</a> çš„åˆé›†"
+
+#: mediagoblin/templates/mediagoblin/user_pages/comment_email.txt:19
+#, python-format
+msgid ""
+"Hi %(username)s,\n"
+"%(comment_author)s commented on your post (%(comment_url)s) at %(instance_name)s\n"
+msgstr "%(username)s 您好:\n%(comment_author)s 在 %(instance_name)s 对您的内容 (%(comment_url)s) 张贴评论\n"
+
+#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30
+#, python-format
+msgid "%(username)s's media"
+msgstr "%(username)s的媒体"
+
+#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:38
+#, python-format
+msgid ""
+"<a href=\"%(user_url)s\">%(username)s</a>'s media with tag <a "
+"href=\"%(tag_url)s\">%(tag)s</a>"
+msgstr "<a href=\"%(user_url)s\">%(username)s</a> 的有 <a href=\"%(tag_url)s\">%(tag)s</a> 标签的媒体"
+
+#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:48
+#, python-format
+msgid "<a href=\"%(user_url)s\">%(username)s</a>'s media"
+msgstr "<a href=\"%(user_url)s\">%(username)s</a> 的媒体"
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:38
+#, python-format
+msgid "â– Browsing media by <a href=\"%(user_url)s\">%(username)s</a>"
+msgstr "â– æµè§ˆ <a href=\"%(user_url)s\">%(username)s</a> 的媒体"
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:95
+msgid "Add a comment"
+msgstr "新增评论"
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:104
+msgid "Add this comment"
+msgstr "增加评论"
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:132
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:152
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:164
+#, python-format
+msgid "%(formatted_time)s ago"
+msgstr "%(formatted_time)så‰"
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:150
+msgid "Added"
+msgstr "已增加"
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:161
+msgid "Created"
+msgstr "已创建"
+
+#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:28
+#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:40
+#, python-format
+msgid "Add “%(media_title)s†to a collection"
+msgstr "把“%(media_title)sâ€åŠ å…¥åˆé›†"
+
+#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:54
+msgid "+"
+msgstr "+"
+
+#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:58
+msgid "Add a new collection"
+msgstr "新增新的åˆé›†"
+
+#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:29
+msgid ""
+"You can track the state of media being processed for your gallery here."
+msgstr "您å¯ä»¥åœ¨è¿™é‡Œè¿½è¸ªæ‚¨çš„艺廊中媒体处ç†çš„状æ€ã€‚"
+
+#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:89
+msgid "Your last 10 successful uploads"
+msgstr "您的最近 10 次æˆåŠŸä¸Šä¼ çš„çºªå½•"
+
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:31
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:89
+#, python-format
+msgid "%(username)s's profile"
+msgstr "%(username)s 的个人资料"
+
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:43
+msgid "Sorry, no such user found."
+msgstr "抱歉,找ä¸åˆ°è¯¥ç”¨æˆ·ã€‚"
+
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:50
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:70
+msgid "Email verification needed"
+msgstr "需è¦è®¤è¯ç”µå­é‚®ä»¶åœ°å€"
+
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:53
+msgid "Almost done! Your account still needs to be activated."
+msgstr "快完æˆäº†ï¼ä½†æ‚¨éœ€è¦æ¿€æ´»æ‚¨çš„账户。"
+
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:58
+msgid ""
+"An email should arrive in a few moments with instructions on how to do so."
+msgstr "账户激活说明将在ç¨åŽé€è¾¾ã€‚"
+
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:62
+msgid "In case it doesn't:"
+msgstr "如果ä»ç„¶æ— æ³•认è¯ï¼Œæ‚¨å¯ä»¥ï¼š"
+
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:65
+msgid "Resend verification email"
+msgstr "é‡å‘认è¯é‚®ä»¶"
+
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:73
+msgid ""
+"Someone has registered an account with this username, but it still has to be"
+" activated."
+msgstr "有人用注册了该账户,但是该账户需è¦è¢«å¯ç”¨ã€‚"
+
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:79
+#, python-format
+msgid ""
+"If you are that person but you've lost your verification email, you can <a "
+"href=\"%(login_url)s\">log in</a> and resend it."
+msgstr "如果您就是本人但是未收到认è¯ä¿¡ï¼Œæ‚¨å¯ä»¥<a href=\"%(login_url)s\">登录</a>ç„¶åŽé‡å‘一次。"
+
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:96
+msgid "Here's a spot to tell others about yourself."
+msgstr "这个地方能让您å‘他人介ç»è‡ªå·±ã€‚"
+
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:100
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:117
+msgid "Edit profile"
+msgstr "编辑个人资料"
+
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:105
+msgid "This user hasn't filled in their profile (yet)."
+msgstr "这个用户(还)没有填写个人资料。"
+
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:124
+msgid "Browse collections"
+msgstr "æµè§ˆåˆé›†"
+
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:137
+#, python-format
+msgid "View all of %(username)s's media"
+msgstr "查看 %(username)s 的全部媒体"
+
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:150
+msgid ""
+"This is where your media will appear, but you don't seem to have added "
+"anything yet."
+msgstr "此处是您的媒体会出现的地方,但是似乎还没有加入任何东西。"
+
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:162
+#: mediagoblin/templates/mediagoblin/utils/collection_gallery.html:84
+#: mediagoblin/templates/mediagoblin/utils/object_gallery.html:70
+msgid "There doesn't seem to be any media here yet..."
+msgstr "那里好åƒè¿˜æ²¡æœ‰ä»»ä½•的媒体……"
+
+#: mediagoblin/templates/mediagoblin/utils/collection_gallery.html:49
+msgid "(remove)"
+msgstr "(移除)"
+
+#: mediagoblin/templates/mediagoblin/utils/collections.html:21
+msgid "Collected in"
+msgstr "åˆé›†äºŽ"
+
+#: mediagoblin/templates/mediagoblin/utils/collections.html:40
+msgid "Add to a collection"
+msgstr "添加到åˆé›†"
+
+#: mediagoblin/templates/mediagoblin/utils/feed_link.html:21
+#: mediagoblin/themes/airy/templates/mediagoblin/utils/feed_link.html:21
+msgid "feed icon"
+msgstr "feed 图标"
+
+#: mediagoblin/templates/mediagoblin/utils/feed_link.html:23
+#: mediagoblin/themes/airy/templates/mediagoblin/utils/feed_link.html:23
+msgid "Atom feed"
+msgstr "Atom feed"
+
+#: mediagoblin/templates/mediagoblin/utils/license.html:25
+msgid "All rights reserved"
+msgstr "ç‰ˆæƒæ‰€æœ‰"
+
+#: mediagoblin/templates/mediagoblin/utils/pagination.html:39
+msgid "↠Newer"
+msgstr "↠更新的"
+
+#: mediagoblin/templates/mediagoblin/utils/pagination.html:45
+msgid "Older →"
+msgstr "更旧的 →"
+
+#: mediagoblin/templates/mediagoblin/utils/pagination.html:48
+msgid "Go to page:"
+msgstr "跳到页数:"
+
+#: mediagoblin/templates/mediagoblin/utils/prev_next.html:28
+#: mediagoblin/templates/mediagoblin/utils/prev_next.html:33
+msgid "newer"
+msgstr "æ›´æ–°çš„"
+
+#: mediagoblin/templates/mediagoblin/utils/prev_next.html:39
+#: mediagoblin/templates/mediagoblin/utils/prev_next.html:44
+msgid "older"
+msgstr "æ›´æ—§çš„"
+
+#: mediagoblin/templates/mediagoblin/utils/tags.html:20
+msgid "Tagged with"
+msgstr "标签"
+
+#: mediagoblin/tools/exif.py:83
+msgid "Could not read the image file."
+msgstr "无法读å–图片文件。"
+
+#: mediagoblin/tools/response.py:35
+msgid "Oops!"
+msgstr "糟糕ï¼"
+
+#: mediagoblin/tools/response.py:36
+msgid "An error occured"
+msgstr "å‘生错误"
+
+#: mediagoblin/tools/response.py:51
+msgid "Operation not allowed"
+msgstr "æ“作ä¸å…许"
+
+#: mediagoblin/tools/response.py:52
+msgid ""
+"Sorry Dave, I can't let you do that!</p><p>You have tried to perform a "
+"function that you are not allowed to. Have you been trying to delete all "
+"user accounts again?"
+msgstr "对ä¸èµ·è€å…„,我ä¸èƒ½è®©ä½ è¿™æ ·åšï¼</p><p>æ‚¨æ­£åœ¨è¯•ç€æ“作ä¸å…è®¸æ‚¨ä½¿ç”¨çš„åŠŸèƒ½ã€‚æ‚¨éš¾é“æƒ³æ‰“算删除所有用户账户å—?"
+
+#: mediagoblin/tools/response.py:60
+msgid ""
+"There doesn't seem to be a page at this address. Sorry!</p><p>If you're sure"
+" the address is correct, maybe the page you're looking for has been moved or"
+" deleted."
+msgstr "ä¸å¥½æ„æ€ï¼Œçœ‹èµ·æ¥è¿™ä¸ªç½‘å€ä¸Šæ²¡æœ‰ç½‘页。</p><p>å¦‚æžœæ‚¨ç¡®å®šè¿™ä¸ªç½‘å€æ˜¯æ­£ç¡®çš„,您在寻找的页é¢å¯èƒ½å·²ç»ç§»åŠ¨æˆ–æ˜¯è¢«åˆ é™¤äº†ã€‚"
+
+#: mediagoblin/tools/timesince.py:62
+msgid "year"
+msgstr "å¹´"
+
+#: mediagoblin/tools/timesince.py:63
+msgid "month"
+msgstr "月"
+
+#: mediagoblin/tools/timesince.py:64
+msgid "week"
+msgstr "周"
+
+#: mediagoblin/tools/timesince.py:65
+msgid "day"
+msgstr "æ—¥"
+
+#: mediagoblin/tools/timesince.py:66
+msgid "hour"
+msgstr "å°æ—¶"
+
+#: mediagoblin/tools/timesince.py:67
+msgid "minute"
+msgstr "分钟"
+
+#: mediagoblin/user_pages/forms.py:23
+msgid "Comment"
+msgstr "评论"
+
+#: mediagoblin/user_pages/forms.py:25
+msgid ""
+"You can use <a "
+"href=\"http://daringfireball.net/projects/markdown/basics\">Markdown</a> for"
+" formatting."
+msgstr "您å¯ä»¥ç”¨ <a href=\"http://wowubuntu.com/markdown/\">Markdown</a> æ¥æŽ’ç‰ˆã€‚"
+
+#: mediagoblin/user_pages/forms.py:31
+msgid "I am sure I want to delete this"
+msgstr "我确定我è¦åˆ é™¤è¿™ä¸ªåª’体"
+
+#: mediagoblin/user_pages/forms.py:35
+msgid "I am sure I want to remove this item from the collection"
+msgstr "我确定我è¦ä»Žåˆé›†ä¸­ç§»é™¤æ­¤é¡¹ç›®"
+
+#: mediagoblin/user_pages/forms.py:39
+msgid "Collection"
+msgstr "åˆé›†"
+
+#: mediagoblin/user_pages/forms.py:40
+msgid "-- Select --"
+msgstr "— 请选择 —"
+
+#: mediagoblin/user_pages/forms.py:42
+msgid "Include a note"
+msgstr "加注"
+
+#: mediagoblin/user_pages/lib.py:58
+msgid "commented on your post"
+msgstr "在您的内容张贴评论"
+
+#: mediagoblin/user_pages/views.py:169
+msgid "Sorry, comments are disabled."
+msgstr "抱歉,ä¸å¼€æ”¾è¯„论。"
+
+#: mediagoblin/user_pages/views.py:174
+msgid "Oops, your comment was empty."
+msgstr "啊,您的评论是空的。"
+
+#: mediagoblin/user_pages/views.py:180
+msgid "Your comment has been posted!"
+msgstr "您的评论已ç»å¼ è´´å®Œæˆï¼"
+
+#: mediagoblin/user_pages/views.py:205
+msgid "Please check your entries and try again."
+msgstr "请检查项目并é‡è¯•。"
+
+#: mediagoblin/user_pages/views.py:245
+msgid "You have to select or add a collection"
+msgstr "您需è¦é€‰æ‹©æˆ–是新增一个åˆé›†"
+
+#: mediagoblin/user_pages/views.py:256
+#, python-format
+msgid "\"%s\" already in collection \"%s\""
+msgstr "“%sâ€å·²ç»åœ¨â€œ%sâ€åˆé›†"
+
+#: mediagoblin/user_pages/views.py:262
+#, python-format
+msgid "\"%s\" added to collection \"%s\""
+msgstr "“%sâ€åŠ å…¥â€œ%sâ€åˆé›†"
+
+#: mediagoblin/user_pages/views.py:282
+msgid "You deleted the media."
+msgstr "您已ç»åˆ é™¤æ­¤åª’体。"
+
+#: mediagoblin/user_pages/views.py:289
+msgid "The media was not deleted because you didn't check that you were sure."
+msgstr "由于您没有勾选确认,该媒体没有被移除。"
+
+#: mediagoblin/user_pages/views.py:296
+msgid "You are about to delete another user's media. Proceed with caution."
+msgstr "您正在删除别人的媒体,请å°å¿ƒæ“作。"
+
+#: mediagoblin/user_pages/views.py:370
+msgid "You deleted the item from the collection."
+msgstr "您已ç»ä»Žè¯¥åˆé›†ä¸­åˆ é™¤è¯¥é¡¹ç›®ã€‚"
+
+#: mediagoblin/user_pages/views.py:374
+msgid "The item was not removed because you didn't check that you were sure."
+msgstr "由于您没有勾选确认,该项目没有被移除。"
+
+#: mediagoblin/user_pages/views.py:382
+msgid ""
+"You are about to delete an item from another user's collection. Proceed with"
+" caution."
+msgstr "您正在从别人的åˆé›†ä¸­åˆ é™¤é¡¹ç›®ï¼Œè¯·å°å¿ƒæ“作。"
+
+#: mediagoblin/user_pages/views.py:415
+#, python-format
+msgid "You deleted the collection \"%s\""
+msgstr "您已ç»åˆ é™¤â€œ%sâ€åˆé›†ã€‚"
+
+#: mediagoblin/user_pages/views.py:422
+msgid ""
+"The collection was not deleted because you didn't check that you were sure."
+msgstr "由于您没有勾选确认,该åˆé›†æ²¡æœ‰è¢«ç§»é™¤ã€‚"
+
+#: mediagoblin/user_pages/views.py:430
+msgid ""
+"You are about to delete another user's collection. Proceed with caution."
+msgstr "您正在删除别人的åˆé›†ï¼Œè¯·å°å¿ƒæ“作。"
diff --git a/mediagoblin/i18n/zh_TW.Big5/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/zh_TW.Big5/LC_MESSAGES/mediagoblin.mo
index d75d2eb2..c234ff00 100644
--- a/mediagoblin/i18n/zh_TW.Big5/LC_MESSAGES/mediagoblin.mo
+++ b/mediagoblin/i18n/zh_TW.Big5/LC_MESSAGES/mediagoblin.mo
Binary files differ
diff --git a/mediagoblin/i18n/zh_TW.Big5/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/zh_TW.Big5/LC_MESSAGES/mediagoblin.po
index a5e95640..a7ee8db6 100644
--- a/mediagoblin/i18n/zh_TW.Big5/LC_MESSAGES/mediagoblin.po
+++ b/mediagoblin/i18n/zh_TW.Big5/LC_MESSAGES/mediagoblin.po
@@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: GNU MediaGoblin\n"
"Report-Msgid-Bugs-To: http://issues.mediagoblin.org/\n"
-"POT-Creation-Date: 2013-03-04 18:04-0600\n"
-"PO-Revision-Date: 2013-03-05 00:04+0000\n"
+"POT-Creation-Date: 2013-05-27 13:54-0500\n"
+"PO-Revision-Date: 2013-05-27 18:54+0000\n"
"Last-Translator: cwebber <cwebber@dustycloud.org>\n"
"Language-Team: Chinese (Taiwan) (Big5) (http://www.transifex.com/projects/p/mediagoblin/language/zh_TW.Big5/)\n"
"MIME-Version: 1.0\n"
@@ -18,32 +18,37 @@ msgstr ""
"Language: zh_TW.Big5\n"
"Plural-Forms: nplurals=1; plural=0;\n"
-#: mediagoblin/auth/forms.py:28
-msgid "Invalid User name or email address."
+#: mediagoblin/auth/forms.py:26
+msgid "Username"
msgstr ""
-#: mediagoblin/auth/forms.py:29
-msgid "This field does not take email addresses."
+#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:45
+#: mediagoblin/tests/test_util.py:110
+msgid "Password"
msgstr ""
-#: mediagoblin/auth/forms.py:30
-msgid "This field requires an email address."
+#: mediagoblin/auth/forms.py:34
+msgid "Email address"
msgstr ""
-#: mediagoblin/auth/forms.py:52 mediagoblin/auth/forms.py:67
-msgid "Username"
+#: mediagoblin/auth/forms.py:41
+msgid "Username or Email"
msgstr ""
-#: mediagoblin/auth/forms.py:56 mediagoblin/auth/forms.py:71
-msgid "Password"
+#: mediagoblin/auth/forms.py:52
+msgid "Username or email"
msgstr ""
-#: mediagoblin/auth/forms.py:60
-msgid "Email address"
+#: mediagoblin/auth/tools.py:31
+msgid "Invalid User name or email address."
msgstr ""
-#: mediagoblin/auth/forms.py:78
-msgid "Username or email"
+#: mediagoblin/auth/tools.py:32
+msgid "This field does not take email addresses."
+msgstr ""
+
+#: mediagoblin/auth/tools.py:33
+msgid "This field requires an email address."
msgstr ""
#: mediagoblin/auth/views.py:54
@@ -58,54 +63,54 @@ msgstr ""
msgid "Sorry, a user with that email address already exists."
msgstr ""
-#: mediagoblin/auth/views.py:174
+#: mediagoblin/auth/views.py:182
msgid ""
"Your email address has been verified. You may now login, edit your profile, "
"and submit images!"
msgstr ""
-#: mediagoblin/auth/views.py:180
+#: mediagoblin/auth/views.py:188
msgid "The verification key or user id is incorrect"
msgstr ""
-#: mediagoblin/auth/views.py:198
+#: mediagoblin/auth/views.py:206
msgid "You must be logged in so we know who to send the email to!"
msgstr ""
-#: mediagoblin/auth/views.py:206
+#: mediagoblin/auth/views.py:214
msgid "You've already verified your email address!"
msgstr ""
-#: mediagoblin/auth/views.py:219
+#: mediagoblin/auth/views.py:227
msgid "Resent your verification email."
msgstr ""
-#: mediagoblin/auth/views.py:250
+#: mediagoblin/auth/views.py:258
msgid ""
"If that email address (case sensitive!) is registered an email has been sent"
" with instructions on how to change your password."
msgstr ""
-#: mediagoblin/auth/views.py:261
+#: mediagoblin/auth/views.py:269
msgid "Couldn't find someone with that username."
msgstr ""
-#: mediagoblin/auth/views.py:264
+#: mediagoblin/auth/views.py:272
msgid ""
"An email has been sent with instructions on how to change your password."
msgstr ""
-#: mediagoblin/auth/views.py:271
+#: mediagoblin/auth/views.py:279
msgid ""
"Could not send password recovery email as your username is inactive or your "
"account's email address has not been verified."
msgstr ""
-#: mediagoblin/auth/views.py:328
+#: mediagoblin/auth/views.py:336
msgid "You can now log in using your new password."
msgstr ""
-#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:93
+#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:82
#: mediagoblin/submit/forms.py:28 mediagoblin/submit/forms.py:47
#: mediagoblin/user_pages/forms.py:45
msgid "Title"
@@ -116,7 +121,7 @@ msgid "Description of this work"
msgstr ""
#: mediagoblin/edit/forms.py:29 mediagoblin/edit/forms.py:52
-#: mediagoblin/edit/forms.py:97 mediagoblin/submit/forms.py:32
+#: mediagoblin/edit/forms.py:86 mediagoblin/submit/forms.py:32
#: mediagoblin/submit/forms.py:51 mediagoblin/user_pages/forms.py:49
msgid ""
"You can use\n"
@@ -132,11 +137,11 @@ msgstr ""
msgid "Separate tags by commas."
msgstr ""
-#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:101
+#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:90
msgid "Slug"
msgstr ""
-#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:102
+#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:91
msgid "The slug can't be empty"
msgstr ""
@@ -164,45 +169,45 @@ msgid "This address contains errors"
msgstr ""
#: mediagoblin/edit/forms.py:63
-msgid "Old password"
-msgstr ""
-
-#: mediagoblin/edit/forms.py:64
-msgid "Enter your old password to prove you own this account."
-msgstr ""
-
-#: mediagoblin/edit/forms.py:67
-msgid "New password"
-msgstr ""
-
-#: mediagoblin/edit/forms.py:74
msgid "License preference"
msgstr ""
-#: mediagoblin/edit/forms.py:80
+#: mediagoblin/edit/forms.py:69
msgid "This will be your default license on upload forms."
msgstr ""
-#: mediagoblin/edit/forms.py:82
+#: mediagoblin/edit/forms.py:71
msgid "Email me when others comment on my media"
msgstr ""
-#: mediagoblin/edit/forms.py:94
+#: mediagoblin/edit/forms.py:83
msgid "The title can't be empty"
msgstr ""
-#: mediagoblin/edit/forms.py:96 mediagoblin/submit/forms.py:50
+#: mediagoblin/edit/forms.py:85 mediagoblin/submit/forms.py:50
#: mediagoblin/user_pages/forms.py:48
msgid "Description of this collection"
msgstr ""
-#: mediagoblin/edit/forms.py:103
+#: mediagoblin/edit/forms.py:92
msgid ""
"The title part of this collection's address. You usually don't need to "
"change this."
msgstr ""
-#: mediagoblin/edit/views.py:66
+#: mediagoblin/edit/forms.py:99
+msgid "Old password"
+msgstr ""
+
+#: mediagoblin/edit/forms.py:101
+msgid "Enter your old password to prove you own this account."
+msgstr ""
+
+#: mediagoblin/edit/forms.py:104
+msgid "New password"
+msgstr ""
+
+#: mediagoblin/edit/views.py:67
msgid "An entry with that slug already exists for this user."
msgstr ""
@@ -227,44 +232,63 @@ msgstr ""
msgid "Profile changes saved"
msgstr ""
-#: mediagoblin/edit/views.py:241
-msgid "Wrong password"
-msgstr ""
-
-#: mediagoblin/edit/views.py:252
+#: mediagoblin/edit/views.py:240
msgid "Account settings saved"
msgstr ""
-#: mediagoblin/edit/views.py:286
+#: mediagoblin/edit/views.py:274
msgid "You need to confirm the deletion of your account."
msgstr ""
-#: mediagoblin/edit/views.py:322 mediagoblin/submit/views.py:142
-#: mediagoblin/user_pages/views.py:214
+#: mediagoblin/edit/views.py:310 mediagoblin/submit/views.py:138
+#: mediagoblin/user_pages/views.py:222
#, python-format
msgid "You already have a collection called \"%s\"!"
msgstr ""
-#: mediagoblin/edit/views.py:326
+#: mediagoblin/edit/views.py:314
msgid "A collection with that slug already exists for this user."
msgstr ""
-#: mediagoblin/edit/views.py:343
+#: mediagoblin/edit/views.py:329
msgid "You are editing another user's collection. Proceed with caution."
msgstr ""
-#: mediagoblin/gmg_commands/theme.py:58
+#: mediagoblin/edit/views.py:348
+msgid "Wrong password"
+msgstr ""
+
+#: mediagoblin/edit/views.py:363
+msgid "Your password was changed successfully"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:60
msgid "Cannot link theme... no theme set\n"
msgstr ""
-#: mediagoblin/gmg_commands/theme.py:71
+#: mediagoblin/gmg_commands/assetlink.py:73
msgid "No asset directory for this theme\n"
msgstr ""
-#: mediagoblin/gmg_commands/theme.py:74
+#: mediagoblin/gmg_commands/assetlink.py:76
msgid "However, old link directory symlink found; removed.\n"
msgstr ""
+#: mediagoblin/gmg_commands/assetlink.py:112
+#, python-format
+msgid "Could not link \"%s\": %s exists and is not a symlink\n"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:119
+#, python-format
+msgid "Skipping \"%s\"; already set up.\n"
+msgstr ""
+
+#: mediagoblin/gmg_commands/assetlink.py:124
+#, python-format
+msgid "Old link found for \"%s\"; removing.\n"
+msgstr ""
+
#: mediagoblin/meddleware/csrf.py:134
msgid ""
"CSRF cookie not present. This is most likely the result of a cookie blocker "
@@ -272,12 +296,16 @@ msgid ""
"domain."
msgstr ""
-#: mediagoblin/media_types/__init__.py:61
-#: mediagoblin/media_types/__init__.py:102
+#: mediagoblin/media_types/__init__.py:111
+#: mediagoblin/media_types/__init__.py:155
msgid "Sorry, I don't support that file type :("
msgstr ""
-#: mediagoblin/media_types/video/processing.py:36
+#: mediagoblin/media_types/pdf/processing.py:136
+msgid "unoconv failing to run, check log file"
+msgstr ""
+
+#: mediagoblin/media_types/video/processing.py:37
msgid "Video transcoding failed"
msgstr ""
@@ -344,7 +372,7 @@ msgstr ""
msgid "This field is required for public clients"
msgstr ""
-#: mediagoblin/plugins/oauth/views.py:59
+#: mediagoblin/plugins/oauth/views.py:56
msgid "The client {0} has been registered!"
msgstr ""
@@ -363,7 +391,7 @@ msgstr ""
msgid "Add"
msgstr ""
-#: mediagoblin/processing/__init__.py:172
+#: mediagoblin/processing/__init__.py:193
msgid "Invalid file given for media type."
msgstr ""
@@ -371,45 +399,45 @@ msgstr ""
msgid "File"
msgstr ""
-#: mediagoblin/submit/views.py:51
+#: mediagoblin/submit/views.py:49
msgid "You must provide a file."
msgstr ""
-#: mediagoblin/submit/views.py:97
+#: mediagoblin/submit/views.py:93
msgid "Woohoo! Submitted!"
msgstr ""
-#: mediagoblin/submit/views.py:146
+#: mediagoblin/submit/views.py:144
#, python-format
msgid "Collection \"%s\" added!"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:64
+#: mediagoblin/templates/mediagoblin/base.html:67
msgid "Verify your email!"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:65
+#: mediagoblin/templates/mediagoblin/base.html:68
msgid "log out"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:70
+#: mediagoblin/templates/mediagoblin/base.html:73
#: mediagoblin/templates/mediagoblin/auth/login.html:28
#: mediagoblin/templates/mediagoblin/auth/login.html:36
#: mediagoblin/templates/mediagoblin/auth/login.html:54
msgid "Log in"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:79
+#: mediagoblin/templates/mediagoblin/base.html:82
#, python-format
msgid "<a href=\"%(user_url)s\">%(user_name)s</a>'s account"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:86
+#: mediagoblin/templates/mediagoblin/base.html:89
msgid "Change account settings"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:90
-#: mediagoblin/templates/mediagoblin/base.html:105
+#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:108
#: mediagoblin/templates/mediagoblin/admin/panel.html:21
#: mediagoblin/templates/mediagoblin/admin/panel.html:26
#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:21
@@ -417,72 +445,25 @@ msgstr ""
msgid "Media processing panel"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:96
msgid "Log out"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:96
+#: mediagoblin/templates/mediagoblin/base.html:99
#: mediagoblin/templates/mediagoblin/user_pages/user.html:156
msgid "Add media"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:99
+#: mediagoblin/templates/mediagoblin/base.html:102
#: mediagoblin/templates/mediagoblin/user_pages/collection_list.html:41
msgid "Create new collection"
msgstr ""
-#: mediagoblin/templates/mediagoblin/base.html:122
-#, python-format
-msgid ""
-"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
-"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/base.html:125
-#, python-format
-msgid ""
-"Released under the <a "
-"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
-"href=\"%(source_link)s\">Source code</a> available."
-msgstr ""
-
#: mediagoblin/templates/mediagoblin/error.html:24
msgid "Image of goblin stressing out"
msgstr ""
-#: mediagoblin/templates/mediagoblin/root.html:31
-msgid "Explore"
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:33
-msgid "Hi there, welcome to this MediaGoblin site!"
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:35
-msgid ""
-"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
-"extraordinarily great piece of media hosting software."
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:36
-msgid ""
-"To add your own media, place comments, and more, you can log in with your "
-"MediaGoblin account."
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:38
-msgid "Don't have one yet? It's easy!"
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:39
-#, python-format
-msgid ""
-"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
-" or\n"
-" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/root.html:47
+#: mediagoblin/templates/mediagoblin/root.html:32
msgid "Most recent media"
msgstr ""
@@ -588,6 +569,53 @@ msgid ""
"%(verification_url)s"
msgstr ""
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:21
+#, python-format
+msgid ""
+"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
+"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:24
+#, python-format
+msgid ""
+"Released under the <a "
+"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
+"href=\"%(source_link)s\">Source code</a> available."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:20
+msgid "Explore"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:22
+msgid "Hi there, welcome to this MediaGoblin site!"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:24
+msgid ""
+"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
+"extraordinarily great piece of media hosting software."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:25
+msgid ""
+"To add your own media, place comments, and more, you can log in with your "
+"MediaGoblin account."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:27
+msgid "Don't have one yet? It's easy!"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:28
+#, python-format
+msgid ""
+"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
+" or\n"
+" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/bits/logo.html:23
#: mediagoblin/themes/airy/templates/mediagoblin/bits/logo.html:23
msgid "MediaGoblin logo"
@@ -600,13 +628,13 @@ msgid "Editing attachments for %(media_title)s"
msgstr ""
#: mediagoblin/templates/mediagoblin/edit/attachments.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:159
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:175
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:182
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:198
msgid "Attachments"
msgstr ""
#: mediagoblin/templates/mediagoblin/edit/attachments.html:57
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:181
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:204
msgid "Add attachment"
msgstr ""
@@ -623,12 +651,22 @@ msgstr ""
#: mediagoblin/templates/mediagoblin/edit/attachments.html:63
#: mediagoblin/templates/mediagoblin/edit/edit.html:42
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:52
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:55
#: mediagoblin/templates/mediagoblin/edit/edit_collection.html:33
#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:40
msgid "Save changes"
msgstr ""
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:28
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:38
+#, python-format
+msgid "Changing %(username)s's password"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:45
+msgid "Save"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:28
#, python-format
msgid "Really delete user '%(user_name)s' and all related media/comments?"
@@ -639,7 +677,7 @@ msgid "Yes, really delete my account"
msgstr ""
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:47
+#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:48
#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:49
msgid "Delete permanently"
msgstr ""
@@ -656,7 +694,11 @@ msgstr ""
msgid "Changing %(username)s's account settings"
msgstr ""
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:59
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:46
+msgid "Change your password."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:62
msgid "Delete my account"
msgstr ""
@@ -681,6 +723,7 @@ msgstr ""
#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:56
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:65
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:136
#: mediagoblin/templates/mediagoblin/media_displays/video.html:55
msgid "Download"
@@ -705,6 +748,7 @@ msgid ""
msgstr ""
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:60
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:71
#: mediagoblin/templates/mediagoblin/media_displays/video.html:61
msgid "Original file"
msgstr ""
@@ -713,6 +757,7 @@ msgstr ""
msgid "WebM file (Vorbis codec)"
msgstr ""
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:59
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:87
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:93
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:99
@@ -723,6 +768,10 @@ msgstr ""
msgid "Image for %(media_title)s"
msgstr ""
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:79
+msgid "PDF file"
+msgstr ""
+
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:112
msgid "Toggle Rotate"
msgstr ""
@@ -821,7 +870,7 @@ msgstr ""
msgid "Really remove %(media_title)s from %(collection_title)s?"
msgstr ""
-#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:53
+#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:54
msgid "Remove"
msgstr ""
@@ -864,23 +913,27 @@ msgstr ""
msgid "â– Browsing media by <a href=\"%(user_url)s\">%(username)s</a>"
msgstr ""
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:94
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:95
msgid "Add a comment"
msgstr ""
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:102
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:104
msgid "Add this comment"
msgstr ""
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:123
-msgid "at"
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:132
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:152
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:164
+#, python-format
+msgid "%(formatted_time)s ago"
msgstr ""
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:144
-#, python-format
-msgid ""
-"<h3>Added on</h3>\n"
-" <p>%(date)s</p>"
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:150
+msgid "Added"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:161
+msgid "Created"
msgstr ""
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:28
@@ -1037,7 +1090,7 @@ msgstr ""
msgid "Tagged with"
msgstr ""
-#: mediagoblin/tools/exif.py:80
+#: mediagoblin/tools/exif.py:83
msgid "Could not read the image file."
msgstr ""
@@ -1067,6 +1120,30 @@ msgid ""
" deleted."
msgstr ""
+#: mediagoblin/tools/timesince.py:62
+msgid "year"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:63
+msgid "month"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:64
+msgid "week"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:65
+msgid "day"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:66
+msgid "hour"
+msgstr ""
+
+#: mediagoblin/tools/timesince.py:67
+msgid "minute"
+msgstr ""
+
#: mediagoblin/user_pages/forms.py:23
msgid "Comment"
msgstr ""
@@ -1098,73 +1175,77 @@ msgstr ""
msgid "Include a note"
msgstr ""
-#: mediagoblin/user_pages/lib.py:56
+#: mediagoblin/user_pages/lib.py:58
msgid "commented on your post"
msgstr ""
-#: mediagoblin/user_pages/views.py:166
+#: mediagoblin/user_pages/views.py:169
+msgid "Sorry, comments are disabled."
+msgstr ""
+
+#: mediagoblin/user_pages/views.py:174
msgid "Oops, your comment was empty."
msgstr ""
-#: mediagoblin/user_pages/views.py:172
+#: mediagoblin/user_pages/views.py:180
msgid "Your comment has been posted!"
msgstr ""
-#: mediagoblin/user_pages/views.py:197
+#: mediagoblin/user_pages/views.py:205
msgid "Please check your entries and try again."
msgstr ""
-#: mediagoblin/user_pages/views.py:237
+#: mediagoblin/user_pages/views.py:245
msgid "You have to select or add a collection"
msgstr ""
-#: mediagoblin/user_pages/views.py:248
+#: mediagoblin/user_pages/views.py:256
#, python-format
msgid "\"%s\" already in collection \"%s\""
msgstr ""
-#: mediagoblin/user_pages/views.py:264
+#: mediagoblin/user_pages/views.py:262
#, python-format
msgid "\"%s\" added to collection \"%s\""
msgstr ""
-#: mediagoblin/user_pages/views.py:286
+#: mediagoblin/user_pages/views.py:282
msgid "You deleted the media."
msgstr ""
-#: mediagoblin/user_pages/views.py:293
+#: mediagoblin/user_pages/views.py:289
msgid "The media was not deleted because you didn't check that you were sure."
msgstr ""
-#: mediagoblin/user_pages/views.py:301
+#: mediagoblin/user_pages/views.py:296
msgid "You are about to delete another user's media. Proceed with caution."
msgstr ""
-#: mediagoblin/user_pages/views.py:375
+#: mediagoblin/user_pages/views.py:370
msgid "You deleted the item from the collection."
msgstr ""
-#: mediagoblin/user_pages/views.py:379
+#: mediagoblin/user_pages/views.py:374
msgid "The item was not removed because you didn't check that you were sure."
msgstr ""
-#: mediagoblin/user_pages/views.py:389
+#: mediagoblin/user_pages/views.py:382
msgid ""
"You are about to delete an item from another user's collection. Proceed with"
" caution."
msgstr ""
-#: mediagoblin/user_pages/views.py:422
+#: mediagoblin/user_pages/views.py:415
#, python-format
msgid "You deleted the collection \"%s\""
msgstr ""
-#: mediagoblin/user_pages/views.py:429
+#: mediagoblin/user_pages/views.py:422
msgid ""
"The collection was not deleted because you didn't check that you were sure."
msgstr ""
-#: mediagoblin/user_pages/views.py:439
+#: mediagoblin/user_pages/views.py:430
msgid ""
"You are about to delete another user's collection. Proceed with caution."
msgstr ""
diff --git a/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.mo
index 3d267cfc..4b7a2398 100644
--- a/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.mo
+++ b/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.mo
Binary files differ
diff --git a/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po
index bd50df78..05ecd4b5 100644
--- a/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po
+++ b/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po
@@ -3,17 +3,19 @@
# This file is distributed under the same license as the PROJECT project.
#
# Translators:
-# <chc@citi.sinica.edu.tw>, 2011.
-# Harry Chen <harryhow@gmail.com>, 2011-2012.
-# <medicalwei@gmail.com>, 2012.
+# <chc@citi.sinica.edu.tw>, 2011
+# Harry Chen <harryhow@gmail.com>, 2011-2012
+# medicalwei <medicalwei@gmail.com>, 2013
+# medicalwei <medicalwei@gmail.com>, 2012
+# m13253 <m13253@hotmail.com>, 2013
msgid ""
msgstr ""
"Project-Id-Version: GNU MediaGoblin\n"
"Report-Msgid-Bugs-To: http://issues.mediagoblin.org/\n"
-"POT-Creation-Date: 2013-03-04 18:04-0600\n"
-"PO-Revision-Date: 2013-03-05 00:04+0000\n"
-"Last-Translator: cwebber <cwebber@dustycloud.org>\n"
-"Language-Team: LANGUAGE <LL@li.org>\n"
+"POT-Creation-Date: 2013-05-27 13:54-0500\n"
+"PO-Revision-Date: 2013-06-16 01:40+0000\n"
+"Last-Translator: m13253 <m13253@hotmail.com>\n"
+"Language-Team: Chinese (Taiwan) (http://www.transifex.com/projects/p/mediagoblin/language/zh_TW/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
@@ -21,34 +23,39 @@ msgstr ""
"Language: zh_TW\n"
"Plural-Forms: nplurals=1; plural=0;\n"
-#: mediagoblin/auth/forms.py:28
-msgid "Invalid User name or email address."
-msgstr ""
-
-#: mediagoblin/auth/forms.py:29
-msgid "This field does not take email addresses."
-msgstr ""
-
-#: mediagoblin/auth/forms.py:30
-msgid "This field requires an email address."
-msgstr ""
-
-#: mediagoblin/auth/forms.py:52 mediagoblin/auth/forms.py:67
+#: mediagoblin/auth/forms.py:26
msgid "Username"
msgstr "使用者å稱"
-#: mediagoblin/auth/forms.py:56 mediagoblin/auth/forms.py:71
+#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:45
+#: mediagoblin/tests/test_util.py:110
msgid "Password"
msgstr "密碼"
-#: mediagoblin/auth/forms.py:60
+#: mediagoblin/auth/forms.py:34
msgid "Email address"
msgstr "Email ä½å€"
-#: mediagoblin/auth/forms.py:78
+#: mediagoblin/auth/forms.py:41
+msgid "Username or Email"
+msgstr "使用者å稱或 email"
+
+#: mediagoblin/auth/forms.py:52
msgid "Username or email"
msgstr "使用者å稱或 email"
+#: mediagoblin/auth/tools.py:31
+msgid "Invalid User name or email address."
+msgstr "無效的使用者å稱或 email ä½ç½®ã€‚"
+
+#: mediagoblin/auth/tools.py:32
+msgid "This field does not take email addresses."
+msgstr "本欄ä½ä¸æŽ¥å— email ä½ç½®ã€‚"
+
+#: mediagoblin/auth/tools.py:33
+msgid "This field requires an email address."
+msgstr "本欄ä½éœ€è¦ email ä½ç½®ã€‚"
+
#: mediagoblin/auth/views.py:54
msgid "Sorry, registration is disabled on this instance."
msgstr "抱歉,本站已經暫åœè¨»å†Šã€‚"
@@ -61,54 +68,54 @@ msgstr "抱歉,這個使用者å稱已經存在。"
msgid "Sorry, a user with that email address already exists."
msgstr "抱歉,此 email ä½ç½®å·²ç¶“被註冊了。"
-#: mediagoblin/auth/views.py:174
+#: mediagoblin/auth/views.py:182
msgid ""
"Your email address has been verified. You may now login, edit your profile, "
"and submit images!"
msgstr "您的 email ä½å€å·²è¢«èªè­‰ã€‚您已經å¯ä»¥ç™»å…¥ï¼Œç·¨è¼¯æ‚¨çš„個人檔案並上傳圖片ï¼"
-#: mediagoblin/auth/views.py:180
+#: mediagoblin/auth/views.py:188
msgid "The verification key or user id is incorrect"
msgstr "èªè­‰ç¢¼æˆ–是使用者 ID 錯誤"
-#: mediagoblin/auth/views.py:198
+#: mediagoblin/auth/views.py:206
msgid "You must be logged in so we know who to send the email to!"
msgstr "您必須登入,我們æ‰çŸ¥é“ä¿¡è¦é€çµ¦èª°ï¼"
-#: mediagoblin/auth/views.py:206
+#: mediagoblin/auth/views.py:214
msgid "You've already verified your email address!"
msgstr "您的電å­éƒµä»¶å·²ç¶“確èªäº†ï¼"
-#: mediagoblin/auth/views.py:219
+#: mediagoblin/auth/views.py:227
msgid "Resent your verification email."
msgstr "é‡é€èªè­‰ä¿¡ã€‚"
-#: mediagoblin/auth/views.py:250
+#: mediagoblin/auth/views.py:258
msgid ""
"If that email address (case sensitive!) is registered an email has been sent"
" with instructions on how to change your password."
-msgstr ""
+msgstr "如果那 email ä½ç½® (請注æ„大å°å¯«) 已經註冊,寫有修改密碼步驟的 email 已經é€å‡ºã€‚"
-#: mediagoblin/auth/views.py:261
+#: mediagoblin/auth/views.py:269
msgid "Couldn't find someone with that username."
-msgstr ""
+msgstr "找ä¸åˆ°ç›¸é—œçš„使用者å稱。"
-#: mediagoblin/auth/views.py:264
+#: mediagoblin/auth/views.py:272
msgid ""
"An email has been sent with instructions on how to change your password."
msgstr "修改密碼的指示已經由電å­éƒµä»¶å¯„é€åˆ°æ‚¨çš„信箱。"
-#: mediagoblin/auth/views.py:271
+#: mediagoblin/auth/views.py:279
msgid ""
"Could not send password recovery email as your username is inactive or your "
"account's email address has not been verified."
msgstr "無法傳é€å¯†ç¢¼å›žå¾©ä¿¡ä»¶ï¼Œå› ç‚ºæ‚¨çš„使用者å稱已失效或是帳號尚未èªè­‰ã€‚"
-#: mediagoblin/auth/views.py:328
+#: mediagoblin/auth/views.py:336
msgid "You can now log in using your new password."
msgstr "您ç¾åœ¨å¯ä»¥ç”¨æ–°çš„密碼登入了ï¼"
-#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:93
+#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:82
#: mediagoblin/submit/forms.py:28 mediagoblin/submit/forms.py:47
#: mediagoblin/user_pages/forms.py:45
msgid "Title"
@@ -119,7 +126,7 @@ msgid "Description of this work"
msgstr "這個作å“çš„æè¿°"
#: mediagoblin/edit/forms.py:29 mediagoblin/edit/forms.py:52
-#: mediagoblin/edit/forms.py:97 mediagoblin/submit/forms.py:32
+#: mediagoblin/edit/forms.py:86 mediagoblin/submit/forms.py:32
#: mediagoblin/submit/forms.py:51 mediagoblin/user_pages/forms.py:49
msgid ""
"You can use\n"
@@ -135,11 +142,11 @@ msgstr "標籤"
msgid "Separate tags by commas."
msgstr "用逗號分隔標籤。"
-#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:101
+#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:90
msgid "Slug"
msgstr "簡稱"
-#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:102
+#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:91
msgid "The slug can't be empty"
msgstr "簡稱ä¸èƒ½ç‚ºç©ºç™½"
@@ -167,45 +174,45 @@ msgid "This address contains errors"
msgstr "本網å€å‡ºéŒ¯äº†"
#: mediagoblin/edit/forms.py:63
-msgid "Old password"
-msgstr "舊的密碼"
-
-#: mediagoblin/edit/forms.py:64
-msgid "Enter your old password to prove you own this account."
-msgstr "è¼¸å…¥æ‚¨çš„èˆŠå¯†ç¢¼ä¾†è­‰æ˜Žæ‚¨æ“æœ‰é€™å€‹å¸³è™Ÿã€‚"
-
-#: mediagoblin/edit/forms.py:67
-msgid "New password"
-msgstr "新密碼"
-
-#: mediagoblin/edit/forms.py:74
msgid "License preference"
-msgstr ""
+msgstr "授權å好"
-#: mediagoblin/edit/forms.py:80
+#: mediagoblin/edit/forms.py:69
msgid "This will be your default license on upload forms."
-msgstr ""
+msgstr "在上傳é é¢ï¼Œé€™å°‡æœƒæ˜¯æ‚¨é è¨­çš„æŽˆæ¬Šæ¨¡å¼ã€‚"
-#: mediagoblin/edit/forms.py:82
+#: mediagoblin/edit/forms.py:71
msgid "Email me when others comment on my media"
-msgstr "ç•¶æœ‰äººå°æˆ‘的媒體評論時寄信給我"
+msgstr "ç•¶æœ‰äººå°æˆ‘的媒體留言時寄信給我"
-#: mediagoblin/edit/forms.py:94
+#: mediagoblin/edit/forms.py:83
msgid "The title can't be empty"
msgstr "標題ä¸èƒ½æ˜¯ç©ºçš„"
-#: mediagoblin/edit/forms.py:96 mediagoblin/submit/forms.py:50
+#: mediagoblin/edit/forms.py:85 mediagoblin/submit/forms.py:50
#: mediagoblin/user_pages/forms.py:48
msgid "Description of this collection"
msgstr "這個è’è—çš„æè¿°"
-#: mediagoblin/edit/forms.py:103
+#: mediagoblin/edit/forms.py:92
msgid ""
"The title part of this collection's address. You usually don't need to "
"change this."
msgstr "æ­¤è’è—ç¶²å€çš„æ¨™é¡Œéƒ¨ä»½ï¼Œé€šå¸¸ä¸éœ€è¦ä¿®æ”¹ã€‚"
-#: mediagoblin/edit/views.py:66
+#: mediagoblin/edit/forms.py:99
+msgid "Old password"
+msgstr "舊的密碼"
+
+#: mediagoblin/edit/forms.py:101
+msgid "Enter your old password to prove you own this account."
+msgstr "è¼¸å…¥æ‚¨çš„èˆŠå¯†ç¢¼ä¾†è­‰æ˜Žæ‚¨æ“æœ‰é€™å€‹å¸³è™Ÿã€‚"
+
+#: mediagoblin/edit/forms.py:104
+msgid "New password"
+msgstr "新密碼"
+
+#: mediagoblin/edit/views.py:67
msgid "An entry with that slug already exists for this user."
msgstr "這個簡稱已經被其他人用了"
@@ -220,7 +227,7 @@ msgstr "您加上了附件「%sã€ï¼"
#: mediagoblin/edit/views.py:182
msgid "You can only edit your own profile."
-msgstr ""
+msgstr "您åªèƒ½ä¿®æ”¹æ‚¨è‡ªå·±çš„個人檔案。"
#: mediagoblin/edit/views.py:188
msgid "You are editing a user's profile. Proceed with caution."
@@ -230,57 +237,80 @@ msgstr "您正在修改別人的個人檔案,請å°å¿ƒæ“作。"
msgid "Profile changes saved"
msgstr "個人檔案修改已儲存"
-#: mediagoblin/edit/views.py:241
-msgid "Wrong password"
-msgstr "密碼錯誤"
-
-#: mediagoblin/edit/views.py:252
+#: mediagoblin/edit/views.py:240
msgid "Account settings saved"
msgstr "帳號設定已儲存"
-#: mediagoblin/edit/views.py:286
+#: mediagoblin/edit/views.py:274
msgid "You need to confirm the deletion of your account."
-msgstr ""
+msgstr "您必須è¦ç¢ºèªæ˜¯å¦åˆªé™¤æ‚¨çš„帳號。"
-#: mediagoblin/edit/views.py:322 mediagoblin/submit/views.py:142
-#: mediagoblin/user_pages/views.py:214
+#: mediagoblin/edit/views.py:310 mediagoblin/submit/views.py:138
+#: mediagoblin/user_pages/views.py:222
#, python-format
msgid "You already have a collection called \"%s\"!"
msgstr "您已經有一個稱åšã€Œ%sã€çš„è’è—了ï¼"
-#: mediagoblin/edit/views.py:326
+#: mediagoblin/edit/views.py:314
msgid "A collection with that slug already exists for this user."
msgstr "這個使用者已經有使用該簡稱的è’è—了。"
-#: mediagoblin/edit/views.py:343
+#: mediagoblin/edit/views.py:329
msgid "You are editing another user's collection. Proceed with caution."
msgstr "您正在修改別人的è’è—,請å°å¿ƒæ“作。"
-#: mediagoblin/gmg_commands/theme.py:58
+#: mediagoblin/edit/views.py:348
+msgid "Wrong password"
+msgstr "密碼錯誤"
+
+#: mediagoblin/edit/views.py:363
+msgid "Your password was changed successfully"
+msgstr "您的密碼已經æˆåŠŸä¿®æ”¹"
+
+#: mediagoblin/gmg_commands/assetlink.py:60
msgid "Cannot link theme... no theme set\n"
msgstr "無法連çµä½ˆæ™¯â€¦æ²’有此佈景\n"
-#: mediagoblin/gmg_commands/theme.py:71
+#: mediagoblin/gmg_commands/assetlink.py:73
msgid "No asset directory for this theme\n"
msgstr "此佈景沒有素æç›®éŒ„\n"
-#: mediagoblin/gmg_commands/theme.py:74
+#: mediagoblin/gmg_commands/assetlink.py:76
msgid "However, old link directory symlink found; removed.\n"
msgstr "但是舊的目錄連çµå·²ç¶“找到並移除。\n"
+#: mediagoblin/gmg_commands/assetlink.py:112
+#, python-format
+msgid "Could not link \"%s\": %s exists and is not a symlink\n"
+msgstr "無法連çµã€Œ%sã€ï¼š%s å­˜åœ¨ï¼Œä¸”ä¸æ˜¯ç¬¦è™Ÿé€£çµ\n"
+
+#: mediagoblin/gmg_commands/assetlink.py:119
+#, python-format
+msgid "Skipping \"%s\"; already set up.\n"
+msgstr "è·³éŽã€Œ%sã€ï¼Œå·²ç¶“建置完æˆã€‚\n"
+
+#: mediagoblin/gmg_commands/assetlink.py:124
+#, python-format
+msgid "Old link found for \"%s\"; removing.\n"
+msgstr "找到「%sã€èˆŠçš„連çµï¼Œåˆªé™¤ä¸­ã€‚\n"
+
#: mediagoblin/meddleware/csrf.py:134
msgid ""
"CSRF cookie not present. This is most likely the result of a cookie blocker "
"or somesuch.<br/>Make sure to permit the settings of cookies for this "
"domain."
-msgstr ""
+msgstr "è·¨ç¶²ç«™å­˜å– (CSRF) çš„ cookie ä¸å­˜åœ¨ï¼Œæœ‰å¯èƒ½æ˜¯ cookie 阻擋程å¼ä¹‹é¡žçš„程å¼å°Žè‡´çš„。<br/>è«‹å…許此網域的 cookie 設定。"
-#: mediagoblin/media_types/__init__.py:61
-#: mediagoblin/media_types/__init__.py:102
+#: mediagoblin/media_types/__init__.py:111
+#: mediagoblin/media_types/__init__.py:155
msgid "Sorry, I don't support that file type :("
msgstr "æŠ±æ­‰ï¼Œæˆ‘ä¸æ”¯æ´é€™æ¨£çš„æª”æ¡ˆæ ¼å¼ :("
-#: mediagoblin/media_types/video/processing.py:36
+#: mediagoblin/media_types/pdf/processing.py:136
+msgid "unoconv failing to run, check log file"
+msgstr "unoconv 無法執行,請檢查紀錄檔"
+
+#: mediagoblin/media_types/video/processing.py:37
msgid "Video transcoding failed"
msgstr "å½±åƒè½‰ç¢¼å¤±æ•—"
@@ -307,7 +337,7 @@ msgstr "å稱"
#: mediagoblin/plugins/oauth/forms.py:35
msgid "The name of the OAuth client"
-msgstr "OAuth client çš„å稱"
+msgstr "OAuth 用戶程å¼çš„å稱"
#: mediagoblin/plugins/oauth/forms.py:36
msgid "Description"
@@ -331,7 +361,7 @@ msgid ""
" <strong>Public</strong> - The client can't make confidential\n"
" requests to the GNU MediaGoblin instance (e.g. client-side\n"
" JavaScript client)."
-msgstr "<strong>秘密</strong> — OAuth client å¯ä»¥å° GNU MediaGoblin ç«™å°ç™¼é€ä¸è¢«ä½¿ç”¨è€…ä»£ç†æ””截的請求 (例如伺æœç«¯çš„ client)。\n<strong>公開</strong> — OAuth client ç„¡æ³•å° GNU MediaGoblin ç«™å°ç™¼é€ç§˜å¯†çš„請求 (例如客戶端的 JavaScript client)。"
+msgstr "<strong>秘密</strong> — OAuth 用戶程å¼å¯ä»¥å° GNU MediaGoblin ç«™å°ç™¼é€ä¸è¢«ä½¿ç”¨è€…ä»£ç†æ””截的請求 (例如伺æœç«¯çš„用戶程å¼)。\n<strong>公開</strong> — OAuth 用戶程å¼ç„¡æ³•å° GNU MediaGoblin ç«™å°ç™¼é€ç§˜å¯†çš„請求 (例如客戶端的 JavaScript 用戶程å¼)。"
#: mediagoblin/plugins/oauth/forms.py:52
msgid "Redirect URI"
@@ -341,23 +371,23 @@ msgstr "é‡å®šå‘ URI"
msgid ""
"The redirect URI for the applications, this field\n"
" is <strong>required</strong> for public clients."
-msgstr "此應用程å¼çš„é‡å®šå‘ URI,本欄ä½åœ¨å…¬é–‹é¡žåž‹çš„ OAuth client 為必填。"
+msgstr "此應用程å¼çš„é‡å®šå‘ URI,本欄ä½åœ¨å…¬é–‹é¡žåž‹çš„ OAuth 用戶程å¼ç‚ºå¿…填。"
#: mediagoblin/plugins/oauth/forms.py:66
msgid "This field is required for public clients"
-msgstr "本欄ä½åœ¨å…¬é–‹é¡žåž‹çš„ OAuth client 為必填"
+msgstr "本欄ä½åœ¨å…¬é–‹é¡žåž‹çš„用戶程å¼ç‚ºå¿…å¡«"
-#: mediagoblin/plugins/oauth/views.py:59
+#: mediagoblin/plugins/oauth/views.py:56
msgid "The client {0} has been registered!"
-msgstr "OAuth client {0} 註冊完æˆï¼"
+msgstr "OAuth ç”¨æˆ¶ç¨‹å¼ {0} 註冊完æˆï¼"
#: mediagoblin/plugins/oauth/templates/oauth/client/connections.html:22
msgid "OAuth client connections"
-msgstr ""
+msgstr "OAuth 用戶程å¼é€£ç·š"
#: mediagoblin/plugins/oauth/templates/oauth/client/list.html:22
msgid "Your OAuth clients"
-msgstr ""
+msgstr "您的 OAuth 用戶程å¼"
#: mediagoblin/plugins/oauth/templates/oauth/client/register.html:29
#: mediagoblin/templates/mediagoblin/submit/collection.html:30
@@ -366,7 +396,7 @@ msgstr ""
msgid "Add"
msgstr "增加"
-#: mediagoblin/processing/__init__.py:172
+#: mediagoblin/processing/__init__.py:193
msgid "Invalid file given for media type."
msgstr "指定錯誤的媒體類別ï¼"
@@ -374,45 +404,45 @@ msgstr "指定錯誤的媒體類別ï¼"
msgid "File"
msgstr "檔案"
-#: mediagoblin/submit/views.py:51
+#: mediagoblin/submit/views.py:49
msgid "You must provide a file."
msgstr "您必須æä¾›ä¸€å€‹æª”案"
-#: mediagoblin/submit/views.py:97
+#: mediagoblin/submit/views.py:93
msgid "Woohoo! Submitted!"
msgstr "啊哈ï¼PO 上去啦ï¼"
-#: mediagoblin/submit/views.py:146
+#: mediagoblin/submit/views.py:144
#, python-format
msgid "Collection \"%s\" added!"
msgstr "è’è—「%sã€æ–°å¢žå®Œæˆï¼"
-#: mediagoblin/templates/mediagoblin/base.html:64
+#: mediagoblin/templates/mediagoblin/base.html:67
msgid "Verify your email!"
msgstr "ç¢ºèªæ‚¨çš„é›»å­éƒµä»¶"
-#: mediagoblin/templates/mediagoblin/base.html:65
+#: mediagoblin/templates/mediagoblin/base.html:68
msgid "log out"
msgstr "登出"
-#: mediagoblin/templates/mediagoblin/base.html:70
+#: mediagoblin/templates/mediagoblin/base.html:73
#: mediagoblin/templates/mediagoblin/auth/login.html:28
#: mediagoblin/templates/mediagoblin/auth/login.html:36
#: mediagoblin/templates/mediagoblin/auth/login.html:54
msgid "Log in"
msgstr "登入"
-#: mediagoblin/templates/mediagoblin/base.html:79
+#: mediagoblin/templates/mediagoblin/base.html:82
#, python-format
msgid "<a href=\"%(user_url)s\">%(user_name)s</a>'s account"
msgstr "<a href=\"%(user_url)s\">%(user_name)s</a> 的帳號"
-#: mediagoblin/templates/mediagoblin/base.html:86
+#: mediagoblin/templates/mediagoblin/base.html:89
msgid "Change account settings"
msgstr "更改帳號設定"
-#: mediagoblin/templates/mediagoblin/base.html:90
-#: mediagoblin/templates/mediagoblin/base.html:105
+#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:108
#: mediagoblin/templates/mediagoblin/admin/panel.html:21
#: mediagoblin/templates/mediagoblin/admin/panel.html:26
#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:21
@@ -420,72 +450,25 @@ msgstr "更改帳號設定"
msgid "Media processing panel"
msgstr "媒體處ç†é¢æ¿"
-#: mediagoblin/templates/mediagoblin/base.html:93
+#: mediagoblin/templates/mediagoblin/base.html:96
msgid "Log out"
-msgstr ""
+msgstr "登出"
-#: mediagoblin/templates/mediagoblin/base.html:96
+#: mediagoblin/templates/mediagoblin/base.html:99
#: mediagoblin/templates/mediagoblin/user_pages/user.html:156
msgid "Add media"
msgstr "新增媒體"
-#: mediagoblin/templates/mediagoblin/base.html:99
+#: mediagoblin/templates/mediagoblin/base.html:102
#: mediagoblin/templates/mediagoblin/user_pages/collection_list.html:41
msgid "Create new collection"
msgstr "新增新的è’è—"
-#: mediagoblin/templates/mediagoblin/base.html:122
-#, python-format
-msgid ""
-"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
-"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
-msgstr ""
-
-#: mediagoblin/templates/mediagoblin/base.html:125
-#, python-format
-msgid ""
-"Released under the <a "
-"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
-"href=\"%(source_link)s\">Source code</a> available."
-msgstr "以 <a href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a> 授權釋出。備有<a href=\"%(source_link)s\">原始碼</a>。"
-
#: mediagoblin/templates/mediagoblin/error.html:24
msgid "Image of goblin stressing out"
msgstr "滿臉å•號的哥布林"
-#: mediagoblin/templates/mediagoblin/root.html:31
-msgid "Explore"
-msgstr "探索"
-
-#: mediagoblin/templates/mediagoblin/root.html:33
-msgid "Hi there, welcome to this MediaGoblin site!"
-msgstr "å˜¿ï¼æ­¡è¿Žä¾†åˆ° MediaGoblin ç«™å°ï¼ "
-
-#: mediagoblin/templates/mediagoblin/root.html:35
-msgid ""
-"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
-"extraordinarily great piece of media hosting software."
-msgstr "本站使用 <a href=\"http://mediagoblin.org\">MediaGoblin</a> — 與眾ä¸åŒçš„媒體分享網站。"
-
-#: mediagoblin/templates/mediagoblin/root.html:36
-msgid ""
-"To add your own media, place comments, and more, you can log in with your "
-"MediaGoblin account."
-msgstr "您å¯ä»¥ç™»å…¥æ‚¨çš„ MediaGoblin 帳號以進行上傳媒體ã€å¼µè²¼è©•論等等。"
-
-#: mediagoblin/templates/mediagoblin/root.html:38
-msgid "Don't have one yet? It's easy!"
-msgstr "沒有帳號嗎?開帳號很簡單ï¼"
-
-#: mediagoblin/templates/mediagoblin/root.html:39
-#, python-format
-msgid ""
-"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
-" or\n"
-" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
-msgstr "<a class=\"button_action_highlight\" href=\"%(register_url)s\">在這個網站上建立帳號</a>\n 或是\n <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">在自己的伺æœå™¨ä¸Šå»ºç«‹ MediaGoblin</a>"
-
-#: mediagoblin/templates/mediagoblin/root.html:47
+#: mediagoblin/templates/mediagoblin/root.html:32
msgid "Most recent media"
msgstr "最新的媒體"
@@ -591,6 +574,53 @@ msgid ""
"%(verification_url)s"
msgstr "%(username)s 您好:\n\nè¦å•Ÿå‹• GNU MediaGoblin 帳號,請在您的ç€è¦½å™¨ä¸­æ‰“開下é¢çš„ç¶²å€:\n\n%(verification_url)s"
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:21
+#, python-format
+msgid ""
+"Powered by <a href=\"http://mediagoblin.org/\" title='Version "
+"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project."
+msgstr "本站使用 <a href=\"http://mediagoblin.org/\" title='Version %(version)s'>MediaGoblin</a>,這是一個 <a href=\"http://gnu.org/\">GNU</a> 專案。"
+
+#: mediagoblin/templates/mediagoblin/bits/base_footer.html:24
+#, python-format
+msgid ""
+"Released under the <a "
+"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a "
+"href=\"%(source_link)s\">Source code</a> available."
+msgstr "以 <a href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a> 授權釋出。備有<a href=\"%(source_link)s\">原始碼</a>。"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:20
+msgid "Explore"
+msgstr "探索"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:22
+msgid "Hi there, welcome to this MediaGoblin site!"
+msgstr "å˜¿ï¼æ­¡è¿Žä¾†åˆ° MediaGoblin ç«™å°ï¼ "
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:24
+msgid ""
+"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an "
+"extraordinarily great piece of media hosting software."
+msgstr "本站使用 <a href=\"http://mediagoblin.org\">MediaGoblin</a> — 與眾ä¸åŒçš„媒體分享網站。"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:25
+msgid ""
+"To add your own media, place comments, and more, you can log in with your "
+"MediaGoblin account."
+msgstr "您å¯ä»¥ç™»å…¥æ‚¨çš„ MediaGoblin 帳號以進行上傳媒體ã€å¼µè²¼è©•論等等。"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:27
+msgid "Don't have one yet? It's easy!"
+msgstr "沒有帳號嗎?開帳號很簡單ï¼"
+
+#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:28
+#, python-format
+msgid ""
+"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n"
+" or\n"
+" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>"
+msgstr "<a class=\"button_action_highlight\" href=\"%(register_url)s\">在本站建立您的帳號</a>\n 或是\n <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">在您自己的伺æœå™¨ä¸Šå®‰è£ MediaGoblin</a>"
+
#: mediagoblin/templates/mediagoblin/bits/logo.html:23
#: mediagoblin/themes/airy/templates/mediagoblin/bits/logo.html:23
msgid "MediaGoblin logo"
@@ -603,13 +633,13 @@ msgid "Editing attachments for %(media_title)s"
msgstr "編輯 %(media_title)s 的附件"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:159
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:175
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:182
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:198
msgid "Attachments"
msgstr "附件"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:57
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:181
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:204
msgid "Add attachment"
msgstr "新增附件"
@@ -626,23 +656,33 @@ msgstr "å–æ¶ˆ"
#: mediagoblin/templates/mediagoblin/edit/attachments.html:63
#: mediagoblin/templates/mediagoblin/edit/edit.html:42
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:52
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:55
#: mediagoblin/templates/mediagoblin/edit/edit_collection.html:33
#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:40
msgid "Save changes"
msgstr "儲存變更"
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:28
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:38
+#, python-format
+msgid "Changing %(username)s's password"
+msgstr "更改 %(username)s 的密碼"
+
+#: mediagoblin/templates/mediagoblin/edit/change_pass.html:45
+msgid "Save"
+msgstr "儲存"
+
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:28
#, python-format
msgid "Really delete user '%(user_name)s' and all related media/comments?"
-msgstr ""
+msgstr "真的è¦åˆªé™¤ä½¿ç”¨è€…「%(user_name)sã€ä»¥åŠç›¸é—œçš„媒體與留言?"
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:35
msgid "Yes, really delete my account"
-msgstr ""
+msgstr "æ˜¯çš„ï¼Œæˆ‘çœŸçš„è¦æŠŠæˆ‘çš„å¸³è™Ÿåˆªé™¤"
#: mediagoblin/templates/mediagoblin/edit/delete_account.html:44
-#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:47
+#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:48
#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:49
msgid "Delete permanently"
msgstr "永久刪除"
@@ -659,9 +699,13 @@ msgstr "編輯 %(media_title)s"
msgid "Changing %(username)s's account settings"
msgstr "正在改變 %(username)s 的帳號設定"
-#: mediagoblin/templates/mediagoblin/edit/edit_account.html:59
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:46
+msgid "Change your password."
+msgstr "更改您的密碼。"
+
+#: mediagoblin/templates/mediagoblin/edit/edit_account.html:62
msgid "Delete my account"
-msgstr ""
+msgstr "刪除我的帳號"
#: mediagoblin/templates/mediagoblin/edit/edit_collection.html:29
#, python-format
@@ -680,10 +724,11 @@ msgstr "編輯 %(username)s 的個人檔案"
#: mediagoblin/templates/mediagoblin/listings/tag.html:35
#, python-format
msgid "Media tagged with: %(tag_name)s"
-msgstr "此媒體被 tag æˆï¼š%(tag_name)s"
+msgstr "這個媒體具有以下標籤:%(tag_name)s"
#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:56
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:65
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:136
#: mediagoblin/templates/mediagoblin/media_displays/video.html:55
msgid "Download"
@@ -708,6 +753,7 @@ msgid ""
msgstr "您å¯ä»¥åœ¨ <a href=\"http://getfirefox.com\">http://getfirefox.com</a> å–å¾—å¯ä»¥æ’­æ”¾æ­¤è²éŸ³çš„ç€è¦½å™¨ï¼"
#: mediagoblin/templates/mediagoblin/media_displays/audio.html:60
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:71
#: mediagoblin/templates/mediagoblin/media_displays/video.html:61
msgid "Original file"
msgstr "原始檔案"
@@ -716,6 +762,7 @@ msgstr "原始檔案"
msgid "WebM file (Vorbis codec)"
msgstr "WebM 檔案 (Vorbis 編碼)"
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:59
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:87
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:93
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:99
@@ -726,13 +773,17 @@ msgstr "WebM 檔案 (Vorbis 編碼)"
msgid "Image for %(media_title)s"
msgstr " %(media_title)s 的照片"
+#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:79
+msgid "PDF file"
+msgstr "PDF 檔"
+
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:112
msgid "Toggle Rotate"
msgstr "åˆ‡æ›æ—‹è½‰"
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:113
msgid "Perspective"
-msgstr "視角"
+msgstr "é€è¦–"
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:116
#: mediagoblin/templates/mediagoblin/media_displays/stl.html:117
@@ -771,14 +822,14 @@ msgid ""
"Sorry, this video will not work because\n"
" your web browser does not support HTML5 \n"
" video."
-msgstr ""
+msgstr "抱歉,由於您的ç€è¦½å™¨ä¸æ”¯æ´ HTML5 影片,本影片無法播放"
#: mediagoblin/templates/mediagoblin/media_displays/video.html:47
msgid ""
"You can get a modern web browser that \n"
" can play this video at <a href=\"http://getfirefox.com\">\n"
" http://getfirefox.com</a>!"
-msgstr ""
+msgstr "您å¯ä»¥åœ¨ <a href=\"http://getfirefox.com\">http://getfirefox.com</a> å–å¾—å¯ä»¥æ’­æ”¾æ­¤å½±ç‰‡çš„先進ç€è¦½å™¨ã€‚"
#: mediagoblin/templates/mediagoblin/media_displays/video.html:69
msgid "WebM file (640p; VP8/Vorbis)"
@@ -824,26 +875,26 @@ msgstr "真的è¦åˆªé™¤ %(title)s?"
msgid "Really remove %(media_title)s from %(collection_title)s?"
msgstr "確定è¦å¾ž %(collection_title)s 移除 %(media_title)s 嗎?"
-#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:53
+#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:54
msgid "Remove"
msgstr "移除"
#: mediagoblin/templates/mediagoblin/user_pages/collection_list.html:21
#, python-format
msgid "%(username)s's collections"
-msgstr ""
+msgstr "%(username)s çš„è’è—"
#: mediagoblin/templates/mediagoblin/user_pages/collection_list.html:28
#, python-format
msgid "<a href=\"%(user_url)s\">%(username)s</a>'s collections"
-msgstr ""
+msgstr "<a href=\"%(user_url)s\">%(username)s</a> çš„è’è—"
#: mediagoblin/templates/mediagoblin/user_pages/comment_email.txt:19
#, python-format
msgid ""
"Hi %(username)s,\n"
"%(comment_author)s commented on your post (%(comment_url)s) at %(instance_name)s\n"
-msgstr "%(username)s 您好:\n%(comment_author)s 在 %(instance_name)s å°æ‚¨çš„內容 (%(comment_url)s) 張貼評論\n"
+msgstr "%(username)s 您好:\n%(comment_author)s 在 %(instance_name)s å°æ‚¨çš„內容 (%(comment_url)s) 張貼留言\n"
#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30
#, python-format
@@ -855,7 +906,7 @@ msgstr "%(username)s的媒體"
msgid ""
"<a href=\"%(user_url)s\">%(username)s</a>'s media with tag <a "
"href=\"%(tag_url)s\">%(tag)s</a>"
-msgstr ""
+msgstr "標籤為 <a href=\"%(tag_url)s\">%(tag)s</a> 的 <a href=\"%(user_url)s\">%(username)s</a> 的媒體"
#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:48
#, python-format
@@ -867,30 +918,34 @@ msgstr "<a href=\"%(user_url)s\">%(username)s</a> 的媒體"
msgid "â– Browsing media by <a href=\"%(user_url)s\">%(username)s</a>"
msgstr "â– ç€è¦½ <a href=\"%(user_url)s\">%(username)s</a> 的媒體"
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:94
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:95
msgid "Add a comment"
-msgstr "新增評論"
+msgstr "新增留言"
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:102
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:104
msgid "Add this comment"
-msgstr "增加評論"
-
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:123
-msgid "at"
-msgstr "在"
+msgstr "增加留言"
-#: mediagoblin/templates/mediagoblin/user_pages/media.html:144
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:132
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:152
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:164
#, python-format
-msgid ""
-"<h3>Added on</h3>\n"
-" <p>%(date)s</p>"
-msgstr "<h3>加入日期</h3>\n <p>%(date)s</p>"
+msgid "%(formatted_time)s ago"
+msgstr "%(formatted_time)s å‰"
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:150
+msgid "Added"
+msgstr "新增於"
+
+#: mediagoblin/templates/mediagoblin/user_pages/media.html:161
+msgid "Created"
+msgstr "建立於"
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:28
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:40
#, python-format
msgid "Add “%(media_title)s†to a collection"
-msgstr ""
+msgstr "加入 “%(media_title)s†至è’è—"
#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:54
msgid "+"
@@ -969,7 +1024,7 @@ msgstr "這個使用者(還)沒有填寫個人檔案。"
#: mediagoblin/templates/mediagoblin/user_pages/user.html:124
msgid "Browse collections"
-msgstr ""
+msgstr "ç€è¦½è’è—"
#: mediagoblin/templates/mediagoblin/user_pages/user.html:137
#, python-format
@@ -994,11 +1049,11 @@ msgstr " (移除)"
#: mediagoblin/templates/mediagoblin/utils/collections.html:21
msgid "Collected in"
-msgstr ""
+msgstr "è’集了"
#: mediagoblin/templates/mediagoblin/utils/collections.html:40
msgid "Add to a collection"
-msgstr ""
+msgstr "加入至è’è—"
#: mediagoblin/templates/mediagoblin/utils/feed_link.html:21
#: mediagoblin/themes/airy/templates/mediagoblin/utils/feed_link.html:21
@@ -1040,7 +1095,7 @@ msgstr "更舊的"
msgid "Tagged with"
msgstr "標籤"
-#: mediagoblin/tools/exif.py:80
+#: mediagoblin/tools/exif.py:83
msgid "Could not read the image file."
msgstr "無法讀å–圖片檔案。"
@@ -1070,9 +1125,33 @@ msgid ""
" deleted."
msgstr "ä¸å¥½æ„æ€ï¼Œçœ‹èµ·ä¾†é€™å€‹ç¶²å€ä¸Šæ²’有網é ã€‚</p><p>å¦‚æžœæ‚¨ç¢ºå®šé€™å€‹ç¶²å€æ˜¯æ­£ç¢ºçš„,您在尋找的é é¢å¯èƒ½å·²ç¶“移動或是被刪除了。"
+#: mediagoblin/tools/timesince.py:62
+msgid "year"
+msgstr "å¹´"
+
+#: mediagoblin/tools/timesince.py:63
+msgid "month"
+msgstr "月"
+
+#: mediagoblin/tools/timesince.py:64
+msgid "week"
+msgstr "週"
+
+#: mediagoblin/tools/timesince.py:65
+msgid "day"
+msgstr "æ—¥"
+
+#: mediagoblin/tools/timesince.py:66
+msgid "hour"
+msgstr "å°æ™‚"
+
+#: mediagoblin/tools/timesince.py:67
+msgid "minute"
+msgstr "分"
+
#: mediagoblin/user_pages/forms.py:23
msgid "Comment"
-msgstr ""
+msgstr "留言"
#: mediagoblin/user_pages/forms.py:25
msgid ""
@@ -1091,7 +1170,7 @@ msgstr "我確定我è¦å¾žè’è—中移除此項目"
#: mediagoblin/user_pages/forms.py:39
msgid "Collection"
-msgstr ""
+msgstr "è’è—"
#: mediagoblin/user_pages/forms.py:40
msgid "-- Select --"
@@ -1101,73 +1180,77 @@ msgstr "— è«‹é¸æ“‡ —"
msgid "Include a note"
msgstr "加註"
-#: mediagoblin/user_pages/lib.py:56
+#: mediagoblin/user_pages/lib.py:58
msgid "commented on your post"
-msgstr "在您的內容張貼評論"
+msgstr "在您的內容張貼留言"
+
+#: mediagoblin/user_pages/views.py:169
+msgid "Sorry, comments are disabled."
+msgstr "抱歉,留言被關閉。"
-#: mediagoblin/user_pages/views.py:166
+#: mediagoblin/user_pages/views.py:174
msgid "Oops, your comment was empty."
msgstr "啊,您的留言是空的。"
-#: mediagoblin/user_pages/views.py:172
+#: mediagoblin/user_pages/views.py:180
msgid "Your comment has been posted!"
msgstr "您的留言已經張貼完æˆï¼"
-#: mediagoblin/user_pages/views.py:197
+#: mediagoblin/user_pages/views.py:205
msgid "Please check your entries and try again."
msgstr "請檢查項目並é‡è©¦ã€‚"
-#: mediagoblin/user_pages/views.py:237
+#: mediagoblin/user_pages/views.py:245
msgid "You have to select or add a collection"
msgstr "您需è¦é¸æ“‡æˆ–是新增一個è’è—"
-#: mediagoblin/user_pages/views.py:248
+#: mediagoblin/user_pages/views.py:256
#, python-format
msgid "\"%s\" already in collection \"%s\""
msgstr "「%sã€å·²ç¶“在「%sã€è’è—"
-#: mediagoblin/user_pages/views.py:264
+#: mediagoblin/user_pages/views.py:262
#, python-format
msgid "\"%s\" added to collection \"%s\""
msgstr "「%sã€åŠ å…¥ã€Œ%sã€è’è—"
-#: mediagoblin/user_pages/views.py:286
+#: mediagoblin/user_pages/views.py:282
msgid "You deleted the media."
msgstr "您已經刪除此媒體。"
-#: mediagoblin/user_pages/views.py:293
+#: mediagoblin/user_pages/views.py:289
msgid "The media was not deleted because you didn't check that you were sure."
msgstr "由於您沒有勾é¸ç¢ºèªï¼Œè©²åª’體沒有被移除。"
-#: mediagoblin/user_pages/views.py:301
+#: mediagoblin/user_pages/views.py:296
msgid "You are about to delete another user's media. Proceed with caution."
msgstr "您正在刪除別人的媒體,請å°å¿ƒæ“作。"
-#: mediagoblin/user_pages/views.py:375
+#: mediagoblin/user_pages/views.py:370
msgid "You deleted the item from the collection."
msgstr "您已經從該è’è—中刪除該項目。"
-#: mediagoblin/user_pages/views.py:379
+#: mediagoblin/user_pages/views.py:374
msgid "The item was not removed because you didn't check that you were sure."
msgstr "由於您沒有勾é¸ç¢ºèªï¼Œè©²é …目沒有被移除。"
-#: mediagoblin/user_pages/views.py:389
+#: mediagoblin/user_pages/views.py:382
msgid ""
"You are about to delete an item from another user's collection. Proceed with"
" caution."
msgstr "您正在從別人的è’è—中刪除項目,請å°å¿ƒæ“作。"
-#: mediagoblin/user_pages/views.py:422
+#: mediagoblin/user_pages/views.py:415
#, python-format
msgid "You deleted the collection \"%s\""
msgstr "您已經刪除「%sã€è’è—。"
-#: mediagoblin/user_pages/views.py:429
+#: mediagoblin/user_pages/views.py:422
msgid ""
"The collection was not deleted because you didn't check that you were sure."
msgstr "由於您沒有勾é¸ç¢ºèªï¼Œè©²è’è—æ²’有被移除。"
-#: mediagoblin/user_pages/views.py:439
+#: mediagoblin/user_pages/views.py:430
msgid ""
"You are about to delete another user's collection. Proceed with caution."
msgstr "您正在刪除別人的è’è—,請å°å¿ƒæ“作。"
diff --git a/mediagoblin/init/__init__.py b/mediagoblin/init/__init__.py
index 7c832442..e0711416 100644
--- a/mediagoblin/init/__init__.py
+++ b/mediagoblin/init/__init__.py
@@ -14,8 +14,6 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-from beaker.cache import CacheManager
-from beaker.util import parse_cache_config_options
import jinja2
from mediagoblin.tools import staticdirect
@@ -26,6 +24,7 @@ from mediagoblin import mg_globals
from mediagoblin.mg_globals import setup_globals
from mediagoblin.db.open import setup_connection_and_db_from_config, \
check_db_migrations_current, load_models
+from mediagoblin.tools.pluginapi import hook_runall
from mediagoblin.tools.workbench import WorkbenchManager
from mediagoblin.storage import storage_system_from_config
@@ -59,16 +58,20 @@ def setup_global_and_app_config(config_path):
return global_config, app_config
-def setup_database():
+def setup_database(run_migrations=False):
app_config = mg_globals.app_config
+ global_config = mg_globals.global_config
# Load all models for media types (plugins, ...)
load_models(app_config)
-
# Set up the database
- db = setup_connection_and_db_from_config(app_config)
-
- check_db_migrations_current(db)
+ db = setup_connection_and_db_from_config(app_config, run_migrations)
+ if run_migrations:
+ #Run the migrations to initialize/update the database.
+ from mediagoblin.gmg_commands.dbupdate import run_all_migrations
+ run_all_migrations(db, app_config, global_config)
+ else:
+ check_db_migrations_current(db)
setup_globals(database=db)
@@ -118,6 +121,12 @@ def get_staticdirector(app_config):
direct_domains = {None: app_config['direct_remote_path'].strip()}
direct_domains['theme'] = app_config['theme_web_path'].strip()
+ # Let plugins load additional paths
+ for plugin_static in hook_runall("static_setup"):
+ direct_domains[plugin_static.name] = "%s/%s" % (
+ app_config['plugin_web_path'].rstrip('/'),
+ plugin_static.name)
+
return staticdirect.StaticDirect(
direct_domains)
@@ -146,16 +155,3 @@ def setup_workbench():
workbench_manager = WorkbenchManager(app_config['workbench_path'])
setup_globals(workbench_manager=workbench_manager)
-
-
-def setup_beaker_cache():
- """
- Setup the Beaker Cache manager.
- """
- cache_config = mg_globals.global_config['beaker.cache']
- cache_config = dict(
- [(u'cache.%s' % key, value)
- for key, value in cache_config.iteritems()])
- cache = CacheManager(**parse_cache_config_options(cache_config))
- setup_globals(cache=cache)
- return cache
diff --git a/mediagoblin/init/celery/__init__.py b/mediagoblin/init/celery/__init__.py
index 8d7a41bd..57242bf6 100644
--- a/mediagoblin/init/celery/__init__.py
+++ b/mediagoblin/init/celery/__init__.py
@@ -16,12 +16,18 @@
import os
import sys
+import logging
from celery import Celery
-from mediagoblin.tools.pluginapi import PluginManager
+from mediagoblin.tools.pluginapi import hook_runall
-MANDATORY_CELERY_IMPORTS = ['mediagoblin.processing.task']
+_log = logging.getLogger(__name__)
+
+
+MANDATORY_CELERY_IMPORTS = [
+ 'mediagoblin.processing.task',
+ 'mediagoblin.notifications.task']
DEFAULT_SETTINGS_MODULE = 'mediagoblin.init.celery.dummy_settings_module'
@@ -66,8 +72,7 @@ def setup_celery_app(app_config, global_config,
celery_app = Celery()
celery_app.config_from_object(celery_settings)
- for callable_hook in PluginManager().get_hook_callables('celery_setup'):
- callable_hook(celery_app)
+ hook_runall('celery_setup', celery_app)
def setup_celery_from_config(app_config, global_config,
@@ -98,3 +103,13 @@ def setup_celery_from_config(app_config, global_config,
if set_environ:
os.environ['CELERY_CONFIG_MODULE'] = settings_module
+
+ # Replace the default celery.current_app.conf if celery has already been
+ # initiated
+ from celery import current_app
+
+ _log.info('Setting celery configuration from object "{0}"'.format(
+ settings_module))
+ current_app.config_from_object(this_module)
+
+ _log.debug('Celery broker host: {0}'.format(current_app.conf['BROKER_HOST']))
diff --git a/mediagoblin/init/celery/from_celery.py b/mediagoblin/init/celery/from_celery.py
index 8a794abb..b395a826 100644
--- a/mediagoblin/init/celery/from_celery.py
+++ b/mediagoblin/init/celery/from_celery.py
@@ -22,7 +22,7 @@ from celery.signals import setup_logging
from mediagoblin import app, mg_globals
from mediagoblin.init.celery import setup_celery_from_config
-from mediagoblin.tools.pluginapi import PluginManager
+from mediagoblin.tools.pluginapi import hook_runall
OUR_MODULENAME = __name__
@@ -47,9 +47,7 @@ def setup_logging_from_paste_ini(loglevel, **kw):
logging.config.fileConfig(logging_conf_file)
- for callable_hook in \
- PluginManager().get_hook_callables('celery_logging_setup'):
- callable_hook()
+ hook_runall('celery_logging_setup')
setup_logging.connect(setup_logging_from_paste_ini)
diff --git a/mediagoblin/init/config.py b/mediagoblin/init/config.py
index ac4ab9bf..11a91cff 100644
--- a/mediagoblin/init/config.py
+++ b/mediagoblin/init/config.py
@@ -14,6 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
+import logging
import os
import pkg_resources
@@ -21,6 +22,9 @@ from configobj import ConfigObj, flatten_errors
from validate import Validator
+_log = logging.getLogger(__name__)
+
+
CONFIG_SPEC_PATH = pkg_resources.resource_filename(
'mediagoblin', 'config_spec.ini')
@@ -42,6 +46,9 @@ def read_mediagoblin_config(config_path, config_spec=CONFIG_SPEC_PATH):
Also provides %(__file__)s and %(here)s values of this file and
its directory respectively similar to paste deploy.
+ Also reads for [plugins] section, appends all config_spec.ini
+ files from said plugins into the general config_spec specification.
+
This function doesn't itself raise any exceptions if validation
fails, you'll have to do something
@@ -57,10 +64,45 @@ def read_mediagoblin_config(config_path, config_spec=CONFIG_SPEC_PATH):
"""
config_path = os.path.abspath(config_path)
+ # PRE-READ of config file. This allows us to fetch the plugins so
+ # we can add their plugin specs to the general config_spec.
+ config = ConfigObj(
+ config_path,
+ interpolation='ConfigParser')
+
+ plugins = config.get("plugins", {}).keys()
+ plugin_configs = {}
+
+ for plugin in plugins:
+ try:
+ plugin_config_spec_path = pkg_resources.resource_filename(
+ plugin, "config_spec.ini")
+ if not os.path.exists(plugin_config_spec_path):
+ continue
+
+ plugin_config_spec = ConfigObj(
+ plugin_config_spec_path,
+ encoding='UTF8', list_values=False, _inspec=True)
+ _setup_defaults(plugin_config_spec, config_path)
+
+ if not "plugin_spec" in plugin_config_spec:
+ continue
+
+ plugin_configs[plugin] = plugin_config_spec["plugin_spec"]
+
+ except ImportError:
+ _log.warning(
+ "When setting up config section, could not import '%s'" %
+ plugin)
+
+ # Now load the main config spec
config_spec = ConfigObj(
config_spec,
encoding='UTF8', list_values=False, _inspec=True)
+ # append the plugin specific sections of the config spec
+ config_spec['plugins'] = plugin_configs
+
_setup_defaults(config_spec, config_path)
config = ConfigObj(
diff --git a/mediagoblin/init/plugins/__init__.py b/mediagoblin/init/plugins/__init__.py
index cdf9b5ad..0df4f381 100644
--- a/mediagoblin/init/plugins/__init__.py
+++ b/mediagoblin/init/plugins/__init__.py
@@ -59,6 +59,4 @@ def setup_plugins():
pman.register_hooks(plugin.hooks)
# Execute anything registered to the setup hook.
- setup_list = pman.get_hook_callables('setup')
- for fun in setup_list:
- fun()
+ pluginapi.hook_runall('setup')
diff --git a/mediagoblin/listings/views.py b/mediagoblin/listings/views.py
index 35af7148..07dbb3d5 100644
--- a/mediagoblin/listings/views.py
+++ b/mediagoblin/listings/views.py
@@ -14,6 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
+from mediagoblin import mg_globals
from mediagoblin.db.models import MediaEntry
from mediagoblin.db.util import media_entries_for_tag_slug
from mediagoblin.tools.pagination import Pagination
@@ -80,6 +81,17 @@ def atom_feed(request):
link = request.urlgen('index', qualified=True)
feed_title += "for all recent items"
+ atomlinks = [
+ {'href': link,
+ 'rel': 'alternate',
+ 'type': 'text/html'}]
+
+ if mg_globals.app_config["push_urls"]:
+ for push_url in mg_globals.app_config["push_urls"]:
+ atomlinks.append({
+ 'rel': 'hub',
+ 'href': push_url})
+
cursor = cursor.order_by(MediaEntry.created.desc())
cursor = cursor.limit(ATOM_DEFAULT_NR_OF_UPDATED_ITEMS)
@@ -87,9 +99,8 @@ def atom_feed(request):
feed_title,
feed_url=request.url,
id=link,
- links=[{'href': link,
- 'rel': 'alternate',
- 'type': 'text/html'}])
+ links=atomlinks)
+
for entry in cursor:
feed.add(entry.get('title'),
entry.description_html,
diff --git a/mediagoblin/meddleware/csrf.py b/mediagoblin/meddleware/csrf.py
index 661f0ba2..44d42d75 100644
--- a/mediagoblin/meddleware/csrf.py
+++ b/mediagoblin/meddleware/csrf.py
@@ -111,7 +111,7 @@ class CsrfMeddleware(BaseMeddleware):
httponly=True)
# update the Vary header
- response.vary = (getattr(response, 'vary', None) or []) + ['Cookie']
+ response.vary = list(getattr(response, 'vary', None) or []) + ['Cookie']
def _make_token(self, request):
"""Generate a new token to use for CSRF protection."""
diff --git a/mediagoblin/media_types/__init__.py b/mediagoblin/media_types/__init__.py
index 0abb38d3..134157dc 100644
--- a/mediagoblin/media_types/__init__.py
+++ b/mediagoblin/media_types/__init__.py
@@ -15,11 +15,10 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
-import sys
import logging
import tempfile
-from mediagoblin import mg_globals
+from mediagoblin.tools.pluginapi import hook_handle
from mediagoblin.tools.translate import lazy_pass_to_ugettext as _
_log = logging.getLogger(__name__)
@@ -31,6 +30,26 @@ class InvalidFileType(Exception):
pass
+class MediaManagerBase(object):
+ "Base class for all media managers"
+
+ # Please override in actual media managers
+ media_fetch_order = None
+
+ @staticmethod
+ def sniff_handler(*args, **kwargs):
+ return False
+
+ def __init__(self, entry):
+ self.entry = entry
+
+ def __getitem__(self, i):
+ return getattr(self, i)
+
+ def __contains__(self, i):
+ return hasattr(self, i)
+
+
def sniff_media(media):
'''
Iterate through the enabled media types and find those suited
@@ -47,38 +66,18 @@ def sniff_media(media):
media_file.write(media.stream.read())
media.stream.seek(0)
- for media_type, manager in get_media_managers():
- _log.info('Sniffing {0}'.format(media_type))
- if 'sniff_handler' in manager and \
- manager['sniff_handler'](media_file, media=media):
- _log.info('{0} accepts the file'.format(media_type))
- return media_type, manager
- else:
- _log.debug('{0} did not accept the file'.format(media_type))
+ media_type = hook_handle('sniff_handler', media_file, media=media)
+ if media_type:
+ _log.info('{0} accepts the file'.format(media_type))
+ return media_type, hook_handle(('media_manager', media_type))
+ else:
+ _log.debug('{0} did not accept the file'.format(media_type))
raise FileTypeNotSupported(
# TODO: Provide information on which file types are supported
_(u'Sorry, I don\'t support that file type :('))
-def get_media_types():
- """
- Generator, yields the available media types
- """
- for media_type in mg_globals.app_config['media_types']:
- yield media_type
-
-
-def get_media_managers():
- '''
- Generator, yields all enabled media managers
- '''
- for media_type in get_media_types():
- __import__(media_type)
-
- yield media_type, sys.modules[media_type].MEDIA_MANAGER
-
-
def get_media_type_and_manager(filename):
'''
Try to find the media type based on the file name, extension
@@ -89,11 +88,10 @@ def get_media_type_and_manager(filename):
# Get the file extension
ext = os.path.splitext(filename)[1].lower()
- for media_type, manager in get_media_managers():
- # Omit the dot from the extension and match it against
- # the media manager
- if ext[1:] in manager['accepted_extensions']:
- return media_type, manager
+ # Omit the dot from the extension and match it against
+ # the media manager
+ if hook_handle('get_media_type_and_manager', ext[1:]):
+ return hook_handle('get_media_type_and_manager', ext[1:])
else:
_log.info('File {0} has no file extension, let\'s hope the sniffers get it.'.format(
filename))
diff --git a/mediagoblin/media_types/ascii/__init__.py b/mediagoblin/media_types/ascii/__init__.py
index 856d1d7b..4baf8dd3 100644
--- a/mediagoblin/media_types/ascii/__init__.py
+++ b/mediagoblin/media_types/ascii/__init__.py
@@ -14,16 +14,34 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
+from mediagoblin.media_types import MediaManagerBase
from mediagoblin.media_types.ascii.processing import process_ascii, \
sniff_handler
+from mediagoblin.tools import pluginapi
+ACCEPTED_EXTENSIONS = ["txt", "asc", "nfo"]
+MEDIA_TYPE = 'mediagoblin.media_types.ascii'
-MEDIA_MANAGER = {
- "human_readable": "ASCII",
- "processor": process_ascii, # alternately a string,
- # 'mediagoblin.media_types.image.processing'?
- "sniff_handler": sniff_handler,
- "display_template": "mediagoblin/media_displays/ascii.html",
- "default_thumb": "images/media_thumbs/ascii.jpg",
- "accepted_extensions": [
- "txt", "asc", "nfo"]}
+
+def setup_plugin():
+ config = pluginapi.get_config(MEDIA_TYPE)
+
+
+class ASCIIMediaManager(MediaManagerBase):
+ human_readable = "ASCII"
+ processor = staticmethod(process_ascii)
+ display_template = "mediagoblin/media_displays/ascii.html"
+ default_thumb = "images/media_thumbs/ascii.jpg"
+
+
+def get_media_type_and_manager(ext):
+ if ext in ACCEPTED_EXTENSIONS:
+ return MEDIA_TYPE, ASCIIMediaManager
+
+
+hooks = {
+ 'setup': setup_plugin,
+ 'get_media_type_and_manager': get_media_type_and_manager,
+ ('media_manager', MEDIA_TYPE): lambda: ASCIIMediaManager,
+ 'sniff_handler': sniff_handler,
+}
diff --git a/mediagoblin/media_types/ascii/asciitoimage.py b/mediagoblin/media_types/ascii/asciitoimage.py
index 108de023..786941f6 100644
--- a/mediagoblin/media_types/ascii/asciitoimage.py
+++ b/mediagoblin/media_types/ascii/asciitoimage.py
@@ -14,9 +14,14 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-import Image
-import ImageFont
-import ImageDraw
+try:
+ from PIL import Image
+ from PIL import ImageFont
+ from PIL import ImageDraw
+except ImportError:
+ import Image
+ import ImageFont
+ import ImageDraw
import logging
import pkg_resources
import os
diff --git a/mediagoblin/media_types/ascii/processing.py b/mediagoblin/media_types/ascii/processing.py
index 382cd015..aca784e8 100644
--- a/mediagoblin/media_types/ascii/processing.py
+++ b/mediagoblin/media_types/ascii/processing.py
@@ -15,7 +15,10 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import chardet
import os
-import Image
+try:
+ from PIL import Image
+except ImportError:
+ import Image
import logging
from mediagoblin import mg_globals as mgg
@@ -25,24 +28,26 @@ from mediagoblin.media_types.ascii import asciitoimage
_log = logging.getLogger(__name__)
SUPPORTED_EXTENSIONS = ['txt', 'asc', 'nfo']
+MEDIA_TYPE = 'mediagoblin.media_types.ascii'
def sniff_handler(media_file, **kw):
+ _log.info('Sniffing {0}'.format(MEDIA_TYPE))
if kw.get('media') is not None:
name, ext = os.path.splitext(kw['media'].filename)
clean_ext = ext[1:].lower()
if clean_ext in SUPPORTED_EXTENSIONS:
- return True
+ return MEDIA_TYPE
- return False
+ return None
def process_ascii(proc_state):
"""Code to process a txt file. Will be run by celery.
A Workbench() represents a local tempory dir. It is automatically
- cleaned up when this function exits.
+ cleaned up when this function exits.
"""
entry = proc_state.entry
workbench = proc_state.workbench
@@ -127,8 +132,14 @@ def process_ascii(proc_state):
'ascii',
'xmlcharrefreplace'))
- mgg.queue_store.delete_file(queued_filepath)
+ # Remove queued media file from storage and database.
+ # queued_filepath is in the task_id directory which should
+ # be removed too, but fail if the directory is not empty to be on
+ # the super-safe side.
+ mgg.queue_store.delete_file(queued_filepath) # rm file
+ mgg.queue_store.delete_dir(queued_filepath[:-1]) # rm dir
entry.queued_media_file = []
+
media_files_dict = entry.setdefault('media_files', {})
media_files_dict['thumb'] = thumb_filepath
media_files_dict['unicode'] = unicode_filepath
diff --git a/mediagoblin/media_types/audio/__init__.py b/mediagoblin/media_types/audio/__init__.py
index 4f3ead60..c7ed8d2d 100644
--- a/mediagoblin/media_types/audio/__init__.py
+++ b/mediagoblin/media_types/audio/__init__.py
@@ -14,12 +14,35 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
+from mediagoblin.media_types import MediaManagerBase
from mediagoblin.media_types.audio.processing import process_audio, \
sniff_handler
+from mediagoblin.tools import pluginapi
-MEDIA_MANAGER = {
- 'human_readable': 'Audio',
- 'processor': process_audio,
+# Why isn't .ogg in this list? It's still detected, but via sniffing,
+# .ogg files could be either video or audio... sniffing determines which.
+
+ACCEPTED_EXTENSIONS = ["mp3", "flac", "wav", "m4a"]
+MEDIA_TYPE = 'mediagoblin.media_types.audio'
+
+
+def setup_plugin():
+ config = pluginapi.get_config(MEDIA_TYPE)
+
+
+class AudioMediaManager(MediaManagerBase):
+ human_readable = "Audio"
+ processor = staticmethod(process_audio)
+ display_template = "mediagoblin/media_displays/audio.html"
+
+
+def get_media_type_and_manager(ext):
+ if ext in ACCEPTED_EXTENSIONS:
+ return MEDIA_TYPE, AudioMediaManager
+
+hooks = {
+ 'setup': setup_plugin,
+ 'get_media_type_and_manager': get_media_type_and_manager,
'sniff_handler': sniff_handler,
- 'display_template': 'mediagoblin/media_displays/audio.html',
- 'accepted_extensions': ['mp3', 'flac', 'wav', 'm4a']}
+ ('media_manager', MEDIA_TYPE): lambda: AudioMediaManager,
+}
diff --git a/mediagoblin/media_types/audio/processing.py b/mediagoblin/media_types/audio/processing.py
index 5dffcaf9..22383bc1 100644
--- a/mediagoblin/media_types/audio/processing.py
+++ b/mediagoblin/media_types/audio/processing.py
@@ -27,19 +27,22 @@ from mediagoblin.media_types.audio.transcoders import (AudioTranscoder,
_log = logging.getLogger(__name__)
+MEDIA_TYPE = 'mediagoblin.media_types.audio'
+
def sniff_handler(media_file, **kw):
+ _log.info('Sniffing {0}'.format(MEDIA_TYPE))
try:
transcoder = AudioTranscoder()
data = transcoder.discover(media_file.name)
except BadMediaFail:
_log.debug('Audio discovery raised BadMediaFail')
- return False
+ return None
if data.is_audio == True and data.is_video == False:
- return True
+ return MEDIA_TYPE
- return False
+ return None
def process_audio(proc_state):
@@ -147,4 +150,10 @@ def process_audio(proc_state):
else:
entry.media_files['thumb'] = ['fake', 'thumb', 'path.jpg']
- mgg.queue_store.delete_file(queued_filepath)
+ # Remove queued media file from storage and database.
+ # queued_filepath is in the task_id directory which should
+ # be removed too, but fail if the directory is not empty to be on
+ # the super-safe side.
+ mgg.queue_store.delete_file(queued_filepath) # rm file
+ mgg.queue_store.delete_dir(queued_filepath[:-1]) # rm dir
+ entry.queued_media_file = []
diff --git a/mediagoblin/media_types/audio/spectrogram.py b/mediagoblin/media_types/audio/spectrogram.py
index 458855c1..dd4d0299 100644
--- a/mediagoblin/media_types/audio/spectrogram.py
+++ b/mediagoblin/media_types/audio/spectrogram.py
@@ -19,7 +19,10 @@
# Bram de Jong <bram.dejong at domain.com where domain in gmail>
# 2012, Joar Wandborg <first name at last name dot se>
-from PIL import Image
+try:
+ from PIL import Image
+except ImportError:
+ import Image
import math
import numpy
diff --git a/mediagoblin/media_types/audio/transcoders.py b/mediagoblin/media_types/audio/transcoders.py
index 3a9a2125..84e6af7e 100644
--- a/mediagoblin/media_types/audio/transcoders.py
+++ b/mediagoblin/media_types/audio/transcoders.py
@@ -15,7 +15,10 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
-import Image
+try:
+ from PIL import Image
+except ImportError:
+ import Image
from mediagoblin.processing import BadMediaFail
from mediagoblin.media_types.audio import audioprocessing
diff --git a/mediagoblin/media_types/image/__init__.py b/mediagoblin/media_types/image/__init__.py
index 3e167db1..1bb9c6f3 100644
--- a/mediagoblin/media_types/image/__init__.py
+++ b/mediagoblin/media_types/image/__init__.py
@@ -13,20 +13,60 @@
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
+import datetime
+from mediagoblin.media_types import MediaManagerBase
from mediagoblin.media_types.image.processing import process_image, \
sniff_handler
+from mediagoblin.tools import pluginapi
-MEDIA_MANAGER = {
- "human_readable": "Image",
- "processor": process_image, # alternately a string,
- # 'mediagoblin.media_types.image.processing'?
- "sniff_handler": sniff_handler,
- "display_template": "mediagoblin/media_displays/image.html",
- "default_thumb": "images/media_thumbs/image.png",
- "accepted_extensions": ["jpg", "jpeg", "png", "gif", "tiff"],
+ACCEPTED_EXTENSIONS = ["jpg", "jpeg", "png", "gif", "tiff"]
+MEDIA_TYPE = 'mediagoblin.media_types.image'
- # Used by the media_entry.get_display_media method
- "media_fetch_order": [u'medium', u'original', u'thumb'],
+
+def setup_plugin():
+ config = pluginapi.get_config('mediagoblin.media_types.image')
+
+
+class ImageMediaManager(MediaManagerBase):
+ human_readable = "Image"
+ processor = staticmethod(process_image)
+ display_template = "mediagoblin/media_displays/image.html"
+ default_thumb = "images/media_thumbs/image.png"
+
+ media_fetch_order = [u'medium', u'original', u'thumb']
+
+ def get_original_date(self):
+ """
+ Get the original date and time from the EXIF information. Returns
+ either a datetime object or None (if anything goes wrong)
+ """
+ if not self.entry.media_data or not self.entry.media_data.exif_all:
+ return None
+
+ try:
+ # Try wrapped around all since exif_all might be none,
+ # EXIF DateTimeOriginal or printable might not exist
+ # or strptime might not be able to parse date correctly
+ exif_date = self.entry.media_data.exif_all[
+ 'EXIF DateTimeOriginal']['printable']
+ original_date = datetime.datetime.strptime(
+ exif_date,
+ '%Y:%m:%d %H:%M:%S')
+ return original_date
+ except (KeyError, ValueError):
+ return None
+
+
+def get_media_type_and_manager(ext):
+ if ext in ACCEPTED_EXTENSIONS:
+ return MEDIA_TYPE, ImageMediaManager
+
+
+hooks = {
+ 'setup': setup_plugin,
+ 'get_media_type_and_manager': get_media_type_and_manager,
+ 'sniff_handler': sniff_handler,
+ ('media_manager', MEDIA_TYPE): lambda: ImageMediaManager,
}
diff --git a/mediagoblin/media_types/image/processing.py b/mediagoblin/media_types/image/processing.py
index ca88d3f4..baf2ac7e 100644
--- a/mediagoblin/media_types/image/processing.py
+++ b/mediagoblin/media_types/image/processing.py
@@ -14,13 +14,15 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-import Image
+try:
+ from PIL import Image
+except ImportError:
+ import Image
import os
import logging
from mediagoblin import mg_globals as mgg
-from mediagoblin.processing import BadMediaFail, \
- create_pub_filepath, FilenameBuilder
+from mediagoblin.processing import BadMediaFail, FilenameBuilder
from mediagoblin.tools.exif import exif_fix_image_orientation, \
extract_exif, clean_exif, get_gps_data, get_useful, \
exif_image_needs_rotation
@@ -33,30 +35,28 @@ PIL_FILTERS = {
'BICUBIC': Image.BICUBIC,
'ANTIALIAS': Image.ANTIALIAS}
+MEDIA_TYPE = 'mediagoblin.media_types.image'
-def resize_image(entry, filename, new_path, exif_tags, workdir, new_size,
- size_limits=(0, 0)):
+
+def resize_image(proc_state, resized, keyname, target_name, new_size,
+ exif_tags, workdir):
"""
Store a resized version of an image and return its pathname.
Arguments:
- entry -- the entry for the image to resize
- filename -- the filename of the original image being resized
- new_path -- public file path for the new resized image
+ proc_state -- the processing state for the image to resize
+ resized -- an image from Image.open() of the original image being resized
+ keyname -- Under what key to save in the db.
+ target_name -- public file path for the new resized image
exif_tags -- EXIF data for the original image
workdir -- directory path for storing converted image files
new_size -- 2-tuple size for the resized image
"""
- try:
- resized = Image.open(filename)
- except IOError:
- raise BadMediaFail()
- resized = exif_fix_image_orientation(resized, exif_tags) # Fix orientation
+ config = mgg.global_config['media_type:mediagoblin.media_types.image']
- filter_config = \
- mgg.global_config['media_type:mediagoblin.media_types.image']\
- ['resize_filter']
+ resized = exif_fix_image_orientation(resized, exif_tags) # Fix orientation
+ filter_config = config['resize_filter']
try:
resize_filter = PIL_FILTERS[filter_config.upper()]
except KeyError:
@@ -67,23 +67,48 @@ def resize_image(entry, filename, new_path, exif_tags, workdir, new_size,
resized.thumbnail(new_size, resize_filter)
# Copy the new file to the conversion subdir, then remotely.
- tmp_resized_filename = os.path.join(workdir, new_path[-1])
+ tmp_resized_filename = os.path.join(workdir, target_name)
with file(tmp_resized_filename, 'w') as resized_file:
- resized.save(resized_file)
- mgg.public_store.copy_local_to_storage(tmp_resized_filename, new_path)
+ resized.save(resized_file, quality=config['quality'])
+ proc_state.store_public(keyname, tmp_resized_filename, target_name)
+
+
+def resize_tool(proc_state, force, keyname, target_name,
+ conversions_subdir, exif_tags):
+ # filename -- the filename of the original image being resized
+ filename = proc_state.get_queued_filename()
+ max_width = mgg.global_config['media:' + keyname]['max_width']
+ max_height = mgg.global_config['media:' + keyname]['max_height']
+ # If the size of the original file exceeds the specified size for the desized
+ # file, a target_name file is created and later associated with the media
+ # entry.
+ # Also created if the file needs rotation, or if forced.
+ try:
+ im = Image.open(filename)
+ except IOError:
+ raise BadMediaFail()
+ if force \
+ or im.size[0] > max_width \
+ or im.size[1] > max_height \
+ or exif_image_needs_rotation(exif_tags):
+ resize_image(
+ proc_state, im, unicode(keyname), target_name,
+ (max_width, max_height),
+ exif_tags, conversions_subdir)
-SUPPORTED_FILETYPES = ['png', 'gif', 'jpg', 'jpeg']
+SUPPORTED_FILETYPES = ['png', 'gif', 'jpg', 'jpeg', 'tiff']
def sniff_handler(media_file, **kw):
+ _log.info('Sniffing {0}'.format(MEDIA_TYPE))
if kw.get('media') is not None: # That's a double negative!
name, ext = os.path.splitext(kw['media'].filename)
clean_ext = ext[1:].lower() # Strip the . from ext and make lowercase
if clean_ext in SUPPORTED_FILETYPES:
_log.info('Found file extension in supported filetypes')
- return True
+ return MEDIA_TYPE
else:
_log.debug('Media present, extension not found in {0}'.format(
SUPPORTED_FILETYPES))
@@ -91,7 +116,7 @@ def sniff_handler(media_file, **kw):
_log.warning('Need additional information (keyword argument \'media\')'
' to be able to handle sniffing')
- return False
+ return None
def process_image(proc_state):
@@ -116,29 +141,14 @@ def process_image(proc_state):
gps_data = get_gps_data(exif_tags)
# Always create a small thumbnail
- thumb_filepath = create_pub_filepath(
- entry, name_builder.fill('{basename}.thumbnail{ext}'))
- resize_image(entry, queued_filename, thumb_filepath,
- exif_tags, conversions_subdir,
- (mgg.global_config['media:thumb']['max_width'],
- mgg.global_config['media:thumb']['max_height']))
-
- # If the size of the original file exceeds the specified size of a `medium`
- # file, a `.medium.jpg` files is created and later associated with the media
- # entry.
- medium = Image.open(queued_filename)
- if medium.size[0] > mgg.global_config['media:medium']['max_width'] \
- or medium.size[1] > mgg.global_config['media:medium']['max_height'] \
- or exif_image_needs_rotation(exif_tags):
- medium_filepath = create_pub_filepath(
- entry, name_builder.fill('{basename}.medium{ext}'))
- resize_image(
- entry, queued_filename, medium_filepath,
- exif_tags, conversions_subdir,
- (mgg.global_config['media:medium']['max_width'],
- mgg.global_config['media:medium']['max_height']))
- else:
- medium_filepath = None
+ resize_tool(proc_state, True, 'thumb',
+ name_builder.fill('{basename}.thumbnail{ext}'),
+ conversions_subdir, exif_tags)
+
+ # Possibly create a medium
+ resize_tool(proc_state, False, 'medium',
+ name_builder.fill('{basename}.medium{ext}'),
+ conversions_subdir, exif_tags)
# Copy our queued local workbench to its final destination
proc_state.copy_original(name_builder.fill('{basename}{ext}'))
@@ -146,12 +156,6 @@ def process_image(proc_state):
# Remove queued media file from storage and database
proc_state.delete_queue_file()
- # Insert media file information into database
- media_files_dict = entry.setdefault('media_files', {})
- media_files_dict[u'thumb'] = thumb_filepath
- if medium_filepath:
- media_files_dict[u'medium'] = medium_filepath
-
# Insert exif data into database
exif_all = clean_exif(exif_tags)
diff --git a/mediagoblin/media_types/pdf/__init__.py b/mediagoblin/media_types/pdf/__init__.py
new file mode 100644
index 00000000..67509ddc
--- /dev/null
+++ b/mediagoblin/media_types/pdf/__init__.py
@@ -0,0 +1,47 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+from mediagoblin.media_types import MediaManagerBase
+from mediagoblin.media_types.pdf.processing import process_pdf, \
+ sniff_handler
+from mediagoblin.tools import pluginapi
+
+ACCEPTED_EXTENSIONS = ['pdf']
+MEDIA_TYPE = 'mediagoblin.media_types.pdf'
+
+
+def setup_plugin():
+ config = pluginapi.get_config(MEDIA_TYPE)
+
+
+class PDFMediaManager(MediaManagerBase):
+ human_readable = "PDF"
+ processor = staticmethod(process_pdf)
+ display_template = "mediagoblin/media_displays/pdf.html"
+ default_thumb = "images/media_thumbs/pdf.jpg"
+
+
+def get_media_type_and_manager(ext):
+ if ext in ACCEPTED_EXTENSIONS:
+ return MEDIA_TYPE, PDFMediaManager
+
+
+hooks = {
+ 'setup': setup_plugin,
+ 'get_media_type_and_manager': get_media_type_and_manager,
+ 'sniff_handler': sniff_handler,
+ ('media_manager', MEDIA_TYPE): lambda: PDFMediaManager,
+}
diff --git a/mediagoblin/media_types/pdf/migrations.py b/mediagoblin/media_types/pdf/migrations.py
new file mode 100644
index 00000000..f54c23ea
--- /dev/null
+++ b/mediagoblin/media_types/pdf/migrations.py
@@ -0,0 +1,17 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+MIGRATIONS = {}
diff --git a/mediagoblin/media_types/pdf/models.py b/mediagoblin/media_types/pdf/models.py
new file mode 100644
index 00000000..c39262d1
--- /dev/null
+++ b/mediagoblin/media_types/pdf/models.py
@@ -0,0 +1,58 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+
+from mediagoblin.db.base import Base
+
+from sqlalchemy import (
+ Column, Float, Integer, String, DateTime, ForeignKey)
+from sqlalchemy.orm import relationship, backref
+
+
+BACKREF_NAME = "pdf__media_data"
+
+
+class PdfData(Base):
+ __tablename__ = "pdf__mediadata"
+
+ # The primary key *and* reference to the main media_entry
+ media_entry = Column(Integer, ForeignKey('core__media_entries.id'),
+ primary_key=True)
+ get_media_entry = relationship("MediaEntry",
+ backref=backref(BACKREF_NAME, uselist=False,
+ cascade="all, delete-orphan"))
+ pages = Column(Integer)
+
+ # These are taken from what pdfinfo can do, perhaps others make sense too
+ pdf_author = Column(String)
+ pdf_title = Column(String)
+ # note on keywords: this is the pdf parsed string, it should be considered a cached
+ # value like the rest of these values, since they can be deduced at query time / client
+ # side too.
+ pdf_keywords = Column(String)
+ pdf_creator = Column(String)
+ pdf_producer = Column(String)
+ pdf_creation_date = Column(DateTime)
+ pdf_modified_date = Column(DateTime)
+ pdf_version_major = Column(Integer)
+ pdf_version_minor = Column(Integer)
+ pdf_page_size_width = Column(Float) # unit: pts
+ pdf_page_size_height = Column(Float)
+ pdf_pages = Column(Integer)
+
+
+DATA_MODEL = PdfData
+MODELS = [PdfData]
diff --git a/mediagoblin/media_types/pdf/processing.py b/mediagoblin/media_types/pdf/processing.py
new file mode 100644
index 00000000..f35b4376
--- /dev/null
+++ b/mediagoblin/media_types/pdf/processing.py
@@ -0,0 +1,280 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+import os
+import logging
+import dateutil.parser
+from subprocess import PIPE, Popen
+
+from mediagoblin import mg_globals as mgg
+from mediagoblin.processing import (create_pub_filepath,
+ FilenameBuilder, BadMediaFail)
+from mediagoblin.tools.translate import fake_ugettext_passthrough as _
+
+_log = logging.getLogger(__name__)
+
+MEDIA_TYPE = 'mediagoblin.media_types.pdf'
+
+# TODO - cache (memoize) util
+
+# This is a list created via uniconv --show and hand removing some types that
+# we already support via other media types better.
+unoconv_supported = [
+ 'bib', # - BibTeX [.bib]
+ #bmp - Windows Bitmap [.bmp]
+ 'csv', # - Text CSV [.csv]
+ 'dbf', # - dBASE [.dbf]
+ 'dif', # - Data Interchange Format [.dif]
+ 'doc6', # - Microsoft Word 6.0 [.doc]
+ 'doc95', # - Microsoft Word 95 [.doc]
+ 'docbook', # - DocBook [.xml]
+ 'doc', # - Microsoft Word 97/2000/XP [.doc]
+ 'docx7', # - Microsoft Office Open XML [.docx]
+ 'docx', # - Microsoft Office Open XML [.docx]
+ #emf - Enhanced Metafile [.emf]
+ 'eps', # - Encapsulated PostScript [.eps]
+ 'fodp', # - OpenDocument Presentation (Flat XML) [.fodp]
+ 'fods', # - OpenDocument Spreadsheet (Flat XML) [.fods]
+ 'fodt', # - OpenDocument Text (Flat XML) [.fodt]
+ #gif - Graphics Interchange Format [.gif]
+ 'html', # - HTML Document (OpenOffice.org Writer) [.html]
+ #jpg - Joint Photographic Experts Group [.jpg]
+ 'latex', # - LaTeX 2e [.ltx]
+ 'mediawiki', # - MediaWiki [.txt]
+ 'met', # - OS/2 Metafile [.met]
+ 'odd', # - OpenDocument Drawing [.odd]
+ 'odg', # - ODF Drawing (Impress) [.odg]
+ 'odp', # - ODF Presentation [.odp]
+ 'ods', # - ODF Spreadsheet [.ods]
+ 'odt', # - ODF Text Document [.odt]
+ 'ooxml', # - Microsoft Office Open XML [.xml]
+ 'otg', # - OpenDocument Drawing Template [.otg]
+ 'otp', # - ODF Presentation Template [.otp]
+ 'ots', # - ODF Spreadsheet Template [.ots]
+ 'ott', # - Open Document Text [.ott]
+ #pbm - Portable Bitmap [.pbm]
+ #pct - Mac Pict [.pct]
+ 'pdb', # - AportisDoc (Palm) [.pdb]
+ #pdf - Portable Document Format [.pdf]
+ #pgm - Portable Graymap [.pgm]
+ #png - Portable Network Graphic [.png]
+ 'pot', # - Microsoft PowerPoint 97/2000/XP Template [.pot]
+ 'potm', # - Microsoft PowerPoint 2007/2010 XML Template [.potm]
+ #ppm - Portable Pixelmap [.ppm]
+ 'pps', # - Microsoft PowerPoint 97/2000/XP (Autoplay) [.pps]
+ 'ppt', # - Microsoft PowerPoint 97/2000/XP [.ppt]
+ 'pptx', # - Microsoft PowerPoint 2007/2010 XML [.pptx]
+ 'psw', # - Pocket Word [.psw]
+ 'pwp', # - PlaceWare [.pwp]
+ 'pxl', # - Pocket Excel [.pxl]
+ #ras - Sun Raster Image [.ras]
+ 'rtf', # - Rich Text Format [.rtf]
+ 'sda', # - StarDraw 5.0 (OpenOffice.org Impress) [.sda]
+ 'sdc3', # - StarCalc 3.0 [.sdc]
+ 'sdc4', # - StarCalc 4.0 [.sdc]
+ 'sdc', # - StarCalc 5.0 [.sdc]
+ 'sdd3', # - StarDraw 3.0 (OpenOffice.org Impress) [.sdd]
+ 'sdd4', # - StarImpress 4.0 [.sdd]
+ 'sdd', # - StarImpress 5.0 [.sdd]
+ 'sdw3', # - StarWriter 3.0 [.sdw]
+ 'sdw4', # - StarWriter 4.0 [.sdw]
+ 'sdw', # - StarWriter 5.0 [.sdw]
+ 'slk', # - SYLK [.slk]
+ 'stc', # - OpenOffice.org 1.0 Spreadsheet Template [.stc]
+ 'std', # - OpenOffice.org 1.0 Drawing Template [.std]
+ 'sti', # - OpenOffice.org 1.0 Presentation Template [.sti]
+ 'stw', # - Open Office.org 1.0 Text Document Template [.stw]
+ #svg - Scalable Vector Graphics [.svg]
+ 'svm', # - StarView Metafile [.svm]
+ 'swf', # - Macromedia Flash (SWF) [.swf]
+ 'sxc', # - OpenOffice.org 1.0 Spreadsheet [.sxc]
+ 'sxd3', # - StarDraw 3.0 [.sxd]
+ 'sxd5', # - StarDraw 5.0 [.sxd]
+ 'sxd', # - OpenOffice.org 1.0 Drawing (OpenOffice.org Impress) [.sxd]
+ 'sxi', # - OpenOffice.org 1.0 Presentation [.sxi]
+ 'sxw', # - Open Office.org 1.0 Text Document [.sxw]
+ #text - Text Encoded [.txt]
+ #tiff - Tagged Image File Format [.tiff]
+ #txt - Text [.txt]
+ 'uop', # - Unified Office Format presentation [.uop]
+ 'uos', # - Unified Office Format spreadsheet [.uos]
+ 'uot', # - Unified Office Format text [.uot]
+ 'vor3', # - StarDraw 3.0 Template (OpenOffice.org Impress) [.vor]
+ 'vor4', # - StarWriter 4.0 Template [.vor]
+ 'vor5', # - StarDraw 5.0 Template (OpenOffice.org Impress) [.vor]
+ 'vor', # - StarCalc 5.0 Template [.vor]
+ #wmf - Windows Metafile [.wmf]
+ 'xhtml', # - XHTML Document [.html]
+ 'xls5', # - Microsoft Excel 5.0 [.xls]
+ 'xls95', # - Microsoft Excel 95 [.xls]
+ 'xls', # - Microsoft Excel 97/2000/XP [.xls]
+ 'xlt5', # - Microsoft Excel 5.0 Template [.xlt]
+ 'xlt95', # - Microsoft Excel 95 Template [.xlt]
+ 'xlt', # - Microsoft Excel 97/2000/XP Template [.xlt]
+ #xpm - X PixMap [.xpm]
+]
+
+def is_unoconv_working():
+ # TODO: must have libreoffice-headless installed too, need to check for it
+ unoconv = where('unoconv')
+ if not unoconv:
+ return False
+ try:
+ proc = Popen([unoconv, '--show'], stderr=PIPE)
+ output = proc.stderr.read()
+ except OSError, e:
+ _log.warn(_('unoconv failing to run, check log file'))
+ return False
+ if 'ERROR' in output:
+ return False
+ return True
+
+def supported_extensions(cache=[None]):
+ if cache[0] == None:
+ cache[0] = 'pdf'
+ if is_unoconv_working():
+ cache.extend(unoconv_supported)
+ return cache
+
+def where(name):
+ for p in os.environ['PATH'].split(os.pathsep):
+ fullpath = os.path.join(p, name)
+ if os.path.exists(fullpath):
+ return fullpath
+ return None
+
+def check_prerequisites():
+ if not where('pdfinfo'):
+ _log.warn('missing pdfinfo')
+ return False
+ if not where('pdftocairo'):
+ _log.warn('missing pdfcairo')
+ return False
+ return True
+
+def sniff_handler(media_file, **kw):
+ _log.info('Sniffing {0}'.format(MEDIA_TYPE))
+ if not check_prerequisites():
+ return None
+ if kw.get('media') is not None:
+ name, ext = os.path.splitext(kw['media'].filename)
+ clean_ext = ext[1:].lower()
+
+ if clean_ext in supported_extensions():
+ return MEDIA_TYPE
+
+ return None
+
+def create_pdf_thumb(original, thumb_filename, width, height):
+ # Note: pdftocairo adds '.png', remove it
+ thumb_filename = thumb_filename[:-4]
+ executable = where('pdftocairo')
+ args = [executable, '-scale-to', str(min(width, height)),
+ '-singlefile', '-png', original, thumb_filename]
+ _log.debug('calling {0}'.format(repr(' '.join(args))))
+ Popen(executable=executable, args=args).wait()
+
+def pdf_info(original):
+ """
+ Extract dictionary of pdf information. This could use a library instead
+ of a process.
+
+ Note: I'm assuming pdfinfo output is sanitized (integers where integers are
+ expected, etc.) - if this is wrong then an exception will be raised and caught
+ leading to the dreaded error page. It seems a safe assumption.
+ """
+ ret_dict = {}
+ pdfinfo = where('pdfinfo')
+ try:
+ proc = Popen(executable=pdfinfo,
+ args=[pdfinfo, original], stdout=PIPE)
+ lines = proc.stdout.readlines()
+ except OSError:
+ _log.debug('pdfinfo could not read the pdf file.')
+ raise BadMediaFail()
+
+ info_dict = dict([[part.strip() for part in l.strip().split(':', 1)]
+ for l in lines if ':' in l])
+
+ for date_key in [('pdf_mod_date', 'ModDate'),
+ ('pdf_creation_date', 'CreationDate')]:
+ if date_key in info_dict:
+ ret_dict[date_key] = dateutil.parser.parse(info_dict[date_key])
+ for db_key, int_key in [('pdf_pages', 'Pages')]:
+ if int_key in info_dict:
+ ret_dict[db_key] = int(info_dict[int_key])
+
+ # parse 'PageSize' field: 595 x 842 pts (A4)
+ page_size_parts = info_dict['Page size'].split()
+ ret_dict['pdf_page_size_width'] = float(page_size_parts[0])
+ ret_dict['pdf_page_size_height'] = float(page_size_parts[2])
+
+ for db_key, str_key in [('pdf_keywords', 'Keywords'),
+ ('pdf_creator', 'Creator'), ('pdf_producer', 'Producer'),
+ ('pdf_author', 'Author'), ('pdf_title', 'Title')]:
+ ret_dict[db_key] = info_dict.get(str_key, None)
+ ret_dict['pdf_version_major'], ret_dict['pdf_version_minor'] = \
+ map(int, info_dict['PDF version'].split('.'))
+
+ return ret_dict
+
+def process_pdf(proc_state):
+ """Code to process a pdf file. Will be run by celery.
+
+ A Workbench() represents a local tempory dir. It is automatically
+ cleaned up when this function exits.
+ """
+ entry = proc_state.entry
+ workbench = proc_state.workbench
+
+ queued_filename = proc_state.get_queued_filename()
+ name_builder = FilenameBuilder(queued_filename)
+
+ # Copy our queued local workbench to its final destination
+ original_dest = name_builder.fill('{basename}{ext}')
+ proc_state.copy_original(original_dest)
+
+ # Create a pdf if this is a different doc, store pdf for viewer
+ ext = queued_filename.rsplit('.', 1)[-1].lower()
+ if ext == 'pdf':
+ pdf_filename = queued_filename
+ else:
+ pdf_filename = queued_filename.rsplit('.', 1)[0] + '.pdf'
+ unoconv = where('unoconv')
+ Popen(executable=unoconv,
+ args=[unoconv, '-v', '-f', 'pdf', queued_filename]).wait()
+ if not os.path.exists(pdf_filename):
+ _log.debug('unoconv failed to convert file to pdf')
+ raise BadMediaFail()
+ proc_state.store_public(keyname=u'pdf', local_file=pdf_filename)
+
+ pdf_info_dict = pdf_info(pdf_filename)
+
+ for name, width, height in [
+ (u'thumb', mgg.global_config['media:thumb']['max_width'],
+ mgg.global_config['media:thumb']['max_height']),
+ (u'medium', mgg.global_config['media:medium']['max_width'],
+ mgg.global_config['media:medium']['max_height']),
+ ]:
+ filename = name_builder.fill('{basename}.%s.png' % name)
+ path = workbench.joinpath(filename)
+ create_pdf_thumb(pdf_filename, path, width, height)
+ assert(os.path.exists(path))
+ proc_state.store_public(keyname=name, local_file=path)
+
+ proc_state.delete_queue_file()
+
+ entry.media_data_init(**pdf_info_dict)
+ entry.save()
diff --git a/mediagoblin/media_types/stl/__init__.py b/mediagoblin/media_types/stl/__init__.py
index edffc633..1d2a8478 100644
--- a/mediagoblin/media_types/stl/__init__.py
+++ b/mediagoblin/media_types/stl/__init__.py
@@ -14,14 +14,33 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
+from mediagoblin.media_types import MediaManagerBase
from mediagoblin.media_types.stl.processing import process_stl, \
sniff_handler
+from mediagoblin.tools import pluginapi
+MEDIA_TYPE = 'mediagoblin.media_types.stl'
+ACCEPTED_EXTENSIONS = ["obj", "stl"]
-MEDIA_MANAGER = {
- "human_readable": "stereo lithographics",
- "processor": process_stl,
- "sniff_handler": sniff_handler,
- "display_template": "mediagoblin/media_displays/stl.html",
- "default_thumb": "images/media_thumbs/video.jpg",
- "accepted_extensions": ["obj", "stl"]}
+
+def setup_plugin():
+ config = pluginapi.get_config(MEDIA_TYPE)
+
+
+class STLMediaManager(MediaManagerBase):
+ human_readable = "stereo lithographics"
+ processor = staticmethod(process_stl)
+ display_template = "mediagoblin/media_displays/stl.html"
+ default_thumb = "images/media_thumbs/video.jpg"
+
+
+def get_media_type_and_manager(ext):
+ if ext in ACCEPTED_EXTENSIONS:
+ return MEDIA_TYPE, STLMediaManager
+
+hooks = {
+ 'setup': setup_plugin,
+ 'get_media_type_and_manager': get_media_type_and_manager,
+ 'sniff_handler': sniff_handler,
+ ('media_manager', MEDIA_TYPE): lambda: STLMediaManager,
+}
diff --git a/mediagoblin/media_types/stl/model_loader.py b/mediagoblin/media_types/stl/model_loader.py
index 60fa4851..88f19314 100644
--- a/mediagoblin/media_types/stl/model_loader.py
+++ b/mediagoblin/media_types/stl/model_loader.py
@@ -80,6 +80,7 @@ class ObjModel(ThreeDee):
def load(self, fileob):
for line in fileob:
+ line = line.strip()
if line[0] == "v":
self.verts.append(self.__vector(line))
@@ -121,6 +122,8 @@ def auto_detect(fileob, hint):
pass
except ValueError:
pass
+ except IndexError:
+ pass
try:
# It is pretty important that the binary stl model loader
# is tried second, because its possible for it to parse
diff --git a/mediagoblin/media_types/stl/processing.py b/mediagoblin/media_types/stl/processing.py
index 77744ac5..53751416 100644
--- a/mediagoblin/media_types/stl/processing.py
+++ b/mediagoblin/media_types/stl/processing.py
@@ -29,6 +29,7 @@ from mediagoblin.media_types.stl import model_loader
_log = logging.getLogger(__name__)
SUPPORTED_FILETYPES = ['stl', 'obj']
+MEDIA_TYPE = 'mediagoblin.media_types.stl'
BLEND_FILE = pkg_resources.resource_filename(
'mediagoblin.media_types.stl',
@@ -43,13 +44,14 @@ BLEND_SCRIPT = pkg_resources.resource_filename(
def sniff_handler(media_file, **kw):
+ _log.info('Sniffing {0}'.format(MEDIA_TYPE))
if kw.get('media') is not None:
name, ext = os.path.splitext(kw['media'].filename)
clean_ext = ext[1:].lower()
-
+
if clean_ext in SUPPORTED_FILETYPES:
_log.info('Found file extension in supported filetypes')
- return True
+ return MEDIA_TYPE
else:
_log.debug('Media present, extension not found in {0}'.format(
SUPPORTED_FILETYPES))
@@ -57,15 +59,13 @@ def sniff_handler(media_file, **kw):
_log.warning('Need additional information (keyword argument \'media\')'
' to be able to handle sniffing')
- return False
+ return None
def blender_render(config):
"""
Called to prerender a model.
"""
- arg_string = "blender -b blender_render.blend -F "
- arg_string +="JPEG -P blender_render.py"
env = {"RENDER_SETUP" : json.dumps(config), "DISPLAY":":0"}
subprocess.call(
["blender",
@@ -165,8 +165,12 @@ def process_stl(proc_state):
with open(queued_filename, 'rb') as queued_file:
model_file.write(queued_file.read())
- # Remove queued media file from storage and database
- mgg.queue_store.delete_file(queued_filepath)
+ # Remove queued media file from storage and database.
+ # queued_filepath is in the task_id directory which should
+ # be removed too, but fail if the directory is not empty to be on
+ # the super-safe side.
+ mgg.queue_store.delete_file(queued_filepath) # rm file
+ mgg.queue_store.delete_dir(queued_filepath[:-1]) # rm dir
entry.queued_media_file = []
# Insert media file information into database
diff --git a/mediagoblin/media_types/tools.py b/mediagoblin/media_types/tools.py
new file mode 100644
index 00000000..fe7b3772
--- /dev/null
+++ b/mediagoblin/media_types/tools.py
@@ -0,0 +1,27 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+import logging
+
+from mediagoblin import mg_globals
+
+_log = logging.getLogger(__name__)
+
+
+def media_type_warning():
+ if mg_globals.app_config.get('media_types'):
+ _log.warning('Media_types have been converted to plugins. Old'
+ ' media_types will no longer work. Please convert them'
+ ' to plugins to continue using them.')
diff --git a/mediagoblin/media_types/video/__init__.py b/mediagoblin/media_types/video/__init__.py
index fab601f6..e8a4308b 100644
--- a/mediagoblin/media_types/video/__init__.py
+++ b/mediagoblin/media_types/video/__init__.py
@@ -14,21 +14,38 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
+from mediagoblin.media_types import MediaManagerBase
from mediagoblin.media_types.video.processing import process_video, \
sniff_handler
+from mediagoblin.tools import pluginapi
+MEDIA_TYPE = 'mediagoblin.media_types.video'
+ACCEPTED_EXTENSIONS = [
+ "mp4", "mov", "webm", "avi", "3gp", "3gpp", "mkv", "ogv", "m4v"]
-MEDIA_MANAGER = {
- "human_readable": "Video",
- "processor": process_video, # alternately a string,
- # 'mediagoblin.media_types.image.processing'?
- "sniff_handler": sniff_handler,
- "display_template": "mediagoblin/media_displays/video.html",
- "default_thumb": "images/media_thumbs/video.jpg",
- "accepted_extensions": [
- "mp4", "mov", "webm", "avi", "3gp", "3gpp", "mkv", "ogv", "m4v"],
+
+def setup_plugin():
+ config = pluginapi.get_config(MEDIA_TYPE)
+
+
+class VideoMediaManager(MediaManagerBase):
+ human_readable = "Video"
+ processor = staticmethod(process_video)
+ display_template = "mediagoblin/media_displays/video.html"
+ default_thumb = "images/media_thumbs/video.jpg"
# Used by the media_entry.get_display_media method
- "media_fetch_order": [u'webm_640', u'original'],
- "default_webm_type": 'video/webm; codecs="vp8, vorbis"',
+ media_fetch_order = [u'webm_640', u'original']
+ default_webm_type = 'video/webm; codecs="vp8, vorbis"'
+
+
+def get_media_type_and_manager(ext):
+ if ext in ACCEPTED_EXTENSIONS:
+ return MEDIA_TYPE, VideoMediaManager
+
+hooks = {
+ 'setup': setup_plugin,
+ 'get_media_type_and_manager': get_media_type_and_manager,
+ 'sniff_handler': sniff_handler,
+ ('media_manager', MEDIA_TYPE): lambda: VideoMediaManager,
}
diff --git a/mediagoblin/media_types/video/models.py b/mediagoblin/media_types/video/models.py
index f696a892..0b52c53f 100644
--- a/mediagoblin/media_types/video/models.py
+++ b/mediagoblin/media_types/video/models.py
@@ -90,7 +90,7 @@ class VideoData(Base):
return '%s; codecs="%s, %s"' % (
mimetype, video_codec, audio_codec)
else:
- return video.MEDIA_MANAGER["default_webm_type"]
+ return video.VideoMediaManager.default_webm_type
DATA_MODEL = VideoData
diff --git a/mediagoblin/media_types/video/processing.py b/mediagoblin/media_types/video/processing.py
index ff2c94a0..5386ba60 100644
--- a/mediagoblin/media_types/video/processing.py
+++ b/mediagoblin/media_types/video/processing.py
@@ -29,6 +29,8 @@ from .util import skip_transcode
_log = logging.getLogger(__name__)
_log.setLevel(logging.DEBUG)
+MEDIA_TYPE = 'mediagoblin.media_types.video'
+
class VideoTranscodingFail(BaseProcessingFail):
'''
@@ -41,17 +43,18 @@ def sniff_handler(media_file, **kw):
transcoder = transcoders.VideoTranscoder()
data = transcoder.discover(media_file.name)
+ _log.info('Sniffing {0}'.format(MEDIA_TYPE))
_log.debug('Discovered: {0}'.format(data))
if not data:
_log.error('Could not discover {0}'.format(
kw.get('media')))
- return False
+ return None
if data['is_video'] == True:
- return True
+ return MEDIA_TYPE
- return False
+ return None
def process_video(proc_state):
@@ -186,7 +189,7 @@ def store_metadata(media_entry, metadata):
[(key, tags_metadata[key])
for key in [
"application-name", "artist", "audio-codec", "bitrate",
- "container-format", "copyright", "encoder",
+ "container-format", "copyright", "encoder",
"encoder-version", "license", "nominal-bitrate", "title",
"video-codec"]
if key in tags_metadata])
@@ -203,7 +206,7 @@ def store_metadata(media_entry, metadata):
dt.get_year(), dt.get_month(), dt.get_day(), dt.get_hour(),
dt.get_minute(), dt.get_second(),
dt.get_microsecond()).isoformat()
-
+
metadata['tags'] = tags
# Only save this field if there's something to save
diff --git a/mediagoblin/media_types/video/transcoders.py b/mediagoblin/media_types/video/transcoders.py
index d8290d41..9d6b7655 100644
--- a/mediagoblin/media_types/video/transcoders.py
+++ b/mediagoblin/media_types/video/transcoders.py
@@ -22,11 +22,20 @@ import logging
import urllib
import multiprocessing
import gobject
+
+old_argv = sys.argv
+sys.argv = []
+
import pygst
pygst.require('0.10')
import gst
+
+sys.argv = old_argv
import struct
-import Image
+try:
+ from PIL import Image
+except ImportError:
+ import Image
from gst.extend import discoverer
@@ -53,283 +62,6 @@ def pixbuf_to_pilbuf(buf):
return data
-class VideoThumbnailer:
- # Declaration of thumbnailer states
- STATE_NULL = 0
- STATE_HALTING = 1
- STATE_PROCESSING = 2
-
- # The current thumbnailer state
-
- def __init__(self, source_path, dest_path):
- '''
- Set up playbin pipeline in order to get video properties.
-
- Initializes and runs the gobject.MainLoop()
-
- Abstract
- - Set up a playbin with a fake audio sink and video sink. Load the video
- into the playbin
- - Initialize
- '''
- # This will contain the thumbnailing pipeline
- self.state = self.STATE_NULL
- self.thumbnail_pipeline = None
- self.buffer_probes = {}
- self.errors = []
-
- self.source_path = source_path
- self.dest_path = dest_path
-
- self.loop = gobject.MainLoop()
-
- # Set up the playbin. It will be used to discover certain
- # properties of the input file
- self.playbin = gst.element_factory_make('playbin')
-
- self.videosink = gst.element_factory_make('fakesink', 'videosink')
- self.playbin.set_property('video-sink', self.videosink)
-
- self.audiosink = gst.element_factory_make('fakesink', 'audiosink')
- self.playbin.set_property('audio-sink', self.audiosink)
-
- self.bus = self.playbin.get_bus()
- self.bus.add_signal_watch()
- self.watch_id = self.bus.connect('message', self._on_bus_message)
-
- self.playbin.set_property('uri', 'file:{0}'.format(
- urllib.pathname2url(self.source_path)))
-
- self.playbin.set_state(gst.STATE_PAUSED)
-
- self.run()
-
- def run(self):
- self.loop.run()
-
- def _on_bus_message(self, bus, message):
- _log.debug(' thumbnail playbin: {0}'.format(message))
-
- if message.type == gst.MESSAGE_ERROR:
- _log.error('thumbnail playbin: {0}'.format(message))
- gobject.idle_add(self._on_bus_error)
-
- elif message.type == gst.MESSAGE_STATE_CHANGED:
- # The pipeline state has changed
- # Parse state changing data
- _prev, state, _pending = message.parse_state_changed()
-
- _log.debug('State changed: {0}'.format(state))
-
- if state == gst.STATE_PAUSED:
- if message.src == self.playbin:
- gobject.idle_add(self._on_bus_paused)
-
- def _on_bus_paused(self):
- '''
- Set up thumbnailing pipeline
- '''
- current_video = self.playbin.get_property('current-video')
-
- if current_video == 0:
- _log.debug('Found current video from playbin')
- else:
- _log.error('Could not get any current video from playbin!')
-
- self.duration = self._get_duration(self.playbin)
- _log.info('Video length: {0}'.format(self.duration / gst.SECOND))
-
- _log.info('Setting up thumbnailing pipeline')
- self.thumbnail_pipeline = gst.parse_launch(
- 'filesrc location="{0}" ! decodebin ! '
- 'ffmpegcolorspace ! videoscale ! '
- 'video/x-raw-rgb,depth=24,bpp=24,pixel-aspect-ratio=1/1,width=180 ! '
- 'fakesink signal-handoffs=True'.format(self.source_path))
-
- self.thumbnail_bus = self.thumbnail_pipeline.get_bus()
- self.thumbnail_bus.add_signal_watch()
- self.thumbnail_watch_id = self.thumbnail_bus.connect(
- 'message', self._on_thumbnail_bus_message)
-
- self.thumbnail_pipeline.set_state(gst.STATE_PAUSED)
-
- #gobject.timeout_add(3000, self._on_timeout)
-
- return False
-
- def _on_thumbnail_bus_message(self, bus, message):
- _log.debug('thumbnail: {0}'.format(message))
-
- if message.type == gst.MESSAGE_ERROR:
- _log.error(message)
- gobject.idle_add(self._on_bus_error)
-
- if message.type == gst.MESSAGE_STATE_CHANGED:
- _log.debug('State changed')
- _prev, state, _pending = message.parse_state_changed()
-
- if (state == gst.STATE_PAUSED and
- not self.state == self.STATE_PROCESSING and
- message.src == self.thumbnail_pipeline):
- _log.info('Pipeline paused, processing')
- self.state = self.STATE_PROCESSING
-
- for sink in self.thumbnail_pipeline.sinks():
- name = sink.get_name()
- factoryname = sink.get_factory().get_name()
-
- if factoryname == 'fakesink':
- sinkpad = sink.get_pad('sink')
-
- self.buffer_probes[name] = sinkpad.add_buffer_probe(
- self.buffer_probe_handler, name)
-
- _log.info('Added buffer probe')
-
- break
-
- # Apply the wadsworth constant, fallback to 1 second
- # TODO: Will break if video is shorter than 1 sec
- seek_amount = max(self.duration / 100 * 30, 1 * gst.SECOND)
-
- _log.debug('seek amount: {0}'.format(seek_amount))
-
- seek_result = self.thumbnail_pipeline.seek(
- 1.0,
- gst.FORMAT_TIME,
- gst.SEEK_FLAG_FLUSH | gst.SEEK_FLAG_ACCURATE,
- gst.SEEK_TYPE_SET,
- seek_amount,
- gst.SEEK_TYPE_NONE,
- 0)
-
- if not seek_result:
- self.errors.append('COULD_NOT_SEEK')
- _log.error('Couldn\'t seek! result: {0}'.format(
- seek_result))
- _log.info(message)
- self.shutdown()
- else:
- _log.debug('Seek successful')
- self.thumbnail_pipeline.set_state(gst.STATE_PAUSED)
- else:
- _log.debug('Won\'t seek: \t{0}\n\t{1}'.format(
- self.state,
- message.src))
-
- def buffer_probe_handler_real(self, pad, buff, name):
- '''
- Capture buffers as gdk_pixbufs when told to.
- '''
- _log.info('Capturing frame')
- try:
- caps = buff.caps
- if caps is None:
- _log.error('No caps passed to buffer probe handler!')
- self.shutdown()
- return False
-
- _log.debug('caps: {0}'.format(caps))
-
- filters = caps[0]
- width = filters["width"]
- height = filters["height"]
-
- im = Image.new('RGB', (width, height))
-
- data = pixbuf_to_pilbuf(buff.data)
-
- im.putdata(data)
-
- im.save(self.dest_path)
-
- _log.info('Saved thumbnail')
-
- self.shutdown()
-
- except gst.QueryError as e:
- _log.error('QueryError: {0}'.format(e))
-
- return False
-
- def buffer_probe_handler(self, pad, buff, name):
- '''
- Proxy function for buffer_probe_handler_real
- '''
- _log.debug('Attaching real buffer handler to gobject idle event')
- gobject.idle_add(
- lambda: self.buffer_probe_handler_real(pad, buff, name))
-
- return True
-
- def _get_duration(self, pipeline, retries=0):
- '''
- Get the duration of a pipeline.
-
- Retries 5 times.
- '''
- if retries == 5:
- return 0
-
- try:
- return pipeline.query_duration(gst.FORMAT_TIME)[0]
- except gst.QueryError:
- return self._get_duration(pipeline, retries + 1)
-
- def _on_timeout(self):
- _log.error('Timeout in thumbnailer!')
- self.shutdown()
-
- def _on_bus_error(self, *args):
- _log.error('AHAHAHA! Error! args: {0}'.format(args))
-
- def shutdown(self):
- '''
- Tell gobject to call __halt when the mainloop is idle.
- '''
- _log.info('Shutting down')
- self.__halt()
-
- def __halt(self):
- '''
- Halt all pipelines and shut down the main loop
- '''
- _log.info('Halting...')
- self.state = self.STATE_HALTING
-
- self.__disconnect()
-
- gobject.idle_add(self.__halt_final)
-
- def __disconnect(self):
- _log.debug('Disconnecting...')
- if not self.playbin is None:
- self.playbin.set_state(gst.STATE_NULL)
- for sink in self.playbin.sinks():
- name = sink.get_name()
- factoryname = sink.get_factory().get_name()
-
- _log.debug('Disconnecting {0}'.format(name))
-
- if factoryname == "fakesink":
- pad = sink.get_pad("sink")
- pad.remove_buffer_probe(self.buffer_probes[name])
- del self.buffer_probes[name]
-
- self.playbin = None
-
- if self.bus is not None:
- self.bus.disconnect(self.watch_id)
- self.bus = None
-
- def __halt_final(self):
- _log.info('Done')
- if self.errors:
- _log.error(','.join(self.errors))
-
- self.loop.quit()
-
-
class VideoThumbnailerMarkII(object):
'''
Creates a thumbnail from a video file. Rewrite of VideoThumbnailer.
@@ -398,8 +130,8 @@ class VideoThumbnailerMarkII(object):
self.run()
except Exception as exc:
_log.critical(
- 'Exception "{0}" caught, disconnecting and re-raising'\
- .format(exc))
+ 'Exception "{0}" caught, shutting down mainloop and re-raising'\
+ .format(exc))
self.disconnect()
raise
@@ -410,7 +142,8 @@ class VideoThumbnailerMarkII(object):
self.mainloop.run()
def on_playbin_message(self, message_bus, message):
- _log.debug('playbin message: {0}'.format(message))
+ # Silenced to prevent clobbering of output
+ #_log.debug('playbin message: {0}'.format(message))
if message.type == gst.MESSAGE_ERROR:
_log.error('playbin error: {0}'.format(message))
@@ -433,17 +166,20 @@ pending: {2}'.format(
def on_playbin_paused(self):
if self.has_reached_playbin_pause:
- _log.warn('Has already reached logic for playbin pause. Aborting \
+ _log.warn('Has already reached on_playbin_paused. Aborting \
without doing anything this time.')
return False
self.has_reached_playbin_pause = True
+ # XXX: Why is this even needed at this point?
current_video = self.playbin.get_property('current-video')
if not current_video:
- _log.critical('thumbnail could not get any video data \
+ _log.critical('Could not get any video data \
from playbin')
+ else:
+ _log.info('Got video data from playbin')
self.duration = self.get_duration(self.playbin)
self.permission_to_take_picture = True
@@ -474,7 +210,8 @@ from playbin')
return False
def on_thumbnail_message(self, message_bus, message):
- _log.debug('thumbnail message: {0}'.format(message))
+ # This is silenced to prevent clobbering of the terminal window
+ #_log.debug('thumbnail message: {0}'.format(message))
if message.type == gst.MESSAGE_ERROR:
_log.error('thumbnail error: {0}'.format(message.parse_error()))
@@ -490,29 +227,10 @@ pending: {2}'.format(
cur_state,
pending_state))
- if cur_state == gst.STATE_PAUSED and\
- not self.state == self.STATE_PROCESSING_THUMBNAIL:
- self.state = self.STATE_PROCESSING_THUMBNAIL
-
+ if cur_state == gst.STATE_PAUSED and \
+ not self.state == self.STATE_PROCESSING_THUMBNAIL:
# Find the fakesink sink pad and attach the on_buffer_probe
# handler to it.
- for sink in self.thumbnail_pipeline.sinks():
- sink_name = sink.get_name()
- sink_factory_name = sink.get_factory().get_name()
-
- if sink_factory_name == 'fakesink':
- sink_pad = sink.get_pad('sink')
-
- self.buffer_probes[sink_name] = sink_pad\
- .add_buffer_probe(
- self.on_pad_buffer_probe,
- sink_name)
-
- _log.info('Attached buffer probes: {0}'.format(
- self.buffer_probes))
-
- break
-
seek_amount = self.position_callback(self.duration, gst)
seek_result = self.thumbnail_pipeline.seek(
@@ -525,10 +243,30 @@ pending: {2}'.format(
0)
if not seek_result:
- _log.critical('Could not seek.')
+ _log.info('Could not seek.')
+ else:
+ _log.info('Seek successful, attaching buffer probe')
+ self.state = self.STATE_PROCESSING_THUMBNAIL
+ for sink in self.thumbnail_pipeline.sinks():
+ sink_name = sink.get_name()
+ sink_factory_name = sink.get_factory().get_name()
+
+ if sink_factory_name == 'fakesink':
+ sink_pad = sink.get_pad('sink')
+
+ self.buffer_probes[sink_name] = sink_pad\
+ .add_buffer_probe(
+ self.on_pad_buffer_probe,
+ sink_name)
+
+ _log.info('Attached buffer probes: {0}'.format(
+ self.buffer_probes))
+
+ break
+
elif self.state == self.STATE_PROCESSING_THUMBNAIL:
- _log.debug('Already processing thumbnail')
+ _log.info('Already processing thumbnail')
def on_pad_buffer_probe(self, *args):
_log.debug('buffer probe handler: {0}'.format(args))
@@ -649,7 +387,7 @@ pending: {2}'.format(
return self.get_duration(pipeline, attempt + 1)
-class VideoTranscoder:
+class VideoTranscoder(object):
'''
Video transcoder
@@ -1011,6 +749,10 @@ if __name__ == '__main__':
action='store_true',
help='Dear program, please be quiet unless *error*')
+ parser.add_option('-w', '--width',
+ type=int,
+ default=180)
+
(options, args) = parser.parse_args()
if options.verbose:
@@ -1030,6 +772,7 @@ if __name__ == '__main__':
transcoder = VideoTranscoder()
if options.action == 'thumbnail':
+ args.append(options.width)
VideoThumbnailerMarkII(*args)
elif options.action == 'video':
def cb(data):
diff --git a/mediagoblin/messages.py b/mediagoblin/messages.py
index 80d8ece7..d58f13d4 100644
--- a/mediagoblin/messages.py
+++ b/mediagoblin/messages.py
@@ -14,16 +14,24 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
+from mediagoblin.tools import common
+
DEBUG = 'debug'
INFO = 'info'
SUCCESS = 'success'
WARNING = 'warning'
ERROR = 'error'
+ADD_MESSAGE_TEST = []
+
def add_message(request, level, text):
messages = request.session.setdefault('messages', [])
messages.append({'level': level, 'text': text})
+
+ if common.TESTS_ENABLED:
+ ADD_MESSAGE_TEST.append(messages)
+
request.session.save()
@@ -33,4 +41,10 @@ def fetch_messages(request, clear_from_session=True):
# Save that we removed the messages from the session
request.session['messages'] = []
request.session.save()
+
return messages
+
+
+def clear_add_message():
+ global ADD_MESSAGE_TEST
+ ADD_MESSAGE_TEST = []
diff --git a/mediagoblin/mg_globals.py b/mediagoblin/mg_globals.py
index e4b94bdc..26ed66fa 100644
--- a/mediagoblin/mg_globals.py
+++ b/mediagoblin/mg_globals.py
@@ -29,9 +29,6 @@ import threading
# SQL database engine
database = None
-# beaker's cache manager
-cache = None
-
# should be the same as the
public_store = None
queue_store = None
diff --git a/mediagoblin/notifications/__init__.py b/mediagoblin/notifications/__init__.py
new file mode 100644
index 00000000..4b7fbb8c
--- /dev/null
+++ b/mediagoblin/notifications/__init__.py
@@ -0,0 +1,141 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import logging
+
+from mediagoblin.db.models import Notification, \
+ CommentNotification, CommentSubscription
+from mediagoblin.notifications.task import email_notification_task
+from mediagoblin.notifications.tools import generate_comment_message
+
+_log = logging.getLogger(__name__)
+
+def trigger_notification(comment, media_entry, request):
+ '''
+ Send out notifications about a new comment.
+ '''
+ subscriptions = CommentSubscription.query.filter_by(
+ media_entry_id=media_entry.id).all()
+
+ for subscription in subscriptions:
+ if not subscription.notify:
+ continue
+
+ if comment.get_author == subscription.user:
+ continue
+
+ cn = CommentNotification(
+ user_id=subscription.user_id,
+ subject_id=comment.id)
+
+ cn.save()
+
+ if subscription.send_email:
+ message = generate_comment_message(
+ subscription.user,
+ comment,
+ media_entry,
+ request)
+
+ email_notification_task.apply_async([cn.id, message])
+
+
+def mark_notification_seen(notification):
+ if notification:
+ notification.seen = True
+ notification.save()
+
+
+def mark_comment_notification_seen(comment_id, user):
+ notification = CommentNotification.query.filter_by(
+ user_id=user.id,
+ subject_id=comment_id).first()
+
+ _log.debug('Marking {0} as seen.'.format(notification))
+
+ mark_notification_seen(notification)
+
+
+def get_comment_subscription(user_id, media_entry_id):
+ return CommentSubscription.query.filter_by(
+ user_id=user_id,
+ media_entry_id=media_entry_id).first()
+
+def add_comment_subscription(user, media_entry):
+ '''
+ Create a comment subscription for a User on a MediaEntry.
+
+ Uses the User's wants_comment_notification to set email notifications for
+ the subscription to enabled/disabled.
+ '''
+ cn = get_comment_subscription(user.id, media_entry.id)
+
+ if not cn:
+ cn = CommentSubscription(
+ user_id=user.id,
+ media_entry_id=media_entry.id)
+
+ cn.notify = True
+
+ if not user.wants_comment_notification:
+ cn.send_email = False
+
+ cn.save()
+
+
+def silence_comment_subscription(user, media_entry):
+ '''
+ Silence a subscription so that the user is never notified in any way about
+ new comments on an entry
+ '''
+ cn = get_comment_subscription(user.id, media_entry.id)
+
+ if cn:
+ cn.notify = False
+ cn.send_email = False
+ cn.save()
+
+
+def remove_comment_subscription(user, media_entry):
+ cn = get_comment_subscription(user.id, media_entry.id)
+
+ if cn:
+ cn.delete()
+
+
+NOTIFICATION_FETCH_LIMIT = 100
+
+
+def get_notifications(user_id, only_unseen=True):
+ query = Notification.query.filter_by(user_id=user_id)
+
+ if only_unseen:
+ query = query.filter_by(seen=False)
+
+ notifications = query.limit(
+ NOTIFICATION_FETCH_LIMIT).all()
+
+ return notifications
+
+def get_notification_count(user_id, only_unseen=True):
+ query = Notification.query.filter_by(user_id=user_id)
+
+ if only_unseen:
+ query = query.filter_by(seen=False)
+
+ count = query.count()
+
+ return count
diff --git a/mediagoblin/notifications/routing.py b/mediagoblin/notifications/routing.py
new file mode 100644
index 00000000..e57956d3
--- /dev/null
+++ b/mediagoblin/notifications/routing.py
@@ -0,0 +1,25 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+from mediagoblin.tools.routing import add_route
+
+add_route('mediagoblin.notifications.subscribe_comments',
+ '/u/<string:user>/m/<string:media>/notifications/subscribe/comments/',
+ 'mediagoblin.notifications.views:subscribe_comments')
+
+add_route('mediagoblin.notifications.silence_comments',
+ '/u/<string:user>/m/<string:media>/notifications/silence/',
+ 'mediagoblin.notifications.views:silence_comments')
diff --git a/mediagoblin/notifications/task.py b/mediagoblin/notifications/task.py
new file mode 100644
index 00000000..52573b57
--- /dev/null
+++ b/mediagoblin/notifications/task.py
@@ -0,0 +1,46 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import logging
+
+from celery import registry
+from celery.task import Task
+
+from mediagoblin.tools.mail import send_email
+from mediagoblin.db.models import CommentNotification
+
+
+_log = logging.getLogger(__name__)
+
+
+class EmailNotificationTask(Task):
+ '''
+ Celery notification task.
+
+ This task is executed by celeryd to offload long-running operations from
+ the web server.
+ '''
+ def run(self, notification_id, message):
+ cn = CommentNotification.query.filter_by(id=notification_id).first()
+ _log.info('Sending notification email about {0}'.format(cn))
+
+ return send_email(
+ message['from'],
+ [message['to']],
+ message['subject'],
+ message['body'])
+
+email_notification_task = registry.tasks[EmailNotificationTask.name]
diff --git a/mediagoblin/notifications/tools.py b/mediagoblin/notifications/tools.py
new file mode 100644
index 00000000..25432780
--- /dev/null
+++ b/mediagoblin/notifications/tools.py
@@ -0,0 +1,55 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+from mediagoblin.tools.template import render_template
+from mediagoblin.tools.translate import pass_to_ugettext as _
+from mediagoblin import mg_globals
+
+def generate_comment_message(user, comment, media, request):
+ """
+ Sends comment email to user when a comment is made on their media.
+
+ Args:
+ - user: the user object to whom the email is sent
+ - comment: the comment object referencing user's media
+ - media: the media object the comment is about
+ - request: the request
+ """
+
+ comment_url = request.urlgen(
+ 'mediagoblin.user_pages.media_home.view_comment',
+ comment=comment.id,
+ user=media.get_uploader.username,
+ media=media.slug_or_id,
+ qualified=True) + '#comment'
+
+ comment_author = comment.get_author.username
+
+ rendered_email = render_template(
+ request, 'mediagoblin/user_pages/comment_email.txt',
+ {'username': user.username,
+ 'comment_author': comment_author,
+ 'comment_content': comment.content,
+ 'comment_url': comment_url})
+
+ return {
+ 'from': mg_globals.app_config['email_sender_address'],
+ 'to': user.email,
+ 'subject': '{instance_title} - {comment_author} '.format(
+ comment_author=comment_author,
+ instance_title=mg_globals.app_config['html_title']) \
+ + _('commented on your post'),
+ 'body': rendered_email}
diff --git a/mediagoblin/notifications/views.py b/mediagoblin/notifications/views.py
new file mode 100644
index 00000000..d275bc92
--- /dev/null
+++ b/mediagoblin/notifications/views.py
@@ -0,0 +1,54 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+from mediagoblin.tools.response import render_to_response, render_404, redirect
+from mediagoblin.tools.translate import pass_to_ugettext as _
+from mediagoblin.decorators import (uses_pagination, get_user_media_entry,
+ get_media_entry_by_id,
+ require_active_login, user_may_delete_media, user_may_alter_collection,
+ get_user_collection, get_user_collection_item, active_user_from_url)
+
+from mediagoblin import messages
+
+from mediagoblin.notifications import add_comment_subscription, \
+ silence_comment_subscription
+
+from werkzeug.exceptions import BadRequest
+
+@get_user_media_entry
+@require_active_login
+def subscribe_comments(request, media):
+
+ add_comment_subscription(request.user, media)
+
+ messages.add_message(request,
+ messages.SUCCESS,
+ _('Subscribed to comments on %s!')
+ % media.title)
+
+ return redirect(request, location=media.url_for_self(request.urlgen))
+
+@get_user_media_entry
+@require_active_login
+def silence_comments(request, media):
+ silence_comment_subscription(request.user, media)
+
+ messages.add_message(request,
+ messages.SUCCESS,
+ _('You will not receive notifications for comments on'
+ ' %s.') % media.title)
+
+ return redirect(request, location=media.url_for_self(request.urlgen))
diff --git a/mediagoblin/plugins/api/__init__.py b/mediagoblin/plugins/api/__init__.py
index d3fdf2ef..1eddd9e0 100644
--- a/mediagoblin/plugins/api/__init__.py
+++ b/mediagoblin/plugins/api/__init__.py
@@ -23,11 +23,11 @@ _log = logging.getLogger(__name__)
PLUGIN_DIR = os.path.dirname(__file__)
-config = pluginapi.get_config(__name__)
-
def setup_plugin():
_log.info('Setting up API...')
+ config = pluginapi.get_config(__name__)
+
_log.debug('API config: {0}'.format(config))
routes = [
diff --git a/mediagoblin/plugins/api/views.py b/mediagoblin/plugins/api/views.py
index 2055a663..9159fe65 100644
--- a/mediagoblin/plugins/api/views.py
+++ b/mediagoblin/plugins/api/views.py
@@ -18,7 +18,6 @@ import json
import logging
from os.path import splitext
-from werkzeug.datastructures import FileStorage
from werkzeug.exceptions import BadRequest, Forbidden
from werkzeug.wrappers import Response
@@ -27,7 +26,8 @@ from mediagoblin.meddleware.csrf import csrf_exempt
from mediagoblin.media_types import sniff_media
from mediagoblin.plugins.api.tools import api_auth, get_entry_serializable, \
json_response
-from mediagoblin.submit.lib import prepare_queue_task, run_process_media
+from mediagoblin.submit.lib import check_file_field, prepare_queue_task, \
+ run_process_media, new_upload_entry
_log = logging.getLogger(__name__)
@@ -45,9 +45,7 @@ def post_entry(request):
_log.debug('Must POST against post_entry')
raise BadRequest()
- if not 'file' in request.files \
- or not isinstance(request.files['file'], FileStorage) \
- or not request.files['file'].stream:
+ if not check_file_field(request, 'file'):
_log.debug('File field not found')
raise BadRequest()
@@ -55,7 +53,7 @@ def post_entry(request):
media_type, media_manager = sniff_media(media_file)
- entry = request.db.MediaEntry()
+ entry = new_upload_entry(request.user)
entry.media_type = unicode(media_type)
entry.title = unicode(request.form.get('title')
or splitext(media_file.filename)[0])
@@ -63,8 +61,6 @@ def post_entry(request):
entry.description = unicode(request.form.get('description'))
entry.license = unicode(request.form.get('license', ''))
- entry.uploader = request.user.id
-
entry.generate_slug()
# queue appropriately
diff --git a/mediagoblin/plugins/basic_auth/__init__.py b/mediagoblin/plugins/basic_auth/__init__.py
new file mode 100644
index 00000000..33a554b0
--- /dev/null
+++ b/mediagoblin/plugins/basic_auth/__init__.py
@@ -0,0 +1,88 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+from mediagoblin.plugins.basic_auth import forms as auth_forms
+from mediagoblin.plugins.basic_auth import tools as auth_tools
+from mediagoblin.auth.tools import create_basic_user
+from mediagoblin.db.models import User
+from mediagoblin.tools import pluginapi
+from sqlalchemy import or_
+
+
+def setup_plugin():
+ config = pluginapi.get_config('mediagoblin.plugins.basic_auth')
+
+
+def get_user(**kwargs):
+ username = kwargs.pop('username', None)
+ if username:
+ user = User.query.filter(
+ or_(
+ User.username == username,
+ User.email == username,
+ )).first()
+ return user
+
+
+def create_user(registration_form):
+ user = get_user(username=registration_form.username.data)
+ if not user and 'password' in registration_form:
+ user = create_basic_user(registration_form)
+ user.pw_hash = gen_password_hash(
+ registration_form.password.data)
+ user.save()
+ return user
+
+
+def get_login_form(request):
+ return auth_forms.LoginForm(request.form)
+
+
+def get_registration_form(request):
+ return auth_forms.RegistrationForm(request.form)
+
+
+def gen_password_hash(raw_pass, extra_salt=None):
+ return auth_tools.bcrypt_gen_password_hash(raw_pass, extra_salt)
+
+
+def check_password(raw_pass, stored_hash, extra_salt=None):
+ if stored_hash:
+ return auth_tools.bcrypt_check_password(raw_pass,
+ stored_hash, extra_salt)
+ return None
+
+
+def auth():
+ return True
+
+
+def append_to_global_context(context):
+ context['pass_auth'] = True
+ return context
+
+
+hooks = {
+ 'setup': setup_plugin,
+ 'authentication': auth,
+ 'auth_get_user': get_user,
+ 'auth_create_user': create_user,
+ 'auth_get_login_form': get_login_form,
+ 'auth_get_registration_form': get_registration_form,
+ 'auth_gen_password_hash': gen_password_hash,
+ 'auth_check_password': check_password,
+ 'auth_fake_login_attempt': auth_tools.fake_login_attempt,
+ 'template_global_context': append_to_global_context,
+}
diff --git a/mediagoblin/plugins/basic_auth/forms.py b/mediagoblin/plugins/basic_auth/forms.py
new file mode 100644
index 00000000..6cf01b38
--- /dev/null
+++ b/mediagoblin/plugins/basic_auth/forms.py
@@ -0,0 +1,46 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+import wtforms
+
+from mediagoblin.tools.translate import lazy_pass_to_ugettext as _
+from mediagoblin.auth.tools import normalize_user_or_email_field
+
+
+class RegistrationForm(wtforms.Form):
+ username = wtforms.TextField(
+ _('Username'),
+ [wtforms.validators.Required(),
+ normalize_user_or_email_field(allow_email=False)])
+ password = wtforms.PasswordField(
+ _('Password'),
+ [wtforms.validators.Required(),
+ wtforms.validators.Length(min=5, max=1024)])
+ email = wtforms.TextField(
+ _('Email address'),
+ [wtforms.validators.Required(),
+ normalize_user_or_email_field(allow_user=False)])
+
+
+class LoginForm(wtforms.Form):
+ username = wtforms.TextField(
+ _('Username or Email'),
+ [wtforms.validators.Required(),
+ normalize_user_or_email_field()])
+ password = wtforms.PasswordField(
+ _('Password'))
+ stay_logged_in = wtforms.BooleanField(
+ label='',
+ description=_('Stay logged in'))
diff --git a/mediagoblin/auth/lib.py b/mediagoblin/plugins/basic_auth/tools.py
index 8829995a..1300bb9a 100644
--- a/mediagoblin/auth/lib.py
+++ b/mediagoblin/plugins/basic_auth/tools.py
@@ -13,14 +13,8 @@
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-import random
-
import bcrypt
-
-from mediagoblin.tools.mail import send_email
-from mediagoblin.tools.template import render_template
-from mediagoblin import mg_globals
+import random
def bcrypt_check_password(raw_pass, stored_hash, extra_salt=None):
@@ -88,68 +82,3 @@ def fake_login_attempt():
randplus_hashed_pass = bcrypt.hashpw(hashed_pass, rand_salt)
randplus_stored_hash == randplus_hashed_pass
-
-
-EMAIL_VERIFICATION_TEMPLATE = (
- u"http://{host}{uri}?"
- u"userid={userid}&token={verification_key}")
-
-
-def send_verification_email(user, request):
- """
- Send the verification email to users to activate their accounts.
-
- Args:
- - user: a user object
- - request: the request
- """
- rendered_email = render_template(
- request, 'mediagoblin/auth/verification_email.txt',
- {'username': user.username,
- 'verification_url': EMAIL_VERIFICATION_TEMPLATE.format(
- host=request.host,
- uri=request.urlgen('mediagoblin.auth.verify_email'),
- userid=unicode(user.id),
- verification_key=user.verification_key)})
-
- # TODO: There is no error handling in place
- send_email(
- mg_globals.app_config['email_sender_address'],
- [user.email],
- # TODO
- # Due to the distributed nature of GNU MediaGoblin, we should
- # find a way to send some additional information about the
- # specific GNU MediaGoblin instance in the subject line. For
- # example "GNU MediaGoblin @ Wandborg - [...]".
- 'GNU MediaGoblin - Verify your email!',
- rendered_email)
-
-
-EMAIL_FP_VERIFICATION_TEMPLATE = (
- u"http://{host}{uri}?"
- u"userid={userid}&token={fp_verification_key}")
-
-
-def send_fp_verification_email(user, request):
- """
- Send the verification email to users to change their password.
-
- Args:
- - user: a user object
- - request: the request
- """
- rendered_email = render_template(
- request, 'mediagoblin/auth/fp_verification_email.txt',
- {'username': user.username,
- 'verification_url': EMAIL_FP_VERIFICATION_TEMPLATE.format(
- host=request.host,
- uri=request.urlgen('mediagoblin.auth.verify_forgot_password'),
- userid=unicode(user.id),
- fp_verification_key=user.fp_verification_key)})
-
- # TODO: There is no error handling in place
- send_email(
- mg_globals.app_config['email_sender_address'],
- [user.email],
- 'GNU MediaGoblin - Change forgotten password!',
- rendered_email)
diff --git a/mediagoblin/plugins/httpapiauth/__init__.py b/mediagoblin/plugins/httpapiauth/__init__.py
index 081b590e..2b2d593c 100644
--- a/mediagoblin/plugins/httpapiauth/__init__.py
+++ b/mediagoblin/plugins/httpapiauth/__init__.py
@@ -15,10 +15,10 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
-import base64
-from werkzeug.exceptions import BadRequest, Unauthorized
+from werkzeug.exceptions import Unauthorized
+from mediagoblin.auth.tools import check_login_simple
from mediagoblin.plugins.api.tools import Auth
_log = logging.getLogger(__name__)
@@ -40,10 +40,10 @@ class HTTPAuth(Auth):
if not request.authorization:
return False
- user = request.db.User.query.filter_by(
- username=unicode(request.authorization['username'])).first()
+ user = check_login_simple(unicode(request.authorization['username']),
+ request.authorization['password'])
- if user.check_login(request.authorization['password']):
+ if user:
request.user = user
return True
else:
diff --git a/mediagoblin/plugins/oauth/__init__.py b/mediagoblin/plugins/oauth/__init__.py
index 4714d95d..5762379d 100644
--- a/mediagoblin/plugins/oauth/__init__.py
+++ b/mediagoblin/plugins/oauth/__init__.py
@@ -34,7 +34,7 @@ def setup_plugin():
_log.debug('OAuth config: {0}'.format(config))
routes = [
- ('mediagoblin.plugins.oauth.authorize',
+ ('mediagoblin.plugins.oauth.authorize',
'/oauth/authorize',
'mediagoblin.plugins.oauth.views:authorize'),
('mediagoblin.plugins.oauth.authorize_client',
diff --git a/mediagoblin/plugins/oauth/forms.py b/mediagoblin/plugins/oauth/forms.py
index d0a4e9b8..5edd992a 100644
--- a/mediagoblin/plugins/oauth/forms.py
+++ b/mediagoblin/plugins/oauth/forms.py
@@ -19,7 +19,7 @@ import wtforms
from urlparse import urlparse
from mediagoblin.tools.extlib.wtf_html5 import URLField
-from mediagoblin.tools.translate import fake_ugettext_passthrough as _
+from mediagoblin.tools.translate import lazy_pass_to_ugettext as _
class AuthorizationForm(wtforms.Form):
diff --git a/mediagoblin/plugins/oauth/migrations.py b/mediagoblin/plugins/oauth/migrations.py
index 6aa0d7cb..d7b89da3 100644
--- a/mediagoblin/plugins/oauth/migrations.py
+++ b/mediagoblin/plugins/oauth/migrations.py
@@ -102,6 +102,21 @@ class OAuthCode_v0(declarative_base()):
client_id = Column(Integer, ForeignKey(OAuthClient_v0.id), nullable=False)
+class OAuthRefreshToken_v0(declarative_base()):
+ __tablename__ = 'oauth__refresh_tokens'
+
+ id = Column(Integer, primary_key=True)
+ created = Column(DateTime, nullable=False,
+ default=datetime.now)
+
+ token = Column(Unicode, index=True)
+
+ user_id = Column(Integer, ForeignKey(User.id), nullable=False)
+
+ # XXX: Is it OK to use OAuthClient_v0.id in this way?
+ client_id = Column(Integer, ForeignKey(OAuthClient_v0.id), nullable=False)
+
+
@RegisterMigration(1, MIGRATIONS)
def remove_and_replace_token_and_code(db):
metadata = MetaData(bind=db.bind)
@@ -122,3 +137,22 @@ def remove_and_replace_token_and_code(db):
OAuthCode_v0.__table__.create(db.bind)
db.commit()
+
+
+@RegisterMigration(2, MIGRATIONS)
+def remove_refresh_token_field(db):
+ metadata = MetaData(bind=db.bind)
+
+ token_table = Table('oauth__tokens', metadata, autoload=True,
+ autoload_with=db.bind)
+
+ refresh_token = token_table.columns['refresh_token']
+
+ refresh_token.drop()
+ db.commit()
+
+@RegisterMigration(3, MIGRATIONS)
+def create_refresh_token_table(db):
+ OAuthRefreshToken_v0.__table__.create(db.bind)
+
+ db.commit()
diff --git a/mediagoblin/plugins/oauth/models.py b/mediagoblin/plugins/oauth/models.py
index 695dad31..439424d3 100644
--- a/mediagoblin/plugins/oauth/models.py
+++ b/mediagoblin/plugins/oauth/models.py
@@ -14,17 +14,17 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-import uuid
-import bcrypt
from datetime import datetime, timedelta
-from mediagoblin.db.base import Base
-from mediagoblin.db.models import User
from sqlalchemy import (
Column, Unicode, Integer, DateTime, ForeignKey, Enum)
-from sqlalchemy.orm import relationship
+from sqlalchemy.orm import relationship, backref
+from mediagoblin.db.base import Base
+from mediagoblin.db.models import User
+from mediagoblin.plugins.oauth.tools import generate_identifier, \
+ generate_secret, generate_token, generate_code, generate_refresh_token
# Don't remove this, I *think* it applies sqlalchemy-migrate functionality onto
# the models.
@@ -41,11 +41,14 @@ class OAuthClient(Base):
name = Column(Unicode)
description = Column(Unicode)
- identifier = Column(Unicode, unique=True, index=True)
- secret = Column(Unicode, index=True)
+ identifier = Column(Unicode, unique=True, index=True,
+ default=generate_identifier)
+ secret = Column(Unicode, index=True, default=generate_secret)
owner_id = Column(Integer, ForeignKey(User.id))
- owner = relationship(User, backref='registered_clients')
+ owner = relationship(
+ User,
+ backref=backref('registered_clients', cascade='all, delete-orphan'))
redirect_uri = Column(Unicode)
@@ -54,14 +57,8 @@ class OAuthClient(Base):
u'public',
name=u'oauth__client_type'))
- def generate_identifier(self):
- self.identifier = unicode(uuid.uuid4())
-
- def generate_secret(self):
- self.secret = unicode(
- bcrypt.hashpw(
- unicode(uuid.uuid4()),
- bcrypt.gensalt()))
+ def update_secret(self):
+ self.secret = generate_secret()
def __repr__(self):
return '<{0} {1}:{2} ({3})>'.format(
@@ -76,10 +73,15 @@ class OAuthUserClient(Base):
id = Column(Integer, primary_key=True)
user_id = Column(Integer, ForeignKey(User.id))
- user = relationship(User, backref='oauth_clients')
+ user = relationship(
+ User,
+ backref=backref('oauth_client_relations',
+ cascade='all, delete-orphan'))
client_id = Column(Integer, ForeignKey(OAuthClient.id))
- client = relationship(OAuthClient, backref='users')
+ client = relationship(
+ OAuthClient,
+ backref=backref('oauth_user_relations', cascade='all, delete-orphan'))
state = Column(Enum(
u'approved',
@@ -103,15 +105,18 @@ class OAuthToken(Base):
default=datetime.now)
expires = Column(DateTime, nullable=False,
default=lambda: datetime.now() + timedelta(days=30))
- token = Column(Unicode, index=True)
- refresh_token = Column(Unicode, index=True)
+ token = Column(Unicode, index=True, default=generate_token)
user_id = Column(Integer, ForeignKey(User.id), nullable=False,
index=True)
- user = relationship(User)
+ user = relationship(
+ User,
+ backref=backref('oauth_tokens', cascade='all, delete-orphan'))
client_id = Column(Integer, ForeignKey(OAuthClient.id), nullable=False)
- client = relationship(OAuthClient)
+ client = relationship(
+ OAuthClient,
+ backref=backref('oauth_tokens', cascade='all, delete-orphan'))
def __repr__(self):
return '<{0} #{1} expires {2} [{3}, {4}]>'.format(
@@ -121,6 +126,34 @@ class OAuthToken(Base):
self.user,
self.client)
+class OAuthRefreshToken(Base):
+ __tablename__ = 'oauth__refresh_tokens'
+
+ id = Column(Integer, primary_key=True)
+ created = Column(DateTime, nullable=False,
+ default=datetime.now)
+
+ token = Column(Unicode, index=True,
+ default=generate_refresh_token)
+
+ user_id = Column(Integer, ForeignKey(User.id), nullable=False)
+
+ user = relationship(User, backref=backref('oauth_refresh_tokens',
+ cascade='all, delete-orphan'))
+
+ client_id = Column(Integer, ForeignKey(OAuthClient.id), nullable=False)
+ client = relationship(OAuthClient,
+ backref=backref(
+ 'oauth_refresh_tokens',
+ cascade='all, delete-orphan'))
+
+ def __repr__(self):
+ return '<{0} #{1} [{3}, {4}]>'.format(
+ self.__class__.__name__,
+ self.id,
+ self.user,
+ self.client)
+
class OAuthCode(Base):
__tablename__ = 'oauth__codes'
@@ -130,14 +163,17 @@ class OAuthCode(Base):
default=datetime.now)
expires = Column(DateTime, nullable=False,
default=lambda: datetime.now() + timedelta(minutes=5))
- code = Column(Unicode, index=True)
+ code = Column(Unicode, index=True, default=generate_code)
user_id = Column(Integer, ForeignKey(User.id), nullable=False,
index=True)
- user = relationship(User)
+ user = relationship(User, backref=backref('oauth_codes',
+ cascade='all, delete-orphan'))
client_id = Column(Integer, ForeignKey(OAuthClient.id), nullable=False)
- client = relationship(OAuthClient)
+ client = relationship(OAuthClient, backref=backref(
+ 'oauth_codes',
+ cascade='all, delete-orphan'))
def __repr__(self):
return '<{0} #{1} expires {2} [{3}, {4}]>'.format(
@@ -150,6 +186,7 @@ class OAuthCode(Base):
MODELS = [
OAuthToken,
+ OAuthRefreshToken,
OAuthCode,
OAuthClient,
OAuthUserClient]
diff --git a/mediagoblin/plugins/oauth/tools.py b/mediagoblin/plugins/oauth/tools.py
index d21c8a5b..27ff32b4 100644
--- a/mediagoblin/plugins/oauth/tools.py
+++ b/mediagoblin/plugins/oauth/tools.py
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
# GNU MediaGoblin -- federated, autonomous media hosting
# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
#
@@ -14,13 +15,26 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
+import uuid
+
+from random import getrandbits
+
+from datetime import datetime
+
from functools import wraps
-from mediagoblin.plugins.oauth.models import OAuthClient
from mediagoblin.plugins.api.tools import json_response
def require_client_auth(controller):
+ '''
+ View decorator
+
+ - Requires the presence of ``?client_id``
+ '''
+ # Avoid circular import
+ from mediagoblin.plugins.oauth.models import OAuthClient
+
@wraps(controller)
def wrapper(request, *args, **kw):
if not request.GET.get('client_id'):
@@ -41,3 +55,60 @@ def require_client_auth(controller):
return controller(request, client)
return wrapper
+
+
+def create_token(client, user):
+ '''
+ Create an OAuthToken and an OAuthRefreshToken entry in the database
+
+ Returns the data structure expected by the OAuth clients.
+ '''
+ from mediagoblin.plugins.oauth.models import OAuthToken, OAuthRefreshToken
+
+ token = OAuthToken()
+ token.user = user
+ token.client = client
+ token.save()
+
+ refresh_token = OAuthRefreshToken()
+ refresh_token.user = user
+ refresh_token.client = client
+ refresh_token.save()
+
+ # expire time of token in full seconds
+ # timedelta.total_seconds is python >= 2.7 or we would use that
+ td = token.expires - datetime.now()
+ exp_in = 86400*td.days + td.seconds # just ignore µsec
+
+ return {'access_token': token.token, 'token_type': 'bearer',
+ 'refresh_token': refresh_token.token, 'expires_in': exp_in}
+
+
+def generate_identifier():
+ ''' Generates a ``uuid.uuid4()`` '''
+ return unicode(uuid.uuid4())
+
+
+def generate_token():
+ ''' Uses generate_identifier '''
+ return generate_identifier()
+
+
+def generate_refresh_token():
+ ''' Uses generate_identifier '''
+ return generate_identifier()
+
+
+def generate_code():
+ ''' Uses generate_identifier '''
+ return generate_identifier()
+
+
+def generate_secret():
+ '''
+ Generate a long string of pseudo-random characters
+ '''
+ # XXX: We might not want it to use bcrypt, since bcrypt takes its time to
+ # generate the result.
+ return unicode(getrandbits(192))
+
diff --git a/mediagoblin/plugins/oauth/views.py b/mediagoblin/plugins/oauth/views.py
index c7b2a332..d6fd314f 100644
--- a/mediagoblin/plugins/oauth/views.py
+++ b/mediagoblin/plugins/oauth/views.py
@@ -16,21 +16,21 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
-import json
from urllib import urlencode
-from uuid import uuid4
-from datetime import datetime
+
+from werkzeug.exceptions import BadRequest
from mediagoblin.tools.response import render_to_response, redirect
from mediagoblin.decorators import require_active_login
-from mediagoblin.messages import add_message, SUCCESS, ERROR
+from mediagoblin.messages import add_message, SUCCESS
from mediagoblin.tools.translate import pass_to_ugettext as _
-from mediagoblin.plugins.oauth.models import OAuthCode, OAuthToken, \
- OAuthClient, OAuthUserClient
+from mediagoblin.plugins.oauth.models import OAuthCode, OAuthClient, \
+ OAuthUserClient, OAuthRefreshToken
from mediagoblin.plugins.oauth.forms import ClientRegistrationForm, \
AuthorizationForm
-from mediagoblin.plugins.oauth.tools import require_client_auth
+from mediagoblin.plugins.oauth.tools import require_client_auth, \
+ create_token
from mediagoblin.plugins.api.tools import json_response
_log = logging.getLogger(__name__)
@@ -45,14 +45,11 @@ def register_client(request):
if request.method == 'POST' and form.validate():
client = OAuthClient()
- client.name = unicode(request.form['name'])
- client.description = unicode(request.form['description'])
- client.type = unicode(request.form['type'])
+ client.name = unicode(form.name.data)
+ client.description = unicode(form.description.data)
+ client.type = unicode(form.type.data)
client.owner_id = request.user.id
- client.redirect_uri = unicode(request.form['redirect_uri'])
-
- client.generate_identifier()
- client.generate_secret()
+ client.redirect_uri = unicode(form.redirect_uri.data)
client.save()
@@ -92,9 +89,9 @@ def authorize_client(request):
form.client_id.data).first()
if not client:
- _log.error('''No such client id as received from client authorization
- form.''')
- return BadRequest()
+ _log.error('No such client id as received from client authorization \
+form.')
+ raise BadRequest()
if form.validate():
relation = OAuthUserClient()
@@ -105,7 +102,7 @@ def authorize_client(request):
elif form.deny.data:
relation.state = u'rejected'
else:
- return BadRequest
+ raise BadRequest()
relation.save()
@@ -136,7 +133,7 @@ def authorize(request, client):
return json_response({
'status': 400,
'errors':
- [u'Public clients MUST have a redirect_uri pre-set']},
+ [u'Public clients should have a redirect_uri pre-set.']},
_disable_cors=True)
redirect_uri = client.redirect_uri
@@ -146,11 +143,10 @@ def authorize(request, client):
if not redirect_uri:
return json_response({
'status': 400,
- 'errors': [u'Can not find a redirect_uri for client: {0}'\
- .format(client.name)]}, _disable_cors=True)
+ 'errors': [u'No redirect_uri supplied!']},
+ _disable_cors=True)
code = OAuthCode()
- code.code = unicode(uuid4())
code.user = request.user
code.client = client
code.save()
@@ -180,59 +176,79 @@ def authorize(request, client):
def access_token(request):
+ '''
+ Access token endpoint provides access tokens to any clients that have the
+ right grants/credentials
+ '''
+
+ client = None
+ user = None
+
if request.GET.get('code'):
+ # Validate the code arg, then get the client object from the db.
code = OAuthCode.query.filter(OAuthCode.code ==
request.GET.get('code')).first()
- if code:
- if code.client.type == u'confidential':
- client_identifier = request.GET.get('client_id')
-
- if not client_identifier:
- return json_response({
- 'error': 'invalid_request',
- 'error_description':
- 'Missing client_id in request'})
-
- client_secret = request.GET.get('client_secret')
-
- if not client_secret:
- return json_response({
- 'error': 'invalid_request',
- 'error_description':
- 'Missing client_secret in request'})
-
- if not client_secret == code.client.secret or \
- not client_identifier == code.client.identifier:
- return json_response({
- 'error': 'invalid_client',
- 'error_description':
- 'The client_id or client_secret does not match the'
- ' code'})
-
- token = OAuthToken()
- token.token = unicode(uuid4())
- token.user = code.user
- token.client = code.client
- token.save()
-
- # expire time of token in full seconds
- # timedelta.total_seconds is python >= 2.7 or we would use that
- td = token.expires - datetime.now()
- exp_in = 86400*td.days + td.seconds # just ignore µsec
-
- access_token_data = {
- 'access_token': token.token,
- 'token_type': 'bearer',
- 'expires_in': exp_in}
- return json_response(access_token_data, _disable_cors=True)
- else:
+ if not code:
return json_response({
'error': 'invalid_request',
'error_description':
- 'Invalid code'})
- else:
- return json_response({
- 'error': 'invalid_request',
- 'error_descriptin':
- 'Missing `code` parameter in request'})
+ 'Invalid code.'})
+
+ client = code.client
+ user = code.user
+
+ elif request.args.get('refresh_token'):
+ # Validate a refresh token, then get the client object from the db.
+ refresh_token = OAuthRefreshToken.query.filter(
+ OAuthRefreshToken.token ==
+ request.args.get('refresh_token')).first()
+
+ if not refresh_token:
+ return json_response({
+ 'error': 'invalid_request',
+ 'error_description':
+ 'Invalid refresh token.'})
+
+ client = refresh_token.client
+ user = refresh_token.user
+
+ if client:
+ client_identifier = request.GET.get('client_id')
+
+ if not client_identifier:
+ return json_response({
+ 'error': 'invalid_request',
+ 'error_description':
+ 'Missing client_id in request.'})
+
+ if not client_identifier == client.identifier:
+ return json_response({
+ 'error': 'invalid_client',
+ 'error_description':
+ 'Mismatching client credentials.'})
+
+ if client.type == u'confidential':
+ client_secret = request.GET.get('client_secret')
+
+ if not client_secret:
+ return json_response({
+ 'error': 'invalid_request',
+ 'error_description':
+ 'Missing client_secret in request.'})
+
+ if not client_secret == client.secret:
+ return json_response({
+ 'error': 'invalid_client',
+ 'error_description':
+ 'Mismatching client credentials.'})
+
+
+ access_token_data = create_token(client, user)
+
+ return json_response(access_token_data, _disable_cors=True)
+
+ return json_response({
+ 'error': 'invalid_request',
+ 'error_description':
+ 'Missing `code` or `refresh_token` parameter in request.'})
diff --git a/mediagoblin/plugins/openid/__init__.py b/mediagoblin/plugins/openid/__init__.py
new file mode 100644
index 00000000..ee88808c
--- /dev/null
+++ b/mediagoblin/plugins/openid/__init__.py
@@ -0,0 +1,123 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+import os
+import uuid
+
+from sqlalchemy import or_
+
+from mediagoblin.auth.tools import create_basic_user
+from mediagoblin.db.models import User
+from mediagoblin.plugins.openid.models import OpenIDUserURL
+from mediagoblin.tools import pluginapi
+from mediagoblin.tools.translate import lazy_pass_to_ugettext as _
+
+PLUGIN_DIR = os.path.dirname(__file__)
+
+
+def setup_plugin():
+ config = pluginapi.get_config('mediagoblin.plugins.openid')
+
+ routes = [
+ ('mediagoblin.plugins.openid.register',
+ '/auth/openid/register/',
+ 'mediagoblin.plugins.openid.views:register'),
+ ('mediagoblin.plugins.openid.login',
+ '/auth/openid/login/',
+ 'mediagoblin.plugins.openid.views:login'),
+ ('mediagoblin.plugins.openid.finish_login',
+ '/auth/openid/login/finish/',
+ 'mediagoblin.plugins.openid.views:finish_login'),
+ ('mediagoblin.plugins.openid.edit',
+ '/edit/openid/',
+ 'mediagoblin.plugins.openid.views:start_edit'),
+ ('mediagoblin.plugins.openid.finish_edit',
+ '/edit/openid/finish/',
+ 'mediagoblin.plugins.openid.views:finish_edit'),
+ ('mediagoblin.plugins.openid.delete',
+ '/edit/openid/delete/',
+ 'mediagoblin.plugins.openid.views:delete_openid'),
+ ('mediagoblin.plugins.openid.finish_delete',
+ '/edit/openid/delete/finish/',
+ 'mediagoblin.plugins.openid.views:finish_delete')]
+
+ pluginapi.register_routes(routes)
+ pluginapi.register_template_path(os.path.join(PLUGIN_DIR, 'templates'))
+
+ pluginapi.register_template_hooks(
+ {'register_link': 'mediagoblin/plugins/openid/register_link.html',
+ 'login_link': 'mediagoblin/plugins/openid/login_link.html',
+ 'edit_link': 'mediagoblin/plugins/openid/edit_link.html'})
+
+
+def create_user(register_form):
+ if 'openid' in register_form:
+ username = register_form.username.data
+ user = User.query.filter(
+ or_(
+ User.username == username,
+ User.email == username,
+ )).first()
+
+ if not user:
+ user = create_basic_user(register_form)
+
+ new_entry = OpenIDUserURL()
+ new_entry.openid_url = register_form.openid.data
+ new_entry.user_id = user.id
+ new_entry.save()
+
+ return user
+
+
+def extra_validation(register_form):
+ openid = register_form.openid.data if 'openid' in \
+ register_form else None
+ if openid:
+ openid_url_exists = OpenIDUserURL.query.filter_by(
+ openid_url=openid
+ ).count()
+
+ extra_validation_passes = True
+
+ if openid_url_exists:
+ register_form.openid.errors.append(
+ _('Sorry, an account is already registered to that OpenID.'))
+ extra_validation_passes = False
+
+ return extra_validation_passes
+
+
+def no_pass_redirect():
+ return 'openid'
+
+
+def add_to_form_context(context):
+ context['openid_link'] = True
+ return context
+
+
+def Auth():
+ return True
+
+hooks = {
+ 'setup': setup_plugin,
+ 'authentication': Auth,
+ 'auth_extra_validation': extra_validation,
+ 'auth_create_user': create_user,
+ 'auth_no_pass_redirect': no_pass_redirect,
+ ('mediagoblin.auth.register',
+ 'mediagoblin/auth/register.html'): add_to_form_context,
+}
diff --git a/mediagoblin/plugins/openid/forms.py b/mediagoblin/plugins/openid/forms.py
new file mode 100644
index 00000000..f26024bd
--- /dev/null
+++ b/mediagoblin/plugins/openid/forms.py
@@ -0,0 +1,41 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+import wtforms
+
+from mediagoblin.tools.translate import lazy_pass_to_ugettext as _
+from mediagoblin.auth.tools import normalize_user_or_email_field
+
+
+class RegistrationForm(wtforms.Form):
+ openid = wtforms.HiddenField(
+ '',
+ [wtforms.validators.Required()])
+ username = wtforms.TextField(
+ _('Username'),
+ [wtforms.validators.Required(),
+ normalize_user_or_email_field(allow_email=False)])
+ email = wtforms.TextField(
+ _('Email address'),
+ [wtforms.validators.Required(),
+ normalize_user_or_email_field(allow_user=False)])
+
+
+class LoginForm(wtforms.Form):
+ openid = wtforms.TextField(
+ _('OpenID'),
+ [wtforms.validators.Required(),
+ # Can openid's only be urls?
+ wtforms.validators.URL(message='Please enter a valid url.')])
diff --git a/mediagoblin/plugins/openid/models.py b/mediagoblin/plugins/openid/models.py
new file mode 100644
index 00000000..6773f0ad
--- /dev/null
+++ b/mediagoblin/plugins/openid/models.py
@@ -0,0 +1,65 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+from sqlalchemy import Column, Integer, Unicode, ForeignKey
+from sqlalchemy.orm import relationship, backref
+
+from mediagoblin.db.models import User
+from mediagoblin.db.base import Base
+
+
+class OpenIDUserURL(Base):
+ __tablename__ = "openid__user_urls"
+
+ id = Column(Integer, primary_key=True)
+ openid_url = Column(Unicode, nullable=False)
+ user_id = Column(Integer, ForeignKey(User.id), nullable=False)
+
+ # OpenID's are owned by their user, so do the full thing.
+ user = relationship(User, backref=backref('openid_urls',
+ cascade='all, delete-orphan'))
+
+
+# OpenID Store Models
+class Nonce(Base):
+ __tablename__ = "openid__nonce"
+
+ server_url = Column(Unicode, primary_key=True)
+ timestamp = Column(Integer, primary_key=True)
+ salt = Column(Unicode, primary_key=True)
+
+ def __unicode__(self):
+ return u'Nonce: %r, %r' % (self.server_url, self.salt)
+
+
+class Association(Base):
+ __tablename__ = "openid__association"
+
+ server_url = Column(Unicode, primary_key=True)
+ handle = Column(Unicode, primary_key=True)
+ secret = Column(Unicode)
+ issued = Column(Integer)
+ lifetime = Column(Integer)
+ assoc_type = Column(Unicode)
+
+ def __unicode__(self):
+ return u'Association: %r, %r' % (self.server_url, self.handle)
+
+
+MODELS = [
+ OpenIDUserURL,
+ Nonce,
+ Association
+]
diff --git a/mediagoblin/plugins/openid/store.py b/mediagoblin/plugins/openid/store.py
new file mode 100644
index 00000000..8f9a7012
--- /dev/null
+++ b/mediagoblin/plugins/openid/store.py
@@ -0,0 +1,127 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+import base64
+import time
+
+from openid.association import Association as OIDAssociation
+from openid.store.interface import OpenIDStore
+from openid.store import nonce
+
+from mediagoblin.plugins.openid.models import Association, Nonce
+
+
+class SQLAlchemyOpenIDStore(OpenIDStore):
+ def __init__(self):
+ self.max_nonce_age = 6 * 60 * 60
+
+ def storeAssociation(self, server_url, association):
+ assoc = Association.query.filter_by(
+ server_url=server_url, handle=association.handle
+ ).first()
+
+ if not assoc:
+ assoc = Association()
+ assoc.server_url = unicode(server_url)
+ assoc.handle = association.handle
+
+ # django uses base64 encoding, python-openid uses a blob field for
+ # secret
+ assoc.secret = unicode(base64.encodestring(association.secret))
+ assoc.issued = association.issued
+ assoc.lifetime = association.lifetime
+ assoc.assoc_type = association.assoc_type
+ assoc.save()
+
+ def getAssociation(self, server_url, handle=None):
+ assocs = []
+ if handle is not None:
+ assocs = Association.query.filter_by(
+ server_url=server_url, handle=handle
+ )
+ else:
+ assocs = Association.query.filter_by(
+ server_url=server_url
+ )
+
+ if assocs.count() == 0:
+ return None
+ else:
+ associations = []
+ for assoc in assocs:
+ association = OIDAssociation(
+ assoc.handle, base64.decodestring(assoc.secret),
+ assoc.issued, assoc.lifetime, assoc.assoc_type
+ )
+ if association.getExpiresIn() == 0:
+ assoc.delete()
+ else:
+ associations.append((association.issued, association))
+
+ if not associations:
+ return None
+ associations.sort()
+ return associations[-1][1]
+
+ def removeAssociation(self, server_url, handle):
+ assocs = Association.query.filter_by(
+ server_url=server_url, handle=handle
+ ).first()
+
+ assoc_exists = True if assocs else False
+ for assoc in assocs:
+ assoc.delete()
+ return assoc_exists
+
+ def useNonce(self, server_url, timestamp, salt):
+ if abs(timestamp - time.time()) > nonce.SKEW:
+ return False
+
+ ononce = Nonce.query.filter_by(
+ server_url=server_url,
+ timestamp=timestamp,
+ salt=salt
+ ).first()
+
+ if ononce:
+ return False
+ else:
+ ononce = Nonce()
+ ononce.server_url = server_url
+ ononce.timestamp = timestamp
+ ononce.salt = salt
+ ononce.save()
+ return True
+
+ def cleanupNonces(self, _now=None):
+ if _now is None:
+ _now = int(time.time())
+ expired = Nonce.query.filter(
+ Nonce.timestamp < (_now - nonce.SKEW)
+ )
+ count = expired.count()
+ for each in expired:
+ each.delete()
+ return count
+
+ def cleanupAssociations(self):
+ now = int(time.time())
+ assoc = Association.query.all()
+ count = 0
+ for each in assoc:
+ if (each.lifetime + each.issued) <= now:
+ each.delete()
+ count = count + 1
+ return count
diff --git a/mediagoblin/plugins/openid/templates/mediagoblin/plugins/openid/add.html b/mediagoblin/plugins/openid/templates/mediagoblin/plugins/openid/add.html
new file mode 100644
index 00000000..8d308c81
--- /dev/null
+++ b/mediagoblin/plugins/openid/templates/mediagoblin/plugins/openid/add.html
@@ -0,0 +1,44 @@
+{#
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#}
+{% extends "mediagoblin/base.html" %}
+
+{% import "/mediagoblin/utils/wtforms.html" as wtforms_util %}
+
+{% block title -%}
+ {% trans %}Add an OpenID{% endtrans %} &mdash; {{ super() }}
+{%- endblock %}
+
+{% block mediagoblin_content %}
+ <form action="{{ request.urlgen('mediagoblin.plugins.openid.edit') }}"
+ method="POST" enctype="multipart/form-data">
+ {{ csrf_token }}
+ <div class="form_box">
+ <h1>{% trans %}Add an OpenID{% endtrans %}</h1>
+ <p>
+ <a href="{{ request.urlgen('mediagoblin.plugins.openid.delete') }}">
+ {% trans %}Delete an OpenID{% endtrans %}
+ </a>
+ </p>
+ {{ wtforms_util.render_divs(form, True) }}
+ <div class="form_submit_buttons">
+ <input type="submit" value="{% trans %}Add{% endtrans %}" class="button_form"/>
+ </div>
+ </div>
+ </form>
+{% endblock %}
+
diff --git a/mediagoblin/plugins/openid/templates/mediagoblin/plugins/openid/delete.html b/mediagoblin/plugins/openid/templates/mediagoblin/plugins/openid/delete.html
new file mode 100644
index 00000000..84301b9e
--- /dev/null
+++ b/mediagoblin/plugins/openid/templates/mediagoblin/plugins/openid/delete.html
@@ -0,0 +1,43 @@
+{#
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#}
+{% extends "mediagoblin/base.html" %}
+
+{% import "/mediagoblin/utils/wtforms.html" as wtforms_util %}
+
+{% block title -%}
+ {% trans %}Delete an OpenID{% endtrans %} &mdash; {{ super() }}
+{%- endblock %}
+
+{% block mediagoblin_content %}
+ <form action="{{ request.urlgen('mediagoblin.plugins.openid.delete') }}"
+ method="POST" enctype="multipart/form-data">
+ {{ csrf_token }}
+ <div class="form_box">
+ <h1>{% trans %}Delete an OpenID{% endtrans %}</h1>
+ <p>
+ <a href="{{ request.urlgen('mediagoblin.plugins.openid.edit') }}">
+ {% trans %}Add an OpenID{% endtrans %}
+ </a>
+ </p>
+ {{ wtforms_util.render_divs(form, True) }}
+ <div class="form_submit_buttons">
+ <input type="submit" value="{% trans %}Delete{% endtrans %}" class="button_form"/>
+ </div>
+ </div>
+ </form>
+{% endblock %}
diff --git a/mediagoblin/plugins/openid/templates/mediagoblin/plugins/openid/edit_link.html b/mediagoblin/plugins/openid/templates/mediagoblin/plugins/openid/edit_link.html
new file mode 100644
index 00000000..2e63e1f8
--- /dev/null
+++ b/mediagoblin/plugins/openid/templates/mediagoblin/plugins/openid/edit_link.html
@@ -0,0 +1,25 @@
+{#
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#}
+
+{% block openid_edit_link %}
+ <p>
+ <a href="{{ request.urlgen('mediagoblin.plugins.openid.edit') }}">
+ {% trans %}Edit your OpenID's{% endtrans %}
+ </a>
+ </p>
+{% endblock %}
diff --git a/mediagoblin/plugins/openid/templates/mediagoblin/plugins/openid/login.html b/mediagoblin/plugins/openid/templates/mediagoblin/plugins/openid/login.html
new file mode 100644
index 00000000..33df7200
--- /dev/null
+++ b/mediagoblin/plugins/openid/templates/mediagoblin/plugins/openid/login.html
@@ -0,0 +1,65 @@
+{#
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#}
+{% extends "mediagoblin/base.html" %}
+
+{% import "/mediagoblin/utils/wtforms.html" as wtforms_util %}
+
+{% block mediagoblin_head %}
+ <script type="text/javascript"
+ src="{{ request.staticdirect('/js/autofilledin_password.js') }}"></script>
+{% endblock %}
+
+{% block title -%}
+ {% trans %}Log in{% endtrans %} &mdash; {{ super() }}
+{%- endblock %}
+
+{% block mediagoblin_content %}
+ <form action="{{ post_url }}"
+ method="POST" enctype="multipart/form-data">
+ {{ csrf_token }}
+ <div class="form_box">
+ <h1>{% trans %}Log in{% endtrans %}</h1>
+ {% if login_failed %}
+ <div class="form_field_error">
+ {% trans %}Logging in failed!{% endtrans %}
+ </div>
+ {% endif %}
+ {% if allow_registration %}
+ <p>
+ {% trans %}Log in to create an account!{% endtrans %}
+ </p>
+ {% endif %}
+ {% if pass_auth is defined %}
+ <p>
+ <a href="{{ request.urlgen('mediagoblin.auth.login') }}?{{ request.query_string }}">
+ {%- trans %}Or login with a password!{% endtrans %}
+ </a>
+ </p>
+ {% endif %}
+ {{ wtforms_util.render_divs(login_form, True) }}
+ <div class="form_submit_buttons">
+ <input type="submit" value="{% trans %}Log in{% endtrans %}" class="button_form"/>
+ </div>
+ {% if next %}
+ <input type="hidden" name="next" value="{{ next }}" class="button_form"
+ style="display: none;"/>
+ {% endif %}
+ </div>
+ </form>
+{% endblock %}
+
diff --git a/mediagoblin/plugins/openid/templates/mediagoblin/plugins/openid/login_link.html b/mediagoblin/plugins/openid/templates/mediagoblin/plugins/openid/login_link.html
new file mode 100644
index 00000000..e5e77d01
--- /dev/null
+++ b/mediagoblin/plugins/openid/templates/mediagoblin/plugins/openid/login_link.html
@@ -0,0 +1,25 @@
+{#
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#}
+
+{% block openid_login_link %}
+ <p>
+ <a href="{{ request.urlgen('mediagoblin.plugins.openid.login') }}?{{ request.query_string }}">
+ {%- trans %}Or login with OpenID!{% endtrans %}
+ </a>
+ </p>
+{% endblock %}
diff --git a/mediagoblin/plugins/openid/templates/mediagoblin/plugins/openid/register_link.html b/mediagoblin/plugins/openid/templates/mediagoblin/plugins/openid/register_link.html
new file mode 100644
index 00000000..9bccb4d8
--- /dev/null
+++ b/mediagoblin/plugins/openid/templates/mediagoblin/plugins/openid/register_link.html
@@ -0,0 +1,27 @@
+{#
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#}
+
+{% block openid_register_link %}
+ {% if openid_link is defined %}
+ <p>
+ <a href="{{ request.urlgen('mediagoblin.plugins.openid.login') }}">
+ {%- trans %}Or register with OpenID!{% endtrans %}
+ </a>
+ </p>
+ {% endif %}
+{% endblock %}
diff --git a/mediagoblin/plugins/openid/templates/mediagoblin/plugins/openid/request_form.html b/mediagoblin/plugins/openid/templates/mediagoblin/plugins/openid/request_form.html
new file mode 100644
index 00000000..68d028d0
--- /dev/null
+++ b/mediagoblin/plugins/openid/templates/mediagoblin/plugins/openid/request_form.html
@@ -0,0 +1,24 @@
+{#
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#}
+{% extends "mediagoblin/base.html" %}
+
+{% block mediagoblin_content %}
+ <div onload="document.getElementById('openid_message').submit()">
+ {{ html|safe }}
+ </div>
+{% endblock %}
diff --git a/mediagoblin/plugins/openid/views.py b/mediagoblin/plugins/openid/views.py
new file mode 100644
index 00000000..b639a4cb
--- /dev/null
+++ b/mediagoblin/plugins/openid/views.py
@@ -0,0 +1,404 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+from openid.consumer import consumer
+from openid.consumer.discover import DiscoveryFailure
+from openid.extensions.sreg import SRegRequest, SRegResponse
+
+from mediagoblin import mg_globals, messages
+from mediagoblin.db.models import User
+from mediagoblin.decorators import (auth_enabled, allow_registration,
+ require_active_login)
+from mediagoblin.tools.response import redirect, render_to_response
+from mediagoblin.tools.translate import pass_to_ugettext as _
+from mediagoblin.plugins.openid import forms as auth_forms
+from mediagoblin.plugins.openid.models import OpenIDUserURL
+from mediagoblin.plugins.openid.store import SQLAlchemyOpenIDStore
+from mediagoblin.auth.tools import register_user
+
+
+def _start_verification(request, form, return_to, sreg=True):
+ """
+ Start OpenID Verification.
+
+ Returns False if verification fails, otherwise, will return either a
+ redirect or render_to_response object
+ """
+ openid_url = form.openid.data
+ c = consumer.Consumer(request.session, SQLAlchemyOpenIDStore())
+
+ # Try to discover provider
+ try:
+ auth_request = c.begin(openid_url)
+ except DiscoveryFailure:
+ # Discovery failed, return to login page
+ form.openid.errors.append(
+ _('Sorry, the OpenID server could not be found'))
+
+ return False
+
+ host = 'http://' + request.host
+
+ if sreg:
+ # Ask provider for email and nickname
+ auth_request.addExtension(SRegRequest(required=['email', 'nickname']))
+
+ # Do we even need this?
+ if auth_request is None:
+ form.openid.errors.append(
+ _('No OpenID service was found for %s' % openid_url))
+
+ elif auth_request.shouldSendRedirect():
+ # Begin the authentication process as a HTTP redirect
+ redirect_url = auth_request.redirectURL(
+ host, return_to)
+
+ return redirect(
+ request, location=redirect_url)
+
+ else:
+ # Send request as POST
+ form_html = auth_request.htmlMarkup(
+ host, host + return_to,
+ # Is this necessary?
+ form_tag_attrs={'id': 'openid_message'})
+
+ # Beware: this renders a template whose content is a form
+ # and some javascript to submit it upon page load. Non-JS
+ # users will have to click the form submit button to
+ # initiate OpenID authentication.
+ return render_to_response(
+ request,
+ 'mediagoblin/plugins/openid/request_form.html',
+ {'html': form_html})
+
+ return False
+
+
+def _finish_verification(request):
+ """
+ Complete OpenID Verification Process.
+
+ If the verification failed, will return false, otherwise, will return
+ the response
+ """
+ c = consumer.Consumer(request.session, SQLAlchemyOpenIDStore())
+
+ # Check the response from the provider
+ response = c.complete(request.args, request.base_url)
+ if response.status == consumer.FAILURE:
+ messages.add_message(
+ request,
+ messages.WARNING,
+ _('Verification of %s failed: %s' %
+ (response.getDisplayIdentifier(), response.message)))
+
+ elif response.status == consumer.SUCCESS:
+ # Verification was successfull
+ return response
+
+ elif response.status == consumer.CANCEL:
+ # Verification canceled
+ messages.add_message(
+ request,
+ messages.WARNING,
+ _('Verification cancelled'))
+
+ return False
+
+
+def _response_email(response):
+ """ Gets the email from the OpenID providers response"""
+ sreg_response = SRegResponse.fromSuccessResponse(response)
+ if sreg_response and 'email' in sreg_response:
+ return sreg_response.data['email']
+ return None
+
+
+def _response_nickname(response):
+ """ Gets the nickname from the OpenID providers response"""
+ sreg_response = SRegResponse.fromSuccessResponse(response)
+ if sreg_response and 'nickname' in sreg_response:
+ return sreg_response.data['nickname']
+ return None
+
+
+@auth_enabled
+def login(request):
+ """OpenID Login View"""
+ login_form = auth_forms.LoginForm(request.form)
+ allow_registration = mg_globals.app_config["allow_registration"]
+
+ # Can't store next in request.GET because of redirects to OpenID provider
+ # Store it in the session
+ next = request.GET.get('next')
+ request.session['next'] = next
+
+ login_failed = False
+
+ if request.method == 'POST' and login_form.validate():
+ return_to = request.urlgen(
+ 'mediagoblin.plugins.openid.finish_login')
+
+ success = _start_verification(request, login_form, return_to)
+
+ if success:
+ return success
+
+ login_failed = True
+
+ return render_to_response(
+ request,
+ 'mediagoblin/plugins/openid/login.html',
+ {'login_form': login_form,
+ 'next': request.session.get('next'),
+ 'login_failed': login_failed,
+ 'post_url': request.urlgen('mediagoblin.plugins.openid.login'),
+ 'allow_registration': allow_registration})
+
+
+@auth_enabled
+def finish_login(request):
+ """Complete OpenID Login Process"""
+ response = _finish_verification(request)
+
+ if not response:
+ # Verification failed, redirect to login page.
+ return redirect(request, 'mediagoblin.plugins.openid.login')
+
+ # Verification was successfull
+ query = OpenIDUserURL.query.filter_by(
+ openid_url=response.identity_url,
+ ).first()
+ user = query.user if query else None
+
+ if user:
+ # Set up login in session
+ request.session['user_id'] = unicode(user.id)
+ request.session.save()
+
+ if request.session.get('next'):
+ return redirect(request, location=request.session.pop('next'))
+ else:
+ return redirect(request, "index")
+ else:
+ # No user, need to register
+ if not mg_globals.app.auth:
+ messages.add_message(
+ request,
+ messages.WARNING,
+ _('Sorry, authentication is disabled on this instance.'))
+ return redirect(request, 'index')
+
+ # Get email and nickname from response
+ email = _response_email(response)
+ username = _response_nickname(response)
+
+ register_form = auth_forms.RegistrationForm(request.form,
+ openid=response.identity_url,
+ email=email,
+ username=username)
+ return render_to_response(
+ request,
+ 'mediagoblin/auth/register.html',
+ {'register_form': register_form,
+ 'post_url': request.urlgen('mediagoblin.plugins.openid.register')})
+
+
+@allow_registration
+@auth_enabled
+def register(request):
+ """OpenID Registration View"""
+ if request.method == 'GET':
+ # Need to connect to openid provider before registering a user to
+ # get the users openid url. If method is 'GET', then this page was
+ # acessed without logging in first.
+ return redirect(request, 'mediagoblin.plugins.openid.login')
+
+ register_form = auth_forms.RegistrationForm(request.form)
+
+ if register_form.validate():
+ user = register_user(request, register_form)
+
+ if user:
+ # redirect the user to their homepage... there will be a
+ # message waiting for them to verify their email
+ return redirect(
+ request, 'mediagoblin.user_pages.user_home',
+ user=user.username)
+
+ return render_to_response(
+ request,
+ 'mediagoblin/auth/register.html',
+ {'register_form': register_form,
+ 'post_url': request.urlgen('mediagoblin.plugins.openid.register')})
+
+
+@require_active_login
+def start_edit(request):
+ """Starts the process of adding an openid url to a users account"""
+ form = auth_forms.LoginForm(request.form)
+
+ if request.method == 'POST' and form.validate():
+ query = OpenIDUserURL.query.filter_by(
+ openid_url=form.openid.data
+ ).first()
+ user = query.user if query else None
+
+ if not user:
+ return_to = request.urlgen('mediagoblin.plugins.openid.finish_edit')
+ success = _start_verification(request, form, return_to, False)
+
+ if success:
+ return success
+ else:
+ form.openid.errors.append(
+ _('Sorry, an account is already registered to that OpenID.'))
+
+ return render_to_response(
+ request,
+ 'mediagoblin/plugins/openid/add.html',
+ {'form': form,
+ 'post_url': request.urlgen('mediagoblin.plugins.openid.edit')})
+
+
+@require_active_login
+def finish_edit(request):
+ """Finishes the process of adding an openid url to a user"""
+ response = _finish_verification(request)
+
+ if not response:
+ # Verification failed, redirect to add openid page.
+ return redirect(request, 'mediagoblin.plugins.openid.edit')
+
+ # Verification was successfull
+ query = OpenIDUserURL.query.filter_by(
+ openid_url=response.identity_url,
+ ).first()
+ user_exists = query.user if query else None
+
+ if user_exists:
+ # user exists with that openid url, redirect back to edit page
+ messages.add_message(
+ request,
+ messages.WARNING,
+ _('Sorry, an account is already registered to that OpenID.'))
+ return redirect(request, 'mediagoblin.plugins.openid.edit')
+
+ else:
+ # Save openid to user
+ user = User.query.filter_by(
+ id=request.session['user_id']
+ ).first()
+
+ new_entry = OpenIDUserURL()
+ new_entry.openid_url = response.identity_url
+ new_entry.user_id = user.id
+ new_entry.save()
+
+ messages.add_message(
+ request,
+ messages.SUCCESS,
+ _('Your OpenID url was saved successfully.'))
+
+ return redirect(request, 'mediagoblin.edit.account')
+
+
+@require_active_login
+def delete_openid(request):
+ """View to remove an openid from a users account"""
+ form = auth_forms.LoginForm(request.form)
+
+ if request.method == 'POST' and form.validate():
+ # Check if a user has this openid
+ query = OpenIDUserURL.query.filter_by(
+ openid_url=form.openid.data
+ )
+ user = query.first().user if query.first() else None
+
+ if user and user.id == int(request.session['user_id']):
+ count = len(user.openid_urls)
+ if not count > 1 and not user.pw_hash:
+ # Make sure the user has a pw or another OpenID
+ messages.add_message(
+ request,
+ messages.WARNING,
+ _("You can't delete your only OpenID URL unless you"
+ " have a password set"))
+ elif user:
+ # There is a user, but not the same user who is logged in
+ form.openid.errors.append(
+ _('That OpenID is not registered to this account.'))
+
+ if not form.errors and not request.session.get('messages'):
+ # Okay to continue with deleting openid
+ return_to = request.urlgen(
+ 'mediagoblin.plugins.openid.finish_delete')
+ success = _start_verification(request, form, return_to, False)
+
+ if success:
+ return success
+
+ return render_to_response(
+ request,
+ 'mediagoblin/plugins/openid/delete.html',
+ {'form': form,
+ 'post_url': request.urlgen('mediagoblin.plugins.openid.delete')})
+
+
+@require_active_login
+def finish_delete(request):
+ """Finishes the deletion of an OpenID from an user's account"""
+ response = _finish_verification(request)
+
+ if not response:
+ # Verification failed, redirect to delete openid page.
+ return redirect(request, 'mediagoblin.plugins.openid.delete')
+
+ query = OpenIDUserURL.query.filter_by(
+ openid_url=response.identity_url
+ )
+ user = query.first().user if query.first() else None
+
+ # Need to check this again because of generic openid urls such as google's
+ if user and user.id == int(request.session['user_id']):
+ count = len(user.openid_urls)
+ if count > 1 or user.pw_hash:
+ # User has more then one openid or also has a password.
+ query.first().delete()
+
+ messages.add_message(
+ request,
+ messages.SUCCESS,
+ _('OpenID was successfully removed.'))
+
+ return redirect(request, 'mediagoblin.edit.account')
+
+ elif not count > 1:
+ messages.add_message(
+ request,
+ messages.WARNING,
+ _("You can't delete your only OpenID URL unless you have a "
+ "password set"))
+
+ return redirect(request, 'mediagoblin.plugins.openid.delete')
+
+ else:
+ messages.add_message(
+ request,
+ messages.WARNING,
+ _('That OpenID is not registered to this account.'))
+
+ return redirect(request, 'mediagoblin.plugins.openid.delete')
diff --git a/mediagoblin/plugins/piwigo/README.rst b/mediagoblin/plugins/piwigo/README.rst
new file mode 100644
index 00000000..0c71ffbc
--- /dev/null
+++ b/mediagoblin/plugins/piwigo/README.rst
@@ -0,0 +1,23 @@
+===================
+ piwigo api plugin
+===================
+
+.. danger::
+ This plugin does not work.
+ It might make your instance unstable or even insecure.
+ So do not use it, unless you want to help to develop it.
+
+.. warning::
+ You should not depend on this plugin in any way for now.
+ It might even go away without any notice.
+
+Okay, so if you still want to test this plugin,
+add the following to your mediagoblin_local.ini:
+
+.. code-block:: ini
+
+ [plugins]
+ [[mediagoblin.plugins.piwigo]]
+
+Then try to connect using some piwigo client.
+There should be some logging, that might help.
diff --git a/mediagoblin/plugins/piwigo/__init__.py b/mediagoblin/plugins/piwigo/__init__.py
new file mode 100644
index 00000000..c4da708a
--- /dev/null
+++ b/mediagoblin/plugins/piwigo/__init__.py
@@ -0,0 +1,42 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2013 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import logging
+
+from mediagoblin.tools import pluginapi
+from mediagoblin.tools.session import SessionManager
+from .tools import PWGSession
+
+_log = logging.getLogger(__name__)
+
+
+def setup_plugin():
+ _log.info('Setting up piwigo...')
+
+ routes = [
+ ('mediagoblin.plugins.piwigo.wsphp',
+ '/api/piwigo/ws.php',
+ 'mediagoblin.plugins.piwigo.views:ws_php'),
+ ]
+
+ pluginapi.register_routes(routes)
+
+ PWGSession.session_manager = SessionManager("pwg_id", "plugins.piwigo")
+
+
+hooks = {
+ 'setup': setup_plugin
+}
diff --git a/mediagoblin/plugins/piwigo/forms.py b/mediagoblin/plugins/piwigo/forms.py
new file mode 100644
index 00000000..fb04aa6a
--- /dev/null
+++ b/mediagoblin/plugins/piwigo/forms.py
@@ -0,0 +1,44 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2013 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+
+import wtforms
+
+
+class AddSimpleForm(wtforms.Form):
+ image = wtforms.FileField()
+ name = wtforms.TextField(
+ validators=[wtforms.validators.Length(min=0, max=500)])
+ comment = wtforms.TextField()
+ # tags = wtforms.FieldList(wtforms.TextField())
+ category = wtforms.IntegerField()
+ level = wtforms.IntegerField()
+
+
+_md5_validator = wtforms.validators.Regexp(r"^[0-9a-fA-F]{32}$")
+
+
+class AddForm(wtforms.Form):
+ original_sum = wtforms.TextField(None,
+ [_md5_validator,
+ wtforms.validators.Required()])
+ thumbnail_sum = wtforms.TextField(None,
+ [wtforms.validators.Optional(),
+ _md5_validator])
+ file_sum = wtforms.TextField(None, [_md5_validator])
+ name = wtforms.TextField()
+ date_creation = wtforms.TextField()
+ categories = wtforms.TextField()
diff --git a/mediagoblin/plugins/piwigo/tools.py b/mediagoblin/plugins/piwigo/tools.py
new file mode 100644
index 00000000..484ea531
--- /dev/null
+++ b/mediagoblin/plugins/piwigo/tools.py
@@ -0,0 +1,165 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2013 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+from collections import namedtuple
+import logging
+
+import six
+import lxml.etree as ET
+from werkzeug.exceptions import MethodNotAllowed, BadRequest
+
+from mediagoblin.tools.request import setup_user_in_request
+from mediagoblin.tools.response import Response
+
+
+_log = logging.getLogger(__name__)
+
+
+PwgError = namedtuple("PwgError", ["code", "msg"])
+
+
+class PwgNamedArray(list):
+ def __init__(self, l, item_name, as_attrib=()):
+ self.item_name = item_name
+ self.as_attrib = as_attrib
+ list.__init__(self, l)
+
+ def fill_element_xml(self, el):
+ for it in self:
+ n = ET.SubElement(el, self.item_name)
+ if isinstance(it, dict):
+ _fill_element_dict(n, it, self.as_attrib)
+ else:
+ _fill_element(n, it)
+
+
+def _fill_element_dict(el, data, as_attr=()):
+ for k, v in data.iteritems():
+ if k in as_attr:
+ if not isinstance(v, six.string_types):
+ v = str(v)
+ el.set(k, v)
+ else:
+ n = ET.SubElement(el, k)
+ _fill_element(n, v)
+
+
+def _fill_element(el, data):
+ if isinstance(data, bool):
+ if data:
+ el.text = "1"
+ else:
+ el.text = "0"
+ elif isinstance(data, six.string_types):
+ el.text = data
+ elif isinstance(data, int):
+ el.text = str(data)
+ elif isinstance(data, dict):
+ _fill_element_dict(el, data)
+ elif isinstance(data, PwgNamedArray):
+ data.fill_element_xml(el)
+ else:
+ _log.warn("Can't convert to xml: %r", data)
+
+
+def response_xml(result):
+ r = ET.Element("rsp")
+ r.set("stat", "ok")
+ status = None
+ if isinstance(result, PwgError):
+ r.set("stat", "fail")
+ err = ET.SubElement(r, "err")
+ err.set("code", str(result.code))
+ err.set("msg", result.msg)
+ if result.code >= 100 and result.code < 600:
+ status = result.code
+ else:
+ _fill_element(r, result)
+ return Response(ET.tostring(r, encoding="utf-8", xml_declaration=True),
+ mimetype='text/xml', status=status)
+
+
+class CmdTable(object):
+ _cmd_table = {}
+
+ def __init__(self, cmd_name, only_post=False):
+ assert not cmd_name in self._cmd_table
+ self.cmd_name = cmd_name
+ self.only_post = only_post
+
+ def __call__(self, to_be_wrapped):
+ assert not self.cmd_name in self._cmd_table
+ self._cmd_table[self.cmd_name] = (to_be_wrapped, self.only_post)
+ return to_be_wrapped
+
+ @classmethod
+ def find_func(cls, request):
+ if request.method == "GET":
+ cmd_name = request.args.get("method")
+ else:
+ cmd_name = request.form.get("method")
+ entry = cls._cmd_table.get(cmd_name)
+ if not entry:
+ return entry
+ _log.debug("Found method %s", cmd_name)
+ func, only_post = entry
+ if only_post and request.method != "POST":
+ _log.warn("Method %s only allowed for POST", cmd_name)
+ raise MethodNotAllowed()
+ return func
+
+
+def check_form(form):
+ if not form.validate():
+ _log.error("form validation failed for form %r", form)
+ for f in form:
+ if len(f.errors):
+ _log.error("Errors for %s: %r", f.name, f.errors)
+ raise BadRequest()
+ dump = []
+ for f in form:
+ dump.append("%s=%r" % (f.name, f.data))
+ _log.debug("form: %s", " ".join(dump))
+
+
+class PWGSession(object):
+ session_manager = None
+
+ def __init__(self, request):
+ self.request = request
+ self.in_pwg_session = False
+
+ def __enter__(self):
+ # Backup old state
+ self.old_session = self.request.session
+ self.old_user = self.request.user
+ # Load piwigo session into state
+ self.request.session = self.session_manager.load_session_from_cookie(
+ self.request)
+ setup_user_in_request(self.request)
+ self.in_pwg_session = True
+ return self
+
+ def __exit__(self, *args):
+ # Restore state
+ self.request.session = self.old_session
+ self.request.user = self.old_user
+ self.in_pwg_session = False
+
+ def save_to_cookie(self, response):
+ assert self.in_pwg_session
+ self.session_manager.save_session_to_cookie(self.request.session,
+ self.request, response)
diff --git a/mediagoblin/plugins/piwigo/views.py b/mediagoblin/plugins/piwigo/views.py
new file mode 100644
index 00000000..ca723189
--- /dev/null
+++ b/mediagoblin/plugins/piwigo/views.py
@@ -0,0 +1,249 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2013 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import logging
+import re
+from os.path import splitext
+import shutil
+
+from werkzeug.exceptions import MethodNotAllowed, BadRequest, NotImplemented
+from werkzeug.wrappers import BaseResponse
+
+from mediagoblin.meddleware.csrf import csrf_exempt
+from mediagoblin.auth.tools import check_login_simple
+from mediagoblin.media_types import sniff_media
+from mediagoblin.submit.lib import check_file_field, prepare_queue_task, \
+ run_process_media, new_upload_entry
+
+from mediagoblin.user_pages.lib import add_media_to_collection
+from mediagoblin.db.models import Collection
+
+from .tools import CmdTable, response_xml, check_form, \
+ PWGSession, PwgNamedArray, PwgError
+from .forms import AddSimpleForm, AddForm
+
+
+_log = logging.getLogger(__name__)
+
+
+@CmdTable("pwg.session.login", True)
+def pwg_login(request):
+ username = request.form.get("username")
+ password = request.form.get("password")
+ user = check_login_simple(username, password)
+ if not user:
+ return PwgError(999, 'Invalid username/password')
+ request.session["user_id"] = user.id
+ request.session.save()
+ return True
+
+
+@CmdTable("pwg.session.logout")
+def pwg_logout(request):
+ _log.info("Logout")
+ request.session.delete()
+ return True
+
+
+@CmdTable("pwg.getVersion")
+def pwg_getversion(request):
+ return "2.5.0 (MediaGoblin)"
+
+
+@CmdTable("pwg.session.getStatus")
+def pwg_session_getStatus(request):
+ if request.user:
+ username = request.user.username
+ else:
+ username = "guest"
+ return {'username': username}
+
+
+@CmdTable("pwg.categories.getList")
+def pwg_categories_getList(request):
+ catlist = [{'id': -29711,
+ 'uppercats': "-29711",
+ 'name': "All my images"}]
+
+ if request.user:
+ collections = Collection.query.filter_by(
+ get_creator=request.user).order_by(Collection.title)
+
+ for c in collections:
+ catlist.append({'id': c.id,
+ 'uppercats': str(c.id),
+ 'name': c.title,
+ 'comment': c.description
+ })
+
+ return {
+ 'categories': PwgNamedArray(
+ catlist,
+ 'category',
+ (
+ 'id',
+ 'url',
+ 'nb_images',
+ 'total_nb_images',
+ 'nb_categories',
+ 'date_last',
+ 'max_date_last',
+ )
+ )
+ }
+
+
+@CmdTable("pwg.images.exist")
+def pwg_images_exist(request):
+ return {}
+
+
+@CmdTable("pwg.images.addSimple", True)
+def pwg_images_addSimple(request):
+ form = AddSimpleForm(request.form)
+ if not form.validate():
+ _log.error("addSimple: form failed")
+ raise BadRequest()
+ dump = []
+ for f in form:
+ dump.append("%s=%r" % (f.name, f.data))
+ _log.info("addSimple: %r %s %r", request.form, " ".join(dump),
+ request.files)
+
+ if not check_file_field(request, 'image'):
+ raise BadRequest()
+
+ filename = request.files['image'].filename
+
+ # Sniff the submitted media to determine which
+ # media plugin should handle processing
+ media_type, media_manager = sniff_media(
+ request.files['image'])
+
+ # create entry and save in database
+ entry = new_upload_entry(request.user)
+ entry.media_type = unicode(media_type)
+ entry.title = (
+ unicode(form.name.data)
+ or unicode(splitext(filename)[0]))
+
+ entry.description = unicode(form.comment.data)
+
+ '''
+ # Process the user's folksonomy "tags"
+ entry.tags = convert_to_tag_list_of_dicts(
+ form.tags.data)
+ '''
+
+ # Generate a slug from the title
+ entry.generate_slug()
+
+ queue_file = prepare_queue_task(request.app, entry, filename)
+
+ with queue_file:
+ shutil.copyfileobj(request.files['image'].stream,
+ queue_file,
+ length=4 * 1048576)
+
+ # Save now so we have this data before kicking off processing
+ entry.save()
+
+ # Pass off to processing
+ #
+ # (... don't change entry after this point to avoid race
+ # conditions with changes to the document via processing code)
+ feed_url = request.urlgen(
+ 'mediagoblin.user_pages.atom_feed',
+ qualified=True, user=request.user.username)
+ run_process_media(entry, feed_url)
+
+ collection_id = form.category.data
+ if collection_id > 0:
+ collection = Collection.query.get(collection_id)
+ if collection is not None and collection.creator == request.user.id:
+ add_media_to_collection(collection, entry, "")
+
+ return {'image_id': entry.id, 'url': entry.url_for_self(request.urlgen,
+ qualified=True)}
+
+
+md5sum_matcher = re.compile(r"^[0-9a-fA-F]{32}$")
+
+
+def fetch_md5(request, parm_name, optional_parm=False):
+ val = request.form.get(parm_name)
+ if (val is None) and (not optional_parm):
+ _log.error("Parameter %s missing", parm_name)
+ raise BadRequest("Parameter %s missing" % parm_name)
+ if not md5sum_matcher.match(val):
+ _log.error("Parameter %s=%r has no valid md5 value", parm_name, val)
+ raise BadRequest("Parameter %s is not md5" % parm_name)
+ return val
+
+
+@CmdTable("pwg.images.addChunk", True)
+def pwg_images_addChunk(request):
+ o_sum = fetch_md5(request, 'original_sum')
+ typ = request.form.get('type')
+ pos = request.form.get('position')
+ data = request.form.get('data')
+
+ # Validate params:
+ pos = int(pos)
+ if not typ in ("file", "thumb"):
+ _log.error("type %r not allowed for now", typ)
+ return False
+
+ _log.info("addChunk for %r, type %r, position %d, len: %d",
+ o_sum, typ, pos, len(data))
+ if typ == "thumb":
+ _log.info("addChunk: Ignoring thumb, because we create our own")
+ return True
+
+ return True
+
+
+@CmdTable("pwg.images.add", True)
+def pwg_images_add(request):
+ _log.info("add: %r", request.form)
+ form = AddForm(request.form)
+ check_form(form)
+
+ return {'image_id': 123456, 'url': ''}
+
+
+@csrf_exempt
+def ws_php(request):
+ if request.method not in ("GET", "POST"):
+ _log.error("Method %r not supported", request.method)
+ raise MethodNotAllowed()
+
+ func = CmdTable.find_func(request)
+ if not func:
+ _log.warn("wsphp: Unhandled %s %r %r", request.method,
+ request.args, request.form)
+ raise NotImplemented()
+
+ with PWGSession(request) as session:
+ result = func(request)
+
+ if isinstance(result, BaseResponse):
+ return result
+
+ response = response_xml(result)
+ session.save_to_cookie(response)
+
+ return response
diff --git a/mediagoblin/plugins/raven/README.rst b/mediagoblin/plugins/raven/README.rst
index de5fd20d..4006060d 100644
--- a/mediagoblin/plugins/raven/README.rst
+++ b/mediagoblin/plugins/raven/README.rst
@@ -4,6 +4,8 @@
.. _raven-setup:
+Warning: this plugin is somewhat experimental.
+
Set up the raven plugin
=======================
diff --git a/mediagoblin/processing/__init__.py b/mediagoblin/processing/__init__.py
index f9445e28..f3a85940 100644
--- a/mediagoblin/processing/__init__.py
+++ b/mediagoblin/processing/__init__.py
@@ -75,6 +75,14 @@ class FilenameBuilder(object):
class ProcessingState(object):
+ """
+ The first and only argument to the "processor" of a media type
+
+ This could be thought of as a "request" to the processor
+ function. It has the main info for the request (media entry)
+ and a bunch of tools for the request on it.
+ It can get more fancy without impacting old media types.
+ """
def __init__(self, entry):
self.entry = entry
self.workbench = None
@@ -97,14 +105,27 @@ class ProcessingState(object):
return queued_filename
def copy_original(self, target_name, keyname=u"original"):
+ self.store_public(keyname, self.get_queued_filename(), target_name)
+
+ def store_public(self, keyname, local_file, target_name=None):
+ if target_name is None:
+ target_name = os.path.basename(local_file)
target_filepath = create_pub_filepath(self.entry, target_name)
- mgg.public_store.copy_local_to_storage(self.get_queued_filename(),
- target_filepath)
+ if keyname in self.entry.media_files:
+ _log.warn("store_public: keyname %r already used for file %r, "
+ "replacing with %r", keyname,
+ self.entry.media_files[keyname], target_filepath)
+ mgg.public_store.copy_local_to_storage(local_file, target_filepath)
self.entry.media_files[keyname] = target_filepath
def delete_queue_file(self):
+ # Remove queued media file from storage and database.
+ # queued_filepath is in the task_id directory which should
+ # be removed too, but fail if the directory is not empty to be on
+ # the super-safe side.
queued_filepath = self.entry.queued_media_file
- mgg.queue_store.delete_file(queued_filepath)
+ mgg.queue_store.delete_file(queued_filepath) # rm file
+ mgg.queue_store.delete_dir(queued_filepath[:-1]) # rm dir
self.entry.queued_media_file = []
diff --git a/mediagoblin/processing/task.py b/mediagoblin/processing/task.py
index aec50aab..9af192ed 100644
--- a/mediagoblin/processing/task.py
+++ b/mediagoblin/processing/task.py
@@ -89,7 +89,7 @@ class ProcessMedia(task.Task):
with mgg.workbench_manager.create() as workbench:
proc_state.set_workbench(workbench)
# run the processing code
- entry.media_manager['processor'](proc_state)
+ entry.media_manager.processor(proc_state)
# We set the state to processed and save the entry here so there's
# no need to save at the end of the processing stage, probably ;)
diff --git a/mediagoblin/routing.py b/mediagoblin/routing.py
index a650f22f..986eb2ed 100644
--- a/mediagoblin/routing.py
+++ b/mediagoblin/routing.py
@@ -35,6 +35,7 @@ def get_url_map():
import mediagoblin.edit.routing
import mediagoblin.webfinger.routing
import mediagoblin.listings.routing
+ import mediagoblin.notifications.routing
for route in PluginManager().get_routes():
add_route(*route)
diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css
index 8df9f2e1..84d274d1 100644
--- a/mediagoblin/static/css/base.css
+++ b/mediagoblin/static/css/base.css
@@ -129,6 +129,7 @@ header {
.header_dropdown {
margin-bottom: 20px;
+ padding: 0px 10px 0px 10px;
}
.header_dropdown li {
@@ -333,6 +334,10 @@ text-align: center;
width: 20px;
}
+.boolean {
+ margin-bottom: 8px;
+ }
+
textarea#description, textarea#bio {
resize: vertical;
height: 100px;
@@ -360,11 +365,36 @@ textarea#description, textarea#bio {
font-size: 0.9em;
}
+a.comment_authorlink {
+ text-decoration: none;
+ padding-right: 5px;
+ font-weight: bold;
+ padding-left: 2px;
+}
+
+a.comment_authorlink:hover {
+ text-decoration: underline;
+}
+
+a.comment_whenlink {
+ text-decoration: none;
+}
+
+a.comment_whenlink:hover {
+ text-decoration: underline;
+}
+
.comment_content {
margin-left: 8px;
margin-top: 8px;
}
+.comment_active {
+ box-shadow: 0px 0px 15px 15px #378566;
+ background: #378566;
+ color: #f7f7f7;
+}
+
textarea#comment_content {
resize: vertical;
width: 100%;
@@ -414,9 +444,12 @@ a.thumb_entry_title {
padding: 8px;
}
-.media_thumbnail img {
- max-height: 135px;
-}
+/* For now, this is commented out since our thumbnails are actually 180px high.
+ *
+ * .media_thumbnail img {
+ * max-height: 135px;
+ * }
+ */
.thumb_entry_last {
margin-right: 0px;
@@ -462,6 +495,38 @@ img.media_icon {
vertical-align: sub;
}
+/* EXIF information */
+
+#exif_content h3 {
+ border-bottom: 1px solid #333;
+}
+
+#exif_camera_information {
+ margin-bottom: 20px;
+}
+
+#exif_additional_info {
+ display: none;
+}
+
+#exif_additional_info table {
+ font-size: 11px;
+ margin-top: 10px;
+}
+
+#exif_additional_info td {
+ vertical-align: top;
+ padding-bottom: 5px;
+}
+
+#exif_content .col1 {
+ padding-right: 20px;
+}
+
+#exif_additional_info table tr {
+ margin-bottom: 10px;
+}
+
/* navigation */
.navigation {
@@ -540,6 +605,7 @@ table.media_panel {
table.media_panel th {
font-weight: bold;
padding-bottom: 4px;
+ text-align: left;
}
@@ -665,3 +731,29 @@ pre {
width: 46%;
}
}
+
+/* Exif display */
+#exif_content h3 {
+ border-bottom: 1px solid #333;
+}
+#exif_camera_information {
+ margin-bottom: 20px;
+}
+
+#exif_additional_info {
+ display: none;
+}
+#exif_additional_info table {
+ font-size: 11px;
+ margin-top: 10px;
+}
+#exif_additional_info td {
+ vertical-align: top;
+ padding-bottom: 5px;
+}
+#exif_content .col1 {
+ padding-right: 20px;
+}
+#exif_additional_info table tr {
+ margin-bottom: 10px;
+}
diff --git a/mediagoblin/static/extlib/pdf.js b/mediagoblin/static/extlib/pdf.js
new file mode 120000
index 00000000..f829660a
--- /dev/null
+++ b/mediagoblin/static/extlib/pdf.js
@@ -0,0 +1 @@
+../../../extlib/pdf.js \ No newline at end of file
diff --git a/mediagoblin/static/js/notifications.js b/mediagoblin/static/js/notifications.js
new file mode 100644
index 00000000..0153463a
--- /dev/null
+++ b/mediagoblin/static/js/notifications.js
@@ -0,0 +1,36 @@
+'use strict';
+/**
+ * GNU MediaGoblin -- federated, autonomous media hosting
+ * Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+var notifications = {};
+
+(function (n) {
+ n._base = '/';
+ n._endpoint = 'notifications/json';
+
+ n.init = function () {
+ $('.notification-gem').on('click', function () {
+ $('.header_dropdown_down:visible').click();
+ });
+ }
+
+})(notifications)
+
+$(document).ready(function () {
+ notifications.init();
+});
diff --git a/mediagoblin/storage/__init__.py b/mediagoblin/storage/__init__.py
index 5c1d7d36..bbe134a7 100644
--- a/mediagoblin/storage/__init__.py
+++ b/mediagoblin/storage/__init__.py
@@ -101,10 +101,20 @@ class StorageInterface(object):
def delete_file(self, filepath):
"""
- Delete or dereference the file at filepath.
+ Delete or dereference the file (not directory) at filepath.
+ """
+ # Subclasses should override this method.
+ self.__raise_not_implemented()
+
+ def delete_dir(self, dirpath, recursive=False):
+ """Delete the directory at dirpath
+
+ :param recursive: Usually, a directory must not contain any
+ files for the delete to succeed. If True, containing files
+ and subdirectories within dirpath will be recursively
+ deleted.
- This might need to delete directories, buckets, whatever, for
- cleanliness. (Be sure to avoid race conditions on that though)
+ :returns: True in case of success, False otherwise.
"""
# Subclasses should override this method.
self.__raise_not_implemented()
diff --git a/mediagoblin/storage/cloudfiles.py b/mediagoblin/storage/cloudfiles.py
index b6e57c91..250f06d4 100644
--- a/mediagoblin/storage/cloudfiles.py
+++ b/mediagoblin/storage/cloudfiles.py
@@ -75,7 +75,7 @@ class CloudFilesStorage(StorageInterface):
_log.debug('Container: {0}'.format(
self.container.name))
- self.container_uri = self.container.public_uri()
+ self.container_uri = self.container.public_ssl_uri()
def _resolve_filepath(self, filepath):
return '/'.join(
diff --git a/mediagoblin/storage/filestorage.py b/mediagoblin/storage/filestorage.py
index ef786b61..3d6e0753 100644
--- a/mediagoblin/storage/filestorage.py
+++ b/mediagoblin/storage/filestorage.py
@@ -62,10 +62,32 @@ class BasicFileStorage(StorageInterface):
return open(self._resolve_filepath(filepath), mode)
def delete_file(self, filepath):
- # TODO: Also delete unused directories if empty (safely, with
- # checks to avoid race conditions).
+ """Delete file at filepath
+
+ Raises OSError in case filepath is a directory."""
+ #TODO: log error
os.remove(self._resolve_filepath(filepath))
+ def delete_dir(self, dirpath, recursive=False):
+ """returns True on succes, False on failure"""
+
+ dirpath = self._resolve_filepath(dirpath)
+
+ # Shortcut the default and simple case of nonempty=F, recursive=F
+ if recursive:
+ try:
+ shutil.rmtree(dirpath)
+ except OSError as e:
+ #TODO: log something here
+ return False
+ else: # recursively delete everything
+ try:
+ os.rmdir(dirpath)
+ except OSError as e:
+ #TODO: log something here
+ return False
+ return True
+
def file_url(self, filepath):
if not self.base_url:
raise NoWebServing(
diff --git a/mediagoblin/submit/forms.py b/mediagoblin/submit/forms.py
index bd1e904f..e9bd93fd 100644
--- a/mediagoblin/submit/forms.py
+++ b/mediagoblin/submit/forms.py
@@ -18,7 +18,7 @@
import wtforms
from mediagoblin.tools.text import tag_length_validator
-from mediagoblin.tools.translate import fake_ugettext_passthrough as _
+from mediagoblin.tools.translate import lazy_pass_to_ugettext as _
from mediagoblin.tools.licenses import licenses_as_choices
diff --git a/mediagoblin/submit/lib.py b/mediagoblin/submit/lib.py
index 679fc543..7e85696b 100644
--- a/mediagoblin/submit/lib.py
+++ b/mediagoblin/submit/lib.py
@@ -17,7 +17,9 @@
import logging
import uuid
from werkzeug.utils import secure_filename
+from werkzeug.datastructures import FileStorage
+from mediagoblin.db.models import MediaEntry
from mediagoblin.processing import mark_entry_failed
from mediagoblin.processing.task import process_media
@@ -25,11 +27,31 @@ from mediagoblin.processing.task import process_media
_log = logging.getLogger(__name__)
+def check_file_field(request, field_name):
+ """Check if a file field meets minimal criteria"""
+ retval = (field_name in request.files
+ and isinstance(request.files[field_name], FileStorage)
+ and request.files[field_name].stream)
+ if not retval:
+ _log.debug("Form did not contain proper file field %s", field_name)
+ return retval
+
+
+def new_upload_entry(user):
+ """
+ Create a new MediaEntry for uploading
+ """
+ entry = MediaEntry()
+ entry.uploader = user.id
+ entry.license = user.license_preference
+ return entry
+
+
def prepare_queue_task(app, entry, filename):
"""
Prepare a MediaEntry for the processing queue and get a queue file
"""
- # We generate this ourselves so we know what the taks id is for
+ # We generate this ourselves so we know what the task id is for
# retrieval later.
# (If we got it off the task's auto-generation, there'd be
diff --git a/mediagoblin/submit/views.py b/mediagoblin/submit/views.py
index def7e839..3f9d5b2d 100644
--- a/mediagoblin/submit/views.py
+++ b/mediagoblin/submit/views.py
@@ -19,10 +19,10 @@ import mediagoblin.mg_globals as mg_globals
from os.path import splitext
import logging
+import uuid
_log = logging.getLogger(__name__)
-from werkzeug.datastructures import FileStorage
from mediagoblin.tools.text import convert_to_tag_list_of_dicts
from mediagoblin.tools.translate import pass_to_ugettext as _
@@ -32,7 +32,10 @@ from mediagoblin.submit import forms as submit_forms
from mediagoblin.messages import add_message, SUCCESS
from mediagoblin.media_types import sniff_media, \
InvalidFileType, FileTypeNotSupported
-from mediagoblin.submit.lib import run_process_media, prepare_queue_task
+from mediagoblin.submit.lib import check_file_field, prepare_queue_task, \
+ run_process_media, new_upload_entry
+
+from mediagoblin.notifications import add_comment_subscription
@require_active_login
@@ -44,36 +47,36 @@ def submit_start(request):
license=request.user.license_preference)
if request.method == 'POST' and submit_form.validate():
- if not ('file' in request.files
- and isinstance(request.files['file'], FileStorage)
- and request.files['file'].stream):
+ if not check_file_field(request, 'file'):
submit_form.file.errors.append(
_(u'You must provide a file.'))
else:
try:
filename = request.files['file'].filename
+ # If the filename contains non ascii generate a unique name
+ if not all(ord(c) < 128 for c in filename):
+ filename = unicode(uuid.uuid4()) + splitext(filename)[-1]
+
# Sniff the submitted media to determine which
# media plugin should handle processing
media_type, media_manager = sniff_media(
request.files['file'])
# create entry and save in database
- entry = request.db.MediaEntry()
+ entry = new_upload_entry(request.user)
entry.media_type = unicode(media_type)
entry.title = (
- unicode(request.form['title'])
- or unicode(splitext(filename)[0]))
-
- entry.description = unicode(request.form.get('description'))
+ unicode(submit_form.title.data)
+ or unicode(splitext(request.files['file'].filename)[0]))
- entry.license = unicode(request.form.get('license', "")) or None
+ entry.description = unicode(submit_form.description.data)
- entry.uploader = request.user.id
+ entry.license = unicode(submit_form.license.data) or None
# Process the user's folksonomy "tags"
entry.tags = convert_to_tag_list_of_dicts(
- request.form.get('tags'))
+ submit_form.tags.data)
# Generate a slug from the title
entry.generate_slug()
@@ -96,6 +99,8 @@ def submit_start(request):
run_process_media(entry, feed_url)
add_message(request, SUCCESS, _('Woohoo! Submitted!'))
+ add_comment_subscription(request.user, entry)
+
return redirect(request, "mediagoblin.user_pages.user_home",
user=request.user.username)
except Exception as e:
@@ -116,6 +121,7 @@ def submit_start(request):
{'submit_form': submit_form,
'app_config': mg_globals.app_config})
+
@require_active_login
def add_collection(request, media=None):
"""
@@ -124,32 +130,30 @@ def add_collection(request, media=None):
submit_form = submit_forms.AddCollectionForm(request.form)
if request.method == 'POST' and submit_form.validate():
- try:
- collection = request.db.Collection()
-
- collection.title = unicode(request.form['title'])
- collection.description = unicode(request.form.get('description'))
- collection.creator = request.user.id
- collection.generate_slug()
-
- # Make sure this user isn't duplicating an existing collection
- existing_collection = request.db.Collection.find_one({
- 'creator': request.user.id,
- 'title':collection.title})
-
- if existing_collection:
- messages.add_message(
- request, messages.ERROR, _('You already have a collection called "%s"!' % collection.title))
- else:
- collection.save()
-
- add_message(request, SUCCESS, _('Collection "%s" added!' % collection.title))
+ collection = request.db.Collection()
+
+ collection.title = unicode(submit_form.title.data)
+ collection.description = unicode(submit_form.description.data)
+ collection.creator = request.user.id
+ collection.generate_slug()
+
+ # Make sure this user isn't duplicating an existing collection
+ existing_collection = request.db.Collection.query.filter_by(
+ creator=request.user.id,
+ title=collection.title).first()
+
+ if existing_collection:
+ add_message(request, messages.ERROR,
+ _('You already have a collection called "%s"!') \
+ % collection.title)
+ else:
+ collection.save()
- return redirect(request, "mediagoblin.user_pages.user_home",
- user=request.user.username)
+ add_message(request, SUCCESS,
+ _('Collection "%s" added!') % collection.title)
- except Exception as e:
- raise
+ return redirect(request, "mediagoblin.user_pages.user_home",
+ user=request.user.username)
return render_to_response(
request,
diff --git a/mediagoblin/templates/mediagoblin/admin/panel.html b/mediagoblin/templates/mediagoblin/admin/panel.html
index 6bcb5c24..1c3c866e 100644
--- a/mediagoblin/templates/mediagoblin/admin/panel.html
+++ b/mediagoblin/templates/mediagoblin/admin/panel.html
@@ -104,7 +104,7 @@
<td>{{ media_entry.id }}</td>
<td>{{ media_entry.get_uploader.username }}</td>
<td><a href="{{ media_entry.url_for_self(request.urlgen) }}">{{ media_entry.title }}</a></td>
- <td>{{ media_entry.created.strftime("%F %R") }}</td>
+ <td><span title='{{ media_entry.created.strftime("%F %R") }}'>{{ timesince(media_entry.created) }}</span></td>
</tr>
{% endfor %}
</table>
diff --git a/mediagoblin/templates/mediagoblin/auth/change_fp.html b/mediagoblin/templates/mediagoblin/auth/change_fp.html
index 1f7d9aca..a3cf9cb9 100644
--- a/mediagoblin/templates/mediagoblin/auth/change_fp.html
+++ b/mediagoblin/templates/mediagoblin/auth/change_fp.html
@@ -34,11 +34,10 @@
{{ csrf_token }}
<div class="form_box">
<h1>{% trans %}Set your new password{% endtrans %}</h1>
- {{ wtforms_util.render_divs(cp_form) }}
+ {{ wtforms_util.render_divs(cp_form, True) }}
<div class="form_submit_buttons">
<input type="submit" value="{% trans %}Set password{% endtrans %}" class="button_form"/>
</div>
</div>
- </form>
{% endblock %}
diff --git a/mediagoblin/templates/mediagoblin/auth/forgot_password.html b/mediagoblin/templates/mediagoblin/auth/forgot_password.html
index 46aeddef..6cfd2c85 100644
--- a/mediagoblin/templates/mediagoblin/auth/forgot_password.html
+++ b/mediagoblin/templates/mediagoblin/auth/forgot_password.html
@@ -29,7 +29,7 @@
{{ csrf_token }}
<div class="form_box">
<h1>{% trans %}Recover password{% endtrans %}</h1>
- {{ wtforms_util.render_divs(fp_form) }}
+ {{ wtforms_util.render_divs(fp_form, True) }}
<div class="form_submit_buttons">
<input type="submit" value="{% trans %}Send instructions{% endtrans %}" class="button_form"/>
</div>
diff --git a/mediagoblin/templates/mediagoblin/auth/login.html b/mediagoblin/templates/mediagoblin/auth/login.html
index 4a39059d..3329b5d0 100644
--- a/mediagoblin/templates/mediagoblin/auth/login.html
+++ b/mediagoblin/templates/mediagoblin/auth/login.html
@@ -29,7 +29,7 @@
{%- endblock %}
{% block mediagoblin_content %}
- <form action="{{ request.urlgen('mediagoblin.auth.login') }}"
+ <form action="{{ post_url }}"
method="POST" enctype="multipart/form-data">
{{ csrf_token }}
<div class="form_box">
@@ -41,15 +41,19 @@
{% endif %}
{% if allow_registration %}
<p>
- {% trans %}Don't have an account yet?{% endtrans %} <a href="{{ request.urlgen('mediagoblin.auth.register') }}">
+ {% trans %}Don't have an account yet?{% endtrans %}
+ <a href="{{ request.urlgen('mediagoblin.auth.register') }}">
{%- trans %}Create one here!{% endtrans %}</a>
</p>
{% endif %}
- {{ wtforms_util.render_divs(login_form) }}
- <p>
- <a href="{{ request.urlgen('mediagoblin.auth.forgot_password') }}" id="forgot_password">
- {% trans %}Forgot your password?{% endtrans %}</a>
- </p>
+ {% template_hook("login_link") %}
+ {{ wtforms_util.render_divs(login_form, True) }}
+ {% if pass_auth %}
+ <p>
+ <a href="{{ request.urlgen('mediagoblin.auth.forgot_password') }}" id="forgot_password">
+ {% trans %}Forgot your password?{% endtrans %}</a>
+ </p>
+ {% endif %}
<div class="form_submit_buttons">
<input type="submit" value="{% trans %}Log in{% endtrans %}" class="button_form"/>
</div>
diff --git a/mediagoblin/templates/mediagoblin/auth/register.html b/mediagoblin/templates/mediagoblin/auth/register.html
index 6dff0207..a7b8033f 100644
--- a/mediagoblin/templates/mediagoblin/auth/register.html
+++ b/mediagoblin/templates/mediagoblin/auth/register.html
@@ -30,11 +30,12 @@
{% block mediagoblin_content %}
- <form action="{{ request.urlgen('mediagoblin.auth.register') }}"
+ <form action="{{ post_url }}"
method="POST" enctype="multipart/form-data">
<div class="form_box">
<h1>{% trans %}Create an account!{% endtrans %}</h1>
- {{ wtforms_util.render_divs(register_form) }}
+ {% template_hook("register_link") %}
+ {{ wtforms_util.render_divs(register_form, True) }}
{{ csrf_token }}
<div class="form_submit_buttons">
<input type="submit" value="{% trans %}Create{% endtrans %}"
@@ -42,6 +43,4 @@
</div>
</div>
</form>
-<!-- Focus the username field by default -->
-<script>$(document).ready(function(){$("#username").focus();});</script>
{% endblock %}
diff --git a/mediagoblin/templates/mediagoblin/base.html b/mediagoblin/templates/mediagoblin/base.html
index 66b95661..1fc4467c 100644
--- a/mediagoblin/templates/mediagoblin/base.html
+++ b/mediagoblin/templates/mediagoblin/base.html
@@ -16,7 +16,10 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-#}
<!doctype html>
-<html>
+<html
+{% block mediagoblin_html_tag %}
+{% endblock mediagoblin_html_tag %}
+>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
@@ -31,6 +34,8 @@
src="{{ request.staticdirect('/js/extlib/jquery.js') }}"></script>
<script type="text/javascript"
src="{{ request.staticdirect('/js/header_dropdown.js') }}"></script>
+ <script type="text/javascript"
+ src="{{ request.staticdirect('/js/notifications.js') }}"></script>
{# For clarification, the difference between the extra_head.html template
# and the head template hook is that the former should be used by
@@ -45,7 +50,7 @@
{% endblock mediagoblin_head %}
</head>
<body>
- {% include 'mediagoblin/bits/body-start.html' %}
+ {% include 'mediagoblin/bits/body_start.html' %}
{% block mediagoblin_body %}
{% block mediagoblin_header %}
<header>
@@ -54,6 +59,12 @@
<div class="header_right">
{%- if request.user %}
{% if request.user and request.user.status == 'active' %}
+
+ {% set notification_count = request.notifications.get_notification_count(request.user.id) %}
+ {% if notification_count %}
+ <a href="#notifications" class="notification-gem button_action" title="Notifications">
+ {{ notification_count }}</a>
+ {% endif %}
<div class="button_action header_dropdown_down">&#9660;</div>
<div class="button_action header_dropdown_up">&#9650;</div>
{% elif request.user and request.user.status == "needs_email_verification" %}
@@ -64,7 +75,7 @@
{% trans %}Verify your email!{% endtrans %}</a>
or <a href="{{ request.urlgen('mediagoblin.auth.logout') }}">{% trans %}log out{% endtrans %}</a>
{% endif %}
- {%- else %}
+ {%- elif auth %}
<a href="{{ request.urlgen('mediagoblin.auth.login') }}?next={{
request.base_url|urlencode }}">
{%- trans %}Log in{% endtrans -%}
@@ -106,29 +117,21 @@
</a>
</p>
{% endif %}
+ {% include 'mediagoblin/fragments/header_notifications.html' %}
</div>
{% endif %}
</header>
{% endblock %}
<div class="container">
- {% include 'mediagoblin/bits/above-content.html' %}
+ {% include 'mediagoblin/bits/above_content.html' %}
<div class="mediagoblin_content">
{% include "mediagoblin/utils/messages.html" %}
{% block mediagoblin_content %}
{% endblock mediagoblin_content %}
</div>
- {%- block mediagoblin_footer %}
- <footer>
- {% trans -%}
- Powered by <a href="http://mediagoblin.org/" title='Version {{ version }}'>MediaGoblin</a>, a <a href="http://gnu.org/">GNU</a> project.
- {%- endtrans %}
- {% trans source_link=app_config['source_link'] -%}
- Released under the <a href="http://www.fsf.org/licensing/licenses/agpl-3.0.html">AGPL</a>. <a href="{{ source_link }}">Source code</a> available.
- {%- endtrans %}
- </footer>
- {%- endblock mediagoblin_footer %}
+ {%- include "mediagoblin/bits/base_footer.html" %}
</div>
{%- endblock mediagoblin_body %}
- {% include 'mediagoblin/bits/body-end.html' %}
+ {% include 'mediagoblin/bits/body_end.html' %}
</body>
</html>
diff --git a/mediagoblin/templates/mediagoblin/bits/above-content.html b/mediagoblin/templates/mediagoblin/bits/above_content.html
index bb7b9762..bb7b9762 100644
--- a/mediagoblin/templates/mediagoblin/bits/above-content.html
+++ b/mediagoblin/templates/mediagoblin/bits/above_content.html
diff --git a/mediagoblin/templates/mediagoblin/bits/base_footer.html b/mediagoblin/templates/mediagoblin/bits/base_footer.html
new file mode 100644
index 00000000..80cd41b0
--- /dev/null
+++ b/mediagoblin/templates/mediagoblin/bits/base_footer.html
@@ -0,0 +1,28 @@
+{#
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011-2013 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#}
+
+{%- block mediagoblin_footer %}
+ <footer>
+ {% trans -%}
+ Powered by <a href="http://mediagoblin.org/" title='Version {{ version }}'>MediaGoblin</a>, a <a href="http://gnu.org/">GNU</a> project.
+ {%- endtrans %}
+ {% trans source_link=app_config['source_link'] -%}
+ Released under the <a href="http://www.fsf.org/licensing/licenses/agpl-3.0.html">AGPL</a>. <a href="{{ source_link }}">Source code</a> available.
+ {%- endtrans %}
+ </footer>
+{%- endblock mediagoblin_footer -%}
diff --git a/mediagoblin/templates/mediagoblin/bits/body-end.html b/mediagoblin/templates/mediagoblin/bits/body_end.html
index bb7b9762..bb7b9762 100644
--- a/mediagoblin/templates/mediagoblin/bits/body-end.html
+++ b/mediagoblin/templates/mediagoblin/bits/body_end.html
diff --git a/mediagoblin/templates/mediagoblin/bits/body-start.html b/mediagoblin/templates/mediagoblin/bits/body_start.html
index bb7b9762..bb7b9762 100644
--- a/mediagoblin/templates/mediagoblin/bits/body-start.html
+++ b/mediagoblin/templates/mediagoblin/bits/body_start.html
diff --git a/mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html b/mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html
new file mode 100644
index 00000000..9ef28a4d
--- /dev/null
+++ b/mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html
@@ -0,0 +1,41 @@
+{#
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#}
+
+{% if request.user %}
+ <h1>{% trans %}Explore{% endtrans %}</h1>
+ {% else %}
+ <h1>{% trans %}Hi there, welcome to this MediaGoblin site!{% endtrans %}</h1>
+ <img class="right_align" src="{{ request.staticdirect('/images/frontpage_image.png') }}" />
+ <p>{% trans %}This site is running <a href="http://mediagoblin.org">MediaGoblin</a>, an extraordinarily great piece of media hosting software.{% endtrans %}</p>
+ {% if auth %}
+ <p>{% trans %}To add your own media, place comments, and more, you can log in with your MediaGoblin account.{% endtrans %}</p>
+ {% if allow_registration %}
+ <p>{% trans %}Don't have one yet? It's easy!{% endtrans %}</p>
+ {% trans register_url=request.urlgen('mediagoblin.auth.register') -%}
+ <a class="button_action_highlight" href="{{ register_url }}">Create an account at this site</a>
+ or
+ {%- endtrans %}
+ {% endif %}
+ {% endif %}
+ {% trans %}
+ <a class="button_action" href="http://wiki.mediagoblin.org/HackingHowto">Set up MediaGoblin on your own server</a>
+ {%- endtrans %}
+
+ <div class="clear"></div>
+ {% endif %}
+
diff --git a/mediagoblin/templates/mediagoblin/edit/change_pass.html b/mediagoblin/templates/mediagoblin/edit/change_pass.html
new file mode 100644
index 00000000..2a1ffee0
--- /dev/null
+++ b/mediagoblin/templates/mediagoblin/edit/change_pass.html
@@ -0,0 +1,52 @@
+{#
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#}
+{% extends "mediagoblin/base.html" %}
+
+{% import "/mediagoblin/utils/wtforms.html" as wtforms_util %}
+
+{% block mediagoblin_head %}
+ <script type="text/javascript"
+ src="{{ request.staticdirect('/js/show_password.js') }}"></script>
+{% endblock mediagoblin_head %}
+
+{% block title -%}
+ {% trans username=user.username -%}
+ Changing {{ username }}'s password
+ {%- endtrans %} &mdash; {{ super() }}
+{%- endblock %}
+
+{% block mediagoblin_content %}
+ <form action="{{ request.urlgen('mediagoblin.edit.pass') }}"
+ method="POST" enctype="multipart/form-data">
+ <div class="form_box edit_box">
+ <h1>
+ {%- trans username=user.username -%}
+ Changing {{ username }}'s password
+ {%- endtrans -%}
+ </h1>
+ {{ wtforms_util.render_divs(form, True) }}
+ {{ csrf_token }}
+ <div class="form_submit_buttons">
+ <input type="submit" value="{% trans %}Save{% endtrans %}"
+ class="button_form" />
+ </div>
+ </div>
+ </form>
+{% endblock %}
+
+
diff --git a/mediagoblin/templates/mediagoblin/edit/edit_account.html b/mediagoblin/templates/mediagoblin/edit/edit_account.html
index 7fe2c031..51293acb 100644
--- a/mediagoblin/templates/mediagoblin/edit/edit_account.html
+++ b/mediagoblin/templates/mediagoblin/edit/edit_account.html
@@ -41,16 +41,18 @@
Changing {{ username }}'s account settings
{%- endtrans -%}
</h1>
- {{ wtforms_util.render_field_div(form.old_password) }}
- {{ wtforms_util.render_field_div(form.new_password) }}
- <div class="form_field_input">
- <p>{{ form.wants_comment_notification }}
- {{ wtforms_util.render_label(form.wants_comment_notification) }}</p>
- </div>
- {{- wtforms_util.render_field_div(form.license_preference) }}
- <div class="form_submit_buttons">
+ {% if pass_auth is defined %}
+ <p>
+ <a href="{{ request.urlgen('mediagoblin.edit.pass') }}">
+ {% trans %}Change your password.{% endtrans %}
+ </a>
+ </p>
+ {% endif %}
+ {% template_hook("edit_link") %}
+ {{ wtforms_util.render_divs(form, True) }}
+ <div class="form_submit_buttons">
<input type="submit" value="{% trans %}Save changes{% endtrans %}" class="button_form" />
- {{ csrf_token }}
+ {{ csrf_token }}
</div>
</div>
</form>
diff --git a/mediagoblin/templates/mediagoblin/edit/verification.txt b/mediagoblin/templates/mediagoblin/edit/verification.txt
new file mode 100644
index 00000000..d53cd5e8
--- /dev/null
+++ b/mediagoblin/templates/mediagoblin/edit/verification.txt
@@ -0,0 +1,29 @@
+{#
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+-#}
+
+{% trans username=username, verification_url=verification_url|safe -%}
+Hi,
+
+We wanted to verify that you are {{ username }}. If this is the case, then
+please follow the link below to verify your new email address.
+
+{{ verification_url }}
+
+If you are not {{ username }} or didn't request an email change, you can ignore
+this email.
+{%- endtrans %}
diff --git a/mediagoblin/templates/mediagoblin/fragments/header_notifications.html b/mediagoblin/templates/mediagoblin/fragments/header_notifications.html
new file mode 100644
index 00000000..613100aa
--- /dev/null
+++ b/mediagoblin/templates/mediagoblin/fragments/header_notifications.html
@@ -0,0 +1,40 @@
+{% set notifications = request.notifications.get_notifications(request.user.id) %}
+{% if notifications %}
+ <div class="header_notifications">
+ <h3>{% trans %}New comments{% endtrans %}</h3>
+ <ul>
+ {% for notification in notifications %}
+ {% set comment = notification.subject %}
+ {% set comment_author = comment.get_author %}
+ {% set media = comment.get_entry %}
+ <li class="comment_wrapper">
+ <div class="comment_author">
+ <img src="{{ request.staticdirect('/images/icon_comment.png') }}" />
+ <a href="{{ request.urlgen('mediagoblin.user_pages.user_home',
+ user=comment_author.username) }}"
+ class="comment_authorlink">
+ {{- comment_author.username -}}
+ </a>
+ <a href="{{ request.urlgen('mediagoblin.user_pages.media_home.view_comment',
+ comment=comment.id,
+ user=media.get_uploader.username,
+ media=media.slug_or_id) }}#comment"
+ class="comment_whenlink">
+ <span title='{{- comment.created.strftime("%I:%M%p %Y-%m-%d") -}}'>
+ {%- trans formatted_time=timesince(comment.created) -%}
+ {{ formatted_time }} ago
+ {%- endtrans -%}
+ </span>
+ </a>:
+ </div>
+ <div class="comment_content">
+ {% autoescape False -%}
+ {{ comment.content_html }}
+ {%- endautoescape %}
+ </div>
+
+ </li>
+ {% endfor %}
+ </ul>
+ </div>
+{% endif %}
diff --git a/mediagoblin/templates/mediagoblin/media_displays/image.html b/mediagoblin/templates/mediagoblin/media_displays/image.html
index 158dd67f..d0050f50 100644
--- a/mediagoblin/templates/mediagoblin/media_displays/image.html
+++ b/mediagoblin/templates/mediagoblin/media_displays/image.html
@@ -27,3 +27,20 @@
{{ super() }}
{% template_hook("image_sideinfo") %}
{% endblock %}
+
+{% block mediagoblin_after_added_sidebar %}
+ {% if app_config['original_date_visible'] %}
+ {% set original_date = media.media_manager.get_original_date() %}
+
+ {% if original_date %}
+ <h3>{% trans %}Created{% endtrans %}</h3>
+
+ <p><span title="{{ original_date.strftime("%I:%M%p %Y-%m-%d") }}">
+ {%- trans formatted_time=timesince(original_date) -%}
+ {{ formatted_time }} ago
+ {%- endtrans -%}
+ </span></p>
+ {%- endif %}
+ {% endif %}
+{% endblock %}
+
diff --git a/mediagoblin/templates/mediagoblin/media_displays/pdf.html b/mediagoblin/templates/mediagoblin/media_displays/pdf.html
new file mode 100644
index 00000000..9319e87c
--- /dev/null
+++ b/mediagoblin/templates/mediagoblin/media_displays/pdf.html
@@ -0,0 +1,86 @@
+{#
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#}
+
+{% extends 'mediagoblin/user_pages/media.html' %}
+
+{% set medium_view = request.app.public_store.file_url(
+ media.media_files['medium']) %}
+
+{% if 'pdf' in media.media_files %}
+ {% set pdf_view = request.app.public_store.file_url(
+ media.media_files['pdf']) %}
+{% else %}
+ {% set pdf_view = request.app.public_store.file_url(
+ media.media_files['original']) %}
+{% endif %}
+
+{% set pdf_js = global_config.get('media_type:mediagoblin.media_types.pdf', {}).get('pdf_js', False) %}
+
+{% if pdf_js %}
+ {% block mediagoblin_html_tag %}
+ dir="ltr" mozdisallowselectionprint moznomarginboxes
+ {% endblock mediagoblin_html_tag %}
+{% endif %}
+
+{% block mediagoblin_head -%}
+ {{ super() }}
+
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
+
+{%- endblock %}
+
+{% block mediagoblin_media %}
+ {% if pdf_js %}
+ <iframe width="640px" height="480px"
+ src="{{ request.staticdirect('/extlib/pdf.js/web/viewer.html') }}?file={{ pdf_view }} ">
+ </iframe>
+ {% else %}
+ <a href="{{ pdf_view }}">
+ <img id="medium"
+ class="media_image"
+ src="{{ medium_view }}"
+ alt="
+ {%- trans media_title=media.title -%}
+ Image for {{ media_title}}
+ {%- endtrans %}"/>
+ </a>
+ {% endif %}
+{% endblock %}
+
+{% block mediagoblin_sidebar %}
+ <h3>{% trans %}Download{% endtrans %}</h3>
+ <ul>
+ {% if 'original' in media.media_files %}
+ <li>
+ <a href="{{ request.app.public_store.file_url(
+ media.media_files.original) }}">
+ {%- trans %}Original file{% endtrans -%}
+ </a>
+ </li>
+ {% endif %}
+ {% if 'pdf' in media.media_files %}
+ <li>
+ <a href="{{ request.app.public_store.file_url(
+ media.media_files.pdf) }}">
+ {%- trans %}PDF file{% endtrans -%}
+ </a>
+ </li>
+ {% endif %}
+ </ul>
+{% endblock %}
diff --git a/mediagoblin/templates/mediagoblin/media_displays/stl.html b/mediagoblin/templates/mediagoblin/media_displays/stl.html
index a89e0b4f..bc12ce4e 100644
--- a/mediagoblin/templates/mediagoblin/media_displays/stl.html
+++ b/mediagoblin/templates/mediagoblin/media_displays/stl.html
@@ -108,32 +108,26 @@ window.show_things = function () {
<div style="padding: 4px;">
- <a class="button_action" onclick="show('perspective');"
- title="{%- trans %}Toggle Rotate{% endtrans -%}">
+ <a class="button_action" onclick="show('perspective');">
{%- trans %}Perspective{% endtrans -%}
</a>
- <a class="button_action" onclick="show('front_view');"
- title="{%- trans %}Front{% endtrans -%}">
+ <a class="button_action" onclick="show('front_view');">
{%- trans %}Front{% endtrans -%}
</a>
- <a class="button_action" onclick="show('top_view');"
- title="{%- trans %}Top{% endtrans -%}">
+ <a class="button_action" onclick="show('top_view');">
{%- trans %}Top{% endtrans -%}
</a>
- <a class="button_action" onclick="show('side_view');"
- title="{%- trans %}Side{% endtrans -%}">
+ <a class="button_action" onclick="show('side_view');">
{%- trans %}Side{% endtrans -%}
</a>
{% if media.media_data.file_type == "stl" %}
<a id="webgl_button" class="button_action"
- onclick="show_things();"
- title="{%- trans %}WebGL{% endtrans -%}">
+ onclick="show_things();">
{%- trans %}WebGL{% endtrans -%}
</a>
{% endif %}
<a class="button_action" href="{{ model_download }}"
- title="{%- trans %}Download{% endtrans -%}"
style="float:right;">
{%- trans %}Download model{% endtrans -%}
</a>
diff --git a/mediagoblin/templates/mediagoblin/root.html b/mediagoblin/templates/mediagoblin/root.html
index 529d89ef..15d53af1 100644
--- a/mediagoblin/templates/mediagoblin/root.html
+++ b/mediagoblin/templates/mediagoblin/root.html
@@ -27,23 +27,8 @@
{%- endblock mediagoblin_head %}
{% block mediagoblin_content %}
- {% if request.user %}
- <h1>{% trans %}Explore{% endtrans %}</h1>
- {% else %}
- <h1>{% trans %}Hi there, welcome to this MediaGoblin site!{% endtrans %}</h1>
- <img class="right_align" src="{{ request.staticdirect('/images/frontpage_image.png') }}" />
- <p>{% trans %}This site is running <a href="http://mediagoblin.org">MediaGoblin</a>, an extraordinarily great piece of media hosting software.{% endtrans %}</p>
- <p>{% trans %}To add your own media, place comments, and more, you can log in with your MediaGoblin account.{% endtrans %}</p>
- {% if allow_registration %}
- <p>{% trans %}Don't have one yet? It's easy!{% endtrans %}</p>
- {% trans register_url=request.urlgen('mediagoblin.auth.register') -%}
- <a class="button_action_highlight" href="{{ register_url }}">Create an account at this site</a>
- or
- <a class="button_action" href="http://wiki.mediagoblin.org/HackingHowto">Set up MediaGoblin on your own server</a>
- {%- endtrans %}
- {% endif %}
- <div class="clear"></div>
- {% endif %}
+ {% include "mediagoblin/bits/frontpage_welcome.html" %}
+
<h2>{% trans %}Most recent media{% endtrans %}</h2>
{{ object_gallery(request, media_entries, pagination) }}
diff --git a/mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html b/mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html
index 2b790584..694eb979 100644
--- a/mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html
+++ b/mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html
@@ -41,9 +41,10 @@
<div class="form_submit_buttons">
{# TODO: This isn't a button really... might do unexpected things :) #}
- <a class="button_action" href="{{ request.urlgen('mediagoblin.user_pages.user_collection',
- collection=collection.slug,
- user=request.user.username) }}">{% trans %}Cancel{% endtrans %}</a>
+ <a class="button_action" href="
+ {{- collection.url_for_self(request.urlgen) }}">
+ {%- trans %}Cancel{% endtrans -%}
+ </a>
<input type="submit" value="{% trans %}Delete permanently{% endtrans %}" class="button_form" />
{{ csrf_token }}
</div>
diff --git a/mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html b/mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html
index 449cc3ce..dc31d90f 100644
--- a/mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html
+++ b/mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html
@@ -47,9 +47,10 @@
<div class="form_submit_buttons">
{# TODO: This isn't a button really... might do unexpected things :) #}
- <a class="button_action" href="{{ request.urlgen('mediagoblin.user_pages.user_collection',
- collection=collection_item.in_collection.slug,
- user=request.user.username) }}">{% trans %}Cancel{% endtrans %}</a>
+ <a class="button_action" href="
+ {{- collection_item.in_collection.url_for_self(request.urlgen) }}">
+ {%- trans %}Cancel{% endtrans -%}
+ </a>
<input type="submit" value="{% trans %}Remove{% endtrans %}" class="button_form" />
{{ csrf_token }}
</div>
diff --git a/mediagoblin/templates/mediagoblin/user_pages/collection_list.html b/mediagoblin/templates/mediagoblin/user_pages/collection_list.html
index abf22623..8ac0b988 100644
--- a/mediagoblin/templates/mediagoblin/user_pages/collection_list.html
+++ b/mediagoblin/templates/mediagoblin/user_pages/collection_list.html
@@ -15,7 +15,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#}
-{% extends "mediagoblin/base.html" %}
+{%- extends "mediagoblin/base.html" %}
{% block title %}
{%- trans username=user.username -%}
@@ -39,17 +39,17 @@
<a href="{{ request.urlgen('mediagoblin.submit.collection',
user=user.username) }}">
{%- trans %}Create new collection{% endtrans -%}
+ </a>
</p>
{% endif %}
{% endif %}
<ul>
{% for coll in collections %}
- {% set coll_url = request.urlgen(
- 'mediagoblin.user_pages.user_collection',
- user=user.username,
- collection=coll.slug) %}
- <li><a href="{{ coll_url }}">{{ coll.title }}</li>
+ {%- set coll_url = coll.url_for_self(request.urlgen) %}
+ <li>
+ <a href="{{ coll_url }}">{{ coll.title }}</a>
+ </li>
{% endfor %}
</ul>
diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html
index b77c12b9..c16e4c78 100644
--- a/mediagoblin/templates/mediagoblin/user_pages/media.html
+++ b/mediagoblin/templates/mediagoblin/user_pages/media.html
@@ -43,7 +43,7 @@
{%- endtrans -%}
</p>
{% include "mediagoblin/utils/prev_next.html" %}
- <div class="media_pane">
+ <div class="media_pane">
<div class="media_image_container">
{% block mediagoblin_media %}
{% set display_media = request.app.public_store.file_url(
@@ -71,7 +71,7 @@
{{ media.title }}
</h2>
{% if request.user and
- (media.uploader == request.user.id or
+ (media.uploader == request.user.id or
request.user.is_admin) %}
{% set edit_url = request.urlgen('mediagoblin.edit.edit_media',
user= media.get_uploader.username,
@@ -81,20 +81,25 @@
user= media.get_uploader.username,
media_id=media.id) %}
<a class="button_action" href="{{ delete_url }}">{% trans %}Delete{% endtrans %}</a>
+
{% endif %}
{% autoescape False %}
<p>{{ media.description_html }}</p>
{% endautoescape %}
{% if comments %}
- <a
- {% if not request.user %}
- href="{{ request.urlgen('mediagoblin.auth.login') }}"
- {% endif %}
- class="button_action" id="button_addcomment" title="Add a comment">
- {% trans %}Add a comment{% endtrans %}
- </a>
+ {% if app_config['allow_comments'] %}
+ <a
+ {% if not request.user %}
+ href="{{ request.urlgen('mediagoblin.auth.login') }}"
+ {% endif %}
+ class="button_action" id="button_addcomment" title="Add a comment">
+ {% trans %}Add a comment{% endtrans %}
+ </a>
+ {% include "mediagoblin/utils/comment-subscription.html" %}
+
+ {% endif %}
{% if request.user %}
- <form action="{{ request.urlgen('mediagoblin.user_pages.media_post_comment',
+ <form action="{{ request.urlgen('mediagoblin.user_pages.media_post_comment',
user= media.get_uploader.username,
media_id=media.id) }}" method="POST" id="form_comment">
{{ wtforms_util.render_divs(comment_form) }}
@@ -117,16 +122,20 @@
<div class="comment_author">
<img src="{{ request.staticdirect('/images/icon_comment.png') }}" />
<a href="{{ request.urlgen('mediagoblin.user_pages.user_home',
- user=comment_author.username) }}">
+ user=comment_author.username) }}"
+ class="comment_authorlink">
{{- comment_author.username -}}
</a>
- {% trans %}at{% endtrans %}
<a href="{{ request.urlgen('mediagoblin.user_pages.media_home.view_comment',
comment=comment.id,
user=media.get_uploader.username,
- media=media.slug_or_id) }}#comment">
- {{- comment.created.strftime("%I:%M%p %Y-%m-%d") -}}
- </a>:
+ media=media.slug_or_id) }}#comment"
+ class="comment_whenlink">
+ <span title='{{- comment.created.strftime("%I:%M%p %Y-%m-%d") -}}'>
+ {%- trans formatted_time=timesince(comment.created) -%}
+ {{ formatted_time }} ago
+ {%- endtrans -%}
+ </span></a>:
</div>
<div class="comment_content">
{% autoescape False -%}
@@ -141,10 +150,16 @@
{% endif %}
</div>
<div class="media_sidebar">
- {% trans date=media.created.strftime("%Y-%m-%d") -%}
- <h3>Added on</h3>
- <p>{{ date }}</p>
- {%- endtrans %}
+ <h3>{% trans %}Added{% endtrans %}</h3>
+ <p><span title="{{ media.created.strftime("%I:%M%p %Y-%m-%d") }}">
+ {%- trans formatted_time=timesince(media.created) -%}
+ {{ formatted_time }} ago
+ {%- endtrans -%}
+ </span></p>
+
+ {% block mediagoblin_after_added_sidebar %}
+ {% endblock %}
+
{% if media.tags %}
{% include "mediagoblin/utils/tags.html" %}
{% endif %}
@@ -154,7 +169,7 @@
{% include "mediagoblin/utils/license.html" %}
{% include "mediagoblin/utils/exif.html" %}
-
+
{%- if media.attachment_files|count %}
<h3>{% trans %}Attachments{% endtrans %}</h3>
<ul>
diff --git a/mediagoblin/templates/mediagoblin/utils/comment-subscription.html b/mediagoblin/templates/mediagoblin/utils/comment-subscription.html
new file mode 100644
index 00000000..bd367e80
--- /dev/null
+++ b/mediagoblin/templates/mediagoblin/utils/comment-subscription.html
@@ -0,0 +1,34 @@
+{#
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#}
+{%- if request.user %}
+ {% set subscription = request.notifications.get_comment_subscription(
+ request.user.id, media.id) %}
+ {% if not subscription or not subscription.notify %}
+ <a type="submit" href="{{ request.urlgen('mediagoblin.notifications.subscribe_comments',
+ user=media.get_uploader.username,
+ media=media.slug_or_id)}}"
+ class="button_action">Subscribe to comments
+ </a>
+ {% else %}
+ <a type="submit" href="{{ request.urlgen('mediagoblin.notifications.silence_comments',
+ user=media.get_uploader.username,
+ media=media.slug_or_id)}}"
+ class="button_action">Silence comments
+ </a>
+ {% endif %}
+{%- endif %}
diff --git a/mediagoblin/templates/mediagoblin/utils/exif.html b/mediagoblin/templates/mediagoblin/utils/exif.html
index a89e69c8..b62208e1 100644
--- a/mediagoblin/templates/mediagoblin/utils/exif.html
+++ b/mediagoblin/templates/mediagoblin/utils/exif.html
@@ -17,18 +17,51 @@
#}
{% block exif_content %}
+<noscript>
+ <style type="text/css">
+ #exif_additional_info {
+ display: block;
+ }
+ </style>
+</noscript>
+<div id="exif_content">
{% if app_config['exif_visible']
and media.media_data
and media.media_data.exif_all is defined
and media.media_data.exif_all %}
- <h3>EXIF</h3>
- <table>
+ <h3>Camera Information</h3>
+ <table id="exif_camera_information">
+ <tbody>
+ {% for label, value in media.exif_display_data_short().iteritems() %}
+ <tr>
+ <td class="col1">{{ label }}</td>
+ <td>{{ value }}</td>
+ </tr>
+ {% endfor %}
+ </tbody>
+ </table>
+ <h3 id="exif_additional_info_button" class="button_action">
+ Additional Information
+ </h3>
+ <div id="exif_additional_info">
+ <table class="exif_info">
{% for key, tag in media.exif_display_iter() %}
<tr>
- <td>{{ key }}</td>
+ <td class="col1">{{ key }}</td>
<td>{{ tag.printable }}</td>
</tr>
{% endfor %}
</table>
+ </div>
{% endif %}
+<script type="text/javascript">
+$(document).ready(function(){
+
+$("#exif_additional_info_button").click(function(){
+ $("#exif_additional_info").slideToggle("slow");
+});
+
+});
+</script>
+</div> <!-- end exif_content div -->
{% endblock %}
diff --git a/mediagoblin/templates/mediagoblin/utils/wtforms.html b/mediagoblin/templates/mediagoblin/utils/wtforms.html
index 35b4aa04..e079274e 100644
--- a/mediagoblin/templates/mediagoblin/utils/wtforms.html
+++ b/mediagoblin/templates/mediagoblin/utils/wtforms.html
@@ -19,7 +19,7 @@
{# Render the label for a field #}
{% macro render_label(field) %}
{%- if field.label.text -%}
- <label for="{{ field.label.field_id }}">{{ _(field.label.text) }}</label>
+ <label for="{{ field.label.field_id }}">{{ field.label.text }}</label>
{%- endif -%}
{%- endmacro %}
@@ -33,25 +33,37 @@
{%- endmacro %}
{# Generically render a field #}
-{% macro render_field_div(field) %}
- {{- render_label_p(field) }}
- <div class="form_field_input">
- {{ field }}
- {%- if field.errors -%}
- {% for error in field.errors %}
- <p class="form_field_error">{{ _(error) }}</p>
- {% endfor %}
- {%- endif %}
- {%- if field.description %}
- <p class="form_field_description">{{ _(field.description)|safe }}</p>
- {%- endif %}
- </div>
+{% macro render_field_div(field, autofocus_first=False) %}
+ {% if field.type == 'BooleanField' %}
+ {{ render_bool(field) }}
+ {% else %}
+ {{- render_label_p(field) }}
+ <div class="form_field_input">
+ {% if autofocus_first %}
+ {{ field(autofocus=True) }}
+ {% else %}
+ {{ field }}
+ {% endif %}
+ {%- if field.errors -%}
+ {% for error in field.errors %}
+ <p class="form_field_error">{{ error }}</p>
+ {% endfor %}
+ {%- endif %}
+ {%- if field.description %}
+ <p class="form_field_description">{{ field.description|safe }}</p>
+ {%- endif %}
+ </div>
+ {% endif %}
{%- endmacro %}
{# Auto-render a form as a series of divs #}
-{% macro render_divs(form) -%}
+{% macro render_divs(form, autofocus_first=False) -%}
{% for field in form %}
- {{ render_field_div(field) }}
+ {% if autofocus_first and loop.first %}
+ {{ render_field_div(field, True) }}
+ {% else %}
+ {{ render_field_div(field) }}
+ {% endif %}
{% endfor %}
{%- endmacro %}
@@ -59,7 +71,7 @@
{% macro render_table(form) -%}
{% for field in form %}
<tr>
- <th>{{ _(field.label.text) }}</th>
+ <th>{{ field.label.text }}</th>
<td>
{{field}}
{% if field.errors %}
@@ -74,3 +86,19 @@
</tr>
{% endfor %}
{%- endmacro %}
+
+{# Render a boolean field #}
+{% macro render_bool(field) %}
+ <div class="boolean">
+ <label for="{{ field.label.field_id }}">
+ {{ field }}</input>
+ {{ field.description|safe }}
+ </label>
+ {%- if field.errors -%}
+ {% for error in field.errors %}
+ <p class="form_field_error">{{ error }}</p>
+ {% endfor %}
+ {% endif %}
+ </div>
+{% endmacro %}
+
diff --git a/mediagoblin/tests/__init__.py b/mediagoblin/tests/__init__.py
index 5a3235c6..cf200791 100644
--- a/mediagoblin/tests/__init__.py
+++ b/mediagoblin/tests/__init__.py
@@ -14,23 +14,9 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-import os
-import shutil
-
-from mediagoblin import mg_globals
-from mediagoblin.tests.tools import (
- TEST_USER_DEV, suicide_if_bad_celery_environ)
-
def setup_package():
- suicide_if_bad_celery_environ()
import warnings
from sqlalchemy.exc import SAWarning
warnings.simplefilter("error", SAWarning)
-
-
-def teardown_package():
- # Remove and reinstall user_dev directories
- if os.path.exists(TEST_USER_DEV):
- shutil.rmtree(TEST_USER_DEV)
diff --git a/mediagoblin/tests/appconfig_context_modified.ini b/mediagoblin/tests/appconfig_context_modified.ini
new file mode 100644
index 00000000..cc6721f5
--- /dev/null
+++ b/mediagoblin/tests/appconfig_context_modified.ini
@@ -0,0 +1,27 @@
+[mediagoblin]
+direct_remote_path = /test_static/
+email_sender_address = "notice@mediagoblin.example.org"
+email_debug_mode = true
+
+#Runs with an in-memory sqlite db for speed.
+sql_engine = "sqlite://"
+run_migrations = true
+
+# Celery shouldn't be set up by the application as it's setup via
+# mediagoblin.init.celery.from_celery
+celery_setup_elsewhere = true
+
+[storage:publicstore]
+base_dir = %(here)s/user_dev/media/public
+base_url = /mgoblin_media/
+
+[storage:queuestore]
+base_dir = %(here)s/user_dev/media/queue
+
+[celery]
+CELERY_ALWAYS_EAGER = true
+CELERY_RESULT_DBURI = "sqlite:///%(here)s/user_dev/celery.db"
+BROKER_HOST = "sqlite:///%(here)s/user_dev/kombu.db"
+
+[plugins]
+[[mediagoblin.tests.testplugins.modify_context]]
diff --git a/mediagoblin/tests/appconfig_plugin_specs.ini b/mediagoblin/tests/appconfig_plugin_specs.ini
new file mode 100644
index 00000000..5511cd97
--- /dev/null
+++ b/mediagoblin/tests/appconfig_plugin_specs.ini
@@ -0,0 +1,21 @@
+[mediagoblin]
+direct_remote_path = /mgoblin_static/
+email_sender_address = "notice@mediagoblin.example.org"
+
+## Uncomment and change to your DB's appropiate setting.
+## Default is a local sqlite db "mediagoblin.db".
+# sql_engine = postgresql:///gmg
+
+# set to false to enable sending notices
+email_debug_mode = true
+
+# Set to false to disable registrations
+allow_registration = true
+
+[plugins]
+[[mediagoblin.tests.testplugins.pluginspec]]
+some_string = "not blork"
+some_int = "not an int"
+
+# this one shouldn't have its own config
+[[mediagoblin.tests.testplugins.callables1]]
diff --git a/mediagoblin/tests/appconfig_static_plugin.ini b/mediagoblin/tests/appconfig_static_plugin.ini
new file mode 100644
index 00000000..5ce5c5bd
--- /dev/null
+++ b/mediagoblin/tests/appconfig_static_plugin.ini
@@ -0,0 +1,27 @@
+[mediagoblin]
+direct_remote_path = /test_static/
+email_sender_address = "notice@mediagoblin.example.org"
+email_debug_mode = true
+
+#Runs with an in-memory sqlite db for speed.
+sql_engine = "sqlite://"
+run_migrations = true
+
+# Celery shouldn't be set up by the application as it's setup via
+# mediagoblin.init.celery.from_celery
+celery_setup_elsewhere = true
+
+[storage:publicstore]
+base_dir = %(here)s/user_dev/media/public
+base_url = /mgoblin_media/
+
+[storage:queuestore]
+base_dir = %(here)s/user_dev/media/queue
+
+[celery]
+CELERY_ALWAYS_EAGER = true
+CELERY_RESULT_DBURI = "sqlite:///%(here)s/user_dev/celery.db"
+BROKER_HOST = "sqlite:///%(here)s/user_dev/kombu.db"
+
+[plugins]
+[[mediagoblin.tests.testplugins.staticstuff]]
diff --git a/mediagoblin/tests/auth_configs/__init__.py b/mediagoblin/tests/auth_configs/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/mediagoblin/tests/auth_configs/__init__.py
diff --git a/mediagoblin/tests/auth_configs/authentication_disabled_appconfig.ini b/mediagoblin/tests/auth_configs/authentication_disabled_appconfig.ini
new file mode 100644
index 00000000..a64e9e40
--- /dev/null
+++ b/mediagoblin/tests/auth_configs/authentication_disabled_appconfig.ini
@@ -0,0 +1,25 @@
+[mediagoblin]
+direct_remote_path = /test_static/
+email_sender_address = "notice@mediagoblin.example.org"
+email_debug_mode = true
+
+# TODO: Switch to using an in-memory database
+sql_engine = "sqlite:///%(here)s/user_dev/mediagoblin.db"
+
+# Celery shouldn't be set up by the application as it's setup via
+# mediagoblin.init.celery.from_celery
+celery_setup_elsewhere = true
+
+[storage:publicstore]
+base_dir = %(here)s/user_dev/media/public
+base_url = /mgoblin_media/
+
+[storage:queuestore]
+base_dir = %(here)s/user_dev/media/queue
+
+[celery]
+CELERY_ALWAYS_EAGER = true
+CELERY_RESULT_DBURI = "sqlite:///%(here)s/user_dev/celery.db"
+BROKER_HOST = "sqlite:///%(here)s/user_dev/kombu.db"
+
+[plugins]
diff --git a/mediagoblin/tests/auth_configs/openid_appconfig.ini b/mediagoblin/tests/auth_configs/openid_appconfig.ini
new file mode 100644
index 00000000..c2bd82fd
--- /dev/null
+++ b/mediagoblin/tests/auth_configs/openid_appconfig.ini
@@ -0,0 +1,41 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+[mediagoblin]
+direct_remote_path = /test_static/
+email_sender_address = "notice@mediagoblin.example.org"
+email_debug_mode = true
+
+# TODO: Switch to using an in-memory database
+sql_engine = "sqlite:///%(here)s/user_dev/mediagoblin.db"
+
+# Celery shouldn't be set up by the application as it's setup via
+# mediagoblin.init.celery.from_celery
+celery_setup_elsewhere = true
+
+[storage:publicstore]
+base_dir = %(here)s/user_dev/media/public
+base_url = /mgoblin_media/
+
+[storage:queuestore]
+base_dir = %(here)s/user_dev/media/queue
+
+[celery]
+CELERY_ALWAYS_EAGER = true
+CELERY_RESULT_DBURI = "sqlite:///%(here)s/user_dev/celery.db"
+BROKER_HOST = "sqlite:///%(here)s/user_dev/kombu.db"
+
+[plugins]
+[[mediagoblin.plugins.openid]]
diff --git a/mediagoblin/tests/conftest.py b/mediagoblin/tests/conftest.py
new file mode 100644
index 00000000..dbb0aa0a
--- /dev/null
+++ b/mediagoblin/tests/conftest.py
@@ -0,0 +1,41 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2013 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import pytest
+
+from mediagoblin.tests import tools
+from mediagoblin.tools.testing import _activate_testing
+
+
+@pytest.fixture()
+def test_app(request):
+ """
+ py.test fixture to pass sandboxed mediagoblin applications into tests that
+ want them.
+
+ You could make a local version of this method for your own tests
+ to override the paste and config files being used by passing them
+ in differently to get_app.
+ """
+ return tools.get_app(request)
+
+
+@pytest.fixture()
+def pt_fixture_enable_testing():
+ """
+ py.test fixture to enable testing mode in tools.
+ """
+ _activate_testing()
diff --git a/mediagoblin/tests/pytest.ini b/mediagoblin/tests/pytest.ini
new file mode 100644
index 00000000..e561c074
--- /dev/null
+++ b/mediagoblin/tests/pytest.ini
@@ -0,0 +1,2 @@
+[pytest]
+usefixtures = tmpdir pt_fixture_enable_testing
diff --git a/mediagoblin/tests/resources.py b/mediagoblin/tests/resources.py
new file mode 100644
index 00000000..f7b3037d
--- /dev/null
+++ b/mediagoblin/tests/resources.py
@@ -0,0 +1,41 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2013 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+
+from pkg_resources import resource_filename
+
+
+def resource(filename):
+ return resource_filename('mediagoblin.tests', 'test_submission/' + filename)
+
+
+GOOD_JPG = resource('good.jpg')
+GOOD_PNG = resource('good.png')
+EVIL_FILE = resource('evil')
+EVIL_JPG = resource('evil.jpg')
+EVIL_PNG = resource('evil.png')
+BIG_BLUE = resource('bigblue.png')
+GOOD_PDF = resource('good.pdf')
+
+
+def resource_exif(f):
+ return resource_filename('mediagoblin.tests', 'test_exif/' + f)
+
+
+GOOD_JPG = resource_exif('good.jpg')
+EMPTY_JPG = resource_exif('empty.jpg')
+BAD_JPG = resource_exif('bad.jpg')
+GPS_JPG = resource_exif('has-gps.jpg')
diff --git a/mediagoblin/tests/test_api.py b/mediagoblin/tests/test_api.py
index 82b1c1b4..89cf1026 100644
--- a/mediagoblin/tests/test_api.py
+++ b/mediagoblin/tests/test_api.py
@@ -18,40 +18,27 @@
import logging
import base64
-from pkg_resources import resource_filename
+import pytest
from mediagoblin import mg_globals
from mediagoblin.tools import template, pluginapi
-from mediagoblin.tests.tools import get_app, fixture_add_user
+from mediagoblin.tests.tools import fixture_add_user
+from .resources import GOOD_JPG, GOOD_PNG, EVIL_FILE, EVIL_JPG, EVIL_PNG, \
+ BIG_BLUE
_log = logging.getLogger(__name__)
-def resource(filename):
- '''
- Borrowed from the submission tests
- '''
- return resource_filename('mediagoblin.tests', 'test_submission/' + filename)
-
-
-GOOD_JPG = resource('good.jpg')
-GOOD_PNG = resource('good.png')
-EVIL_FILE = resource('evil')
-EVIL_JPG = resource('evil.jpg')
-EVIL_PNG = resource('evil.png')
-BIG_BLUE = resource('bigblue.png')
-
class TestAPI(object):
- def setUp(self):
- self.app = get_app(dump_old_app=False)
+ def setup(self):
self.db = mg_globals.database
self.user_password = u'4cc355_70k3N'
self.user = fixture_add_user(u'joapi', self.user_password)
- def login(self):
- self.app.post(
+ def login(self, test_app):
+ test_app.post(
'/auth/login/', {
'username': self.user.username,
'password': self.user_password})
@@ -65,14 +52,14 @@ class TestAPI(object):
self.user.username,
self.user_password])))}
- def do_post(self, data, **kwargs):
+ def do_post(self, data, test_app, **kwargs):
url = kwargs.pop('url', '/api/submit')
do_follow = kwargs.pop('do_follow', False)
if not 'headers' in kwargs.keys():
kwargs['headers'] = self.http_auth_headers()
- response = self.app.post(url, data, **kwargs)
+ response = test_app.post(url, data, **kwargs)
if do_follow:
response.follow()
@@ -82,21 +69,22 @@ class TestAPI(object):
def upload_data(self, filename):
return {'upload_files': [('file', filename)]}
- def test_1_test_test_view(self):
- self.login()
+ def test_1_test_test_view(self, test_app):
+ self.login(test_app)
- response = self.app.get(
+ response = test_app.get(
'/api/test',
headers=self.http_auth_headers())
assert response.body == \
'{"username": "joapi", "email": "joapi@example.com"}'
- def test_2_test_submission(self):
- self.login()
+ def test_2_test_submission(self, test_app):
+ self.login(test_app)
response = self.do_post(
{'title': 'Great JPG!'},
+ test_app,
**self.upload_data(GOOD_JPG))
assert response.status_int == 200
diff --git a/mediagoblin/tests/test_auth.py b/mediagoblin/tests/test_auth.py
index a59a319c..61503d32 100644
--- a/mediagoblin/tests/test_auth.py
+++ b/mediagoblin/tests/test_auth.py
@@ -13,59 +13,17 @@
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
import urlparse
-import datetime
-
-from nose.tools import assert_equal
+import pkg_resources
+import pytest
from mediagoblin import mg_globals
-from mediagoblin.auth import lib as auth_lib
from mediagoblin.db.models import User
-from mediagoblin.tests.tools import setup_fresh_app, get_app, fixture_add_user
+from mediagoblin.tests.tools import get_app, fixture_add_user
from mediagoblin.tools import template, mail
+from mediagoblin.auth import tools as auth_tools
-########################
-# Test bcrypt auth funcs
-########################
-
-def test_bcrypt_check_password():
- # Check known 'lollerskates' password against check function
- assert auth_lib.bcrypt_check_password(
- 'lollerskates',
- '$2a$12$PXU03zfrVCujBhVeICTwtOaHTUs5FFwsscvSSTJkqx/2RQ0Lhy/nO')
-
- assert not auth_lib.bcrypt_check_password(
- 'notthepassword',
- '$2a$12$PXU03zfrVCujBhVeICTwtOaHTUs5FFwsscvSSTJkqx/2RQ0Lhy/nO')
-
- # Same thing, but with extra fake salt.
- assert not auth_lib.bcrypt_check_password(
- 'notthepassword',
- '$2a$12$ELVlnw3z1FMu6CEGs/L8XO8vl0BuWSlUHgh0rUrry9DUXGMUNWwl6',
- '3><7R45417')
-
-
-def test_bcrypt_gen_password_hash():
- pw = 'youwillneverguessthis'
-
- # Normal password hash generation, and check on that hash
- hashed_pw = auth_lib.bcrypt_gen_password_hash(pw)
- assert auth_lib.bcrypt_check_password(
- pw, hashed_pw)
- assert not auth_lib.bcrypt_check_password(
- 'notthepassword', hashed_pw)
-
- # Same thing, extra salt.
- hashed_pw = auth_lib.bcrypt_gen_password_hash(pw, '3><7R45417')
- assert auth_lib.bcrypt_check_password(
- pw, hashed_pw, '3><7R45417')
- assert not auth_lib.bcrypt_check_password(
- 'notthepassword', hashed_pw, '3><7R45417')
-
-
-@setup_fresh_app
def test_register_views(test_app):
"""
Massive test function that all our registration-related views all work.
@@ -102,8 +60,8 @@ def test_register_views(test_app):
context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/auth/register.html']
form = context['register_form']
- assert_equal (form.username.errors, [u'Field must be between 3 and 30 characters long.'])
- assert_equal (form.password.errors, [u'Field must be between 5 and 1024 characters long.'])
+ assert form.username.errors == [u'Field must be between 3 and 30 characters long.']
+ assert form.password.errors == [u'Field must be between 5 and 1024 characters long.']
## bad form
template.clear_test_template_context()
@@ -114,11 +72,11 @@ def test_register_views(test_app):
context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/auth/register.html']
form = context['register_form']
- assert_equal (form.username.errors, [u'This field does not take email addresses.'])
- assert_equal (form.email.errors, [u'This field requires an email address.'])
+ assert form.username.errors == [u'This field does not take email addresses.']
+ assert form.email.errors == [u'This field requires an email address.']
## At this point there should be no users in the database ;)
- assert_equal(User.query.count(), 0)
+ assert User.query.count() == 0
# Successful register
# -------------------
@@ -131,14 +89,12 @@ def test_register_views(test_app):
response.follow()
## Did we redirect to the proper page? Use the right template?
- assert_equal(
- urlparse.urlsplit(response.location)[2],
- '/u/happygirl/')
+ assert urlparse.urlsplit(response.location)[2] == '/u/happygirl/'
assert 'mediagoblin/user_pages/user.html' in template.TEMPLATE_TEST_CONTEXT
## Make sure user is in place
- new_user = mg_globals.database.User.find_one(
- {'username': u'happygirl'})
+ new_user = mg_globals.database.User.query.filter_by(
+ username=u'happygirl').first()
assert new_user
assert new_user.status == u'needs_email_verification'
assert new_user.email_verified == False
@@ -161,24 +117,19 @@ def test_register_views(test_app):
assert path == u'/auth/verify_email/'
parsed_get_params = urlparse.parse_qs(get_params)
- ### user should have these same parameters
- assert parsed_get_params['userid'] == [
- unicode(new_user.id)]
- assert parsed_get_params['token'] == [
- new_user.verification_key]
-
## Try verifying with bs verification key, shouldn't work
template.clear_test_template_context()
response = test_app.get(
- "/auth/verify_email/?userid=%s&token=total_bs" % unicode(
- new_user.id))
+ "/auth/verify_email/?token=total_bs")
response.follow()
- context = template.TEMPLATE_TEST_CONTEXT[
- 'mediagoblin/user_pages/user.html']
+
+ # Correct redirect?
+ assert urlparse.urlsplit(response.location)[2] == '/'
+
# assert context['verification_successful'] == True
# TODO: Would be good to test messages here when we can do so...
- new_user = mg_globals.database.User.find_one(
- {'username': u'happygirl'})
+ new_user = mg_globals.database.User.query.filter_by(
+ username=u'happygirl').first()
assert new_user
assert new_user.status == u'needs_email_verification'
assert new_user.email_verified == False
@@ -191,8 +142,8 @@ def test_register_views(test_app):
'mediagoblin/user_pages/user.html']
# assert context['verification_successful'] == True
# TODO: Would be good to test messages here when we can do so...
- new_user = mg_globals.database.User.find_one(
- {'username': u'happygirl'})
+ new_user = mg_globals.database.User.query.filter_by(
+ username=u'happygirl').first()
assert new_user
assert new_user.status == u'active'
assert new_user.email_verified == True
@@ -224,9 +175,7 @@ def test_register_views(test_app):
response.follow()
## Did we redirect to the proper page? Use the right template?
- assert_equal(
- urlparse.urlsplit(response.location)[2],
- '/auth/login/')
+ assert urlparse.urlsplit(response.location)[2] == '/auth/login/'
assert 'mediagoblin/auth/login.html' in template.TEMPLATE_TEST_CONTEXT
## Make sure link to change password is sent by email
@@ -240,35 +189,17 @@ def test_register_views(test_app):
path = urlparse.urlsplit(email_context['verification_url'])[2]
get_params = urlparse.urlsplit(email_context['verification_url'])[3]
- assert path == u'/auth/forgot_password/verify/'
parsed_get_params = urlparse.parse_qs(get_params)
-
- # user should have matching parameters
- new_user = mg_globals.database.User.find_one({'username': u'happygirl'})
- assert parsed_get_params['userid'] == [unicode(new_user.id)]
- assert parsed_get_params['token'] == [new_user.fp_verification_key]
-
- ### The forgotten password token should be set to expire in ~ 10 days
- # A few ticks have expired so there are only 9 full days left...
- assert (new_user.fp_token_expire - datetime.datetime.now()).days == 9
+ assert path == u'/auth/forgot_password/verify/'
## Try using a bs password-changing verification key, shouldn't work
template.clear_test_template_context()
response = test_app.get(
- "/auth/forgot_password/verify/?userid=%s&token=total_bs" % unicode(
- new_user.id), status=404)
- assert_equal(response.status.split()[0], u'404') # status="404 NOT FOUND"
+ "/auth/forgot_password/verify/?token=total_bs")
+ response.follow()
- ## Try using an expired token to change password, shouldn't work
- template.clear_test_template_context()
- new_user = mg_globals.database.User.find_one({'username': u'happygirl'})
- real_token_expiration = new_user.fp_token_expire
- new_user.fp_token_expire = datetime.datetime.now()
- new_user.save()
- response = test_app.get("%s?%s" % (path, get_params), status=404)
- assert_equal(response.status.split()[0], u'404') # status="404 NOT FOUND"
- new_user.fp_token_expire = real_token_expiration
- new_user.save()
+ # Correct redirect?
+ assert urlparse.urlsplit(response.location)[2] == '/'
## Verify step 1 of password-change works -- can see form to change password
template.clear_test_template_context()
@@ -279,7 +210,6 @@ def test_register_views(test_app):
template.clear_test_template_context()
response = test_app.post(
'/auth/forgot_password/verify/', {
- 'userid': parsed_get_params['userid'],
'password': 'iamveryveryhappy',
'token': parsed_get_params['token']})
response.follow()
@@ -294,20 +224,18 @@ def test_register_views(test_app):
# User should be redirected
response.follow()
- assert_equal(
- urlparse.urlsplit(response.location)[2],
- '/')
+ assert urlparse.urlsplit(response.location)[2] == '/'
assert 'mediagoblin/root.html' in template.TEMPLATE_TEST_CONTEXT
-def test_authentication_views():
+def test_authentication_views(test_app):
"""
Test logging in and logging out
"""
- test_app = get_app(dump_old_app=False)
# Make a new user
test_user = fixture_add_user(active_user=False)
+
# Get login
# ---------
test_app.get('/auth/login/')
@@ -320,7 +248,6 @@ def test_authentication_views():
context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/auth/login.html']
form = context['login_form']
assert form.username.errors == [u'This field is required.']
- assert form.password.errors == [u'This field is required.']
# Failed login - blank user
# -------------------------
@@ -338,9 +265,7 @@ def test_authentication_views():
response = test_app.post(
'/auth/login/', {
'username': u'chris'})
- context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/auth/login.html']
- form = context['login_form']
- assert form.password.errors == [u'This field is required.']
+ assert 'mediagoblin/auth/login.html' in template.TEMPLATE_TEST_CONTEXT
# Failed login - bad user
# -----------------------
@@ -372,9 +297,7 @@ def test_authentication_views():
# User should be redirected
response.follow()
- assert_equal(
- urlparse.urlsplit(response.location)[2],
- '/')
+ assert urlparse.urlsplit(response.location)[2] == '/'
assert 'mediagoblin/root.html' in template.TEMPLATE_TEST_CONTEXT
# Make sure user is in the session
@@ -389,9 +312,7 @@ def test_authentication_views():
# Should be redirected to index page
response.follow()
- assert_equal(
- urlparse.urlsplit(response.location)[2],
- '/')
+ assert urlparse.urlsplit(response.location)[2] == '/'
assert 'mediagoblin/root.html' in template.TEMPLATE_TEST_CONTEXT
# Make sure the user is not in the session
@@ -407,6 +328,48 @@ def test_authentication_views():
'username': u'chris',
'password': 'toast',
'next' : '/u/chris/'})
- assert_equal(
- urlparse.urlsplit(response.location)[2],
- '/u/chris/')
+ assert urlparse.urlsplit(response.location)[2] == '/u/chris/'
+
+
+@pytest.fixture()
+def authentication_disabled_app(request):
+ return get_app(
+ request,
+ mgoblin_config=pkg_resources.resource_filename(
+ 'mediagoblin.tests.auth_configs',
+ 'authentication_disabled_appconfig.ini'))
+
+
+def test_authentication_disabled_app(authentication_disabled_app):
+ # app.auth should = false
+ assert mg_globals.app.auth is False
+
+ # Try to visit register page
+ template.clear_test_template_context()
+ response = authentication_disabled_app.get('/auth/register/')
+ response.follow()
+
+ # Correct redirect?
+ assert urlparse.urlsplit(response.location)[2] == '/'
+ assert 'mediagoblin/root.html' in template.TEMPLATE_TEST_CONTEXT
+
+ # Try to vist login page
+ template.clear_test_template_context()
+ response = authentication_disabled_app.get('/auth/login/')
+ response.follow()
+
+ # Correct redirect?
+ assert urlparse.urlsplit(response.location)[2] == '/'
+ assert 'mediagoblin/root.html' in template.TEMPLATE_TEST_CONTEXT
+
+ ## Test check_login_simple should return None
+ assert auth_tools.check_login_simple('test', 'simple') is None
+
+ # Try to visit the forgot password page
+ template.clear_test_template_context()
+ response = authentication_disabled_app.get('/auth/register/')
+ response.follow()
+
+ # Correct redirect?
+ assert urlparse.urlsplit(response.location)[2] == '/'
+ assert 'mediagoblin/root.html' in template.TEMPLATE_TEST_CONTEXT
diff --git a/mediagoblin/tests/test_basic_auth.py b/mediagoblin/tests/test_basic_auth.py
new file mode 100644
index 00000000..cdd80fca
--- /dev/null
+++ b/mediagoblin/tests/test_basic_auth.py
@@ -0,0 +1,59 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+from mediagoblin.plugins.basic_auth import tools as auth_tools
+from mediagoblin.tools.testing import _activate_testing
+
+_activate_testing()
+
+
+########################
+# Test bcrypt auth funcs
+########################
+
+
+def test_bcrypt_check_password():
+ # Check known 'lollerskates' password against check function
+ assert auth_tools.bcrypt_check_password(
+ 'lollerskates',
+ '$2a$12$PXU03zfrVCujBhVeICTwtOaHTUs5FFwsscvSSTJkqx/2RQ0Lhy/nO')
+
+ assert not auth_tools.bcrypt_check_password(
+ 'notthepassword',
+ '$2a$12$PXU03zfrVCujBhVeICTwtOaHTUs5FFwsscvSSTJkqx/2RQ0Lhy/nO')
+
+ # Same thing, but with extra fake salt.
+ assert not auth_tools.bcrypt_check_password(
+ 'notthepassword',
+ '$2a$12$ELVlnw3z1FMu6CEGs/L8XO8vl0BuWSlUHgh0rUrry9DUXGMUNWwl6',
+ '3><7R45417')
+
+
+def test_bcrypt_gen_password_hash():
+ pw = 'youwillneverguessthis'
+
+ # Normal password hash generation, and check on that hash
+ hashed_pw = auth_tools.bcrypt_gen_password_hash(pw)
+ assert auth_tools.bcrypt_check_password(
+ pw, hashed_pw)
+ assert not auth_tools.bcrypt_check_password(
+ 'notthepassword', hashed_pw)
+
+ # Same thing, extra salt.
+ hashed_pw = auth_tools.bcrypt_gen_password_hash(pw, '3><7R45417')
+ assert auth_tools.bcrypt_check_password(
+ pw, hashed_pw, '3><7R45417')
+ assert not auth_tools.bcrypt_check_password(
+ 'notthepassword', hashed_pw, '3><7R45417')
diff --git a/mediagoblin/tests/test_cache.py b/mediagoblin/tests/test_cache.py
deleted file mode 100644
index 48fa1386..00000000
--- a/mediagoblin/tests/test_cache.py
+++ /dev/null
@@ -1,52 +0,0 @@
-# GNU MediaGoblin -- federated, autonomous media hosting
-# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-
-from mediagoblin.tests.tools import setup_fresh_app
-from mediagoblin import mg_globals
-
-
-DATA_TO_CACHE = {
- 'herp': 'derp',
- 'lol': 'cats'}
-
-
-def _get_some_data(key):
- """
- Stuid function that makes use of some caching.
- """
- some_data_cache = mg_globals.cache.get_cache('sum_data')
- if some_data_cache.has_key(key):
- return some_data_cache.get(key)
-
- value = DATA_TO_CACHE.get(key)
- some_data_cache.put(key, value)
- return value
-
-
-@setup_fresh_app
-def test_cache_working(test_app):
- some_data_cache = mg_globals.cache.get_cache('sum_data')
- assert not some_data_cache.has_key('herp')
- assert _get_some_data('herp') == 'derp'
- assert some_data_cache.get('herp') == 'derp'
- # should get the same value again
- assert _get_some_data('herp') == 'derp'
-
- # now we force-change it, but the function should use the cached
- # version
- some_data_cache.put('herp', 'pred')
- assert _get_some_data('herp') == 'pred'
diff --git a/mediagoblin/tests/test_celery_setup.py b/mediagoblin/tests/test_celery_setup.py
index 5530c6f2..0184436a 100644
--- a/mediagoblin/tests/test_celery_setup.py
+++ b/mediagoblin/tests/test_celery_setup.py
@@ -48,7 +48,7 @@ def test_setup_celery_from_config():
assert isinstance(fake_celery_module.CELERYD_ETA_SCHEDULER_PRECISION, float)
assert fake_celery_module.CELERY_RESULT_PERSISTENT is True
assert fake_celery_module.CELERY_IMPORTS == [
- 'foo.bar.baz', 'this.is.an.import', 'mediagoblin.processing.task']
+ 'foo.bar.baz', 'this.is.an.import', 'mediagoblin.processing.task', 'mediagoblin.notifications.task']
assert fake_celery_module.CELERY_RESULT_BACKEND == 'database'
assert fake_celery_module.CELERY_RESULT_DBURI == (
'sqlite:///' +
diff --git a/mediagoblin/tests/test_collections.py b/mediagoblin/tests/test_collections.py
index b19f6362..87782f30 100644
--- a/mediagoblin/tests/test_collections.py
+++ b/mediagoblin/tests/test_collections.py
@@ -14,17 +14,12 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-from mediagoblin.tests.tools import fixture_add_collection, fixture_add_user, \
- get_app
+from mediagoblin.tests.tools import fixture_add_collection, fixture_add_user
from mediagoblin.db.models import Collection, User
-from mediagoblin.db.base import Session
-from nose.tools import assert_equal
-def test_user_deletes_collection():
+def test_user_deletes_collection(test_app):
# Setup db.
- get_app(dump_old_app=False)
-
user = fixture_add_user()
coll = fixture_add_collection(user=user)
# Reload into session:
@@ -34,4 +29,4 @@ def test_user_deletes_collection():
user.delete()
cnt2 = Collection.query.count()
- assert_equal(cnt1, cnt2 + 1)
+ assert cnt1 == cnt2 + 1
diff --git a/mediagoblin/tests/test_csrf_middleware.py b/mediagoblin/tests/test_csrf_middleware.py
index e720264c..a272caf6 100644
--- a/mediagoblin/tests/test_csrf_middleware.py
+++ b/mediagoblin/tests/test_csrf_middleware.py
@@ -14,12 +14,10 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-from mediagoblin.tests.tools import get_app
from mediagoblin import mg_globals
-def test_csrf_cookie_set():
- test_app = get_app(dump_old_app=False)
+def test_csrf_cookie_set(test_app):
cookie_name = mg_globals.app_config['csrf_cookie_name']
# get login page
@@ -33,11 +31,14 @@ def test_csrf_cookie_set():
assert response.headers.get('Vary', False) == 'Cookie'
-def test_csrf_token_must_match():
- # We need a fresh app for this test on webtest < 1.3.6.
- # We do not understand why, but it fixes the tests.
- # If we require webtest >= 1.3.6, we can switch to a non fresh app here.
- test_app = get_app(dump_old_app=True)
+# We need a fresh app for this test on webtest < 1.3.6.
+# We do not understand why, but it fixes the tests.
+# If we require webtest >= 1.3.6, we can switch to a non fresh app here.
+#
+# ... this comment might be irrelevant post-pytest-fixtures, but I'm not
+# removing it yet in case we move to module-level tests :)
+# -- cwebber
+def test_csrf_token_must_match(test_app):
# construct a request with no cookie or form token
assert test_app.post('/auth/login/',
@@ -67,8 +68,7 @@ def test_csrf_token_must_match():
extra_environ={'gmg.verify_csrf': True}).\
status_int == 200
-def test_csrf_exempt():
- test_app = get_app(dump_old_app=False)
+def test_csrf_exempt(test_app):
# monkey with the views to decorate a known endpoint
import mediagoblin.auth.views
from mediagoblin.meddleware.csrf import csrf_exempt
diff --git a/mediagoblin/tests/test_edit.py b/mediagoblin/tests/test_edit.py
index 7db6eaea..d70d0478 100644
--- a/mediagoblin/tests/test_edit.py
+++ b/mediagoblin/tests/test_edit.py
@@ -14,35 +14,36 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-from nose.tools import assert_equal
+import urlparse
from mediagoblin import mg_globals
from mediagoblin.db.models import User
-from mediagoblin.tests.tools import get_app, fixture_add_user
-from mediagoblin.tools import template
-from mediagoblin.auth.lib import bcrypt_check_password
+from mediagoblin.tests.tools import fixture_add_user
+from mediagoblin import auth
+from mediagoblin.tools import template, mail
+
class TestUserEdit(object):
- def setUp(self):
- self.app = get_app(dump_old_app=False)
+ def setup(self):
# set up new user
self.user_password = u'toast'
self.user = fixture_add_user(password = self.user_password)
- self.login()
- def login(self):
- self.app.post(
+ def login(self, test_app):
+ test_app.post(
'/auth/login/', {
'username': self.user.username,
'password': self.user_password})
- def test_user_deletion(self):
+ def test_user_deletion(self, test_app):
"""Delete user via web interface"""
+ self.login(test_app)
+
# Make sure user exists
assert User.query.filter_by(username=u'chris').first()
- res = self.app.post('/edit/account/delete/', {'confirmed': 'y'})
+ res = test_app.post('/edit/account/delete/', {'confirmed': 'y'})
# Make sure user has been deleted
assert User.query.filter_by(username=u'chris').first() == None
@@ -52,84 +53,156 @@ class TestUserEdit(object):
#Restore user at end of test
self.user = fixture_add_user(password = self.user_password)
- self.login()
+ self.login(test_app)
- def test_change_password(self):
+ def test_change_password(self, test_app):
"""Test changing password correctly and incorrectly"""
+ self.login(test_app)
+
# test that the password can be changed
- # template.clear_test_template_context()
- res = self.app.post(
- '/edit/account/', {
+ template.clear_test_template_context()
+ res = test_app.post(
+ '/edit/password/', {
'old_password': 'toast',
'new_password': '123456',
- 'wants_comment_notification': 'y'
})
+ res.follow()
+
+ # Did we redirect to the correct page?
+ assert urlparse.urlsplit(res.location)[2] == '/edit/account/'
- # Check for redirect on success
- assert_equal(res.status_int, 302)
# test_user has to be fetched again in order to have the current values
test_user = User.query.filter_by(username=u'chris').first()
- assert bcrypt_check_password('123456', test_user.pw_hash)
+ assert auth.check_password('123456', test_user.pw_hash)
# Update current user passwd
self.user_password = '123456'
# test that the password cannot be changed if the given
- # old_password is wrong template.clear_test_template_context()
- self.app.post(
- '/edit/account/', {
+ # old_password is wrong
+ template.clear_test_template_context()
+ test_app.post(
+ '/edit/password/', {
'old_password': 'toast',
'new_password': '098765',
})
test_user = User.query.filter_by(username=u'chris').first()
- assert not bcrypt_check_password('098765', test_user.pw_hash)
-
+ assert not auth.check_password('098765', test_user.pw_hash)
- def test_change_bio_url(self):
+ def test_change_bio_url(self, test_app):
"""Test changing bio and URL"""
+ self.login(test_app)
+
# Test if legacy profile editing URL redirects correctly
- res = self.app.post(
+ res = test_app.post(
'/edit/profile/', {
'bio': u'I love toast!',
'url': u'http://dustycloud.org/'}, expect_errors=True)
# Should redirect to /u/chris/edit/
- assert_equal (res.status_int, 302)
+ assert res.status_int == 302
assert res.headers['Location'].endswith("/u/chris/edit/")
- res = self.app.post(
+ res = test_app.post(
'/u/chris/edit/', {
'bio': u'I love toast!',
'url': u'http://dustycloud.org/'})
test_user = User.query.filter_by(username=u'chris').first()
- assert_equal(test_user.bio, u'I love toast!')
- assert_equal(test_user.url, u'http://dustycloud.org/')
+ assert test_user.bio == u'I love toast!'
+ assert test_user.url == u'http://dustycloud.org/'
# change a different user than the logged in (should fail with 403)
fixture_add_user(username=u"foo")
- res = self.app.post(
+ res = test_app.post(
'/u/foo/edit/', {
'bio': u'I love toast!',
'url': u'http://dustycloud.org/'}, expect_errors=True)
- assert_equal(res.status_int, 403)
+ assert res.status_int == 403
# test changing the bio and the URL inproperly
too_long_bio = 150 * 'T' + 150 * 'o' + 150 * 'a' + 150 * 's' + 150* 't'
- self.app.post(
+ test_app.post(
'/u/chris/edit/', {
# more than 500 characters
'bio': too_long_bio,
'url': 'this-is-no-url'})
# Check form errors
- context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/edit/edit_profile.html']
+ context = template.TEMPLATE_TEST_CONTEXT[
+ 'mediagoblin/edit/edit_profile.html']
form = context['form']
- assert_equal(form.bio.errors, [u'Field must be between 0 and 500 characters long.'])
- assert_equal(form.url.errors, [u'This address contains errors'])
+ assert form.bio.errors == [
+ u'Field must be between 0 and 500 characters long.']
+ assert form.url.errors == [
+ u'This address contains errors']
+
+ def test_email_change(self, test_app):
+ self.login(test_app)
+
+ # Test email already in db
+ template.clear_test_template_context()
+ test_app.post(
+ '/edit/account/', {
+ 'new_email': 'chris@example.com',
+ 'password': 'toast'})
+ # Check form errors
+ context = template.TEMPLATE_TEST_CONTEXT[
+ 'mediagoblin/edit/edit_account.html']
+ assert context['form'].new_email.errors == [
+ u'Sorry, a user with that email address already exists.']
+
+ # Test successful email change
+ template.clear_test_template_context()
+ res = test_app.post(
+ '/edit/account/', {
+ 'new_email': 'new@example.com',
+ 'password': 'toast'})
+ res.follow()
+
+ # Correct redirect?
+ assert urlparse.urlsplit(res.location)[2] == '/u/chris/'
+
+ # Make sure we get email verification and try verifying
+ assert len(mail.EMAIL_TEST_INBOX) == 1
+ message = mail.EMAIL_TEST_INBOX.pop()
+ assert message['To'] == 'new@example.com'
+ email_context = template.TEMPLATE_TEST_CONTEXT[
+ 'mediagoblin/edit/verification.txt']
+ assert email_context['verification_url'] in \
+ message.get_payload(decode=True)
+
+ path = urlparse.urlsplit(email_context['verification_url'])[2]
+ assert path == u'/edit/verify_email/'
+
+ ## Try verifying with bs verification key, shouldn't work
+ template.clear_test_template_context()
+ res = test_app.get(
+ "/edit/verify_email/?token=total_bs")
+ res.follow()
+
+ # Correct redirect?
+ assert urlparse.urlsplit(res.location)[2] == '/'
+
+ # Email shouldn't be saved
+ email_in_db = mg_globals.database.User.query.filter_by(
+ email='new@example.com').first()
+ email = User.query.filter_by(username='chris').first().email
+ assert email_in_db is None
+ assert email == 'chris@example.com'
+
+ # Verify email activation works
+ template.clear_test_template_context()
+ get_params = urlparse.urlsplit(email_context['verification_url'])[3]
+ res = test_app.get('%s?%s' % (path, get_params))
+ res.follow()
+
+ # New email saved?
+ email = User.query.filter_by(username='chris').first().email
+ assert email == 'new@example.com'
# test changing the url inproperly
diff --git a/mediagoblin/tests/test_exif.py b/mediagoblin/tests/test_exif.py
index 100d17f0..c07e24ae 100644
--- a/mediagoblin/tests/test_exif.py
+++ b/mediagoblin/tests/test_exif.py
@@ -15,39 +15,20 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
-import pkg_resources
-import Image
+try:
+ from PIL import Image
+except ImportError:
+ import Image
from mediagoblin.tools.exif import exif_fix_image_orientation, \
extract_exif, clean_exif, get_gps_data, get_useful
+from .resources import GOOD_JPG, EMPTY_JPG, BAD_JPG, GPS_JPG
def assert_in(a, b):
assert a in b, "%r not in %r" % (a, b)
-GOOD_JPG = pkg_resources.resource_filename(
- 'mediagoblin.tests',
- os.path.join(
- 'test_exif',
- 'good.jpg'))
-EMPTY_JPG = pkg_resources.resource_filename(
- 'mediagoblin.tests',
- os.path.join(
- 'test_exif',
- 'empty.jpg'))
-BAD_JPG = pkg_resources.resource_filename(
- 'mediagoblin.tests',
- os.path.join(
- 'test_exif',
- 'bad.jpg'))
-GPS_JPG = pkg_resources.resource_filename(
- 'mediagoblin.tests',
- os.path.join(
- 'test_exif',
- 'has-gps.jpg'))
-
-
def test_exif_extraction():
'''
Test EXIF extraction from a good image
@@ -67,63 +48,324 @@ def test_exif_extraction():
assert gps == {}
# Do we have the "useful" tags?
- assert useful == {
- 'EXIF Flash': {
- 'field_type': 3,
- 'printable': u'Flash did not fire',
- 'field_offset': 380,
- 'tag': 37385,
- 'values': [0],
- 'field_length': 2},
- 'EXIF ExposureTime': {
- 'field_type': 5,
- 'printable': '1/125',
- 'field_offset': 700,
- 'tag': 33434,
- 'values': [[1, 125]],
- 'field_length': 8},
- 'EXIF FocalLength': {
- 'field_type': 5,
- 'printable': '18',
- 'field_offset': 780,
- 'tag': 37386,
- 'values': [[18, 1]],
- 'field_length': 8},
- 'Image Model': {
- 'field_type': 2,
- 'printable': 'NIKON D80',
- 'field_offset': 152,
- 'tag': 272,
- 'values': 'NIKON D80',
- 'field_length': 10},
- 'Image Make': {
- 'field_type': 2,
- 'printable': 'NIKON CORPORATION',
- 'field_offset': 134,
- 'tag': 271,
- 'values': 'NIKON CORPORATION',
- 'field_length': 18},
- 'EXIF ExposureMode': {
- 'field_type': 3,
- 'printable': 'Manual Exposure',
- 'field_offset': 584,
- 'tag': 41986,
- 'values': [1],
- 'field_length': 2},
- 'EXIF ISOSpeedRatings': {
- 'field_type': 3,
- 'printable': '100',
- 'field_offset': 260,
- 'tag': 34855,
- 'values': [100],
- 'field_length': 2},
- 'EXIF FNumber': {
- 'field_type': 5,
- 'printable': '10',
- 'field_offset': 708,
- 'tag': 33437,
- 'values': [[10, 1]],
- 'field_length': 8}}
+ assert useful == {'EXIF CVAPattern': {'field_length': 8,
+ 'field_offset': 26224,
+ 'field_type': 7,
+ 'printable': u'[0, 2, 0, 2, 1, 2, 0, 1]',
+ 'tag': 41730,
+ 'values': [0, 2, 0, 2, 1, 2, 0, 1]},
+ 'EXIF ColorSpace': {'field_length': 2,
+ 'field_offset': 476,
+ 'field_type': 3,
+ 'printable': u'sRGB',
+ 'tag': 40961,
+ 'values': [1]},
+ 'EXIF ComponentsConfiguration': {'field_length': 4,
+ 'field_offset': 308,
+ 'field_type': 7,
+ 'printable': u'YCbCr',
+ 'tag': 37121,
+ 'values': [1, 2, 3, 0]},
+ 'EXIF CompressedBitsPerPixel': {'field_length': 8,
+ 'field_offset': 756,
+ 'field_type': 5,
+ 'printable': u'4',
+ 'tag': 37122,
+ 'values': [[4, 1]]},
+ 'EXIF Contrast': {'field_length': 2,
+ 'field_offset': 656,
+ 'field_type': 3,
+ 'printable': u'Soft',
+ 'tag': 41992,
+ 'values': [1]},
+ 'EXIF CustomRendered': {'field_length': 2,
+ 'field_offset': 572,
+ 'field_type': 3,
+ 'printable': u'Normal',
+ 'tag': 41985,
+ 'values': [0]},
+ 'EXIF DateTimeDigitized': {'field_length': 20,
+ 'field_offset': 736,
+ 'field_type': 2,
+ 'printable': u'2011:06:22 12:20:33',
+ 'tag': 36868,
+ 'values': u'2011:06:22 12:20:33'},
+ 'EXIF DateTimeOriginal': {'field_length': 20,
+ 'field_offset': 716,
+ 'field_type': 2,
+ 'printable': u'2011:06:22 12:20:33',
+ 'tag': 36867,
+ 'values': u'2011:06:22 12:20:33'},
+ 'EXIF DigitalZoomRatio': {'field_length': 8,
+ 'field_offset': 26232,
+ 'field_type': 5,
+ 'printable': u'1',
+ 'tag': 41988,
+ 'values': [[1, 1]]},
+ 'EXIF ExifImageLength': {'field_length': 2,
+ 'field_offset': 500,
+ 'field_type': 3,
+ 'printable': u'2592',
+ 'tag': 40963,
+ 'values': [2592]},
+ 'EXIF ExifImageWidth': {'field_length': 2,
+ 'field_offset': 488,
+ 'field_type': 3,
+ 'printable': u'3872',
+ 'tag': 40962,
+ 'values': [3872]},
+ 'EXIF ExifVersion': {'field_length': 4,
+ 'field_offset': 272,
+ 'field_type': 7,
+ 'printable': u'0221',
+ 'tag': 36864,
+ 'values': [48, 50, 50, 49]},
+ 'EXIF ExposureBiasValue': {'field_length': 8,
+ 'field_offset': 764,
+ 'field_type': 10,
+ 'printable': u'0',
+ 'tag': 37380,
+ 'values': [[0, 1]]},
+ 'EXIF ExposureMode': {'field_length': 2,
+ 'field_offset': 584,
+ 'field_type': 3,
+ 'printable': u'Manual Exposure',
+ 'tag': 41986,
+ 'values': [1]},
+ 'EXIF ExposureProgram': {'field_length': 2,
+ 'field_offset': 248,
+ 'field_type': 3,
+ 'printable': u'Manual',
+ 'tag': 34850,
+ 'values': [1]},
+ 'EXIF ExposureTime': {'field_length': 8,
+ 'field_offset': 700,
+ 'field_type': 5,
+ 'printable': u'1/125',
+ 'tag': 33434,
+ 'values': [[1, 125]]},
+ 'EXIF FNumber': {'field_length': 8,
+ 'field_offset': 708,
+ 'field_type': 5,
+ 'printable': u'10',
+ 'tag': 33437,
+ 'values': [[10, 1]]},
+ 'EXIF FileSource': {'field_length': 1,
+ 'field_offset': 536,
+ 'field_type': 7,
+ 'printable': u'Digital Camera',
+ 'tag': 41728,
+ 'values': [3]},
+ 'EXIF Flash': {'field_length': 2,
+ 'field_offset': 380,
+ 'field_type': 3,
+ 'printable': u'Flash did not fire',
+ 'tag': 37385,
+ 'values': [0]},
+ 'EXIF FlashPixVersion': {'field_length': 4,
+ 'field_offset': 464,
+ 'field_type': 7,
+ 'printable': u'0100',
+ 'tag': 40960,
+ 'values': [48, 49, 48, 48]},
+ 'EXIF FocalLength': {'field_length': 8,
+ 'field_offset': 780,
+ 'field_type': 5,
+ 'printable': u'18',
+ 'tag': 37386,
+ 'values': [[18, 1]]},
+ 'EXIF FocalLengthIn35mmFilm': {'field_length': 2,
+ 'field_offset': 620,
+ 'field_type': 3,
+ 'printable': u'27',
+ 'tag': 41989,
+ 'values': [27]},
+ 'EXIF GainControl': {'field_length': 2,
+ 'field_offset': 644,
+ 'field_type': 3,
+ 'printable': u'None',
+ 'tag': 41991,
+ 'values': [0]},
+ 'EXIF ISOSpeedRatings': {'field_length': 2,
+ 'field_offset': 260,
+ 'field_type': 3,
+ 'printable': u'100',
+ 'tag': 34855,
+ 'values': [100]},
+ 'EXIF InteroperabilityOffset': {'field_length': 4,
+ 'field_offset': 512,
+ 'field_type': 4,
+ 'printable': u'26240',
+ 'tag': 40965,
+ 'values': [26240]},
+ 'EXIF LightSource': {'field_length': 2,
+ 'field_offset': 368,
+ 'field_type': 3,
+ 'printable': u'Unknown',
+ 'tag': 37384,
+ 'values': [0]},
+ 'EXIF MaxApertureValue': {'field_length': 8,
+ 'field_offset': 772,
+ 'field_type': 5,
+ 'printable': u'18/5',
+ 'tag': 37381,
+ 'values': [[18, 5]]},
+ 'EXIF MeteringMode': {'field_length': 2,
+ 'field_offset': 356,
+ 'field_type': 3,
+ 'printable': u'Pattern',
+ 'tag': 37383,
+ 'values': [5]},
+ 'EXIF Saturation': {'field_length': 2,
+ 'field_offset': 668,
+ 'field_type': 3,
+ 'printable': u'Normal',
+ 'tag': 41993,
+ 'values': [0]},
+ 'EXIF SceneCaptureType': {'field_length': 2,
+ 'field_offset': 632,
+ 'field_type': 3,
+ 'printable': u'Standard',
+ 'tag': 41990,
+ 'values': [0]},
+ 'EXIF SceneType': {'field_length': 1,
+ 'field_offset': 548,
+ 'field_type': 7,
+ 'printable': u'Directly Photographed',
+ 'tag': 41729,
+ 'values': [1]},
+ 'EXIF SensingMethod': {'field_length': 2,
+ 'field_offset': 524,
+ 'field_type': 3,
+ 'printable': u'One-chip color area',
+ 'tag': 41495,
+ 'values': [2]},
+ 'EXIF Sharpness': {'field_length': 2,
+ 'field_offset': 680,
+ 'field_type': 3,
+ 'printable': u'Normal',
+ 'tag': 41994,
+ 'values': [0]},
+ 'EXIF SubSecTime': {'field_length': 3,
+ 'field_offset': 428,
+ 'field_type': 2,
+ 'printable': u'10',
+ 'tag': 37520,
+ 'values': u'10'},
+ 'EXIF SubSecTimeDigitized': {'field_length': 3,
+ 'field_offset': 452,
+ 'field_type': 2,
+ 'printable': u'10',
+ 'tag': 37522,
+ 'values': u'10'},
+ 'EXIF SubSecTimeOriginal': {'field_length': 3,
+ 'field_offset': 440,
+ 'field_type': 2,
+ 'printable': u'10',
+ 'tag': 37521,
+ 'values': u'10'},
+ 'EXIF SubjectDistanceRange': {'field_length': 2,
+ 'field_offset': 692,
+ 'field_type': 3,
+ 'printable': u'0',
+ 'tag': 41996,
+ 'values': [0]},
+ 'EXIF WhiteBalance': {'field_length': 2,
+ 'field_offset': 596,
+ 'field_type': 3,
+ 'printable': u'Auto',
+ 'tag': 41987,
+ 'values': [0]},
+ 'Image DateTime': {'field_length': 20,
+ 'field_offset': 194,
+ 'field_type': 2,
+ 'printable': u'2011:06:22 12:20:33',
+ 'tag': 306,
+ 'values': u'2011:06:22 12:20:33'},
+ 'Image ExifOffset': {'field_length': 4,
+ 'field_offset': 126,
+ 'field_type': 4,
+ 'printable': u'214',
+ 'tag': 34665,
+ 'values': [214]},
+ 'Image Make': {'field_length': 18,
+ 'field_offset': 134,
+ 'field_type': 2,
+ 'printable': u'NIKON CORPORATION',
+ 'tag': 271,
+ 'values': u'NIKON CORPORATION'},
+ 'Image Model': {'field_length': 10,
+ 'field_offset': 152,
+ 'field_type': 2,
+ 'printable': u'NIKON D80',
+ 'tag': 272,
+ 'values': u'NIKON D80'},
+ 'Image Orientation': {'field_length': 2,
+ 'field_offset': 42,
+ 'field_type': 3,
+ 'printable': u'Rotated 90 CCW',
+ 'tag': 274,
+ 'values': [6]},
+ 'Image ResolutionUnit': {'field_length': 2,
+ 'field_offset': 78,
+ 'field_type': 3,
+ 'printable': u'Pixels/Inch',
+ 'tag': 296,
+ 'values': [2]},
+ 'Image Software': {'field_length': 15,
+ 'field_offset': 178,
+ 'field_type': 2,
+ 'printable': u'Shotwell 0.9.3',
+ 'tag': 305,
+ 'values': u'Shotwell 0.9.3'},
+ 'Image XResolution': {'field_length': 8,
+ 'field_offset': 162,
+ 'field_type': 5,
+ 'printable': u'300',
+ 'tag': 282,
+ 'values': [[300, 1]]},
+ 'Image YCbCrPositioning': {'field_length': 2,
+ 'field_offset': 114,
+ 'field_type': 3,
+ 'printable': u'Co-sited',
+ 'tag': 531,
+ 'values': [2]},
+ 'Image YResolution': {'field_length': 8,
+ 'field_offset': 170,
+ 'field_type': 5,
+ 'printable': u'300',
+ 'tag': 283,
+ 'values': [[300, 1]]},
+ 'Thumbnail Compression': {'field_length': 2,
+ 'field_offset': 26280,
+ 'field_type': 3,
+ 'printable': u'JPEG (old-style)',
+ 'tag': 259,
+ 'values': [6]},
+ 'Thumbnail ResolutionUnit': {'field_length': 2,
+ 'field_offset': 26316,
+ 'field_type': 3,
+ 'printable': u'Pixels/Inch',
+ 'tag': 296,
+ 'values': [2]},
+ 'Thumbnail XResolution': {'field_length': 8,
+ 'field_offset': 26360,
+ 'field_type': 5,
+ 'printable': u'300',
+ 'tag': 282,
+ 'values': [[300, 1]]},
+ 'Thumbnail YCbCrPositioning': {'field_length': 2,
+ 'field_offset': 26352,
+ 'field_type': 3,
+ 'printable': u'Co-sited',
+ 'tag': 531,
+ 'values': [2]},
+ 'Thumbnail YResolution': {'field_length': 8,
+ 'field_offset': 26368,
+ 'field_type': 5,
+ 'printable': u'300',
+ 'tag': 283,
+ 'values': [[300, 1]]}}
def test_exif_image_orientation():
diff --git a/mediagoblin/tests/test_globals.py b/mediagoblin/tests/test_globals.py
index 303f89e2..fe3088f8 100644
--- a/mediagoblin/tests/test_globals.py
+++ b/mediagoblin/tests/test_globals.py
@@ -14,16 +14,16 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-from nose.tools import assert_raises
+import pytest
from mediagoblin import mg_globals
class TestGlobals(object):
- def setUp(self):
+ def setup(self):
self.old_database = mg_globals.database
- def tearDown(self):
+ def teardown(self):
mg_globals.database = self.old_database
def test_setup_globals(self):
@@ -36,7 +36,7 @@ class TestGlobals(object):
assert mg_globals.public_store == 'my favorite public_store!'
assert mg_globals.queue_store == 'my favorite queue_store!'
- assert_raises(
+ pytest.raises(
AssertionError,
mg_globals.setup_globals,
- no_such_global_foo = "Dummy")
+ no_such_global_foo="Dummy")
diff --git a/mediagoblin/tests/test_http_callback.py b/mediagoblin/tests/test_http_callback.py
index 8bee7045..a0511af7 100644
--- a/mediagoblin/tests/test_http_callback.py
+++ b/mediagoblin/tests/test_http_callback.py
@@ -16,18 +16,21 @@
import json
+import pytest
from urlparse import urlparse, parse_qs
from mediagoblin import mg_globals
from mediagoblin.tools import processing
-from mediagoblin.tests.tools import get_app, fixture_add_user
+from mediagoblin.tests.tools import fixture_add_user
from mediagoblin.tests.test_submission import GOOD_PNG
from mediagoblin.tests import test_oauth as oauth
class TestHTTPCallback(object):
- def setUp(self):
- self.app = get_app(dump_old_app=False)
+ @pytest.fixture(autouse=True)
+ def setup(self, test_app):
+ self.test_app = test_app
+
self.db = mg_globals.database
self.user_password = u'secret'
@@ -36,12 +39,12 @@ class TestHTTPCallback(object):
self.login()
def login(self):
- self.app.post('/auth/login/', {
+ self.test_app.post('/auth/login/', {
'username': self.user.username,
'password': self.user_password})
def get_access_token(self, client_id, client_secret, code):
- response = self.app.get('/oauth/access_token', {
+ response = self.test_app.get('/oauth/access_token', {
'code': code,
'client_id': client_id,
'client_secret': client_secret})
@@ -52,9 +55,8 @@ class TestHTTPCallback(object):
def test_callback(self):
''' Test processing HTTP callback '''
-
self.oauth = oauth.TestOAuth()
- self.oauth.setUp()
+ self.oauth.setup(self.test_app)
redirect, client_id = self.oauth.test_4_authorize_confidential_client()
@@ -69,7 +71,7 @@ class TestHTTPCallback(object):
callback_url = 'https://foo.example?secrettestmediagoblinparam'
- res = self.app.post('/api/submit?client_id={0}&access_token={1}\
+ self.test_app.post('/api/submit?client_id={0}&access_token={1}\
&client_secret={2}'.format(
client_id,
access_token,
diff --git a/mediagoblin/tests/test_messages.py b/mediagoblin/tests/test_messages.py
index 4c0f3e2e..22f9e800 100644
--- a/mediagoblin/tests/test_messages.py
+++ b/mediagoblin/tests/test_messages.py
@@ -14,19 +14,16 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-from mediagoblin.messages import fetch_messages, add_message
-from mediagoblin.tests.tools import get_app
+from mediagoblin import messages
from mediagoblin.tools import template
-
-def test_messages():
+def test_messages(test_app):
"""
Added messages should show up in the request.session,
fetched messages should be the same as the added ones,
and fetching should clear the message list.
"""
- test_app = get_app(dump_old_app=False)
# Aquire a request object
test_app.get('/')
context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/root.html']
@@ -35,11 +32,19 @@ def test_messages():
# The message queue should be empty
assert request.session.get('messages', []) == []
+ # First of all, we should clear the messages queue
+ messages.clear_add_message()
# Adding a message should modify the session accordingly
- add_message(request, 'herp_derp', 'First!')
+ messages.add_message(request, 'herp_derp', 'First!')
test_msg_queue = [{'text': 'First!', 'level': 'herp_derp'}]
- assert request.session['messages'] == test_msg_queue
+
+ # Alternative tests to the following, test divided in two steps:
+ # assert request.session['messages'] == test_msg_queue
+ # 1. Tests if add_message worked
+ assert messages.ADD_MESSAGE_TEST[-1] == test_msg_queue
+ # 2. Tests if add_message updated session information
+ assert messages.ADD_MESSAGE_TEST[-1] == request.session['messages']
# fetch_messages should return and empty the queue
- assert fetch_messages(request) == test_msg_queue
+ assert messages.fetch_messages(request) == test_msg_queue
assert request.session.get('messages') == []
diff --git a/mediagoblin/tests/test_mgoblin_app.ini b/mediagoblin/tests/test_mgoblin_app.ini
index 42d3785a..535cf1c1 100644
--- a/mediagoblin/tests/test_mgoblin_app.ini
+++ b/mediagoblin/tests/test_mgoblin_app.ini
@@ -3,8 +3,9 @@ direct_remote_path = /test_static/
email_sender_address = "notice@mediagoblin.example.org"
email_debug_mode = true
-# TODO: Switch to using an in-memory database
-sql_engine = "sqlite:///%(here)s/test_user_dev/mediagoblin.db"
+#Runs with an in-memory sqlite db for speed.
+sql_engine = "sqlite://"
+run_migrations = true
# tag parsing
tags_max_length = 50
@@ -12,28 +13,24 @@ tags_max_length = 50
# So we can start to test attachments:
allow_attachments = True
-# Celery shouldn't be set up by the application as it's setup via
-# mediagoblin.init.celery.from_celery
-celery_setup_elsewhere = true
-
[storage:publicstore]
-base_dir = %(here)s/test_user_dev/media/public
+base_dir = %(here)s/user_dev/media/public
base_url = /mgoblin_media/
[storage:queuestore]
-base_dir = %(here)s/test_user_dev/media/queue
-
-[beaker.cache]
-data_dir = %(here)s/test_user_dev/beaker/cache/data
-lock_dir = %(here)s/test_user_dev/beaker/cache/lock
+base_dir = %(here)s/user_dev/media/queue
[celery]
CELERY_ALWAYS_EAGER = true
-CELERY_RESULT_DBURI = "sqlite:///%(here)s/test_user_dev/celery.db"
-BROKER_HOST = "sqlite:///%(here)s/test_user_dev/kombu.db"
+CELERY_RESULT_DBURI = "sqlite:///%(here)s/user_dev/celery.db"
+BROKER_HOST = "sqlite:///%(here)s/user_dev/kombu.db"
[plugins]
[[mediagoblin.plugins.api]]
[[mediagoblin.plugins.oauth]]
[[mediagoblin.plugins.httpapiauth]]
-
+[[mediagoblin.plugins.piwigo]]
+[[mediagoblin.plugins.basic_auth]]
+[[mediagoblin.plugins.openid]]
+[[mediagoblin.media_types.image]]
+[[mediagoblin.media_types.pdf]]
diff --git a/mediagoblin/tests/test_misc.py b/mediagoblin/tests/test_misc.py
index 776affc6..43ad0b6d 100644
--- a/mediagoblin/tests/test_misc.py
+++ b/mediagoblin/tests/test_misc.py
@@ -14,26 +14,24 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-from nose.tools import assert_equal
-
from mediagoblin.db.base import Session
from mediagoblin.db.models import User, MediaEntry, MediaComment
-from mediagoblin.tests.tools import get_app, \
- fixture_add_user, fixture_media_entry
+from mediagoblin.tests.tools import fixture_add_user, fixture_media_entry
-def test_404_for_non_existent():
- test_app = get_app(dump_old_app=False)
+def test_404_for_non_existent(test_app):
res = test_app.get('/does-not-exist/', expect_errors=True)
- assert_equal(res.status_int, 404)
+ assert res.status_int == 404
-def test_user_deletes_other_comments():
+def test_user_deletes_other_comments(test_app):
user_a = fixture_add_user(u"chris_a")
user_b = fixture_add_user(u"chris_b")
- media_a = fixture_media_entry(uploader=user_a.id, save=False)
- media_b = fixture_media_entry(uploader=user_b.id, save=False)
+ media_a = fixture_media_entry(uploader=user_a.id, save=False,
+ expunge=False, fake_upload=False)
+ media_b = fixture_media_entry(uploader=user_b.id, save=False,
+ expunge=False, fake_upload=False)
Session.add(media_a)
Session.add(media_b)
Session.flush()
@@ -60,11 +58,11 @@ def test_user_deletes_other_comments():
cmt_cnt2 = MediaComment.query.count()
# One user deleted
- assert_equal(usr_cnt2, usr_cnt1 - 1)
+ assert usr_cnt2 == usr_cnt1 - 1
# One media gone
- assert_equal(med_cnt2, med_cnt1 - 1)
+ assert med_cnt2 == med_cnt1 - 1
# Three of four comments gone.
- assert_equal(cmt_cnt2, cmt_cnt1 - 3)
+ assert cmt_cnt2 == cmt_cnt1 - 3
User.query.get(user_b.id).delete()
@@ -73,17 +71,17 @@ def test_user_deletes_other_comments():
cmt_cnt2 = MediaComment.query.count()
# All users gone
- assert_equal(usr_cnt2, usr_cnt1 - 2)
+ assert usr_cnt2 == usr_cnt1 - 2
# All media gone
- assert_equal(med_cnt2, med_cnt1 - 2)
+ assert med_cnt2 == med_cnt1 - 2
# All comments gone
- assert_equal(cmt_cnt2, cmt_cnt1 - 4)
+ assert cmt_cnt2 == cmt_cnt1 - 4
-def test_media_deletes_broken_attachment():
+def test_media_deletes_broken_attachment(test_app):
user_a = fixture_add_user(u"chris_a")
- media = fixture_media_entry(uploader=user_a.id, save=False)
+ media = fixture_media_entry(uploader=user_a.id, save=False, expunge=False)
media.attachment_files.append(dict(
name=u"some name",
filepath=[u"does", u"not", u"exist"],
diff --git a/mediagoblin/tests/test_modelmethods.py b/mediagoblin/tests/test_modelmethods.py
index 7719bd97..427aa47c 100644
--- a/mediagoblin/tests/test_modelmethods.py
+++ b/mediagoblin/tests/test_modelmethods.py
@@ -17,13 +17,10 @@
# Maybe not every model needs a test, but some models have special
# methods, and so it makes sense to test them here.
-from nose.tools import assert_equal
-
from mediagoblin.db.base import Session
from mediagoblin.db.models import MediaEntry
-from mediagoblin.tests.tools import get_app, \
- fixture_add_user
+from mediagoblin.tests.tools import fixture_add_user
import mock
@@ -35,8 +32,7 @@ UUID_MOCK = mock.Mock(return_value=FakeUUID())
class TestMediaEntrySlugs(object):
- def setUp(self):
- self.test_app = get_app(dump_old_app=True)
+ def _setup(self):
self.chris_user = fixture_add_user(u'chris')
self.emily_user = fixture_add_user(u'emily')
self.existing_entry = self._insert_media_entry_fixture(
@@ -57,56 +53,78 @@ class TestMediaEntrySlugs(object):
return entry
- def test_unique_slug_from_title(self):
+ def test_unique_slug_from_title(self, test_app):
+ self._setup()
+
entry = self._insert_media_entry_fixture(u"Totally unique slug!", save=False)
entry.generate_slug()
assert entry.slug == u'totally-unique-slug'
- def test_old_good_unique_slug(self):
+ def test_old_good_unique_slug(self, test_app):
+ self._setup()
+
entry = self._insert_media_entry_fixture(
u"A title here", u"a-different-slug-there", save=False)
entry.generate_slug()
assert entry.slug == u"a-different-slug-there"
- def test_old_weird_slug(self):
+ def test_old_weird_slug(self, test_app):
+ self._setup()
+
entry = self._insert_media_entry_fixture(
slug=u"wowee!!!!!", save=False)
entry.generate_slug()
assert entry.slug == u"wowee"
- def test_existing_slug_use_id(self):
- entry = self._insert_media_entry_fixture(
- u"Beware, I exist!!", this_id=9000, save=False)
- entry.generate_slug()
- assert entry.slug == u"beware-i-exist-9000"
-
- @mock.patch('uuid.uuid4', UUID_MOCK)
- def test_existing_slug_cant_use_id(self):
- # This one grabs the nine thousand slug
- self._insert_media_entry_fixture(
- slug=u"beware-i-exist-9000")
+ def test_existing_slug_use_id(self, test_app):
+ self._setup()
entry = self._insert_media_entry_fixture(
u"Beware, I exist!!", this_id=9000, save=False)
entry.generate_slug()
- assert entry.slug == u"beware-i-exist-test"
-
- @mock.patch('uuid.uuid4', UUID_MOCK)
- def test_existing_slug_cant_use_id_extra_junk(self):
- # This one grabs the nine thousand slug
- self._insert_media_entry_fixture(
- slug=u"beware-i-exist-9000")
-
- # This one grabs makes sure the annoyance doesn't stop
- self._insert_media_entry_fixture(
- slug=u"beware-i-exist-test")
-
- entry = self._insert_media_entry_fixture(
- u"Beware, I exist!!", this_id=9000, save=False)
- entry.generate_slug()
- assert entry.slug == u"beware-i-exist-testtest"
+ assert entry.slug == u"beware-i-exist-9000"
- def test_garbage_slug(self):
+ def test_existing_slug_cant_use_id(self, test_app):
+ self._setup()
+
+ # Getting tired of dealing with test_app and this mock.patch
+ # thing conflicting, getting lazy.
+ @mock.patch('uuid.uuid4', UUID_MOCK)
+ def _real_test():
+ # This one grabs the nine thousand slug
+ self._insert_media_entry_fixture(
+ slug=u"beware-i-exist-9000")
+
+ entry = self._insert_media_entry_fixture(
+ u"Beware, I exist!!", this_id=9000, save=False)
+ entry.generate_slug()
+ assert entry.slug == u"beware-i-exist-test"
+
+ _real_test()
+
+ def test_existing_slug_cant_use_id_extra_junk(self, test_app):
+ self._setup()
+
+ # Getting tired of dealing with test_app and this mock.patch
+ # thing conflicting, getting lazy.
+ @mock.patch('uuid.uuid4', UUID_MOCK)
+ def _real_test():
+ # This one grabs the nine thousand slug
+ self._insert_media_entry_fixture(
+ slug=u"beware-i-exist-9000")
+
+ # This one grabs makes sure the annoyance doesn't stop
+ self._insert_media_entry_fixture(
+ slug=u"beware-i-exist-test")
+
+ entry = self._insert_media_entry_fixture(
+ u"Beware, I exist!!", this_id=9000, save=False)
+ entry.generate_slug()
+ assert entry.slug == u"beware-i-exist-testtest"
+
+ _real_test()
+
+ def test_garbage_slug(self, test_app):
"""
Titles that sound totally like Q*Bert shouldn't have slugs at
all. We'll just reference them by id.
@@ -126,13 +144,15 @@ class TestMediaEntrySlugs(object):
| |#| |#| |#| |#|
\|/ \|/ \|/ \|/
"""
+ self._setup()
+
qbert_entry = self._insert_media_entry_fixture(
u"@!#?@!", save=False)
qbert_entry.generate_slug()
assert qbert_entry.slug is None
-def test_media_data_init():
+def test_media_data_init(test_app):
Session.rollback()
Session.remove()
media = MediaEntry()
@@ -144,4 +164,4 @@ def test_media_data_init():
for obj in Session():
obj_in_session += 1
print repr(obj)
- assert_equal(obj_in_session, 0)
+ assert obj_in_session == 0
diff --git a/mediagoblin/tests/test_notifications.py b/mediagoblin/tests/test_notifications.py
new file mode 100644
index 00000000..d52b8d5a
--- /dev/null
+++ b/mediagoblin/tests/test_notifications.py
@@ -0,0 +1,151 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import pytest
+
+import urlparse
+
+from mediagoblin.tools import template, mail
+
+from mediagoblin.db.models import Notification, CommentNotification, \
+ CommentSubscription
+from mediagoblin.db.base import Session
+
+from mediagoblin.notifications import mark_comment_notification_seen
+
+from mediagoblin.tests.tools import fixture_add_comment, \
+ fixture_media_entry, fixture_add_user, \
+ fixture_comment_subscription
+
+
+class TestNotifications:
+ @pytest.fixture(autouse=True)
+ def setup(self, test_app):
+ self.test_app = test_app
+
+ # TODO: Possibly abstract into a decorator like:
+ # @as_authenticated_user('chris')
+ self.test_user = fixture_add_user()
+
+ self.current_user = None
+
+ self.login()
+
+ def login(self, username=u'chris', password=u'toast'):
+ response = self.test_app.post(
+ '/auth/login/', {
+ 'username': username,
+ 'password': password})
+
+ response.follow()
+
+ assert urlparse.urlsplit(response.location)[2] == '/'
+ assert 'mediagoblin/root.html' in template.TEMPLATE_TEST_CONTEXT
+
+ ctx = template.TEMPLATE_TEST_CONTEXT['mediagoblin/root.html']
+
+ assert Session.merge(ctx['request'].user).username == username
+
+ self.current_user = ctx['request'].user
+
+ def logout(self):
+ self.test_app.get('/auth/logout/')
+ self.current_user = None
+
+ @pytest.mark.parametrize('wants_email', [True, False])
+ def test_comment_notification(self, wants_email):
+ '''
+ Test
+ - if a notification is created when posting a comment on
+ another users media entry.
+ - that the comment data is consistent and exists.
+
+ '''
+ user = fixture_add_user('otherperson', password='nosreprehto',
+ wants_comment_notification=wants_email)
+
+ user_id = user.id
+
+ media_entry = fixture_media_entry(uploader=user.id, state=u'processed')
+
+ media_entry_id = media_entry.id
+
+ subscription = fixture_comment_subscription(media_entry)
+
+ subscription_id = subscription.id
+
+ media_uri_id = '/u/{0}/m/{1}/'.format(user.username,
+ media_entry.id)
+ media_uri_slug = '/u/{0}/m/{1}/'.format(user.username,
+ media_entry.slug)
+
+ self.test_app.post(
+ media_uri_id + 'comment/add/',
+ {
+ 'comment_content': u'Test comment #42'
+ }
+ )
+
+ notifications = Notification.query.filter_by(
+ user_id=user.id).all()
+
+ assert len(notifications) == 1
+
+ notification = notifications[0]
+
+ assert type(notification) == CommentNotification
+ assert notification.seen == False
+ assert notification.user_id == user.id
+ assert notification.subject.get_author.id == self.test_user.id
+ assert notification.subject.content == u'Test comment #42'
+
+ if wants_email == True:
+ assert mail.EMAIL_TEST_MBOX_INBOX == [
+ {'from': 'notice@mediagoblin.example.org',
+ 'message': 'Content-Type: text/plain; \
+charset="utf-8"\nMIME-Version: 1.0\nContent-Transfer-Encoding: \
+base64\nSubject: GNU MediaGoblin - chris commented on your \
+post\nFrom: notice@mediagoblin.example.org\nTo: \
+otherperson@example.com\n\nSGkgb3RoZXJwZXJzb24sCmNocmlzIGNvbW1lbnRlZCBvbiB5b3VyIHBvc3QgKGh0dHA6Ly9sb2Nh\nbGhvc3Q6ODAvdS9vdGhlcnBlcnNvbi9tL3NvbWUtdGl0bGUvYy8xLyNjb21tZW50KSBhdCBHTlUg\nTWVkaWFHb2JsaW4KClRlc3QgY29tbWVudCAjNDIKCkdOVSBNZWRpYUdvYmxpbg==\n',
+ 'to': [u'otherperson@example.com']}]
+ else:
+ assert mail.EMAIL_TEST_MBOX_INBOX == []
+
+ # Save the ids temporarily because of DetachedInstanceError
+ notification_id = notification.id
+ comment_id = notification.subject.id
+
+ self.logout()
+ self.login('otherperson', 'nosreprehto')
+
+ self.test_app.get(media_uri_slug + '/c/{0}/'.format(comment_id))
+
+ notification = Notification.query.filter_by(id=notification_id).first()
+
+ assert notification.seen == True
+
+ self.test_app.get(media_uri_slug + '/notifications/silence/')
+
+ subscription = CommentSubscription.query.filter_by(id=subscription_id)\
+ .first()
+
+ assert subscription.notify == False
+
+ notifications = Notification.query.filter_by(
+ user_id=user_id).all()
+
+ # User should not have been notified
+ assert len(notifications) == 1
diff --git a/mediagoblin/tests/test_oauth.py b/mediagoblin/tests/test_oauth.py
index 94ba5dab..ea3bd798 100644
--- a/mediagoblin/tests/test_oauth.py
+++ b/mediagoblin/tests/test_oauth.py
@@ -17,19 +17,22 @@
import json
import logging
+import pytest
from urlparse import parse_qs, urlparse
from mediagoblin import mg_globals
from mediagoblin.tools import template, pluginapi
-from mediagoblin.tests.tools import get_app, fixture_add_user
+from mediagoblin.tests.tools import fixture_add_user
_log = logging.getLogger(__name__)
class TestOAuth(object):
- def setUp(self):
- self.app = get_app()
+ @pytest.fixture(autouse=True)
+ def setup(self, test_app):
+ self.test_app = test_app
+
self.db = mg_globals.database
self.pman = pluginapi.PluginManager()
@@ -40,14 +43,14 @@ class TestOAuth(object):
self.login()
def login(self):
- self.app.post(
- '/auth/login/', {
- 'username': self.user.username,
- 'password': self.user_password})
+ self.test_app.post(
+ '/auth/login/', {
+ 'username': self.user.username,
+ 'password': self.user_password})
def register_client(self, name, client_type, description=None,
- redirect_uri=''):
- return self.app.post(
+ redirect_uri=''):
+ return self.test_app.post(
'/oauth/client/register', {
'name': name,
'description': description,
@@ -59,8 +62,8 @@ class TestOAuth(object):
def test_1_public_client_registration_without_redirect_uri(self):
''' Test 'public' OAuth client registration without any redirect uri '''
- response = self.register_client(u'OMGOMGOMG', 'public',
- 'OMGOMG Apache License v2')
+ response = self.register_client(
+ u'OMGOMGOMG', 'public', 'OMGOMG Apache License v2')
ctx = self.get_context('oauth/client/register.html')
@@ -70,26 +73,30 @@ class TestOAuth(object):
assert response.status_int == 200
# Should display an error
- assert ctx['form'].redirect_uri.errors
+ assert len(ctx['form'].redirect_uri.errors)
# Should not pass through
assert not client
def test_2_successful_public_client_registration(self):
''' Successfully register a public client '''
- self.login()
- self.register_client(u'OMGOMG', 'public', 'OMG!',
- 'http://foo.example')
+ uri = 'http://foo.example'
+ self.register_client(
+ u'OMGOMG', 'public', 'OMG!', uri)
client = self.db.OAuthClient.query.filter(
self.db.OAuthClient.name == u'OMGOMG').first()
+ # redirect_uri should be set
+ assert client.redirect_uri == uri
+
# Client should have been registered
assert client
def test_3_successful_confidential_client_reg(self):
''' Register a confidential OAuth client '''
- response = self.register_client(u'GMOGMO', 'confidential', 'NO GMO!')
+ response = self.register_client(
+ u'GMOGMO', 'confidential', 'NO GMO!')
assert response.status_int == 302
@@ -103,15 +110,14 @@ class TestOAuth(object):
def test_4_authorize_confidential_client(self):
''' Authorize a confidential client as a logged in user '''
-
client = self.test_3_successful_confidential_client_reg()
client_identifier = client.identifier
redirect_uri = 'https://foo.example'
- response = self.app.get('/oauth/authorize', {
+ response = self.test_app.get('/oauth/authorize', {
'client_id': client.identifier,
- 'scope': 'admin',
+ 'scope': 'all',
'redirect_uri': redirect_uri})
# User-agent should NOT be redirected
@@ -122,7 +128,7 @@ class TestOAuth(object):
form = ctx['form']
# Short for client authorization post reponse
- capr = self.app.post(
+ capr = self.test_app.post(
'/oauth/client/authorize', {
'client_id': form.client_id.data,
'allow': 'Allow',
@@ -137,6 +143,7 @@ class TestOAuth(object):
return authorization_response, client_identifier
def get_code_from_redirect_uri(self, uri):
+ ''' Get the value of ?code= from an URI '''
return parse_qs(urlparse(uri).query)['code'][0]
def test_token_endpoint_successful_confidential_request(self):
@@ -148,7 +155,7 @@ class TestOAuth(object):
client = self.db.OAuthClient.query.filter(
self.db.OAuthClient.identifier == unicode(client_id)).first()
- token_res = self.app.get('/oauth/access_token?client_id={0}&\
+ token_res = self.test_app.get('/oauth/access_token?client_id={0}&\
code={1}&client_secret={2}'.format(client_id, code, client.secret))
assert token_res.status_int == 200
@@ -162,6 +169,11 @@ code={1}&client_secret={2}'.format(client_id, code, client.secret))
assert type(token_data['expires_in']) == int
assert token_data['expires_in'] > 0
+ # There should be a refresh token provided in the token data
+ assert len(token_data['refresh_token'])
+
+ return client_id, token_data
+
def test_token_endpont_missing_id_confidential_request(self):
''' Unsuccessful request against token endpoint, missing client_id '''
code_redirect, client_id = self.test_4_authorize_confidential_client()
@@ -171,7 +183,7 @@ code={1}&client_secret={2}'.format(client_id, code, client.secret))
client = self.db.OAuthClient.query.filter(
self.db.OAuthClient.identifier == unicode(client_id)).first()
- token_res = self.app.get('/oauth/access_token?\
+ token_res = self.test_app.get('/oauth/access_token?\
code={0}&client_secret={1}'.format(code, client.secret))
assert token_res.status_int == 200
@@ -181,4 +193,30 @@ code={0}&client_secret={1}'.format(code, client.secret))
assert 'error' in token_data
assert not 'access_token' in token_data
assert token_data['error'] == 'invalid_request'
- assert token_data['error_description'] == 'Missing client_id in request'
+ assert len(token_data['error_description'])
+
+ def test_refresh_token(self):
+ ''' Try to get a new access token using the refresh token '''
+ # Get an access token and a refresh token
+ client_id, token_data =\
+ self.test_token_endpoint_successful_confidential_request()
+
+ client = self.db.OAuthClient.query.filter(
+ self.db.OAuthClient.identifier == client_id).first()
+
+ token_res = self.test_app.get('/oauth/access_token',
+ {'refresh_token': token_data['refresh_token'],
+ 'client_id': client_id,
+ 'client_secret': client.secret
+ })
+
+ assert token_res.status_int == 200
+
+ new_token_data = json.loads(token_res.body)
+
+ assert not 'error' in new_token_data
+ assert 'access_token' in new_token_data
+ assert 'token_type' in new_token_data
+ assert 'expires_in' in new_token_data
+ assert type(new_token_data['expires_in']) == int
+ assert new_token_data['expires_in'] > 0
diff --git a/mediagoblin/tests/test_openid.py b/mediagoblin/tests/test_openid.py
new file mode 100644
index 00000000..23a2290e
--- /dev/null
+++ b/mediagoblin/tests/test_openid.py
@@ -0,0 +1,373 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import urlparse
+import pkg_resources
+import pytest
+import mock
+
+openid_consumer = pytest.importorskip(
+ "openid.consumer.consumer")
+
+from mediagoblin import mg_globals
+from mediagoblin.db.base import Session
+from mediagoblin.db.models import User
+from mediagoblin.plugins.openid.models import OpenIDUserURL
+from mediagoblin.tests.tools import get_app, fixture_add_user
+from mediagoblin.tools import template
+
+# App with plugin enabled
+@pytest.fixture()
+def openid_plugin_app(request):
+ return get_app(
+ request,
+ mgoblin_config=pkg_resources.resource_filename(
+ 'mediagoblin.tests.auth_configs',
+ 'openid_appconfig.ini'))
+
+
+class TestOpenIDPlugin(object):
+ def _setup(self, openid_plugin_app, value=True, edit=False, delete=False):
+ if value:
+ response = openid_consumer.SuccessResponse(mock.Mock(), mock.Mock())
+ if edit or delete:
+ response.identity_url = u'http://add.myopenid.com'
+ else:
+ response.identity_url = u'http://real.myopenid.com'
+ self._finish_verification = mock.Mock(return_value=response)
+ else:
+ self._finish_verification = mock.Mock(return_value=False)
+
+ @mock.patch('mediagoblin.plugins.openid.views._response_email', mock.Mock(return_value=None))
+ @mock.patch('mediagoblin.plugins.openid.views._response_nickname', mock.Mock(return_value=None))
+ @mock.patch('mediagoblin.plugins.openid.views._finish_verification', self._finish_verification)
+ def _setup_start(self, openid_plugin_app, edit, delete):
+ if edit:
+ self._start_verification = mock.Mock(return_value=openid_plugin_app.post(
+ '/edit/openid/finish/'))
+ elif delete:
+ self._start_verification = mock.Mock(return_value=openid_plugin_app.post(
+ '/edit/openid/delete/finish/'))
+ else:
+ self._start_verification = mock.Mock(return_value=openid_plugin_app.post(
+ '/auth/openid/login/finish/'))
+ _setup_start(self, openid_plugin_app, edit, delete)
+
+ def test_bad_login(self, openid_plugin_app):
+ """ Test that attempts to login with invalid paramaters"""
+
+ # Test GET request for auth/register page
+ res = openid_plugin_app.get('/auth/register/').follow()
+
+ # Make sure it redirected to the correct place
+ assert urlparse.urlsplit(res.location)[2] == '/auth/openid/login/'
+
+ # Test GET request for auth/login page
+ res = openid_plugin_app.get('/auth/login/')
+ res.follow()
+
+ # Correct redirect?
+ assert urlparse.urlsplit(res.location)[2] == '/auth/openid/login/'
+
+ # Test GET request for auth/openid/register page
+ res = openid_plugin_app.get('/auth/openid/register/')
+ res.follow()
+
+ # Correct redirect?
+ assert urlparse.urlsplit(res.location)[2] == '/auth/openid/login/'
+
+ # Test GET request for auth/openid/login/finish page
+ res = openid_plugin_app.get('/auth/openid/login/finish/')
+ res.follow()
+
+ # Correct redirect?
+ assert urlparse.urlsplit(res.location)[2] == '/auth/openid/login/'
+
+ # Test GET request for auth/openid/login page
+ res = openid_plugin_app.get('/auth/openid/login/')
+
+ # Correct place?
+ assert 'mediagoblin/plugins/openid/login.html' in template.TEMPLATE_TEST_CONTEXT
+
+ # Try to login with an empty form
+ template.clear_test_template_context()
+ openid_plugin_app.post(
+ '/auth/openid/login/', {})
+ context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/plugins/openid/login.html']
+ form = context['login_form']
+ assert form.openid.errors == [u'This field is required.']
+
+ # Try to login with wrong form values
+ template.clear_test_template_context()
+ openid_plugin_app.post(
+ '/auth/openid/login/', {
+ 'openid': 'not_a_url.com'})
+ context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/plugins/openid/login.html']
+ form = context['login_form']
+ assert form.openid.errors == [u'Please enter a valid url.']
+
+ # Should be no users in the db
+ assert User.query.count() == 0
+
+ # Phony OpenID URl
+ template.clear_test_template_context()
+ openid_plugin_app.post(
+ '/auth/openid/login/', {
+ 'openid': 'http://phoney.myopenid.com/'})
+ context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/plugins/openid/login.html']
+ form = context['login_form']
+ assert form.openid.errors == [u'Sorry, the OpenID server could not be found']
+
+ def test_login(self, openid_plugin_app):
+ """Tests that test login and registion with openid"""
+ # Test finish_login redirects correctly when response = False
+ self._setup(openid_plugin_app, False)
+
+ @mock.patch('mediagoblin.plugins.openid.views._finish_verification', self._finish_verification)
+ @mock.patch('mediagoblin.plugins.openid.views._start_verification', self._start_verification)
+ def _test_non_response():
+ template.clear_test_template_context()
+ res = openid_plugin_app.post(
+ '/auth/openid/login/', {
+ 'openid': 'http://phoney.myopenid.com/'})
+ res.follow()
+
+ # Correct Place?
+ assert urlparse.urlsplit(res.location)[2] == '/auth/openid/login/'
+ assert 'mediagoblin/plugins/openid/login.html' in template.TEMPLATE_TEST_CONTEXT
+ _test_non_response()
+
+ # Test login with new openid
+ # Need to clear_test_template_context before calling _setup
+ template.clear_test_template_context()
+ self._setup(openid_plugin_app)
+
+ @mock.patch('mediagoblin.plugins.openid.views._finish_verification', self._finish_verification)
+ @mock.patch('mediagoblin.plugins.openid.views._start_verification', self._start_verification)
+ def _test_new_user():
+ openid_plugin_app.post(
+ '/auth/openid/login/', {
+ 'openid': u'http://real.myopenid.com'})
+
+ # Right place?
+ assert 'mediagoblin/auth/register.html' in template.TEMPLATE_TEST_CONTEXT
+ context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/auth/register.html']
+ register_form = context['register_form']
+
+ # Register User
+ res = openid_plugin_app.post(
+ '/auth/openid/register/', {
+ 'openid': register_form.openid.data,
+ 'username': u'chris',
+ 'email': u'chris@example.com'})
+ res.follow()
+
+ # Correct place?
+ assert urlparse.urlsplit(res.location)[2] == '/u/chris/'
+ assert 'mediagoblin/user_pages/user.html' in template.TEMPLATE_TEST_CONTEXT
+
+ # No need to test if user is in logged in and verification email
+ # awaits, since openid uses the register_user function which is
+ # tested in test_auth
+
+ # Logout User
+ openid_plugin_app.get('/auth/logout')
+
+ # Get user and detach from session
+ test_user = mg_globals.database.User.query.filter_by(
+ username=u'chris').first()
+ Session.expunge(test_user)
+
+ # Log back in
+ # Could not get it to work by 'POST'ing to /auth/openid/login/
+ template.clear_test_template_context()
+ res = openid_plugin_app.post(
+ '/auth/openid/login/finish/', {
+ 'openid': u'http://real.myopenid.com'})
+ res.follow()
+
+ assert urlparse.urlsplit(res.location)[2] == '/'
+ assert 'mediagoblin/root.html' in template.TEMPLATE_TEST_CONTEXT
+
+ # Make sure user is in the session
+ context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/root.html']
+ session = context['request'].session
+ assert session['user_id'] == unicode(test_user.id)
+
+ _test_new_user()
+
+ # Test register with empty form
+ template.clear_test_template_context()
+ openid_plugin_app.post(
+ '/auth/openid/register/', {})
+ context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/auth/register.html']
+ register_form = context['register_form']
+
+ assert register_form.openid.errors == [u'This field is required.']
+ assert register_form.email.errors == [u'This field is required.']
+ assert register_form.username.errors == [u'This field is required.']
+
+ # Try to register with existing username and email
+ template.clear_test_template_context()
+ openid_plugin_app.post(
+ '/auth/openid/register/', {
+ 'openid': 'http://real.myopenid.com',
+ 'email': 'chris@example.com',
+ 'username': 'chris'})
+ context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/auth/register.html']
+ register_form = context['register_form']
+
+ assert register_form.username.errors == [u'Sorry, a user with that name already exists.']
+ assert register_form.email.errors == [u'Sorry, a user with that email address already exists.']
+ assert register_form.openid.errors == [u'Sorry, an account is already registered to that OpenID.']
+
+ def test_add_delete(self, openid_plugin_app):
+ """Test adding and deleting openids"""
+ # Add user
+ test_user = fixture_add_user(password='')
+ openid = OpenIDUserURL()
+ openid.openid_url = 'http://real.myopenid.com'
+ openid.user_id = test_user.id
+ openid.save()
+
+ # Log user in
+ template.clear_test_template_context()
+ self._setup(openid_plugin_app)
+
+ @mock.patch('mediagoblin.plugins.openid.views._finish_verification', self._finish_verification)
+ @mock.patch('mediagoblin.plugins.openid.views._start_verification', self._start_verification)
+ def _login_user():
+ openid_plugin_app.post(
+ '/auth/openid/login/finish/', {
+ 'openid': u'http://real.myopenid.com'})
+
+ _login_user()
+
+ # Try and delete only OpenID url
+ template.clear_test_template_context()
+ res = openid_plugin_app.post(
+ '/edit/openid/delete/', {
+ 'openid': 'http://real.myopenid.com'})
+ assert 'mediagoblin/plugins/openid/delete.html' in template.TEMPLATE_TEST_CONTEXT
+
+ # Add OpenID to user
+ # Empty form
+ template.clear_test_template_context()
+ res = openid_plugin_app.post(
+ '/edit/openid/', {})
+ context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/plugins/openid/add.html']
+ form = context['form']
+ assert form.openid.errors == [u'This field is required.']
+
+ # Try with a bad url
+ template.clear_test_template_context()
+ openid_plugin_app.post(
+ '/edit/openid/', {
+ 'openid': u'not_a_url.com'})
+ context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/plugins/openid/add.html']
+ form = context['form']
+ assert form.openid.errors == [u'Please enter a valid url.']
+
+ # Try with a url that's already registered
+ template.clear_test_template_context()
+ openid_plugin_app.post(
+ '/edit/openid/', {
+ 'openid': 'http://real.myopenid.com'})
+ context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/plugins/openid/add.html']
+ form = context['form']
+ assert form.openid.errors == [u'Sorry, an account is already registered to that OpenID.']
+
+ # Test adding openid to account
+ # Need to clear_test_template_context before calling _setup
+ template.clear_test_template_context()
+ self._setup(openid_plugin_app, edit=True)
+
+ # Need to remove openid_url from db because it was added at setup
+ openid = OpenIDUserURL.query.filter_by(
+ openid_url=u'http://add.myopenid.com')
+ openid.delete()
+
+ @mock.patch('mediagoblin.plugins.openid.views._finish_verification', self._finish_verification)
+ @mock.patch('mediagoblin.plugins.openid.views._start_verification', self._start_verification)
+ def _test_add():
+ # Successful add
+ template.clear_test_template_context()
+ res = openid_plugin_app.post(
+ '/edit/openid/', {
+ 'openid': u'http://add.myopenid.com'})
+ res.follow()
+
+ # Correct place?
+ assert urlparse.urlsplit(res.location)[2] == '/edit/account/'
+ assert 'mediagoblin/edit/edit_account.html' in template.TEMPLATE_TEST_CONTEXT
+
+ # OpenID Added?
+ new_openid = mg_globals.database.OpenIDUserURL.query.filter_by(
+ openid_url=u'http://add.myopenid.com').first()
+ assert new_openid
+
+ _test_add()
+
+ # Test deleting openid from account
+ # Need to clear_test_template_context before calling _setup
+ template.clear_test_template_context()
+ self._setup(openid_plugin_app, delete=True)
+
+ # Need to add OpenID back to user because it was deleted during
+ # patch
+ openid = OpenIDUserURL()
+ openid.openid_url = 'http://add.myopenid.com'
+ openid.user_id = test_user.id
+ openid.save()
+
+ @mock.patch('mediagoblin.plugins.openid.views._finish_verification', self._finish_verification)
+ @mock.patch('mediagoblin.plugins.openid.views._start_verification', self._start_verification)
+ def _test_delete(self, test_user):
+ # Delete openid from user
+ # Create another user to test deleting OpenID that doesn't belong to them
+ new_user = fixture_add_user(username='newman')
+ openid = OpenIDUserURL()
+ openid.openid_url = 'http://realfake.myopenid.com/'
+ openid.user_id = new_user.id
+ openid.save()
+
+ # Try and delete OpenID url that isn't the users
+ template.clear_test_template_context()
+ res = openid_plugin_app.post(
+ '/edit/openid/delete/', {
+ 'openid': 'http://realfake.myopenid.com/'})
+ context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/plugins/openid/delete.html']
+ form = context['form']
+ assert form.openid.errors == [u'That OpenID is not registered to this account.']
+
+ # Delete OpenID
+ # Kind of weird to POST to delete/finish
+ template.clear_test_template_context()
+ res = openid_plugin_app.post(
+ '/edit/openid/delete/finish/', {
+ 'openid': u'http://add.myopenid.com'})
+ res.follow()
+
+ # Correct place?
+ assert urlparse.urlsplit(res.location)[2] == '/edit/account/'
+ assert 'mediagoblin/edit/edit_account.html' in template.TEMPLATE_TEST_CONTEXT
+
+ # OpenID deleted?
+ new_openid = mg_globals.database.OpenIDUserURL.query.filter_by(
+ openid_url=u'http://add.myopenid.com').first()
+ assert not new_openid
+
+ _test_delete(self, test_user)
diff --git a/mediagoblin/tests/test_paste.ini b/mediagoblin/tests/test_paste.ini
index d7c18642..a9595432 100644
--- a/mediagoblin/tests/test_paste.ini
+++ b/mediagoblin/tests/test_paste.ini
@@ -6,27 +6,30 @@ use = egg:Paste#urlmap
/ = mediagoblin
/mgoblin_media/ = publicstore_serve
/test_static/ = mediagoblin_static
+/theme_static/ = theme_static
+/plugin_static/ = plugin_static
[app:mediagoblin]
use = egg:mediagoblin#app
-filter-with = beaker
-config = %(here)s/test_mgoblin_app.ini
+config = %(here)s/mediagoblin.ini
[app:publicstore_serve]
use = egg:Paste#static
-document_root = %(here)s/test_user_dev/media/public
+document_root = %(here)s/user_dev/media/public
[app:mediagoblin_static]
use = egg:Paste#static
document_root = %(here)s/mediagoblin/static/
-[filter:beaker]
-use = egg:Beaker#beaker_session
-cache_dir = %(here)s/test_user_dev/beaker
-beaker.session.key = mediagoblin
-# beaker.session.secret = somesupersecret
-beaker.session.data_dir = %(here)s/test_user_dev/beaker/sessions/data
-beaker.session.lock_dir = %(here)s/test_user_dev/beaker/sessions/lock
+[app:theme_static]
+use = egg:Paste#static
+document_root = %(here)s/user_dev/theme_static/
+cache_max_age = 86400
+
+[app:plugin_static]
+use = egg:Paste#static
+document_root = %(here)s/user_dev/plugin_static/
+cache_max_age = 86400
[celery]
CELERY_ALWAYS_EAGER = true
diff --git a/mediagoblin/tests/test_pdf.py b/mediagoblin/tests/test_pdf.py
new file mode 100644
index 00000000..b4d1940a
--- /dev/null
+++ b/mediagoblin/tests/test_pdf.py
@@ -0,0 +1,39 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2013 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import tempfile
+import shutil
+import os
+import pytest
+
+from mediagoblin.media_types.pdf.processing import (
+ pdf_info, check_prerequisites, create_pdf_thumb)
+from .resources import GOOD_PDF as GOOD
+
+
+@pytest.mark.skipif("not check_prerequisites()")
+def test_pdf():
+ good_dict = {'pdf_version_major': 1, 'pdf_title': '',
+ 'pdf_page_size_width': 612, 'pdf_author': '',
+ 'pdf_keywords': '', 'pdf_pages': 10,
+ 'pdf_producer': 'dvips + GNU Ghostscript 7.05',
+ 'pdf_version_minor': 3,
+ 'pdf_creator': 'LaTeX with hyperref package',
+ 'pdf_page_size_height': 792}
+ assert pdf_info(GOOD) == good_dict
+ temp_dir = tempfile.mkdtemp()
+ create_pdf_thumb(GOOD, os.path.join(temp_dir, 'good_256_256.png'), 256, 256)
+ shutil.rmtree(temp_dir)
diff --git a/mediagoblin/tests/test_piwigo.py b/mediagoblin/tests/test_piwigo.py
new file mode 100644
index 00000000..16ad0111
--- /dev/null
+++ b/mediagoblin/tests/test_piwigo.py
@@ -0,0 +1,71 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2013 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import pytest
+from .tools import fixture_add_user
+
+
+XML_PREFIX = "<?xml version='1.0' encoding='utf-8'?>\n"
+
+
+class Test_PWG(object):
+ @pytest.fixture(autouse=True)
+ def setup(self, test_app):
+ self.test_app = test_app
+
+ fixture_add_user()
+
+ self.username = u"chris"
+ self.password = "toast"
+
+ def do_post(self, method, params):
+ params["method"] = method
+ return self.test_app.post("/api/piwigo/ws.php", params)
+
+ def do_get(self, method, params=None):
+ if params is None:
+ params = {}
+ params["method"] = method
+ return self.test_app.get("/api/piwigo/ws.php", params)
+
+ def test_session(self):
+ resp = self.do_post("pwg.session.login",
+ {"username": u"nouser", "password": "wrong"})
+ assert resp.body == XML_PREFIX \
+ + '<rsp stat="fail"><err code="999" msg="Invalid username/password"/></rsp>'
+
+ resp = self.do_post("pwg.session.login",
+ {"username": self.username, "password": "wrong"})
+ assert resp.body == XML_PREFIX \
+ + '<rsp stat="fail"><err code="999" msg="Invalid username/password"/></rsp>'
+
+ resp = self.do_get("pwg.session.getStatus")
+ assert resp.body == XML_PREFIX \
+ + '<rsp stat="ok"><username>guest</username></rsp>'
+
+ resp = self.do_post("pwg.session.login",
+ {"username": self.username, "password": self.password})
+ assert resp.body == XML_PREFIX + '<rsp stat="ok">1</rsp>'
+
+ resp = self.do_get("pwg.session.getStatus")
+ assert resp.body == XML_PREFIX \
+ + '<rsp stat="ok"><username>chris</username></rsp>'
+
+ self.do_get("pwg.session.logout")
+
+ resp = self.do_get("pwg.session.getStatus")
+ assert resp.body == XML_PREFIX \
+ + '<rsp stat="ok"><username>guest</username></rsp>'
diff --git a/mediagoblin/tests/test_pluginapi.py b/mediagoblin/tests/test_pluginapi.py
index 315a95da..eae0ce15 100644
--- a/mediagoblin/tests/test_pluginapi.py
+++ b/mediagoblin/tests/test_pluginapi.py
@@ -14,12 +14,22 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
+import os
+import json
import sys
+
from configobj import ConfigObj
+import pytest
+import pkg_resources
+from validate import VdtTypeError
+
from mediagoblin import mg_globals
from mediagoblin.init.plugins import setup_plugins
+from mediagoblin.init.config import read_mediagoblin_config
+from mediagoblin.gmg_commands.assetlink import link_plugin_assets
from mediagoblin.tools import pluginapi
-from nose.tools import eq_
+from mediagoblin.tests.tools import get_app
+from mediagoblin.tools.common import CollectingPrinter
def with_cleanup(*modules_to_delete):
@@ -97,7 +107,7 @@ def test_no_plugins():
setup_plugins()
# Make sure we didn't load anything.
- eq_(len(pman.plugins), 0)
+ assert len(pman.plugins) == 0
@with_cleanup('mediagoblin.plugins.sampleplugin')
@@ -117,14 +127,14 @@ def test_one_plugin():
setup_plugins()
# Make sure we only found one plugin
- eq_(len(pman.plugins), 1)
+ assert len(pman.plugins) == 1
# Make sure the plugin is the one we think it is.
- eq_(pman.plugins[0], 'mediagoblin.plugins.sampleplugin')
+ assert pman.plugins[0] == 'mediagoblin.plugins.sampleplugin'
# Make sure there was one hook registered
- eq_(len(pman.hooks), 1)
+ assert len(pman.hooks) == 1
# Make sure _setup_plugin_called was called once
import mediagoblin.plugins.sampleplugin
- eq_(mediagoblin.plugins.sampleplugin._setup_plugin_called, 1)
+ assert mediagoblin.plugins.sampleplugin._setup_plugin_called == 1
@with_cleanup('mediagoblin.plugins.sampleplugin')
@@ -145,14 +155,14 @@ def test_same_plugin_twice():
setup_plugins()
# Make sure we only found one plugin
- eq_(len(pman.plugins), 1)
+ assert len(pman.plugins) == 1
# Make sure the plugin is the one we think it is.
- eq_(pman.plugins[0], 'mediagoblin.plugins.sampleplugin')
+ assert pman.plugins[0] == 'mediagoblin.plugins.sampleplugin'
# Make sure there was one hook registered
- eq_(len(pman.hooks), 1)
+ assert len(pman.hooks) == 1
# Make sure _setup_plugin_called was called once
import mediagoblin.plugins.sampleplugin
- eq_(mediagoblin.plugins.sampleplugin._setup_plugin_called, 1)
+ assert mediagoblin.plugins.sampleplugin._setup_plugin_called == 1
@with_cleanup()
@@ -172,4 +182,285 @@ def test_disabled_plugin():
setup_plugins()
# Make sure we didn't load the plugin
- eq_(len(pman.plugins), 0)
+ assert len(pman.plugins) == 0
+
+
+CONFIG_ALL_CALLABLES = [
+ ('mediagoblin', {}, []),
+ ('plugins', {}, [
+ ('mediagoblin.tests.testplugins.callables1', {}, []),
+ ('mediagoblin.tests.testplugins.callables2', {}, []),
+ ('mediagoblin.tests.testplugins.callables3', {}, []),
+ ])
+ ]
+
+
+@with_cleanup()
+def test_hook_handle():
+ """
+ Test the hook_handle method
+ """
+ cfg = build_config(CONFIG_ALL_CALLABLES)
+
+ mg_globals.app_config = cfg['mediagoblin']
+ mg_globals.global_config = cfg
+
+ setup_plugins()
+
+ # Just one hook provided
+ call_log = []
+ assert pluginapi.hook_handle(
+ "just_one", call_log) == "Called just once"
+ assert call_log == ["expect this one call"]
+
+ # Nothing provided and unhandled not okay
+ call_log = []
+ pluginapi.hook_handle(
+ "nothing_handling", call_log) == None
+ assert call_log == []
+
+ # Nothing provided and unhandled okay
+ call_log = []
+ assert pluginapi.hook_handle(
+ "nothing_handling", call_log, unhandled_okay=True) is None
+ assert call_log == []
+
+ # Multiple provided, go with the first!
+ call_log = []
+ assert pluginapi.hook_handle(
+ "multi_handle", call_log) == "the first returns"
+ assert call_log == ["Hi, I'm the first"]
+
+ # Multiple provided, one has CantHandleIt
+ call_log = []
+ assert pluginapi.hook_handle(
+ "multi_handle_with_canthandle",
+ call_log) == "the second returns"
+ assert call_log == ["Hi, I'm the second"]
+
+
+@with_cleanup()
+def test_hook_runall():
+ """
+ Test the hook_runall method
+ """
+ cfg = build_config(CONFIG_ALL_CALLABLES)
+
+ mg_globals.app_config = cfg['mediagoblin']
+ mg_globals.global_config = cfg
+
+ setup_plugins()
+
+ # Just one hook, check results
+ call_log = []
+ assert pluginapi.hook_runall(
+ "just_one", call_log) == ["Called just once"]
+ assert call_log == ["expect this one call"]
+
+ # None provided, check results
+ call_log = []
+ assert pluginapi.hook_runall(
+ "nothing_handling", call_log) == []
+ assert call_log == []
+
+ # Multiple provided, check results
+ call_log = []
+ assert pluginapi.hook_runall(
+ "multi_handle", call_log) == [
+ "the first returns",
+ "the second returns",
+ "the third returns",
+ ]
+ assert call_log == [
+ "Hi, I'm the first",
+ "Hi, I'm the second",
+ "Hi, I'm the third"]
+
+ # Multiple provided, one has CantHandleIt, check results
+ call_log = []
+ assert pluginapi.hook_runall(
+ "multi_handle_with_canthandle", call_log) == [
+ "the second returns",
+ "the third returns",
+ ]
+ assert call_log == [
+ "Hi, I'm the second",
+ "Hi, I'm the third"]
+
+
+@with_cleanup()
+def test_hook_transform():
+ """
+ Test the hook_transform method
+ """
+ cfg = build_config(CONFIG_ALL_CALLABLES)
+
+ mg_globals.app_config = cfg['mediagoblin']
+ mg_globals.global_config = cfg
+
+ setup_plugins()
+
+ assert pluginapi.hook_transform(
+ "expand_tuple", (-1, 0)) == (-1, 0, 1, 2, 3)
+
+
+def test_plugin_config():
+ """
+ Make sure plugins can set up their own config
+ """
+ config, validation_result = read_mediagoblin_config(
+ pkg_resources.resource_filename(
+ 'mediagoblin.tests', 'appconfig_plugin_specs.ini'))
+
+ pluginspec_section = config['plugins'][
+ 'mediagoblin.tests.testplugins.pluginspec']
+ assert pluginspec_section['some_string'] == 'not blork'
+ assert pluginspec_section['dont_change_me'] == 'still the default'
+
+ # Make sure validation works... this should be an error
+ assert isinstance(
+ validation_result[
+ 'plugins'][
+ 'mediagoblin.tests.testplugins.pluginspec'][
+ 'some_int'],
+ VdtTypeError)
+
+ # the callables thing shouldn't really have anything though.
+ assert len(config['plugins'][
+ 'mediagoblin.tests.testplugins.callables1']) == 0
+
+
+@pytest.fixture()
+def context_modified_app(request):
+ """
+ Get a MediaGoblin app fixture using appconfig_context_modified.ini
+ """
+ return get_app(
+ request,
+ mgoblin_config=pkg_resources.resource_filename(
+ 'mediagoblin.tests', 'appconfig_context_modified.ini'))
+
+
+def test_modify_context(context_modified_app):
+ """
+ Test that we can modify both the view/template specific and
+ global contexts for templates.
+ """
+ # Specific thing passed into a page
+ result = context_modified_app.get("/modify_context/specific/")
+ assert result.body.strip() == """Specific page!
+
+specific thing: in yer specificpage
+global thing: globally appended!
+something: orother
+doubleme: happyhappy"""
+
+ # General test, should have global context variable only
+ result = context_modified_app.get("/modify_context/")
+ assert result.body.strip() == """General page!
+
+global thing: globally appended!
+lol: cats
+doubleme: joyjoy"""
+
+
+@pytest.fixture()
+def static_plugin_app(request):
+ """
+ Get a MediaGoblin app fixture using appconfig_static_plugin.ini
+ """
+ return get_app(
+ request,
+ mgoblin_config=pkg_resources.resource_filename(
+ 'mediagoblin.tests', 'appconfig_static_plugin.ini'))
+
+
+def test_plugin_assetlink(static_plugin_app):
+ """
+ Test that the assetlink command works correctly
+ """
+ linked_assets_dir = mg_globals.app_config['plugin_linked_assets_dir']
+ plugin_link_dir = os.path.join(
+ linked_assets_dir.rstrip(os.path.sep),
+ 'staticstuff')
+
+ plugin_statics = pluginapi.hook_runall("static_setup")
+ assert len(plugin_statics) == 1
+ plugin_static = plugin_statics[0]
+
+ def run_assetlink():
+ printer = CollectingPrinter()
+
+ link_plugin_assets(
+ plugin_static, linked_assets_dir, printer)
+
+ return printer
+
+ # it shouldn't exist yet
+ assert not os.path.lexists(plugin_link_dir)
+
+ # link dir doesn't exist, link it
+ result = run_assetlink().collection[0]
+ assert result == \
+ 'Linked asset directory for plugin "staticstuff":\n %s\nto:\n %s\n' % (
+ plugin_static.file_path.rstrip(os.path.sep),
+ plugin_link_dir)
+ assert os.path.lexists(plugin_link_dir)
+ assert os.path.islink(plugin_link_dir)
+ assert os.path.realpath(plugin_link_dir) == plugin_static.file_path
+
+ # link dir exists, leave it alone
+ # (and it should exist still since we just ran it..)
+ result = run_assetlink().collection[0]
+ assert result == 'Skipping "staticstuff"; already set up.\n'
+ assert os.path.lexists(plugin_link_dir)
+ assert os.path.islink(plugin_link_dir)
+ assert os.path.realpath(plugin_link_dir) == plugin_static.file_path
+
+ # link dir exists, is a symlink to somewhere else (re-link)
+ junk_file_path = os.path.join(
+ linked_assets_dir.rstrip(os.path.sep),
+ 'junk.txt')
+ with file(junk_file_path, 'w') as junk_file:
+ junk_file.write('barf')
+
+ os.unlink(plugin_link_dir)
+ os.symlink(junk_file_path, plugin_link_dir)
+
+ result = run_assetlink().combined_string
+ assert result == """Old link found for "staticstuff"; removing.
+Linked asset directory for plugin "staticstuff":
+ %s
+to:
+ %s
+""" % (plugin_static.file_path.rstrip(os.path.sep), plugin_link_dir)
+ assert os.path.lexists(plugin_link_dir)
+ assert os.path.islink(plugin_link_dir)
+ assert os.path.realpath(plugin_link_dir) == plugin_static.file_path
+
+ # link dir exists, but is a non-symlink
+ os.unlink(plugin_link_dir)
+ with file(plugin_link_dir, 'w') as clobber_file:
+ clobber_file.write('clobbered!')
+
+ result = run_assetlink().collection[0]
+ assert result == 'Could not link "staticstuff": %s exists and is not a symlink\n' % (
+ plugin_link_dir)
+
+ with file(plugin_link_dir, 'r') as clobber_file:
+ assert clobber_file.read() == 'clobbered!'
+
+
+def test_plugin_staticdirect(static_plugin_app):
+ """
+ Test that the staticdirect utilities pull up the right things
+ """
+ result = json.loads(
+ static_plugin_app.get('/staticstuff/').body)
+
+ assert len(result) == 2
+
+ assert result['mgoblin_bunny_pic'] == '/test_static/images/bunny_pic.png'
+ assert result['plugin_bunny_css'] == \
+ '/plugin_static/staticstuff/css/bunnify.css'
+
diff --git a/mediagoblin/tests/test_processing.py b/mediagoblin/tests/test_processing.py
index fe8489aa..591add96 100644
--- a/mediagoblin/tests/test_processing.py
+++ b/mediagoblin/tests/test_processing.py
@@ -1,7 +1,5 @@
#!/usr/bin/env python
-from nose.tools import assert_equal
-
from mediagoblin import processing
class TestProcessing(object):
@@ -10,7 +8,7 @@ class TestProcessing(object):
result = builder.fill(format)
if output is None:
return result
- assert_equal(output, result)
+ assert output == result
def test_easy_filename_fill(self):
self.run_fill('/home/user/foo.TXT', '{basename}bar{ext}', 'foobar.txt')
diff --git a/mediagoblin/tests/test_session.py b/mediagoblin/tests/test_session.py
new file mode 100644
index 00000000..78d790eb
--- /dev/null
+++ b/mediagoblin/tests/test_session.py
@@ -0,0 +1,30 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+from mediagoblin.tools import session
+
+def test_session():
+ sess = session.Session()
+ assert not sess
+ assert not sess.is_updated()
+ sess['user_id'] = 27
+ assert sess
+ assert not sess.is_updated()
+ sess.save()
+ assert sess.is_updated()
+ sess.delete()
+ assert not sess
+ assert sess.is_updated()
diff --git a/mediagoblin/tests/test_storage.py b/mediagoblin/tests/test_storage.py
index 61326ae9..f6f1d18f 100644
--- a/mediagoblin/tests/test_storage.py
+++ b/mediagoblin/tests/test_storage.py
@@ -18,7 +18,7 @@
import os
import tempfile
-from nose.tools import assert_raises, assert_equal, assert_true
+import pytest
from werkzeug.utils import secure_filename
from mediagoblin import storage
@@ -41,10 +41,8 @@ def test_clean_listy_filepath():
assert storage.clean_listy_filepath(
['../../../etc/', 'passwd']) == expected
- assert_raises(
- storage.InvalidFilepath,
- storage.clean_listy_filepath,
- ['../../', 'linooks.jpg'])
+ with pytest.raises(storage.InvalidFilepath):
+ storage.clean_listy_filepath(['../../', 'linooks.jpg'])
class FakeStorageSystem():
@@ -78,10 +76,10 @@ def test_storage_system_from_config():
'garbage_arg': 'garbage_arg',
'storage_class':
'mediagoblin.tests.test_storage:FakeStorageSystem'})
- assert_equal(this_storage.foobie, 'eiboof')
- assert_equal(this_storage.blech, 'hcelb')
- assert_equal(unicode(this_storage.__class__),
- u'mediagoblin.tests.test_storage.FakeStorageSystem')
+ assert this_storage.foobie == 'eiboof'
+ assert this_storage.blech == 'hcelb'
+ assert unicode(this_storage.__class__) == \
+ u'mediagoblin.tests.test_storage.FakeStorageSystem'
##########################
@@ -89,7 +87,7 @@ def test_storage_system_from_config():
##########################
def get_tmp_filestorage(mount_url=None, fake_remote=False):
- tmpdir = tempfile.mkdtemp()
+ tmpdir = tempfile.mkdtemp(prefix="test_gmg_storage")
if fake_remote:
this_storage = FakeRemoteStorage(tmpdir, mount_url)
else:
@@ -97,6 +95,14 @@ def get_tmp_filestorage(mount_url=None, fake_remote=False):
return tmpdir, this_storage
+def cleanup_storage(this_storage, tmpdir, *paths):
+ for p in paths:
+ while p:
+ assert this_storage.delete_dir(p) == True
+ p.pop(-1)
+ os.rmdir(tmpdir)
+
+
def test_basic_storage__resolve_filepath():
tmpdir, this_storage = get_tmp_filestorage()
@@ -108,11 +114,13 @@ def test_basic_storage__resolve_filepath():
assert result == os.path.join(
tmpdir, 'etc/passwd')
- assert_raises(
+ pytest.raises(
storage.InvalidFilepath,
this_storage._resolve_filepath,
['../../', 'etc', 'passwd'])
+ cleanup_storage(this_storage, tmpdir)
+
def test_basic_storage_file_exists():
tmpdir, this_storage = get_tmp_filestorage()
@@ -126,6 +134,9 @@ def test_basic_storage_file_exists():
assert not this_storage.file_exists(['dir1', 'dir2', 'thisfile.lol'])
assert not this_storage.file_exists(['dnedir1', 'dnedir2', 'somefile.lol'])
+ this_storage.delete_file(['dir1', 'dir2', 'filename.txt'])
+ cleanup_storage(this_storage, tmpdir, ['dir1', 'dir2'])
+
def test_basic_storage_get_unique_filepath():
tmpdir, this_storage = get_tmp_filestorage()
@@ -146,6 +157,9 @@ def test_basic_storage_get_unique_filepath():
assert len(new_filename) > len('filename.txt')
assert new_filename == secure_filename(new_filename)
+ os.remove(filename)
+ cleanup_storage(this_storage, tmpdir, ['dir1', 'dir2'])
+
def test_basic_storage_get_file():
tmpdir, this_storage = get_tmp_filestorage()
@@ -182,6 +196,11 @@ def test_basic_storage_get_file():
with this_storage.get_file(['testydir', 'testyfile.txt']) as testyfile:
assert testyfile.read() == 'testy file! so testy.'
+ this_storage.delete_file(filepath)
+ this_storage.delete_file(new_filepath)
+ this_storage.delete_file(['testydir', 'testyfile.txt'])
+ cleanup_storage(this_storage, tmpdir, ['dir1', 'dir2'], ['testydir'])
+
def test_basic_storage_delete_file():
tmpdir, this_storage = get_tmp_filestorage()
@@ -196,19 +215,24 @@ def test_basic_storage_delete_file():
assert os.path.exists(
os.path.join(tmpdir, 'dir1/dir2/ourfile.txt'))
+ assert this_storage.delete_dir(['dir1', 'dir2']) == False
this_storage.delete_file(filepath)
+ assert this_storage.delete_dir(['dir1', 'dir2']) == True
assert not os.path.exists(
os.path.join(tmpdir, 'dir1/dir2/ourfile.txt'))
+ cleanup_storage(this_storage, tmpdir, ['dir1'])
+
def test_basic_storage_url_for_file():
# Not supplying a base_url should actually just bork.
tmpdir, this_storage = get_tmp_filestorage()
- assert_raises(
+ pytest.raises(
storage.NoWebServing,
this_storage.file_url,
['dir1', 'dir2', 'filename.txt'])
+ cleanup_storage(this_storage, tmpdir)
# base_url without domain
tmpdir, this_storage = get_tmp_filestorage('/media/')
@@ -216,6 +240,7 @@ def test_basic_storage_url_for_file():
['dir1', 'dir2', 'filename.txt'])
expected = '/media/dir1/dir2/filename.txt'
assert result == expected
+ cleanup_storage(this_storage, tmpdir)
# base_url with domain
tmpdir, this_storage = get_tmp_filestorage(
@@ -224,6 +249,7 @@ def test_basic_storage_url_for_file():
['dir1', 'dir2', 'filename.txt'])
expected = 'http://media.example.org/ourmedia/dir1/dir2/filename.txt'
assert result == expected
+ cleanup_storage(this_storage, tmpdir)
def test_basic_storage_get_local_path():
@@ -237,10 +263,13 @@ def test_basic_storage_get_local_path():
assert result == expected
+ cleanup_storage(this_storage, tmpdir)
+
def test_basic_storage_is_local():
tmpdir, this_storage = get_tmp_filestorage()
assert this_storage.local_storage is True
+ cleanup_storage(this_storage, tmpdir)
def test_basic_storage_copy_locally():
@@ -255,9 +284,14 @@ def test_basic_storage_copy_locally():
new_file_dest = os.path.join(dest_tmpdir, 'file2.txt')
this_storage.copy_locally(filepath, new_file_dest)
+ this_storage.delete_file(filepath)
assert file(new_file_dest).read() == 'Testing this file'
+ os.remove(new_file_dest)
+ os.rmdir(dest_tmpdir)
+ cleanup_storage(this_storage, tmpdir, ['dir1', 'dir2'])
+
def _test_copy_local_to_storage_works(tmpdir, this_storage):
local_filename = tempfile.mktemp()
@@ -267,10 +301,15 @@ def _test_copy_local_to_storage_works(tmpdir, this_storage):
this_storage.copy_local_to_storage(
local_filename, ['dir1', 'dir2', 'copiedto.txt'])
+ os.remove(local_filename)
+
assert file(
os.path.join(tmpdir, 'dir1/dir2/copiedto.txt'),
'r').read() == 'haha'
+ this_storage.delete_file(['dir1', 'dir2', 'copiedto.txt'])
+ cleanup_storage(this_storage, tmpdir, ['dir1', 'dir2'])
+
def test_basic_storage_copy_local_to_storage():
tmpdir, this_storage = get_tmp_filestorage()
diff --git a/mediagoblin/tests/test_submission.py b/mediagoblin/tests/test_submission.py
index fc3d8c83..ac941063 100644
--- a/mediagoblin/tests/test_submission.py
+++ b/mediagoblin/tests/test_submission.py
@@ -20,28 +20,17 @@ sys.setdefaultencoding('utf-8')
import urlparse
import os
+import pytest
-from nose.tools import assert_equal, assert_true
-from pkg_resources import resource_filename
-
-from mediagoblin.tests.tools import get_app, \
- fixture_add_user
+from mediagoblin.tests.tools import fixture_add_user
from mediagoblin import mg_globals
from mediagoblin.db.models import MediaEntry
from mediagoblin.tools import template
-from mediagoblin.media_types.image import MEDIA_MANAGER as img_MEDIA_MANAGER
-
-def resource(filename):
- return resource_filename('mediagoblin.tests', 'test_submission/' + filename)
-
+from mediagoblin.media_types.image import ImageMediaManager
+from mediagoblin.media_types.pdf.processing import check_prerequisites as pdf_check_prerequisites
-GOOD_JPG = resource('good.jpg')
-GOOD_PNG = resource('good.png')
-EVIL_FILE = resource('evil')
-EVIL_JPG = resource('evil.jpg')
-EVIL_PNG = resource('evil.png')
-BIG_BLUE = resource('bigblue.png')
-from .test_exif import GPS_JPG
+from .resources import GOOD_JPG, GOOD_PNG, EVIL_FILE, EVIL_JPG, EVIL_PNG, \
+ BIG_BLUE, GOOD_PDF, GPS_JPG
GOOD_TAG_STRING = u'yin,yang'
BAD_TAG_STRING = unicode('rage,' + 'f' * 26 + 'u' * 26)
@@ -51,8 +40,9 @@ REQUEST_CONTEXT = ['mediagoblin/user_pages/user.html', 'request']
class TestSubmission:
- def setUp(self):
- self.test_app = get_app(dump_old_app=False)
+ @pytest.fixture(autouse=True)
+ def setup(self, test_app):
+ self.test_app = test_app
# TODO: Possibly abstract into a decorator like:
# @as_authenticated_user('chris')
@@ -87,28 +77,28 @@ class TestSubmission:
return {'upload_files': [('file', filename)]}
def check_comments(self, request, media_id, count):
- comments = request.db.MediaComment.find({'media_entry': media_id})
- assert_equal(count, len(list(comments)))
+ comments = request.db.MediaComment.query.filter_by(media_entry=media_id)
+ assert count == len(list(comments))
def test_missing_fields(self):
# Test blank form
# ---------------
response, form = self.do_post({}, *FORM_CONTEXT)
- assert_equal(form.file.errors, [u'You must provide a file.'])
+ assert form.file.errors == [u'You must provide a file.']
# Test blank file
# ---------------
response, form = self.do_post({'title': u'test title'}, *FORM_CONTEXT)
- assert_equal(form.file.errors, [u'You must provide a file.'])
+ assert form.file.errors == [u'You must provide a file.']
def check_url(self, response, path):
- assert_equal(urlparse.urlsplit(response.location)[2], path)
+ assert urlparse.urlsplit(response.location)[2] == path
def check_normal_upload(self, title, filename):
response, context = self.do_post({'title': title}, do_follow=True,
**self.upload_data(filename))
self.check_url(response, '/u/{0}/'.format(self.test_user.username))
- assert_true('mediagoblin/user_pages/user.html' in context)
+ assert 'mediagoblin/user_pages/user.html' in context
# Make sure the media view is at least reachable, logged in...
url = '/u/{0}/m/{1}/'.format(self.test_user.username,
title.lower().replace(' ', '-'))
@@ -123,10 +113,18 @@ class TestSubmission:
def test_normal_png(self):
self.check_normal_upload(u'Normal upload 2', GOOD_PNG)
+ @pytest.mark.skipif("not pdf_check_prerequisites()")
+ def test_normal_pdf(self):
+ response, context = self.do_post({'title': u'Normal upload 3 (pdf)'},
+ do_follow=True,
+ **self.upload_data(GOOD_PDF))
+ self.check_url(response, '/u/{0}/'.format(self.test_user.username))
+ assert 'mediagoblin/user_pages/user.html' in context
+
def check_media(self, request, find_data, count=None):
- media = MediaEntry.find(find_data)
+ media = MediaEntry.query.filter_by(**find_data)
if count is not None:
- assert_equal(media.count(), count)
+ assert media.count() == count
if count == 0:
return
return media[0]
@@ -151,10 +149,10 @@ class TestSubmission:
'tags': BAD_TAG_STRING},
*FORM_CONTEXT,
**self.upload_data(GOOD_JPG))
- assert_equal(form.tags.errors, [
+ assert form.tags.errors == [
u'Tags must be shorter than 50 characters. ' \
'Tags that are too long: ' \
- 'ffffffffffffffffffffffffffuuuuuuuuuuuuuuuuuuuuuuuuuu'])
+ 'ffffffffffffffffffffffffffuuuuuuuuuuuuuuuuuuuuuuuuuu']
def test_delete(self):
response, request = self.do_post({'title': u'Balanced Goblin'},
@@ -173,7 +171,7 @@ class TestSubmission:
'slug': u"Balanced=Goblin",
'tags': u''})
media = self.check_media(request, {'title': u'Balanced Goblin'}, 1)
- assert_equal(media.slug, u"balanced-goblin")
+ assert media.slug == u"balanced-goblin"
# Add a comment, so we can test for its deletion later.
self.check_comments(request, media_id, 0)
@@ -207,7 +205,7 @@ class TestSubmission:
response, form = self.do_post({'title': u'Malicious Upload 1'},
*FORM_CONTEXT,
**self.upload_data(EVIL_FILE))
- assert_equal(len(form.file.errors), 1)
+ assert len(form.file.errors) == 1
assert 'Sorry, I don\'t support that file type :(' == \
str(form.file.errors[0])
@@ -220,8 +218,9 @@ class TestSubmission:
**self.upload_data(GOOD_JPG))
media = self.check_media(request, {'title': u'Balanced Goblin'}, 1)
- assert_equal(media.media_type, u'mediagoblin.media_types.image')
- assert_equal(media.media_manager, img_MEDIA_MANAGER)
+ assert media.media_type == u'mediagoblin.media_types.image'
+ assert isinstance(media.media_manager, ImageMediaManager)
+ assert media.media_manager.entry == media
def test_sniffing(self):
@@ -241,8 +240,8 @@ class TestSubmission:
request = context['request']
- media = request.db.MediaEntry.find_one({
- u'title': u'UNIQUE_TITLE_PLS_DONT_CREATE_OTHER_MEDIA_WITH_THIS_TITLE'})
+ media = request.db.MediaEntry.query.filter_by(
+ title=u'UNIQUE_TITLE_PLS_DONT_CREATE_OTHER_MEDIA_WITH_THIS_TITLE').first()
assert media.media_type == 'mediagoblin.media_types.image'
@@ -253,9 +252,9 @@ class TestSubmission:
response, context = self.do_post({'title': title}, do_follow=True,
**self.upload_data(filename))
self.check_url(response, '/u/{0}/'.format(self.test_user.username))
- entry = mg_globals.database.MediaEntry.find_one({'title': title})
- assert_equal(entry.state, 'failed')
- assert_equal(entry.fail_error, u'mediagoblin.processing:BadMediaFail')
+ entry = mg_globals.database.MediaEntry.query.filter_by(title=title).first()
+ assert entry.state == 'failed'
+ assert entry.fail_error == u'mediagoblin.processing:BadMediaFail'
def test_evil_jpg(self):
# Test non-supported file with .jpg extension
@@ -270,9 +269,12 @@ class TestSubmission:
def test_media_data(self):
self.check_normal_upload(u"With GPS data", GPS_JPG)
media = self.check_media(None, {"title": u"With GPS data"}, 1)
- assert_equal(media.media_data.gps_latitude, 59.336666666666666)
+ assert media.media_data.gps_latitude == 59.336666666666666
def test_processing(self):
+ public_store_dir = mg_globals.global_config[
+ 'storage:publicstore']['base_dir']
+
data = {'title': u'Big Blue'}
response, request = self.do_post(data, *REQUEST_CONTEXT, do_follow=True,
**self.upload_data(BIG_BLUE))
@@ -282,12 +284,11 @@ class TestSubmission:
('medium', 'bigblue.medium.png'),
('thumb', 'bigblue.thumbnail.png')):
# Does the processed image have a good filename?
- filename = resource_filename(
- 'mediagoblin.tests',
- os.path.join('test_user_dev/media/public',
- *media.media_files.get(key, [])))
- assert_true(filename.endswith('_' + basename))
+ filename = os.path.join(
+ public_store_dir,
+ *media.media_files[key])
+ assert filename.endswith('_' + basename)
# Is it smaller than the last processed image we looked at?
size = os.stat(filename).st_size
- assert_true(last_size > size)
+ assert last_size > size
last_size = size
diff --git a/mediagoblin/tests/test_submission/good.pdf b/mediagoblin/tests/test_submission/good.pdf
new file mode 100644
index 00000000..ab5db006
--- /dev/null
+++ b/mediagoblin/tests/test_submission/good.pdf
Binary files differ
diff --git a/mediagoblin/tests/test_tags.py b/mediagoblin/tests/test_tags.py
index ccb93085..e25cc283 100644
--- a/mediagoblin/tests/test_tags.py
+++ b/mediagoblin/tests/test_tags.py
@@ -14,17 +14,15 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-from mediagoblin.tests.tools import get_app
from mediagoblin.tools import text
-def test_list_of_dicts_conversion():
+def test_list_of_dicts_conversion(test_app):
"""
When the user adds tags to a media entry, the string from the form is
converted into a list of tags, where each tag is stored in the database
as a dict. Each tag dict should contain the tag's name and slug. Another
function performs the reverse operation when populating a form to edit tags.
"""
- test_app = get_app(dump_old_app=False)
# Leading, trailing, and internal whitespace should be removed and slugified
assert text.convert_to_tag_list_of_dicts('sleep , 6 AM, chainsaw! ') == [
{'name': u'sleep', 'slug': u'sleep'},
diff --git a/mediagoblin/tests/test_timesince.py b/mediagoblin/tests/test_timesince.py
new file mode 100644
index 00000000..6579eb09
--- /dev/null
+++ b/mediagoblin/tests/test_timesince.py
@@ -0,0 +1,57 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+from datetime import datetime, timedelta
+
+from mediagoblin.tools.timesince import is_aware, timesince
+
+
+def test_timesince():
+ test_time = datetime.now()
+
+ # it should ignore second and microseconds
+ assert timesince(test_time, test_time + timedelta(microseconds=1)) == "0 minutes"
+ assert timesince(test_time, test_time + timedelta(seconds=1)) == "0 minutes"
+
+ # test minutes, hours, days, weeks, months and years (singular and plural)
+ assert timesince(test_time, test_time + timedelta(minutes=1)) == "1 minute"
+ assert timesince(test_time, test_time + timedelta(minutes=2)) == "2 minutes"
+
+ assert timesince(test_time, test_time + timedelta(hours=1)) == "1 hour"
+ assert timesince(test_time, test_time + timedelta(hours=2)) == "2 hours"
+
+ assert timesince(test_time, test_time + timedelta(days=1)) == "1 day"
+ assert timesince(test_time, test_time + timedelta(days=2)) == "2 days"
+
+ assert timesince(test_time, test_time + timedelta(days=7)) == "1 week"
+ assert timesince(test_time, test_time + timedelta(days=14)) == "2 weeks"
+
+ assert timesince(test_time, test_time + timedelta(days=30)) == "1 month"
+ assert timesince(test_time, test_time + timedelta(days=60)) == "2 months"
+
+ assert timesince(test_time, test_time + timedelta(days=365)) == "1 year"
+ assert timesince(test_time, test_time + timedelta(days=730)) == "2 years"
+
+ # okay now we want to test combinations
+ # e.g. 1 hour, 5 days
+ assert timesince(test_time, test_time + timedelta(days=5, hours=1)) == "5 days, 1 hour"
+
+ assert timesince(test_time, test_time + timedelta(days=15)) == "2 weeks, 1 day"
+
+ assert timesince(test_time, test_time + timedelta(days=97)) == "3 months, 1 week"
+
+ assert timesince(test_time, test_time + timedelta(days=2250)) == "6 years, 2 months"
+
diff --git a/mediagoblin/tests/test_util.py b/mediagoblin/tests/test_util.py
index e4c04b7a..bc14f528 100644
--- a/mediagoblin/tests/test_util.py
+++ b/mediagoblin/tests/test_util.py
@@ -104,6 +104,28 @@ def test_locale_to_lower_lower():
assert translate.locale_to_lower_lower('en_us') == 'en-us'
+def test_gettext_lazy_proxy():
+ from mediagoblin.tools.translate import lazy_pass_to_ugettext as _
+ from mediagoblin.tools.translate import pass_to_ugettext, set_thread_locale
+ proxy = _(u"Password")
+ orig = u"Password"
+
+ set_thread_locale("es")
+ p1 = unicode(proxy)
+ p1_should = pass_to_ugettext(orig)
+ assert p1_should != orig, "Test useless, string not translated"
+ assert p1 == p1_should
+
+ set_thread_locale("sv")
+ p2 = unicode(proxy)
+ p2_should = pass_to_ugettext(orig)
+ assert p2_should != orig, "Test broken, string not translated"
+ assert p2 == p2_should
+
+ assert p1_should != p2_should, "Test broken, same translated string"
+ assert p1 != p2
+
+
def test_html_cleaner():
# Remove images
result = text.clean_html(
diff --git a/mediagoblin/tests/test_workbench.py b/mediagoblin/tests/test_workbench.py
index 636c8689..6695618b 100644
--- a/mediagoblin/tests/test_workbench.py
+++ b/mediagoblin/tests/test_workbench.py
@@ -21,13 +21,18 @@ import tempfile
from mediagoblin.tools import workbench
from mediagoblin.mg_globals import setup_globals
from mediagoblin.decorators import get_workbench
-from mediagoblin.tests.test_storage import get_tmp_filestorage
+from mediagoblin.tests.test_storage import get_tmp_filestorage, cleanup_storage
class TestWorkbench(object):
- def setUp(self):
+ def setup(self):
+ self.workbench_base = tempfile.mkdtemp(prefix='gmg_workbench_testing')
self.workbench_manager = workbench.WorkbenchManager(
- os.path.join(tempfile.gettempdir(), u'mgoblin_workbench_testing'))
+ self.workbench_base)
+
+ def teardown(self):
+ # If the workbench is empty, this should work.
+ os.rmdir(self.workbench_base)
def test_create_workbench(self):
workbench = self.workbench_manager.create()
@@ -70,6 +75,8 @@ class TestWorkbench(object):
filename = this_workbench.localized_file(this_storage, filepath)
assert filename == os.path.join(
tmpdir, 'dir1/dir2/ourfile.txt')
+ this_storage.delete_file(filepath)
+ cleanup_storage(this_storage, tmpdir, ['dir1', 'dir2'])
# with a fake remote file storage
tmpdir, this_storage = get_tmp_filestorage(fake_remote=True)
@@ -95,6 +102,10 @@ class TestWorkbench(object):
assert filename == os.path.join(
this_workbench.dir, 'thisfile.text')
+ this_storage.delete_file(filepath)
+ cleanup_storage(this_storage, tmpdir, ['dir1', 'dir2'])
+ this_workbench.destroy()
+
def test_workbench_decorator(self):
"""Test @get_workbench decorator and automatic cleanup"""
# The decorator needs mg_globals.workbench_manager
diff --git a/mediagoblin/tests/testplugins/__init__.py b/mediagoblin/tests/testplugins/__init__.py
new file mode 100644
index 00000000..621845ba
--- /dev/null
+++ b/mediagoblin/tests/testplugins/__init__.py
@@ -0,0 +1,15 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
diff --git a/mediagoblin/tests/test_tests.py b/mediagoblin/tests/testplugins/callables1/__init__.py
index d539f1e0..fe801a01 100644
--- a/mediagoblin/tests/test_tests.py
+++ b/mediagoblin/tests/testplugins/callables1/__init__.py
@@ -14,23 +14,30 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-from mediagoblin import mg_globals
-from mediagoblin.tests.tools import get_app, fixture_add_user
-from mediagoblin.db.models import User
+def setup_plugin():
+ pass
-def test_get_app_wipes_db():
- """
- Make sure we get a fresh database on every wipe :)
- """
- get_app(dump_old_app=True)
- assert User.query.count() == 0
+def just_one(call_log):
+ call_log.append("expect this one call")
+ return "Called just once"
- fixture_add_user()
- assert User.query.count() == 1
- get_app(dump_old_app=False)
- assert User.query.count() == 1
+def multi_handle(call_log):
+ call_log.append("Hi, I'm the first")
+ return "the first returns"
- get_app(dump_old_app=True)
- assert User.query.count() == 0
+def multi_handle_with_canthandle(call_log):
+ return None
+
+
+def expand_tuple(this_tuple):
+ return this_tuple + (1,)
+
+hooks = {
+ 'setup': setup_plugin,
+ 'just_one': just_one,
+ 'multi_handle': multi_handle,
+ 'multi_handle_with_canthandle': multi_handle_with_canthandle,
+ 'expand_tuple': expand_tuple,
+ }
diff --git a/mediagoblin/tests/testplugins/callables2/__init__.py b/mediagoblin/tests/testplugins/callables2/__init__.py
new file mode 100644
index 00000000..9d5cf950
--- /dev/null
+++ b/mediagoblin/tests/testplugins/callables2/__init__.py
@@ -0,0 +1,41 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+def setup_plugin():
+ pass
+
+
+def just_one(call_log):
+ assert "SHOULD NOT HAPPEN"
+
+def multi_handle(call_log):
+ call_log.append("Hi, I'm the second")
+ return "the second returns"
+
+def multi_handle_with_canthandle(call_log):
+ call_log.append("Hi, I'm the second")
+ return "the second returns"
+
+def expand_tuple(this_tuple):
+ return this_tuple + (2,)
+
+hooks = {
+ 'setup': setup_plugin,
+ 'just_one': just_one,
+ 'multi_handle': multi_handle,
+ 'multi_handle_with_canthandle': multi_handle_with_canthandle,
+ 'expand_tuple': expand_tuple,
+ }
diff --git a/mediagoblin/tests/testplugins/callables3/__init__.py b/mediagoblin/tests/testplugins/callables3/__init__.py
new file mode 100644
index 00000000..04efc8fc
--- /dev/null
+++ b/mediagoblin/tests/testplugins/callables3/__init__.py
@@ -0,0 +1,41 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+def setup_plugin():
+ pass
+
+
+def just_one(call_log):
+ assert "SHOULD NOT HAPPEN"
+
+def multi_handle(call_log):
+ call_log.append("Hi, I'm the third")
+ return "the third returns"
+
+def multi_handle_with_canthandle(call_log):
+ call_log.append("Hi, I'm the third")
+ return "the third returns"
+
+def expand_tuple(this_tuple):
+ return this_tuple + (3,)
+
+hooks = {
+ 'setup': setup_plugin,
+ 'just_one': just_one,
+ 'multi_handle': multi_handle,
+ 'multi_handle_with_canthandle': multi_handle_with_canthandle,
+ 'expand_tuple': expand_tuple,
+ }
diff --git a/mediagoblin/tests/testplugins/modify_context/__init__.py b/mediagoblin/tests/testplugins/modify_context/__init__.py
new file mode 100644
index 00000000..164e66c1
--- /dev/null
+++ b/mediagoblin/tests/testplugins/modify_context/__init__.py
@@ -0,0 +1,55 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+from mediagoblin.tools import pluginapi
+import pkg_resources
+
+
+def append_to_specific_context(context):
+ context['specific_page_append'] = 'in yer specificpage'
+ return context
+
+def append_to_global_context(context):
+ context['global_append'] = 'globally appended!'
+ return context
+
+def double_doubleme(context):
+ if 'doubleme' in context:
+ context['doubleme'] = context['doubleme'] * 2
+ return context
+
+
+def setup_plugin():
+ routes = [
+ ('modify_context.specific_page',
+ '/modify_context/specific/',
+ 'mediagoblin.tests.testplugins.modify_context.views:specific'),
+ ('modify_context.general_page',
+ '/modify_context/',
+ 'mediagoblin.tests.testplugins.modify_context.views:general')]
+
+ pluginapi.register_routes(routes)
+ pluginapi.register_template_path(
+ pkg_resources.resource_filename(
+ 'mediagoblin.tests.testplugins.modify_context', 'templates'))
+
+
+hooks = {
+ 'setup': setup_plugin,
+ ('modify_context.specific_page',
+ 'contextplugin/specific.html'): append_to_specific_context,
+ 'template_global_context': append_to_global_context,
+ 'template_context_prerender': double_doubleme}
diff --git a/mediagoblin/tests/testplugins/modify_context/templates/contextplugin/general.html b/mediagoblin/tests/testplugins/modify_context/templates/contextplugin/general.html
new file mode 100644
index 00000000..9cf96d3e
--- /dev/null
+++ b/mediagoblin/tests/testplugins/modify_context/templates/contextplugin/general.html
@@ -0,0 +1,5 @@
+General page!
+
+global thing: {{ global_append }}
+lol: {{ lol }}
+doubleme: {{ doubleme }}
diff --git a/mediagoblin/tests/testplugins/modify_context/templates/contextplugin/specific.html b/mediagoblin/tests/testplugins/modify_context/templates/contextplugin/specific.html
new file mode 100644
index 00000000..5b1b4c4a
--- /dev/null
+++ b/mediagoblin/tests/testplugins/modify_context/templates/contextplugin/specific.html
@@ -0,0 +1,6 @@
+Specific page!
+
+specific thing: {{ specific_page_append }}
+global thing: {{ global_append }}
+something: {{ something }}
+doubleme: {{ doubleme }}
diff --git a/mediagoblin/init/celery/from_tests.py b/mediagoblin/tests/testplugins/modify_context/views.py
index 3149e1ba..701ec6f9 100644
--- a/mediagoblin/init/celery/from_tests.py
+++ b/mediagoblin/tests/testplugins/modify_context/views.py
@@ -14,20 +14,20 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-import os
+from mediagoblin.tools.response import render_to_response
-from mediagoblin.tests.tools import TEST_APP_CONFIG
-from mediagoblin.init.celery.from_celery import setup_self
+def specific(request):
+ return render_to_response(
+ request,
+ 'contextplugin/specific.html',
+ {"something": "orother",
+ "doubleme": "happy"})
-OUR_MODULENAME = __name__
-CELERY_SETUP = False
-
-if os.environ.get('CELERY_CONFIG_MODULE') == OUR_MODULENAME:
- if CELERY_SETUP:
- pass
- else:
- setup_self(check_environ_for_conf=False, module_name=OUR_MODULENAME,
- default_conf_file=TEST_APP_CONFIG)
- CELERY_SETUP = True
+def general(request):
+ return render_to_response(
+ request,
+ 'contextplugin/general.html',
+ {"lol": "cats",
+ "doubleme": "joy"})
diff --git a/mediagoblin/tests/testplugins/pluginspec/__init__.py b/mediagoblin/tests/testplugins/pluginspec/__init__.py
new file mode 100644
index 00000000..76ca2b1f
--- /dev/null
+++ b/mediagoblin/tests/testplugins/pluginspec/__init__.py
@@ -0,0 +1,22 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+def setup_plugin():
+ pass
+
+hooks = {
+ 'setup': setup_plugin,
+}
diff --git a/mediagoblin/tests/testplugins/pluginspec/config_spec.ini b/mediagoblin/tests/testplugins/pluginspec/config_spec.ini
new file mode 100644
index 00000000..5c9c3bd7
--- /dev/null
+++ b/mediagoblin/tests/testplugins/pluginspec/config_spec.ini
@@ -0,0 +1,4 @@
+[plugin_spec]
+some_string = string(default="blork")
+some_int = integer(default=50)
+dont_change_me = string(default="still the default") \ No newline at end of file
diff --git a/mediagoblin/tests/testplugins/staticstuff/__init__.py b/mediagoblin/tests/testplugins/staticstuff/__init__.py
new file mode 100644
index 00000000..a2591646
--- /dev/null
+++ b/mediagoblin/tests/testplugins/staticstuff/__init__.py
@@ -0,0 +1,36 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+from mediagoblin.tools.staticdirect import PluginStatic
+from mediagoblin.tools import pluginapi
+from pkg_resources import resource_filename
+
+def setup_plugin():
+ routes = [
+ ('staticstuff.static_demo',
+ '/staticstuff/',
+ 'mediagoblin.tests.testplugins.staticstuff.views:static_demo')]
+
+ pluginapi.register_routes(routes)
+
+
+hooks = {
+ 'setup': setup_plugin,
+ 'static_setup': lambda: PluginStatic(
+ 'staticstuff',
+ resource_filename(
+ 'mediagoblin.tests.testplugins.staticstuff',
+ 'static'))}
diff --git a/mediagoblin/tests/testplugins/staticstuff/static/css/bunnify.css b/mediagoblin/tests/testplugins/staticstuff/static/css/bunnify.css
new file mode 100644
index 00000000..1294ab8a
--- /dev/null
+++ b/mediagoblin/tests/testplugins/staticstuff/static/css/bunnify.css
@@ -0,0 +1,4 @@
+body {
+ background-color: #5edcf1;
+ color: #eb8add;
+} \ No newline at end of file
diff --git a/mediagoblin/tests/testplugins/staticstuff/views.py b/mediagoblin/tests/testplugins/staticstuff/views.py
new file mode 100644
index 00000000..34a5e8cb
--- /dev/null
+++ b/mediagoblin/tests/testplugins/staticstuff/views.py
@@ -0,0 +1,28 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import json
+
+from werkzeug import Response
+
+
+def static_demo(request):
+ return Response(json.dumps({
+ # this does not exist, but we'll pretend it does ;)
+ 'mgoblin_bunny_pic': request.staticdirect(
+ 'images/bunny_pic.png'),
+ 'plugin_bunny_css': request.staticdirect(
+ 'css/bunnify.css', 'staticstuff')}))
diff --git a/mediagoblin/tests/tools.py b/mediagoblin/tests/tools.py
index cc4a7add..98361adc 100644
--- a/mediagoblin/tests/tools.py
+++ b/mediagoblin/tests/tools.py
@@ -19,21 +19,19 @@ import os
import pkg_resources
import shutil
-from functools import wraps
from paste.deploy import loadapp
from webtest import TestApp
from mediagoblin import mg_globals
-from mediagoblin.db.models import User, MediaEntry, Collection
+from mediagoblin.db.models import User, MediaEntry, Collection, MediaComment, \
+ CommentSubscription, CommentNotification
from mediagoblin.tools import testing
from mediagoblin.init.config import read_mediagoblin_config
-from mediagoblin.db.open import setup_connection_and_db_from_config
from mediagoblin.db.base import Session
from mediagoblin.meddleware import BaseMeddleware
-from mediagoblin.auth.lib import bcrypt_gen_password_hash
+from mediagoblin.auth import gen_password_hash
from mediagoblin.gmg_commands.dbupdate import run_dbupdate
-from mediagoblin.init.celery import setup_celery_app
MEDIAGOBLIN_TEST_DB_NAME = u'__mediagoblin_tests__'
@@ -41,21 +39,9 @@ TEST_SERVER_CONFIG = pkg_resources.resource_filename(
'mediagoblin.tests', 'test_paste.ini')
TEST_APP_CONFIG = pkg_resources.resource_filename(
'mediagoblin.tests', 'test_mgoblin_app.ini')
-TEST_USER_DEV = pkg_resources.resource_filename(
- 'mediagoblin.tests', 'test_user_dev')
-MGOBLIN_APP = None
-USER_DEV_DIRECTORIES_TO_SETUP = [
- 'media/public', 'media/queue',
- 'beaker/sessions/data', 'beaker/sessions/lock']
-BAD_CELERY_MESSAGE = """\
-Sorry, you *absolutely* must run nosetests with the
-mediagoblin.init.celery.from_tests module. Like so:
-$ CELERY_CONFIG_MODULE=mediagoblin.init.celery.from_tests ./bin/nosetests"""
-
-
-class BadCeleryEnviron(Exception): pass
+USER_DEV_DIRECTORIES_TO_SETUP = ['media/public', 'media/queue']
class TestingMeddleware(BaseMeddleware):
@@ -97,41 +83,40 @@ class TestingMeddleware(BaseMeddleware):
return
-def suicide_if_bad_celery_environ():
- if not os.environ.get('CELERY_CONFIG_MODULE') == \
- 'mediagoblin.init.celery.from_tests':
- raise BadCeleryEnviron(BAD_CELERY_MESSAGE)
-
+def get_app(request, paste_config=None, mgoblin_config=None):
+ """Create a MediaGoblin app for testing.
-def get_app(dump_old_app=True):
- suicide_if_bad_celery_environ()
-
- # Make sure we've turned on testing
- testing._activate_testing()
-
- # Leave this imported as it sets up celery.
- from mediagoblin.init.celery import from_tests
+ Args:
+ - request: Not an http request, but a pytest fixture request. We
+ use this to make temporary directories that pytest
+ automatically cleans up as needed.
+ - paste_config: particular paste config used by this application.
+ - mgoblin_config: particular mediagoblin config used by this
+ application.
+ """
+ paste_config = paste_config or TEST_SERVER_CONFIG
+ mgoblin_config = mgoblin_config or TEST_APP_CONFIG
- global MGOBLIN_APP
+ # This is the directory we're copying the paste/mgoblin config stuff into
+ run_dir = request.config._tmpdirhandler.mktemp(
+ 'mgoblin_app', numbered=True)
+ user_dev_dir = run_dir.mkdir('user_dev').strpath
- # Just return the old app if that exists and it's okay to set up
- # and return
- if MGOBLIN_APP and not dump_old_app:
- return MGOBLIN_APP
+ new_paste_config = run_dir.join('paste.ini').strpath
+ new_mgoblin_config = run_dir.join('mediagoblin.ini').strpath
+ shutil.copyfile(paste_config, new_paste_config)
+ shutil.copyfile(mgoblin_config, new_mgoblin_config)
Session.rollback()
Session.remove()
- # Remove and reinstall user_dev directories
- if os.path.exists(TEST_USER_DEV):
- shutil.rmtree(TEST_USER_DEV)
-
+ # install user_dev directories
for directory in USER_DEV_DIRECTORIES_TO_SETUP:
- full_dir = os.path.join(TEST_USER_DEV, directory)
+ full_dir = os.path.join(user_dev_dir, directory)
os.makedirs(full_dir)
# Get app config
- global_config, validation_result = read_mediagoblin_config(TEST_APP_CONFIG)
+ global_config, validation_result = read_mediagoblin_config(new_mgoblin_config)
app_config = global_config['mediagoblin']
# Run database setup/migrations
@@ -139,10 +124,7 @@ def get_app(dump_old_app=True):
# setup app and return
test_app = loadapp(
- 'config:' + TEST_SERVER_CONFIG)
-
- # Re-setup celery
- setup_celery_app(app_config, global_config)
+ 'config:' + new_paste_config)
# Insert the TestingMeddleware, which can do some
# sanity checks on every request/response.
@@ -151,26 +133,10 @@ def get_app(dump_old_app=True):
mg_globals.app.meddleware.insert(0, TestingMeddleware(mg_globals.app))
app = TestApp(test_app)
- MGOBLIN_APP = app
return app
-def setup_fresh_app(func):
- """
- Decorator to setup a fresh test application for this function.
-
- Cleans out test buckets and passes in a new, fresh test_app.
- """
- @wraps(func)
- def wrapper(*args, **kwargs):
- test_app = get_app()
- testing.clear_test_buckets()
- return func(test_app, *args, **kwargs)
-
- return wrapper
-
-
def install_fixtures_simple(db, fixtures):
"""
Very simply install fixtures in the database
@@ -198,13 +164,13 @@ def assert_db_meets_expected(db, expected):
for collection_name, collection_data in expected.iteritems():
collection = db[collection_name]
for expected_document in collection_data:
- document = collection.find_one({'id': expected_document['id']})
+ document = collection.query.filter_by(id=expected_document['id']).first()
assert document is not None # make sure it exists
assert document == expected_document # make sure it matches
def fixture_add_user(username=u'chris', password=u'toast',
- active_user=True):
+ active_user=True, wants_comment_notification=True):
# Reuse existing user or create a new one
test_user = User.query.filter_by(username=username).first()
if test_user is None:
@@ -212,11 +178,13 @@ def fixture_add_user(username=u'chris', password=u'toast',
test_user.username = username
test_user.email = username + u'@example.com'
if password is not None:
- test_user.pw_hash = bcrypt_gen_password_hash(password)
+ test_user.pw_hash = gen_password_hash(password)
if active_user:
test_user.email_verified = True
test_user.status = u'active'
+ test_user.wants_comment_notification = wants_comment_notification
+
test_user.save()
# Reload
@@ -228,19 +196,79 @@ def fixture_add_user(username=u'chris', password=u'toast',
return test_user
+def fixture_comment_subscription(entry, notify=True, send_email=None):
+ if send_email is None:
+ uploader = User.query.filter_by(id=entry.uploader).first()
+ send_email = uploader.wants_comment_notification
+
+ cs = CommentSubscription(
+ media_entry_id=entry.id,
+ user_id=entry.uploader,
+ notify=notify,
+ send_email=send_email)
+
+ cs.save()
+
+ cs = CommentSubscription.query.filter_by(id=cs.id).first()
+
+ Session.expunge(cs)
+
+ return cs
+
+
+def fixture_add_comment_notification(entry_id, subject_id, user_id,
+ seen=False):
+ cn = CommentNotification(user_id=user_id,
+ seen=seen,
+ subject_id=subject_id)
+ cn.save()
+
+ cn = CommentNotification.query.filter_by(id=cn.id).first()
+
+ Session.expunge(cn)
+
+ return cn
+
+
def fixture_media_entry(title=u"Some title", slug=None,
- uploader=None, save=True, gen_slug=True):
+ uploader=None, save=True, gen_slug=True,
+ state=u'unprocessed', fake_upload=True,
+ expunge=True):
+ """
+ Add a media entry for testing purposes.
+
+ Caution: if you're adding multiple entries with fake_upload=True,
+ make sure you save between them... otherwise you'll hit an
+ IntegrityError from multiple newly-added-MediaEntries adding
+ FileKeynames at once. :)
+ """
+ if uploader is None:
+ uploader = fixture_add_user().id
+
entry = MediaEntry()
entry.title = title
entry.slug = slug
- entry.uploader = uploader or fixture_add_user().id
+ entry.uploader = uploader
entry.media_type = u'image'
-
+ entry.state = state
+
+ if fake_upload:
+ entry.media_files = {'thumb': ['a', 'b', 'c.jpg'],
+ 'medium': ['d', 'e', 'f.png'],
+ 'original': ['g', 'h', 'i.png']}
+ entry.media_type = u'mediagoblin.media_types.image'
+
if gen_slug:
entry.generate_slug()
+
if save:
entry.save()
+ if expunge:
+ entry = MediaEntry.query.filter_by(id=entry.id).first()
+
+ Session.expunge(entry)
+
return entry
@@ -263,3 +291,26 @@ def fixture_add_collection(name=u"My first Collection", user=None):
Session.expunge(coll)
return coll
+
+def fixture_add_comment(author=None, media_entry=None, comment=None):
+ if author is None:
+ author = fixture_add_user().id
+
+ if media_entry is None:
+ media_entry = fixture_media_entry().id
+
+ if comment is None:
+ comment = \
+ 'Auto-generated test comment by user #{0} on media #{0}'.format(
+ author, media_entry)
+
+ comment = MediaComment(author=author,
+ media_entry=media_entry,
+ content=comment)
+
+ comment.save()
+
+ Session.expunge(comment)
+
+ return comment
+
diff --git a/mediagoblin/tools/crypto.py b/mediagoblin/tools/crypto.py
new file mode 100644
index 00000000..1379d21b
--- /dev/null
+++ b/mediagoblin/tools/crypto.py
@@ -0,0 +1,113 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2013 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import errno
+import itsdangerous
+import logging
+import os.path
+import random
+import tempfile
+from mediagoblin import mg_globals
+
+_log = logging.getLogger(__name__)
+
+
+# Use the system (hardware-based) random number generator if it exists.
+# -- this optimization is lifted from Django
+try:
+ getrandbits = random.SystemRandom().getrandbits
+except AttributeError:
+ getrandbits = random.getrandbits
+
+
+__itsda_secret = None
+
+
+def load_key(filename):
+ global __itsda_secret
+ key_file = open(filename)
+ try:
+ __itsda_secret = key_file.read()
+ finally:
+ key_file.close()
+
+
+def create_key(key_dir, key_filepath):
+ global __itsda_secret
+ old_umask = os.umask(077)
+ key_file = None
+ try:
+ if not os.path.isdir(key_dir):
+ os.makedirs(key_dir)
+ _log.info("Created %s", key_dir)
+ key = str(getrandbits(192))
+ key_file = tempfile.NamedTemporaryFile(dir=key_dir, suffix='.bin',
+ delete=False)
+ key_file.write(key)
+ key_file.flush()
+ os.rename(key_file.name, key_filepath)
+ key_file.close()
+ finally:
+ os.umask(old_umask)
+ if (key_file is not None) and (not key_file.closed):
+ key_file.close()
+ os.unlink(key_file.name)
+ __itsda_secret = key
+ _log.info("Saved new key for It's Dangerous")
+
+
+def setup_crypto():
+ global __itsda_secret
+ key_dir = mg_globals.app_config["crypto_path"]
+ key_filepath = os.path.join(key_dir, 'itsdangeroussecret.bin')
+ try:
+ load_key(key_filepath)
+ except IOError, error:
+ if error.errno != errno.ENOENT:
+ raise
+ create_key(key_dir, key_filepath)
+
+
+def get_timed_signer_url(namespace):
+ """
+ This gives a basic signing/verifying object.
+
+ The namespace makes sure signed tokens can't be used in
+ a different area. Like using a forgot-password-token as
+ a session cookie.
+
+ Basic usage:
+
+ .. code-block:: python
+
+ _signer = None
+ TOKEN_VALID_DAYS = 10
+ def setup():
+ global _signer
+ _signer = get_timed_signer_url("session cookie")
+ def create_token(obj):
+ return _signer.dumps(obj)
+ def parse_token(token):
+ # This might raise an exception in case
+ # of an invalid token, or an expired token.
+ return _signer.loads(token, max_age=TOKEN_VALID_DAYS*24*3600)
+
+ For more details see
+ http://pythonhosted.org/itsdangerous/#itsdangerous.URLSafeTimedSerializer
+ """
+ assert __itsda_secret is not None
+ return itsdangerous.URLSafeTimedSerializer(__itsda_secret,
+ salt=namespace)
diff --git a/mediagoblin/tools/exif.py b/mediagoblin/tools/exif.py
index d0f9d0a6..6b3639e8 100644
--- a/mediagoblin/tools/exif.py
+++ b/mediagoblin/tools/exif.py
@@ -134,7 +134,7 @@ def _ratio_to_list(ratio):
def get_useful(tags):
- return dict((key, tag) for (key, tag) in tags.iteritems() if key in USEFUL_TAGS)
+ return dict((key, tag) for (key, tag) in tags.iteritems())
def get_gps_data(tags):
diff --git a/mediagoblin/tools/mail.py b/mediagoblin/tools/mail.py
index 4fa02ce5..0fabc5a9 100644
--- a/mediagoblin/tools/mail.py
+++ b/mediagoblin/tools/mail.py
@@ -16,7 +16,7 @@
import smtplib
from email.MIMEText import MIMEText
-from mediagoblin import mg_globals
+from mediagoblin import mg_globals, messages
from mediagoblin.tools import common
### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -90,7 +90,12 @@ def send_email(from_addr, to_addrs, subject, message_body):
if common.TESTS_ENABLED or mg_globals.app_config['email_debug_mode']:
mhost = FakeMhost()
elif not mg_globals.app_config['email_debug_mode']:
- mhost = smtplib.SMTP(
+ if mg_globals.app_config['email_smtp_use_ssl']:
+ smtp_init = smtplib.SMTP_SSL
+ else:
+ smtp_init = smtplib.SMTP
+
+ mhost = smtp_init(
mg_globals.app_config['email_smtp_host'],
mg_globals.app_config['email_smtp_port'])
@@ -135,3 +140,16 @@ def normalize_email(email):
return None
email = "@".join((em_user, em_dom.lower()))
return email
+
+
+def email_debug_message(request):
+ """
+ If the server is running in email debug mode (which is
+ the current default), give a debug message to the user
+ so that they have an idea where to find their email.
+ """
+ if mg_globals.app_config['email_debug_mode']:
+ # DEBUG message, no need to translate
+ messages.add_message(request, messages.DEBUG,
+ u"This instance is running in email debug mode. "
+ u"The email will be on the console of the server process.")
diff --git a/mediagoblin/tools/pluginapi.py b/mediagoblin/tools/pluginapi.py
index 784bede9..3f98aa8a 100644
--- a/mediagoblin/tools/pluginapi.py
+++ b/mediagoblin/tools/pluginapi.py
@@ -272,3 +272,96 @@ def get_hook_templates(hook_name):
A list of strings representing template paths.
"""
return PluginManager().get_template_hooks(hook_name)
+
+
+#############################
+## Hooks: The Next Generation
+#############################
+
+
+def hook_handle(hook_name, *args, **kwargs):
+ """
+ Run through hooks attempting to find one that handle this hook.
+
+ All callables called with the same arguments until one handles
+ things and returns a non-None value.
+
+ (If you are writing a handler and you don't have a particularly
+ useful value to return even though you've handled this, returning
+ True is a good solution.)
+
+ Note that there is a special keyword argument:
+ if "default_handler" is passed in as a keyword argument, this will
+ be used if no handler is found.
+
+ Some examples of using this:
+ - You need an interface implemented, but only one fit for it
+ - You need to *do* something, but only one thing needs to do it.
+ """
+ default_handler = kwargs.pop('default_handler', None)
+
+ callables = PluginManager().get_hook_callables(hook_name)
+
+ result = None
+
+ for callable in callables:
+ result = callable(*args, **kwargs)
+
+ if result is not None:
+ break
+
+ if result is None and default_handler is not None:
+ result = default_handler(*args, **kwargs)
+
+ return result
+
+
+def hook_runall(hook_name, *args, **kwargs):
+ """
+ Run through all callable hooks and pass in arguments.
+
+ All non-None results are accrued in a list and returned from this.
+ (Other "false-like" values like False and friends are still
+ accrued, however.)
+
+ Some examples of using this:
+ - You have an interface call where actually multiple things can
+ and should implement it
+ - You need to get a list of things from various plugins that
+ handle them and do something with them
+ - You need to *do* something, and actually multiple plugins need
+ to do it separately
+ """
+ callables = PluginManager().get_hook_callables(hook_name)
+
+ results = []
+
+ for callable in callables:
+ result = callable(*args, **kwargs)
+
+ if result is not None:
+ results.append(result)
+
+ return results
+
+
+def hook_transform(hook_name, arg):
+ """
+ Run through a bunch of hook callables and transform some input.
+
+ Note that unlike the other hook tools, this one only takes ONE
+ argument. This argument is passed to each function, which in turn
+ returns something that becomes the input of the next callable.
+
+ Some examples of using this:
+ - You have an object, say a form, but you want plugins to each be
+ able to modify it.
+ """
+ result = arg
+
+ callables = PluginManager().get_hook_callables(hook_name)
+
+ for callable in callables:
+ result = callable(result)
+
+ return result
diff --git a/mediagoblin/tools/processing.py b/mediagoblin/tools/processing.py
index cff4cb9d..2abe6452 100644
--- a/mediagoblin/tools/processing.py
+++ b/mediagoblin/tools/processing.py
@@ -21,8 +21,6 @@ import traceback
from urllib2 import urlopen, Request, HTTPError
from urllib import urlencode
-from mediagoblin.tools.common import TESTS_ENABLED
-
_log = logging.getLogger(__name__)
TESTS_CALLBACKS = {}
diff --git a/mediagoblin/tools/request.py b/mediagoblin/tools/request.py
index bc67b96f..ee342eae 100644
--- a/mediagoblin/tools/request.py
+++ b/mediagoblin/tools/request.py
@@ -35,4 +35,4 @@ def setup_user_in_request(request):
# Something's wrong... this user doesn't exist? Invalidate
# this session.
_log.warn("Killing session for user id %r", request.session['user_id'])
- request.session.invalidate()
+ request.session.delete()
diff --git a/mediagoblin/tools/response.py b/mediagoblin/tools/response.py
index 80df1f5a..0be1f835 100644
--- a/mediagoblin/tools/response.py
+++ b/mediagoblin/tools/response.py
@@ -77,7 +77,7 @@ def render_http_exception(request, exc, description):
elif stock_desc and exc.code == 404:
return render_404(request)
- return render_error(request, title=exc.args[0],
+ return render_error(request, title='{0} {1}'.format(exc.code, exc.name),
err_msg=description,
status=exc.code)
@@ -99,3 +99,10 @@ def redirect(request, *args, **kwargs):
if querystring:
location += querystring
return werkzeug.utils.redirect(location)
+
+
+def redirect_obj(request, obj):
+ """Redirect to the page for the given object.
+
+ Requires obj to have a .url_for_self method."""
+ return redirect(request, location=obj.url_for_self(request.urlgen))
diff --git a/mediagoblin/tools/routing.py b/mediagoblin/tools/routing.py
index 791cd1e6..a15795fe 100644
--- a/mediagoblin/tools/routing.py
+++ b/mediagoblin/tools/routing.py
@@ -16,6 +16,7 @@
import logging
+import six
from werkzeug.routing import Map, Rule
from mediagoblin.tools.common import import_component
@@ -43,7 +44,7 @@ def endpoint_to_controller(rule):
_log.debug('endpoint: {0} view_func: {1}'.format(endpoint, view_func))
# import the endpoint, or if it's already a callable, call that
- if isinstance(view_func, basestring):
+ if isinstance(view_func, six.string_types):
view_func = import_component(view_func)
rule.gmg_controller = view_func
diff --git a/mediagoblin/tools/session.py b/mediagoblin/tools/session.py
new file mode 100644
index 00000000..a57f69cc
--- /dev/null
+++ b/mediagoblin/tools/session.py
@@ -0,0 +1,75 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2013 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import itsdangerous
+import logging
+
+from mediagoblin.tools import crypto
+
+_log = logging.getLogger(__name__)
+
+MAX_AGE = 30 * 24 * 60 * 60
+
+class Session(dict):
+ def __init__(self, *args, **kwargs):
+ self.send_new_cookie = False
+ dict.__init__(self, *args, **kwargs)
+
+ def save(self):
+ self.send_new_cookie = True
+
+ def is_updated(self):
+ return self.send_new_cookie
+
+ def delete(self):
+ self.clear()
+ self.save()
+
+
+class SessionManager(object):
+ def __init__(self, cookie_name='MGSession', namespace=None):
+ if namespace is None:
+ namespace = cookie_name
+ self.signer = crypto.get_timed_signer_url(namespace)
+ self.cookie_name = cookie_name
+
+ def load_session_from_cookie(self, request):
+ cookie = request.cookies.get(self.cookie_name)
+ if not cookie:
+ return Session()
+ ### FIXME: Future cookie-blacklisting code
+ # m = BadCookie.query.filter_by(cookie = cookie)
+ # if m:
+ # _log.warn("Bad cookie received: %s", m.reason)
+ # raise BadRequest()
+ try:
+ return Session(self.signer.loads(cookie))
+ except itsdangerous.BadData:
+ return Session()
+
+ def save_session_to_cookie(self, session, request, response):
+ if not session.is_updated():
+ return
+ elif not session:
+ response.delete_cookie(self.cookie_name)
+ else:
+ if session.get('stay_logged_in', False):
+ max_age = MAX_AGE
+ else:
+ max_age = None
+
+ response.set_cookie(self.cookie_name, self.signer.dumps(session),
+ max_age=max_age, httponly=True)
diff --git a/mediagoblin/tools/staticdirect.py b/mediagoblin/tools/staticdirect.py
index 31abc566..ef8b20d0 100644
--- a/mediagoblin/tools/staticdirect.py
+++ b/mediagoblin/tools/staticdirect.py
@@ -61,3 +61,41 @@ class StaticDirect(object):
def get(self, filepath, domain=None):
return '%s/%s' % (
self.domains[domain], filepath.lstrip('/'))
+
+
+class PluginStatic(object):
+ """Pass this into the ``'static_setup'`` hook to register your
+ plugin's static directory.
+
+ This has two mandatory attributes that you must pass in on class
+ init:
+ - name: this name will be both used for lookup in "urlgen" for
+ your plugin's static resources and for the subdirectory that
+ it'll be "mounted" to for serving via your web browser. It
+ *MUST* be unique. If writing a plugin bundled with MediaGoblin
+ please use the pattern 'coreplugin__foo' where 'foo' is your
+ plugin name. All external plugins should use their modulename,
+ so if your plugin is 'mg_bettertags' you should also call this
+ name 'mg_bettertags'.
+ - file_path: the directory your plugin's static resources are
+ located in. It's recommended that you use
+ pkg_resources.resource_filename() for this.
+
+ An example of using this::
+
+ from pkg_resources import resource_filename
+ from mediagoblin.tools.staticdirect import PluginStatic
+
+ hooks = {
+ 'static_setup': lambda: PluginStatic(
+ 'mg_bettertags',
+ resource_filename('mg_bettertags', 'static'))
+ }
+
+ """
+ def __init__(self, name, file_path):
+ self.name = name
+ self.file_path = file_path
+
+ def __call__(self):
+ return self
diff --git a/mediagoblin/tools/template.py b/mediagoblin/tools/template.py
index 74d811eb..615ce129 100644
--- a/mediagoblin/tools/template.py
+++ b/mediagoblin/tools/template.py
@@ -14,7 +14,6 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-from math import ceil
import jinja2
from jinja2.ext import Extension
@@ -27,11 +26,13 @@ from mediagoblin import mg_globals
from mediagoblin import messages
from mediagoblin import _version
from mediagoblin.tools import common
-from mediagoblin.tools.translate import get_gettext_translation
-from mediagoblin.tools.pluginapi import get_hook_templates
+from mediagoblin.tools.translate import set_thread_locale
+from mediagoblin.tools.pluginapi import get_hook_templates, hook_transform
+from mediagoblin.tools.timesince import timesince
from mediagoblin.meddleware.csrf import render_csrf_form_token
+
SETUP_JINJA_ENVS = {}
@@ -42,7 +43,7 @@ def get_jinja_env(template_loader, locale):
(In the future we may have another system for providing theming;
for now this is good enough.)
"""
- mg_globals.thread_scope.translations = get_gettext_translation(locale)
+ set_thread_locale(locale)
# If we have a jinja environment set up with this locale, just
# return that one.
@@ -70,12 +71,19 @@ def get_jinja_env(template_loader, locale):
template_env.globals['app_config'] = mg_globals.app_config
template_env.globals['global_config'] = mg_globals.global_config
template_env.globals['version'] = _version.__version__
+ template_env.globals['auth'] = mg_globals.app.auth
template_env.filters['urlencode'] = url_quote_plus
+ # add human readable fuzzy date time
+ template_env.globals['timesince'] = timesince
+
# allow for hooking up plugin templates
template_env.globals['get_hook_templates'] = get_hook_templates
+ template_env.globals = hook_transform(
+ 'template_global_context', template_env.globals)
+
if exists(locale):
SETUP_JINJA_ENVS[locale] = template_env
@@ -99,6 +107,20 @@ def render_template(request, template_path, context):
rendered_csrf_token = render_csrf_form_token(request)
if rendered_csrf_token is not None:
context['csrf_token'] = render_csrf_form_token(request)
+
+ # allow plugins to do things to the context
+ if request.controller_name:
+ context = hook_transform(
+ (request.controller_name, template_path),
+ context)
+
+ # More evil: allow plugins to possibly do something to the context
+ # in every request ever with access to the request and other
+ # variables. Note: this is slower than using
+ # template_global_context
+ context = hook_transform(
+ 'template_context_prerender', context)
+
rendered = template.render(context)
if common.TESTS_ENABLED:
diff --git a/mediagoblin/tools/timesince.py b/mediagoblin/tools/timesince.py
new file mode 100644
index 00000000..b761c1be
--- /dev/null
+++ b/mediagoblin/tools/timesince.py
@@ -0,0 +1,95 @@
+# Copyright (c) Django Software Foundation and individual contributors.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification,
+# are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# 3. Neither the name of Django nor the names of its contributors may be used
+# to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+from __future__ import unicode_literals
+
+import datetime
+import pytz
+
+from mediagoblin.tools.translate import pass_to_ugettext, lazy_pass_to_ungettext as _
+
+"""UTC time zone as a tzinfo instance."""
+utc = pytz.utc if pytz else UTC()
+
+def is_aware(value):
+ """
+ Determines if a given datetime.datetime is aware.
+
+ The logic is described in Python's docs:
+ http://docs.python.org/library/datetime.html#datetime.tzinfo
+ """
+ return value.tzinfo is not None and value.tzinfo.utcoffset(value) is not None
+
+def timesince(d, now=None, reversed=False):
+ """
+ Takes two datetime objects and returns the time between d and now
+ as a nicely formatted string, e.g. "10 minutes". If d occurs after now,
+ then "0 minutes" is returned.
+
+ Units used are years, months, weeks, days, hours, and minutes.
+ Seconds and microseconds are ignored. Up to two adjacent units will be
+ displayed. For example, "2 weeks, 3 days" and "1 year, 3 months" are
+ possible outputs, but "2 weeks, 3 hours" and "1 year, 5 days" are not.
+
+ Adapted from http://blog.natbat.co.uk/archive/2003/Jun/14/time_since
+ """
+ chunks = (
+ (60 * 60 * 24 * 365, lambda n: _('year', 'years', n)),
+ (60 * 60 * 24 * 30, lambda n: _('month', 'months', n)),
+ (60 * 60 * 24 * 7, lambda n : _('week', 'weeks', n)),
+ (60 * 60 * 24, lambda n : _('day', 'days', n)),
+ (60 * 60, lambda n: _('hour', 'hours', n)),
+ (60, lambda n: _('minute', 'minutes', n))
+ )
+ # Convert datetime.date to datetime.datetime for comparison.
+ if not isinstance(d, datetime.datetime):
+ d = datetime.datetime(d.year, d.month, d.day)
+ if now and not isinstance(now, datetime.datetime):
+ now = datetime.datetime(now.year, now.month, now.day)
+
+ if not now:
+ now = datetime.datetime.now(utc if is_aware(d) else None)
+
+ delta = (d - now) if reversed else (now - d)
+ # ignore microseconds
+ since = delta.days * 24 * 60 * 60 + delta.seconds
+ if since <= 0:
+ # d is in the future compared to now, stop processing.
+ return '0 ' + pass_to_ugettext('minutes')
+ for i, (seconds, name) in enumerate(chunks):
+ count = since // seconds
+ if count != 0:
+ break
+ s = pass_to_ugettext('%(number)d %(type)s') % {'number': count, 'type': name(count)}
+ if i + 1 < len(chunks):
+ # Now get the second item
+ seconds2, name2 = chunks[i + 1]
+ count2 = (since - (seconds * count)) // seconds2
+ if count2 != 0:
+ s += pass_to_ugettext(', %(number)d %(type)s') % {'number': count2, 'type': name2(count2)}
+ return s
diff --git a/mediagoblin/tools/translate.py b/mediagoblin/tools/translate.py
index 1d37c4de..b20e57d1 100644
--- a/mediagoblin/tools/translate.py
+++ b/mediagoblin/tools/translate.py
@@ -42,6 +42,22 @@ def set_available_locales():
AVAILABLE_LOCALES = locales
+class ReallyLazyProxy(LazyProxy):
+ """
+ Like LazyProxy, except that it doesn't cache the value ;)
+ """
+ @property
+ def value(self):
+ return self._func(*self._args, **self._kwargs)
+
+ def __repr__(self):
+ return "<%s for %s(%r, %r)>" % (
+ self.__class__.__name__,
+ self._func,
+ self._args,
+ self._kwargs)
+
+
def locale_to_lower_upper(locale):
"""
Take a locale, regardless of style, and format it like "en_US"
@@ -112,6 +128,11 @@ def get_gettext_translation(locale):
return this_gettext
+def set_thread_locale(locale):
+ """Set the current translation for this thread"""
+ mg_globals.thread_scope.translations = get_gettext_translation(locale)
+
+
def pass_to_ugettext(*args, **kwargs):
"""
Pass a translation on to the appropriate ugettext method.
@@ -122,6 +143,16 @@ def pass_to_ugettext(*args, **kwargs):
return mg_globals.thread_scope.translations.ugettext(
*args, **kwargs)
+def pass_to_ungettext(*args, **kwargs):
+ """
+ Pass a translation on to the appropriate ungettext method.
+
+ The reason we can't have a global ugettext method is because
+ mg_globals gets swapped out by the application per-request.
+ """
+ return mg_globals.thread_scope.translations.ungettext(
+ *args, **kwargs)
+
def lazy_pass_to_ugettext(*args, **kwargs):
"""
@@ -134,7 +165,7 @@ def lazy_pass_to_ugettext(*args, **kwargs):
you would want to use the lazy version for _.
"""
- return LazyProxy(pass_to_ugettext, *args, **kwargs)
+ return ReallyLazyProxy(pass_to_ugettext, *args, **kwargs)
def pass_to_ngettext(*args, **kwargs):
@@ -156,7 +187,17 @@ def lazy_pass_to_ngettext(*args, **kwargs):
level but you need it to not translate until the time that it's
used as a string.
"""
- return LazyProxy(pass_to_ngettext, *args, **kwargs)
+ return ReallyLazyProxy(pass_to_ngettext, *args, **kwargs)
+
+def lazy_pass_to_ungettext(*args, **kwargs):
+ """
+ Lazily pass to ungettext.
+
+ This is useful if you have to define a translation on a module
+ level but you need it to not translate until the time that it's
+ used as a string.
+ """
+ return ReallyLazyProxy(pass_to_ungettext, *args, **kwargs)
def fake_ugettext_passthrough(string):
diff --git a/mediagoblin/user_pages/forms.py b/mediagoblin/user_pages/forms.py
index e9746a6c..9a193680 100644
--- a/mediagoblin/user_pages/forms.py
+++ b/mediagoblin/user_pages/forms.py
@@ -16,7 +16,7 @@
import wtforms
from wtforms.ext.sqlalchemy.fields import QuerySelectField
-from mediagoblin.tools.translate import fake_ugettext_passthrough as _
+from mediagoblin.tools.translate import lazy_pass_to_ugettext as _
class MediaCommentForm(wtforms.Form):
comment_content = wtforms.TextAreaField(
diff --git a/mediagoblin/user_pages/lib.py b/mediagoblin/user_pages/lib.py
index 8a064a7c..2f47e4b1 100644
--- a/mediagoblin/user_pages/lib.py
+++ b/mediagoblin/user_pages/lib.py
@@ -18,6 +18,8 @@ from mediagoblin.tools.mail import send_email
from mediagoblin.tools.template import render_template
from mediagoblin.tools.translate import pass_to_ugettext as _
from mediagoblin import mg_globals
+from mediagoblin.db.base import Session
+from mediagoblin.db.models import CollectionItem
def send_comment_email(user, comment, media, request):
@@ -55,3 +57,21 @@ def send_comment_email(user, comment, media, request):
instance_title=mg_globals.app_config['html_title']) \
+ _('commented on your post'),
rendered_email)
+
+
+def add_media_to_collection(collection, media, note=None, commit=True):
+ collection_item = CollectionItem()
+ collection_item.collection = collection.id
+ collection_item.media_entry = media.id
+ if note:
+ collection_item.note = note
+ Session.add(collection_item)
+
+ collection.items = collection.items + 1
+ Session.add(collection)
+
+ media.collected = media.collected + 1
+ Session.add(media)
+
+ if commit:
+ Session.commit()
diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py
index c611daa1..596d4c20 100644
--- a/mediagoblin/user_pages/views.py
+++ b/mediagoblin/user_pages/views.py
@@ -20,11 +20,14 @@ import datetime
from mediagoblin import messages, mg_globals
from mediagoblin.db.models import (MediaEntry, MediaTag, Collection,
CollectionItem, User)
-from mediagoblin.tools.response import render_to_response, render_404, redirect
+from mediagoblin.tools.response import render_to_response, render_404, \
+ redirect, redirect_obj
from mediagoblin.tools.translate import pass_to_ugettext as _
from mediagoblin.tools.pagination import Pagination
from mediagoblin.user_pages import forms as user_forms
-from mediagoblin.user_pages.lib import send_comment_email
+from mediagoblin.user_pages.lib import add_media_to_collection
+from mediagoblin.notifications import trigger_notification, \
+ add_comment_subscription, mark_comment_notification_seen
from mediagoblin.decorators import (uses_pagination, get_user_media_entry,
get_media_entry_by_id,
@@ -32,6 +35,7 @@ from mediagoblin.decorators import (uses_pagination, get_user_media_entry,
get_user_collection, get_user_collection_item, active_user_from_url)
from werkzeug.contrib.atom import AtomFeed
+from werkzeug.exceptions import MethodNotAllowed
_log = logging.getLogger(__name__)
@@ -108,6 +112,7 @@ def user_gallery(request, page, url_user=None):
'media_entries': media_entries,
'pagination': pagination})
+
MEDIA_COMMENTS_PER_PAGE = 50
@@ -119,6 +124,9 @@ def media_home(request, media, page, **kwargs):
"""
comment_id = request.matchdict.get('comment', None)
if comment_id:
+ if request.user:
+ mark_comment_notification_seen(comment_id, request.user)
+
pagination = Pagination(
page, media.get_comments(
mg_globals.app_config['comments_ascending']),
@@ -134,7 +142,7 @@ def media_home(request, media, page, **kwargs):
comment_form = user_forms.MediaCommentForm(request.form)
- media_template_name = media.media_manager['display_template']
+ media_template_name = media.media_manager.display_template
return render_to_response(
request,
@@ -152,14 +160,21 @@ def media_post_comment(request, media):
"""
recieves POST from a MediaEntry() comment form, saves the comment.
"""
- assert request.method == 'POST'
+ if not request.method == 'POST':
+ raise MethodNotAllowed()
comment = request.db.MediaComment()
comment.media_entry = media.id
comment.author = request.user.id
comment.content = unicode(request.form['comment_content'])
- if not comment.content.strip():
+ # Show error message if commenting is disabled.
+ if not mg_globals.app_config['allow_comments']:
+ messages.add_message(
+ request,
+ messages.ERROR,
+ _("Sorry, comments are disabled."))
+ elif not comment.content.strip():
messages.add_message(
request,
messages.ERROR,
@@ -171,13 +186,11 @@ def media_post_comment(request, media):
request, messages.SUCCESS,
_('Your comment has been posted!'))
- media_uploader = media.get_uploader
- #don't send email if you comment on your own post
- if (comment.author != media_uploader and
- media_uploader.wants_comment_notification):
- send_comment_email(media_uploader, comment, media, request)
+ trigger_notification(comment, media, request)
+
+ add_comment_subscription(request.user, media)
- return redirect(request, location=media.url_for_self(request.urlgen))
+ return redirect_obj(request, media)
@get_media_entry_by_id
@@ -204,11 +217,11 @@ def media_collect(request, media):
# If we are here, method=POST and the form is valid, submit things.
# If the user is adding a new collection, use that:
- if request.form['collection_title']:
+ if form.collection_title.data:
# Make sure this user isn't duplicating an existing collection
existing_collection = Collection.query.filter_by(
creator=request.user.id,
- title=request.form['collection_title']).first()
+ title=form.collection_title.data).first()
if existing_collection:
messages.add_message(request, messages.ERROR,
_('You already have a collection called "%s"!')
@@ -218,8 +231,8 @@ def media_collect(request, media):
media=media.slug_or_id)
collection = Collection()
- collection.title = request.form['collection_title']
- collection.description = request.form.get('collection_description')
+ collection.title = form.collection_title.data
+ collection.description = form.collection_description.data
collection.creator = request.user.id
collection.generate_slug()
collection.save()
@@ -248,25 +261,13 @@ def media_collect(request, media):
_('"%s" already in collection "%s"')
% (media.title, collection.title))
else: # Add item to collection
- collection_item = request.db.CollectionItem()
- collection_item.collection = collection.id
- collection_item.media_entry = media.id
- collection_item.note = request.form['note']
- collection_item.save()
-
- collection.items = collection.items + 1
- collection.save()
-
- media.collected = media.collected + 1
- media.save()
+ add_media_to_collection(collection, media, form.note.data)
messages.add_message(request, messages.SUCCESS,
_('"%s" added to collection "%s"')
% (media.title, collection.title))
- return redirect(request, "mediagoblin.user_pages.media_home",
- user=media.get_uploader.username,
- media=media.slug_or_id)
+ return redirect_obj(request, media)
#TODO: Why does @user_may_delete_media not implicate @require_active_login?
@@ -291,8 +292,7 @@ def media_confirm_delete(request, media):
messages.add_message(
request, messages.ERROR,
_("The media was not deleted because you didn't check that you were sure."))
- return redirect(request,
- location=media.url_for_self(request.urlgen))
+ return redirect_obj(request, media)
if ((request.user.is_admin and
request.user.id != media.uploader)):
@@ -378,9 +378,7 @@ def collection_item_confirm_remove(request, collection_item):
request, messages.ERROR,
_("The item was not removed because you didn't check that you were sure."))
- return redirect(request, "mediagoblin.user_pages.user_collection",
- user=username,
- collection=collection.slug)
+ return redirect_obj(request, collection)
if ((request.user.is_admin and
request.user.id != collection_item.in_collection.creator)):
@@ -418,8 +416,8 @@ def collection_confirm_delete(request, collection):
item.delete()
collection.delete()
- messages.add_message(
- request, messages.SUCCESS, _('You deleted the collection "%s"' % collection_title))
+ messages.add_message(request, messages.SUCCESS,
+ _('You deleted the collection "%s"') % collection_title)
return redirect(request, "mediagoblin.user_pages.user_home",
user=username)
@@ -428,9 +426,7 @@ def collection_confirm_delete(request, collection):
request, messages.ERROR,
_("The collection was not deleted because you didn't check that you were sure."))
- return redirect(request, "mediagoblin.user_pages.user_collection",
- user=username,
- collection=collection.slug)
+ return redirect_obj(request, collection)
if ((request.user.is_admin and
request.user.id != collection.creator)):
@@ -537,9 +533,7 @@ def collection_atom_feed(request):
ATOM feed id is a tag URI (see http://en.wikipedia.org/wiki/Tag_URI)
"""
atomlinks = [{
- 'href': request.urlgen(
- 'mediagoblin.user_pages.user_collection',
- qualified=True, user=request.matchdict['user'], collection=collection.slug),
+ 'href': collection.url_for_self(request.urlgen, qualified=True),
'rel': 'alternate',
'type': 'text/html'
}]