diff options
88 files changed, 5741 insertions, 691 deletions
@@ -10,7 +10,8 @@ mediagoblin.egg-info *.pyo docs/_build/ user_dev/ -mediagoblin_user.ini +paste_local.ini +mediagoblin_local.ini server-log.txt *~ *.swp diff --git a/.tx/config b/.tx/config new file mode 100644 index 00000000..711b5d94 --- /dev/null +++ b/.tx/config @@ -0,0 +1,8 @@ +[mediagoblin.mediagoblin] +file_filter = mediagoblin/i18n/<lang>/LC_MESSAGES/mediagoblin.po +source_file = mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po +source_lang = en + +[main] +host = https://www.transifex.net + @@ -10,4 +10,4 @@ encoding = utf-8 # # Extraction from JavaScript files # [javascript: mediagoblin/static/js/**.js] -# extract_messages = $._, jQuery._
\ No newline at end of file +# extract_messages = $._, jQuery._ diff --git a/docs/source/mediagoblin.rst b/docs/source/about_mediagoblin.rst index af6658f3..af6658f3 100644 --- a/docs/source/mediagoblin.rst +++ b/docs/source/about_mediagoblin.rst diff --git a/docs/source/foreword.rst b/docs/source/foreword.rst index 1d423f08..4fd96842 100644 --- a/docs/source/foreword.rst +++ b/docs/source/foreword.rst @@ -8,26 +8,19 @@ About this manual This is the GNU MediaGoblin manual. This documentation targets the following groups of individuals: -* people who want to use the software -* people who want to deploy the software -* contributors - -This manual is a living document and is in the ``mediagoblin`` -repository in the ``docs/`` directory. +* people who want to try the software locally +* people who want to deploy and administrate the software +This manual doesn't cover contributors to the codebase. But we want +and love contributors! To join as a contributor please visit the +following pages instead: -Who wrote this documentation? -============================= +* http://mediagoblin.org/pages/join.html for general "join us" information +* http://wiki.mediagoblin.org/ for our contributor-focused wiki -In no particular order: - -* Chris -* Will -* Deb -* Greg -* Karen -* Matt -* Asheesh +If you are viewing this from http://docs.mediagoblin.org be aware that +this manual is a living document and is in the ``mediagoblin`` +repository in the ``docs/`` directory. I found an error in the docs---who do I tell? @@ -35,7 +28,7 @@ I found an error in the docs---who do I tell? There are a few ways---please pick the one most convenient to you! -1. Write up a bug report in the bug tracker at http://bugs.foocorp.net/ . +1. Write up a bug report in the bug tracker at http://bugs.foocorp.net/projects/mediagoblin/issues 2. Tell someone on IRC ``#mediagoblin`` on Freenode. 3. Send an email to Will ``willg at bluesock dot org``. diff --git a/docs/source/git.rst b/docs/source/git.rst deleted file mode 100644 index ab3206b6..00000000 --- a/docs/source/git.rst +++ /dev/null @@ -1,224 +0,0 @@ -========================== - Git, Cloning and Patches -========================== - -.. contents:: Sections - :local: - - -GNU MediaGoblin uses git for all our version control and we have the -repositories hosted on `Gitorious <http://gitorious.org/>`_. We have -two repositories: - -* MediaGoblin software: http://gitorious.org/mediagoblin/mediagoblin -* MediaGoblin website: http://gitorious.org/mediagoblin/mediagoblin-website - -It's most likely you want to look at the software repository--not the -website one. - -The rest of this chapter talks about using the software repository. - - -How to clone the project -======================== - -Do:: - - git clone git://gitorious.org/mediagoblin/mediagoblin.git - - -How to contribute changes -========================= - -Tie your changes to issues in the issue tracker ------------------------------------------------ - -All patches should be tied to issues in the `issue tracker -<http://bugs.foocorp.net/projects/mediagoblin/issues>`_. That makes -it a lot easier for everyone to track proposed changes and make sure -your hard work doesn't get dropped on the floor! If there isn't an -issue for what you're working on, please create one. The better the -description of what it is you're trying to fix/implement, the better -everyone else is able to understand why you're doing what you're -doing. - - -Use bugfix branches to make changes ------------------------------------ - -The best way to isolate your changes is to create a branch based off -of the MediaGoblin repository master branch, do the changes related to -that one issue there, and then let us know how to get it. - -It's much easier on us if you isolate your changes to a branch focused -on the issue. Then we don't have to sift through things. - -It's much easier on you if you isolate your changes to a branch -focused on the issue. Then when we merge your changes in, you just -have to do a ``git fetch`` and that's it. This is especially true if -we reject some of your changes, but accept others or otherwise tweak -your changes. - -Further, if you isolate your changes to a branch, then you can work on -multiple issues at the same time and they don't conflict with one -another. - -Name your branches using the isue number and something that makes it clear -what it's about. For example, if you were working on tagging, you -might name your branch ``360_tagging``. - - -Properly document your changes ------------------------------- - -Include comments in the code. - -Write comprehensive commit messages. The better your commit message -is at describing what you did and why, the easier it is for us to -quickly accept your patch. - -Write comprehensive comments in the issue tracker about what you're -doing and why. - - -How to send us your changes ---------------------------- - -There are two ways to let us know how to get it: - -1. *(preferred)* **push changes to publicly available git clone and - let us know where to find it** - - Push your feature/bugfix/issue branch to your publicly available - git clone and add a comment to the issue with the url for your - clone and the branch to look at. - -2. **attaching the patch files to the issue** - - Run:: - - git format-patch --stdout <remote>/master > issue_<number>.patch - - ``format-patch`` creates a patch of all the commits that are in - your branch that aren't in ``<remote>/master``. The ``--stdout`` - flag causes all this output to go to stdout where it's redirected - to a file named ``issue_<number>.patch``. That file should be - based on the issue you're working with. For example, - ``issue_42.patch`` is a good filename and ``issue_42_rev2.patch`` - is good if you did a revision of it. - - Having said all that, the filename isn't wildly important. - - -Example workflow -================ - -Here's an example workflow. - - -Contributing changes --------------------- - -Slartibartfast from the planet Magrathea far off in the universe has -decided that he is bored with fjords and wants to fix issue 42 (the -meaning of life bug) and send us the changes. - -Slartibartfast has cloned the MediaGoblin repository and his clone -lives on gitorious. - -Slartibartfast works locally. The remote named ``origin`` points to -his clone on gitorious. The remote named ``gmg`` points to the -MediaGoblin repository. - -Slartibartfast does the following: - -1. Fetches the latest from the MediaGoblin repository:: - - git fetch --all -p - - This tells ``git fetch`` to fetch all the recent data from all of - the remotes (``--all``) and prune any branches that have been - deleted in the remotes (``-p``). - -2. Creates a branch from the tip of the MediaGoblin repository (the - remote is named ``gmg``) master branch called ``bug42_meaning_of_life``:: - - git checkout -b bug42_meaning_of_life gmg/master - - This creates a new branch (``-b``) named ``bug42_meaning_of_life`` based - on the tip of the ``master`` branch of the remote named ``gmg`` and checks - it out. - -3. Slartibartfast works hard on his changes in the ``bug42_meaning_of_life`` - branch. When done, he wants to notify us that he has made changes - he wants us to see. - -4. Slartibartfast pushes his changes to his clone:: - - git push origin bug42_meaning_of_life --set-upstream - - This pushes the changes in the ``bug42_meaning_of_life`` branch to the - remote named ``origin``. - -5. Slartibartfast adds a comment to issue 42 with the url for his - repository and the name of the branch he put the code in. He also - explains what he did and why it addresses the issue. - - -Updating a contribution ------------------------ - -Slartibartfast brushes his hands off with the sense of accomplishment -that comes with the knowledge of a job well done. He stands, wanders -over to get a cup of water, then realizes that he forgot to run the -unit tests! - -He runs the unit tests and discovers there's a bug in the code! - -Then he does this: - -1. He checks out the ``bug42_meaning_of_life`` branch:: - - git checkout bug42_meaning_of_life - -2. He fixes the bug and checks it into the ``bug42_meaning_of_life`` branch. - -3. He pushes his changes to his clone (the remote is named ``origin``):: - - git push origin bug42_meaning_of_life - -4. He adds another comment to issue 42 explaining about the mistake - and how he fixed it and that he's pushed the new change to the - ``bug42_meaning_of_life`` branch of his publicly available clone. - - -What happens next ------------------ - -Slartibartfast is once again happy with his work. He finds issue 42 -in the issue tracker and adds a comment saying he submitted a merge -request with his changes and explains what they are. - -Later, someone checks out his code and finds a problem with it. He -adds a comment to the issue tracker specifying the problem and asks -Slartibartfast to fix it. Slartibartfst goes through the above steps -again, fixes the issue, pushes it to his ``bug42_meaning_of_life`` branch and adds -another comment to the issue tracker about how he fixed it. - -Later, someone checks out his code and is happy with it. Someone -pulls it into the master branch of the MediaGoblin repository and adds -another comment to the issue and probably closes the issue out. - -Slartibartfast is notified of this. Slartibartfast does a:: - - git fetch --all - -The changes show up in the ``master`` branch of the ``gmg`` remote. -Slartibartfast now deletes his ``bug42_meaning_of_life`` branch -because he doesn't need it anymore. - - -How to learn git -================ - -Check out `the wiki <http://wiki.mediagoblin.org/>`_. diff --git a/docs/source/index.rst b/docs/source/index.rst index 8c00869a..79f2653e 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -12,11 +12,10 @@ Table of Contents: :maxdepth: 2 foreword - mediagoblin - contributinghowto + about_mediagoblin deploymenthowto theminghowto - git + contributinghowto codebase vision diff --git a/mediagoblin.ini b/mediagoblin.ini index e889646a..c22d12d7 100644 --- a/mediagoblin.ini +++ b/mediagoblin.ini @@ -1,7 +1,4 @@ [mediagoblin] -queuestore_base_dir = %(here)s/user_dev/media/queue -publicstore_base_dir = %(here)s/user_dev/media/public -publicstore_base_url = /mgoblin_media/ direct_remote_path = /mgoblin_static/ email_sender_address = "notice@mediagoblin.example.org" @@ -14,5 +11,12 @@ allow_registration = true ## Uncomment this to put some user-overriding templates here #local_templates = %(here)s/user_dev/templates/ +[storage:queuestore] +base_dir = %(here)s/user_dev/media/queue + +[storage:publicstore] +base_dir = %(here)s/user_dev/media/public +base_url = /mgoblin_media/ + [celery] # Put celery stuff here diff --git a/mediagoblin/app.py b/mediagoblin/app.py index c1ee3d77..3030929d 100644 --- a/mediagoblin/app.py +++ b/mediagoblin/app.py @@ -101,6 +101,23 @@ class MediaGoblinApp(object): ## Routing / controller loading stuff route_match = self.routing.match(path_info) + ## Attach utilities to the request object + request.matchdict = route_match + request.urlgen = routes.URLGenerator(self.routing, environ) + # Do we really want to load this via middleware? Maybe? + request.session = request.environ['beaker.session'] + # Attach self as request.app + # Also attach a few utilities from request.app for convenience? + request.app = self + request.locale = util.get_locale_from_request(request) + + request.template_env = util.get_jinja_env( + self.template_loader, request.locale) + request.db = self.db + request.staticdirect = self.staticdirector + + util.setup_user_in_request(request) + # No matching page? if route_match is None: # Try to do see if we have a match with a trailing slash @@ -116,28 +133,12 @@ class MediaGoblinApp(object): return request.get_response(redirect)(environ, start_response) # Okay, no matches. 404 time! - return exc.HTTPNotFound()(environ, start_response) + request.matchdict = {} # in case our template expects it + return util.render_404(request)(environ, start_response) controller = util.import_component(route_match['controller']) request.start_response = start_response - ## Attach utilities to the request object - request.matchdict = route_match - request.urlgen = routes.URLGenerator(self.routing, environ) - # Do we really want to load this via middleware? Maybe? - request.session = request.environ['beaker.session'] - # Attach self as request.app - # Also attach a few utilities from request.app for convenience? - request.app = self - request.locale = util.get_locale_from_request(request) - - request.template_env = util.get_jinja_env( - self.template_loader, request.locale) - request.db = self.db - request.staticdirect = self.staticdirector - - util.setup_user_in_request(request) - return controller(request)(environ, start_response) diff --git a/mediagoblin/auth/forms.py b/mediagoblin/auth/forms.py index 7bc0aeb1..917909c5 100644 --- a/mediagoblin/auth/forms.py +++ b/mediagoblin/auth/forms.py @@ -16,34 +16,36 @@ import wtforms +from mediagoblin.util import fake_ugettext_passthrough as _ + class RegistrationForm(wtforms.Form): username = wtforms.TextField( - 'Username', + _('Username'), [wtforms.validators.Required(), wtforms.validators.Length(min=3, max=30), wtforms.validators.Regexp(r'^\w+$')]) password = wtforms.PasswordField( - 'Password', + _('Password'), [wtforms.validators.Required(), wtforms.validators.Length(min=6, max=30), wtforms.validators.EqualTo( 'confirm_password', - 'Passwords must match.')]) + _('Passwords must match.'))]) confirm_password = wtforms.PasswordField( - 'Confirm password', + _('Confirm password'), [wtforms.validators.Required()]) email = wtforms.TextField( - 'Email address', + _('Email address'), [wtforms.validators.Required(), wtforms.validators.Email()]) class LoginForm(wtforms.Form): username = wtforms.TextField( - 'Username', + _('Username'), [wtforms.validators.Required(), wtforms.validators.Regexp(r'^\w+$')]) password = wtforms.PasswordField( - 'Password', + _('Password'), [wtforms.validators.Required()]) diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py index df7e2a88..4c4a34fd 100644 --- a/mediagoblin/auth/views.py +++ b/mediagoblin/auth/views.py @@ -20,7 +20,8 @@ from webob import exc from mediagoblin import messages from mediagoblin import mg_globals -from mediagoblin.util import render_to_response, redirect +from mediagoblin.util import render_to_response, redirect, render_404 +from mediagoblin.util import pass_to_ugettext as _ from mediagoblin.db.util import ObjectId from mediagoblin.auth import lib as auth_lib from mediagoblin.auth import forms as auth_forms @@ -36,7 +37,7 @@ def register(request): messages.add_message( request, messages.WARNING, - ('Sorry, registration is disabled on this instance.')) + _('Sorry, registration is disabled on this instance.')) return redirect(request, "index") register_form = auth_forms.RegistrationForm(request.POST) @@ -44,20 +45,27 @@ def register(request): if request.method == 'POST' and register_form.validate(): # TODO: Make sure the user doesn't exist already - users_with_username = \ - request.db.User.find({ - 'username': request.POST['username'].lower() - }).count() + users_with_username = request.db.User.find( + {'username': request.POST['username'].lower()}).count() + users_with_email = request.db.User.find( + {'email': request.POST['email'].lower()}).count() + + extra_validation_passes = True if users_with_username: register_form.username.errors.append( - u'Sorry, a user with that name already exists.') - - else: + _(u'Sorry, a user with that name already exists.')) + extra_validation_passes = False + if users_with_email: + register_form.email.errors.append( + _(u'Sorry, that email address has already been taken.')) + extra_validation_passes = False + + if extra_validation_passes: # Create the user user = request.db.User() user['username'] = request.POST['username'].lower() - user['email'] = request.POST['email'] + user['email'] = request.POST['email'].lower() user['pw_hash'] = auth_lib.bcrypt_gen_password_hash( request.POST['password']) user.save(validate=True) @@ -136,7 +144,7 @@ def verify_email(request): """ # If we don't have userid and token parameters, we can't do anything; 404 if not request.GET.has_key('userid') or not request.GET.has_key('token'): - return exc.HTTPNotFound() + return render_404(request) user = request.db.User.find_one( {'_id': ObjectId(unicode(request.GET['userid']))}) @@ -148,16 +156,17 @@ def verify_email(request): messages.add_message( request, messages.SUCCESS, - ('Your email address has been verified. ' - 'You may now login, edit your profile, and submit images!')) + _("Your email address has been verified. " + "You may now login, edit your profile, and submit images!")) else: - messages.add_message(request, - messages.ERROR, - 'The verification key or user id is incorrect') + messages.add_message( + request, + messages.ERROR, + _('The verification key or user id is incorrect')) return redirect( request, 'mediagoblin.user_pages.user_home', - user=request.user['username']) + user=user['username']) def resend_activation(request): @@ -174,7 +183,7 @@ def resend_activation(request): messages.add_message( request, messages.INFO, - 'Resent your verification email.') + _('Resent your verification email.')) return redirect( request, 'mediagoblin.user_pages.user_home', user=request.user['username']) diff --git a/mediagoblin/config_spec.ini b/mediagoblin/config_spec.ini index a82541b6..11badc1f 100644 --- a/mediagoblin/config_spec.ini +++ b/mediagoblin/config_spec.ini @@ -4,15 +4,10 @@ db_host = string() db_name = string(default="mediagoblin") db_port = integer() -# -queuestore_base_dir = string(default="%(here)s/user_dev/media/queue") -publicstore_base_dir = string(default="%(here)s/user_dev/media/public") # Where temporary files used in processing and etc are kept workbench_path = string(default="%(here)s/user_dev/media/workbench") -# -publicstore_base_url = string(default="/mgoblin_media/") # Where mediagoblin-builtin static assets are kept direct_remote_path = string(default="/mgoblin_static/") @@ -42,6 +37,15 @@ celery_setup_elsewhere = boolean(default=False) # source files for a media file but can also be a HUGE security risk. allow_attachments = boolean(default=False) + +[storage:publicstore] +base_dir = string(default="%(here)s/user_dev/media/public") +base_url = string(default="/mgoblin_media/") + +[storage:queuestore] +base_dir = string(default="%(here)s/user_dev/media/queue") + + [celery] # known booleans celery_result_persistent = boolean() diff --git a/mediagoblin/db/migrations.py b/mediagoblin/db/migrations.py index 6a8ebcf9..5456b248 100644 --- a/mediagoblin/db/migrations.py +++ b/mediagoblin/db/migrations.py @@ -52,3 +52,43 @@ def mediaentry_mediafiles_main_to_original(database): document['media_files']['original'] = original collection.save(document) + + +@RegisterMigration(3) +def mediaentry_remove_thumbnail_file(database): + """ + Use media_files['thumb'] instead of media_entries['thumbnail_file'] + """ + database['media_entries'].update( + {'thumbnail_file': {'$exists': True}}, + {'$unset': {'thumbnail_file': 1}}, + multi=True) + + +@RegisterMigration(4) +def mediaentry_add_queued_task_id(database): + """ + Add the 'queued_task_id' field for entries that don't have it. + """ + collection = database['media_entries'] + collection.update( + {'queued_task_id': {'$exists': False}}, + {'$set': {'queued_task_id': None}}, + multi=True) + + +@RegisterMigration(5) +def mediaentry_add_fail_error_and_metadata(database): + """ + Add 'fail_error' and 'fail_metadata' fields to media entries + """ + collection = database['media_entries'] + collection.update( + {'fail_error': {'$exists': False}}, + {'$set': {'fail_error': None}}, + multi=True) + + collection.update( + {'fail_metadata': {'$exists': False}}, + {'$set': {'fail_metadata': {}}}, + multi=True) diff --git a/mediagoblin/db/models.py b/mediagoblin/db/models.py index 4ef2d928..b6e52441 100644 --- a/mediagoblin/db/models.py +++ b/mediagoblin/db/models.py @@ -162,6 +162,8 @@ class MediaEntry(Document): queued for processing. This is stored in the mg_globals.queue_store storage system. + - queued_task_id: celery task id. Use this to fetch the task state. + - media_files: Files relevant to this that have actually been processed and are available for various types of display. Stored like: {'thumb': ['dir1', 'dir2', 'pic.png'} @@ -170,7 +172,8 @@ class MediaEntry(Document): critical to this piece of media but may be usefully relevant to people viewing the work. (currently unused.) - - thumbnail_file: Deprecated... we should remove this ;) + - fail_error: path to the exception raised + - fail_metadata: """ __collection__ = 'media_entries' @@ -190,6 +193,7 @@ class MediaEntry(Document): # For now let's assume there can only be one main file queued # at a time 'queued_media_file': [unicode], + 'queued_task_id': unicode, # A dictionary of logical names to filepaths 'media_files': dict, @@ -198,8 +202,10 @@ class MediaEntry(Document): # record form 'attachment_files': list, - # This one should just be a single file record - 'thumbnail_file': [unicode]} + # If things go badly in processing things, we'll store that + # data here + 'fail_error': unicode, + 'fail_metadata': dict} required_fields = [ 'uploader', 'created', 'media_type', 'slug'] @@ -291,6 +297,13 @@ class MediaEntry(Document): def uploader(self): return self.db.User.find_one({'_id': self['uploader']}) + def get_fail_exception(self): + """ + Get the exception that's appropriate for this error + """ + if self['fail_error']: + return util.import_component(self['fail_error']) + class MediaComment(Document): """ diff --git a/mediagoblin/decorators.py b/mediagoblin/decorators.py index 2e90274e..c66049ca 100644 --- a/mediagoblin/decorators.py +++ b/mediagoblin/decorators.py @@ -17,7 +17,7 @@ from webob import exc -from mediagoblin.util import redirect +from mediagoblin.util import redirect, render_404 from mediagoblin.db.util import ObjectId, InvalidId @@ -60,9 +60,9 @@ def uses_pagination(controller): try: page = int(request.GET.get('page', 1)) if page < 0: - return exc.HTTPNotFound() + return render_404(request) except ValueError: - return exc.HTTPNotFound() + return render_404(request) return controller(request, page=page, *args, **kwargs) @@ -78,7 +78,7 @@ def get_user_media_entry(controller): {'username': request.matchdict['user']}) if not user: - return exc.HTTPNotFound() + return render_404(request) media = request.db.MediaEntry.find_one( {'slug': request.matchdict['media'], @@ -93,11 +93,11 @@ def get_user_media_entry(controller): 'state': 'processed', 'uploader': user['_id']}) except InvalidId: - return exc.HTTPNotFound() + return render_404(request) # Still no media? Okay, 404. if not media: - return exc.HTTPNotFound() + return render_404(request) return controller(request, media=media, *args, **kwargs) @@ -113,11 +113,11 @@ def get_media_entry_by_id(controller): {'_id': ObjectId(request.matchdict['media']), 'state': 'processed'}) except InvalidId: - return exc.HTTPNotFound() + return render_404(request) # Still no media? Okay, 404. if not media: - return exc.HTTPNotFound() + return render_404(request) return controller(request, media=media, *args, **kwargs) diff --git a/mediagoblin/edit/forms.py b/mediagoblin/edit/forms.py index 3969e509..c5ab9fd9 100644 --- a/mediagoblin/edit/forms.py +++ b/mediagoblin/edit/forms.py @@ -16,26 +16,29 @@ import wtforms + from mediagoblin.util import tag_length_validator, TOO_LONG_TAG_WARNING +from mediagoblin.util import fake_ugettext_passthrough as _ class EditForm(wtforms.Form): title = wtforms.TextField( - 'Title', + _('Title'), [wtforms.validators.Length(min=0, max=500)]) slug = wtforms.TextField( - 'Slug', - [wtforms.validators.Required(message="The slug can't be empty")]) + _('Slug'), + [wtforms.validators.Required(message=_("The slug can't be empty"))]) description = wtforms.TextAreaField('Description of this work') tags = wtforms.TextField( - 'Tags', + _('Tags'), [tag_length_validator]) class EditProfileForm(wtforms.Form): - bio = wtforms.TextAreaField('Bio', + bio = wtforms.TextAreaField( + _('Bio'), [wtforms.validators.Length(min=0, max=500)]) url = wtforms.TextField( - 'Website', + _('Website'), [wtforms.validators.Optional(), wtforms.validators.URL(message='Improperly formed URL')]) diff --git a/mediagoblin/edit/views.py b/mediagoblin/edit/views.py index c4d503b7..b0145a04 100644 --- a/mediagoblin/edit/views.py +++ b/mediagoblin/edit/views.py @@ -27,6 +27,7 @@ from mediagoblin import mg_globals from mediagoblin.util import ( render_to_response, redirect, clean_html, convert_to_tag_list_of_dicts, media_tags_as_string, cleaned_markdown_conversion) +from mediagoblin.util import pass_to_ugettext as _ from mediagoblin.edit import forms from mediagoblin.edit.lib import may_edit_media from mediagoblin.decorators import require_active_login, get_user_media_entry @@ -61,7 +62,7 @@ def edit_media(request, media): if existing_user_slug_entries: form.slug.errors.append( - u'An entry with that slug already exists for this user.') + _(u'An entry with that slug already exists for this user.')) else: media['title'] = request.POST['title'] media['description'] = request.POST.get('description') @@ -90,7 +91,7 @@ def edit_media(request, media): and request.method != 'POST': messages.add_message( request, messages.WARNING, - "You are editing another user's media. Proceed with caution.") + _("You are editing another user's media. Proceed with caution.")) return render_to_response( request, @@ -161,7 +162,7 @@ def edit_profile(request): if request.method != 'POST': messages.add_message( request, messages.WARNING, - "You are editing a user's profile. Proceed with caution.") + _("You are editing a user's profile. Proceed with caution.")) else: user = request.user diff --git a/mediagoblin/errormiddleware.py b/mediagoblin/errormiddleware.py new file mode 100644 index 00000000..352dc891 --- /dev/null +++ b/mediagoblin/errormiddleware.py @@ -0,0 +1,60 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# 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 paste.exceptions.errormiddleware import make_error_middleware + +MGOBLIN_ERROR_MESSAGE = """\ +<div style="text-align:center;font-family: monospace"> + <h1>YEOWCH... that's an error!</h1> + <pre> +.-------------------------. +| __ _ | +| -, \_,------,_// | +| <\ ,-- --.\ | +| / (x ) ( X ) | +| ' '--, ,--'\ | +| / \ -v-v-u-v / | +| . '.__.--__'.\ | +| / ',___/ / \__/' | +| | | ,'\_'/, || | +| \_| | | | | || | +| W',_ ||| |||_'' | +| | '------'| | +| |__| |_|_ | +| ,,,-' '-,,, | +'-------------------------' + </pre> + <p>Something bad happened, and things broke.</p> + <p>If this is not your website, you may want to alert the owner.</p> + <br><br> + <p> + Powered... er broken... by + <a href="http://www.mediagoblin.org">MediaGoblin</a>, + a <a href="http://www.gnu.org">GNU Project</a>. + </p> +</div>""" + + +def mgoblin_error_middleware(app, global_conf, **kw): + """ + MediaGoblin wrapped error middleware. + + This is really just wrapping the error middleware from Paste. + It should take all of Paste's default options, so see: + http://pythonpaste.org/modules/exceptions.html + """ + kw['error_message'] = MGOBLIN_ERROR_MESSAGE + return make_error_middleware(app, global_conf, **kw) diff --git a/mediagoblin/gmg_commands/__init__.py b/mediagoblin/gmg_commands/__init__.py index 921f0430..8226fd0e 100644 --- a/mediagoblin/gmg_commands/__init__.py +++ b/mediagoblin/gmg_commands/__init__.py @@ -44,6 +44,14 @@ SUBCOMMAND_MAP = { 'setup': 'mediagoblin.gmg_commands.wipealldata:wipe_parser_setup', 'func': 'mediagoblin.gmg_commands.wipealldata:wipe', 'help': 'Wipes **all** the data for this MediaGoblin instance'}, + 'env_export': { + 'setup': 'mediagoblin.gmg_commands.import_export:import_export_parse_setup', + 'func': 'mediagoblin.gmg_commands.import_export:env_export', + 'help': 'Exports the data for this MediaGoblin instance'}, + 'env_import': { + 'setup': 'mediagoblin.gmg_commands.import_export:import_export_parse_setup', + 'func': 'mediagoblin.gmg_commands.import_export:env_import', + 'help': 'Exports the data for this MediaGoblin instance'}, } diff --git a/mediagoblin/gmg_commands/import_export.py b/mediagoblin/gmg_commands/import_export.py new file mode 100644 index 00000000..367924a5 --- /dev/null +++ b/mediagoblin/gmg_commands/import_export.py @@ -0,0 +1,250 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# 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 import mg_globals +from mediagoblin.db.open import setup_connection_and_db_from_config +from mediagoblin.init.config import read_mediagoblin_config +from mediagoblin.storage import BasicFileStorage +from mediagoblin.init import setup_storage, setup_global_and_app_config + +import shutil +import tarfile +import tempfile +import subprocess +import os.path +import os +import sys +from contextlib import closing + + +def import_export_parse_setup(subparser): + # TODO: Add default + subparser.add_argument( + 'tar_file') + subparser.add_argument( + '-cf', '--conf_file', default='mediagoblin.ini', + help='Config file used to set up environment') + subparser.add_argument( + '--mongodump_path', default='mongodump', + help='mongodump binary') + subparser.add_argument( + '--mongorestore_path', default='mongorestore', + help='mongorestore binary') + subparser.add_argument( + '--cache_path', + help='Temporary directory where files will be temporarily dumped') + + +def _import_media(db, args): + """ + Import media files + + Must be called after _import_database() + """ + print "\n== Importing media ==\n" + + media_cache = BasicFileStorage( + args._cache_path['media']) + + # TODO: Add import of queue files + queue_cache = BasicFileStorage( + args._cache_path['queue']) + + for entry in db.media_entries.find(): + for name, path in entry['media_files'].items(): + media_file = mg_globals.public_store.get_file(path, mode='wb') + media_file.write( + media_cache.get_file(path, mode='rb').read()) + + print "\n== Media imported ==\n" + + +def _import_database(db, args): + """ + Restore mongo database from ___.bson files + """ + print "\n== Importing database ==\n" + + p = subprocess.Popen([ + args.mongorestore_path, + '-d', db.name, + os.path.join(args._cache_path['database'], db.name)]) + + p.wait() + + print "\n== Database imported ==\n" + + +def env_import(args): + """ + Restore mongo database and media files from a tar archive + """ + if not args.cache_path: + args.cache_path = tempfile.mkdtemp() + + setup_global_and_app_config(args.conf_file) + + # Creates mg_globals.public_store and mg_globals.queue_store + setup_storage() + + config, validation_result = read_mediagoblin_config(args.conf_file) + connection, db = setup_connection_and_db_from_config( + config['mediagoblin'], use_pymongo=True) + + tf = tarfile.open( + args.tar_file, + mode='r|gz') + + tf.extractall(args.cache_path) + + args.cache_path = os.path.join( + args.cache_path, 'mediagoblin-data') + args = _setup_paths(args) + + # Import database from extracted data + _import_database(db, args) + + _import_media(db, args) + + _clean(args) + + +def _setup_paths(args): + """ + Populate ``args`` variable with cache subpaths + """ + args._cache_path = dict() + PATH_MAP = { + 'media': 'media', + 'queue': 'queue', + 'database': 'database'} + + for key, val in PATH_MAP.items(): + args._cache_path[key] = os.path.join(args.cache_path, val) + + return args + + +def _create_archive(args): + """ + Create the tar archive + """ + print "\n== Compressing to archive ==\n" + + tf = tarfile.open( + args.tar_file, + mode='w|gz') + + with closing(tf): + tf.add(args.cache_path, 'mediagoblin-data/') + + print "\n== Archiving done ==\n" + + +def _clean(args): + """ + Remove cache directory + """ + shutil.rmtree(args.cache_path) + + +def _export_check(args): + """ + Run security checks for export command + """ + if os.path.exists(args.tar_file): + overwrite = raw_input( + 'The output file already exists. ' + 'Are you **SURE** you want to overwrite it? ' + '(yes/no)> ') + if not overwrite == 'yes': + print "Aborting." + + return False + + return True + + +def _export_database(db, args): + print "\n== Exporting database ==\n" + + command = '{mongodump_path} -d {database} -o {mongodump_cache}'.format( + mongodump_path=args.mongodump_path, + database=db.name, + mongodump_cache=args._cache_path['database']) + + p = subprocess.Popen([ + args.mongodump_path, + '-d', db.name, + '-o', args._cache_path['database']]) + + p.wait() + + print "\n== Database exported ==\n" + + +def _export_media(db, args): + print "\n== Exporting media ==\n" + + media_cache = BasicFileStorage( + args._cache_path['media']) + + # TODO: Add export of queue files + queue_cache = BasicFileStorage( + args._cache_path['queue']) + + for entry in db.media_entries.find(): + for name, path in entry['media_files'].items(): + mc_file = media_cache.get_file(path, mode='wb') + mc_file.write( + mg_globals.public_store.get_file(path, mode='rb').read()) + + print "\n== Media exported ==\n" + + +def env_export(args): + """ + Export database and media files to a tar archive + """ + if args.cache_path: + if os.path.exists(args.cache_path): + print 'The cache directory must not exist before you run this script' + print 'Cache directory: ', args.cache_path + + return False + else: + args.cache_path = tempfile.mkdtemp() + + args = _setup_paths(args) + + if not _export_check(args): + print "\n== Checks did not pass, exiting ==\n" + sys.exit(0) + + setup_global_and_app_config(args.conf_file) + setup_storage() + + config, validation_result = read_mediagoblin_config(args.conf_file) + connection, db = setup_connection_and_db_from_config( + config['mediagoblin'], use_pymongo=True) + + _export_database(db, args) + + _export_media(db, args) + + _create_archive(args) + + _clean(args) diff --git a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo Binary files differnew file mode 100644 index 00000000..6bb69ce9 --- /dev/null +++ b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo diff --git a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po new file mode 100644 index 00000000..30c55e21 --- /dev/null +++ b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po @@ -0,0 +1,317 @@ +# Translations template for PROJECT. +# Copyright (C) 2011 ORGANIZATION +# This file is distributed under the same license as the PROJECT project. +# +# Rafael Maguiña <rafael.maguina@gmail.com>, 2011. +# <mediagoblin.org@samba-tng.org>, 2011. +# <cwebber@dustycloud.org>, 2011. +# Jan-Christoph Borchardt <JanCBorchardt@fsfe.org>, 2011. +msgid "" +msgstr "" +"Project-Id-Version: GNU MediaGoblin\n" +"Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" +"POT-Creation-Date: 2011-08-08 22:53-0500\n" +"PO-Revision-Date: 2011-08-10 23:20+0000\n" +"Last-Translator: JanCBorchardt <JanCBorchardt@fsfe.org>\n" +"Language-Team: German (http://www.transifex.net/projects/p/mediagoblin/team/de/)\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: de\n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" + +#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:46 +msgid "Username" +msgstr "Benutzername" + +#: mediagoblin/auth/forms.py:29 mediagoblin/auth/forms.py:50 +msgid "Password" +msgstr "Passwort" + +#: mediagoblin/auth/forms.py:34 +msgid "Passwords must match." +msgstr "Passwörter müssen übereinstimmen." + +#: mediagoblin/auth/forms.py:36 +msgid "Confirm password" +msgstr "Passwort wiederholen" + +#: mediagoblin/auth/forms.py:39 +msgid "Email address" +msgstr "Email-Adresse" + +#: mediagoblin/auth/views.py:40 +msgid "Sorry, registration is disabled on this instance." +msgstr "Registrierung ist auf dieser Instanz leider deaktiviert." + +#: mediagoblin/auth/views.py:55 +msgid "Sorry, a user with that name already exists." +msgstr "Leider gibt es bereits einen Benutzer mit diesem Namen." + +#: mediagoblin/auth/views.py:152 +msgid "" +"Your email address has been verified. You may now login, edit your profile, " +"and submit images!" +msgstr "" +"Deine Email-Adresse wurde bestätigt. Du kannst dich nun anmelden, dein " +"Profil bearbeiten und Bilder hochladen!" + +#: mediagoblin/auth/views.py:158 +msgid "The verification key or user id is incorrect" +msgstr "Der Bestätigungssschlüssel oder die Nutzernummer ist falsch." + +#: mediagoblin/auth/views.py:179 +#: mediagoblin/templates/mediagoblin/auth/resent_verification_email.html:22 +msgid "Resent your verification email." +msgstr "Bestätigungs-Email noch Mal senden." + +#: mediagoblin/edit/forms.py:26 mediagoblin/submit/forms.py:26 +msgid "Title" +msgstr "Titel" + +#: mediagoblin/edit/forms.py:29 +msgid "Slug" +msgstr "Kurztitel" + +#: mediagoblin/edit/forms.py:30 +msgid "The slug can't be empty" +msgstr "Bitte gib einen Kurztitel ein" + +#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:31 +msgid "Tags" +msgstr "Markierungen" + +#: mediagoblin/edit/forms.py:38 +msgid "Bio" +msgstr "Biographie" + +#: mediagoblin/edit/forms.py:41 +msgid "Website" +msgstr "Webseite" + +#: mediagoblin/edit/forms.py:43 +msgid "Improperly formed URL" +msgstr "Adresse fehlerhaft" + +#: mediagoblin/edit/views.py:54 +msgid "An entry with that slug already exists for this user." +msgstr "Diesen Kurztitel hast du bereits vergeben." + +#: mediagoblin/edit/views.py:75 +msgid "You are editing another user's media. Proceed with caution." +msgstr "Du bearbeitest die Medien eines Anderen. Bitte sei vorsichtig." + +#: mediagoblin/edit/views.py:96 +msgid "You are editing a user's profile. Proceed with caution." +msgstr "Du bearbeitest das Profil eines Anderen. Bitte sei vorsichtig." + +#: mediagoblin/submit/forms.py:29 +msgid "File" +msgstr "Datei" + +#: mediagoblin/submit/views.py:45 +msgid "You must provide a file." +msgstr "Du musst eine Datei angeben." + +#: mediagoblin/submit/views.py:48 +msgid "The file doesn't seem to be an image!" +msgstr "Diese Datei scheint kein Bild zu sein!" + +#: mediagoblin/submit/views.py:96 +msgid "Woohoo! Submitted!" +msgstr "Yeeeaaah! Geschafft!" + +#: mediagoblin/templates/mediagoblin/base.html:22 +msgid "GNU MediaGoblin" +msgstr "GNU MediaGoblin" + +#: mediagoblin/templates/mediagoblin/base.html:45 +msgid "Mediagoblin logo" +msgstr "Mediagoblin-Logo" + +#: mediagoblin/templates/mediagoblin/base.html:51 +msgid "Submit media" +msgstr "Medien hochladen" + +#: mediagoblin/templates/mediagoblin/base.html:62 +msgid "verify your email!" +msgstr "Bitte bestätige deine Email-Adresse!" + +#: mediagoblin/templates/mediagoblin/base.html:72 +msgid "Login" +msgstr "Anmelden" + +#: mediagoblin/templates/mediagoblin/base.html:88 +msgid "" +"Powered by <a href=\"http://mediagoblin.org\">MediaGoblin</a>, a <a " +"href=\"http://gnu.org/\">GNU project</a>" +msgstr "" +"Läüft mit <a href=\"http://mediagoblin.org\">MediaGoblin</a>, einem <a " +"href=\"http://gnu.org/\">GNU-Projekt</a>" + +#: mediagoblin/templates/mediagoblin/root.html:21 +msgid "Welcome to GNU MediaGoblin!" +msgstr "Willkommen bei GNU MediaGoblin!" + +#: mediagoblin/templates/mediagoblin/root.html:26 +msgid "Submit an item" +msgstr "Eintrag hochladen" + +#: mediagoblin/templates/mediagoblin/root.html:31 +#, python-format +msgid "If you have an account, you can <a href=\"%(login_url)s\">Login</a>." +msgstr "" +"Falls du ein Konto hast, kannst du dich <a " +"href=\"%(login_url)s\">anmelden</a>." + +#: mediagoblin/templates/mediagoblin/root.html:37 +#, python-format +msgid "" +"If you don't have an account, please <a " +"href=\"%(register_url)s\">Register</a>." +msgstr "" +"Wenn du noch kein Konto hast, <a href=\"%(register_url)s\">registriere " +"dich</a>." + +#: mediagoblin/templates/mediagoblin/auth/login.html:26 +msgid "Log in" +msgstr "Anmelden" + +#: mediagoblin/templates/mediagoblin/auth/login.html:29 +msgid "Login failed!" +msgstr "Anmeldung fehlgeschlagen!" + +#: mediagoblin/templates/mediagoblin/auth/login.html:34 +#: mediagoblin/templates/mediagoblin/auth/register.html:30 +#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 +#: mediagoblin/templates/mediagoblin/submit/start.html:32 +msgid "Submit" +msgstr "Bestätigen" + +#: mediagoblin/templates/mediagoblin/auth/login.html:42 +msgid "Don't have an account yet?" +msgstr "Hast du noch kein Konto?" + +#: mediagoblin/templates/mediagoblin/auth/login.html:45 +msgid "Create one here!" +msgstr "Registriere dich!" + +#: mediagoblin/templates/mediagoblin/auth/register.html:27 +msgid "Create an account!" +msgstr "Neues Konto registrieren!" + +#: 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 "" +"Hi %(username)s,\n" +"\n" +"um dein Konto bei GNU MediaGoblin zu aktivieren, musst du folgende Adresse in einem Webbrowser öffnen:\n" +"\n" +"%(verification_url)s" + +#: mediagoblin/templates/mediagoblin/edit/edit.html:29 +#, python-format +msgid "Editing %(media_title)s" +msgstr "%(media_title)s bearbeiten" + +#: mediagoblin/templates/mediagoblin/edit/edit.html:36 +msgid "Cancel" +msgstr "Abbrechen" + +#: mediagoblin/templates/mediagoblin/edit/edit.html:37 +msgid "Save changes" +msgstr "Änderungen speichern" + +#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:29 +#, python-format +msgid "Editing %(username)s's profile" +msgstr "%(username)s’s Profil barbeiten" + +#: mediagoblin/templates/mediagoblin/listings/tag.html:29 +msgid "Media tagged with:" +msgstr "Medien markiert mit:" + +#: mediagoblin/templates/mediagoblin/listings/tag.html:40 +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:46 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:101 +msgid "atom feed" +msgstr "Atom-Feed" + +#: mediagoblin/templates/mediagoblin/submit/start.html:26 +msgid "Submit yer media" +msgstr "Medien hochladen" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 +#, python-format +msgid "<a href=\"%(user_url)s\">%(username)s</a>'s media" +msgstr "<a href=\"%(user_url)s\">%(username)s</a>’s Medien" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:51 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:30 +msgid "Sorry, no such user found." +msgstr "Dieser Benutzer wurde leider nicht gefunden." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:37 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:57 +msgid "Verification needed" +msgstr "Überprüfung notwendig" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:40 +msgid "Almost done! Your account still needs to be verified." +msgstr "Fast geschafft! Dein Konto muss nur noch bestätigt werden." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:45 +msgid "" +"An email should arrive in a few moments with instructions on how to do so." +msgstr "" +"Gleich solltest du eine Email bekommen, die dir sagt was du noch machen " +"musst." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:49 +msgid "In case it doesn't:" +msgstr "Wenn sie nicht ankommt:" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:52 +msgid "Resend verification email" +msgstr "Bestätigung noch Mal senden" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:60 +msgid "" +"Someone has registered an account with this username, but it still has to be" +" verified." +msgstr "" +"Jemand hat schon ein Konto mit diesem Nutzernamen registriert, aber es muss " +"noch bestätigt werden." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:66 +#, 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 "" +"Wenn dir dieses Konto gehört und die Bestätigungsmail weg ist, kannst du " +"dich <a href=\"%(login_url)s\">anmelden</a> und sie erneut senden." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:76 +#, python-format +msgid "%(username)s's profile" +msgstr "%(username)s’s Profil" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:84 +msgid "Edit profile" +msgstr "Profil bearbeiten" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:95 +#, python-format +msgid "View all of %(username)s's media" +msgstr "Alle Medien von %(username)s anschauen" + + diff --git a/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po new file mode 100644 index 00000000..9c46ebe8 --- /dev/null +++ b/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po @@ -0,0 +1,300 @@ +# Translations template for PROJECT. +# Copyright (C) 2011 ORGANIZATION +# This file is distributed under the same license as the PROJECT project. +# FIRST AUTHOR <EMAIL@ADDRESS>, 2011. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PROJECT VERSION\n" +"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"POT-Creation-Date: 2011-08-13 19:47-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" +"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" + +#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:46 +msgid "Username" +msgstr "" + +#: mediagoblin/auth/forms.py:29 mediagoblin/auth/forms.py:50 +msgid "Password" +msgstr "" + +#: mediagoblin/auth/forms.py:34 +msgid "Passwords must match." +msgstr "" + +#: mediagoblin/auth/forms.py:36 +msgid "Confirm password" +msgstr "" + +#: mediagoblin/auth/forms.py:39 +msgid "Email address" +msgstr "" + +#: mediagoblin/auth/views.py:40 +msgid "Sorry, registration is disabled on this instance." +msgstr "" + +#: mediagoblin/auth/views.py:57 +msgid "Sorry, a user with that name already exists." +msgstr "" + +#: mediagoblin/auth/views.py:61 +msgid "Sorry, that email address has already been taken." +msgstr "" + +#: mediagoblin/auth/views.py:159 +msgid "" +"Your email address has been verified. You may now login, edit your " +"profile, and submit images!" +msgstr "" + +#: mediagoblin/auth/views.py:165 +msgid "The verification key or user id is incorrect" +msgstr "" + +#: mediagoblin/auth/views.py:186 +#: mediagoblin/templates/mediagoblin/auth/resent_verification_email.html:22 +msgid "Resent your verification email." +msgstr "" + +#: mediagoblin/edit/forms.py:26 mediagoblin/submit/forms.py:27 +msgid "Title" +msgstr "" + +#: mediagoblin/edit/forms.py:29 +msgid "Slug" +msgstr "" + +#: mediagoblin/edit/forms.py:30 +msgid "The slug can't be empty" +msgstr "" + +#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:31 +msgid "Tags" +msgstr "" + +#: mediagoblin/edit/forms.py:38 +msgid "Bio" +msgstr "" + +#: mediagoblin/edit/forms.py:41 +msgid "Website" +msgstr "" + +#: mediagoblin/edit/forms.py:43 +msgid "Improperly formed URL" +msgstr "" + +#: mediagoblin/edit/views.py:54 +msgid "An entry with that slug already exists for this user." +msgstr "" + +#: mediagoblin/edit/views.py:75 +msgid "You are editing another user's media. Proceed with caution." +msgstr "" + +#: mediagoblin/edit/views.py:96 +msgid "You are editing a user's profile. Proceed with caution." +msgstr "" + +#: mediagoblin/submit/forms.py:25 +msgid "File" +msgstr "" + +#: mediagoblin/submit/views.py:46 +msgid "You must provide a file." +msgstr "" + +#: mediagoblin/submit/views.py:49 +msgid "The file doesn't seem to be an image!" +msgstr "" + +#: mediagoblin/submit/views.py:94 +msgid "Woohoo! Submitted!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/base.html:22 +msgid "GNU MediaGoblin" +msgstr "" + +#: mediagoblin/templates/mediagoblin/base.html:45 +msgid "Mediagoblin logo" +msgstr "" + +#: mediagoblin/templates/mediagoblin/base.html:51 +msgid "Submit media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/base.html:62 +msgid "verify your email!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/base.html:72 +msgid "Login" +msgstr "" + +#: mediagoblin/templates/mediagoblin/base.html:88 +msgid "" +"Powered by <a href=\"http://mediagoblin.org\">MediaGoblin</a>, a <a " +"href=\"http://gnu.org/\">GNU project</a>" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:23 +msgid "Welcome to GNU MediaGoblin!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:28 +msgid "Submit an item" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:33 +#, python-format +msgid "If you have an account, you can <a href=\"%(login_url)s\">Login</a>." +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:39 +#, python-format +msgid "" +"If you don't have an account, please <a " +"href=\"%(register_url)s\">Register</a>." +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/login.html:26 +msgid "Log in" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/login.html:29 +msgid "Login failed!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/login.html:34 +#: mediagoblin/templates/mediagoblin/auth/register.html:30 +#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 +#: mediagoblin/templates/mediagoblin/submit/start.html:29 +msgid "Submit" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/login.html:42 +msgid "Don't have an account yet?" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/login.html:45 +msgid "Create one here!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/register.html:27 +msgid "Create an account!" +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 "" + +#: mediagoblin/templates/mediagoblin/edit/edit.html:29 +#, python-format +msgid "Editing %(media_title)s" +msgstr "" + +#: mediagoblin/templates/mediagoblin/edit/edit.html:36 +msgid "Cancel" +msgstr "" + +#: mediagoblin/templates/mediagoblin/edit/edit.html:37 +msgid "Save changes" +msgstr "" + +#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:29 +#, python-format +msgid "Editing %(username)s's profile" +msgstr "" + +#: mediagoblin/templates/mediagoblin/listings/tag.html:31 +msgid "Media tagged with:" +msgstr "" + +#: mediagoblin/templates/mediagoblin/listings/tag.html:42 +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:48 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:104 +msgid "atom feed" +msgstr "" + +#: mediagoblin/templates/mediagoblin/submit/start.html:26 +msgid "Submit yer media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:32 +#, python-format +msgid "<a href=\"%(user_url)s\">%(username)s</a>'s media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:53 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:32 +msgid "Sorry, no such user found." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:39 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:59 +msgid "Verification needed" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:42 +msgid "Almost done! Your account still needs to be verified." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:47 +msgid "An email should arrive in a few moments with instructions on how to do so." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:51 +msgid "In case it doesn't:" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:54 +msgid "Resend verification email" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 +msgid "" +"Someone has registered an account with this username, but it still has to" +" be verified." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:68 +#, 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 "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:78 +#, python-format +msgid "%(username)s's profile" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:86 +msgid "Edit profile" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:98 +#, python-format +msgid "View all of %(username)s's media" +msgstr "" + +#: mediagoblin/user_pages/forms.py:24 +msgid "Comment" +msgstr "" + diff --git a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo Binary files differnew file mode 100644 index 00000000..114ab7c0 --- /dev/null +++ b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo diff --git a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po new file mode 100644 index 00000000..ea19af01 --- /dev/null +++ b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po @@ -0,0 +1,319 @@ +# Translations template for PROJECT. +# Copyright (C) 2011 ORGANIZATION +# This file is distributed under the same license as the PROJECT project. +# +# <john_w1954@fastmail.fm>, 2011. +# Fernando Inocencio <faigos@gmail.com>, 2011. +msgid "" +msgstr "" +"Project-Id-Version: GNU MediaGoblin\n" +"Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" +"POT-Creation-Date: 2011-08-13 19:47-0500\n" +"PO-Revision-Date: 2011-08-15 20:33+0000\n" +"Last-Translator: fajro <faigos@gmail.com>\n" +"Language-Team: LANGUAGE <LL@li.org>\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: eo\n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" + +#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:46 +msgid "Username" +msgstr "Uzantnomo" + +#: mediagoblin/auth/forms.py:29 mediagoblin/auth/forms.py:50 +msgid "Password" +msgstr "Pasvorton" + +#: mediagoblin/auth/forms.py:34 +msgid "Passwords must match." +msgstr "Pasvortoj devas koincidi. " + +#: mediagoblin/auth/forms.py:36 +msgid "Confirm password" +msgstr "Retajpu pasvorton" + +#: mediagoblin/auth/forms.py:39 +msgid "Email address" +msgstr "Retadreso" + +#: mediagoblin/auth/views.py:40 +msgid "Sorry, registration is disabled on this instance." +msgstr "Bedaŭrinde, registrado estas malaktivita en tiu ĉi instanco." + +#: mediagoblin/auth/views.py:57 +msgid "Sorry, a user with that name already exists." +msgstr "Bedaŭrinde, uzanto kun tiu nomo jam ekzistas." + +#: mediagoblin/auth/views.py:61 +msgid "Sorry, that email address has already been taken." +msgstr "" + +#: mediagoblin/auth/views.py:159 +msgid "" +"Your email address has been verified. You may now login, edit your profile, " +"and submit images!" +msgstr "" +"Vian retadreson estas kontrolita. Vi povas nun ensaluti, redakti vian " +"profilon, kaj alŝuti bildojn!" + +#: mediagoblin/auth/views.py:165 +msgid "The verification key or user id is incorrect" +msgstr "La kontrol-kodo aŭ la uzantonomo ne estas korekta" + +#: mediagoblin/auth/views.py:186 +#: mediagoblin/templates/mediagoblin/auth/resent_verification_email.html:22 +msgid "Resent your verification email." +msgstr "Resendi vian kontrol-mesaĝon." + +#: mediagoblin/edit/forms.py:26 mediagoblin/submit/forms.py:27 +msgid "Title" +msgstr "Titolo" + +#: mediagoblin/edit/forms.py:29 +msgid "Slug" +msgstr "" + +#: mediagoblin/edit/forms.py:30 +msgid "The slug can't be empty" +msgstr "" + +#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:31 +msgid "Tags" +msgstr "Etikedoj" + +#: mediagoblin/edit/forms.py:38 +msgid "Bio" +msgstr "Bio" + +#: mediagoblin/edit/forms.py:41 +msgid "Website" +msgstr "Retejo" + +#: mediagoblin/edit/forms.py:43 +msgid "Improperly formed URL" +msgstr "" + +#: mediagoblin/edit/views.py:54 +msgid "An entry with that slug already exists for this user." +msgstr "" + +#: mediagoblin/edit/views.py:75 +msgid "You are editing another user's media. Proceed with caution." +msgstr "" + +#: mediagoblin/edit/views.py:96 +msgid "You are editing a user's profile. Proceed with caution." +msgstr "" + +#: mediagoblin/submit/forms.py:25 +msgid "File" +msgstr "Dosiero" + +#: mediagoblin/submit/views.py:46 +msgid "You must provide a file." +msgstr "Vi devas provizi dosieron." + +#: mediagoblin/submit/views.py:49 +msgid "The file doesn't seem to be an image!" +msgstr "" + +#: mediagoblin/submit/views.py:94 +msgid "Woohoo! Submitted!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/base.html:22 +msgid "GNU MediaGoblin" +msgstr "GNU MediaGoblin" + +#: mediagoblin/templates/mediagoblin/base.html:45 +msgid "Mediagoblin logo" +msgstr " Logogramo de Mediagoblin" + +#: mediagoblin/templates/mediagoblin/base.html:51 +msgid "Submit media" +msgstr "Alŝuti aŭd-vid-dosieron" + +#: mediagoblin/templates/mediagoblin/base.html:62 +msgid "verify your email!" +msgstr "kontrolu vian retpoŝton! " + +#: mediagoblin/templates/mediagoblin/base.html:72 +msgid "Login" +msgstr "Ensaluti" + +#: mediagoblin/templates/mediagoblin/base.html:88 +msgid "" +"Powered by <a href=\"http://mediagoblin.org\">MediaGoblin</a>, a <a " +"href=\"http://gnu.org/\">GNU project</a>" +msgstr "" +"Provizita de <a href=\"http://mediagoblin.org\">MediaGoblin</a>, unu el la " +"<a href=\"http://gnu.org/\">GNU projectoj</a>" + +#: mediagoblin/templates/mediagoblin/root.html:23 +msgid "Welcome to GNU MediaGoblin!" +msgstr "Bonvenon al GNU MediaGoblin!" + +#: mediagoblin/templates/mediagoblin/root.html:28 +msgid "Submit an item" +msgstr "Alŝuti dosieron" + +#: mediagoblin/templates/mediagoblin/root.html:33 +#, python-format +msgid "If you have an account, you can <a href=\"%(login_url)s\">Login</a>." +msgstr "Se vi havas konton, vi povas <a href=\"%(login_url)s\">Ensaluti</a>." + +#: mediagoblin/templates/mediagoblin/root.html:39 +#, python-format +msgid "" +"If you don't have an account, please <a " +"href=\"%(register_url)s\">Register</a>." +msgstr "" +"Se vi ne havas konton, bonvolu <a href=\"%(register_url)s\">Registriĝi</a>." + +#: mediagoblin/templates/mediagoblin/auth/login.html:26 +msgid "Log in" +msgstr "Ensaluti" + +#: mediagoblin/templates/mediagoblin/auth/login.html:29 +msgid "Login failed!" +msgstr "Ensalutado malsukcesis!" + +#: mediagoblin/templates/mediagoblin/auth/login.html:34 +#: mediagoblin/templates/mediagoblin/auth/register.html:30 +#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 +#: mediagoblin/templates/mediagoblin/submit/start.html:29 +msgid "Submit" +msgstr "Alŝuti" + +#: mediagoblin/templates/mediagoblin/auth/login.html:42 +msgid "Don't have an account yet?" +msgstr "Ĉu ankoraŭ sen konto?" + +#: mediagoblin/templates/mediagoblin/auth/login.html:45 +msgid "Create one here!" +msgstr "Kreu unu ĉi tie!" + +#: mediagoblin/templates/mediagoblin/auth/register.html:27 +msgid "Create an account!" +msgstr "Kreu konton!" + +#: 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 "" +"Sal %(username)s,\n" +"\n" +"por aktivigi vian GNU MediaGoblin konton, malfermu la sekvantan URLon en via retumilo:\n" +"\n" +"%(verification_url)s" + +#: mediagoblin/templates/mediagoblin/edit/edit.html:29 +#, python-format +msgid "Editing %(media_title)s" +msgstr "Editing %(media_title)s" + +#: mediagoblin/templates/mediagoblin/edit/edit.html:36 +msgid "Cancel" +msgstr "Nuligi" + +#: mediagoblin/templates/mediagoblin/edit/edit.html:37 +msgid "Save changes" +msgstr "Konservi ŝanĝojn" + +#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:29 +#, python-format +msgid "Editing %(username)s's profile" +msgstr "Redaktanta profilon de %(username)s'" + +#: mediagoblin/templates/mediagoblin/listings/tag.html:31 +msgid "Media tagged with:" +msgstr "Dosiero markita kiel:" + +#: mediagoblin/templates/mediagoblin/listings/tag.html:42 +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:48 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:104 +msgid "atom feed" +msgstr "Atom-a informfluado" + +#: mediagoblin/templates/mediagoblin/submit/start.html:26 +msgid "Submit yer media" +msgstr "Alŝutu vian aŭd-vid-dosieron" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:32 +#, python-format +msgid "<a href=\"%(user_url)s\">%(username)s</a>'s media" +msgstr "<a href=\"%(user_url)s\">%(username)s</a>-a aŭd-vid-dosiero" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:53 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:32 +msgid "Sorry, no such user found." +msgstr "Uzanto ne trovita." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:39 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:59 +msgid "Verification needed" +msgstr "Kontrolon bezonata" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:42 +msgid "Almost done! Your account still needs to be verified." +msgstr "Preskaŭ farite! Via konto ankoraŭ devas esti kontrolita." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:47 +msgid "" +"An email should arrive in a few moments with instructions on how to do so." +msgstr "" +"Retmesaĝo alvenos post kelkaj momentoj kun instrukcioj pri kiel tion fari." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:51 +msgid "In case it doesn't:" +msgstr "Se tio ne okazas:" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:54 +msgid "Resend verification email" +msgstr "Resendu kontrolmesaĝon" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 +msgid "" +"Someone has registered an account with this username, but it still has to be" +" verified." +msgstr "" +"Iu registris konton kun tiu ĉi uzantonomo, sed ĝi devas ankoraŭ esti " +"kontrolita." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:68 +#, 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 "" +"Se vi estas tiu sed vi perdis vian kontrolmesaĝon, vi povas <a " +"href=\"%(login_url)s\">ensaluti</a> kaj resendi ĝin." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:78 +#, python-format +msgid "%(username)s's profile" +msgstr "%(username)s'-a profilo" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:86 +msgid "Edit profile" +msgstr "Redakti profilo" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:98 +#, python-format +msgid "View all of %(username)s's media" +msgstr "Rigardu ĉiuj aŭd-vid-dosierojn de %(username)s'" + +#: mediagoblin/user_pages/forms.py:24 +msgid "Comment" +msgstr "Komento" + + diff --git a/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo Binary files differnew file mode 100644 index 00000000..dfd3a1bc --- /dev/null +++ b/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo diff --git a/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po new file mode 100644 index 00000000..0a12586c --- /dev/null +++ b/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po @@ -0,0 +1,312 @@ +# Translations template for PROJECT. +# Copyright (C) 2011 ORGANIZATION +# This file is distributed under the same license as the PROJECT project. +# +# <jacobo@gnu.org>, 2011. +msgid "" +msgstr "" +"Project-Id-Version: GNU MediaGoblin\n" +"Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" +"POT-Creation-Date: 2011-08-08 22:53-0500\n" +"PO-Revision-Date: 2011-08-10 20:30+0000\n" +"Last-Translator: nvjacobo <jacobo@gnu.org>\n" +"Language-Team: Spanish (Castilian) (http://www.transifex.net/projects/p/mediagoblin/team/es/)\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: es\n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" + +#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:46 +msgid "Username" +msgstr "Nombre de Usuario" + +#: mediagoblin/auth/forms.py:29 mediagoblin/auth/forms.py:50 +msgid "Password" +msgstr "Contraseña" + +#: mediagoblin/auth/forms.py:34 +msgid "Passwords must match." +msgstr "Las contraseñas deben coincidir." + +#: mediagoblin/auth/forms.py:36 +msgid "Confirm password" +msgstr "Confirme su contraseña" + +#: mediagoblin/auth/forms.py:39 +msgid "Email address" +msgstr "Dirección de correo electrónico" + +#: mediagoblin/auth/views.py:40 +msgid "Sorry, registration is disabled on this instance." +msgstr "Lo sentimos, el registro está deshabilitado en este momento." + +#: mediagoblin/auth/views.py:55 +msgid "Sorry, a user with that name already exists." +msgstr "Lo sentimos, un usuario con ese nombre ya existe." + +#: mediagoblin/auth/views.py:152 +msgid "" +"Your email address has been verified. You may now login, edit your profile, " +"and submit images!" +msgstr "" +"Su dirección de correo electrónico ha sido verificada. Ahora puede ingresar," +" editar su perfil, y enviar las imágenes!" + +#: mediagoblin/auth/views.py:158 +msgid "The verification key or user id is incorrect" +msgstr "" +"La clave de la verificación o la identificación del usuario es incorrecta" + +#: mediagoblin/auth/views.py:179 +#: mediagoblin/templates/mediagoblin/auth/resent_verification_email.html:22 +msgid "Resent your verification email." +msgstr "Reenvíe su correo electrónico de verificación" + +#: mediagoblin/edit/forms.py:26 mediagoblin/submit/forms.py:26 +msgid "Title" +msgstr "Título" + +#: mediagoblin/edit/forms.py:29 +msgid "Slug" +msgstr "Ficha" + +#: mediagoblin/edit/forms.py:30 +msgid "The slug can't be empty" +msgstr "La ficha no puede estar vacia" + +#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:31 +msgid "Tags" +msgstr "Etiquetas" + +#: mediagoblin/edit/forms.py:38 +msgid "Bio" +msgstr "Bio" + +#: mediagoblin/edit/forms.py:41 +msgid "Website" +msgstr "Sitio web" + +#: mediagoblin/edit/forms.py:43 +msgid "Improperly formed URL" +msgstr "URL de forma incorrecta" + +#: mediagoblin/edit/views.py:54 +msgid "An entry with that slug already exists for this user." +msgstr "Una entrada con esa ficha ya existe para este usuario." + +#: mediagoblin/edit/views.py:75 +msgid "You are editing another user's media. Proceed with caution." +msgstr "" +"Usted está editando el contenido de otro usuario. Proceder con precaución." + +#: mediagoblin/edit/views.py:96 +msgid "You are editing a user's profile. Proceed with caution." +msgstr "Usted está editando un perfil de usuario. Proceder con precaucións." + +#: mediagoblin/submit/forms.py:29 +msgid "File" +msgstr "Archivo" + +#: mediagoblin/submit/views.py:45 +msgid "You must provide a file." +msgstr "Usted debe proporcionar un archivo." + +#: mediagoblin/submit/views.py:48 +msgid "The file doesn't seem to be an image!" +msgstr "El archivo no parece ser una imagen!" + +#: mediagoblin/submit/views.py:96 +msgid "Woohoo! Submitted!" +msgstr "Woohoo! Enviado!" + +#: mediagoblin/templates/mediagoblin/base.html:22 +msgid "GNU MediaGoblin" +msgstr "GNU MediaGoblin" + +#: mediagoblin/templates/mediagoblin/base.html:45 +msgid "Mediagoblin logo" +msgstr "Mediagoblin logo" + +#: mediagoblin/templates/mediagoblin/base.html:51 +msgid "Submit media" +msgstr "Enviar contenido" + +#: mediagoblin/templates/mediagoblin/base.html:62 +msgid "verify your email!" +msgstr "Verifique su correo electrónico" + +#: mediagoblin/templates/mediagoblin/base.html:72 +msgid "Login" +msgstr "Conectarse" + +#: mediagoblin/templates/mediagoblin/base.html:88 +msgid "" +"Powered by <a href=\"http://mediagoblin.org\">MediaGoblin</a>, a <a " +"href=\"http://gnu.org/\">GNU project</a>" +msgstr "" +"Potenciado por <a href=\"http://mediagoblin.org\">MediaGoblin</a>, a <a " +"href=\"http://gnu.org/\">GNU project</a>" + +#: mediagoblin/templates/mediagoblin/root.html:21 +msgid "Welcome to GNU MediaGoblin!" +msgstr "¡Bienvenido a GNU MediaGoblin!" + +#: mediagoblin/templates/mediagoblin/root.html:26 +msgid "Submit an item" +msgstr "Enviar un item" + +#: mediagoblin/templates/mediagoblin/root.html:31 +#, python-format +msgid "If you have an account, you can <a href=\"%(login_url)s\">Login</a>." +msgstr "" +"Si tiene una cuenta, puede iniciar sesión <a " +"href=\"%(login_url)s\">Login</a>." + +#: mediagoblin/templates/mediagoblin/root.html:37 +#, python-format +msgid "" +"If you don't have an account, please <a " +"href=\"%(register_url)s\">Register</a>." +msgstr "" +"Si no tienes una cuenta, por favor, <a " +"href=\"%(register_url)s\">Regístrese</a> ." + +#: mediagoblin/templates/mediagoblin/auth/login.html:26 +msgid "Log in" +msgstr "Conectarse" + +#: mediagoblin/templates/mediagoblin/auth/login.html:29 +msgid "Login failed!" +msgstr "El inicio de sesión fallo" + +#: mediagoblin/templates/mediagoblin/auth/login.html:34 +#: mediagoblin/templates/mediagoblin/auth/register.html:30 +#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 +#: mediagoblin/templates/mediagoblin/submit/start.html:32 +msgid "Submit" +msgstr "Enviar" + +#: mediagoblin/templates/mediagoblin/auth/login.html:42 +msgid "Don't have an account yet?" +msgstr "¿No tienes una cuenta?" + +#: mediagoblin/templates/mediagoblin/auth/login.html:45 +msgid "Create one here!" +msgstr "Crea una aquí" + +#: mediagoblin/templates/mediagoblin/auth/register.html:27 +msgid "Create an account!" +msgstr "Crea una cuenta!" + +#: 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 "" +"Hola %(username)s , para activar su cuenta MediaGoblin GNU, abra ls " +"siguiente URL en su navegador: %(verification_url)s " + +#: mediagoblin/templates/mediagoblin/edit/edit.html:29 +#, python-format +msgid "Editing %(media_title)s" +msgstr "Edición %(media_title)s " + +#: mediagoblin/templates/mediagoblin/edit/edit.html:36 +msgid "Cancel" +msgstr "Cancelar" + +#: mediagoblin/templates/mediagoblin/edit/edit.html:37 +msgid "Save changes" +msgstr "Salvar cambios" + +#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:29 +#, python-format +msgid "Editing %(username)s's profile" +msgstr "Edición %(username)s de perfil" + +#: mediagoblin/templates/mediagoblin/listings/tag.html:29 +msgid "Media tagged with:" +msgstr "El contenido con la etiqueta:" + +#: mediagoblin/templates/mediagoblin/listings/tag.html:40 +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:46 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:101 +msgid "atom feed" +msgstr "feed Atom" + +#: mediagoblin/templates/mediagoblin/submit/start.html:26 +msgid "Submit yer media" +msgstr "Envíe su contenido" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 +#, python-format +msgid "<a href=\"%(user_url)s\">%(username)s</a>'s media" +msgstr "Contenido de <a href=\"%(user_url)s\">%(username)s</a>'s" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:51 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:30 +msgid "Sorry, no such user found." +msgstr "Lo sentimos, no se ha encontrado el usuario." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:37 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:57 +msgid "Verification needed" +msgstr "Verificación necesaria" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:40 +msgid "Almost done! Your account still needs to be verified." +msgstr "Ya está casi hecho! Su cuenta tiene que ser verificada." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:45 +msgid "" +"An email should arrive in a few moments with instructions on how to do so." +msgstr "" +"Un e-mail debe llegar en unos momentos con las instrucciones para hacerlo." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:49 +msgid "In case it doesn't:" +msgstr "En caso de que no:" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:52 +msgid "Resend verification email" +msgstr "Reenviar correo electrónico de verificación" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:60 +msgid "" +"Someone has registered an account with this username, but it still has to be" +" verified." +msgstr "" +"Alguien ha registrado una cuenta con este nombre de usuario, pero todavía " +"tiene que ser verificado." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:66 +#, 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 "" +"Si usted es esa persona, pero usted ha perdido su correo electrónico de " +"verificación, usted puede reenviarlo <a href=\"%(login_url)s\">acceder</a>." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:76 +#, python-format +msgid "%(username)s's profile" +msgstr "Perfil de %(username)s's" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:84 +msgid "Edit profile" +msgstr "Editar perfil" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:95 +#, python-format +msgid "View all of %(username)s's media" +msgstr "Ver todo el contenido de %(username)s's " + + diff --git a/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo Binary files differnew file mode 100644 index 00000000..f8854734 --- /dev/null +++ b/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo diff --git a/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po new file mode 100644 index 00000000..5afe7091 --- /dev/null +++ b/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po @@ -0,0 +1,329 @@ +# Translations template for PROJECT. +# Copyright (C) 2011 ORGANIZATION +# This file is distributed under the same license as the PROJECT project. +# +# <marktraceur@gmail.com>, 2011. +# Valentin Villenave <valentin@villenave.net>, 2011. +# <transifex@wandborg.se>, 2011. +msgid "" +msgstr "" +"Project-Id-Version: GNU MediaGoblin\n" +"Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" +"POT-Creation-Date: 2011-08-13 19:47-0500\n" +"PO-Revision-Date: 2011-08-16 13:22+0000\n" +"Last-Translator: joar <transifex@wandborg.se>\n" +"Language-Team: LANGUAGE <LL@li.org>\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: fr\n" +"Plural-Forms: nplurals=2; plural=(n > 1)\n" + +#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:46 +msgid "Username" +msgstr "Nom d'utilisateur" + +#: mediagoblin/auth/forms.py:29 mediagoblin/auth/forms.py:50 +msgid "Password" +msgstr "Mot de passe" + +#: mediagoblin/auth/forms.py:34 +msgid "Passwords must match." +msgstr "Les mots de passe doivent correspondre." + +#: mediagoblin/auth/forms.py:36 +msgid "Confirm password" +msgstr "Confirmer le mot de passe" + +#: mediagoblin/auth/forms.py:39 +msgid "Email address" +msgstr "Adresse e-mail" + +#: mediagoblin/auth/views.py:40 +msgid "Sorry, registration is disabled on this instance." +msgstr "L'inscription n'est pas activée sur ce serveur, désolé." + +#: mediagoblin/auth/views.py:57 +msgid "Sorry, a user with that name already exists." +msgstr "Un utilisateur existe déjà avec ce nom, désolé." + +#: mediagoblin/auth/views.py:61 +msgid "Sorry, that email address has already been taken." +msgstr "" + +#: mediagoblin/auth/views.py:159 +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:165 +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:186 +#: mediagoblin/templates/mediagoblin/auth/resent_verification_email.html:22 +msgid "Resent your verification email." +msgstr "E-mail de vérification renvoyé." + +#: mediagoblin/edit/forms.py:26 mediagoblin/submit/forms.py:27 +msgid "Title" +msgstr "Titre" + +#: mediagoblin/edit/forms.py:29 +msgid "Slug" +msgstr "Légende" + +#: mediagoblin/edit/forms.py:30 +msgid "The slug can't be empty" +msgstr "La légende ne peut pas être laissée vide." + +#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:31 +msgid "Tags" +msgstr "Tags" + +#: mediagoblin/edit/forms.py:38 +msgid "Bio" +msgstr "Bio" + +#: mediagoblin/edit/forms.py:41 +msgid "Website" +msgstr "Site web" + +#: mediagoblin/edit/forms.py:43 +msgid "Improperly formed URL" +msgstr "Adresse web mal formée" + +#: mediagoblin/edit/views.py:54 +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." + +#: mediagoblin/edit/views.py:75 +msgid "You are editing another user's media. Proceed with caution." +msgstr "" +"Vous vous apprêtez à modifier le média d'un autre utilisateur. Veuillez " +"prendre garde." + +#: mediagoblin/edit/views.py:96 +msgid "You are editing a user's profile. Proceed with caution." +msgstr "" +"Vous vous apprêtez à modifier le profil d'un utilisateur. Veuillez prendre " +"garde." + +#: mediagoblin/submit/forms.py:25 +msgid "File" +msgstr "Fichier" + +#: mediagoblin/submit/views.py:46 +msgid "You must provide a file." +msgstr "Il vous faut fournir un fichier." + +#: mediagoblin/submit/views.py:49 +msgid "The file doesn't seem to be an image!" +msgstr "Ce fichier ne semble pas être une image !" + +#: mediagoblin/submit/views.py:94 +msgid "Woohoo! Submitted!" +msgstr "Youhou, c'est envoyé !" + +#: mediagoblin/templates/mediagoblin/base.html:22 +msgid "GNU MediaGoblin" +msgstr "GNU MediaGoblin" + +#: mediagoblin/templates/mediagoblin/base.html:45 +msgid "Mediagoblin logo" +msgstr "logo de MediaGoblin" + +#: mediagoblin/templates/mediagoblin/base.html:51 +msgid "Submit media" +msgstr "Soumettre un média" + +#: mediagoblin/templates/mediagoblin/base.html:62 +msgid "verify your email!" +msgstr "vérifier son adresse e-mail" + +#: mediagoblin/templates/mediagoblin/base.html:72 +msgid "Login" +msgstr "Identification" + +#: mediagoblin/templates/mediagoblin/base.html:88 +msgid "" +"Powered by <a href=\"http://mediagoblin.org\">MediaGoblin</a>, a <a " +"href=\"http://gnu.org/\">GNU project</a>" +msgstr "" +"Propulsé par <a href=\"http://mediagoblin.org\">MediaGoblin</a>, un projet " +"de <a href=\"http://gnu.org/\">GNU</a>" + +#: mediagoblin/templates/mediagoblin/root.html:23 +msgid "Welcome to GNU MediaGoblin!" +msgstr "Bienvenue sur GNU MediaGoblin !" + +#: mediagoblin/templates/mediagoblin/root.html:28 +msgid "Submit an item" +msgstr "Soumettre un fichier" + +#: mediagoblin/templates/mediagoblin/root.html:33 +#, python-format +msgid "If you have an account, you can <a href=\"%(login_url)s\">Login</a>." +msgstr "" +"Si vous avez un compte, vous pouvez vous <a " +"href=\"%(login_url)s\">identifier</a>." + +#: mediagoblin/templates/mediagoblin/root.html:39 +#, python-format +msgid "" +"If you don't have an account, please <a " +"href=\"%(register_url)s\">Register</a>." +msgstr "" +"Si vous n'avez pas de compte, veuillez vous <a " +"href=\"%(register_url)s\">inscrire</a>." + +#: mediagoblin/templates/mediagoblin/auth/login.html:26 +msgid "Log in" +msgstr "S'identifier" + +#: mediagoblin/templates/mediagoblin/auth/login.html:29 +msgid "Login failed!" +msgstr "L'identification a échoué !" + +#: mediagoblin/templates/mediagoblin/auth/login.html:34 +#: mediagoblin/templates/mediagoblin/auth/register.html:30 +#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 +#: mediagoblin/templates/mediagoblin/submit/start.html:29 +msgid "Submit" +msgstr "Soumettre" + +#: mediagoblin/templates/mediagoblin/auth/login.html:42 +msgid "Don't have an account yet?" +msgstr "Pas encore de compte ?" + +#: mediagoblin/templates/mediagoblin/auth/login.html:45 +msgid "Create one here!" +msgstr "Créez-en un ici !" + +#: mediagoblin/templates/mediagoblin/auth/register.html:27 +msgid "Create an account!" +msgstr "Créer un compte !" + +#: 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 "" +"Bonjour %(username)s,\n" +"\n" +"pour activer votre compte sur GNU MediaGoblin, veuillez vous rendre à l'adresse suivante avec votre navigateur web:\n" +"\n" +"%(verification_url)s" + +#: mediagoblin/templates/mediagoblin/edit/edit.html:29 +#, python-format +msgid "Editing %(media_title)s" +msgstr "Modification de %(media_title)s" + +#: mediagoblin/templates/mediagoblin/edit/edit.html:36 +msgid "Cancel" +msgstr "Annuler" + +#: mediagoblin/templates/mediagoblin/edit/edit.html:37 +msgid "Save changes" +msgstr "Enregistrer les modifications" + +#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:29 +#, python-format +msgid "Editing %(username)s's profile" +msgstr "Modification du profil de %(username)s" + +#: mediagoblin/templates/mediagoblin/listings/tag.html:31 +msgid "Media tagged with:" +msgstr "Média comportant les tags suivants :" + +#: mediagoblin/templates/mediagoblin/listings/tag.html:42 +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:48 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:104 +msgid "atom feed" +msgstr "flux Atom" + +#: mediagoblin/templates/mediagoblin/submit/start.html:26 +msgid "Submit yer media" +msgstr "Soumettez ce média" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:32 +#, python-format +msgid "<a href=\"%(user_url)s\">%(username)s</a>'s media" +msgstr "Médias de <a href=\"%(user_url)s\">%(username)s</a>" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:53 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:32 +msgid "Sorry, no such user found." +msgstr "Impossible de trouver cet utilisateur, désolé." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:39 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:59 +msgid "Verification needed" +msgstr "Vérification requise" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:42 +msgid "Almost done! Your account still needs to be verified." +msgstr "C'est presque fini ! Il vous faut encore vérifier votre compte." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:47 +msgid "" +"An email should arrive in a few moments with instructions on how to do so." +msgstr "" +"Un e-mail devrait vous parvenir dans quelques instants ; il vous indiquera " +"comment procéder." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:51 +msgid "In case it doesn't:" +msgstr "Si la vérification n'est pas arrivée à bon port :" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:54 +msgid "Resend verification email" +msgstr "Renvoyer l'e-mail de vérification" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 +msgid "" +"Someone has registered an account with this username, but it still has to be" +" verified." +msgstr "" +"Quelqu'un a créé un compte à ce nom, mais le compte n'a pas encore été " +"vérifié." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:68 +#, 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 "" +"Si c'est de vous qu'il s'agit, mais que vous avez perdu l'e-mail de " +"vérification, vous pouvez vous <a href=\"%(login_url)s\">identifier</a> et " +"le renvoyer." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:78 +#, python-format +msgid "%(username)s's profile" +msgstr "profil de %(username)s" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:86 +msgid "Edit profile" +msgstr "Modifier le profil" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:98 +#, python-format +msgid "View all of %(username)s's media" +msgstr "Voir tous les médias de %(username)s" + +#: mediagoblin/user_pages/forms.py:24 +msgid "Comment" +msgstr "" + + diff --git a/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.mo Binary files differnew file mode 100644 index 00000000..78455ad2 --- /dev/null +++ b/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.mo diff --git a/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po new file mode 100644 index 00000000..0aba5755 --- /dev/null +++ b/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po @@ -0,0 +1,310 @@ +# Translations template for PROJECT. +# Copyright (C) 2011 ORGANIZATION +# This file is distributed under the same license as the PROJECT project. +# +# <averym@gmail.com>, 2011. +msgid "" +msgstr "" +"Project-Id-Version: GNU MediaGoblin\n" +"Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" +"POT-Creation-Date: 2011-08-13 19:47-0500\n" +"PO-Revision-Date: 2011-08-14 00:47+0000\n" +"Last-Translator: cwebber <cwebber@dustycloud.org>\n" +"Language-Team: LANGUAGE <LL@li.org>\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: ja\n" +"Plural-Forms: nplurals=1; plural=0\n" + +#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:46 +msgid "Username" +msgstr "ユーザネーム" + +#: mediagoblin/auth/forms.py:29 mediagoblin/auth/forms.py:50 +msgid "Password" +msgstr "パスワード" + +#: mediagoblin/auth/forms.py:34 +msgid "Passwords must match." +msgstr "パスワードが一致している必要があります。" + +#: mediagoblin/auth/forms.py:36 +msgid "Confirm password" +msgstr "パスワードを確認" + +#: mediagoblin/auth/forms.py:39 +msgid "Email address" +msgstr "メールアドレス" + +#: mediagoblin/auth/views.py:40 +msgid "Sorry, registration is disabled on this instance." +msgstr "申し訳ありませんが、このインスタンスで登録は無効になっています。" + +#: mediagoblin/auth/views.py:57 +msgid "Sorry, a user with that name already exists." +msgstr "申し訳ありませんが、その名前を持つユーザーがすでに存在しています。" + +#: mediagoblin/auth/views.py:61 +msgid "Sorry, that email address has already been taken." +msgstr "" + +#: mediagoblin/auth/views.py:159 +msgid "" +"Your email address has been verified. You may now login, edit your profile, " +"and submit images!" +msgstr "メアドが確認されています。これで、ログインしてプロファイルを編集し、画像を提出することができます!" + +#: mediagoblin/auth/views.py:165 +msgid "The verification key or user id is incorrect" +msgstr "検証キーまたはユーザーIDが間違っています" + +#: mediagoblin/auth/views.py:186 +#: mediagoblin/templates/mediagoblin/auth/resent_verification_email.html:22 +msgid "Resent your verification email." +msgstr "検証メールを再送しました。" + +#: mediagoblin/edit/forms.py:26 mediagoblin/submit/forms.py:27 +msgid "Title" +msgstr "タイトル" + +#: mediagoblin/edit/forms.py:29 +msgid "Slug" +msgstr "スラグ" + +#: mediagoblin/edit/forms.py:30 +msgid "The slug can't be empty" +msgstr "スラグは必要です。" + +#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:31 +msgid "Tags" +msgstr "タグ" + +#: mediagoblin/edit/forms.py:38 +msgid "Bio" +msgstr "自己紹介" + +#: mediagoblin/edit/forms.py:41 +msgid "Website" +msgstr "URL" + +#: mediagoblin/edit/forms.py:43 +msgid "Improperly formed URL" +msgstr "不適切な形式のURL" + +#: mediagoblin/edit/views.py:54 +msgid "An entry with that slug already exists for this user." +msgstr "そのスラグを持つエントリは、このユーザーは既に存在します。" + +#: mediagoblin/edit/views.py:75 +msgid "You are editing another user's media. Proceed with caution." +msgstr "あなたは、他のユーザーのメディアを編集しています。ご注意ください。" + +#: mediagoblin/edit/views.py:96 +msgid "You are editing a user's profile. Proceed with caution." +msgstr "あなたは、他のユーザーのプロファイルを編集しています。ご注意ください。" + +#: mediagoblin/submit/forms.py:25 +msgid "File" +msgstr "ファイル" + +#: mediagoblin/submit/views.py:46 +msgid "You must provide a file." +msgstr "ファイルを提供する必要があります。" + +#: mediagoblin/submit/views.py:49 +msgid "The file doesn't seem to be an image!" +msgstr "ファイルが画像ではないようです!" + +#: mediagoblin/submit/views.py:94 +msgid "Woohoo! Submitted!" +msgstr "投稿終了!" + +#: mediagoblin/templates/mediagoblin/base.html:22 +msgid "GNU MediaGoblin" +msgstr "GNU MediaGoblin" + +#: mediagoblin/templates/mediagoblin/base.html:45 +msgid "Mediagoblin logo" +msgstr "MediaGoblinロゴ" + +#: mediagoblin/templates/mediagoblin/base.html:51 +msgid "Submit media" +msgstr "コンテンツを投稿" + +#: mediagoblin/templates/mediagoblin/base.html:62 +msgid "verify your email!" +msgstr "メアドを確認してください!" + +#: mediagoblin/templates/mediagoblin/base.html:72 +msgid "Login" +msgstr "ログイン" + +#: mediagoblin/templates/mediagoblin/base.html:88 +msgid "" +"Powered by <a href=\"http://mediagoblin.org\">MediaGoblin</a>, a <a " +"href=\"http://gnu.org/\">GNU project</a>" +msgstr "" +"Powered by <a href=\"http://mediagoblin.org\">MediaGoblin</a>, a <a " +"href=\"http://gnu.org/\">GNU project</a>" + +#: mediagoblin/templates/mediagoblin/root.html:23 +msgid "Welcome to GNU MediaGoblin!" +msgstr "GNU MediaGoblinへようこそ!" + +#: mediagoblin/templates/mediagoblin/root.html:28 +msgid "Submit an item" +msgstr "アイテムを投稿" + +#: mediagoblin/templates/mediagoblin/root.html:33 +#, python-format +msgid "If you have an account, you can <a href=\"%(login_url)s\">Login</a>." +msgstr "もしアカウントが持ったら、<a href=\"%(login_url)s\">ログイン</a>できます。" + +#: mediagoblin/templates/mediagoblin/root.html:39 +#, python-format +msgid "" +"If you don't have an account, please <a " +"href=\"%(register_url)s\">Register</a>." +msgstr "アカウントが持っていなければ、<a href=\"%(register_url)s\">登録</a>してお願いします。" + +#: mediagoblin/templates/mediagoblin/auth/login.html:26 +msgid "Log in" +msgstr "ログイン" + +#: mediagoblin/templates/mediagoblin/auth/login.html:29 +msgid "Login failed!" +msgstr "ログイン失敗!" + +#: mediagoblin/templates/mediagoblin/auth/login.html:34 +#: mediagoblin/templates/mediagoblin/auth/register.html:30 +#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 +#: mediagoblin/templates/mediagoblin/submit/start.html:29 +msgid "Submit" +msgstr "送信" + +#: mediagoblin/templates/mediagoblin/auth/login.html:42 +msgid "Don't have an account yet?" +msgstr "まだアカウントを持っていませんか?" + +#: mediagoblin/templates/mediagoblin/auth/login.html:45 +msgid "Create one here!" +msgstr "ここで作成!" + +#: mediagoblin/templates/mediagoblin/auth/register.html:27 +msgid "Create an account!" +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アカウントを検証にするには、このURLを開いてください。\n" +"\n" +"%(verification_url)s" + +#: mediagoblin/templates/mediagoblin/edit/edit.html:29 +#, python-format +msgid "Editing %(media_title)s" +msgstr "%(media_title)sを編集中" + +#: mediagoblin/templates/mediagoblin/edit/edit.html:36 +msgid "Cancel" +msgstr "キャンセル" + +#: mediagoblin/templates/mediagoblin/edit/edit.html:37 +msgid "Save changes" +msgstr "投稿する" + +#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:29 +#, python-format +msgid "Editing %(username)s's profile" +msgstr "%(username)sさんのプロフィールを編集中" + +#: mediagoblin/templates/mediagoblin/listings/tag.html:31 +msgid "Media tagged with:" +msgstr "タグ付けされたコンテンツ:" + +#: mediagoblin/templates/mediagoblin/listings/tag.html:42 +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:48 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:104 +msgid "atom feed" +msgstr "Atomフィード" + +#: mediagoblin/templates/mediagoblin/submit/start.html:26 +msgid "Submit yer media" +msgstr "コンテンツを投稿" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:32 +#, 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/gallery.html:53 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:32 +msgid "Sorry, no such user found." +msgstr "申し訳ありませんが、そのユーザーは見つかりませんでした。" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:39 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:59 +msgid "Verification needed" +msgstr "確認必要" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:42 +msgid "Almost done! Your account still needs to be verified." +msgstr "ほぼ完了!アカウントを検証する必要があります。" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:47 +msgid "" +"An email should arrive in a few moments with instructions on how to do so." +msgstr "メールは、その方法の指示でいくつかの瞬間に到着します。" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:51 +msgid "In case it doesn't:" +msgstr "到着しない場合は、" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:54 +msgid "Resend verification email" +msgstr "確認メールを再送信" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 +msgid "" +"Someone has registered an account with this username, but it still has to be" +" verified." +msgstr "誰かがこのユーザ名でアカウントを登録しているが、まだ検証する必要があります。" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:68 +#, 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:78 +#, python-format +msgid "%(username)s's profile" +msgstr "%(username)sさんのプロフィール" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:86 +msgid "Edit profile" +msgstr "プロフィールを編集" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:98 +#, python-format +msgid "View all of %(username)s's media" +msgstr "%(username)sさんのコンテンツをすべて見る" + +#: mediagoblin/user_pages/forms.py:24 +msgid "Comment" +msgstr "" + + diff --git a/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.mo Binary files differnew file mode 100644 index 00000000..8911785f --- /dev/null +++ b/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.mo diff --git a/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po new file mode 100644 index 00000000..bd00fd1f --- /dev/null +++ b/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po @@ -0,0 +1,308 @@ +# Translations template for PROJECT. +# Copyright (C) 2011 ORGANIZATION +# This file is distributed under the same license as the PROJECT project. +# +# <odin.omdal@gmail.com>, 2011. +msgid "" +msgstr "" +"Project-Id-Version: GNU MediaGoblin\n" +"Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" +"POT-Creation-Date: 2011-08-08 22:53-0500\n" +"PO-Revision-Date: 2011-08-10 21:23+0000\n" +"Last-Translator: velmont <odin.omdal@gmail.com>\n" +"Language-Team: LANGUAGE <LL@li.org>\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: nn_NO\n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" + +#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:46 +msgid "Username" +msgstr "Brukarnamn" + +#: mediagoblin/auth/forms.py:29 mediagoblin/auth/forms.py:50 +msgid "Password" +msgstr "Passord" + +#: mediagoblin/auth/forms.py:34 +msgid "Passwords must match." +msgstr "Passorda må vera like." + +#: mediagoblin/auth/forms.py:36 +msgid "Confirm password" +msgstr "Gjenta passord" + +#: mediagoblin/auth/forms.py:39 +msgid "Email address" +msgstr "E-postadresse" + +#: mediagoblin/auth/views.py:40 +msgid "Sorry, registration is disabled on this instance." +msgstr "Registrering er slege av. Orsak." + +#: mediagoblin/auth/views.py:55 +msgid "Sorry, a user with that name already exists." +msgstr "Ein konto med dette brukarnamnet finst allereide." + +#: mediagoblin/auth/views.py:152 +msgid "" +"Your email address has been verified. You may now login, edit your profile, " +"and submit images!" +msgstr "" +"E-postadressa di, og dimed kontoen din er stadfesta. Du kan no logga inn, " +"endra profilen din og lasta opp filer." + +#: mediagoblin/auth/views.py:158 +msgid "The verification key or user id is incorrect" +msgstr "Stadfestingsnykelen eller brukar-ID-en din er feil." + +#: mediagoblin/auth/views.py:179 +#: mediagoblin/templates/mediagoblin/auth/resent_verification_email.html:22 +msgid "Resent your verification email." +msgstr "Send ein ny stadfestingsepost." + +#: mediagoblin/edit/forms.py:26 mediagoblin/submit/forms.py:26 +msgid "Title" +msgstr "Tittel" + +#: mediagoblin/edit/forms.py:29 +msgid "Slug" +msgstr "Adressetittel" + +#: mediagoblin/edit/forms.py:30 +msgid "The slug can't be empty" +msgstr "Adressetittelen kan ikkje vera tom" + +#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:31 +msgid "Tags" +msgstr "Merkelappar" + +#: mediagoblin/edit/forms.py:38 +msgid "Bio" +msgstr "Presentasjon" + +#: mediagoblin/edit/forms.py:41 +msgid "Website" +msgstr "Heimeside" + +#: mediagoblin/edit/forms.py:43 +msgid "Improperly formed URL" +msgstr "Ugyldeg URL" + +#: mediagoblin/edit/views.py:54 +msgid "An entry with that slug already exists for this user." +msgstr "Eit innlegg med denne adressetittelen finst allereie." + +#: mediagoblin/edit/views.py:75 +msgid "You are editing another user's media. Proceed with caution." +msgstr "Ver forsiktig, du redigerer ein annan konto sitt innlegg." + +#: mediagoblin/edit/views.py:96 +msgid "You are editing a user's profile. Proceed with caution." +msgstr "Ver forsiktig, du redigerer ein annan konto sin profil." + +#: mediagoblin/submit/forms.py:29 +msgid "File" +msgstr "Fil" + +#: mediagoblin/submit/views.py:45 +msgid "You must provide a file." +msgstr "Du må velja ei fil." + +#: mediagoblin/submit/views.py:48 +msgid "The file doesn't seem to be an image!" +msgstr "Fila verkar ikkje å vera ei gyldig biletefil." + +#: mediagoblin/submit/views.py:96 +msgid "Woohoo! Submitted!" +msgstr "Johoo! Opplasta!" + +#: mediagoblin/templates/mediagoblin/base.html:22 +msgid "GNU MediaGoblin" +msgstr "GNU MediaGoblin" + +#: mediagoblin/templates/mediagoblin/base.html:45 +msgid "Mediagoblin logo" +msgstr "MediaGoblin-logo" + +#: mediagoblin/templates/mediagoblin/base.html:51 +msgid "Submit media" +msgstr "Last opp" + +#: mediagoblin/templates/mediagoblin/base.html:62 +msgid "verify your email!" +msgstr "Stadfest epostadressa di" + +#: mediagoblin/templates/mediagoblin/base.html:72 +msgid "Login" +msgstr "Logg inn" + +#: mediagoblin/templates/mediagoblin/base.html:88 +msgid "" +"Powered by <a href=\"http://mediagoblin.org\">MediaGoblin</a>, a <a " +"href=\"http://gnu.org/\">GNU project</a>" +msgstr "" +"Driven av <a href=\"http://mediagoblin.org\">MediaGoblin</a>, eit <a " +"href=\"http://gnu.org/\">GNU-prosjekt</a>" + +#: mediagoblin/templates/mediagoblin/root.html:21 +msgid "Welcome to GNU MediaGoblin!" +msgstr "Velkomen til GNU MediaGoblin!" + +#: mediagoblin/templates/mediagoblin/root.html:26 +msgid "Submit an item" +msgstr "Last opp" + +#: mediagoblin/templates/mediagoblin/root.html:31 +#, python-format +msgid "If you have an account, you can <a href=\"%(login_url)s\">Login</a>." +msgstr "Har du ein konto? <a href=\"%(login_url)s\">Logg inn</a>." + +#: mediagoblin/templates/mediagoblin/root.html:37 +#, python-format +msgid "" +"If you don't have an account, please <a " +"href=\"%(register_url)s\">Register</a>." +msgstr "Har du ingen konto? <a href=\"%(register_url)s\">Registrer deg</a>." + +#: mediagoblin/templates/mediagoblin/auth/login.html:26 +msgid "Log in" +msgstr "Logg inn" + +#: mediagoblin/templates/mediagoblin/auth/login.html:29 +msgid "Login failed!" +msgstr "Innlogging feila!" + +#: mediagoblin/templates/mediagoblin/auth/login.html:34 +#: mediagoblin/templates/mediagoblin/auth/register.html:30 +#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 +#: mediagoblin/templates/mediagoblin/submit/start.html:32 +msgid "Submit" +msgstr "Send" + +#: mediagoblin/templates/mediagoblin/auth/login.html:42 +msgid "Don't have an account yet?" +msgstr "Har du ingen konto?" + +#: mediagoblin/templates/mediagoblin/auth/login.html:45 +msgid "Create one here!" +msgstr "Lag ein!" + +#: mediagoblin/templates/mediagoblin/auth/register.html:27 +msgid "Create an account!" +msgstr "Lag ein konto." + +#: 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 "" +"Hei %(username)s,\n" +"\n" +"opna den følgjande adressa i netlesaren din for å aktivera kontoen din:\n" +"\n" +"%(verification_url)s" + +#: mediagoblin/templates/mediagoblin/edit/edit.html:29 +#, python-format +msgid "Editing %(media_title)s" +msgstr "Redigerer %(media_title)s" + +#: mediagoblin/templates/mediagoblin/edit/edit.html:36 +msgid "Cancel" +msgstr "Avbryt" + +#: mediagoblin/templates/mediagoblin/edit/edit.html:37 +msgid "Save changes" +msgstr "Lagra" + +#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:29 +#, python-format +msgid "Editing %(username)s's profile" +msgstr "Redigerar profilen til %(username)s" + +#: mediagoblin/templates/mediagoblin/listings/tag.html:29 +msgid "Media tagged with:" +msgstr "Merkelappar:" + +#: mediagoblin/templates/mediagoblin/listings/tag.html:40 +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:46 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:101 +msgid "atom feed" +msgstr "atom-feed" + +#: mediagoblin/templates/mediagoblin/submit/start.html:26 +msgid "Submit yer media" +msgstr "Last opp" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 +#, python-format +msgid "<a href=\"%(user_url)s\">%(username)s</a>'s media" +msgstr "<a href=\"%(user_url)s\">%(username)s</a> sin mediafiler" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:51 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:30 +msgid "Sorry, no such user found." +msgstr "Fann ingen slik brukar" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:37 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:57 +msgid "Verification needed" +msgstr "Treng stadfesting" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:40 +msgid "Almost done! Your account still needs to be verified." +msgstr "Nesten klart. Du treng berre stadfesta kontoen din." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:45 +msgid "" +"An email should arrive in a few moments with instructions on how to do so." +msgstr "Ein epost med instruksjonar kjem straks." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:49 +msgid "In case it doesn't:" +msgstr "I tilfelle det ikkje skjer:" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:52 +msgid "Resend verification email" +msgstr "Send ein ny epost" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:60 +msgid "" +"Someone has registered an account with this username, but it still has to be" +" verified." +msgstr "" +"Det finst allereie ein konto med det brukarnamnet, men den kontoen treng " +"stadfesting." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:66 +#, 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 "" +"Viss dette er deg, kan du <a href=\"%(login_url)s\">logga inn</a> for å få " +"tilsendt ny epost med stadfestingslenkje." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:76 +#, python-format +msgid "%(username)s's profile" +msgstr "%(username)s sin profil" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:84 +msgid "Edit profile" +msgstr "Endra profil" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:95 +#, python-format +msgid "View all of %(username)s's media" +msgstr "Sjå all media frå %(username)s" + + diff --git a/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.mo Binary files differnew file mode 100644 index 00000000..4dc4ab5f --- /dev/null +++ b/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.mo diff --git a/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po new file mode 100644 index 00000000..43f65af6 --- /dev/null +++ b/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po @@ -0,0 +1,310 @@ +# Translations template for PROJECT. +# Copyright (C) 2011 ORGANIZATION +# This file is distributed under the same license as the PROJECT project. +# +# <snd.noise@gmail.com>, 2011. +msgid "" +msgstr "" +"Project-Id-Version: GNU MediaGoblin\n" +"Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" +"POT-Creation-Date: 2011-08-08 22:53-0500\n" +"PO-Revision-Date: 2011-08-10 23:16+0000\n" +"Last-Translator: osc <snd.noise@gmail.com>\n" +"Language-Team: Portuguese (Brazilian) (http://www.transifex.net/projects/p/mediagoblin/team/pt_BR/)\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: pt_BR\n" +"Plural-Forms: nplurals=2; plural=(n > 1)\n" + +#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:46 +msgid "Username" +msgstr "Nome de Usuário" + +#: mediagoblin/auth/forms.py:29 mediagoblin/auth/forms.py:50 +msgid "Password" +msgstr "Senha" + +#: mediagoblin/auth/forms.py:34 +msgid "Passwords must match." +msgstr "Senhas devem ser iguais." + +#: mediagoblin/auth/forms.py:36 +msgid "Confirm password" +msgstr "Confirmar senha" + +#: mediagoblin/auth/forms.py:39 +msgid "Email address" +msgstr "Endereço de email" + +#: mediagoblin/auth/views.py:40 +msgid "Sorry, registration is disabled on this instance." +msgstr "Desculpa, o registro está desativado neste momento." + +#: mediagoblin/auth/views.py:55 +msgid "Sorry, a user with that name already exists." +msgstr "Desculpe, um usuário com este nome já existe." + +#: mediagoblin/auth/views.py:152 +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:158 +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:179 +#: mediagoblin/templates/mediagoblin/auth/resent_verification_email.html:22 +msgid "Resent your verification email." +msgstr "O email de verificação foi reenviado." + +#: mediagoblin/edit/forms.py:26 mediagoblin/submit/forms.py:26 +msgid "Title" +msgstr "Título" + +#: mediagoblin/edit/forms.py:29 +msgid "Slug" +msgstr "" + +#: mediagoblin/edit/forms.py:30 +msgid "The slug can't be empty" +msgstr "" + +#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:31 +msgid "Tags" +msgstr "Tags" + +#: mediagoblin/edit/forms.py:38 +msgid "Bio" +msgstr "Biográfia" + +#: mediagoblin/edit/forms.py:41 +msgid "Website" +msgstr "Website" + +#: mediagoblin/edit/forms.py:43 +msgid "Improperly formed URL" +msgstr "" + +#: mediagoblin/edit/views.py:54 +msgid "An entry with that slug already exists for this user." +msgstr "" + +#: mediagoblin/edit/views.py:75 +msgid "You are editing another user's media. Proceed with caution." +msgstr "" + +#: mediagoblin/edit/views.py:96 +msgid "You are editing a user's profile. Proceed with caution." +msgstr "" + +#: mediagoblin/submit/forms.py:29 +msgid "File" +msgstr "Arquivo" + +#: mediagoblin/submit/views.py:45 +msgid "You must provide a file." +msgstr "Você deve fornecer um arquivo." + +#: mediagoblin/submit/views.py:48 +msgid "The file doesn't seem to be an image!" +msgstr "O arquivo não parece ser uma imagem!" + +#: mediagoblin/submit/views.py:96 +msgid "Woohoo! Submitted!" +msgstr "Eba! Enviado!" + +#: mediagoblin/templates/mediagoblin/base.html:22 +msgid "GNU MediaGoblin" +msgstr "GNU MediaGoblin" + +#: mediagoblin/templates/mediagoblin/base.html:45 +msgid "Mediagoblin logo" +msgstr "Logo de Mediagoblin" + +#: mediagoblin/templates/mediagoblin/base.html:51 +msgid "Submit media" +msgstr "Enviar mídia" + +#: mediagoblin/templates/mediagoblin/base.html:62 +msgid "verify your email!" +msgstr "Verifique seu email!" + +#: mediagoblin/templates/mediagoblin/base.html:72 +msgid "Login" +msgstr "Login" + +#: mediagoblin/templates/mediagoblin/base.html:88 +msgid "" +"Powered by <a href=\"http://mediagoblin.org\">MediaGoblin</a>, a <a " +"href=\"http://gnu.org/\">GNU project</a>" +msgstr "" +"Powered by <a href=\"http://mediagoblin.org\">MediaGoblin</a>, a <a " +"href=\"http://gnu.org/\">GNU project</a>" + +#: mediagoblin/templates/mediagoblin/root.html:21 +msgid "Welcome to GNU MediaGoblin!" +msgstr "Bemvindo a GNU Mediagoblin!" + +#: mediagoblin/templates/mediagoblin/root.html:26 +msgid "Submit an item" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:31 +#, python-format +msgid "If you have an account, you can <a href=\"%(login_url)s\">Login</a>." +msgstr "Se você tem conta, você pode <a href=\"%(login_url)s\">Entrar</a> ." + +#: mediagoblin/templates/mediagoblin/root.html:37 +#, python-format +msgid "" +"If you don't have an account, please <a " +"href=\"%(register_url)s\">Register</a>." +msgstr "" +"Se você não tem conta, por favor <a href=\"%(register_url)s\">Registrar</a> " +"." + +#: mediagoblin/templates/mediagoblin/auth/login.html:26 +msgid "Log in" +msgstr "Entrar" + +#: mediagoblin/templates/mediagoblin/auth/login.html:29 +msgid "Login failed!" +msgstr "Login falhou!" + +#: mediagoblin/templates/mediagoblin/auth/login.html:34 +#: mediagoblin/templates/mediagoblin/auth/register.html:30 +#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 +#: mediagoblin/templates/mediagoblin/submit/start.html:32 +msgid "Submit" +msgstr "Enviar" + +#: mediagoblin/templates/mediagoblin/auth/login.html:42 +msgid "Don't have an account yet?" +msgstr "Ainda não tem conta?" + +#: mediagoblin/templates/mediagoblin/auth/login.html:45 +msgid "Create one here!" +msgstr "Crie uma aqui!" + +#: mediagoblin/templates/mediagoblin/auth/register.html:27 +msgid "Create an account!" +msgstr "Criar uma conta!" + +#: 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 "" +"Olá %(username)s,\n" +"\n" +"Para ativar sua conta GNU MediaGoblin, visite este endereço no seu navegador:\n" +"\n" +"%(verification_url)s" + +#: mediagoblin/templates/mediagoblin/edit/edit.html:29 +#, python-format +msgid "Editing %(media_title)s" +msgstr "Editando %(media_title)s" + +#: mediagoblin/templates/mediagoblin/edit/edit.html:36 +msgid "Cancel" +msgstr "Cancelar" + +#: mediagoblin/templates/mediagoblin/edit/edit.html:37 +msgid "Save changes" +msgstr "Salvar mudanças" + +#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:29 +#, python-format +msgid "Editing %(username)s's profile" +msgstr "Editando perfil de %(username)s" + +#: mediagoblin/templates/mediagoblin/listings/tag.html:29 +msgid "Media tagged with:" +msgstr "" + +#: mediagoblin/templates/mediagoblin/listings/tag.html:40 +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:46 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:101 +msgid "atom feed" +msgstr "atom feed" + +#: mediagoblin/templates/mediagoblin/submit/start.html:26 +msgid "Submit yer media" +msgstr "Envie sua mídia" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 +#, python-format +msgid "<a href=\"%(user_url)s\">%(username)s</a>'s media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:51 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:30 +msgid "Sorry, no such user found." +msgstr "Desculpe, tal usuário não encontrado." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:37 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:57 +msgid "Verification needed" +msgstr "Verificação necessária" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:40 +msgid "Almost done! Your account still needs to be verified." +msgstr "Quase pronto! Sua conta precisa de verificação." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:45 +msgid "" +"An email should arrive in a few moments with instructions on how to do so." +msgstr "Receberá um email com instruções de como fazer." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:49 +msgid "In case it doesn't:" +msgstr "Caso contrário:" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:52 +msgid "Resend verification email" +msgstr "Reenviar email de verificação" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:60 +msgid "" +"Someone has registered an account with this username, but it still has to be" +" verified." +msgstr "" +"Alguém já registrou uma conta com este nome, mas ainda tem que ser " +"verificada." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:66 +#, 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 "" +"Se você é essa pessoa, mas você perdeu seu e-mail de verificação, você pode " +"<a href=\"%(login_url)s\">efetuar login</a> e reenviá-la." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:76 +#, python-format +msgid "%(username)s's profile" +msgstr "Perfil de %(username)s" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:84 +msgid "Edit profile" +msgstr "Editar perfil" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:95 +#, python-format +msgid "View all of %(username)s's media" +msgstr "" + + diff --git a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo Binary files differnew file mode 100644 index 00000000..361846d4 --- /dev/null +++ b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo diff --git a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po new file mode 100644 index 00000000..feb261c8 --- /dev/null +++ b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po @@ -0,0 +1,314 @@ +# Translations template for PROJECT. +# Copyright (C) 2011 ORGANIZATION +# This file is distributed under the same license as the PROJECT project. +# +# <gapop@hotmail.com>, 2011. +msgid "" +msgstr "" +"Project-Id-Version: GNU MediaGoblin\n" +"Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" +"POT-Creation-Date: 2011-08-08 22:53-0500\n" +"PO-Revision-Date: 2011-08-10 21:52+0000\n" +"Last-Translator: gap <gapop@hotmail.com>\n" +"Language-Team: LANGUAGE <LL@li.org>\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: 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:24 mediagoblin/auth/forms.py:46 +msgid "Username" +msgstr "Nume de utilizator" + +#: mediagoblin/auth/forms.py:29 mediagoblin/auth/forms.py:50 +msgid "Password" +msgstr "Parolă" + +#: mediagoblin/auth/forms.py:34 +msgid "Passwords must match." +msgstr "Parolele trebuie să fie identice." + +#: mediagoblin/auth/forms.py:36 +msgid "Confirm password" +msgstr "Reintroduceți parola" + +#: mediagoblin/auth/forms.py:39 +msgid "Email address" +msgstr "Adresa de e-mail" + +#: mediagoblin/auth/views.py:40 +msgid "Sorry, registration is disabled on this instance." +msgstr "Ne pare rău, dar înscrierile sunt dezactivate pe această instanță." + +#: mediagoblin/auth/views.py:55 +msgid "Sorry, a user with that name already exists." +msgstr "Ne pare rău, există deja un utilizator cu același nume." + +#: mediagoblin/auth/views.py:152 +msgid "" +"Your email address has been verified. You may now login, edit your profile, " +"and submit images!" +msgstr "" +"Adresa dvs. de e-mail a fost confirmată. Puteți să vă autentificați, să vă " +"modificați profilul și să trimiteți imagini!" + +#: mediagoblin/auth/views.py:158 +msgid "The verification key or user id is incorrect" +msgstr "Cheie de verificare sau user ID incorect." + +#: mediagoblin/auth/views.py:179 +#: mediagoblin/templates/mediagoblin/auth/resent_verification_email.html:22 +msgid "Resent your verification email." +msgstr "E-mail-ul de verificare a fost retrimis." + +#: mediagoblin/edit/forms.py:26 mediagoblin/submit/forms.py:26 +msgid "Title" +msgstr "Titlu" + +#: mediagoblin/edit/forms.py:29 +msgid "Slug" +msgstr "Identificator" + +#: mediagoblin/edit/forms.py:30 +msgid "The slug can't be empty" +msgstr "Identificatorul nu poate să lipsească" + +#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:31 +msgid "Tags" +msgstr "Etichete" + +#: mediagoblin/edit/forms.py:38 +msgid "Bio" +msgstr "Biografie" + +#: mediagoblin/edit/forms.py:41 +msgid "Website" +msgstr "Sit Web" + +#: mediagoblin/edit/forms.py:43 +msgid "Improperly formed URL" +msgstr "Adresă URL incorectă" + +#: mediagoblin/edit/views.py:54 +msgid "An entry with that slug already exists for this user." +msgstr "" +"Există deja un entry cu același identificator pentru acest utilizator." + +#: mediagoblin/edit/views.py:75 +msgid "You are editing another user's media. Proceed with caution." +msgstr "Editați fișierul unui alt utilizator. Se recomandă prudență." + +#: mediagoblin/edit/views.py:96 +msgid "You are editing a user's profile. Proceed with caution." +msgstr "Editați profilul unui utilizator. Se recomandă prudență." + +#: mediagoblin/submit/forms.py:29 +msgid "File" +msgstr "Fișier" + +#: mediagoblin/submit/views.py:45 +msgid "You must provide a file." +msgstr "Trebuie să selectați un fișier." + +#: mediagoblin/submit/views.py:48 +msgid "The file doesn't seem to be an image!" +msgstr "Fișierul nu pare a fi o imagine!" + +#: mediagoblin/submit/views.py:96 +msgid "Woohoo! Submitted!" +msgstr "Gata, trimis!" + +#: mediagoblin/templates/mediagoblin/base.html:22 +msgid "GNU MediaGoblin" +msgstr "GNU MediaGoblin" + +#: mediagoblin/templates/mediagoblin/base.html:45 +msgid "Mediagoblin logo" +msgstr "Logo MediaGoblin" + +#: mediagoblin/templates/mediagoblin/base.html:51 +msgid "Submit media" +msgstr "Transmiteți fișier" + +#: mediagoblin/templates/mediagoblin/base.html:62 +msgid "verify your email!" +msgstr "verificați e-mail-ul!" + +#: mediagoblin/templates/mediagoblin/base.html:72 +msgid "Login" +msgstr "Autentificare" + +#: mediagoblin/templates/mediagoblin/base.html:88 +msgid "" +"Powered by <a href=\"http://mediagoblin.org\">MediaGoblin</a>, a <a " +"href=\"http://gnu.org/\">GNU project</a>" +msgstr "" +"Construit cu <a href=\"http://mediagoblin.org\">MediaGoblin</a>, un <a " +"href=\"http://gnu.org/\">proiect GNU</a>" + +#: mediagoblin/templates/mediagoblin/root.html:21 +msgid "Welcome to GNU MediaGoblin!" +msgstr "Bun venit la GNU MediaGoblin!" + +#: mediagoblin/templates/mediagoblin/root.html:26 +msgid "Submit an item" +msgstr "Trimite un fișier" + +#: mediagoblin/templates/mediagoblin/root.html:31 +#, python-format +msgid "If you have an account, you can <a href=\"%(login_url)s\">Login</a>." +msgstr "" +"Dacă aveți deja un cont, vă puteți <a " +"href=\"%(login_url)s\">autentifica</a>." + +#: mediagoblin/templates/mediagoblin/root.html:37 +#, python-format +msgid "" +"If you don't have an account, please <a " +"href=\"%(register_url)s\">Register</a>." +msgstr "" +"Dacă nu aveți cont, vă rugăm să vă <a " +"href=\"%(register_url)s\">înregistrați</a>." + +#: mediagoblin/templates/mediagoblin/auth/login.html:26 +msgid "Log in" +msgstr "Autentificare" + +#: mediagoblin/templates/mediagoblin/auth/login.html:29 +msgid "Login failed!" +msgstr "Autentificare nereușită!" + +#: mediagoblin/templates/mediagoblin/auth/login.html:34 +#: mediagoblin/templates/mediagoblin/auth/register.html:30 +#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 +#: mediagoblin/templates/mediagoblin/submit/start.html:32 +msgid "Submit" +msgstr "Trimite" + +#: mediagoblin/templates/mediagoblin/auth/login.html:42 +msgid "Don't have an account yet?" +msgstr "Nu aveți un cont?" + +#: mediagoblin/templates/mediagoblin/auth/login.html:45 +msgid "Create one here!" +msgstr "Creați-l aici!" + +#: mediagoblin/templates/mediagoblin/auth/register.html:27 +msgid "Create an account!" +msgstr "Creați un cont!" + +#: 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 "" +"Bună, %(username)s,\n" +"\n" +"pentru activarea contului tău GNU MediaGoblin, accesează adresa următoare:\n" +"\n" +"%(verification_url)s" + +#: mediagoblin/templates/mediagoblin/edit/edit.html:29 +#, python-format +msgid "Editing %(media_title)s" +msgstr "Editare %(media_title)s" + +#: mediagoblin/templates/mediagoblin/edit/edit.html:36 +msgid "Cancel" +msgstr "Anulare" + +#: mediagoblin/templates/mediagoblin/edit/edit.html:37 +msgid "Save changes" +msgstr "Salvează modificările" + +#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:29 +#, python-format +msgid "Editing %(username)s's profile" +msgstr "Editare profil %(username)s" + +#: mediagoblin/templates/mediagoblin/listings/tag.html:29 +msgid "Media tagged with:" +msgstr "Etichete:" + +#: mediagoblin/templates/mediagoblin/listings/tag.html:40 +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:46 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:101 +msgid "atom feed" +msgstr "flux atom" + +#: mediagoblin/templates/mediagoblin/submit/start.html:26 +msgid "Submit yer media" +msgstr "Trimite fișierele tale" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 +#, python-format +msgid "<a href=\"%(user_url)s\">%(username)s</a>'s media" +msgstr "Fișierele lui <a href=\"%(user_url)s\">%(username)s</a>" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:51 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:30 +msgid "Sorry, no such user found." +msgstr "Ne pare rău, nu am găsit utilizatorul căutat." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:37 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:57 +msgid "Verification needed" +msgstr "Confirmare necesară" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:40 +msgid "Almost done! Your account still needs to be verified." +msgstr "Aproape gata! Este necesară confirmarea contului dvs." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:45 +msgid "" +"An email should arrive in a few moments with instructions on how to do so." +msgstr "Veți primi în scurt timp un mesaj prin e-mail cu instrucțiuni." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:49 +msgid "In case it doesn't:" +msgstr "Dacă nu primiți mesajul:" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:52 +msgid "Resend verification email" +msgstr "Retrimite mesajul de verificare" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:60 +msgid "" +"Someone has registered an account with this username, but it still has to be" +" verified." +msgstr "" +"Cineva s-a înscris pe site cu acest nume de utilizator, dar nu a fost " +"confirmat încă." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:66 +#, 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 "" +"Dacă dvs. sunteți persoana respectivă și nu mai aveți e-mail-ul de " +"verificare, puteți să vă <a href=\"%(login_url)s\">autentificați</a> pentru " +"a-l retrimite." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:76 +#, python-format +msgid "%(username)s's profile" +msgstr "Profil %(username)s" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:84 +msgid "Edit profile" +msgstr "Editare profil" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:95 +#, python-format +msgid "View all of %(username)s's media" +msgstr "Toate fișierele lui %(username)s" + + diff --git a/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.mo Binary files differnew file mode 100644 index 00000000..a70b1fef --- /dev/null +++ b/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.mo diff --git a/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po new file mode 100644 index 00000000..bf2dd4fa --- /dev/null +++ b/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po @@ -0,0 +1,309 @@ +# Translations template for PROJECT. +# Copyright (C) 2011 ORGANIZATION +# This file is distributed under the same license as the PROJECT project. +# +# Jure Repinc <jlp@holodeck1.com>, 2011. +msgid "" +msgstr "" +"Project-Id-Version: GNU MediaGoblin\n" +"Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" +"POT-Creation-Date: 2011-08-08 22:53-0500\n" +"PO-Revision-Date: 2011-08-10 21:28+0000\n" +"Last-Translator: JLP <jlp@holodeck1.com>\n" +"Language-Team: LANGUAGE <LL@li.org>\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: 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:24 mediagoblin/auth/forms.py:46 +msgid "Username" +msgstr "Uporabniško ime" + +#: mediagoblin/auth/forms.py:29 mediagoblin/auth/forms.py:50 +msgid "Password" +msgstr "Geslo" + +#: mediagoblin/auth/forms.py:34 +msgid "Passwords must match." +msgstr "Gesli morata biti enaki." + +#: mediagoblin/auth/forms.py:36 +msgid "Confirm password" +msgstr "Potrdite geslo" + +#: mediagoblin/auth/forms.py:39 +msgid "Email address" +msgstr "E-poštni naslov" + +#: mediagoblin/auth/views.py:40 +msgid "Sorry, registration is disabled on this instance." +msgstr "Oprostite, prijava za ta izvod ni omogočena." + +#: mediagoblin/auth/views.py:55 +msgid "Sorry, a user with that name already exists." +msgstr "Oprostite, uporabnik s tem imenom že obstaja." + +#: mediagoblin/auth/views.py:152 +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:158 +msgid "The verification key or user id is incorrect" +msgstr "Potrditveni ključ ali uporabniška identifikacija je napačna" + +#: mediagoblin/auth/views.py:179 +#: mediagoblin/templates/mediagoblin/auth/resent_verification_email.html:22 +msgid "Resent your verification email." +msgstr "Ponovno pošiljanje potrditvene e-pošte." + +#: mediagoblin/edit/forms.py:26 mediagoblin/submit/forms.py:26 +msgid "Title" +msgstr "Naslov" + +#: mediagoblin/edit/forms.py:29 +msgid "Slug" +msgstr "Oznaka" + +#: mediagoblin/edit/forms.py:30 +msgid "The slug can't be empty" +msgstr "Oznaka ne sme biti prazna" + +#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:31 +msgid "Tags" +msgstr "Oznake" + +#: mediagoblin/edit/forms.py:38 +msgid "Bio" +msgstr "Biografija" + +#: mediagoblin/edit/forms.py:41 +msgid "Website" +msgstr "Spletna stran" + +#: mediagoblin/edit/forms.py:43 +msgid "Improperly formed URL" +msgstr "Napačno oblikovan URL" + +#: mediagoblin/edit/views.py:54 +msgid "An entry with that slug already exists for this user." +msgstr "Vnos s to oznako za tega uporabnika že obstaja." + +#: mediagoblin/edit/views.py:75 +msgid "You are editing another user's media. Proceed with caution." +msgstr "Urejate vsebino drugega uporabnika. Nadaljujte pazljivo." + +#: mediagoblin/edit/views.py:96 +msgid "You are editing a user's profile. Proceed with caution." +msgstr "Urejate uporabniški profil. Nadaljujte pazljivo." + +#: mediagoblin/submit/forms.py:29 +msgid "File" +msgstr "Datoteka" + +#: mediagoblin/submit/views.py:45 +msgid "You must provide a file." +msgstr "Podati morate datoteko." + +#: mediagoblin/submit/views.py:48 +msgid "The file doesn't seem to be an image!" +msgstr "Kot kaže datoteka ni slika." + +#: mediagoblin/submit/views.py:96 +msgid "Woohoo! Submitted!" +msgstr "Juhej! Poslano." + +#: mediagoblin/templates/mediagoblin/base.html:22 +msgid "GNU MediaGoblin" +msgstr "GNU MediaGoblin" + +#: mediagoblin/templates/mediagoblin/base.html:45 +msgid "Mediagoblin logo" +msgstr "Logotip MediaGoblin" + +#: mediagoblin/templates/mediagoblin/base.html:51 +msgid "Submit media" +msgstr "Pošlji vsebino" + +#: mediagoblin/templates/mediagoblin/base.html:62 +msgid "verify your email!" +msgstr "Preverite svojo e-pošto." + +#: mediagoblin/templates/mediagoblin/base.html:72 +msgid "Login" +msgstr "Prijava" + +#: mediagoblin/templates/mediagoblin/base.html:88 +msgid "" +"Powered by <a href=\"http://mediagoblin.org\">MediaGoblin</a>, a <a " +"href=\"http://gnu.org/\">GNU project</a>" +msgstr "" +"Stran poganja <a href=\"http://mediagoblin.org\">MediaGoblin</a>, del <a " +"href=\"http://gnu.org/\">projekta GNU</a>" + +#: mediagoblin/templates/mediagoblin/root.html:21 +msgid "Welcome to GNU MediaGoblin!" +msgstr "Dobrodošli v GNU MediaGoblin!" + +#: mediagoblin/templates/mediagoblin/root.html:26 +msgid "Submit an item" +msgstr "Pošljite datoteko" + +#: mediagoblin/templates/mediagoblin/root.html:31 +#, python-format +msgid "If you have an account, you can <a href=\"%(login_url)s\">Login</a>." +msgstr "Če imate račun, se lahko <a href=\"%(login_url)s\">Prijavite</a>." + +#: mediagoblin/templates/mediagoblin/root.html:37 +#, python-format +msgid "" +"If you don't have an account, please <a " +"href=\"%(register_url)s\">Register</a>." +msgstr "Če računa še nimate, se <a href=\"%(register_url)s\">Registrirajte</a>." + +#: mediagoblin/templates/mediagoblin/auth/login.html:26 +msgid "Log in" +msgstr "Prijava" + +#: mediagoblin/templates/mediagoblin/auth/login.html:29 +msgid "Login failed!" +msgstr "Neuspešna prijava." + +#: mediagoblin/templates/mediagoblin/auth/login.html:34 +#: mediagoblin/templates/mediagoblin/auth/register.html:30 +#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 +#: mediagoblin/templates/mediagoblin/submit/start.html:32 +msgid "Submit" +msgstr "Pošlji" + +#: mediagoblin/templates/mediagoblin/auth/login.html:42 +msgid "Don't have an account yet?" +msgstr "Še nimate računa?" + +#: mediagoblin/templates/mediagoblin/auth/login.html:45 +msgid "Create one here!" +msgstr "Ustvarite si ga." + +#: mediagoblin/templates/mediagoblin/auth/register.html:27 +msgid "Create an account!" +msgstr "Ustvarite račun." + +#: 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 "" +"Pozdravljeni, %(username)s\n" +"\n" +"Za aktivacijo svojega računa GNU MediaGoblin odprite\n" +"naslednji URL v svojem spletnem brskalniku:\n" +"\n" +"%(verification_url)s" + +#: mediagoblin/templates/mediagoblin/edit/edit.html:29 +#, python-format +msgid "Editing %(media_title)s" +msgstr "Urejanje %(media_title)s" + +#: mediagoblin/templates/mediagoblin/edit/edit.html:36 +msgid "Cancel" +msgstr "Prekliči" + +#: mediagoblin/templates/mediagoblin/edit/edit.html:37 +msgid "Save changes" +msgstr "Shrani spremembe" + +#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:29 +#, python-format +msgid "Editing %(username)s's profile" +msgstr "Urejanje profila – %(username)s" + +#: mediagoblin/templates/mediagoblin/listings/tag.html:29 +msgid "Media tagged with:" +msgstr "Vsebina označena z:" + +#: mediagoblin/templates/mediagoblin/listings/tag.html:40 +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:46 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:101 +msgid "atom feed" +msgstr "Vir Atom" + +#: mediagoblin/templates/mediagoblin/submit/start.html:26 +msgid "Submit yer media" +msgstr "Pošljite svojo vsebino" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 +#, python-format +msgid "<a href=\"%(user_url)s\">%(username)s</a>'s media" +msgstr "Vsebina uporabnika <a href=\"%(user_url)s\">%(username)s</a>" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:51 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:30 +msgid "Sorry, no such user found." +msgstr "Oprostite, tega uporabnika ni bilo moč najti." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:37 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:57 +msgid "Verification needed" +msgstr "Potrebna je potrditev" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:40 +msgid "Almost done! Your account still needs to be verified." +msgstr "Skoraj ste zaključili. Račun je potrebno le še potrditi." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:45 +msgid "" +"An email should arrive in a few moments with instructions on how to do so." +msgstr "V kratkem bi morali prejeti e-pošto z navodili, kako to storiti." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:49 +msgid "In case it doesn't:" +msgstr "Če je ne prejmete:" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:52 +msgid "Resend verification email" +msgstr "Ponovno pošlji potrditveno e-pošto" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:60 +msgid "" +"Someone has registered an account with this username, but it still has to be" +" verified." +msgstr "" +"Nekdo je s tem uporabniškim imenom že registriral račun, vendar mora biti še" +" potrjen." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:66 +#, 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 "" +"Če ste ta oseba vi, a ste izgubili potrditveno e-pošto, se lahko <a " +"href=\"%(login_url)s\">prijavite</a> in jo ponovno pošljete." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:76 +#, python-format +msgid "%(username)s's profile" +msgstr "Profil – %(username)s" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:84 +msgid "Edit profile" +msgstr "Uredi profil" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:95 +#, python-format +msgid "View all of %(username)s's media" +msgstr "Prikaži vso vsebino uporabnika %(username)s" + + diff --git a/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.mo Binary files differnew file mode 100644 index 00000000..153584d3 --- /dev/null +++ b/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.mo diff --git a/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po new file mode 100644 index 00000000..ec8611ee --- /dev/null +++ b/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po @@ -0,0 +1,294 @@ +# Translations template for PROJECT. +# Copyright (C) 2011 ORGANIZATION +# This file is distributed under the same license as the PROJECT project. +# +msgid "" +msgstr "" +"Project-Id-Version: GNU MediaGoblin\n" +"Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" +"POT-Creation-Date: 2011-08-08 22:53-0500\n" +"PO-Revision-Date: 2011-08-09 03:57+0000\n" +"Last-Translator: cwebber <cwebber@dustycloud.org>\n" +"Language-Team: Serbian (http://www.transifex.net/projects/p/mediagoblin/team/sr/)\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: 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:24 mediagoblin/auth/forms.py:46 +msgid "Username" +msgstr "" + +#: mediagoblin/auth/forms.py:29 mediagoblin/auth/forms.py:50 +msgid "Password" +msgstr "" + +#: mediagoblin/auth/forms.py:34 +msgid "Passwords must match." +msgstr "" + +#: mediagoblin/auth/forms.py:36 +msgid "Confirm password" +msgstr "" + +#: mediagoblin/auth/forms.py:39 +msgid "Email address" +msgstr "" + +#: mediagoblin/auth/views.py:40 +msgid "Sorry, registration is disabled on this instance." +msgstr "" + +#: mediagoblin/auth/views.py:55 +msgid "Sorry, a user with that name already exists." +msgstr "" + +#: mediagoblin/auth/views.py:152 +msgid "" +"Your email address has been verified. You may now login, edit your profile, " +"and submit images!" +msgstr "" + +#: mediagoblin/auth/views.py:158 +msgid "The verification key or user id is incorrect" +msgstr "" + +#: mediagoblin/auth/views.py:179 +#: mediagoblin/templates/mediagoblin/auth/resent_verification_email.html:22 +msgid "Resent your verification email." +msgstr "" + +#: mediagoblin/edit/forms.py:26 mediagoblin/submit/forms.py:26 +msgid "Title" +msgstr "" + +#: mediagoblin/edit/forms.py:29 +msgid "Slug" +msgstr "" + +#: mediagoblin/edit/forms.py:30 +msgid "The slug can't be empty" +msgstr "" + +#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:31 +msgid "Tags" +msgstr "" + +#: mediagoblin/edit/forms.py:38 +msgid "Bio" +msgstr "" + +#: mediagoblin/edit/forms.py:41 +msgid "Website" +msgstr "" + +#: mediagoblin/edit/forms.py:43 +msgid "Improperly formed URL" +msgstr "" + +#: mediagoblin/edit/views.py:54 +msgid "An entry with that slug already exists for this user." +msgstr "" + +#: mediagoblin/edit/views.py:75 +msgid "You are editing another user's media. Proceed with caution." +msgstr "" + +#: mediagoblin/edit/views.py:96 +msgid "You are editing a user's profile. Proceed with caution." +msgstr "" + +#: mediagoblin/submit/forms.py:29 +msgid "File" +msgstr "" + +#: mediagoblin/submit/views.py:45 +msgid "You must provide a file." +msgstr "" + +#: mediagoblin/submit/views.py:48 +msgid "The file doesn't seem to be an image!" +msgstr "" + +#: mediagoblin/submit/views.py:96 +msgid "Woohoo! Submitted!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/base.html:22 +msgid "GNU MediaGoblin" +msgstr "" + +#: mediagoblin/templates/mediagoblin/base.html:45 +msgid "Mediagoblin logo" +msgstr "" + +#: mediagoblin/templates/mediagoblin/base.html:51 +msgid "Submit media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/base.html:62 +msgid "verify your email!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/base.html:72 +msgid "Login" +msgstr "" + +#: mediagoblin/templates/mediagoblin/base.html:88 +msgid "" +"Powered by <a href=\"http://mediagoblin.org\">MediaGoblin</a>, a <a " +"href=\"http://gnu.org/\">GNU project</a>" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:21 +msgid "Welcome to GNU MediaGoblin!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:26 +msgid "Submit an item" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:31 +#, python-format +msgid "If you have an account, you can <a href=\"%(login_url)s\">Login</a>." +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:37 +#, python-format +msgid "" +"If you don't have an account, please <a " +"href=\"%(register_url)s\">Register</a>." +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/login.html:26 +msgid "Log in" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/login.html:29 +msgid "Login failed!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/login.html:34 +#: mediagoblin/templates/mediagoblin/auth/register.html:30 +#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 +#: mediagoblin/templates/mediagoblin/submit/start.html:32 +msgid "Submit" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/login.html:42 +msgid "Don't have an account yet?" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/login.html:45 +msgid "Create one here!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/register.html:27 +msgid "Create an account!" +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 "" + +#: mediagoblin/templates/mediagoblin/edit/edit.html:29 +#, python-format +msgid "Editing %(media_title)s" +msgstr "" + +#: mediagoblin/templates/mediagoblin/edit/edit.html:36 +msgid "Cancel" +msgstr "" + +#: mediagoblin/templates/mediagoblin/edit/edit.html:37 +msgid "Save changes" +msgstr "" + +#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:29 +#, python-format +msgid "Editing %(username)s's profile" +msgstr "" + +#: mediagoblin/templates/mediagoblin/listings/tag.html:29 +msgid "Media tagged with:" +msgstr "" + +#: mediagoblin/templates/mediagoblin/listings/tag.html:40 +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:46 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:101 +msgid "atom feed" +msgstr "" + +#: mediagoblin/templates/mediagoblin/submit/start.html:26 +msgid "Submit yer media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 +#, python-format +msgid "<a href=\"%(user_url)s\">%(username)s</a>'s media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:51 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:30 +msgid "Sorry, no such user found." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:37 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:57 +msgid "Verification needed" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:40 +msgid "Almost done! Your account still needs to be verified." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:45 +msgid "" +"An email should arrive in a few moments with instructions on how to do so." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:49 +msgid "In case it doesn't:" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:52 +msgid "Resend verification email" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:60 +msgid "" +"Someone has registered an account with this username, but it still has to be" +" verified." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:66 +#, 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 "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:76 +#, python-format +msgid "%(username)s's profile" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:84 +msgid "Edit profile" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:95 +#, python-format +msgid "View all of %(username)s's media" +msgstr "" + + diff --git a/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.mo Binary files differnew file mode 100644 index 00000000..0d4b463c --- /dev/null +++ b/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.mo diff --git a/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po new file mode 100644 index 00000000..23605892 --- /dev/null +++ b/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po @@ -0,0 +1,319 @@ +# Translations template for PROJECT. +# Copyright (C) 2011 ORGANIZATION +# This file is distributed under the same license as the PROJECT project. +# +# <transifex@wandborg.se>, 2011. +msgid "" +msgstr "" +"Project-Id-Version: GNU MediaGoblin\n" +"Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" +"POT-Creation-Date: 2011-08-13 19:47-0500\n" +"PO-Revision-Date: 2011-08-16 13:22+0000\n" +"Last-Translator: joar <transifex@wandborg.se>\n" +"Language-Team: Swedish (http://www.transifex.net/projects/p/mediagoblin/team/sv/)\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: sv\n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" + +#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:46 +msgid "Username" +msgstr "Användarnamn" + +#: mediagoblin/auth/forms.py:29 mediagoblin/auth/forms.py:50 +msgid "Password" +msgstr "Lösenord" + +#: mediagoblin/auth/forms.py:34 +msgid "Passwords must match." +msgstr "Lösenorden måste vara identiska." + +#: mediagoblin/auth/forms.py:36 +msgid "Confirm password" +msgstr "Bekräfta lösenord" + +#: mediagoblin/auth/forms.py:39 +msgid "Email address" +msgstr "E-postadress" + +#: mediagoblin/auth/views.py:40 +msgid "Sorry, registration is disabled on this instance." +msgstr "Vi beklagar, registreringen är avtängd på den här instansen." + +#: mediagoblin/auth/views.py:57 +msgid "Sorry, a user with that name already exists." +msgstr "En användare med det användarnamnet finns redan." + +#: mediagoblin/auth/views.py:61 +msgid "Sorry, that email address has already been taken." +msgstr "Den e-postadressen är redan tagen." + +#: mediagoblin/auth/views.py:159 +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:165 +msgid "The verification key or user id is incorrect" +msgstr "Verifieringsnyckeln eller användar-IDt är fel." + +#: mediagoblin/auth/views.py:186 +#: mediagoblin/templates/mediagoblin/auth/resent_verification_email.html:22 +msgid "Resent your verification email." +msgstr "Skickade ett nytt verifierings-email." + +#: mediagoblin/edit/forms.py:26 mediagoblin/submit/forms.py:27 +msgid "Title" +msgstr "Titel" + +#: mediagoblin/edit/forms.py:29 +msgid "Slug" +msgstr "Sökvägsnamn" + +#: mediagoblin/edit/forms.py:30 +msgid "The slug can't be empty" +msgstr "Sökvägsnamnet kan inte vara tomt" + +#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:31 +msgid "Tags" +msgstr "Taggar" + +#: mediagoblin/edit/forms.py:38 +msgid "Bio" +msgstr "Presentation" + +#: mediagoblin/edit/forms.py:41 +msgid "Website" +msgstr "Hemsida" + +#: mediagoblin/edit/forms.py:43 +msgid "Improperly formed URL" +msgstr "Ogiltig URL" + +#: mediagoblin/edit/views.py:54 +msgid "An entry with that slug already exists for this user." +msgstr "Ett inlägg med det sökvägsnamnet existerar redan." + +#: mediagoblin/edit/views.py:75 +msgid "You are editing another user's media. Proceed with caution." +msgstr "Var försiktig, du redigerar någon annans inlägg." + +#: mediagoblin/edit/views.py:96 +msgid "You are editing a user's profile. Proceed with caution." +msgstr "Var försiktig, du redigerar en annan användares profil." + +#: mediagoblin/submit/forms.py:25 +msgid "File" +msgstr "Fil" + +#: mediagoblin/submit/views.py:46 +msgid "You must provide a file." +msgstr "Du måste ange en fil" + +#: mediagoblin/submit/views.py:49 +msgid "The file doesn't seem to be an image!" +msgstr "Filen verkar inte vara en giltig bildfil!" + +#: mediagoblin/submit/views.py:94 +msgid "Woohoo! Submitted!" +msgstr "Tjohoo! Upladdat!" + +#: mediagoblin/templates/mediagoblin/base.html:22 +msgid "GNU MediaGoblin" +msgstr "GNU MediaGoblin" + +#: mediagoblin/templates/mediagoblin/base.html:45 +msgid "Mediagoblin logo" +msgstr "MediaGoblin logo" + +#: mediagoblin/templates/mediagoblin/base.html:51 +msgid "Submit media" +msgstr "Ladda upp" + +#: mediagoblin/templates/mediagoblin/base.html:62 +msgid "verify your email!" +msgstr "Verifiera din e-postadress!" + +#: mediagoblin/templates/mediagoblin/base.html:72 +msgid "Login" +msgstr "Logga in" + +#: mediagoblin/templates/mediagoblin/base.html:88 +msgid "" +"Powered by <a href=\"http://mediagoblin.org\">MediaGoblin</a>, a <a " +"href=\"http://gnu.org/\">GNU project</a>" +msgstr "" +"Drivs av <a href=\"http://mediagoblin.org\">MediaGoblin</a>, ett <a " +"href=\"http://gnu.org/\">GNU</a>-projekt" + +#: mediagoblin/templates/mediagoblin/root.html:23 +msgid "Welcome to GNU MediaGoblin!" +msgstr "Välkommen till GNU MediaGoblin!" + +#: mediagoblin/templates/mediagoblin/root.html:28 +msgid "Submit an item" +msgstr "Ladda upp" + +#: mediagoblin/templates/mediagoblin/root.html:33 +#, python-format +msgid "If you have an account, you can <a href=\"%(login_url)s\">Login</a>." +msgstr "Har du ett konto? <a href=\"%(login_url)s\">Logga in</a>." + +#: mediagoblin/templates/mediagoblin/root.html:39 +#, python-format +msgid "" +"If you don't have an account, please <a " +"href=\"%(register_url)s\">Register</a>." +msgstr "" +"Har du inget konto? <a href=\"%(register_url)s\">Registrera ett konto</a>." + +#: mediagoblin/templates/mediagoblin/auth/login.html:26 +msgid "Log in" +msgstr "Logga in" + +#: mediagoblin/templates/mediagoblin/auth/login.html:29 +msgid "Login failed!" +msgstr "Inloggning misslyckades!" + +#: mediagoblin/templates/mediagoblin/auth/login.html:34 +#: mediagoblin/templates/mediagoblin/auth/register.html:30 +#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 +#: mediagoblin/templates/mediagoblin/submit/start.html:29 +msgid "Submit" +msgstr "Skicka" + +#: mediagoblin/templates/mediagoblin/auth/login.html:42 +msgid "Don't have an account yet?" +msgstr "Har du inget konto?" + +#: mediagoblin/templates/mediagoblin/auth/login.html:45 +msgid "Create one here!" +msgstr "Skapa ett!" + +#: mediagoblin/templates/mediagoblin/auth/register.html:27 +msgid "Create an account!" +msgstr "Skapa ett konto!" + +#: 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 "" +"Hej %(username)s,\n" +"\n" +"oppna den följande URLen i din webbläsare för att aktivera ditt konto på GNU MediaGoblin:\n" +"\n" +"%(verification_url)s" + +#: mediagoblin/templates/mediagoblin/edit/edit.html:29 +#, python-format +msgid "Editing %(media_title)s" +msgstr "Redigerar %(media_title)s" + +#: mediagoblin/templates/mediagoblin/edit/edit.html:36 +msgid "Cancel" +msgstr "Avbryt" + +#: mediagoblin/templates/mediagoblin/edit/edit.html:37 +msgid "Save changes" +msgstr "Spara" + +#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:29 +#, python-format +msgid "Editing %(username)s's profile" +msgstr "Redigerar %(username)ss profil" + +#: mediagoblin/templates/mediagoblin/listings/tag.html:31 +msgid "Media tagged with:" +msgstr "Taggat med:" + +#: mediagoblin/templates/mediagoblin/listings/tag.html:42 +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:48 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:104 +msgid "atom feed" +msgstr "atom-feed" + +#: mediagoblin/templates/mediagoblin/submit/start.html:26 +msgid "Submit yer media" +msgstr "Ladda upp" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:32 +#, python-format +msgid "<a href=\"%(user_url)s\">%(username)s</a>'s media" +msgstr "<a href=\"%(user_url)s\">%(username)s</a>s media" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:53 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:32 +msgid "Sorry, no such user found." +msgstr "Finns ingen sådan användare ännu." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:39 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:59 +msgid "Verification needed" +msgstr "Verifiering krävs" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:42 +msgid "Almost done! Your account still needs to be verified." +msgstr "Nästan klart! Nu behöver du bara verifiera ditt konto." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:47 +msgid "" +"An email should arrive in a few moments with instructions on how to do so." +msgstr "" +"Ett e-postmeddelande med instruktioner kommer att hamna hos dig inom kort." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:51 +msgid "In case it doesn't:" +msgstr "Om det inte skulle göra det:" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:54 +msgid "Resend verification email" +msgstr "Skicka ett nytt e-postmeddelande" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 +msgid "" +"Someone has registered an account with this username, but it still has to be" +" verified." +msgstr "" +"Det finns redan ett konto med det här användarnamnet, men det behöver " +"verifieras." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:68 +#, 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 "" +"Om det är du som är den personen och har förlorat ditt e-postmeddelande med " +"detaljer om hur du verifierar ditt konto så kan du <a " +"href=\"%(login_url)s\">logga in</a> och begära ett nytt." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:78 +#, python-format +msgid "%(username)s's profile" +msgstr "%(username)ss profil" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:86 +msgid "Edit profile" +msgstr "Redigera profil" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:98 +#, python-format +msgid "View all of %(username)s's media" +msgstr "Se all media från %(username)s" + +#: mediagoblin/user_pages/forms.py:24 +msgid "Comment" +msgstr "Kommentar" + + diff --git a/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.mo Binary files differnew file mode 100644 index 00000000..9615e44c --- /dev/null +++ b/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.mo diff --git a/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po new file mode 100644 index 00000000..d8f8c98d --- /dev/null +++ b/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po @@ -0,0 +1,310 @@ +# Translations template for PROJECT. +# Copyright (C) 2011 ORGANIZATION +# This file is distributed under the same license as the PROJECT project. +# +# <chc@citi.sinica.edu.tw>, 2011. +msgid "" +msgstr "" +"Project-Id-Version: GNU MediaGoblin\n" +"Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" +"POT-Creation-Date: 2011-08-13 19:47-0500\n" +"PO-Revision-Date: 2011-08-14 00:47+0000\n" +"Last-Translator: cwebber <cwebber@dustycloud.org>\n" +"Language-Team: LANGUAGE <LL@li.org>\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_TW\n" +"Plural-Forms: nplurals=1; plural=0\n" + +#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:46 +msgid "Username" +msgstr "使用者名稱" + +#: mediagoblin/auth/forms.py:29 mediagoblin/auth/forms.py:50 +msgid "Password" +msgstr "密碼" + +#: mediagoblin/auth/forms.py:34 +msgid "Passwords must match." +msgstr "密碼必須一至" + +#: mediagoblin/auth/forms.py:36 +msgid "Confirm password" +msgstr "確認密碼" + +#: mediagoblin/auth/forms.py:39 +msgid "Email address" +msgstr "電子郵件位置" + +#: mediagoblin/auth/views.py:40 +msgid "Sorry, registration is disabled on this instance." +msgstr "抱歉, 這個項目已經被暫停註冊." + +#: mediagoblin/auth/views.py:57 +msgid "Sorry, a user with that name already exists." +msgstr "抱歉, 這個使用者名稱已經存在." + +#: mediagoblin/auth/views.py:61 +msgid "Sorry, that email address has already been taken." +msgstr "" + +#: mediagoblin/auth/views.py:159 +msgid "" +"Your email address has been verified. You may now login, edit your profile, " +"and submit images!" +msgstr "你的電子郵件位址已被認證. 你現在就可以登入, 編輯你的個人檔案而且送出照片!" + +#: mediagoblin/auth/views.py:165 +msgid "The verification key or user id is incorrect" +msgstr "認證碼或是使用者帳號錯誤" + +#: mediagoblin/auth/views.py:186 +#: mediagoblin/templates/mediagoblin/auth/resent_verification_email.html:22 +msgid "Resent your verification email." +msgstr "重送認證郵件." + +#: mediagoblin/edit/forms.py:26 mediagoblin/submit/forms.py:27 +msgid "Title" +msgstr "稱謂" + +#: mediagoblin/edit/forms.py:29 +msgid "Slug" +msgstr "自訂字串" + +#: mediagoblin/edit/forms.py:30 +msgid "The slug can't be empty" +msgstr "自訂字串不能空白" + +#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:31 +msgid "Tags" +msgstr "標籤" + +#: mediagoblin/edit/forms.py:38 +msgid "Bio" +msgstr "自傳" + +#: mediagoblin/edit/forms.py:41 +msgid "Website" +msgstr "網站" + +#: mediagoblin/edit/forms.py:43 +msgid "Improperly formed URL" +msgstr "部正確的網址" + +#: mediagoblin/edit/views.py:54 +msgid "An entry with that slug already exists for this user." +msgstr "這個自訂字串已經被其他人用了" + +#: mediagoblin/edit/views.py:75 +msgid "You are editing another user's media. Proceed with caution." +msgstr "你正在編輯他人的媒體檔案. 請謹慎處理." + +#: mediagoblin/edit/views.py:96 +msgid "You are editing a user's profile. Proceed with caution." +msgstr "你正在編輯他人的檔案. 請謹慎處理." + +#: mediagoblin/submit/forms.py:25 +msgid "File" +msgstr "檔案" + +#: mediagoblin/submit/views.py:46 +msgid "You must provide a file." +msgstr "你必須提供一個檔案" + +#: mediagoblin/submit/views.py:49 +msgid "The file doesn't seem to be an image!" +msgstr "檔案看起來不像是一個圖片喔!" + +#: mediagoblin/submit/views.py:94 +msgid "Woohoo! Submitted!" +msgstr "喔耶! 送出去了!" + +#: mediagoblin/templates/mediagoblin/base.html:22 +msgid "GNU MediaGoblin" +msgstr "GNU MediaGoblin" + +#: mediagoblin/templates/mediagoblin/base.html:45 +msgid "Mediagoblin logo" +msgstr "Mediagoblin 標誌" + +#: mediagoblin/templates/mediagoblin/base.html:51 +msgid "Submit media" +msgstr "送出媒體" + +#: mediagoblin/templates/mediagoblin/base.html:62 +msgid "verify your email!" +msgstr "確認您的電子郵件!" + +#: mediagoblin/templates/mediagoblin/base.html:72 +msgid "Login" +msgstr "登入" + +#: mediagoblin/templates/mediagoblin/base.html:88 +msgid "" +"Powered by <a href=\"http://mediagoblin.org\">MediaGoblin</a>, a <a " +"href=\"http://gnu.org/\">GNU project</a>" +msgstr "" +"由 <a href=\"http://mediagoblin.org\">MediaGoblin</a> 製作, 她是一個 <a " +"href=\"http://gnu.org/\">GNU project</a>" + +#: mediagoblin/templates/mediagoblin/root.html:23 +msgid "Welcome to GNU MediaGoblin!" +msgstr "GNU MediaGoblin 歡迎您!" + +#: mediagoblin/templates/mediagoblin/root.html:28 +msgid "Submit an item" +msgstr "送出一個項目" + +#: mediagoblin/templates/mediagoblin/root.html:33 +#, python-format +msgid "If you have an account, you can <a href=\"%(login_url)s\">Login</a>." +msgstr "如果您有帳號了, 你可以直接 <a href=\"%(login_url)s\">登入</a>." + +#: mediagoblin/templates/mediagoblin/root.html:39 +#, python-format +msgid "" +"If you don't have an account, please <a " +"href=\"%(register_url)s\">Register</a>." +msgstr "如果您尚未取得帳號, 請 <a href=\"%(register_url)s\">註冊</a>." + +#: mediagoblin/templates/mediagoblin/auth/login.html:26 +msgid "Log in" +msgstr "登入" + +#: mediagoblin/templates/mediagoblin/auth/login.html:29 +msgid "Login failed!" +msgstr "登入錯誤" + +#: mediagoblin/templates/mediagoblin/auth/login.html:34 +#: mediagoblin/templates/mediagoblin/auth/register.html:30 +#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 +#: mediagoblin/templates/mediagoblin/submit/start.html:29 +msgid "Submit" +msgstr "送出" + +#: mediagoblin/templates/mediagoblin/auth/login.html:42 +msgid "Don't have an account yet?" +msgstr "還沒有帳號嗎?" + +#: mediagoblin/templates/mediagoblin/auth/login.html:45 +msgid "Create one here!" +msgstr "在這裡建立一個吧!" + +#: mediagoblin/templates/mediagoblin/auth/register.html:27 +msgid "Create an account!" +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/edit/edit.html:29 +#, python-format +msgid "Editing %(media_title)s" +msgstr "編輯 %(media_title)s 中" + +#: mediagoblin/templates/mediagoblin/edit/edit.html:36 +msgid "Cancel" +msgstr "取消" + +#: mediagoblin/templates/mediagoblin/edit/edit.html:37 +msgid "Save changes" +msgstr "儲存變更" + +#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:29 +#, python-format +msgid "Editing %(username)s's profile" +msgstr "編輯 %(username)s'的檔案中" + +#: mediagoblin/templates/mediagoblin/listings/tag.html:31 +msgid "Media tagged with:" +msgstr "媒體被標籤為:" + +#: mediagoblin/templates/mediagoblin/listings/tag.html:42 +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:48 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:104 +msgid "atom feed" +msgstr "atom feed" + +#: mediagoblin/templates/mediagoblin/submit/start.html:26 +msgid "Submit yer media" +msgstr "送出你的媒體檔案" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:32 +#, 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/gallery.html:53 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:32 +msgid "Sorry, no such user found." +msgstr "抱歉, 找不到這個使用者." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:39 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:59 +msgid "Verification needed" +msgstr "需要驗證" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:42 +msgid "Almost done! Your account still needs to be verified." +msgstr "快要完成了! 你的帳號仍需要驗證." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:47 +msgid "" +"An email should arrive in a few moments with instructions on how to do so." +msgstr "很快的會有一封電子郵件告訴你如何做." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:51 +msgid "In case it doesn't:" +msgstr "假設它無法:" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:54 +msgid "Resend verification email" +msgstr "重送認證郵件 " + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 +msgid "" +"Someone has registered an account with this username, but it still has to be" +" verified." +msgstr "有人已經註冊了這個帳號, 但此帳號仍需要驗證." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:68 +#, 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:78 +#, python-format +msgid "%(username)s's profile" +msgstr "%(username)s的個人檔案" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:86 +msgid "Edit profile" +msgstr "編輯個人檔案" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:98 +#, python-format +msgid "View all of %(username)s's media" +msgstr "查看%(username)s的全部媒體檔案" + +#: mediagoblin/user_pages/forms.py:24 +msgid "Comment" +msgstr "" + + diff --git a/mediagoblin/init/__init__.py b/mediagoblin/init/__init__.py index ff005703..44f604b1 100644 --- a/mediagoblin/init/__init__.py +++ b/mediagoblin/init/__init__.py @@ -112,10 +112,15 @@ def get_staticdirector(app_config): def setup_storage(): - app_config = mg_globals.app_config + global_config = mg_globals.global_config + + key_short = 'publicstore' + key_long = "storage:" + key_short + public_store = storage_system_from_config(global_config[key_long]) - public_store = storage_system_from_config(app_config, 'publicstore') - queue_store = storage_system_from_config(app_config, 'queuestore') + key_short = 'queuestore' + key_long = "storage:" + key_short + queue_store = storage_system_from_config(global_config[key_long]) setup_globals( public_store = public_store, diff --git a/mediagoblin/process_media/__init__.py b/mediagoblin/process_media/__init__.py index 125b24e0..e1289a4c 100644 --- a/mediagoblin/process_media/__init__.py +++ b/mediagoblin/process_media/__init__.py @@ -15,10 +15,14 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. import Image -from mediagoblin.db.util import ObjectId -from celery.task import task +from contextlib import contextmanager +from celery.task import Task +from celery import registry + +from mediagoblin.db.util import ObjectId from mediagoblin import mg_globals as mgg +from mediagoblin.process_media.errors import BaseProcessingFail, BadMediaFail THUMB_SIZE = 180, 180 @@ -32,19 +36,106 @@ def create_pub_filepath(entry, filename): filename]) -@task -def process_media_initial(media_id): - workbench = mgg.workbench_manager.create_workbench() +@contextmanager +def closing(callback): + try: + yield callback + finally: + pass + + +################################ +# Media processing initial steps +################################ + +class ProcessMedia(Task): + """ + Pass this entry off for processing. + """ + def run(self, media_id): + """ + Pass the media entry off to the appropriate processing function + (for now just process_image...) + """ + entry = mgg.database.MediaEntry.one( + {'_id': ObjectId(media_id)}) + + # Try to process, and handle expected errors. + try: + process_image(entry) + except BaseProcessingFail, exc: + mark_entry_failed(entry[u'_id'], exc) + return + + entry['state'] = u'processed' + entry.save() + + def on_failure(self, exc, task_id, args, kwargs, einfo): + """ + If the processing failed we should mark that in the database. + + Assuming that the exception raised is a subclass of BaseProcessingFail, + we can use that to get more information about the failure and store that + for conveying information to users about the failure, etc. + """ + entry_id = args[0] + mark_entry_failed(entry_id, exc) + + +process_media = registry.tasks[ProcessMedia.name] + + +def mark_entry_failed(entry_id, exc): + """ + Mark a media entry as having failed in its conversion. - entry = mgg.database.MediaEntry.one( - {'_id': ObjectId(media_id)}) + Uses the exception that was raised to mark more information. If the + exception is a derivative of BaseProcessingFail then we can store extra + information that can be useful for users telling them why their media failed + to process. + + Args: + - entry_id: The id of the media entry + + """ + # Was this a BaseProcessingFail? In other words, was this a + # type of error that we know how to handle? + if isinstance(exc, BaseProcessingFail): + # Looks like yes, so record information about that failure and any + # metadata the user might have supplied. + mgg.database['media_entries'].update( + {'_id': entry_id}, + {'$set': {u'state': u'failed', + u'fail_error': exc.exception_path, + u'fail_metadata': exc.metadata}}) + else: + # Looks like no, so just mark it as failed and don't record a + # failure_error (we'll assume it wasn't handled) and don't record + # metadata (in fact overwrite it if somehow it had previous info + # here) + mgg.database['media_entries'].update( + {'_id': entry_id}, + {'$set': {u'state': u'failed', + u'fail_error': None, + u'fail_metadata': {}}}) + + +def process_image(entry): + """ + Code to process an image + """ + workbench = mgg.workbench_manager.create_workbench() queued_filepath = entry['queued_media_file'] queued_filename = workbench.localized_file( mgg.queue_store, queued_filepath, 'source') - thumb = Image.open(queued_filename) + try: + thumb = Image.open(queued_filename) + except IOError: + raise BadMediaFail() + thumb.thumbnail(THUMB_SIZE, Image.ANTIALIAS) # ensure color mode is compatible with jpg if thumb.mode != "RGB": @@ -53,14 +144,12 @@ def process_media_initial(media_id): thumb_filepath = create_pub_filepath(entry, 'thumbnail.jpg') thumb_file = mgg.public_store.get_file(thumb_filepath, 'w') - with thumb_file: + with closing(thumb_file): thumb.save(thumb_file, "JPEG", quality=90) - """ - 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. - """ + # 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) medium_processed = False @@ -73,7 +162,7 @@ def process_media_initial(media_id): medium_filepath = create_pub_filepath(entry, 'medium.jpg') medium_file = mgg.public_store.get_file(medium_filepath, 'w') - with medium_file: + with closing(medium_file): medium.save(medium_file, "JPEG", quality=90) medium_processed = True @@ -84,7 +173,7 @@ def process_media_initial(media_id): with queued_file: original_filepath = create_pub_filepath(entry, queued_filepath[-1]) - with mgg.public_store.get_file(original_filepath, 'wb') as original_file: + with closing(mgg.public_store.get_file(original_filepath, 'wb')) as original_file: original_file.write(queued_file.read()) mgg.queue_store.delete_file(queued_filepath) @@ -94,8 +183,6 @@ def process_media_initial(media_id): media_files_dict['original'] = original_filepath if medium_processed: media_files_dict['medium'] = medium_filepath - entry['state'] = u'processed' - entry.save() # clean up workbench workbench.destroy_self() diff --git a/mediagoblin/process_media/errors.py b/mediagoblin/process_media/errors.py new file mode 100644 index 00000000..f8ae9ab2 --- /dev/null +++ b/mediagoblin/process_media/errors.py @@ -0,0 +1,44 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# 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.util import lazy_pass_to_ugettext as _ + +class BaseProcessingFail(Exception): + """ + Base exception that all other processing failure messages should + subclass from. + + You shouldn't call this itself; instead you should subclass it + and provid the exception_path and general_message applicable to + this error. + """ + general_message = u'' + + @property + def exception_path(self): + return u"%s:%s" % ( + self.__class__.__module__, self.__class__.__name__) + + def __init__(self, **metadata): + self.metadata = metadata or {} + + +class BadMediaFail(BaseProcessingFail): + """ + Error that should be raised when an inappropriate file was given + for the media type specified. + """ + general_message = _(u'Invalid file given for media type.') diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index 59c2f49d..1852b70c 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -1,12 +1,40 @@ +/* @font-face */ + +@font-face { + font-family: 'Lato'; + font-style: normal; + font-weight: 700; + src: local('Lato Bold'), local('Lato-Bold'), url('http://themes.googleusercontent.com/static/fonts/lato/v1/wkfQbvfT_02e2IWO3yYueQ.woff') format('woff'); +} +@font-face { + font-family: 'Lato'; + font-style: italic; + font-weight: 400; + src: local('Lato Italic'), local('Lato-Italic'), url('http://themes.googleusercontent.com/static/fonts/lato/v1/oUan5VrEkpzIazlUe5ieaA.woff') format('woff'); +} +@font-face { + font-family: 'Lato'; + font-style: italic; + font-weight: 700; + src: local('Lato Bold Italic'), local('Lato-BoldItalic'), url('http://themes.googleusercontent.com/static/fonts/lato/v1/HkF_qI1x_noxlxhrhMQYED8E0i7KZn-EPnyo3HZu7kw.woff') format('woff'); +} +@font-face { + font-family: 'Lato'; + font-style: normal; + font-weight: 400; + src: local('Lato Regular'), local('Lato-Regular'), url('http://themes.googleusercontent.com/static/fonts/lato/v1/9k-RPmcnxYEPm8CNFsH2gg.woff') format('woff'); +} + body { background-color: #111; background-image: url("../images/background.png"); - color: #999; + color: #C3C3C3; font-family: sans-serif; padding: none; margin: 0px; height: 100%; font: 16px "HelveticaNeue-Light","Helvetica Neue Light","Helvetica Neue",Helvetica,Arial,sans-serif; + font-family:'Lato', sans-serif; } form { @@ -14,37 +42,28 @@ form { padding: 0px; } -/* Carter One font */ - -@font-face { - font-family: 'Carter One'; - font-style: normal; - font-weight: normal; - src: local('CarterOne'), url('http://themes.googleusercontent.com/font?kit=VjW2qt1pkqVtO22ObxgEBRsxEYwM7FgeyaSgU71cLG0') format('woff'); -} - /* text styles */ h1{ - font-family: 'Carter One',arial,serif; margin-bottom: 15px; margin-top: 15px; color: #fff; - font-size: 30px; + font-size: 1.875em; } h2{ + font-size: 1.375em; margin-top: 20px; color: #fff; } h3{ - border-bottom: 1px solid #222; - font-size: 18px; + border-bottom: 1px solid #333; + font-size: 1.125em; } a { - color: #999; + color: #86D4B1; } a.highlight { @@ -55,6 +74,11 @@ label { font-weight: normal; } +input, textarea { + font-size:1em; + font-family:'Lato', sans-serif; +} + /* website structure */ .mediagoblin_body { @@ -66,10 +90,15 @@ label { height: 36px; padding-top: 14px; margin-bottom: 20px; - border-bottom: 1px solid #222222; + border-bottom: 1px solid #333; +} + +a.mediagoblin_logo{ + color: #fff; + font-weight: bold; } -.header_submit{ +.header_submit, .header_submit_highlight{ color: #272727; background-color: #aaa; background-image: -webkit-gradient(linear, left top, left bottom, from(##D2D2D2), to(#aaa)); @@ -79,22 +108,25 @@ label { background-image: -o-linear-gradient(top, #D2D2D2, #aaa); background-image: linear-gradient(top, #D2D2D2, #aaa); box-shadow: 0px 0px 4px #000; - border-radius: 5px 5px 5px 5px; + border-radius: 3px; margin: 8px; padding: 3px 8px; text-decoration: none; border: medium none; - font-family: 'Carter One',arial,serif; + font-style: normal; +} + +.header_submit_highlight{ +background-image: -moz-linear-gradient(center top , rgb(134, 212, 177), rgb(109, 173, 144)); } .mediagoblin_footer { height: 30px; - border-top: 1px solid #222222; + border-top: 1px solid #333; bottom: 0px; padding-top: 8px; text-align: center; - font-size: 14px; - color: #999; + font-size: 0.875em; } .mediagoblin_content { @@ -108,7 +140,6 @@ label { /* common website elements */ .button { - font-family: 'Carter One', arial, serif; height: 32px; min-width: 99px; background-color: #86d4b1; @@ -119,15 +150,16 @@ label { background-image: -o-linear-gradient(top, #86d4b1, #62caa2); background-image: linear-gradient(top, #86d4b1, #62caa2); box-shadow: 0px 0px 4px #000; - border-radius: 5px; + border-radius: 3px; border: none; color: #272727; margin: 10px 0px 10px 15px; - font-size: 1em; text-align: center; padding-left: 11px; padding-right: 11px; text-decoration: none; + font-family:'Lato', sans-serif; + font-size:1em; } .pagination{ @@ -138,13 +170,20 @@ text-align: center; margin: 5px; } +.empty_space{ + background-color: #222; + font-style: italic; + text-align: center; + height: 160px; + padding-top: 70px; +} + /* forms */ .form_box { background-color: #222; background-image: url("../images/background_lines.png"); background-repeat: repeat-x; - font-size: 18px; padding-bottom: 30px; padding-top: 30px; margin-left: auto; @@ -157,13 +196,8 @@ text-align: center; background-image: url("../images/background_edit.png"); } -.form_box h1 { - font-size: 28px; -} - .form_field_input input, .form_field_input textarea { width: 100%; - font-size: 18px; } .form_field_box { @@ -178,7 +212,6 @@ text-align: center; background-color: #87453b; color: #fff; border: none; - font-size: 16px; padding: 9px; margin-top: 8px; margin-bottom: 8px; @@ -193,7 +226,7 @@ text-align: center; .comment_author { margin-bottom: 40px; padding-top: 4px; - font-size: 14px; + font-size: 0.9em; } .comment_content p { @@ -205,17 +238,26 @@ text-align: center; .media_thumbnail { padding: 0px; width: 180px; - height: 180px; overflow: hidden; float: left; margin: 0px 4px 10px 4px; text-align: center; + font-size: 0.875em; +} + +.media_thumbnail a { + color: #eee; + text-decoration: none; } /* media detail */ -.media_image_container { - text-align: center; +h2.media_title{ + margin-bottom: 0px; +} + +p.media_uploader{ + font-size: 0.9em; } /* icons */ @@ -232,10 +274,9 @@ img.media_icon{ display: block; float: left; text-align: center; - background-color: #222; + background-color: #333; text-decoration: none; padding: 12px 0pt; - font-family: 'Carter One', arial, serif; font-size: 2em; margin: 0 0 20px } @@ -291,3 +332,15 @@ ul.mediaentry_tags li { margin: 0px 5px 0px 0px; padding: 0px; } + + +/* media processing panel */ + +table.media_panel { + width: 100%; +} + +table.media_panel th { + font-weight: bold; + padding-bottom: 4px; +} diff --git a/mediagoblin/static/images/404.png b/mediagoblin/static/images/404.png Binary files differnew file mode 100644 index 00000000..78d746ba --- /dev/null +++ b/mediagoblin/static/images/404.png diff --git a/mediagoblin/static/images/frontpage_image.png b/mediagoblin/static/images/frontpage_image.png Binary files differnew file mode 100644 index 00000000..689eb2c2 --- /dev/null +++ b/mediagoblin/static/images/frontpage_image.png diff --git a/mediagoblin/static/images/goblin.ico b/mediagoblin/static/images/goblin.ico Binary files differnew file mode 100644 index 00000000..f2e7152f --- /dev/null +++ b/mediagoblin/static/images/goblin.ico diff --git a/mediagoblin/static/images/goblin.png b/mediagoblin/static/images/goblin.png Binary files differnew file mode 100644 index 00000000..0a3ad22e --- /dev/null +++ b/mediagoblin/static/images/goblin.png diff --git a/mediagoblin/static/images/icon_feed.png b/mediagoblin/static/images/icon_feed.png Binary files differindex 11e5b1e7..81889473 100644 --- a/mediagoblin/static/images/icon_feed.png +++ b/mediagoblin/static/images/icon_feed.png diff --git a/mediagoblin/static/images/logo.png b/mediagoblin/static/images/logo.png Binary files differindex cf28a6d4..019ec5ec 100644 --- a/mediagoblin/static/images/logo.png +++ b/mediagoblin/static/images/logo.png diff --git a/mediagoblin/storage.py b/mediagoblin/storage.py index 5d6faa4c..d484be1f 100644 --- a/mediagoblin/storage.py +++ b/mediagoblin/storage.py @@ -15,10 +15,10 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. import os -import re import shutil import urlparse import uuid +import cloudfiles from werkzeug.utils import secure_filename @@ -28,11 +28,21 @@ from mediagoblin import util # Errors ######## -class Error(Exception): pass -class InvalidFilepath(Error): pass -class NoWebServing(Error): pass -class NotImplementedError(Error): pass +class Error(Exception): + pass + + +class InvalidFilepath(Error): + pass + + +class NoWebServing(Error): + pass + + +class NotImplementedError(Error): + pass ############################################### @@ -117,7 +127,7 @@ class StorageInterface(object): Eg, if the filename doesn't exist: >>> storage_handler.get_unique_filename(['dir1', 'dir2', 'fname.jpg']) [u'dir1', u'dir2', u'fname.jpg'] - + But if a file does exist, let's get one back with at uuid tacked on: >>> storage_handler.get_unique_filename(['dir1', 'dir2', 'fname.jpg']) [u'dir1', u'dir2', u'd02c3571-dd62-4479-9d62-9e3012dada29-fname.jpg'] @@ -184,7 +194,7 @@ class BasicFileStorage(StorageInterface): """ return os.path.join( self.base_dir, *clean_listy_filepath(filepath)) - + def file_exists(self, filepath): return os.path.exists(self._resolve_filepath(filepath)) @@ -216,6 +226,204 @@ class BasicFileStorage(StorageInterface): return self._resolve_filepath(filepath) +class CloudFilesStorage(StorageInterface): + def __init__(self, **kwargs): + self.param_container = kwargs.get('cloudfiles_container') + self.param_user = kwargs.get('cloudfiles_user') + self.param_api_key = kwargs.get('cloudfiles_api_key') + self.param_host = kwargs.get('cloudfiles_host') + self.param_use_servicenet = kwargs.get('cloudfiles_use_servicenet') + + if not self.param_host: + print('No CloudFiles host URL specified, ' + 'defaulting to Rackspace US') + + self.connection = cloudfiles.get_connection( + username=self.param_user, + api_key=self.param_api_key, + servicenet=True if self.param_use_servicenet == 'true' or \ + self.param_use_servicenet == True else False) + + if not self.param_container == \ + self.connection.get_container(self.param_container): + self.container = self.connection.create_container( + self.param_container) + self.container.make_public( + ttl=60 * 60 * 2) + else: + self.container = self.connection.get_container( + self.param_container) + + def _resolve_filepath(self, filepath): + return '/'.join( + clean_listy_filepath(filepath)) + + def file_exists(self, filepath): + try: + object = self.container.get_object( + self._resolve_filepath(filepath)) + return True + except cloudfiles.errors.NoSuchObject: + return False + + def get_file(self, filepath, mode='r'): + try: + obj = self.container.get_object( + self._resolve_filepath(filepath)) + except cloudfiles.errors.NoSuchObject: + obj = self.container.create_object( + self._resolve_filepath(filepath)) + + return obj + + def delete_file(self, filepath): + # TODO: Also delete unused directories if empty (safely, with + # checks to avoid race conditions). + self.container.delete_object(filepath) + + def file_url(self, filepath): + return self.get_file(filepath).public_uri() + + +class MountStorage(StorageInterface): + """ + Experimental "Mount" virtual Storage Interface + + This isn't an interface to some real storage, instead it's a + redirecting interface, that redirects requests to other + "StorageInterface"s. + + For example, say you have the paths: + + 1. ['user_data', 'cwebber', 'avatar.jpg'] + 2. ['user_data', 'elrond', 'avatar.jpg'] + 3. ['media_entries', '34352f304c3f4d0ad8ad0f043522b6f2', 'thumb.jpg'] + + You could mount media_entries under CloudFileStorage and user_data + under BasicFileStorage. Then 1 would be passed to + BasicFileStorage under the path ['cwebber', 'avatar.jpg'] and 3 + would be passed to CloudFileStorage under + ['34352f304c3f4d0ad8ad0f043522b6f2', 'thumb.jpg']. + + In other words, this is kind of like mounting /home/ and /etc/ + under different filesystems on your operating system... but with + mediagoblin filestorages :) + + To set this up, you currently need to call the mount() method with + the target path and a backend, that shall be available under that + target path. You have to mount things in a sensible order, + especially you can't mount ["a", "b"] before ["a"]. + """ + def __init__(self, **kwargs): + self.mounttab = {} + + def mount(self, dirpath, backend): + """ + Mount a new backend under dirpath + """ + new_ent = clean_listy_filepath(dirpath) + + print "Mounting:", repr(new_ent) + already, rem_1, table, rem_2 = self._resolve_to_backend(new_ent, True) + print "===", repr(already), repr(rem_1), repr(rem_2), len(table) + + assert (len(rem_2) > 0) or (None not in table), \ + "That path is already mounted" + assert (len(rem_2) > 0) or (len(table)==0), \ + "A longer path is already mounted here" + + for part in rem_2: + table[part] = {} + table = table[part] + table[None] = backend + + def _resolve_to_backend(self, filepath, extra_info = False): + """ + extra_info = True is for internal use! + + Normally, returns the backend and the filepath inside that backend. + + With extra_info = True it returns the last directory node and the + remaining filepath from there in addition. + """ + table = self.mounttab + filepath = filepath[:] + res_fp = None + while True: + new_be = table.get(None) + if (new_be is not None) or res_fp is None: + res_be = new_be + res_fp = filepath[:] + res_extra = (table, filepath[:]) + # print "... New res: %r, %r, %r" % (res_be, res_fp, res_extra) + if len(filepath) == 0: + break + query = filepath.pop(0) + entry = table.get(query) + if entry is not None: + table = entry + res_extra = (table, filepath[:]) + else: + break + if extra_info: + return (res_be, res_fp) + res_extra + else: + return (res_be, res_fp) + + def resolve_to_backend(self, filepath): + backend, filepath = self._resolve_to_backend(filepath) + if backend is None: + raise Error("Path not mounted") + return backend, filepath + + def __repr__(self, table = None, indent = []): + res = [] + if table is None: + res.append("MountStorage<") + table = self.mounttab + v = table.get(None) + if v: + res.append(" " * len(indent) + repr(indent) + ": " + repr(v)) + for k, v in table.iteritems(): + if k == None: + continue + res.append(" " * len(indent) + repr(k) + ":") + res += self.__repr__(v, indent + [k]) + if table is self.mounttab: + res.append(">") + return "\n".join(res) + else: + return res + + def file_exists(self, filepath): + backend, filepath = self.resolve_to_backend(filepath) + return backend.file_exists(filepath) + + def get_file(self, filepath, mode='r'): + backend, filepath = self.resolve_to_backend(filepath) + return backend.get_file(filepath, mode) + + def delete_file(self, filepath): + backend, filepath = self.resolve_to_backend(filepath) + return backend.delete_file(filepath) + + def file_url(self, filepath): + backend, filepath = self.resolve_to_backend(filepath) + return backend.file_url(filepath) + + def get_local_path(self, filepath): + backend, filepath = self.resolve_to_backend(filepath) + return backend.get_local_path(filepath) + + def copy_locally(self, filepath, dest_path): + """ + Need to override copy_locally, because the local_storage + attribute is not correct. + """ + backend, filepath = self.resolve_to_backend(filepath) + backend.copy_locally(filepath, dest_path) + + ########### # Utilities ########### @@ -247,43 +455,36 @@ def clean_listy_filepath(listy_filepath): return cleaned_filepath -def storage_system_from_config(paste_config, storage_prefix): +def storage_system_from_config(config_section): """ - Utility for setting up a storage system from the paste app config. + Utility for setting up a storage system from a config section. - Note that a special argument may be passed in to the paste_config - which is "${storage_prefix}_storage_class" which will provide an + Note that a special argument may be passed in to + the config_section which is "storage_class" which will provide an import path to a storage system. This defaults to "mediagoblin.storage:BasicFileStorage" if otherwise undefined. Arguments: - - paste_config: dictionary of config parameters - - storage_prefix: the storage system we're setting up / will be - getting keys/arguments from. For example 'publicstore' will - grab all arguments that are like 'publicstore_FOO'. + - config_section: dictionary of config parameters Returns: An instantiated storage system. Example: storage_system_from_config( - {'publicstore_base_url': '/media/', - 'publicstore_base_dir': '/var/whatever/media/'}, - 'publicstore') + {'base_url': '/media/', + 'base_dir': '/var/whatever/media/'}) Will return: BasicFileStorage( base_url='/media/', base_dir='/var/whatever/media') """ - prefix_re = re.compile('^%s_(.+)$' % re.escape(storage_prefix)) + # This construct is needed, because dict(config) does + # not replace the variables in the config items. + config_params = dict(config_section.iteritems()) - config_params = dict( - [(prefix_re.match(key).groups()[0], value) - for key, value in paste_config.iteritems() - if prefix_re.match(key)]) - - if config_params.has_key('storage_class'): + if 'storage_class' in config_params: storage_class = config_params['storage_class'] config_params.pop('storage_class') else: @@ -291,5 +492,3 @@ def storage_system_from_config(paste_config, storage_prefix): storage_class = util.import_component(storage_class) return storage_class(**config_params) - - diff --git a/mediagoblin/submit/forms.py b/mediagoblin/submit/forms.py index f02c95a6..4519b057 100644 --- a/mediagoblin/submit/forms.py +++ b/mediagoblin/submit/forms.py @@ -16,15 +16,17 @@ import wtforms + from mediagoblin.util import tag_length_validator +from mediagoblin.util import fake_ugettext_passthrough as _ class SubmitStartForm(wtforms.Form): + file = wtforms.FileField(_('File')) title = wtforms.TextField( - 'Title', + _('Title'), [wtforms.validators.Length(min=0, max=500)]) description = wtforms.TextAreaField('Description of this work') - file = wtforms.FileField('File') tags = wtforms.TextField( - 'Tags', + _('Tags'), [tag_length_validator]) diff --git a/mediagoblin/submit/views.py b/mediagoblin/submit/views.py index 126cf3a8..4481adeb 100644 --- a/mediagoblin/submit/views.py +++ b/mediagoblin/submit/views.py @@ -14,22 +14,21 @@ # 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 mediagoblin.mg_globals as mg_globals -from datetime import datetime - +import uuid from os.path import splitext from cgi import FieldStorage -from string import split from werkzeug.utils import secure_filename +from mediagoblin.db.util import ObjectId from mediagoblin.util import ( render_to_response, redirect, cleaned_markdown_conversion, \ convert_to_tag_list_of_dicts) +from mediagoblin.util import pass_to_ugettext as _ from mediagoblin.decorators import require_active_login from mediagoblin.submit import forms as submit_forms, security -from mediagoblin.process_media import process_media_initial +from mediagoblin.process_media import process_media, mark_entry_failed from mediagoblin.messages import add_message, SUCCESS @@ -45,15 +44,16 @@ def submit_start(request): and isinstance(request.POST['file'], FieldStorage) and request.POST['file'].file): submit_form.file.errors.append( - u'You must provide a file.') + _(u'You must provide a file.')) elif not security.check_filetype(request.POST['file']): submit_form.file.errors.append( - u'The file doesn\'t seem to be an image!') + _(u"The file doesn't seem to be an image!")) else: filename = request.POST['file'].filename # create entry and save in database entry = request.db.MediaEntry() + entry['_id'] = ObjectId() entry['title'] = ( request.POST['title'] or unicode(splitext(filename)[0])) @@ -69,10 +69,6 @@ def submit_start(request): entry['tags'] = convert_to_tag_list_of_dicts( request.POST.get('tags')) - # Save, just so we can get the entry id for the sake of using - # it to generate the file path - entry.save(validate=False) - # Generate a slug from the title entry.generate_slug() @@ -91,12 +87,39 @@ def submit_start(request): # Add queued filename to the entry entry['queued_media_file'] = queue_filepath - entry.save(validate=True) - # queue it for processing - process_media_initial.delay(unicode(entry['_id'])) + # We generate this ourselves so we know what the taks id is for + # retrieval later. + # (If we got it off the task's auto-generation, there'd be a risk of + # a race condition when we'd save after sending off the task) + task_id = unicode(uuid.uuid4()) + entry['queued_task_id'] = task_id + + # Save now so we have this data before kicking off processing + entry.save(validate=True) - add_message(request, SUCCESS, 'Woohoo! Submitted!') + # Pass off to processing + # + # (... don't change entry after this point to avoid race + # conditions with changes to the document via processing code) + try: + process_media.apply_async( + [unicode(entry['_id'])], {}, + task_id=task_id) + except BaseException as exc: + # The purpose of this section is because when running in "lazy" + # or always-eager-with-exceptions-propagated celery mode that + # the failure handling won't happen on Celery end. Since we + # expect a lot of users to run things in this way we have to + # capture stuff here. + # + # ... not completely the diaper pattern because the exception is + # re-raised :) + mark_entry_failed(entry[u'_id'], exc) + # re-raise the exception + raise + + add_message(request, SUCCESS, _('Woohoo! Submitted!')) return redirect(request, "mediagoblin.user_pages.user_home", user = request.user['username']) diff --git a/mediagoblin/templates/mediagoblin/404.html b/mediagoblin/templates/mediagoblin/404.html new file mode 100644 index 00000000..5af46a87 --- /dev/null +++ b/mediagoblin/templates/mediagoblin/404.html @@ -0,0 +1,34 @@ +{# +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# 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 %} + <h1>{% trans %}Oops!{% endtrans %}</h1> + + <div class="grid_8 alpha"> + <p>{% trans %}There doesn't seem to be a page at this address. Sorry!{% endtrans %}</p> + <p> + {%- trans %}If you're sure the address is correct, maybe the page you're looking for has been moved or deleted.{% endtrans -%} + </p> + </div> + + <div class="grid_8 omega"> + <img src="{{ request.staticdirect('/images/404.png') }}" + alt="{% trans %}Image of 404 goblin stressing out{% endtrans %}" /> + </div> +{% endblock %} diff --git a/mediagoblin/templates/mediagoblin/auth/login.html b/mediagoblin/templates/mediagoblin/auth/login.html index e25783ea..afbecf20 100644 --- a/mediagoblin/templates/mediagoblin/auth/login.html +++ b/mediagoblin/templates/mediagoblin/auth/login.html @@ -23,20 +23,27 @@ <form action="{{ request.urlgen('mediagoblin.auth.login') }}" method="POST" enctype="multipart/form-data"> <div class="grid_6 prefix_1 suffix_1 form_box"> - <h1>Log in</h1> + <h1>{% trans %}Log in{% endtrans %}</h1> {% if login_failed %} - <div class="form_field_error">Login failed!</div> + <div class="form_field_error"> + {% trans %}Logging in failed!{% endtrans %} + </div> {% endif %} {{ wtforms_util.render_divs(login_form) }} <div class="form_submit_buttons"> - <input type="submit" value="submit" class="button"/> + <input type="submit" value="{% trans %}Log in{% endtrans %}" class="button"/> </div> {% if next %} <input type="hidden" name="next" value="{{ next }}" class="button" style="display: none;"/> {% endif %} {% if allow_registration %} - <p>Don't have an account yet?<br /><a href="{{ request.urlgen('mediagoblin.auth.register') }}">Create one here!</a></p> + <p> + {% trans %}Don't have an account yet?{% endtrans %} + <br /> + <a href="{{ request.urlgen('mediagoblin.auth.register') }}"> + {%- trans %}Create one here!{% endtrans %}</a> + </p> {% endif %} </div> </form> diff --git a/mediagoblin/templates/mediagoblin/auth/register.html b/mediagoblin/templates/mediagoblin/auth/register.html index f77b3782..d9eedc4a 100644 --- a/mediagoblin/templates/mediagoblin/auth/register.html +++ b/mediagoblin/templates/mediagoblin/auth/register.html @@ -24,10 +24,11 @@ <form action="{{ request.urlgen('mediagoblin.auth.register') }}" method="POST" enctype="multipart/form-data"> <div class="grid_6 prefix_1 suffix_1 form_box"> - <h1>Create an account!</h1> + <h1>{% trans %}Create an account!{% endtrans %}</h1> {{ wtforms_util.render_divs(register_form) }} <div class="form_submit_buttons"> - <input type="submit" value="submit" class="button" /> + <input type="submit" value="{% trans %}Create{% endtrans %}" + class="button" /> </div> </div> </form> diff --git a/mediagoblin/templates/mediagoblin/auth/resent_verification_email.html b/mediagoblin/templates/mediagoblin/auth/resent_verification_email.html index da3a9e99..8fd80ee9 100644 --- a/mediagoblin/templates/mediagoblin/auth/resent_verification_email.html +++ b/mediagoblin/templates/mediagoblin/auth/resent_verification_email.html @@ -19,6 +19,6 @@ {% block mediagoblin_content %} <p> - Resent your verification email. + {% trans %}Resent your verification email.{% endtrans %} </p> {% endblock %} diff --git a/mediagoblin/templates/mediagoblin/auth/verification_email.txt b/mediagoblin/templates/mediagoblin/auth/verification_email.txt index 7863374d..32053101 100644 --- a/mediagoblin/templates/mediagoblin/auth/verification_email.txt +++ b/mediagoblin/templates/mediagoblin/auth/verification_email.txt @@ -14,9 +14,13 @@ # # 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 {{ username }}, -to activate your GNU MediaGoblin account, open the following URL in your web browser +to activate your GNU MediaGoblin account, open the following URL in +your web browser: -{{ verification_url|safe }} +{{ verification_url }} +{%- endtrans %} diff --git a/mediagoblin/templates/mediagoblin/base.html b/mediagoblin/templates/mediagoblin/base.html index 4da685f9..32d5a5d2 100644 --- a/mediagoblin/templates/mediagoblin/base.html +++ b/mediagoblin/templates/mediagoblin/base.html @@ -19,7 +19,7 @@ <html> <head> <meta charset="utf-8"> - <title>{% block title %}GNU MediaGoblin{% endblock title %}</title> + <title>{% block title %}{% trans %}GNU MediaGoblin{% endtrans %}{% endblock title %}</title> <link rel="stylesheet" type="text/css" href="{{ request.staticdirect('/css/extlib/reset.css') }}"/> <link rel="stylesheet" type="text/css" @@ -28,6 +28,8 @@ href="{{ request.staticdirect('/css/extlib/960_16_col.css') }}"/> <link rel="stylesheet" type="text/css" href="{{ request.staticdirect('/css/base.css') }}"/> + <link rel="shortcut icon" + href="{{ request.staticdirect('/images/goblin.ico') }}" /> {% block mediagoblin_head %} {% endblock mediagoblin_head %} </head> @@ -40,15 +42,14 @@ <div class="grid_16 mediagoblin_header"> {% block mediagoblin_logo %} <a class="mediagoblin_logo" - href="{{ request.urlgen('index') }}"> - <img src="{{ request.staticdirect('/images/logo.png') }}" - alt="Mediagoblin logo" /> - </a> + href="{{ request.urlgen('index') }}" + ><img src="{{ request.staticdirect('/images/logo.png') }}" + alt="{% trans %}MediaGoblin logo{% endtrans %}" /></a> {% endblock %} {% if request.user and request.user['status'] == 'active' %} <a class="header_submit" href="{{ request.urlgen('mediagoblin.submit.start') }}"> - Submit media + {% trans %}Submit media{% endtrans %} </a> {% endif %} {% block mediagoblin_header_title %}{% endblock %} @@ -59,17 +60,17 @@ <a href="{{ request.urlgen('mediagoblin.user_pages.user_home', user=request.user['username']) }}" class="header_submit"> - verify your email!</a> + {% trans %}verify your email!{% endtrans %}</a> {% endif %} <a href="{{ request.urlgen('mediagoblin.user_pages.user_home', user= request.user['username']) }}"> {{ request.user['username'] }}</a> - (<a href="{{ request.urlgen('mediagoblin.auth.logout') }}">logout</a>) + (<a href="{{ request.urlgen('mediagoblin.auth.logout') }}">log out</a>) {% else %} <a href="{{ request.urlgen('mediagoblin.auth.login') }}"> - Login</a> + {% trans %}Log in{% endtrans %}</a> {% endif %} </div> </div> @@ -85,7 +86,9 @@ {% block mediagoblin_footer %} <div class="container_16"> <div class="grid_16 mediagoblin_footer"> - Powered by <a href="http://mediagoblin.org">MediaGoblin</a>, a <a href="http://gnu.org/">GNU project</a> + {% trans -%} + Powered by <a href="http://mediagoblin.org">MediaGoblin</a>, a <a href="http://gnu.org/">GNU project</a> + {%- endtrans %} </div> </div> {% endblock %} diff --git a/mediagoblin/templates/mediagoblin/edit/edit.html b/mediagoblin/templates/mediagoblin/edit/edit.html index d19034cb..3dc170c8 100644 --- a/mediagoblin/templates/mediagoblin/edit/edit.html +++ b/mediagoblin/templates/mediagoblin/edit/edit.html @@ -26,15 +26,15 @@ media= media._id) }}" method="POST" enctype="multipart/form-data"> <div class="grid_8 prefix_1 suffix_1 edit_box form_box"> - <h1>Editing {{ media.title }}</h1> + <h1>{% trans media_title=media.title %}Editing {{ media_title }}{% endtrans %}</h1> <div style="text-align: center;" > <img src="{{ request.app.public_store.file_url( media['media_files']['thumb']) }}" /> </div> {{ wtforms_util.render_divs(form) }} <div class="form_submit_buttons"> - <a href="{{ media.url_for_self(request.urlgen) }}">Cancel</a> - <input type="submit" value="Save changes" class="button" /> + <a href="{{ media.url_for_self(request.urlgen) }}">{% trans %}Cancel{% endtrans %}</a> + <input type="submit" value="{% trans %}Save changes{% endtrans %}" class="button" /> </div> </div> </form> diff --git a/mediagoblin/templates/mediagoblin/edit/edit_profile.html b/mediagoblin/templates/mediagoblin/edit/edit_profile.html index a11b86d7..bed5e0ca 100644 --- a/mediagoblin/templates/mediagoblin/edit/edit_profile.html +++ b/mediagoblin/templates/mediagoblin/edit/edit_profile.html @@ -25,10 +25,14 @@ user['username'] }}" method="POST" enctype="multipart/form-data"> <div class="grid_8 prefix_1 suffix_1 edit_box form_box"> - <h1>Editing {{ user['username'] }}'s profile</h1> + <h1> + {%- trans username=user['username'] -%} + Editing {{ username }}'s profile + {%- endtrans %} + </h1> {{ wtforms_util.render_divs(form) }} <div class="form_submit_buttons"> - <input type="submit" value="submit" class="button" /> + <input type="submit" value="{% trans %}Save changes{% endtrans %}" class="button" /> </div> </div> </form> diff --git a/mediagoblin/templates/mediagoblin/listings/tag.html b/mediagoblin/templates/mediagoblin/listings/tag.html index 6f10ec8d..289f44b8 100644 --- a/mediagoblin/templates/mediagoblin/listings/tag.html +++ b/mediagoblin/templates/mediagoblin/listings/tag.html @@ -17,6 +17,8 @@ #} {% extends "mediagoblin/base.html" %} +{% from "mediagoblin/utils/object_gallery.html" import object_gallery %} + {% block mediagoblin_head %} <link rel="alternate" type="application/atom+xml" href="{{ request.urlgen( @@ -26,16 +28,17 @@ {% block mediagoblin_content -%} <h1> - Media tagged with: {{ tag_name }} + {% trans %}Media tagged with:{% endtrans %} {{ tag_name }} </h1> <div class="container_16 media_gallery"> - {% include "mediagoblin/utils/object_gallery.html" %} + {{ object_gallery(request, media_entries, pagination) }} </div> <div class="grid_16"> - <a href="{{ request.urlgen( - 'mediagoblin.listings.tag_atom_feed', - tag=tag_slug) }}">atom feed</a> + {% set feed_url = request.urlgen( + 'mediagoblin.listings.tag_atom_feed', + tag=tag_slug) %} + {% include "mediagoblin/utils/feed_link.html" %} </div> {% endblock %} diff --git a/mediagoblin/templates/mediagoblin/root.html b/mediagoblin/templates/mediagoblin/root.html index ed7b931f..08155c17 100644 --- a/mediagoblin/templates/mediagoblin/root.html +++ b/mediagoblin/templates/mediagoblin/root.html @@ -17,27 +17,36 @@ #} {% extends "mediagoblin/base.html" %} -{% block mediagoblin_content %} - <h1>{% trans %}Welcome to GNU MediaGoblin!{% endtrans %}</h1> +{% from "mediagoblin/utils/object_gallery.html" import object_gallery %} +{% block mediagoblin_content %} {% if request.user %} - <p> - <a href="{{ request.urlgen('mediagoblin.submit.start') }}">Submit an item</a> - </p> + <h1>Explore</h1> {% else %} - <p> - If you have an account, you can - <a href="{{ request.urlgen('mediagoblin.auth.login') }}">Login</a>. - </p> - {% if allow_registration %} - <p> - If you don't have an account, please - <a href="{{ request.urlgen('mediagoblin.auth.register') }}">Register</a>. - </p> - {% endif %} - {% endif %} + <div class="grid_11 alpha"> + <h1>{% trans %}Hi there, media lover! MediaGoblin is...{% endtrans %}</h1> + <ul> + <li>{% trans %}The perfect place for your media!{% endtrans %}</li> + <li>{% trans %}A place for people to collaborate and show off original and derived creations!{% endtrans %}</li> + <li>{% trans %}Free, as in freedom. (We’re a <a href="http://gnu.org">GNU project</a> in the making, after all.){% endtrans %}</li> + <li>{% trans %}Aiming to make the world a better place through decentralization and (eventually, coming soon!) federation!{% endtrans %}</li> + <li>{% trans %}Built for extensibility. (Multiple media types coming soon to the software, including video support!){% endtrans %}</li> + <li>{% trans %}Powered by people like you. (<a href="http://mediagoblin.org/pages/join.html">You can help us improve this software!</a>){% endtrans %}</li> + </ul> - {# temporarily, an "image gallery" that isn't one really ;) #} + {% if allow_registration %} + <p>Excited to join us? To add your own media, make collections and save favorites...<p> + <a class="header_submit_highlight" href="{{ request.urlgen('mediagoblin.auth.register') }}">Create a free account</a> or + <a class="header_submit" href="http://wiki.mediagoblin.org/HackingHowto">Set up MediaGoblin on your own server</a> + {% endif %} + </div> - {% include "mediagoblin/utils/object_gallery.html" %} + <div class="grid_5 omega"> + <img src="{{ request.staticdirect('/images/frontpage_image.png') }}" /> + </div> + + <div class="clear"></div> + {% endif %} + <h2>Most recent media</h2> + {{ object_gallery(request, media_entries, pagination) }} {% endblock %} diff --git a/mediagoblin/templates/mediagoblin/submit/start.html b/mediagoblin/templates/mediagoblin/submit/start.html index 6d00510c..3a40850d 100644 --- a/mediagoblin/templates/mediagoblin/submit/start.html +++ b/mediagoblin/templates/mediagoblin/submit/start.html @@ -23,13 +23,10 @@ <form action="{{ request.urlgen('mediagoblin.submit.start') }}" method="POST" enctype="multipart/form-data"> <div class="grid_8 prefix_1 suffix_1 form_box"> - <h1>Submit yer media</h1> - {{ wtforms_util.render_field_div(submit_form.file) }} - {{ wtforms_util.render_field_div(submit_form.title) }} - {{ wtforms_util.render_textarea_div(submit_form.description) }} - {{ wtforms_util.render_field_div(submit_form.tags) }} + <h1>{% trans %}Submit yer media{% endtrans %}</h1> + {{ wtforms_util.render_divs(submit_form) }} <div class="form_submit_buttons"> - <input type="submit" value="Submit" class="button" /> + <input type="submit" value="{% trans %}Submit{% endtrans %}" class="button" /> </div> </div> </form> diff --git a/mediagoblin/templates/mediagoblin/user_pages/gallery.html b/mediagoblin/templates/mediagoblin/user_pages/gallery.html index 637c892d..3a3d2373 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/gallery.html +++ b/mediagoblin/templates/mediagoblin/user_pages/gallery.html @@ -17,6 +17,8 @@ #} {% extends "mediagoblin/base.html" %} +{% from "mediagoblin/utils/object_gallery.html" import object_gallery %} + {% block mediagoblin_head %} <link rel="alternate" type="application/atom+xml" href="{{ request.urlgen( @@ -27,21 +29,26 @@ {% block mediagoblin_content -%} {% if user %} <h1> - <a href="{{ request.urlgen( - 'mediagoblin.user_pages.user_home', - user=user.username) }}">{{ user.username }}</a>'s media</h1> + {%- trans username=user.username, + user_url=request.urlgen( + 'mediagoblin.user_pages.user_home', + user=user.username) -%} + <a href="{{ user_url }}">{{ username }}</a>'s media + {%- endtrans %} + </h1> - </div> <div class="container_16 media_gallery"> - {% include "mediagoblin/utils/object_gallery.html" %} + {{ object_gallery(request, media_entries, pagination) }} </div> + <div class="grid_16"> - <a href={{ request.urlgen( - 'mediagoblin.user_pages.atom_feed', - user=user.username) }}>atom feed</a> + {% set feed_url = request.urlgen( + 'mediagoblin.user_pages.atom_feed', + user=user.username) %} + {% include "mediagoblin/utils/feed_link.html" %} </div> {% else %} {# This *should* not occur as the view makes sure we pass in a user. #} - <p>Sorry, no such user found.<p/> + <p>{% trans %}Sorry, no such user found.{% endtrans %}<p/> {% endif %} {% endblock %} diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index 1a5eed1f..08d5dbe9 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -24,38 +24,54 @@ {% if media %} <div class="grid_11 alpha"> <div class="media_image_container"> - <img class="media_image" - src="{{ request.app.public_store.file_url( - media.get_display_media(media.media_files)) }}" /> + {% set display_media = request.app.public_store.file_url( + media.get_display_media(media.media_files)) %} + + {# if there's a medium file size, that means the medium size + # isn't the original... so link to the original! + #} + {% if media['media_files'].has_key('medium') %} + <a href="{{ request.app.public_store.file_url( + media['media_files']['original']) }}"> + <img class="media_image" + src="{{ display_media }}" + alt="Image for {{ media.title }}" /> + </a> + {% else %} + <img class="media_image" + src="{{ display_media }}" + alt="Image for {{ media.title }}" /> + {% endif %} </div> - <h2> - {{media.title}} + <h2 class="media_title"> + {{ media.title }} </h2> + <p class="media_uploader"> + {% trans date=media.created.strftime("%Y-%m-%d"), + user_url=request.urlgen( + 'mediagoblin.user_pages.user_home', + user=media.uploader().username), + username=media.uploader().username -%} + Uploaded on {{ date }} by <a href="{{ user_url }}">{{ username }}</a> + {%- endtrans %} + </p> + {% autoescape False %} <p>{{ media.description_html }}</p> {% endautoescape %} - <p> - — uploaded on - {{ "%4d-%02d-%02d"|format(media.created.year, - media.created.month, media.created.day) }} - by - <a href="{{ request.urlgen('mediagoblin.user_pages.user_home', - user= media.uploader().username) }}"> - {{- media.uploader().username }}</a> - </p> <br /> + <h3>{% trans %}Comments{% endtrans %}</h3> - <h3>Comments</h3> {% if request.user %} <form action="{{ request.urlgen('mediagoblin.user_pages.media_post_comment', user= media.uploader().username, media=media._id) }}" method="POST"> - {{ wtforms_util.render_field_div(comment_form.comment_content) }} + {{ wtforms_util.render_divs(comment_form) }} <div class="form_submit_buttons"> - <input type="submit" value="Post comment!" class="button" /> + <input type="submit" value="{% trans %}Post comment!{% endtrans %}" class="button" /> </div> </form> {% endif %} @@ -69,26 +85,23 @@ {% else %} <div class="comment_wrapper" id="comment-{{ comment['_id'] }}"> {% endif %} + <div class="comment_content"> {% autoescape False %} {{ comment.content_html }} {% endautoescape %} </div> + <div class="comment_author">— <a href="{{ request.urlgen('mediagoblin.user_pages.user_home', - user = comment_author['username']) }}"> - {{ comment_author['username'] }}</a> at - <!--</div> - <div class="comment_datetime">--> + user = comment_author['username']) }}"> + {{ comment_author['username'] }}</a> + {% trans %}at{% endtrans %} <a href="{{ request.urlgen('mediagoblin.user_pages.media_home.view_comment', comment = comment['_id'], user = media.uploader().username, media = media._id) }}#comment"> - {{ "%4d-%02d-%02d %02d:%02d"|format(comment.created.year, - comment.created.month, - comment.created.day, - comment.created.hour, - comment.created.minute) }} + {{ comment.created.strftime("%Y-%m-%d %I:%M%p") }} </a> </div> </div> @@ -103,45 +116,42 @@ <div class="grid_5 omega"> {% include "mediagoblin/utils/prev_next.html" %} - <h3>Sidebar content here!</h3> - {% if media.attachment_files or media['uploader'] == request.user['_id'] or - request.user['is_admin'] %} - - <p> - {% if media['uploader'] == request.user['_id'] or - request.user['is_admin'] %} - <p> - <a href="{{ request.urlgen('mediagoblin.edit.edit_media', - user= media.uploader().username, - media= media._id) }}" - ><img src="{{ request.staticdirect('/images/icon_edit.png') }}" - class="media_icon" />edit</a> - </p> - <p> - <img src="{{ request.staticdirect('/images/icon_delete.png') }}" - class="media_icon" />delete - </p> - {% endif %} - </p> + + {% if media['uploader'] == request.user['_id'] or + request.user['is_admin'] %} + <h3>Temporary button holder</h3> + <p> + <a href="{{ request.urlgen('mediagoblin.edit.edit_media', + user= media.uploader().username, + media= media._id) }}" + ><img src="{{ request.staticdirect('/images/icon_edit.png') }}" + class="media_icon" />edit</a> + </p> + <p> + <img src="{{ request.staticdirect('/images/icon_delete.png') }}" + class="media_icon" />{% trans %}delete{% endtrans %} + </p> + {% endif %} {% if media.attachment_files|count %} - <h3>Attachments</h3> - <ul> - {% for attachment in media.attachment_files %} - <li> - <a href="{{ request.app.public_store.file_url( - attachment.filepath) }}"> - {{ attachment.name }} - </a> - </li> - {% endfor %} - {% endif %} - </ul> + <h3>Attachments</h3> + <ul> + {% for attachment in media.attachment_files %} + <li> + <a href="{{ request.app.public_store.file_url(attachment.filepath) }}"> + {{ attachment.name }} + </a> + </li> + {% endfor %} + </ul> {% endif %} - {% if app_config['allow_attachments'] %} + + {% if app_config['allow_attachments'] + and (media['uploader'] == request.user['_id'] + or request.user['is_admin']) %} <a href="{{ request.urlgen('mediagoblin.edit.attachments', - user= media.uploader().username, - media= media._id) }}">Add attachment</a> + user=media.uploader().username, + media=media._id) }}">Add attachment</a> {% endif %} {% if media.tags %} @@ -149,6 +159,6 @@ {% endif %} </div> {% else %} - <p>Sorry, no such media found.<p/> + <p>{% trans %}Sorry, no such media found.{% endtrans %}<p/> {% endif %} {% endblock %} diff --git a/mediagoblin/templates/mediagoblin/user_pages/processing_panel.html b/mediagoblin/templates/mediagoblin/user_pages/processing_panel.html new file mode 100644 index 00000000..abc7efd3 --- /dev/null +++ b/mediagoblin/templates/mediagoblin/user_pages/processing_panel.html @@ -0,0 +1,67 @@ +{# +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# 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 %} + +<h1>{% trans %}Media processing panel{% endtrans %}</h1> + +<p> + {% trans %}You can track the state of media being processed for your gallery here.{% endtrans %} +</p> + +<h2>{% trans %}Media in-processing{% endtrans %}</h2> + +{% if processing_entries.count() %} + <table class="media_panel processing"> + <tr> + <th>Title</th> + <th>When submitted</th> + <th>Status</th> + </tr> + {% for media_entry in processing_entries %} + <tr> + <td>{{ media_entry['title'] }}</td> + <td>{{ media_entry['created'].strftime("%m-%d-%Y %I:%M %p") }}</td> + <td></td> + </tr> + {% endfor %} + </table> +{% else %} + <p><i>{% trans %}No media in-processing{% endtrans %}</i></p> +{% endif %} + +{% if failed_entries.count() %} + <h2>{% trans %}These uploads failed to process:{% endtrans %}</h2> + + <table class="media_panel failed"> + <tr> + <th>Title</th> + <th>When submitted</th> + <th>Reason for failure</th> + </tr> + {% for media_entry in failed_entries %} + <tr> + <td>{{ media_entry['title'] }}</td> + <td>{{ media_entry['created'].strftime("%m-%d-%Y %I:%M %p") }}</td> + <td>{{ media_entry.get_fail_exception().general_message }}</td> + </tr> + {% endfor %} + </table> +{% endif %} +{% endblock %} diff --git a/mediagoblin/templates/mediagoblin/user_pages/user.html b/mediagoblin/templates/mediagoblin/user_pages/user.html index 76cf36be..0214082c 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/user.html +++ b/mediagoblin/templates/mediagoblin/user_pages/user.html @@ -17,6 +17,8 @@ #} {% extends "mediagoblin/base.html" %} +{% from "mediagoblin/utils/object_gallery.html" import object_gallery %} + {% block mediagoblin_head %} <link rel="alternate" type="application/atom+xml" href="{{ request.urlgen( @@ -27,66 +29,128 @@ {% block mediagoblin_content -%} {# If no user... #} {% if not user %} - <p>Sorry, no such user found.<p/> + <p>{% trans %}Sorry, no such user found.{% endtrans %}<p/> {# User exists, but needs verification #} {% elif user.status == "needs_email_verification" %} {% if user == request.user %} {# this should only be visible when you are this user #} <div class="grid_6 prefix_1 suffix_1 form_box"> - <h1>Verification needed</h1> + <h1>{% trans %}Verification needed{% endtrans %}</h1> - <p>Almost done! Your account still needs to be verified.</p> <p> - An email should arrive in a few moments with instructions - on how to do so. + {% trans -%} + Almost done! Your account still needs to be verified. + {%- endtrans %} + </p> + <p> + {% trans -%} + An email should arrive in a few moments with instructions on how to do so. + {%- endtrans %} </p> - <p>In case it doesn't:</p> + <p>{% trans %}In case it doesn't:{% endtrans %}</p> <a href="{{ request.urlgen('mediagoblin.auth.resend_verification') }}" - class="button">Resend verification email</a> + class="button">{% trans %}Resend verification email{% endtrans %}</a> </div> {% else %} {# if the user is not you, but still needs to verify their email #} <div class="grid_6 prefix_1 suffix_1 form_box"> - <h1>Verification needed</h1> + <h1>{% trans %}Verification needed{% endtrans %}</h1> <p> - Someone has registered an account with this username, but it - still has to be verified. + {% trans -%} + Someone has registered an account with this username, but it still has to be verified. + {%- endtrans %} </p> <p> - If you are that person but you've lost your verification - email, you can - <a href="{{ request.urlgen('mediagoblin.auth.login') }}">log in</a> - and resend it. + {% trans login_url=request.urlgen('mediagoblin.auth.login') -%} + If you are that person but you've lost your verification email, you can <a href="{{ login_url }}">log in</a> and resend it. + {%- endtrans %} </p> </div> {% endif %} {# Active(?) (or at least verified at some point) user, horray! #} {% else %} - <h1>{{ user.username }}'s profile</h1> + <h1> + {%- trans username=user.username %}{{ username }}'s profile{% endtrans -%} + </h1> - <div class="grid_6 alpha"> - {% include "mediagoblin/utils/profile.html" %} - {% if request.user['_id'] == user['_id'] or request.user['is_admin'] %} - <a href="{{ request.urlgen('mediagoblin.edit.profile') }}?username={{ - user.username }}">Edit profile</a> + {% if not user['url'] and not user['profile'] %} + {% if request.user['_id'] == user['_id'] %} + <div class="grid_6 alpha empty_space"> + <p> + {% trans %}Here's a spot to tell others about yourself.{% endtrans %} + </p> + <a href="{{ request.urlgen('mediagoblin.edit.profile') }}?username={{ + user.username }}" + class="header_submit"> + {%- trans %}Edit profile{% endtrans -%} + </a> + </div> + {% else %} + <div class="grid_6 alpha empty_space"> + <p> + {% trans -%} + This user hasn't filled in their profile (yet). + {%- endtrans %} + </p> + </div> {% endif %} - </div> - - <div class="grid_10 omega"> - {% set pagination_base_url = user_gallery_url %} - {% include "mediagoblin/utils/object_gallery.html" %} - <div class="clear"></div> - <p><a href="{{ user_gallery_url }}">View all of {{ user.username }}'s media</a></p> - <a href={{ request.urlgen( - 'mediagoblin.user_pages.atom_feed', - user=user.username) }}>atom feed</a> - </div> + {% else %} + <div class="grid_6 alpha"> + {% include "mediagoblin/utils/profile.html" %} + {% if request.user['_id'] == user['_id'] or request.user['is_admin'] %} + <a href="{{ request.urlgen('mediagoblin.edit.profile') }}?username={{ + user.username }}"> + {%- trans %}Edit profile{% endtrans -%} + </a> + {% endif %} + </div> + {% endif %} + {% if media_entries.count() %} + <div class="grid_10 omega"> + {{ object_gallery(request, media_entries, pagination, + pagination_base_url=user_gallery_url, col_number=3) }} + {% include "mediagoblin/utils/object_gallery.html" %} + <div class="clear"></div> + <p> + <a href="{{ user_gallery_url }}"> + {% trans username=user.username -%} + View all of {{ username }}'s media{% endtrans -%} + </a> + </p> + {% set feed_url = request.urlgen( + 'mediagoblin.user_pages.atom_feed', + user=user.username) %} + {% include "mediagoblin/utils/feed_link.html" %} + </div> + {% else %} + {% if request.user['_id'] == user['_id'] %} + <div class="grid_10 omega empty_space"> + <p> + {% trans -%} + This is where your media will appear, but you don't seem to have added anything yet. + {%- endtrans %} + </p> + <a class="header_submit" + href="{{ request.urlgen('mediagoblin.submit.start') }}"> + {%- trans %}Add media{% endtrans -%} + </a> + </div> + {% else %} + <div class="grid_10 omega empty_space"> + <p> + {% trans -%} + There doesn't seem to be any media here yet... + {%- endtrans %} + </p> + </div> + {% endif %} + {% endif %} <div class="clear"></div> {% endif %} {% endblock %} diff --git a/mediagoblin/templates/mediagoblin/utils/feed_link.html b/mediagoblin/templates/mediagoblin/utils/feed_link.html new file mode 100644 index 00000000..c4036bf3 --- /dev/null +++ b/mediagoblin/templates/mediagoblin/utils/feed_link.html @@ -0,0 +1,23 @@ +{# +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# 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/>. +#} + +<a href="{{ feed_url }}"> + <img src="{{ request.staticdirect('/images/icon_feed.png') }}" + class="media_icon" alt="{% trans %}feed icon{% endtrans %}" /> +</a> +<a href="{{ feed_url }}">{%- trans %}Atom feed{% endtrans -%}</a> diff --git a/mediagoblin/templates/mediagoblin/utils/object_gallery.html b/mediagoblin/templates/mediagoblin/utils/object_gallery.html index 03b85b17..34eb7dbc 100644 --- a/mediagoblin/templates/mediagoblin/utils/object_gallery.html +++ b/mediagoblin/templates/mediagoblin/utils/object_gallery.html @@ -18,15 +18,47 @@ {% from "mediagoblin/utils/pagination.html" import render_pagination %} -{% block object_gallery_content -%} - {% if media_entries and media_entries.count() %} - {% for entry in media_entries %} - <div class="media_thumbnail"> - <a href="{{ entry.url_for_self(request.urlgen) }}"> - <img src="{{ request.app.public_store.file_url( - entry['media_files']['thumb']) }}" /></a> - </div> +{% macro media_grid(request, media_entries, col_number=5) %} + <table class="thumb_gallery"> + {% for row in gridify_cursor(media_entries, col_number) %} + <tr class="thumb_row + {%- if loop.first %} thumb_row_first + {%- elif loop.last %} thumb_row_last{% endif %}"> + {% for entry in row %} + {% set entry_url = entry.url_for_self(request.urlgen) %} + <td class="media_thumbnail thumb_entry + {%- if loop.first %} thumb_entry_first + {%- elif loop.last %} thumb_entry_last{% endif %}"> + <a href="{{ entry_url }}"> + <img src="{{ request.app.public_store.file_url( + entry['media_files']['thumb']) }}" /> + </a> + {% if entry['title'] %} + <br /> + <a href="{{ entry_url }}">{{ entry['title'] }}</a> + {% endif %} + </td> + {% endfor %} + </tr> {% endfor %} + </table> +{%- endmacro %} + +{# + Render a media gallery with pagination. + + Args: + - request: Request + - media_entries: pymongo cursor of media entries + - pagination: Paginator object + - pagination_base_url: If you want the pagination to point to a + different URL, point it here + - col_number: How many columns per row (default 5) +#} +{% macro object_gallery(request, media_entries, pagination, + pagination_base_url=None, col_number=5) %} + {% if media_entries and media_entries.count() %} + {{ media_grid(request, media_entries, col_number=col_number) }} <div class="clear"></div> {% if pagination_base_url %} {# different url, so set that and don't keep the get params #} @@ -39,4 +71,4 @@ <i>There doesn't seem to be any media here yet...</i> </p> {% endif %} -{% endblock %} +{% endmacro %} diff --git a/mediagoblin/templates/mediagoblin/utils/tags.html b/mediagoblin/templates/mediagoblin/utils/tags.html index ade41944..32db6e31 100644 --- a/mediagoblin/templates/mediagoblin/utils/tags.html +++ b/mediagoblin/templates/mediagoblin/utils/tags.html @@ -17,7 +17,7 @@ #} {% block tags_content -%} - <h4>Tags</h4> + <h3>Tags</h3> <ul class="mediaentry_tags"> {% for tag in media.tags %} <li class="tag"> diff --git a/mediagoblin/templates/mediagoblin/utils/wtforms.html b/mediagoblin/templates/mediagoblin/utils/wtforms.html index 1d2f8619..2639522a 100644 --- a/mediagoblin/templates/mediagoblin/utils/wtforms.html +++ b/mediagoblin/templates/mediagoblin/utils/wtforms.html @@ -19,9 +19,9 @@ {# Generically render a field #} {% macro render_field_div(field) %} <div class="form_field_box"> - <div class="form_field_label">{{ field.label }}</div> + <div class="form_field_label">{{ _(field.label.text) }}</div> {% if field.description -%} - <div class="form_field_description">{{ field.description }}</div> + <div class="form_field_description">{{ _(field.description) }}</div> {%- endif %} <div class="form_field_input">{{ field }}</div> {%- if field.errors -%} @@ -34,25 +34,6 @@ </div> {%- endmacro %} -{# Generically render a textarea - # ... mostly the same thing except it includes rows and cols #} -{% macro render_textarea_div(field, rows=8, cols=20) %} - <div class="form_field_box"> - <div class="form_field_label">{{ field.label }}</div> - {% if field.description -%} - <div class="form_field_description">{{ field.description }}</div> - {%- endif %} - <div class="form_field_input">{{ field(rows=rows, cols=cols) }}</div> - {%- if field.errors -%} - {% for error in field.errors %} - <div class="form_field_error"> - {{ error }} - </div> - {% endfor %} - {%- endif %} - </div> -{%- endmacro %} - {# Auto-render a form as a series of divs #} {% macro render_divs(form) -%} {% for field in form %} @@ -64,7 +45,7 @@ {% macro render_table(form) -%} {% for field in form %} <tr> - <th>{{field.label}}</th> + <th>{{ _(field.label.text) }}</th> <td> {{field}} {% if field.errors %} diff --git a/mediagoblin/tests/test_mgoblin_app.ini b/mediagoblin/tests/test_mgoblin_app.ini index 7716e9ca..0109d751 100644 --- a/mediagoblin/tests/test_mgoblin_app.ini +++ b/mediagoblin/tests/test_mgoblin_app.ini @@ -1,7 +1,4 @@ [mediagoblin] -queuestore_base_dir = %(here)s/test_user_dev/media/queue -publicstore_base_dir = %(here)s/test_user_dev/media/public -publicstore_base_url = /mgoblin_media/ direct_remote_path = /mgoblin_static/ email_sender_address = "notice@mediagoblin.example.org" email_debug_mode = true @@ -15,5 +12,12 @@ tags_max_length = 50 # mediagoblin.init.celery.from_celery celery_setup_elsewhere = true +[storage:publicstore] +base_dir = %(here)s/test_user_dev/media/public +base_url = /mgoblin_media/ + +[storage:queuestore] +queuestore_base_dir = %(here)s/test_user_dev/media/queue + [celery] celery_always_eager = true diff --git a/mediagoblin/tests/test_storage.py b/mediagoblin/tests/test_storage.py index 1800c29d..45cb35c1 100644 --- a/mediagoblin/tests/test_storage.py +++ b/mediagoblin/tests/test_storage.py @@ -60,23 +60,20 @@ class FakeRemoteStorage(storage.BasicFileStorage): def test_storage_system_from_config(): this_storage = storage.storage_system_from_config( - {'somestorage_base_url': 'http://example.org/moodia/', - 'somestorage_base_dir': '/tmp/', - 'somestorage_garbage_arg': 'garbage_arg', - 'garbage_arg': 'trash'}, - 'somestorage') + {'base_url': 'http://example.org/moodia/', + 'base_dir': '/tmp/', + 'garbage_arg': 'garbage_arg', + 'garbage_arg': 'trash'}) assert this_storage.base_url == 'http://example.org/moodia/' assert this_storage.base_dir == '/tmp/' assert this_storage.__class__ is storage.BasicFileStorage this_storage = storage.storage_system_from_config( - {'somestorage_foobie': 'eiboof', - 'somestorage_blech': 'hcelb', - 'somestorage_garbage_arg': 'garbage_arg', - 'garbage_arg': 'trash', - 'somestorage_storage_class': - 'mediagoblin.tests.test_storage:FakeStorageSystem'}, - 'somestorage') + {'foobie': 'eiboof', + 'blech': 'hcelb', + 'garbage_arg': 'garbage_arg', + 'storage_class': + 'mediagoblin.tests.test_storage:FakeStorageSystem'}) assert this_storage.foobie == 'eiboof' assert this_storage.blech == 'hcelb' assert this_storage.__class__ is FakeStorageSystem diff --git a/mediagoblin/tests/test_submission.py b/mediagoblin/tests/test_submission.py index a7248255..9ae129cd 100644 --- a/mediagoblin/tests/test_submission.py +++ b/mediagoblin/tests/test_submission.py @@ -156,7 +156,7 @@ class TestSubmission: util.clear_test_template_context() response = self.test_app.post( '/submit/', { - 'title': 'Malicious Upload 2' + 'title': 'Malicious Upload 1' }, upload_files=[( 'file', EVIL_FILE)]) @@ -164,33 +164,46 @@ class TestSubmission: form = context['submit_form'] assert form.file.errors == ['The file doesn\'t seem to be an image!'] - # NOTE: The following 2 tests will fail. These can be uncommented - # after http://bugs.foocorp.net/issues/324 is resolved and - # bad files are handled properly. + # NOTE: The following 2 tests will ultimately fail, but they + # *will* pass the initial form submission step. Instead, + # they'll be caught as failures during the processing step. # Test non-supported file with .jpg extension # ------------------------------------------- - #util.clear_test_template_context() - #response = self.test_app.post( - # '/submit/', { - # 'title': 'Malicious Upload 2' - # }, upload_files=[( - # 'file', EVIL_JPG)]) + util.clear_test_template_context() + response = self.test_app.post( + '/submit/', { + 'title': 'Malicious Upload 2' + }, upload_files=[( + 'file', EVIL_JPG)]) + response.follow() + assert_equal( + urlparse.urlsplit(response.location)[2], + '/u/chris/') - #context = util.TEMPLATE_TEST_CONTEXT['mediagoblin/submit/start.html'] - #form = context['submit_form'] - #assert form.file.errors == ['The file doesn\'t seem to be an image!'] + entry = mg_globals.database.MediaEntry.find_one( + {'title': 'Malicious Upload 2'}) + assert_equal(entry['state'], 'failed') + assert_equal( + entry['fail_error'], + u'mediagoblin.process_media.errors:BadMediaFail') # Test non-supported file with .png extension # ------------------------------------------- - #util.clear_test_template_context() - #response = self.test_app.post( - # '/submit/', { - # 'title': 'Malicious Upload 3' - # }, upload_files=[( - # 'file', EVIL_PNG)]) - - #context = util.TEMPLATE_TEST_CONTEXT['mediagoblin/submit/start.html'] - #form = context['submit_form'] - #assert form.file.errors == ['The file doesn\'t seem to be an image!'] + util.clear_test_template_context() + response = self.test_app.post( + '/submit/', { + 'title': 'Malicious Upload 3' + }, upload_files=[( + 'file', EVIL_PNG)]) + response.follow() + assert_equal( + urlparse.urlsplit(response.location)[2], + '/u/chris/') + entry = mg_globals.database.MediaEntry.find_one( + {'title': 'Malicious Upload 3'}) + assert_equal(entry['state'], 'failed') + assert_equal( + entry['fail_error'], + u'mediagoblin.process_media.errors:BadMediaFail') diff --git a/mediagoblin/translations/en/LC_MESSAGES/mediagoblin.mo b/mediagoblin/translations/en/LC_MESSAGES/mediagoblin.mo Binary files differdeleted file mode 100644 index fb7046cd..00000000 --- a/mediagoblin/translations/en/LC_MESSAGES/mediagoblin.mo +++ /dev/null diff --git a/mediagoblin/translations/en/LC_MESSAGES/mediagoblin.po b/mediagoblin/translations/en/LC_MESSAGES/mediagoblin.po deleted file mode 100644 index 3bec204e..00000000 --- a/mediagoblin/translations/en/LC_MESSAGES/mediagoblin.po +++ /dev/null @@ -1,23 +0,0 @@ -# Translations template for PROJECT. -# Copyright (C) 2011 ORGANIZATION -# This file is distributed under the same license as the PROJECT project. -# FIRST AUTHOR <EMAIL@ADDRESS>, 2011. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: PROJECT VERSION\n" -"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2011-05-12 22:28-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" -"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" - -#: mediagoblin/templates/mediagoblin/root.html:22 -msgid "Welcome to GNU MediaGoblin!" -msgstr "" - diff --git a/mediagoblin/user_pages/forms.py b/mediagoblin/user_pages/forms.py index 8829b674..25001019 100644 --- a/mediagoblin/user_pages/forms.py +++ b/mediagoblin/user_pages/forms.py @@ -16,7 +16,10 @@ import wtforms +from mediagoblin.util import fake_ugettext_passthrough as _ + + class MediaCommentForm(wtforms.Form): - comment_content = wtforms.TextAreaField( - 'Comment', - [wtforms.validators.Required()]) + comment_content = wtforms.TextAreaField( + _('Comment'), + [wtforms.validators.Required()]) diff --git a/mediagoblin/user_pages/routing.py b/mediagoblin/user_pages/routing.py index 81bb80c2..65c0fa64 100644 --- a/mediagoblin/user_pages/routing.py +++ b/mediagoblin/user_pages/routing.py @@ -36,4 +36,8 @@ user_routes = [ controller="mediagoblin.user_pages.views:atom_feed"), Route('mediagoblin.user_pages.media_post_comment', '/{user}/m/{media}/comment/add/', - controller="mediagoblin.user_pages.views:media_post_comment")] + controller="mediagoblin.user_pages.views:media_post_comment"), + Route('mediagoblin.user_pages.processing_panel', + '/{user}/panel/', + controller="mediagoblin.user_pages.views:processing_panel"), + ] diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index 8b9d94e5..2d9bcd21 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -1,4 +1,4 @@ -# GNU MediaGoblin -- federated, autonomous media hosting +# MediaGoblin -- federated, autonomous media hosting # Copyright (C) 2011 Free Software Foundation, Inc # # This program is free software: you can redistribute it and/or modify @@ -19,7 +19,8 @@ from webob import exc from mediagoblin import messages, mg_globals from mediagoblin.db.util import DESCENDING, ObjectId from mediagoblin.util import ( - Pagination, render_to_response, redirect, cleaned_markdown_conversion) + Pagination, render_to_response, redirect, cleaned_markdown_conversion, + render_404) from mediagoblin.user_pages import forms as user_forms from mediagoblin.decorators import (uses_pagination, get_user_media_entry, @@ -34,7 +35,7 @@ def user_home(request, page): user = request.db.User.find_one({ 'username': request.matchdict['user']}) if not user: - return exc.HTTPNotFound() + return render_404(request) elif user['status'] != u'active': return render_to_response( request, @@ -50,7 +51,7 @@ def user_home(request, page): #if no data is available, return NotFound if media_entries == None: - return exc.HTTPNotFound() + return render_404(request) user_gallery_url = request.urlgen( 'mediagoblin.user_pages.user_gallery', @@ -71,7 +72,7 @@ def user_gallery(request, page): 'username': request.matchdict['user'], 'status': 'active'}) if not user: - return exc.HTTPNotFound() + return render_404(request) cursor = request.db.MediaEntry.find( {'uploader': user['_id'], @@ -82,7 +83,7 @@ def user_gallery(request, page): #if no data is available, return NotFound if media_entries == None: - return exc.HTTPNotFound() + return render_404(request) return render_to_response( request, @@ -155,7 +156,7 @@ def atom_feed(request): 'username': request.matchdict['user'], 'status': 'active'}) if not user: - return exc.HTTPNotFound() + return render_404(request) cursor = request.db.MediaEntry.find({ 'uploader': user['_id'], @@ -176,3 +177,53 @@ def atom_feed(request): url=entry.url_for_self(request.urlgen)) return feed.get_response() + + +@require_active_login +def processing_panel(request): + """ + Show to the user what media is still in conversion/processing... + and what failed, and why! + """ + # Get the user + user = request.db.User.find_one( + {'username': request.matchdict['user'], + 'status': 'active'}) + + # Make sure the user exists and is active + if not user: + return render_404(request) + elif user['status'] != u'active': + return render_to_response( + request, + 'mediagoblin/user_pages/user.html', + {'user': user}) + + # XXX: Should this be a decorator? + # + # Make sure we have permission to access this user's panel. Only + # admins and this user herself should be able to do so. + if not (user[u'_id'] == request.user[u'_id'] + or request.user.is_admin): + # No? Let's simply redirect to this user's homepage then. + return redirect( + request, 'mediagoblin.user_pages.user_home', + user=request.matchdict['user']) + + # Get media entries which are in-processing + processing_entries = request.db.MediaEntry.find( + {'uploader': user['_id'], + 'state': 'processing'}).sort('created', DESCENDING) + + # Get media entries which have failed to process + failed_entries = request.db.MediaEntry.find( + {'uploader': user['_id'], + 'state': 'failed'}).sort('created', DESCENDING) + + # Render to response + return render_to_response( + request, + 'mediagoblin/user_pages/processing_panel.html', + {'user': user, + 'processing_entries': processing_entries, + 'failed_entries': failed_entries}) diff --git a/mediagoblin/util.py b/mediagoblin/util.py index 5880f856..0b6428da 100644 --- a/mediagoblin/util.py +++ b/mediagoblin/util.py @@ -28,11 +28,13 @@ import copy import wtforms from babel.localedata import exists +from babel.support import LazyProxy import jinja2 import translitcodec from webob import Response, exc from lxml.html.clean import Cleaner import markdown +from wtforms.form import Form from mediagoblin import mg_globals from mediagoblin import messages @@ -93,12 +95,15 @@ def get_jinja_env(template_loader, locale): extensions=['jinja2.ext.i18n', 'jinja2.ext.autoescape']) template_env.install_gettext_callables( - mg_globals.translations.gettext, - mg_globals.translations.ngettext) + mg_globals.translations.ugettext, + mg_globals.translations.ungettext) # All templates will know how to ... # ... fetch all waiting messages and remove them from the queue + # ... construct a grid of thumbnails or other media template_env.globals['fetch_messages'] = messages.fetch_messages + template_env.globals['gridify_list'] = gridify_list + template_env.globals['gridify_cursor'] = gridify_cursor if exists(locale): SETUP_JINJA_ENVS[locale] = template_env @@ -133,9 +138,11 @@ def clear_test_template_context(): TEMPLATE_TEST_CONTEXT = {} -def render_to_response(request, template, context): +def render_to_response(request, template, context, status=200): """Much like Django's shortcut.render()""" - return Response(render_template(request, template, context)) + return Response( + render_template(request, template, context), + status=status) def redirect(request, *args, **kwargs): @@ -300,7 +307,7 @@ def send_email(from_addr, to_addrs, subject, message_body): TRANSLATIONS_PATH = pkg_resources.resource_filename( - 'mediagoblin', 'translations') + 'mediagoblin', 'i18n') def locale_to_lower_upper(locale): @@ -341,8 +348,10 @@ def get_locale_from_request(request): accept_lang_matches = request.accept_language.best_matches() # Your routing can explicitly specify a target language - if request.matchdict.has_key('locale'): - target_lang = request.matchdict['locale'] + matchdict = request.matchdict or {} + + if matchdict.has_key('locale'): + target_lang = matchdict['locale'] elif request.session.has_key('target_lang'): target_lang = request.session['target_lang'] # Pull the first acceptable language @@ -478,6 +487,66 @@ def setup_gettext(locale): translations=this_gettext) +# Force en to be setup before anything else so that +# mg_globals.translations is never None +setup_gettext('en') + + +def pass_to_ugettext(*args, **kwargs): + """ + Pass a translation on to the appropriate ugettext 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.translations.ugettext( + *args, **kwargs) + + +def lazy_pass_to_ugettext(*args, **kwargs): + """ + Lazily pass to ugettext. + + 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 LazyProxy(pass_to_ugettext, *args, **kwargs) + + +def pass_to_ngettext(*args, **kwargs): + """ + Pass a translation on to the appropriate ngettext method. + + The reason we can't have a global ngettext method is because + mg_globals gets swapped out by the application per-request. + """ + return mg_globals.translations.ngettext( + *args, **kwargs) + + +def lazy_pass_to_ngettext(*args, **kwargs): + """ + Lazily pass to ngettext. + + 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 LazyProxy(pass_to_ngettext, *args, **kwargs) + + +def fake_ugettext_passthrough(string): + """ + Fake a ugettext call for extraction's sake ;) + + In wtforms there's a separate way to define a method to translate + things... so we just need to mark up the text so that it can be + extracted, not so that it's actually run through gettext. + """ + return string + + PAGINATION_DEFAULT_PER_PAGE = 30 class Pagination(object): @@ -566,3 +635,40 @@ class Pagination(object): """ return self.get_page_url_explicit( request.path_info, request.GET, page_no) + + +def gridify_list(this_list, num_cols=5): + """ + Generates a list of lists where each sub-list's length depends on + the number of columns in the list + """ + grid = [] + + # Figure out how many rows we should have + num_rows = int(ceil(float(len(this_list)) / num_cols)) + + for row_num in range(num_rows): + slice_min = row_num * num_cols + slice_max = (row_num + 1) * num_cols + + row = this_list[slice_min:slice_max] + + grid.append(row) + + return grid + + +def gridify_cursor(this_cursor, num_cols=5): + """ + Generates a list of lists where each sub-list's length depends on + the number of columns in the list + """ + return gridify_list(list(this_cursor), num_cols) + + +def render_404(request): + """ + Render a 404. + """ + return render_to_response( + request, 'mediagoblin/404.html', {}, status=400) @@ -1,7 +1,11 @@ [DEFAULT] -debug = true +# Set to true to enable web-based debugging messages and etc. +debug = false -[composite:main] +[pipeline:main] +pipeline = errors routing + +[composite:routing] use = egg:Paste#urlmap / = mediagoblin /mgoblin_media/ = publicstore_serve @@ -28,6 +32,10 @@ beaker.session.key = mediagoblin beaker.session.data_dir = %(here)s/user_dev/beaker/sessions/data beaker.session.lock_dir = %(here)s/user_dev/beaker/sessions/lock +[filter:errors] +use = egg:mediagoblin#errors +debug = false + [server:main] use = egg:Paste#http host = 127.0.0.1 @@ -44,6 +44,7 @@ setup( 'webtest', 'ConfigObj', 'Markdown', + 'python-cloudfiles', ## For now we're expecting that users will install this from ## their package managers. # 'lxml', @@ -52,10 +53,14 @@ setup( entry_points = """\ [console_scripts] gmg = mediagoblin.gmg_commands:main_cli + pybabel = mediagoblin.babel.messages.frontend:main [paste.app_factory] app = mediagoblin.app:paste_app_factory + [paste.filter_app_factory] + errors = mediagoblin.errormiddleware:mgoblin_error_middleware + [zc.buildout] make_user_dev_dirs = mediagoblin.buildout_recipes:MakeUserDevDirs |