diff options
49 files changed, 3229 insertions, 5507 deletions
@@ -8,10 +8,12 @@ variety of different ways and this software wouldn't exist without them. Thank you! * Aaron Williamson +* Aditi Mittal * Aeva Ntsc * Alejandro Villanueva * Aleksandar Micovic * Aleksej Serdjukov +* Alon Levy * Alex Camelio * András Veres-Szentkirályi * Bassam Kurdali @@ -21,13 +23,17 @@ Thank you! * Corey Farwell * Chris Moylan * Christopher Allan Webber +* David Thompson * Daniel Neel * Deb Nicholson * Derek Moore * Duncan Paterson * Elrond of Samba TNG * Emily O'Leary +* Gabi Thume +* Gabriel Saldana * Greg Grossmeier +* Hans Lo * Jakob Kramer * Jef van Schendel * Jessica Tallon @@ -36,25 +42,34 @@ Thank you! * Jorge Araya Navarro * Karen Rustad * Kuno Woudt +* Laura Arjona * Larisa Hoffenbecker * Luke Slater * Manuel Urbano Santos * Mark Holmquist +* Mats Sjöberg * Matt Lee * Michele Azzolari +* Mike Linksvayer +* Natalie Foust-Pilcher * Nathan Yergler * Odin Hørthe Omdal * Osama Khalid * Pablo J. Urbano Santos +* Praveen Kumar * Rasmus Larsson +* Rodney Ewing * Runar Petursson * Sacha De'Angeli * Sam Kleinman +* Sam Tuke * Sebastian Spaeth * Shawn Khan +* Simon Fondrie-Teitler * Stefano Zacchiroli * Tiberiu C. Turbureanu * Tran Thanh Bao +* Tryggvi Björgvinsson * Shawn Khan * Will Kahn-Greene @@ -64,4 +79,4 @@ If you think your name should be on this list, let us know! We also are currently borrowing an image in mediagoblin/static/images/media_thumbs/image.png from the wonderful people at http://tango.freedesktop.org/ which is in the public -domain... thanks Tango folks!
\ No newline at end of file +domain... thanks Tango folks! diff --git a/docs/source/siteadmin/media-types.rst b/docs/source/siteadmin/media-types.rst index 210094b9..1527bc70 100644 --- a/docs/source/siteadmin/media-types.rst +++ b/docs/source/siteadmin/media-types.rst @@ -199,8 +199,16 @@ will be able to present them to your wide audience of admirers! PDF and Document ================ -To enable the "PDF and Document" support plugin, you need pdftocairo, pdfinfo, -unoconv with headless support. All executables must be on your execution path. +To enable the "PDF and Document" support plugin, you need: + +1. pdftocairo and pdfinfo for pdf only support. + +2. unoconv with headless support to support converting libreoffice supported + documents as well, such as doc/ppt/xls/odf/odg/odp and more. + For the full list see mediagoblin/media_types/pdf/processing.py, + unoconv_supported. + +All executables must be on your execution path. To install this on Fedora: @@ -208,6 +216,9 @@ To install this on Fedora: sudo yum install -y poppler-utils unoconv libreoffice-headless +Note: You can leave out unoconv and libreoffice-headless if you want only pdf +support. This will result in a much smaller list of dependencies. + pdf.js relies on git submodules, so be sure you have fetched them: .. code-block:: bash diff --git a/docs/source/siteadmin/relnotes.rst b/docs/source/siteadmin/relnotes.rst index 9c9d311c..7b6d8353 100644 --- a/docs/source/siteadmin/relnotes.rst +++ b/docs/source/siteadmin/relnotes.rst @@ -39,6 +39,13 @@ carefully, or at least skim over it. alias /srv/mediagoblin.example.org/mediagoblin/user_dev/plugin_static/; } + Similarly, if you've got a modified paste config, you may want to + borrow the app:plugin_static section from the default paste.ini + file. +5. We now use itsdangerous for sessions; if you had any references to + beaker in your paste config you can remove them. Again, see the + default paste.ini config + **For theme authors** If you have your own theme or you have any "user modified templates", @@ -51,7 +58,23 @@ please note the following: You can easily customize this to give a welcome page appropriate to your site. + **New features** +* PDF media type! +* Improved plugin system. More flexible, better documented, with a + new plugin authoring section of the docs. +* itsdangerous based sessions. No more beaker! +* New, experimental Piwigo-based API. This means you should be able + to use MediaGoblin with something like Shotwell. (Again, a word of + caution: this is *very experimental*!) +* Human readable timestamps, and the option to display the original + date of an image when available (available as the + "original_date_visible" variable) +* Moved unit testing system from nosetests to py.test so we can better + handle issues with sqlalchemy exploding with different database + configurations. Long story :) +* You can now disable the ability to post comments. +* Tags now can be up to length 255 characters by default. 0.3.3 diff --git a/mediagoblin/_version.py b/mediagoblin/_version.py index 8437be8b..2abc105f 100644 --- a/mediagoblin/_version.py +++ b/mediagoblin/_version.py @@ -23,4 +23,4 @@ # see http://www.python.org/dev/peps/pep-0386/ -__version__ = "0.4.0.dev" +__version__ = "0.4.1.dev" diff --git a/mediagoblin/auth/forms.py b/mediagoblin/auth/forms.py index 0a391d67..ec395d60 100644 --- a/mediagoblin/auth/forms.py +++ b/mediagoblin/auth/forms.py @@ -58,9 +58,6 @@ class ChangePassForm(wtforms.Form): 'Password', [wtforms.validators.Required(), wtforms.validators.Length(min=5, max=1024)]) - userid = wtforms.HiddenField( - '', - [wtforms.validators.Required()]) token = wtforms.HiddenField( '', [wtforms.validators.Required()]) diff --git a/mediagoblin/auth/lib.py b/mediagoblin/auth/lib.py index bfc36b28..0810bd1b 100644 --- a/mediagoblin/auth/lib.py +++ b/mediagoblin/auth/lib.py @@ -20,6 +20,7 @@ import bcrypt from mediagoblin.tools.mail import send_email from mediagoblin.tools.template import render_template +from mediagoblin.tools.crypto import get_timed_signer_url from mediagoblin import mg_globals @@ -91,8 +92,8 @@ def fake_login_attempt(): EMAIL_FP_VERIFICATION_TEMPLATE = ( - u"http://{host}{uri}?" - u"userid={userid}&token={fp_verification_key}") + u"{uri}?" + u"token={fp_verification_key}") def send_fp_verification_email(user, request): @@ -103,14 +104,16 @@ def send_fp_verification_email(user, request): - user: a user object - request: the request """ + fp_verification_key = get_timed_signer_url('mail_verification_token') \ + .dumps(user.id) + rendered_email = render_template( request, 'mediagoblin/auth/fp_verification_email.txt', {'username': user.username, 'verification_url': EMAIL_FP_VERIFICATION_TEMPLATE.format( - host=request.host, - uri=request.urlgen('mediagoblin.auth.verify_forgot_password'), - userid=unicode(user.id), - fp_verification_key=user.fp_verification_key)}) + uri=request.urlgen('mediagoblin.auth.verify_forgot_password', + qualified=True), + fp_verification_key=fp_verification_key)}) # TODO: There is no error handling in place send_email( diff --git a/mediagoblin/auth/tools.py b/mediagoblin/auth/tools.py index db6b6e37..c45944d3 100644 --- a/mediagoblin/auth/tools.py +++ b/mediagoblin/auth/tools.py @@ -22,6 +22,7 @@ from sqlalchemy import or_ from mediagoblin import mg_globals from mediagoblin.auth import lib as auth_lib +from mediagoblin.tools.crypto import get_timed_signer_url from mediagoblin.db.models import User from mediagoblin.tools.mail import (normalize_email, send_email, email_debug_message) @@ -62,11 +63,12 @@ def normalize_user_or_email_field(allow_email=True, allow_user=True): EMAIL_VERIFICATION_TEMPLATE = ( - u"http://{host}{uri}?" - u"userid={userid}&token={verification_key}") + u"{uri}?" + u"token={verification_key}") -def send_verification_email(user, request): +def send_verification_email(user, request, email=None, + rendered_email=None): """ Send the verification email to users to activate their accounts. @@ -74,19 +76,24 @@ def send_verification_email(user, request): - user: a user object - request: the request """ - rendered_email = render_template( - request, 'mediagoblin/auth/verification_email.txt', - {'username': user.username, - 'verification_url': EMAIL_VERIFICATION_TEMPLATE.format( - host=request.host, - uri=request.urlgen('mediagoblin.auth.verify_email'), - userid=unicode(user.id), - verification_key=user.verification_key)}) + if not email: + email = user.email + + if not rendered_email: + verification_key = get_timed_signer_url('mail_verification_token') \ + .dumps(user.id) + rendered_email = render_template( + request, 'mediagoblin/auth/verification_email.txt', + {'username': user.username, + 'verification_url': EMAIL_VERIFICATION_TEMPLATE.format( + uri=request.urlgen('mediagoblin.auth.verify_email', + qualified=True), + verification_key=verification_key)}) # TODO: There is no error handling in place send_email( mg_globals.app_config['email_sender_address'], - [user.email], + [email], # TODO # Due to the distributed nature of GNU MediaGoblin, we should # find a way to send some additional information about the diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py index bb7bda77..45cb3a54 100644 --- a/mediagoblin/auth/views.py +++ b/mediagoblin/auth/views.py @@ -15,10 +15,11 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. import uuid -import datetime +from itsdangerous import BadSignature from mediagoblin import messages, mg_globals from mediagoblin.db.models import User +from mediagoblin.tools.crypto import get_timed_signer_url from mediagoblin.tools.response import render_to_response, redirect, render_404 from mediagoblin.tools.translate import pass_to_ugettext as _ from mediagoblin.tools.mail import email_debug_message @@ -115,16 +116,28 @@ def verify_email(request): you are lucky :) """ # If we don't have userid and token parameters, we can't do anything; 404 - if not 'userid' in request.GET or not 'token' in request.GET: + if not 'token' in request.GET: return render_404(request) - user = User.query.filter_by(id=request.args['userid']).first() + # Catch error if token is faked or expired + try: + token = get_timed_signer_url("mail_verification_token") \ + .loads(request.GET['token'], max_age=10*24*3600) + except BadSignature: + messages.add_message( + request, + messages.ERROR, + _('The verification key or user id is incorrect.')) - if user and user.verification_key == unicode(request.GET['token']): + return redirect( + request, + 'index') + + user = User.query.filter_by(id=int(token)).first() + + if user and user.email_verified is False: user.status = u'active' user.email_verified = True - user.verification_key = None - user.save() messages.add_message( @@ -166,9 +179,6 @@ def resend_activation(request): return redirect(request, "mediagoblin.user_pages.user_home", user=request.user['username']) - request.user.verification_key = unicode(uuid.uuid4()) - request.user.save() - email_debug_message(request) send_verification_email(request.user, request) @@ -235,11 +245,6 @@ def forgot_password(request): # SUCCESS. Send reminder and return to login page if user: - user.fp_verification_key = unicode(uuid.uuid4()) - user.fp_token_expire = datetime.datetime.now() + \ - datetime.timedelta(days=10) - user.save() - email_debug_message(request) send_fp_verification_email(user, request) @@ -254,31 +259,44 @@ def verify_forgot_password(request): """ # get form data variables, and specifically check for presence of token formdata = _process_for_token(request) - if not formdata['has_userid_and_token']: + if not formdata['has_token']: return render_404(request) - formdata_token = formdata['vars']['token'] - formdata_userid = formdata['vars']['userid'] formdata_vars = formdata['vars'] + # Catch error if token is faked or expired + try: + token = get_timed_signer_url("mail_verification_token") \ + .loads(formdata_vars['token'], max_age=10*24*3600) + except BadSignature: + messages.add_message( + request, + messages.ERROR, + _('The verification key or user id is incorrect.')) + + return redirect( + request, + 'index') + # check if it's a valid user id - user = User.query.filter_by(id=formdata_userid).first() + user = User.query.filter_by(id=int(token)).first() + + # no user in db if not user: - return render_404(request) + messages.add_message( + request, messages.ERROR, + _('The user id is incorrect.')) + return redirect( + request, 'index') - # check if we have a real user and correct token - if ((user and user.fp_verification_key and - user.fp_verification_key == unicode(formdata_token) and - datetime.datetime.now() < user.fp_token_expire - and user.email_verified and user.status == 'active')): + # check if user active and has email verified + if user.email_verified and user.status == 'active': cp_form = auth_forms.ChangePassForm(formdata_vars) if request.method == 'POST' and cp_form.validate(): user.pw_hash = auth_lib.bcrypt_gen_password_hash( cp_form.password.data) - user.fp_verification_key = None - user.fp_token_expire = None user.save() messages.add_message( @@ -292,10 +310,20 @@ def verify_forgot_password(request): 'mediagoblin/auth/change_fp.html', {'cp_form': cp_form}) - # in case there is a valid id but no user with that id in the db - # or the token expired - else: - return render_404(request) + if not user.email_verified: + messages.add_message( + request, messages.ERROR, + _('You need to verify your email before you can reset your' + ' password.')) + + if not user.status == 'active': + messages.add_message( + request, messages.ERROR, + _('You are no longer an active user. Please contact the system' + ' admin to reactivate your accoutn.')) + + return redirect( + request, 'index') def _process_for_token(request): @@ -313,7 +341,6 @@ def _process_for_token(request): formdata = { 'vars': formdata_vars, - 'has_userid_and_token': - 'userid' in formdata_vars and 'token' in formdata_vars} + 'has_token': 'token' in formdata_vars} return formdata diff --git a/mediagoblin/db/migrations.py b/mediagoblin/db/migrations.py index 29b2522a..7074ffec 100644 --- a/mediagoblin/db/migrations.py +++ b/mediagoblin/db/migrations.py @@ -288,6 +288,25 @@ def unique_collections_slug(db): db.commit() +@RegisterMigration(11, MIGRATIONS) +def drop_token_related_User_columns(db): + """ + Drop unneeded columns from the User table after switching to using + itsdangerous tokens for email and forgot password verification. + """ + metadata = MetaData(bind=db.bind) + user_table = inspect_table(metadata, 'core__users') + + verification_key = user_table.columns['verification_key'] + fp_verification_key = user_table.columns['fp_verification_key'] + fp_token_expire = user_table.columns['fp_token_expire'] + + verification_key.drop() + fp_verification_key.drop() + fp_token_expire.drop() + + db.commit() + class CommentSubscription_v0(declarative_base()): __tablename__ = 'core__comment_subscriptions' id = Column(Integer, primary_key=True) @@ -329,7 +348,7 @@ class ProcessingNotification_v0(Notification_v0): subject_id = Column(Integer, ForeignKey(MediaEntry.id)) -@RegisterMigration(11, MIGRATIONS) +@RegisterMigration(12, MIGRATIONS) def add_new_notification_tables(db): metadata = MetaData(bind=db.bind) diff --git a/mediagoblin/db/models.py b/mediagoblin/db/models.py index 62090126..4c24bfe8 100644 --- a/mediagoblin/db/models.py +++ b/mediagoblin/db/models.py @@ -70,12 +70,9 @@ class User(Base, UserMixin): # set to nullable=True implicitly. wants_comment_notification = Column(Boolean, default=True) license_preference = Column(Unicode) - verification_key = Column(Unicode) is_admin = Column(Boolean, default=False, nullable=False) url = Column(Unicode) bio = Column(UnicodeText) # ?? - fp_verification_key = Column(Unicode) - fp_token_expire = Column(DateTime) ## TODO # plugin data would be in a separate model diff --git a/mediagoblin/db/models_v0.py b/mediagoblin/db/models_v0.py index ec51a1f5..bdedec2e 100644 --- a/mediagoblin/db/models_v0.py +++ b/mediagoblin/db/models_v0.py @@ -18,6 +18,29 @@ TODO: indexes on foreignkeys, where useful. """ +########################################################################### +# WHAT IS THIS FILE? +# ------------------ +# +# Upon occasion, someone runs into this file and wonders why we have +# both a models.py and a models_v0.py. +# +# The short of it is: you can ignore this file. +# +# The long version is, in two parts: +# +# - We used to use MongoDB, then we switched to SQL and SQLAlchemy. +# We needed to convert peoples' databases; the script we had would +# switch them to the first version right after Mongo, convert over +# all their tables, then run any migrations that were added after. +# +# - That script is now removed, but there is some discussion of +# writing a test that would set us at the first SQL migration and +# run everything after. If we wrote that, this file would still be +# useful. But for now, it's legacy! +# +########################################################################### + import datetime import sys diff --git a/mediagoblin/edit/forms.py b/mediagoblin/edit/forms.py index 3b2486de..24b31a76 100644 --- a/mediagoblin/edit/forms.py +++ b/mediagoblin/edit/forms.py @@ -16,9 +16,11 @@ import wtforms -from mediagoblin.tools.text import tag_length_validator, TOO_LONG_TAG_WARNING +from mediagoblin.tools.text import tag_length_validator from mediagoblin.tools.translate import lazy_pass_to_ugettext as _ from mediagoblin.tools.licenses import licenses_as_choices +from mediagoblin.auth.forms import normalize_user_or_email_field + class EditForm(wtforms.Form): title = wtforms.TextField( @@ -59,6 +61,10 @@ class EditProfileForm(wtforms.Form): class EditAccountForm(wtforms.Form): + new_email = wtforms.TextField( + _('New email address'), + [wtforms.validators.Optional(), + normalize_user_or_email_field(allow_user=False)]) license_preference = wtforms.SelectField( _('License preference'), [ diff --git a/mediagoblin/edit/routing.py b/mediagoblin/edit/routing.py index 622729ac..3592f708 100644 --- a/mediagoblin/edit/routing.py +++ b/mediagoblin/edit/routing.py @@ -26,3 +26,5 @@ add_route('mediagoblin.edit.delete_account', '/edit/account/delete/', 'mediagoblin.edit.views:delete_account') add_route('mediagoblin.edit.pass', '/edit/password/', 'mediagoblin.edit.views:change_pass') +add_route('mediagoblin.edit.verify_email', '/edit/verify_email/', + 'mediagoblin.edit.views:verify_email') diff --git a/mediagoblin/edit/views.py b/mediagoblin/edit/views.py index 508c380d..4eda61a2 100644 --- a/mediagoblin/edit/views.py +++ b/mediagoblin/edit/views.py @@ -16,6 +16,7 @@ from datetime import datetime +from itsdangerous import BadSignature from werkzeug.exceptions import Forbidden from werkzeug.utils import secure_filename @@ -23,18 +24,23 @@ from mediagoblin import messages from mediagoblin import mg_globals from mediagoblin.auth import lib as auth_lib +from mediagoblin.auth import tools as auth_tools +from mediagoblin.auth.views import email_debug_message from mediagoblin.edit import forms from mediagoblin.edit.lib import may_edit_media from mediagoblin.decorators import (require_active_login, active_user_from_url, - get_media_entry_by_id, - user_may_alter_collection, get_user_collection) -from mediagoblin.tools.response import render_to_response, \ - redirect, redirect_obj + get_media_entry_by_id, user_may_alter_collection, + get_user_collection) +from mediagoblin.tools.crypto import get_timed_signer_url +from mediagoblin.tools.response import (render_to_response, + redirect, redirect_obj, render_404) from mediagoblin.tools.translate import pass_to_ugettext as _ +from mediagoblin.tools.template import render_template from mediagoblin.tools.text import ( convert_to_tag_list_of_dicts, media_tags_as_string) from mediagoblin.tools.url import slugify from mediagoblin.db.util import check_media_slug_used, check_collection_slug_used +from mediagoblin.db.models import User import mimetypes @@ -212,6 +218,10 @@ def edit_profile(request, url_user=None): {'user': user, 'form': form}) +EMAIL_VERIFICATION_TEMPLATE = ( + u'{uri}?' + u'token={verification_key}') + @require_active_login def edit_account(request): @@ -220,27 +230,45 @@ def edit_account(request): wants_comment_notification=user.wants_comment_notification, license_preference=user.license_preference) - if request.method == 'POST': - form_validated = form.validate() - - if form_validated and \ - form.wants_comment_notification.validate(form): - user.wants_comment_notification = \ - form.wants_comment_notification.data - - if form_validated and \ - form.license_preference.validate(form): - user.license_preference = \ - form.license_preference.data - - if form_validated and not form.errors: + if request.method == 'POST' and form.validate(): + user.wants_comment_notification = form.wants_comment_notification.data + + user.license_preference = form.license_preference.data + + if form.new_email.data: + new_email = form.new_email.data + users_with_email = User.query.filter_by( + email=new_email).count() + if users_with_email: + form.new_email.errors.append( + _('Sorry, a user with that email address' + ' already exists.')) + else: + verification_key = get_timed_signer_url( + 'mail_verification_token').dumps({ + 'user': user.id, + 'email': new_email}) + + rendered_email = render_template( + request, 'mediagoblin/edit/verification.txt', + {'username': user.username, + 'verification_url': EMAIL_VERIFICATION_TEMPLATE.format( + uri=request.urlgen('mediagoblin.edit.verify_email', + qualified=True), + verification_key=verification_key)}) + + email_debug_message(request) + auth_tools.send_verification_email(user, request, new_email, + rendered_email) + + if not form.errors: user.save() messages.add_message(request, - messages.SUCCESS, - _("Account settings saved")) + messages.SUCCESS, + _("Account settings saved")) return redirect(request, - 'mediagoblin.user_pages.user_home', - user=user.username) + 'mediagoblin.user_pages.user_home', + user=user.username) return render_to_response( request, @@ -369,3 +397,48 @@ def change_pass(request): 'mediagoblin/edit/change_pass.html', {'form': form, 'user': user}) + + +def verify_email(request): + """ + Email verification view for changing email address + """ + # If no token, we can't do anything + if not 'token' in request.GET: + return render_404(request) + + # Catch error if token is faked or expired + token = None + try: + token = get_timed_signer_url("mail_verification_token") \ + .loads(request.GET['token'], max_age=10*24*3600) + except BadSignature: + messages.add_message( + request, + messages.ERROR, + _('The verification key or user id is incorrect.')) + + return redirect( + request, + 'index') + + user = User.query.filter_by(id=int(token['user'])).first() + + if user: + user.email = token['email'] + user.save() + + messages.add_message( + request, + messages.SUCCESS, + _('Your email address has been verified.')) + + else: + messages.add_message( + request, + messages.ERROR, + _('The verification key or user id is incorrect.')) + + return redirect( + request, 'mediagoblin.user_pages.user_home', + user=user.username) diff --git a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo Binary files differindex a07400ae..e2fcf85d 100644 --- a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo +++ 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 index 4bde0095..e2147070 100644 --- a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po @@ -15,15 +15,15 @@ # Elrond <elrond+mediagoblin.org@samba-tng.org>, 2011 # Art O. Pal <artopal@fastmail.fm>, 2011 # spaetz <sebastian@sspaeth.de>, 2012 -# Vinzenz Vietzke <vietzke@b1-systems.de>, 2012 -# Vinzenz Vietzke <vietzke@b1-systems.de>, 2011 +# Vinzenz Vietzke <vinz@vinzv.de>, 2012 +# Vinzenz Vietzke <vinz@vinzv.de>, 2011 msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://issues.mediagoblin.org/\n" "POT-Creation-Date: 2013-05-27 13:54-0500\n" -"PO-Revision-Date: 2013-05-27 18:54+0000\n" -"Last-Translator: cwebber <cwebber@dustycloud.org>\n" +"PO-Revision-Date: 2013-05-28 10:43+0000\n" +"Last-Translator: Elrond <elrond+mediagoblin.org@samba-tng.org>\n" "Language-Team: German (http://www.transifex.com/projects/p/mediagoblin/language/de/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -47,7 +47,7 @@ msgstr "E-Mail-Adresse" #: mediagoblin/auth/forms.py:41 msgid "Username or Email" -msgstr "" +msgstr "Benutzername oder E-Mail-Adresse" #: mediagoblin/auth/forms.py:52 msgid "Username or email" @@ -628,7 +628,7 @@ msgid "" "<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n" " or\n" " <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>" -msgstr "" +msgstr "<a class=\"button_action_highlight\" href=\"%(register_url)s\">Registriere dich auf dieser Seite</a> oder <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Installiere MediaGoblin auf deinem eigenen Server</a>" #: mediagoblin/templates/mediagoblin/bits/logo.html:23 #: mediagoblin/themes/airy/templates/mediagoblin/bits/logo.html:23 @@ -784,7 +784,7 @@ msgstr "Bild für %(media_title)s" #: mediagoblin/templates/mediagoblin/media_displays/pdf.html:79 msgid "PDF file" -msgstr "" +msgstr "PDF-Datei" #: mediagoblin/templates/mediagoblin/media_displays/stl.html:112 msgid "Toggle Rotate" @@ -944,11 +944,11 @@ msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/media.html:150 msgid "Added" -msgstr "" +msgstr "Hinzugefügt" #: mediagoblin/templates/mediagoblin/user_pages/media.html:161 msgid "Created" -msgstr "" +msgstr "Originaldatum" #: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:28 #: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:40 @@ -1136,27 +1136,27 @@ msgstr "Tut uns Leid, aber unter der angegebenen Adresse gibt es keine Seite!</p #: mediagoblin/tools/timesince.py:62 msgid "year" -msgstr "" +msgstr "Jahr" #: mediagoblin/tools/timesince.py:63 msgid "month" -msgstr "" +msgstr "Monat" #: mediagoblin/tools/timesince.py:64 msgid "week" -msgstr "" +msgstr "Woche" #: mediagoblin/tools/timesince.py:65 msgid "day" -msgstr "" +msgstr "Tag" #: mediagoblin/tools/timesince.py:66 msgid "hour" -msgstr "" +msgstr "Stunde" #: mediagoblin/tools/timesince.py:67 msgid "minute" -msgstr "" +msgstr "Minute" #: mediagoblin/user_pages/forms.py:23 msgid "Comment" diff --git a/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po index 913c2ec1..1b22b786 100644 --- a/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2013-05-27 13:54-0500\n" +"POT-Creation-Date: 2013-06-16 20:06-0500\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -17,94 +17,94 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 0.9.6\n" -#: mediagoblin/auth/forms.py:26 +#: mediagoblin/auth/forms.py:25 msgid "Username" msgstr "" -#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:45 +#: mediagoblin/auth/forms.py:29 mediagoblin/auth/forms.py:44 #: mediagoblin/tests/test_util.py:110 msgid "Password" msgstr "" -#: mediagoblin/auth/forms.py:34 +#: mediagoblin/auth/forms.py:33 msgid "Email address" msgstr "" -#: mediagoblin/auth/forms.py:41 +#: mediagoblin/auth/forms.py:40 msgid "Username or Email" msgstr "" -#: mediagoblin/auth/forms.py:52 +#: mediagoblin/auth/forms.py:51 msgid "Username or email" msgstr "" -#: mediagoblin/auth/tools.py:31 +#: mediagoblin/auth/tools.py:42 msgid "Invalid User name or email address." msgstr "" -#: mediagoblin/auth/tools.py:32 +#: mediagoblin/auth/tools.py:43 msgid "This field does not take email addresses." msgstr "" -#: mediagoblin/auth/tools.py:33 +#: mediagoblin/auth/tools.py:44 msgid "This field requires an email address." msgstr "" -#: mediagoblin/auth/views.py:54 -msgid "Sorry, registration is disabled on this instance." -msgstr "" - -#: mediagoblin/auth/views.py:68 +#: mediagoblin/auth/tools.py:109 msgid "Sorry, a user with that name already exists." msgstr "" -#: mediagoblin/auth/views.py:72 +#: mediagoblin/auth/tools.py:113 msgid "Sorry, a user with that email address already exists." msgstr "" -#: mediagoblin/auth/views.py:182 +#: mediagoblin/auth/views.py:43 +msgid "Sorry, registration is disabled on this instance." +msgstr "" + +#: mediagoblin/auth/views.py:133 msgid "" "Your email address has been verified. You may now login, edit your " "profile, and submit images!" msgstr "" -#: mediagoblin/auth/views.py:188 +#: mediagoblin/auth/views.py:139 msgid "The verification key or user id is incorrect" msgstr "" -#: mediagoblin/auth/views.py:206 +#: mediagoblin/auth/views.py:157 msgid "You must be logged in so we know who to send the email to!" msgstr "" -#: mediagoblin/auth/views.py:214 +#: mediagoblin/auth/views.py:165 msgid "You've already verified your email address!" msgstr "" -#: mediagoblin/auth/views.py:227 +#: mediagoblin/auth/views.py:178 msgid "Resent your verification email." msgstr "" -#: mediagoblin/auth/views.py:258 +#: mediagoblin/auth/views.py:209 msgid "" "If that email address (case sensitive!) is registered an email has been " "sent with instructions on how to change your password." msgstr "" -#: mediagoblin/auth/views.py:269 +#: mediagoblin/auth/views.py:220 msgid "Couldn't find someone with that username." msgstr "" -#: mediagoblin/auth/views.py:272 +#: mediagoblin/auth/views.py:223 msgid "An email has been sent with instructions on how to change your password." msgstr "" -#: mediagoblin/auth/views.py:279 +#: mediagoblin/auth/views.py:230 msgid "" "Could not send password recovery email as your username is inactive or " "your account's email address has not been verified." msgstr "" -#: mediagoblin/auth/views.py:336 +#: mediagoblin/auth/views.py:287 msgid "You can now log in using your new password." msgstr "" @@ -634,13 +634,13 @@ msgid "Editing attachments for %(media_title)s" msgstr "" #: mediagoblin/templates/mediagoblin/edit/attachments.html:44 -#: mediagoblin/templates/mediagoblin/user_pages/media.html:182 -#: mediagoblin/templates/mediagoblin/user_pages/media.html:198 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:171 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:187 msgid "Attachments" msgstr "" #: mediagoblin/templates/mediagoblin/edit/attachments.html:57 -#: mediagoblin/templates/mediagoblin/user_pages/media.html:204 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:193 msgid "Add attachment" msgstr "" @@ -763,6 +763,17 @@ msgstr "" msgid "WebM file (Vorbis codec)" msgstr "" +#: mediagoblin/templates/mediagoblin/media_displays/image.html:36 +msgid "Created" +msgstr "" + +#: mediagoblin/templates/mediagoblin/media_displays/image.html:39 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:132 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:152 +#, python-format +msgid "%(formatted_time)s ago" +msgstr "" + #: mediagoblin/templates/mediagoblin/media_displays/pdf.html:59 #: mediagoblin/templates/mediagoblin/media_displays/stl.html:87 #: mediagoblin/templates/mediagoblin/media_displays/stl.html:93 @@ -928,21 +939,10 @@ msgstr "" msgid "Add this comment" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:132 -#: mediagoblin/templates/mediagoblin/user_pages/media.html:152 -#: mediagoblin/templates/mediagoblin/user_pages/media.html:164 -#, python-format -msgid "%(formatted_time)s ago" -msgstr "" - #: mediagoblin/templates/mediagoblin/user_pages/media.html:150 msgid "Added" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:161 -msgid "Created" -msgstr "" - #: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:28 #: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:40 #, python-format diff --git a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo Binary files differindex 406b269f..645af16b 100644 --- a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo +++ 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 index eb1ec1ec..873869f0 100644 --- a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po @@ -12,8 +12,8 @@ msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://issues.mediagoblin.org/\n" "POT-Creation-Date: 2013-05-27 13:54-0500\n" -"PO-Revision-Date: 2013-05-27 18:54+0000\n" -"Last-Translator: cwebber <cwebber@dustycloud.org>\n" +"PO-Revision-Date: 2013-06-01 21:16+0000\n" +"Last-Translator: aleksejrs <deletesoftware@yandex.ru>\n" "Language-Team: Esperanto (http://www.transifex.com/projects/p/mediagoblin/language/eo/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -37,7 +37,7 @@ msgstr "Retpoŝtadreso" #: mediagoblin/auth/forms.py:41 msgid "Username or Email" -msgstr "" +msgstr "Uzantonomo aŭ retpoŝtadreso" #: mediagoblin/auth/forms.py:52 msgid "Username or email" @@ -178,7 +178,7 @@ msgstr "Permesila prefero" #: mediagoblin/edit/forms.py:69 msgid "This will be your default license on upload forms." -msgstr "" +msgstr "Tiu ĉi permesilo estos antaŭelektita en la alŝutformularoj." #: mediagoblin/edit/forms.py:71 msgid "Email me when others comment on my media" @@ -264,7 +264,7 @@ msgstr "Malĝusta pasvorto" #: mediagoblin/edit/views.py:363 msgid "Your password was changed successfully" -msgstr "" +msgstr "Via pasvorto estas sukcese ŝanĝita" #: mediagoblin/gmg_commands/assetlink.py:60 msgid "Cannot link theme... no theme set\n" @@ -665,11 +665,11 @@ msgstr "Konservi ŝanĝojn" #: mediagoblin/templates/mediagoblin/edit/change_pass.html:38 #, python-format msgid "Changing %(username)s's password" -msgstr "" +msgstr "Ŝanĝado de pasvorto de %(username)s" #: mediagoblin/templates/mediagoblin/edit/change_pass.html:45 msgid "Save" -msgstr "" +msgstr "Konservi" #: mediagoblin/templates/mediagoblin/edit/delete_account.html:28 #, python-format @@ -700,7 +700,7 @@ msgstr "Ŝanĝado de kontagordoj de %(username)s" #: mediagoblin/templates/mediagoblin/edit/edit_account.html:46 msgid "Change your password." -msgstr "" +msgstr "Ŝanĝi la pasvorton" #: mediagoblin/templates/mediagoblin/edit/edit_account.html:62 msgid "Delete my account" @@ -774,7 +774,7 @@ msgstr "Bildo de «%(media_title)s»" #: mediagoblin/templates/mediagoblin/media_displays/pdf.html:79 msgid "PDF file" -msgstr "" +msgstr "PDF-dosiero" #: mediagoblin/templates/mediagoblin/media_displays/stl.html:112 msgid "Toggle Rotate" @@ -930,15 +930,15 @@ msgstr "Aldoni ĉi tiun komenton" #: mediagoblin/templates/mediagoblin/user_pages/media.html:164 #, python-format msgid "%(formatted_time)s ago" -msgstr "" +msgstr "antaŭ %(formatted_time)s" #: mediagoblin/templates/mediagoblin/user_pages/media.html:150 msgid "Added" -msgstr "" +msgstr "Aldonita" #: mediagoblin/templates/mediagoblin/user_pages/media.html:161 msgid "Created" -msgstr "" +msgstr "Kreita" #: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:28 #: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:40 @@ -1126,27 +1126,27 @@ msgstr "" #: mediagoblin/tools/timesince.py:62 msgid "year" -msgstr "" +msgstr "jaro(j)" #: mediagoblin/tools/timesince.py:63 msgid "month" -msgstr "" +msgstr "monato(j)" #: mediagoblin/tools/timesince.py:64 msgid "week" -msgstr "" +msgstr "semajno(j)" #: mediagoblin/tools/timesince.py:65 msgid "day" -msgstr "" +msgstr "tago(j)" #: mediagoblin/tools/timesince.py:66 msgid "hour" -msgstr "" +msgstr "horo(j)" #: mediagoblin/tools/timesince.py:67 msgid "minute" -msgstr "" +msgstr "minuto(j)" #: mediagoblin/user_pages/forms.py:23 msgid "Comment" @@ -1185,7 +1185,7 @@ msgstr "komentis je via afiŝo" #: mediagoblin/user_pages/views.py:169 msgid "Sorry, comments are disabled." -msgstr "" +msgstr "Ve, komentado estas malebligita." #: mediagoblin/user_pages/views.py:174 msgid "Oops, your comment was empty." diff --git a/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo Binary files differindex ececfb2e..c5e50f53 100644 --- a/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo +++ 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 index 03e755ab..8c2f046f 100644 --- a/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po @@ -20,8 +20,8 @@ msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://issues.mediagoblin.org/\n" "POT-Creation-Date: 2013-05-27 13:54-0500\n" -"PO-Revision-Date: 2013-05-27 18:54+0000\n" -"Last-Translator: cwebber <cwebber@dustycloud.org>\n" +"PO-Revision-Date: 2013-06-02 21:23+0000\n" +"Last-Translator: larjona <larjona99@gmail.com>\n" "Language-Team: Spanish (http://www.transifex.com/projects/p/mediagoblin/language/es/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -45,7 +45,7 @@ msgstr "Dirección de correo electrónico" #: mediagoblin/auth/forms.py:41 msgid "Username or Email" -msgstr "" +msgstr "Nombre de usuario o correo electrónico" #: mediagoblin/auth/forms.py:52 msgid "Username or email" @@ -272,7 +272,7 @@ msgstr "Contraseña incorrecta" #: mediagoblin/edit/views.py:363 msgid "Your password was changed successfully" -msgstr "" +msgstr "Se ha cambiado la contraseña correctamente" #: mediagoblin/gmg_commands/assetlink.py:60 msgid "Cannot link theme... no theme set\n" @@ -289,17 +289,17 @@ msgstr "Sin embargo, se encontró un enlace simbólico de un directorio antiguo; #: mediagoblin/gmg_commands/assetlink.py:112 #, python-format msgid "Could not link \"%s\": %s exists and is not a symlink\n" -msgstr "" +msgstr "No se pudo enlazar \"%s\": %s existe y no es un enlace simbólico\n" #: mediagoblin/gmg_commands/assetlink.py:119 #, python-format msgid "Skipping \"%s\"; already set up.\n" -msgstr "" +msgstr "Omitiendo \"%s\"; ya está establecido.\n" #: mediagoblin/gmg_commands/assetlink.py:124 #, python-format msgid "Old link found for \"%s\"; removing.\n" -msgstr "" +msgstr "Se encontró un enlace antiguo para \"%s\"; se eliminará.\n" #: mediagoblin/meddleware/csrf.py:134 msgid "" @@ -315,7 +315,7 @@ msgstr "Lo sentidos, No soportamos ese tipo de archivo :(" #: mediagoblin/media_types/pdf/processing.py:136 msgid "unoconv failing to run, check log file" -msgstr "" +msgstr "ha fallado la ejecución de unoconv, comprueba el fichero de registro (log)" #: mediagoblin/media_types/video/processing.py:37 msgid "Video transcoding failed" @@ -626,7 +626,7 @@ msgid "" "<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n" " or\n" " <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>" -msgstr "" +msgstr "<a class=\"button_action_highlight\" href=\"%(register_url)s\">Crear una cuenta en este sitio</a>\n o\n <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Instalar MediaGoblin en tu propio servidor</a>" #: mediagoblin/templates/mediagoblin/bits/logo.html:23 #: mediagoblin/themes/airy/templates/mediagoblin/bits/logo.html:23 @@ -673,11 +673,11 @@ msgstr "Guardar cambios" #: mediagoblin/templates/mediagoblin/edit/change_pass.html:38 #, python-format msgid "Changing %(username)s's password" -msgstr "" +msgstr "Cambiando la contraseña de %(username)s" #: mediagoblin/templates/mediagoblin/edit/change_pass.html:45 msgid "Save" -msgstr "" +msgstr "Guardar" #: mediagoblin/templates/mediagoblin/edit/delete_account.html:28 #, python-format @@ -708,7 +708,7 @@ msgstr "Cambio de %(username)s la configuración de la cuenta " #: mediagoblin/templates/mediagoblin/edit/edit_account.html:46 msgid "Change your password." -msgstr "" +msgstr "Cambiar tu contraseña." #: mediagoblin/templates/mediagoblin/edit/edit_account.html:62 msgid "Delete my account" @@ -782,7 +782,7 @@ msgstr "Imágenes para %(media_title)s" #: mediagoblin/templates/mediagoblin/media_displays/pdf.html:79 msgid "PDF file" -msgstr "" +msgstr "Fichero PDF" #: mediagoblin/templates/mediagoblin/media_displays/stl.html:112 msgid "Toggle Rotate" @@ -938,15 +938,15 @@ msgstr "Añade un comentario " #: mediagoblin/templates/mediagoblin/user_pages/media.html:164 #, python-format msgid "%(formatted_time)s ago" -msgstr "" +msgstr "hace %(formatted_time)s" #: mediagoblin/templates/mediagoblin/user_pages/media.html:150 msgid "Added" -msgstr "" +msgstr "Agregado" #: mediagoblin/templates/mediagoblin/user_pages/media.html:161 msgid "Created" -msgstr "" +msgstr "Creado" #: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:28 #: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:40 @@ -1134,27 +1134,27 @@ msgstr "Parece que no hay ninguna página en esta dirección. ¡Lo siento!</p><p #: mediagoblin/tools/timesince.py:62 msgid "year" -msgstr "" +msgstr "año" #: mediagoblin/tools/timesince.py:63 msgid "month" -msgstr "" +msgstr "mes" #: mediagoblin/tools/timesince.py:64 msgid "week" -msgstr "" +msgstr "semana" #: mediagoblin/tools/timesince.py:65 msgid "day" -msgstr "" +msgstr "día" #: mediagoblin/tools/timesince.py:66 msgid "hour" -msgstr "" +msgstr "hora" #: mediagoblin/tools/timesince.py:67 msgid "minute" -msgstr "" +msgstr "minuto" #: mediagoblin/user_pages/forms.py:23 msgid "Comment" @@ -1193,7 +1193,7 @@ msgstr "comentó tu publicación" #: mediagoblin/user_pages/views.py:169 msgid "Sorry, comments are disabled." -msgstr "" +msgstr "Lo siento, los comentarios están desactivados." #: mediagoblin/user_pages/views.py:174 msgid "Oops, your comment was empty." diff --git a/mediagoblin/i18n/he/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/he/LC_MESSAGES/mediagoblin.mo Binary files differindex e2c22c79..09412b0a 100644 --- a/mediagoblin/i18n/he/LC_MESSAGES/mediagoblin.mo +++ b/mediagoblin/i18n/he/LC_MESSAGES/mediagoblin.mo diff --git a/mediagoblin/i18n/he/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/he/LC_MESSAGES/mediagoblin.po index 0cef1736..4a5c2b52 100644 --- a/mediagoblin/i18n/he/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/he/LC_MESSAGES/mediagoblin.po @@ -11,8 +11,8 @@ msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://issues.mediagoblin.org/\n" "POT-Creation-Date: 2013-05-27 13:54-0500\n" -"PO-Revision-Date: 2013-05-27 18:54+0000\n" -"Last-Translator: cwebber <cwebber@dustycloud.org>\n" +"PO-Revision-Date: 2013-06-01 07:11+0000\n" +"Last-Translator: GenghisKhan <genghiskhan@gmx.ca>\n" "Language-Team: Hebrew (http://www.transifex.com/projects/p/mediagoblin/language/he/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -36,7 +36,7 @@ msgstr "כתובת דוא״ל" #: mediagoblin/auth/forms.py:41 msgid "Username or Email" -msgstr "" +msgstr "שם משתמש או דוא״ל" #: mediagoblin/auth/forms.py:52 msgid "Username or email" @@ -263,7 +263,7 @@ msgstr "סיסמה שגויה" #: mediagoblin/edit/views.py:363 msgid "Your password was changed successfully" -msgstr "" +msgstr "סיסמתך שונתה בהצלחה" #: mediagoblin/gmg_commands/assetlink.py:60 msgid "Cannot link theme... no theme set\n" @@ -280,17 +280,17 @@ msgstr "בכל אופן, קישור מדור symlink נמצא; הוסר.\n" #: mediagoblin/gmg_commands/assetlink.py:112 #, python-format msgid "Could not link \"%s\": %s exists and is not a symlink\n" -msgstr "" +msgstr "לא היתה אפשרות לקשר את \"%s\": %s קיים ואינו קישור סמלי (symlink)\n" #: mediagoblin/gmg_commands/assetlink.py:119 #, python-format msgid "Skipping \"%s\"; already set up.\n" -msgstr "" +msgstr "מדלג על \"%s\"; כבר מוגדר.\n" #: mediagoblin/gmg_commands/assetlink.py:124 #, python-format msgid "Old link found for \"%s\"; removing.\n" -msgstr "" +msgstr "קישור ישן נמצא עבור \"%s\"; מסיר כעת.\n" #: mediagoblin/meddleware/csrf.py:134 msgid "" @@ -306,7 +306,7 @@ msgstr "צר לי, אינני תומך בטיפוס קובץ זה :(" #: mediagoblin/media_types/pdf/processing.py:136 msgid "unoconv failing to run, check log file" -msgstr "" +msgstr "unoconv נכשל לפעול, בדוק קובץ יומן" #: mediagoblin/media_types/video/processing.py:37 msgid "Video transcoding failed" @@ -617,7 +617,7 @@ msgid "" "<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n" " or\n" " <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>" -msgstr "" +msgstr "<a class=\"button_action_highlight\" href=\"%(register_url)s\">צור חשבון באתר זה</a>\n או\n <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">התקן את MediaGoblin על שרתך</a>" #: mediagoblin/templates/mediagoblin/bits/logo.html:23 #: mediagoblin/themes/airy/templates/mediagoblin/bits/logo.html:23 @@ -664,11 +664,11 @@ msgstr "שמור שינויים" #: mediagoblin/templates/mediagoblin/edit/change_pass.html:38 #, python-format msgid "Changing %(username)s's password" -msgstr "" +msgstr "משנה כעת את הסיסמה של %(username)s'" #: mediagoblin/templates/mediagoblin/edit/change_pass.html:45 msgid "Save" -msgstr "" +msgstr "שמור" #: mediagoblin/templates/mediagoblin/edit/delete_account.html:28 #, python-format @@ -699,7 +699,7 @@ msgstr "שינוי הגדרות חשבון עבור %(username)s" #: mediagoblin/templates/mediagoblin/edit/edit_account.html:46 msgid "Change your password." -msgstr "" +msgstr "שנה את סיסמתך." #: mediagoblin/templates/mediagoblin/edit/edit_account.html:62 msgid "Delete my account" @@ -773,7 +773,7 @@ msgstr "תמונה עבור %(media_title)s" #: mediagoblin/templates/mediagoblin/media_displays/pdf.html:79 msgid "PDF file" -msgstr "" +msgstr "קובץ PDF" #: mediagoblin/templates/mediagoblin/media_displays/stl.html:112 msgid "Toggle Rotate" @@ -929,15 +929,15 @@ msgstr "הוסף את תגובה זו" #: mediagoblin/templates/mediagoblin/user_pages/media.html:164 #, python-format msgid "%(formatted_time)s ago" -msgstr "" +msgstr "מלפני %(formatted_time)s" #: mediagoblin/templates/mediagoblin/user_pages/media.html:150 msgid "Added" -msgstr "" +msgstr "התווסף" #: mediagoblin/templates/mediagoblin/user_pages/media.html:161 msgid "Created" -msgstr "" +msgstr "נוצר" #: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:28 #: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:40 @@ -1125,27 +1125,27 @@ msgstr "לא נראה שקיים עמוד בכתובת זו. צר לי!</p><p>א #: mediagoblin/tools/timesince.py:62 msgid "year" -msgstr "" +msgstr "שנה" #: mediagoblin/tools/timesince.py:63 msgid "month" -msgstr "" +msgstr "חודש" #: mediagoblin/tools/timesince.py:64 msgid "week" -msgstr "" +msgstr "שבוע" #: mediagoblin/tools/timesince.py:65 msgid "day" -msgstr "" +msgstr "יום" #: mediagoblin/tools/timesince.py:66 msgid "hour" -msgstr "" +msgstr "שעה" #: mediagoblin/tools/timesince.py:67 msgid "minute" -msgstr "" +msgstr "דקה" #: mediagoblin/user_pages/forms.py:23 msgid "Comment" @@ -1184,7 +1184,7 @@ msgstr "הגיב/ה על פרסומך" #: mediagoblin/user_pages/views.py:169 msgid "Sorry, comments are disabled." -msgstr "" +msgstr "מצטערים, תגובות מנוטרלות." #: mediagoblin/user_pages/views.py:174 msgid "Oops, your comment was empty." diff --git a/mediagoblin/i18n/is_IS/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/is_IS/LC_MESSAGES/mediagoblin.mo Binary files differindex 2fb3a8ce..596ab843 100644 --- a/mediagoblin/i18n/is_IS/LC_MESSAGES/mediagoblin.mo +++ b/mediagoblin/i18n/is_IS/LC_MESSAGES/mediagoblin.mo diff --git a/mediagoblin/i18n/is_IS/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/is_IS/LC_MESSAGES/mediagoblin.po index 81ca3838..77896b87 100644 --- a/mediagoblin/i18n/is_IS/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/is_IS/LC_MESSAGES/mediagoblin.po @@ -10,8 +10,8 @@ msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://issues.mediagoblin.org/\n" "POT-Creation-Date: 2013-05-27 13:54-0500\n" -"PO-Revision-Date: 2013-05-27 18:54+0000\n" -"Last-Translator: cwebber <cwebber@dustycloud.org>\n" +"PO-Revision-Date: 2013-06-05 22:51+0000\n" +"Last-Translator: tryggvib <tryggvib@fsfi.is>\n" "Language-Team: Icelandic (Iceland) (http://www.transifex.com/projects/p/mediagoblin/language/is_IS/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -35,7 +35,7 @@ msgstr "Netfang" #: mediagoblin/auth/forms.py:41 msgid "Username or Email" -msgstr "" +msgstr "Notandanafn eða tölvupóstur" #: mediagoblin/auth/forms.py:52 msgid "Username or email" @@ -262,7 +262,7 @@ msgstr "Vitlaust lykilorð" #: mediagoblin/edit/views.py:363 msgid "Your password was changed successfully" -msgstr "" +msgstr "Það tókst að breyta lykilorðinu þínu" #: mediagoblin/gmg_commands/assetlink.py:60 msgid "Cannot link theme... no theme set\n" @@ -279,17 +279,17 @@ msgstr "Fann samt gamlan táknrænan tengil á möppu; fjarlægður.\n" #: mediagoblin/gmg_commands/assetlink.py:112 #, python-format msgid "Could not link \"%s\": %s exists and is not a symlink\n" -msgstr "" +msgstr "Gat ekki tengt \"%s\": %s er til og er ekki sýndartengill\n" #: mediagoblin/gmg_commands/assetlink.py:119 #, python-format msgid "Skipping \"%s\"; already set up.\n" -msgstr "" +msgstr "Hoppa yfir \"%s\"; hefur nú þegar verið sett upp.\n" #: mediagoblin/gmg_commands/assetlink.py:124 #, python-format msgid "Old link found for \"%s\"; removing.\n" -msgstr "" +msgstr "Gamall tengill fannst fyrir \"%s\"; fjarlægi.\n" #: mediagoblin/meddleware/csrf.py:134 msgid "" @@ -305,7 +305,7 @@ msgstr "Ég styð því miður ekki þessa gerð af skrám :(" #: mediagoblin/media_types/pdf/processing.py:136 msgid "unoconv failing to run, check log file" -msgstr "" +msgstr "tekst ekki að keyra unoconv, athugaðu annálsskrá" #: mediagoblin/media_types/video/processing.py:37 msgid "Video transcoding failed" @@ -616,7 +616,7 @@ msgid "" "<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n" " or\n" " <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>" -msgstr "" +msgstr "<a class=\"button_action_highlight\" href=\"%(register_url)s\">Búa til aðgang á þessari síðu</a>\neða\n<a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Settu upp þinn eigin margmiðlunarþjón</a>" #: mediagoblin/templates/mediagoblin/bits/logo.html:23 #: mediagoblin/themes/airy/templates/mediagoblin/bits/logo.html:23 @@ -663,11 +663,11 @@ msgstr "Vista breytingar" #: mediagoblin/templates/mediagoblin/edit/change_pass.html:38 #, python-format msgid "Changing %(username)s's password" -msgstr "" +msgstr "Breyti lykilorði fyrir notandann: %(username)s" #: mediagoblin/templates/mediagoblin/edit/change_pass.html:45 msgid "Save" -msgstr "" +msgstr "Vista" #: mediagoblin/templates/mediagoblin/edit/delete_account.html:28 #, python-format @@ -698,7 +698,7 @@ msgstr "Breyti notandaaðgangsstillingum fyrir: %(username)s" #: mediagoblin/templates/mediagoblin/edit/edit_account.html:46 msgid "Change your password." -msgstr "" +msgstr "Breyta lykilorðinu þínu." #: mediagoblin/templates/mediagoblin/edit/edit_account.html:62 msgid "Delete my account" @@ -772,7 +772,7 @@ msgstr "Mynd fyrir %(media_title)s" #: mediagoblin/templates/mediagoblin/media_displays/pdf.html:79 msgid "PDF file" -msgstr "" +msgstr "PDF skrá" #: mediagoblin/templates/mediagoblin/media_displays/stl.html:112 msgid "Toggle Rotate" @@ -928,15 +928,15 @@ msgstr "Senda inn þessa athugasemd" #: mediagoblin/templates/mediagoblin/user_pages/media.html:164 #, python-format msgid "%(formatted_time)s ago" -msgstr "" +msgstr "Fyrir %(formatted_time)s" #: mediagoblin/templates/mediagoblin/user_pages/media.html:150 msgid "Added" -msgstr "" +msgstr "Bætt við" #: mediagoblin/templates/mediagoblin/user_pages/media.html:161 msgid "Created" -msgstr "" +msgstr "Skapað" #: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:28 #: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:40 @@ -1124,27 +1124,27 @@ msgstr "Því miður! Það virðist ekki vera nein síða á þessari vefslóð #: mediagoblin/tools/timesince.py:62 msgid "year" -msgstr "" +msgstr "ár" #: mediagoblin/tools/timesince.py:63 msgid "month" -msgstr "" +msgstr "mánuður" #: mediagoblin/tools/timesince.py:64 msgid "week" -msgstr "" +msgstr "vika" #: mediagoblin/tools/timesince.py:65 msgid "day" -msgstr "" +msgstr "dagur" #: mediagoblin/tools/timesince.py:66 msgid "hour" -msgstr "" +msgstr "klukkustund" #: mediagoblin/tools/timesince.py:67 msgid "minute" -msgstr "" +msgstr "mínúta" #: mediagoblin/user_pages/forms.py:23 msgid "Comment" @@ -1183,7 +1183,7 @@ msgstr "skrifaði athugasemd við færsluna þína" #: mediagoblin/user_pages/views.py:169 msgid "Sorry, comments are disabled." -msgstr "" +msgstr "Því miður, athugasemdir eru óvirkar." #: mediagoblin/user_pages/views.py:174 msgid "Oops, your comment was empty." diff --git a/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.mo Binary files differindex f9666be3..9cbd03b2 100644 --- a/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.mo +++ 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 index ea0d5d25..6a11d5da 100644 --- a/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po @@ -10,8 +10,8 @@ msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://issues.mediagoblin.org/\n" "POT-Creation-Date: 2013-05-27 13:54-0500\n" -"PO-Revision-Date: 2013-05-27 18:54+0000\n" -"Last-Translator: cwebber <cwebber@dustycloud.org>\n" +"PO-Revision-Date: 2013-05-31 15:40+0000\n" +"Last-Translator: velmont <odin.omdal@gmail.com>\n" "Language-Team: Norwegian Nynorsk (Norway) (http://www.transifex.com/projects/p/mediagoblin/language/nn_NO/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -35,7 +35,7 @@ msgstr "Epost" #: mediagoblin/auth/forms.py:41 msgid "Username or Email" -msgstr "" +msgstr "Brukarnamn eller epost" #: mediagoblin/auth/forms.py:52 msgid "Username or email" @@ -262,7 +262,7 @@ msgstr "Feil passord" #: mediagoblin/edit/views.py:363 msgid "Your password was changed successfully" -msgstr "" +msgstr "Endra passord" #: mediagoblin/gmg_commands/assetlink.py:60 msgid "Cannot link theme... no theme set\n" @@ -279,17 +279,17 @@ msgstr "However, old link directory symlink found; removed.\n" #: mediagoblin/gmg_commands/assetlink.py:112 #, python-format msgid "Could not link \"%s\": %s exists and is not a symlink\n" -msgstr "" +msgstr "Kunne ikkje lenkja «%s»: %s eksisterer og er ikkje ei symlenkje\n" #: mediagoblin/gmg_commands/assetlink.py:119 #, python-format msgid "Skipping \"%s\"; already set up.\n" -msgstr "" +msgstr "Hopper over «%s»: allereie satt opp.\n" #: mediagoblin/gmg_commands/assetlink.py:124 #, python-format msgid "Old link found for \"%s\"; removing.\n" -msgstr "" +msgstr "Gamal lenkje funnen for «%s»; fjernar.\n" #: mediagoblin/meddleware/csrf.py:134 msgid "" @@ -305,7 +305,7 @@ msgstr "Orsak, stør ikkje den filtypen :(" #: mediagoblin/media_types/pdf/processing.py:136 msgid "unoconv failing to run, check log file" -msgstr "" +msgstr "klarte ikkje køyra unoconv, sjekk logg-fil" #: mediagoblin/media_types/video/processing.py:37 msgid "Video transcoding failed" @@ -616,7 +616,7 @@ msgid "" "<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n" " or\n" " <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>" -msgstr "" +msgstr "<a class=\"button_action_highlight\" href=\"%(register_url)s\">Opprett ein konto på denne sida</a>\n eller\n <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set opp din eigen MediaGoblin-server</a>" #: mediagoblin/templates/mediagoblin/bits/logo.html:23 #: mediagoblin/themes/airy/templates/mediagoblin/bits/logo.html:23 @@ -663,11 +663,11 @@ msgstr "Lagra" #: mediagoblin/templates/mediagoblin/edit/change_pass.html:38 #, python-format msgid "Changing %(username)s's password" -msgstr "" +msgstr "Endrar passordet til %(username)s" #: mediagoblin/templates/mediagoblin/edit/change_pass.html:45 msgid "Save" -msgstr "" +msgstr "Lagra" #: mediagoblin/templates/mediagoblin/edit/delete_account.html:28 #, python-format @@ -698,7 +698,7 @@ msgstr "Endrar kontoinnstellingane til %(username)s" #: mediagoblin/templates/mediagoblin/edit/edit_account.html:46 msgid "Change your password." -msgstr "" +msgstr "Endra passordet ditt." #: mediagoblin/templates/mediagoblin/edit/edit_account.html:62 msgid "Delete my account" @@ -772,7 +772,7 @@ msgstr "Bilete for %(media_title)s" #: mediagoblin/templates/mediagoblin/media_displays/pdf.html:79 msgid "PDF file" -msgstr "" +msgstr "PDF-fil" #: mediagoblin/templates/mediagoblin/media_displays/stl.html:112 msgid "Toggle Rotate" @@ -928,15 +928,15 @@ msgstr "Legg til dette innspelet" #: mediagoblin/templates/mediagoblin/user_pages/media.html:164 #, python-format msgid "%(formatted_time)s ago" -msgstr "" +msgstr "%(formatted_time)s sidan" #: mediagoblin/templates/mediagoblin/user_pages/media.html:150 msgid "Added" -msgstr "" +msgstr "Lagt til" #: mediagoblin/templates/mediagoblin/user_pages/media.html:161 msgid "Created" -msgstr "" +msgstr "Oppretta" #: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:28 #: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:40 @@ -1124,27 +1124,27 @@ msgstr "Ser ikkje ut til å finnast noko her. Orsak.</p>\n<p>Dersom du er sikker #: mediagoblin/tools/timesince.py:62 msgid "year" -msgstr "" +msgstr "år" #: mediagoblin/tools/timesince.py:63 msgid "month" -msgstr "" +msgstr "månad" #: mediagoblin/tools/timesince.py:64 msgid "week" -msgstr "" +msgstr "veke" #: mediagoblin/tools/timesince.py:65 msgid "day" -msgstr "" +msgstr "dag" #: mediagoblin/tools/timesince.py:66 msgid "hour" -msgstr "" +msgstr "time" #: mediagoblin/tools/timesince.py:67 msgid "minute" -msgstr "" +msgstr "minutt" #: mediagoblin/user_pages/forms.py:23 msgid "Comment" @@ -1183,7 +1183,7 @@ msgstr "kom med innspel på innlegget ditt" #: mediagoblin/user_pages/views.py:169 msgid "Sorry, comments are disabled." -msgstr "" +msgstr "Innspel er avslege" #: mediagoblin/user_pages/views.py:174 msgid "Oops, your comment was empty." diff --git a/mediagoblin/i18n/pl/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/pl/LC_MESSAGES/mediagoblin.mo Binary files differindex 5a234c82..8b318329 100644 --- a/mediagoblin/i18n/pl/LC_MESSAGES/mediagoblin.mo +++ b/mediagoblin/i18n/pl/LC_MESSAGES/mediagoblin.mo diff --git a/mediagoblin/i18n/pl/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/pl/LC_MESSAGES/mediagoblin.po index 5a36889a..78ab219a 100644 --- a/mediagoblin/i18n/pl/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/pl/LC_MESSAGES/mediagoblin.po @@ -10,8 +10,8 @@ msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://issues.mediagoblin.org/\n" "POT-Creation-Date: 2013-05-27 13:54-0500\n" -"PO-Revision-Date: 2013-05-27 18:54+0000\n" -"Last-Translator: cwebber <cwebber@dustycloud.org>\n" +"PO-Revision-Date: 2013-05-28 13:51+0000\n" +"Last-Translator: Sergiusz Pawlowicz <transifex@pawlowicz.name>\n" "Language-Team: Polish (http://www.transifex.com/projects/p/mediagoblin/language/pl/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -35,7 +35,7 @@ msgstr "Adres e-mail" #: mediagoblin/auth/forms.py:41 msgid "Username or Email" -msgstr "" +msgstr "Nazwa konta lub adres poczty elektronicznej" #: mediagoblin/auth/forms.py:52 msgid "Username or email" @@ -262,7 +262,7 @@ msgstr "Nieprawidłowe hasło" #: mediagoblin/edit/views.py:363 msgid "Your password was changed successfully" -msgstr "" +msgstr "Twoje hasło zostało zmienione" #: mediagoblin/gmg_commands/assetlink.py:60 msgid "Cannot link theme... no theme set\n" @@ -279,17 +279,17 @@ msgstr "Znaleziono stary odnośnik symboliczny do katalogu; usunięto.\n" #: mediagoblin/gmg_commands/assetlink.py:112 #, python-format msgid "Could not link \"%s\": %s exists and is not a symlink\n" -msgstr "" +msgstr "Nie mogę zrobić odnośnika \"%s\": %s istnieje i nie jest odnośnikiem\n" #: mediagoblin/gmg_commands/assetlink.py:119 #, python-format msgid "Skipping \"%s\"; already set up.\n" -msgstr "" +msgstr "Opuszczam \"%s\"; już jest gotowe.\n" #: mediagoblin/gmg_commands/assetlink.py:124 #, python-format msgid "Old link found for \"%s\"; removing.\n" -msgstr "" +msgstr "Znaleziono stary odnośnik dla \"%s\"; usuwam.\n" #: mediagoblin/meddleware/csrf.py:134 msgid "" @@ -305,7 +305,7 @@ msgstr "NIestety, nie obsługujemy tego typu plików :-(" #: mediagoblin/media_types/pdf/processing.py:136 msgid "unoconv failing to run, check log file" -msgstr "" +msgstr "nie dało się uruchomić unoconv, sprawdź log" #: mediagoblin/media_types/video/processing.py:37 msgid "Video transcoding failed" @@ -616,7 +616,7 @@ msgid "" "<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n" " or\n" " <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>" -msgstr "" +msgstr "<a class=\"button_action_highlight\" href=\"%(register_url)s\">Załóż konto na tym serwerze</a>\n albo\n <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Uruchom MediaGoblin na swoim własnym serwerze</a>" #: mediagoblin/templates/mediagoblin/bits/logo.html:23 #: mediagoblin/themes/airy/templates/mediagoblin/bits/logo.html:23 @@ -663,11 +663,11 @@ msgstr "Zapisz zmiany" #: mediagoblin/templates/mediagoblin/edit/change_pass.html:38 #, python-format msgid "Changing %(username)s's password" -msgstr "" +msgstr "Zmieniam hasło użytkownika %(username)s" #: mediagoblin/templates/mediagoblin/edit/change_pass.html:45 msgid "Save" -msgstr "" +msgstr "Zachowaj" #: mediagoblin/templates/mediagoblin/edit/delete_account.html:28 #, python-format @@ -698,7 +698,7 @@ msgstr "Zmiana ustawień konta %(username)s" #: mediagoblin/templates/mediagoblin/edit/edit_account.html:46 msgid "Change your password." -msgstr "" +msgstr "Zmień swoje hasło." #: mediagoblin/templates/mediagoblin/edit/edit_account.html:62 msgid "Delete my account" @@ -772,7 +772,7 @@ msgstr "Grafika dla %(media_title)s" #: mediagoblin/templates/mediagoblin/media_displays/pdf.html:79 msgid "PDF file" -msgstr "" +msgstr "Plik PDF" #: mediagoblin/templates/mediagoblin/media_displays/stl.html:112 msgid "Toggle Rotate" @@ -928,15 +928,15 @@ msgstr "Dodaj komentarz" #: mediagoblin/templates/mediagoblin/user_pages/media.html:164 #, python-format msgid "%(formatted_time)s ago" -msgstr "" +msgstr "%(formatted_time)s temu" #: mediagoblin/templates/mediagoblin/user_pages/media.html:150 msgid "Added" -msgstr "" +msgstr "Dodano" #: mediagoblin/templates/mediagoblin/user_pages/media.html:161 msgid "Created" -msgstr "" +msgstr "Utworzono" #: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:28 #: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:40 @@ -1124,27 +1124,27 @@ msgstr "Wygląda na to, że nic tutaj nie ma!</p><p>Jeśli jesteś pewny, że ad #: mediagoblin/tools/timesince.py:62 msgid "year" -msgstr "" +msgstr "rok" #: mediagoblin/tools/timesince.py:63 msgid "month" -msgstr "" +msgstr "miesiąc" #: mediagoblin/tools/timesince.py:64 msgid "week" -msgstr "" +msgstr "tydzień" #: mediagoblin/tools/timesince.py:65 msgid "day" -msgstr "" +msgstr "dzień" #: mediagoblin/tools/timesince.py:66 msgid "hour" -msgstr "" +msgstr "godzina" #: mediagoblin/tools/timesince.py:67 msgid "minute" -msgstr "" +msgstr "minuta" #: mediagoblin/user_pages/forms.py:23 msgid "Comment" @@ -1183,7 +1183,7 @@ msgstr "komentarze do twojego wpisu" #: mediagoblin/user_pages/views.py:169 msgid "Sorry, comments are disabled." -msgstr "" +msgstr "Komentowanie jest wyłączone." #: mediagoblin/user_pages/views.py:174 msgid "Oops, your comment was empty." diff --git a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo Binary files differindex 309855f5..8cfdf339 100644 --- a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo +++ 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 index 4a33f751..af2d94d6 100644 --- a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po @@ -10,8 +10,8 @@ msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://issues.mediagoblin.org/\n" "POT-Creation-Date: 2013-05-27 13:54-0500\n" -"PO-Revision-Date: 2013-05-27 18:54+0000\n" -"Last-Translator: cwebber <cwebber@dustycloud.org>\n" +"PO-Revision-Date: 2013-05-27 20:40+0000\n" +"Last-Translator: George Pop <gapop@hotmail.com>\n" "Language-Team: Romanian (http://www.transifex.com/projects/p/mediagoblin/language/ro/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -35,7 +35,7 @@ msgstr "Adresa de e-mail" #: mediagoblin/auth/forms.py:41 msgid "Username or Email" -msgstr "" +msgstr "Numele de utilizator sau adresa de e-mail" #: mediagoblin/auth/forms.py:52 msgid "Username or email" @@ -262,7 +262,7 @@ msgstr "Parolă incorectă" #: mediagoblin/edit/views.py:363 msgid "Your password was changed successfully" -msgstr "" +msgstr "Parola a fost schimbată cu succes" #: mediagoblin/gmg_commands/assetlink.py:60 msgid "Cannot link theme... no theme set\n" @@ -279,17 +279,17 @@ msgstr "A fost însă găsit un symlink către vechiul folder; s-a șters.\n" #: mediagoblin/gmg_commands/assetlink.py:112 #, python-format msgid "Could not link \"%s\": %s exists and is not a symlink\n" -msgstr "" +msgstr "Nu s-a putut crea link pentru \"%s\": %s există deja și nu este symlink\n" #: mediagoblin/gmg_commands/assetlink.py:119 #, python-format msgid "Skipping \"%s\"; already set up.\n" -msgstr "" +msgstr "S-a omis \"%s\"; configurat deja.\n" #: mediagoblin/gmg_commands/assetlink.py:124 #, python-format msgid "Old link found for \"%s\"; removing.\n" -msgstr "" +msgstr "Există deja un link pentru \"%s\"; va fi șters.\n" #: mediagoblin/meddleware/csrf.py:134 msgid "" @@ -305,7 +305,7 @@ msgstr "Scuze, nu recunosc acest tip de fișier :(" #: mediagoblin/media_types/pdf/processing.py:136 msgid "unoconv failing to run, check log file" -msgstr "" +msgstr "unoconv nu poate fi executat; verificați log-ul" #: mediagoblin/media_types/video/processing.py:37 msgid "Video transcoding failed" @@ -616,7 +616,7 @@ msgid "" "<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n" " or\n" " <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>" -msgstr "" +msgstr "<a class=\"button_action_highlight\" href=\"%(register_url)s\">Creați un cont pe acest site</a>\n sau\n <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Instalați MediaGoblin pe serverul dvs.</a>" #: mediagoblin/templates/mediagoblin/bits/logo.html:23 #: mediagoblin/themes/airy/templates/mediagoblin/bits/logo.html:23 @@ -663,11 +663,11 @@ msgstr "Salvează modificările" #: mediagoblin/templates/mediagoblin/edit/change_pass.html:38 #, python-format msgid "Changing %(username)s's password" -msgstr "" +msgstr "Se modifică parola pentru %(username)s" #: mediagoblin/templates/mediagoblin/edit/change_pass.html:45 msgid "Save" -msgstr "" +msgstr "Salvează" #: mediagoblin/templates/mediagoblin/edit/delete_account.html:28 #, python-format @@ -698,7 +698,7 @@ msgstr "Se modifică setările contului pentru userul %(username)s" #: mediagoblin/templates/mediagoblin/edit/edit_account.html:46 msgid "Change your password." -msgstr "" +msgstr "Modifică parolă." #: mediagoblin/templates/mediagoblin/edit/edit_account.html:62 msgid "Delete my account" @@ -772,7 +772,7 @@ msgstr "Imagine pentru %(media_title)s" #: mediagoblin/templates/mediagoblin/media_displays/pdf.html:79 msgid "PDF file" -msgstr "" +msgstr "Fișier PDF" #: mediagoblin/templates/mediagoblin/media_displays/stl.html:112 msgid "Toggle Rotate" @@ -928,15 +928,15 @@ msgstr "Trimite acest comentariu" #: mediagoblin/templates/mediagoblin/user_pages/media.html:164 #, python-format msgid "%(formatted_time)s ago" -msgstr "" +msgstr "în urmă cu %(formatted_time)s" #: mediagoblin/templates/mediagoblin/user_pages/media.html:150 msgid "Added" -msgstr "" +msgstr "Adăugat" #: mediagoblin/templates/mediagoblin/user_pages/media.html:161 msgid "Created" -msgstr "" +msgstr "Creat" #: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:28 #: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:40 @@ -1124,27 +1124,27 @@ msgstr "Nu există nicio pagină la această adresă.</p><p>Dacă sunteți sigur #: mediagoblin/tools/timesince.py:62 msgid "year" -msgstr "" +msgstr "anul" #: mediagoblin/tools/timesince.py:63 msgid "month" -msgstr "" +msgstr "luna" #: mediagoblin/tools/timesince.py:64 msgid "week" -msgstr "" +msgstr "săptămâna" #: mediagoblin/tools/timesince.py:65 msgid "day" -msgstr "" +msgstr "ziua" #: mediagoblin/tools/timesince.py:66 msgid "hour" -msgstr "" +msgstr "ora" #: mediagoblin/tools/timesince.py:67 msgid "minute" -msgstr "" +msgstr "minutul" #: mediagoblin/user_pages/forms.py:23 msgid "Comment" @@ -1183,7 +1183,7 @@ msgstr "a făcut un comentariu la postarea ta" #: mediagoblin/user_pages/views.py:169 msgid "Sorry, comments are disabled." -msgstr "" +msgstr "Comentariile sunt dezactivate." #: mediagoblin/user_pages/views.py:174 msgid "Oops, your comment was empty." diff --git a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo Binary files differindex 89836e48..ed28ff43 100644 --- a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo +++ b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo diff --git a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po index 12c79b17..d0ff7bdd 100644 --- a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po @@ -10,8 +10,8 @@ msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://issues.mediagoblin.org/\n" "POT-Creation-Date: 2013-05-27 13:54-0500\n" -"PO-Revision-Date: 2013-05-27 18:54+0000\n" -"Last-Translator: cwebber <cwebber@dustycloud.org>\n" +"PO-Revision-Date: 2013-06-01 21:08+0000\n" +"Last-Translator: aleksejrs <deletesoftware@yandex.ru>\n" "Language-Team: Russian (http://www.transifex.com/projects/p/mediagoblin/language/ru/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -35,7 +35,7 @@ msgstr "Адрес электронной почты" #: mediagoblin/auth/forms.py:41 msgid "Username or Email" -msgstr "" +msgstr "Имя пользователя или адрес электронной почты" #: mediagoblin/auth/forms.py:52 msgid "Username or email" @@ -262,7 +262,7 @@ msgstr "Неправильный пароль" #: mediagoblin/edit/views.py:363 msgid "Your password was changed successfully" -msgstr "" +msgstr "Ваш пароль сменён успешно" #: mediagoblin/gmg_commands/assetlink.py:60 msgid "Cannot link theme... no theme set\n" @@ -663,11 +663,11 @@ msgstr "Сохранить изменения" #: mediagoblin/templates/mediagoblin/edit/change_pass.html:38 #, python-format msgid "Changing %(username)s's password" -msgstr "" +msgstr "Смена пароля %(username)s" #: mediagoblin/templates/mediagoblin/edit/change_pass.html:45 msgid "Save" -msgstr "" +msgstr "Сохранить" #: mediagoblin/templates/mediagoblin/edit/delete_account.html:28 #, python-format @@ -698,7 +698,7 @@ msgstr "Настройка учётной записи %(username)s" #: mediagoblin/templates/mediagoblin/edit/edit_account.html:46 msgid "Change your password." -msgstr "" +msgstr "Сменить пароль" #: mediagoblin/templates/mediagoblin/edit/edit_account.html:62 msgid "Delete my account" @@ -772,7 +772,7 @@ msgstr "Изображение «%(media_title)s»" #: mediagoblin/templates/mediagoblin/media_displays/pdf.html:79 msgid "PDF file" -msgstr "" +msgstr "PDF-файл" #: mediagoblin/templates/mediagoblin/media_displays/stl.html:112 msgid "Toggle Rotate" @@ -928,15 +928,15 @@ msgstr "Добавить этот комментарий" #: mediagoblin/templates/mediagoblin/user_pages/media.html:164 #, python-format msgid "%(formatted_time)s ago" -msgstr "" +msgstr "%(formatted_time)s назад" #: mediagoblin/templates/mediagoblin/user_pages/media.html:150 msgid "Added" -msgstr "" +msgstr "Добавлен" #: mediagoblin/templates/mediagoblin/user_pages/media.html:161 msgid "Created" -msgstr "" +msgstr "Создан" #: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:28 #: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:40 @@ -1144,7 +1144,7 @@ msgstr "" #: mediagoblin/tools/timesince.py:67 msgid "minute" -msgstr "" +msgstr "мин" #: mediagoblin/user_pages/forms.py:23 msgid "Comment" @@ -1183,7 +1183,7 @@ msgstr "оставил комментарий к вашему файлу" #: mediagoblin/user_pages/views.py:169 msgid "Sorry, comments are disabled." -msgstr "" +msgstr "Сожалеем: возможность комментирования отключена." #: mediagoblin/user_pages/views.py:174 msgid "Oops, your comment was empty." diff --git a/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.mo Binary files differindex a262aaee..fd48a37f 100644 --- a/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.mo +++ b/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.mo diff --git a/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.po index ecb83098..e4d1bacc 100644 --- a/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.po @@ -14,8 +14,8 @@ msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://issues.mediagoblin.org/\n" "POT-Creation-Date: 2013-05-27 13:54-0500\n" -"PO-Revision-Date: 2013-05-27 18:54+0000\n" -"Last-Translator: cwebber <cwebber@dustycloud.org>\n" +"PO-Revision-Date: 2013-05-28 07:47+0000\n" +"Last-Translator: martin <zatroch.martin@gmail.com>\n" "Language-Team: Slovak (http://www.transifex.com/projects/p/mediagoblin/language/sk/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -39,7 +39,7 @@ msgstr "Email adresse" #: mediagoblin/auth/forms.py:41 msgid "Username or Email" -msgstr "" +msgstr "Použivateľské meno alebo e-mail" #: mediagoblin/auth/forms.py:52 msgid "Username or email" @@ -266,7 +266,7 @@ msgstr "Nesprávne heslo" #: mediagoblin/edit/views.py:363 msgid "Your password was changed successfully" -msgstr "" +msgstr "Tvoje heslo bolo úspešne zmenené" #: mediagoblin/gmg_commands/assetlink.py:60 msgid "Cannot link theme... no theme set\n" @@ -283,17 +283,17 @@ msgstr "Odstránené; hoci bol pôvodný symbolický odkaz adresára nájdený.\ #: mediagoblin/gmg_commands/assetlink.py:112 #, python-format msgid "Could not link \"%s\": %s exists and is not a symlink\n" -msgstr "" +msgstr "Nemožno odkazovať na \"%s\": %s existuje a nie je symbolickým odkazom\n" #: mediagoblin/gmg_commands/assetlink.py:119 #, python-format msgid "Skipping \"%s\"; already set up.\n" -msgstr "" +msgstr "Preskakujem \"%s\"; opakovane nastavené.\n" #: mediagoblin/gmg_commands/assetlink.py:124 #, python-format msgid "Old link found for \"%s\"; removing.\n" -msgstr "" +msgstr "Nájdený starý odkaz pre \"%s\"; odstraňujem.\n" #: mediagoblin/meddleware/csrf.py:134 msgid "" @@ -309,7 +309,7 @@ msgstr "Prepáč, nepodporujem tento typ súborov =(" #: mediagoblin/media_types/pdf/processing.py:136 msgid "unoconv failing to run, check log file" -msgstr "" +msgstr "beh unoconv zlyhal, preskúmajte log záznam" #: mediagoblin/media_types/video/processing.py:37 msgid "Video transcoding failed" @@ -620,7 +620,7 @@ msgid "" "<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n" " or\n" " <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>" -msgstr "" +msgstr "<a class=\"button_action_highlight\" href=\"%(register_url)s\">Vytvoriť účet na tejto stránke</a>\n alebo\n <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Nastaviť MediaGoblin na vlastnom serveri</a>" #: mediagoblin/templates/mediagoblin/bits/logo.html:23 #: mediagoblin/themes/airy/templates/mediagoblin/bits/logo.html:23 @@ -667,11 +667,11 @@ msgstr "Uložiť zmeny" #: mediagoblin/templates/mediagoblin/edit/change_pass.html:38 #, python-format msgid "Changing %(username)s's password" -msgstr "" +msgstr "Mením heslo používateľa %(username)s" #: mediagoblin/templates/mediagoblin/edit/change_pass.html:45 msgid "Save" -msgstr "" +msgstr "Uložiť" #: mediagoblin/templates/mediagoblin/edit/delete_account.html:28 #, python-format @@ -702,7 +702,7 @@ msgstr "Mením nastavenia účtu používateľa %(username)s" #: mediagoblin/templates/mediagoblin/edit/edit_account.html:46 msgid "Change your password." -msgstr "" +msgstr "Zmeniť svoje heslo." #: mediagoblin/templates/mediagoblin/edit/edit_account.html:62 msgid "Delete my account" @@ -776,7 +776,7 @@ msgstr "Obrázok pre %(media_title)s" #: mediagoblin/templates/mediagoblin/media_displays/pdf.html:79 msgid "PDF file" -msgstr "" +msgstr "PDF súbor" #: mediagoblin/templates/mediagoblin/media_displays/stl.html:112 msgid "Toggle Rotate" @@ -932,15 +932,15 @@ msgstr "Pridať tento komentár" #: mediagoblin/templates/mediagoblin/user_pages/media.html:164 #, python-format msgid "%(formatted_time)s ago" -msgstr "" +msgstr "pred %(formatted_time)s " #: mediagoblin/templates/mediagoblin/user_pages/media.html:150 msgid "Added" -msgstr "" +msgstr "Pridané" #: mediagoblin/templates/mediagoblin/user_pages/media.html:161 msgid "Created" -msgstr "" +msgstr "Vytvorené" #: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:28 #: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:40 @@ -1128,27 +1128,27 @@ msgstr "Zdá sa, že na tejto adrese sa nič nenachádza. Prepáč!</p><p>Pokia #: mediagoblin/tools/timesince.py:62 msgid "year" -msgstr "" +msgstr "rok" #: mediagoblin/tools/timesince.py:63 msgid "month" -msgstr "" +msgstr "mesiac" #: mediagoblin/tools/timesince.py:64 msgid "week" -msgstr "" +msgstr "týždeň" #: mediagoblin/tools/timesince.py:65 msgid "day" -msgstr "" +msgstr "deň" #: mediagoblin/tools/timesince.py:66 msgid "hour" -msgstr "" +msgstr "hodina" #: mediagoblin/tools/timesince.py:67 msgid "minute" -msgstr "" +msgstr "minúta" #: mediagoblin/user_pages/forms.py:23 msgid "Comment" @@ -1187,7 +1187,7 @@ msgstr "okmentoval tvoj príspevok" #: mediagoblin/user_pages/views.py:169 msgid "Sorry, comments are disabled." -msgstr "" +msgstr "Prepáč, komentovanie je vypnuté." #: mediagoblin/user_pages/views.py:174 msgid "Oops, your comment was empty." diff --git a/mediagoblin/i18n/tr_TR/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/tr_TR/LC_MESSAGES/mediagoblin.mo Binary files differnew file mode 100644 index 00000000..4341870b --- /dev/null +++ b/mediagoblin/i18n/tr_TR/LC_MESSAGES/mediagoblin.mo diff --git a/mediagoblin/i18n/tr_TR/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/tr_TR/LC_MESSAGES/mediagoblin.po new file mode 100644 index 00000000..4155520f --- /dev/null +++ b/mediagoblin/i18n/tr_TR/LC_MESSAGES/mediagoblin.po @@ -0,0 +1,1252 @@ +# Translations template for PROJECT. +# Copyright (C) 2013 ORGANIZATION +# This file is distributed under the same license as the PROJECT project. +# +# Translators: +# Caner BAŞARAN <basaran.caner@gmail.com>, 2013 +msgid "" +msgstr "" +"Project-Id-Version: GNU MediaGoblin\n" +"Report-Msgid-Bugs-To: http://issues.mediagoblin.org/\n" +"POT-Creation-Date: 2013-05-27 13:54-0500\n" +"PO-Revision-Date: 2013-06-06 15:44+0000\n" +"Last-Translator: Caner BAŞARAN <basaran.caner@gmail.com>\n" +"Language-Team: Turkish (Turkey) (http://www.transifex.com/projects/p/mediagoblin/language/tr_TR/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 0.9.6\n" +"Language: tr_TR\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#: mediagoblin/auth/forms.py:26 +msgid "Username" +msgstr "Kullanıcı adı" + +#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:45 +#: mediagoblin/tests/test_util.py:110 +msgid "Password" +msgstr "Parola" + +#: mediagoblin/auth/forms.py:34 +msgid "Email address" +msgstr "E-posta adresi" + +#: mediagoblin/auth/forms.py:41 +msgid "Username or Email" +msgstr "Kullanıcı adı veya E-posta" + +#: mediagoblin/auth/forms.py:52 +msgid "Username or email" +msgstr "Kullanıcı adı ya da e-posta" + +#: mediagoblin/auth/tools.py:31 +msgid "Invalid User name or email address." +msgstr "" + +#: mediagoblin/auth/tools.py:32 +msgid "This field does not take email addresses." +msgstr "" + +#: mediagoblin/auth/tools.py:33 +msgid "This field requires an email address." +msgstr "" + +#: mediagoblin/auth/views.py:54 +msgid "Sorry, registration is disabled on this instance." +msgstr "Üzgünüz, bu durumda kayıt devre dışıdır." + +#: mediagoblin/auth/views.py:68 +msgid "Sorry, a user with that name already exists." +msgstr "Maalesef, bu isimde bir kullanıcı mevcut." + +#: mediagoblin/auth/views.py:72 +msgid "Sorry, a user with that email address already exists." +msgstr "Üzgünüz, bu e-posta adresine sahip bir kullanıcı zaten var." + +#: mediagoblin/auth/views.py:182 +msgid "" +"Your email address has been verified. You may now login, edit your profile, " +"and submit images!" +msgstr "E-posta adresiniz doğrulandı. Şimdi giriş yapabilir, profilinizi düzenleyip ve yeni görüntüleri gönderebilirsiniz!" + +#: mediagoblin/auth/views.py:188 +msgid "The verification key or user id is incorrect" +msgstr "Doğrulama anahtarı veya kullanıcı kimliği yanlış" + +#: mediagoblin/auth/views.py:206 +msgid "You must be logged in so we know who to send the email to!" +msgstr "" + +#: mediagoblin/auth/views.py:214 +msgid "You've already verified your email address!" +msgstr "Zaten e-posta adresinizi doğruladınız!" + +#: mediagoblin/auth/views.py:227 +msgid "Resent your verification email." +msgstr "Doğrulama e-postasını tekrar yolla." + +#: mediagoblin/auth/views.py:258 +msgid "" +"If that email address (case sensitive!) is registered an email has been sent" +" with instructions on how to change your password." +msgstr "" + +#: mediagoblin/auth/views.py:269 +msgid "Couldn't find someone with that username." +msgstr "" + +#: mediagoblin/auth/views.py:272 +msgid "" +"An email has been sent with instructions on how to change your password." +msgstr "Parolanızı nasıl değiştireceğinizle ilgili adımları anlatan bir e-posta gönderildi." + +#: mediagoblin/auth/views.py:279 +msgid "" +"Could not send password recovery email as your username is inactive or your " +"account's email address has not been verified." +msgstr "" + +#: mediagoblin/auth/views.py:336 +msgid "You can now log in using your new password." +msgstr "Şimdi yeni parolanızı giriş için kullanabilirsiniz." + +#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:82 +#: mediagoblin/submit/forms.py:28 mediagoblin/submit/forms.py:47 +#: mediagoblin/user_pages/forms.py:45 +msgid "Title" +msgstr "Başlık" + +#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 +msgid "Description of this work" +msgstr "" + +#: mediagoblin/edit/forms.py:29 mediagoblin/edit/forms.py:52 +#: mediagoblin/edit/forms.py:86 mediagoblin/submit/forms.py:32 +#: mediagoblin/submit/forms.py:51 mediagoblin/user_pages/forms.py:49 +msgid "" +"You can use\n" +" <a href=\"http://daringfireball.net/projects/markdown/basics\">\n" +" Markdown</a> for formatting." +msgstr "" + +#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:36 +msgid "Tags" +msgstr "Etiketler" + +#: mediagoblin/edit/forms.py:35 mediagoblin/submit/forms.py:38 +msgid "Separate tags by commas." +msgstr "Etikerleri virgül ile ayırın." + +#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:90 +msgid "Slug" +msgstr "" + +#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:91 +msgid "The slug can't be empty" +msgstr "" + +#: mediagoblin/edit/forms.py:40 +msgid "" +"The title part of this media's address. You usually don't need to change " +"this." +msgstr "" + +#: mediagoblin/edit/forms.py:44 mediagoblin/submit/forms.py:41 +#: mediagoblin/templates/mediagoblin/utils/license.html:20 +msgid "License" +msgstr "" + +#: mediagoblin/edit/forms.py:50 +msgid "Bio" +msgstr "" + +#: mediagoblin/edit/forms.py:56 +msgid "Website" +msgstr "Web sitesi" + +#: mediagoblin/edit/forms.py:58 +msgid "This address contains errors" +msgstr "" + +#: mediagoblin/edit/forms.py:63 +msgid "License preference" +msgstr "" + +#: mediagoblin/edit/forms.py:69 +msgid "This will be your default license on upload forms." +msgstr "" + +#: mediagoblin/edit/forms.py:71 +msgid "Email me when others comment on my media" +msgstr "Medyama birisi yorum yazdığında bana e-posta at" + +#: mediagoblin/edit/forms.py:83 +msgid "The title can't be empty" +msgstr "" + +#: mediagoblin/edit/forms.py:85 mediagoblin/submit/forms.py:50 +#: mediagoblin/user_pages/forms.py:48 +msgid "Description of this collection" +msgstr "" + +#: mediagoblin/edit/forms.py:92 +msgid "" +"The title part of this collection's address. You usually don't need to " +"change this." +msgstr "" + +#: mediagoblin/edit/forms.py:99 +msgid "Old password" +msgstr "Eski parola" + +#: mediagoblin/edit/forms.py:101 +msgid "Enter your old password to prove you own this account." +msgstr "" + +#: mediagoblin/edit/forms.py:104 +msgid "New password" +msgstr "Yeni parola" + +#: mediagoblin/edit/views.py:67 +msgid "An entry with that slug already exists for this user." +msgstr "" + +#: mediagoblin/edit/views.py:85 +msgid "You are editing another user's media. Proceed with caution." +msgstr "Başka bir kullanıcının medyasını düzenlerken dikkatli davranın." + +#: mediagoblin/edit/views.py:155 +#, python-format +msgid "You added the attachment %s!" +msgstr "" + +#: mediagoblin/edit/views.py:182 +msgid "You can only edit your own profile." +msgstr "" + +#: mediagoblin/edit/views.py:188 +msgid "You are editing a user's profile. Proceed with caution." +msgstr "Başka bir kullanıcının profilini düzenlerken dikkatli davranın." + +#: mediagoblin/edit/views.py:204 +msgid "Profile changes saved" +msgstr "Profil değişiklikleri kaydedildi" + +#: mediagoblin/edit/views.py:240 +msgid "Account settings saved" +msgstr "Hesap ayarları kaydedildi" + +#: mediagoblin/edit/views.py:274 +msgid "You need to confirm the deletion of your account." +msgstr "" + +#: mediagoblin/edit/views.py:310 mediagoblin/submit/views.py:138 +#: mediagoblin/user_pages/views.py:222 +#, python-format +msgid "You already have a collection called \"%s\"!" +msgstr "" + +#: mediagoblin/edit/views.py:314 +msgid "A collection with that slug already exists for this user." +msgstr "" + +#: mediagoblin/edit/views.py:329 +msgid "You are editing another user's collection. Proceed with caution." +msgstr "" + +#: mediagoblin/edit/views.py:348 +msgid "Wrong password" +msgstr "Yanlış parola" + +#: mediagoblin/edit/views.py:363 +msgid "Your password was changed successfully" +msgstr "Parolanız başarılı bir şekilde değiştirildi" + +#: mediagoblin/gmg_commands/assetlink.py:60 +msgid "Cannot link theme... no theme set\n" +msgstr "" + +#: mediagoblin/gmg_commands/assetlink.py:73 +msgid "No asset directory for this theme\n" +msgstr "" + +#: mediagoblin/gmg_commands/assetlink.py:76 +msgid "However, old link directory symlink found; removed.\n" +msgstr "" + +#: mediagoblin/gmg_commands/assetlink.py:112 +#, python-format +msgid "Could not link \"%s\": %s exists and is not a symlink\n" +msgstr "" + +#: mediagoblin/gmg_commands/assetlink.py:119 +#, python-format +msgid "Skipping \"%s\"; already set up.\n" +msgstr "" + +#: mediagoblin/gmg_commands/assetlink.py:124 +#, python-format +msgid "Old link found for \"%s\"; removing.\n" +msgstr "" + +#: mediagoblin/meddleware/csrf.py:134 +msgid "" +"CSRF cookie not present. This is most likely the result of a cookie blocker " +"or somesuch.<br/>Make sure to permit the settings of cookies for this " +"domain." +msgstr "" + +#: mediagoblin/media_types/__init__.py:111 +#: mediagoblin/media_types/__init__.py:155 +msgid "Sorry, I don't support that file type :(" +msgstr "Üzgünüz, bu tip dosyaları desteklemiyoruz :(" + +#: mediagoblin/media_types/pdf/processing.py:136 +msgid "unoconv failing to run, check log file" +msgstr "" + +#: mediagoblin/media_types/video/processing.py:37 +msgid "Video transcoding failed" +msgstr "" + +#: mediagoblin/plugins/geolocation/templates/mediagoblin/plugins/geolocation/map.html:24 +msgid "Location" +msgstr "" + +#: mediagoblin/plugins/geolocation/templates/mediagoblin/plugins/geolocation/map.html:52 +#, python-format +msgid "View on <a href=\"%(osm_url)s\">OpenStreetMap</a>" +msgstr "" + +#: mediagoblin/plugins/oauth/forms.py:29 +msgid "Allow" +msgstr "" + +#: mediagoblin/plugins/oauth/forms.py:30 +msgid "Deny" +msgstr "" + +#: mediagoblin/plugins/oauth/forms.py:34 +msgid "Name" +msgstr "" + +#: mediagoblin/plugins/oauth/forms.py:35 +msgid "The name of the OAuth client" +msgstr "" + +#: mediagoblin/plugins/oauth/forms.py:36 +msgid "Description" +msgstr "" + +#: mediagoblin/plugins/oauth/forms.py:38 +msgid "" +"This will be visible to users allowing your\n" +" application to authenticate as them." +msgstr "" + +#: mediagoblin/plugins/oauth/forms.py:40 +msgid "Type" +msgstr "Tür" + +#: mediagoblin/plugins/oauth/forms.py:45 +msgid "" +"<strong>Confidential</strong> - The client can\n" +" make requests to the GNU MediaGoblin instance that can not be\n" +" intercepted by the user agent (e.g. server-side client).<br />\n" +" <strong>Public</strong> - The client can't make confidential\n" +" requests to the GNU MediaGoblin instance (e.g. client-side\n" +" JavaScript client)." +msgstr "" + +#: mediagoblin/plugins/oauth/forms.py:52 +msgid "Redirect URI" +msgstr "" + +#: mediagoblin/plugins/oauth/forms.py:54 +msgid "" +"The redirect URI for the applications, this field\n" +" is <strong>required</strong> for public clients." +msgstr "" + +#: mediagoblin/plugins/oauth/forms.py:66 +msgid "This field is required for public clients" +msgstr "" + +#: mediagoblin/plugins/oauth/views.py:56 +msgid "The client {0} has been registered!" +msgstr "" + +#: mediagoblin/plugins/oauth/templates/oauth/client/connections.html:22 +msgid "OAuth client connections" +msgstr "" + +#: mediagoblin/plugins/oauth/templates/oauth/client/list.html:22 +msgid "Your OAuth clients" +msgstr "" + +#: mediagoblin/plugins/oauth/templates/oauth/client/register.html:29 +#: mediagoblin/templates/mediagoblin/submit/collection.html:30 +#: mediagoblin/templates/mediagoblin/submit/start.html:34 +#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:68 +msgid "Add" +msgstr "Ekle" + +#: mediagoblin/processing/__init__.py:193 +msgid "Invalid file given for media type." +msgstr "Bu medya türü için geçersiz dosya türü." + +#: mediagoblin/submit/forms.py:26 +msgid "File" +msgstr "Dosya" + +#: mediagoblin/submit/views.py:49 +msgid "You must provide a file." +msgstr "Bir dosya sağlamanız gerekir." + +#: mediagoblin/submit/views.py:93 +msgid "Woohoo! Submitted!" +msgstr "Hoooop! Gönderildi!" + +#: mediagoblin/submit/views.py:144 +#, python-format +msgid "Collection \"%s\" added!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/base.html:67 +msgid "Verify your email!" +msgstr "E-postanızı doğrulayın!" + +#: mediagoblin/templates/mediagoblin/base.html:68 +msgid "log out" +msgstr "çıkış" + +#: mediagoblin/templates/mediagoblin/base.html:73 +#: mediagoblin/templates/mediagoblin/auth/login.html:28 +#: mediagoblin/templates/mediagoblin/auth/login.html:36 +#: mediagoblin/templates/mediagoblin/auth/login.html:54 +msgid "Log in" +msgstr "Giriş" + +#: mediagoblin/templates/mediagoblin/base.html:82 +#, python-format +msgid "<a href=\"%(user_url)s\">%(user_name)s</a>'s account" +msgstr "" + +#: mediagoblin/templates/mediagoblin/base.html:89 +msgid "Change account settings" +msgstr "Hesap ayarlarını değiştir" + +#: mediagoblin/templates/mediagoblin/base.html:93 +#: mediagoblin/templates/mediagoblin/base.html:108 +#: mediagoblin/templates/mediagoblin/admin/panel.html:21 +#: mediagoblin/templates/mediagoblin/admin/panel.html:26 +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:21 +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:26 +msgid "Media processing panel" +msgstr "Madya işlem paneli" + +#: mediagoblin/templates/mediagoblin/base.html:96 +msgid "Log out" +msgstr "Çıkış" + +#: mediagoblin/templates/mediagoblin/base.html:99 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:156 +msgid "Add media" +msgstr "Medya ekle" + +#: mediagoblin/templates/mediagoblin/base.html:102 +#: mediagoblin/templates/mediagoblin/user_pages/collection_list.html:41 +msgid "Create new collection" +msgstr "" + +#: mediagoblin/templates/mediagoblin/error.html:24 +msgid "Image of goblin stressing out" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:32 +msgid "Most recent media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/admin/panel.html:29 +msgid "" +"Here you can track the state of media being processed on this instance." +msgstr "" + +#: mediagoblin/templates/mediagoblin/admin/panel.html:32 +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:32 +msgid "Media in-processing" +msgstr "" + +#: mediagoblin/templates/mediagoblin/admin/panel.html:58 +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:56 +msgid "No media in-processing" +msgstr "" + +#: mediagoblin/templates/mediagoblin/admin/panel.html:61 +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:59 +msgid "These uploads failed to process:" +msgstr "" + +#: mediagoblin/templates/mediagoblin/admin/panel.html:90 +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:86 +msgid "No failed entries!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/admin/panel.html:92 +msgid "Last 10 successful uploads" +msgstr "" + +#: mediagoblin/templates/mediagoblin/admin/panel.html:112 +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:107 +msgid "No processed entries, yet!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:28 +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:36 +msgid "Set your new password" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:39 +msgid "Set password" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:23 +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:31 +msgid "Recover password" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:34 +msgid "Send instructions" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 +#, python-format +msgid "" +"Hi %(username)s,\n" +"\n" +"to change your GNU MediaGoblin password, open the following URL in \n" +"your web browser:\n" +"\n" +"%(verification_url)s\n" +"\n" +"If you think this is an error, just ignore this email and continue being\n" +"a happy goblin!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/login.html:39 +msgid "Logging in failed!" +msgstr "Giriş başarısız!" + +#: mediagoblin/templates/mediagoblin/auth/login.html:44 +msgid "Don't have an account yet?" +msgstr "Hala hesabınız yok mu?" + +#: mediagoblin/templates/mediagoblin/auth/login.html:45 +msgid "Create one here!" +msgstr "Şimdi oluşturun!" + +#: mediagoblin/templates/mediagoblin/auth/login.html:51 +msgid "Forgot your password?" +msgstr "Parolanı mı unuttun?" + +#: mediagoblin/templates/mediagoblin/auth/register.html:28 +#: mediagoblin/templates/mediagoblin/auth/register.html:36 +msgid "Create an account!" +msgstr "Hesap oluştur!" + +#: mediagoblin/templates/mediagoblin/auth/register.html:40 +msgid "Create" +msgstr "Oluştur" + +#: mediagoblin/templates/mediagoblin/auth/verification_email.txt:19 +#, python-format +msgid "" +"Hi %(username)s,\n" +"\n" +"to activate your GNU MediaGoblin account, open the following URL in\n" +"your web browser:\n" +"\n" +"%(verification_url)s" +msgstr "Merhaba %(username)s,\n\nGNU MediaGoblin hesabınızı etkinleştirmek için, lütfen aşağıdaki\nURL(bağlantı)'yı Web tarayıcınızda açın:\n\n%(verification_url)s" + +#: mediagoblin/templates/mediagoblin/bits/base_footer.html:21 +#, python-format +msgid "" +"Powered by <a href=\"http://mediagoblin.org/\" title='Version " +"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project." +msgstr "" + +#: mediagoblin/templates/mediagoblin/bits/base_footer.html:24 +#, python-format +msgid "" +"Released under the <a " +"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a " +"href=\"%(source_link)s\">Source code</a> available." +msgstr "" + +#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:20 +msgid "Explore" +msgstr "Keşfet" + +#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:22 +msgid "Hi there, welcome to this MediaGoblin site!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:24 +msgid "" +"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an " +"extraordinarily great piece of media hosting software." +msgstr "" + +#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:25 +msgid "" +"To add your own media, place comments, and more, you can log in with your " +"MediaGoblin account." +msgstr "" + +#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:27 +msgid "Don't have one yet? It's easy!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:28 +#, python-format +msgid "" +"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n" +" or\n" +" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>" +msgstr "" + +#: mediagoblin/templates/mediagoblin/bits/logo.html:23 +#: mediagoblin/themes/airy/templates/mediagoblin/bits/logo.html:23 +msgid "MediaGoblin logo" +msgstr "MediaGoblin logo" + +#: mediagoblin/templates/mediagoblin/edit/attachments.html:23 +#: mediagoblin/templates/mediagoblin/edit/attachments.html:35 +#, python-format +msgid "Editing attachments for %(media_title)s" +msgstr "" + +#: mediagoblin/templates/mediagoblin/edit/attachments.html:44 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:182 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:198 +msgid "Attachments" +msgstr "" + +#: mediagoblin/templates/mediagoblin/edit/attachments.html:57 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:204 +msgid "Add attachment" +msgstr "" + +#: mediagoblin/templates/mediagoblin/edit/attachments.html:61 +#: mediagoblin/templates/mediagoblin/edit/delete_account.html:42 +#: mediagoblin/templates/mediagoblin/edit/edit.html:41 +#: mediagoblin/templates/mediagoblin/edit/edit_collection.html:32 +#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:46 +#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:52 +#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:67 +#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:48 +msgid "Cancel" +msgstr "İptal" + +#: mediagoblin/templates/mediagoblin/edit/attachments.html:63 +#: mediagoblin/templates/mediagoblin/edit/edit.html:42 +#: mediagoblin/templates/mediagoblin/edit/edit_account.html:55 +#: mediagoblin/templates/mediagoblin/edit/edit_collection.html:33 +#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:40 +msgid "Save changes" +msgstr "Değişiklikleri kaydet" + +#: mediagoblin/templates/mediagoblin/edit/change_pass.html:28 +#: mediagoblin/templates/mediagoblin/edit/change_pass.html:38 +#, python-format +msgid "Changing %(username)s's password" +msgstr "" + +#: mediagoblin/templates/mediagoblin/edit/change_pass.html:45 +msgid "Save" +msgstr "Kaydet" + +#: mediagoblin/templates/mediagoblin/edit/delete_account.html:28 +#, python-format +msgid "Really delete user '%(user_name)s' and all related media/comments?" +msgstr "Gerçekten '%(user_name)s' kullanıcısını ve ilgili tüm medya/yorumları silmek istiyor musun?" + +#: mediagoblin/templates/mediagoblin/edit/delete_account.html:35 +msgid "Yes, really delete my account" +msgstr "Evet, gerçekten hesabımı silmek istiyorum" + +#: mediagoblin/templates/mediagoblin/edit/delete_account.html:44 +#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:48 +#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:49 +msgid "Delete permanently" +msgstr "" + +#: mediagoblin/templates/mediagoblin/edit/edit.html:23 +#: mediagoblin/templates/mediagoblin/edit/edit.html:35 +#, python-format +msgid "Editing %(media_title)s" +msgstr "%(media_title)s düzenleme" + +#: mediagoblin/templates/mediagoblin/edit/edit_account.html:28 +#: mediagoblin/templates/mediagoblin/edit/edit_account.html:40 +#, python-format +msgid "Changing %(username)s's account settings" +msgstr "" + +#: mediagoblin/templates/mediagoblin/edit/edit_account.html:46 +msgid "Change your password." +msgstr "Parolanızı değiştirin." + +#: mediagoblin/templates/mediagoblin/edit/edit_account.html:62 +msgid "Delete my account" +msgstr "Hesabımı sil" + +#: mediagoblin/templates/mediagoblin/edit/edit_collection.html:29 +#, python-format +msgid "Editing %(collection_title)s" +msgstr "" + +#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:23 +#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:34 +#, python-format +msgid "Editing %(username)s's profile" +msgstr "%(username)s profilini düzenleme" + +#: mediagoblin/templates/mediagoblin/listings/collection.html:30 +#: mediagoblin/templates/mediagoblin/listings/collection.html:35 +#: mediagoblin/templates/mediagoblin/listings/tag.html:30 +#: mediagoblin/templates/mediagoblin/listings/tag.html:35 +#, python-format +msgid "Media tagged with: %(tag_name)s" +msgstr "" + +#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34 +#: mediagoblin/templates/mediagoblin/media_displays/audio.html:56 +#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:65 +#: mediagoblin/templates/mediagoblin/media_displays/stl.html:136 +#: mediagoblin/templates/mediagoblin/media_displays/video.html:55 +msgid "Download" +msgstr "İndir" + +#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:38 +msgid "Original" +msgstr "Özgün" + +#: mediagoblin/templates/mediagoblin/media_displays/audio.html:44 +msgid "" +"Sorry, this audio will not work because \n" +"\tyour web browser does not support HTML5 \n" +"\taudio." +msgstr "" + +#: mediagoblin/templates/mediagoblin/media_displays/audio.html:47 +msgid "" +"You can get a modern web browser that \n" +"\tcan play the audio at <a href=\"http://getfirefox.com\">\n" +"\t http://getfirefox.com</a>!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/media_displays/audio.html:60 +#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:71 +#: mediagoblin/templates/mediagoblin/media_displays/video.html:61 +msgid "Original file" +msgstr "Özgün dosya" + +#: mediagoblin/templates/mediagoblin/media_displays/audio.html:63 +msgid "WebM file (Vorbis codec)" +msgstr "" + +#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:59 +#: mediagoblin/templates/mediagoblin/media_displays/stl.html:87 +#: mediagoblin/templates/mediagoblin/media_displays/stl.html:93 +#: mediagoblin/templates/mediagoblin/media_displays/stl.html:99 +#: mediagoblin/templates/mediagoblin/media_displays/stl.html:105 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:59 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:65 +#, python-format +msgid "Image for %(media_title)s" +msgstr "" + +#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:79 +msgid "PDF file" +msgstr "PDF dosya" + +#: mediagoblin/templates/mediagoblin/media_displays/stl.html:112 +msgid "Toggle Rotate" +msgstr "" + +#: mediagoblin/templates/mediagoblin/media_displays/stl.html:113 +msgid "Perspective" +msgstr "" + +#: mediagoblin/templates/mediagoblin/media_displays/stl.html:116 +#: mediagoblin/templates/mediagoblin/media_displays/stl.html:117 +msgid "Front" +msgstr "" + +#: mediagoblin/templates/mediagoblin/media_displays/stl.html:120 +#: mediagoblin/templates/mediagoblin/media_displays/stl.html:121 +msgid "Top" +msgstr "" + +#: mediagoblin/templates/mediagoblin/media_displays/stl.html:124 +#: mediagoblin/templates/mediagoblin/media_displays/stl.html:125 +msgid "Side" +msgstr "" + +#: mediagoblin/templates/mediagoblin/media_displays/stl.html:130 +#: mediagoblin/templates/mediagoblin/media_displays/stl.html:131 +msgid "WebGL" +msgstr "WebGL" + +#: mediagoblin/templates/mediagoblin/media_displays/stl.html:138 +msgid "Download model" +msgstr "" + +#: mediagoblin/templates/mediagoblin/media_displays/stl.html:146 +msgid "File Format" +msgstr "Dosya Biçimi" + +#: mediagoblin/templates/mediagoblin/media_displays/stl.html:148 +msgid "Object Height" +msgstr "" + +#: mediagoblin/templates/mediagoblin/media_displays/video.html:44 +msgid "" +"Sorry, this video will not work because\n" +" your web browser does not support HTML5 \n" +" video." +msgstr "" + +#: mediagoblin/templates/mediagoblin/media_displays/video.html:47 +msgid "" +"You can get a modern web browser that \n" +" can play this video at <a href=\"http://getfirefox.com\">\n" +" http://getfirefox.com</a>!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/media_displays/video.html:69 +msgid "WebM file (640p; VP8/Vorbis)" +msgstr "" + +#: mediagoblin/templates/mediagoblin/submit/collection.html:26 +msgid "Add a collection" +msgstr "" + +#: mediagoblin/templates/mediagoblin/submit/start.html:23 +#: mediagoblin/templates/mediagoblin/submit/start.html:30 +msgid "Add your media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/collection.html:30 +#, python-format +msgid "%(collection_title)s (%(username)s's collection)" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/collection.html:39 +#, python-format +msgid "%(collection_title)s by <a href=\"%(user_url)s\">%(username)s</a>" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/collection.html:52 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:79 +msgid "Edit" +msgstr "Düzenle" + +#: mediagoblin/templates/mediagoblin/user_pages/collection.html:56 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:83 +msgid "Delete" +msgstr "Si" + +#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:30 +#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 +#, python-format +msgid "Really delete %(title)s?" +msgstr "Gerçekten %(title)s silmek istiyor musun?" + +#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:31 +#, python-format +msgid "Really remove %(media_title)s from %(collection_title)s?" +msgstr "Gerçekten %(collection_title)s %(media_title)s kaldırmak istiyor musun?" + +#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:54 +msgid "Remove" +msgstr "Kaldır" + +#: mediagoblin/templates/mediagoblin/user_pages/collection_list.html:21 +#, python-format +msgid "%(username)s's collections" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/collection_list.html:28 +#, python-format +msgid "<a href=\"%(user_url)s\">%(username)s</a>'s collections" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/comment_email.txt:19 +#, python-format +msgid "" +"Hi %(username)s,\n" +"%(comment_author)s commented on your post (%(comment_url)s) at %(instance_name)s\n" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 +#, python-format +msgid "%(username)s's media" +msgstr "%(username)s medyası" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:38 +#, python-format +msgid "" +"<a href=\"%(user_url)s\">%(username)s</a>'s media with tag <a " +"href=\"%(tag_url)s\">%(tag)s</a>" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:48 +#, python-format +msgid "<a href=\"%(user_url)s\">%(username)s</a>'s media" +msgstr "<a href=\"%(user_url)s\">%(username)s</a> medyası" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:38 +#, python-format +msgid "❖ Browsing media by <a href=\"%(user_url)s\">%(username)s</a>" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:95 +msgid "Add a comment" +msgstr "Bir yorum ekle" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:104 +msgid "Add this comment" +msgstr "Bu yorumu ekle" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:132 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:152 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:164 +#, python-format +msgid "%(formatted_time)s ago" +msgstr "%(formatted_time)s önce" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:150 +msgid "Added" +msgstr "Eklendi" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:161 +msgid "Created" +msgstr "Oluşturuldu" + +#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:28 +#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:40 +#, python-format +msgid "Add “%(media_title)s” to a collection" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:54 +msgid "+" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:58 +msgid "Add a new collection" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:29 +msgid "" +"You can track the state of media being processed for your gallery here." +msgstr "Burada galerinizdeki işlenmekte olan medyanın durumunu takip edebilirsiniz." + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:89 +msgid "Your last 10 successful uploads" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:31 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:89 +#, python-format +msgid "%(username)s's profile" +msgstr "%(username)s profili" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:43 +msgid "Sorry, no such user found." +msgstr "Üzgünüz, böyle bir kullanıcı bulunamadı." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:50 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:70 +msgid "Email verification needed" +msgstr "E-posta doğrulaması gerekli" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:53 +msgid "Almost done! Your account still needs to be activated." +msgstr "Neredeyse bitti! Hesabınızı etkinleştirmeniz gerekiyor." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:58 +msgid "" +"An email should arrive in a few moments with instructions on how to do so." +msgstr "Bunun nasıl yapılacağı ile ilgili talimatlar, birkaç dakika içinde size e-posta ulaşacak." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 +msgid "In case it doesn't:" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:65 +msgid "Resend verification email" +msgstr "Doğrulama e-postası tekrar yolla" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:73 +msgid "" +"Someone has registered an account with this username, but it still has to be" +" activated." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:79 +#, python-format +msgid "" +"If you are that person but you've lost your verification email, you can <a " +"href=\"%(login_url)s\">log in</a> and resend it." +msgstr "Doğrulama e-postasını kaybettiyseniz, <a href=\"%(login_url)s\">giriş</a> yapabilir ve yeniden yollayabilirsiniz." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 +msgid "Here's a spot to tell others about yourself." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:100 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:117 +msgid "Edit profile" +msgstr "Profil düzenle" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:105 +msgid "This user hasn't filled in their profile (yet)." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:124 +msgid "Browse collections" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:137 +#, python-format +msgid "View all of %(username)s's media" +msgstr "%(username)s tüm medyasını göster" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:150 +msgid "" +"This is where your media will appear, but you don't seem to have added " +"anything yet." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:162 +#: mediagoblin/templates/mediagoblin/utils/collection_gallery.html:84 +#: mediagoblin/templates/mediagoblin/utils/object_gallery.html:70 +msgid "There doesn't seem to be any media here yet..." +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/collection_gallery.html:49 +msgid "(remove)" +msgstr "(kaldır)" + +#: mediagoblin/templates/mediagoblin/utils/collections.html:21 +msgid "Collected in" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/collections.html:40 +msgid "Add to a collection" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/feed_link.html:21 +#: mediagoblin/themes/airy/templates/mediagoblin/utils/feed_link.html:21 +msgid "feed icon" +msgstr "besleme simgesi" + +#: mediagoblin/templates/mediagoblin/utils/feed_link.html:23 +#: mediagoblin/themes/airy/templates/mediagoblin/utils/feed_link.html:23 +msgid "Atom feed" +msgstr "Atom besleme" + +#: mediagoblin/templates/mediagoblin/utils/license.html:25 +msgid "All rights reserved" +msgstr "Tüm hakları saklıdır" + +#: mediagoblin/templates/mediagoblin/utils/pagination.html:39 +msgid "← Newer" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/pagination.html:45 +msgid "Older →" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/pagination.html:48 +msgid "Go to page:" +msgstr "Sayfaya git:" + +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:28 +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:33 +msgid "newer" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:39 +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:44 +msgid "older" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/tags.html:20 +msgid "Tagged with" +msgstr "" + +#: mediagoblin/tools/exif.py:83 +msgid "Could not read the image file." +msgstr "" + +#: mediagoblin/tools/response.py:35 +msgid "Oops!" +msgstr "Amaninnn boo!" + +#: mediagoblin/tools/response.py:36 +msgid "An error occured" +msgstr "" + +#: mediagoblin/tools/response.py:51 +msgid "Operation not allowed" +msgstr "" + +#: mediagoblin/tools/response.py:52 +msgid "" +"Sorry Dave, I can't let you do that!</p><p>You have tried to perform a " +"function that you are not allowed to. Have you been trying to delete all " +"user accounts again?" +msgstr "" + +#: mediagoblin/tools/response.py:60 +msgid "" +"There doesn't seem to be a page at this address. Sorry!</p><p>If you're sure" +" the address is correct, maybe the page you're looking for has been moved or" +" deleted." +msgstr "" + +#: mediagoblin/tools/timesince.py:62 +msgid "year" +msgstr "yıl" + +#: mediagoblin/tools/timesince.py:63 +msgid "month" +msgstr "ay" + +#: mediagoblin/tools/timesince.py:64 +msgid "week" +msgstr "hafta" + +#: mediagoblin/tools/timesince.py:65 +msgid "day" +msgstr "gün" + +#: mediagoblin/tools/timesince.py:66 +msgid "hour" +msgstr "saat" + +#: mediagoblin/tools/timesince.py:67 +msgid "minute" +msgstr "dakika" + +#: mediagoblin/user_pages/forms.py:23 +msgid "Comment" +msgstr "" + +#: mediagoblin/user_pages/forms.py:25 +msgid "" +"You can use <a " +"href=\"http://daringfireball.net/projects/markdown/basics\">Markdown</a> for" +" formatting." +msgstr "" + +#: mediagoblin/user_pages/forms.py:31 +msgid "I am sure I want to delete this" +msgstr "Bunu silmek için eminim" + +#: mediagoblin/user_pages/forms.py:35 +msgid "I am sure I want to remove this item from the collection" +msgstr "" + +#: mediagoblin/user_pages/forms.py:39 +msgid "Collection" +msgstr "" + +#: mediagoblin/user_pages/forms.py:40 +msgid "-- Select --" +msgstr "" + +#: mediagoblin/user_pages/forms.py:42 +msgid "Include a note" +msgstr "" + +#: mediagoblin/user_pages/lib.py:58 +msgid "commented on your post" +msgstr "" + +#: mediagoblin/user_pages/views.py:169 +msgid "Sorry, comments are disabled." +msgstr "Maalesef, yorum devre dışı." + +#: mediagoblin/user_pages/views.py:174 +msgid "Oops, your comment was empty." +msgstr "Amaninnn boo, yorumunuz boştu." + +#: mediagoblin/user_pages/views.py:180 +msgid "Your comment has been posted!" +msgstr "Yorumunuz gönderildi!" + +#: mediagoblin/user_pages/views.py:205 +msgid "Please check your entries and try again." +msgstr "" + +#: mediagoblin/user_pages/views.py:245 +msgid "You have to select or add a collection" +msgstr "" + +#: mediagoblin/user_pages/views.py:256 +#, python-format +msgid "\"%s\" already in collection \"%s\"" +msgstr "" + +#: mediagoblin/user_pages/views.py:262 +#, python-format +msgid "\"%s\" added to collection \"%s\"" +msgstr "" + +#: mediagoblin/user_pages/views.py:282 +msgid "You deleted the media." +msgstr "Medyayı sildiniz." + +#: mediagoblin/user_pages/views.py:289 +msgid "The media was not deleted because you didn't check that you were sure." +msgstr "Medya silinmedi çünkü emin olduğunuzu onaylamadınız." + +#: mediagoblin/user_pages/views.py:296 +msgid "You are about to delete another user's media. Proceed with caution." +msgstr "Başka bir kullanıcının medyasını silerken dikkatli davranın." + +#: mediagoblin/user_pages/views.py:370 +msgid "You deleted the item from the collection." +msgstr "" + +#: mediagoblin/user_pages/views.py:374 +msgid "The item was not removed because you didn't check that you were sure." +msgstr "" + +#: mediagoblin/user_pages/views.py:382 +msgid "" +"You are about to delete an item from another user's collection. Proceed with" +" caution." +msgstr "" + +#: mediagoblin/user_pages/views.py:415 +#, python-format +msgid "You deleted the collection \"%s\"" +msgstr "" + +#: mediagoblin/user_pages/views.py:422 +msgid "" +"The collection was not deleted because you didn't check that you were sure." +msgstr "" + +#: mediagoblin/user_pages/views.py:430 +msgid "" +"You are about to delete another user's collection. Proceed with caution." +msgstr "" diff --git a/mediagoblin/i18n/zh_CN/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/zh_CN/LC_MESSAGES/mediagoblin.mo Binary files differnew file mode 100644 index 00000000..1ed5a4f1 --- /dev/null +++ b/mediagoblin/i18n/zh_CN/LC_MESSAGES/mediagoblin.mo diff --git a/mediagoblin/i18n/zh_CN/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/zh_CN/LC_MESSAGES/mediagoblin.po new file mode 100644 index 00000000..4bb714fe --- /dev/null +++ b/mediagoblin/i18n/zh_CN/LC_MESSAGES/mediagoblin.po @@ -0,0 +1,1256 @@ +# Translations template for PROJECT. +# Copyright (C) 2013 ORGANIZATION +# This file is distributed under the same license as the PROJECT project. +# +# Translators: +# <chc@citi.sinica.edu.tw>, 2011 +# cwebber <cwebber@dustycloud.org>, 2013 +# m13253 <m13253@hotmail.com>, 2013 +# medicalwei <medicalwei@gmail.com>, 2012 +# m13253 <m13253@hotmail.com>, 2013 +msgid "" +msgstr "" +"Project-Id-Version: GNU MediaGoblin\n" +"Report-Msgid-Bugs-To: http://issues.mediagoblin.org/\n" +"POT-Creation-Date: 2013-05-27 13:54-0500\n" +"PO-Revision-Date: 2013-06-16 11:06+0000\n" +"Last-Translator: m13253 <m13253@hotmail.com>\n" +"Language-Team: Chinese (China) (http://www.transifex.com/projects/p/mediagoblin/language/zh_CN/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 0.9.6\n" +"Language: zh_CN\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#: mediagoblin/auth/forms.py:26 +msgid "Username" +msgstr "用户名" + +#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:45 +#: mediagoblin/tests/test_util.py:110 +msgid "Password" +msgstr "密码" + +#: mediagoblin/auth/forms.py:34 +msgid "Email address" +msgstr "电子邮件地址" + +#: mediagoblin/auth/forms.py:41 +msgid "Username or Email" +msgstr "用户名或电子邮件" + +#: mediagoblin/auth/forms.py:52 +msgid "Username or email" +msgstr "用户名或电子邮件" + +#: mediagoblin/auth/tools.py:31 +msgid "Invalid User name or email address." +msgstr "无效用户名或电子邮件地址。" + +#: mediagoblin/auth/tools.py:32 +msgid "This field does not take email addresses." +msgstr "此字段不能填写电子邮件地址。" + +#: mediagoblin/auth/tools.py:33 +msgid "This field requires an email address." +msgstr "此字段需填写电子邮件地址。" + +#: mediagoblin/auth/views.py:54 +msgid "Sorry, registration is disabled on this instance." +msgstr "抱歉,本站已暂停注册。" + +#: mediagoblin/auth/views.py:68 +msgid "Sorry, a user with that name already exists." +msgstr "抱歉,该用户名已存在。" + +#: mediagoblin/auth/views.py:72 +msgid "Sorry, a user with that email address already exists." +msgstr "抱歉,已有用户用该电子邮件注册。" + +#: mediagoblin/auth/views.py:182 +msgid "" +"Your email address has been verified. You may now login, edit your profile, " +"and submit images!" +msgstr "您的电子邮件地址已认证。您现在可以登录、修改个人资料并上传图片了!" + +#: mediagoblin/auth/views.py:188 +msgid "The verification key or user id is incorrect" +msgstr "验证码错误或用户 ID 错误" + +#: mediagoblin/auth/views.py:206 +msgid "You must be logged in so we know who to send the email to!" +msgstr "您必须登录以便让我们知道将电子邮件发给谁" + +#: mediagoblin/auth/views.py:214 +msgid "You've already verified your email address!" +msgstr "您已经认证过电子邮件地址了!" + +#: mediagoblin/auth/views.py:227 +msgid "Resent your verification email." +msgstr "重发认证邮件。" + +#: mediagoblin/auth/views.py:258 +msgid "" +"If that email address (case sensitive!) is registered an email has been sent" +" with instructions on how to change your password." +msgstr "若该邮件地址(区分大小写)已被注册,则密码修改说明已通过电子邮件送达。" + +#: mediagoblin/auth/views.py:269 +msgid "Couldn't find someone with that username." +msgstr "找不到有该用户名的人。" + +#: mediagoblin/auth/views.py:272 +msgid "" +"An email has been sent with instructions on how to change your password." +msgstr "密码修改说明已通过电子邮件送达。" + +#: mediagoblin/auth/views.py:279 +msgid "" +"Could not send password recovery email as your username is inactive or your " +"account's email address has not been verified." +msgstr "无法发送密码找回邮件,因为您的用户名未激活或者您账户的电子邮件地址未认证。" + +#: mediagoblin/auth/views.py:336 +msgid "You can now log in using your new password." +msgstr "您现在可以用新的密码来登录了!" + +#: mediagoblin/edit/forms.py:25 mediagoblin/edit/forms.py:82 +#: mediagoblin/submit/forms.py:28 mediagoblin/submit/forms.py:47 +#: mediagoblin/user_pages/forms.py:45 +msgid "Title" +msgstr "标题" + +#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 +msgid "Description of this work" +msgstr "该作品的描述" + +#: mediagoblin/edit/forms.py:29 mediagoblin/edit/forms.py:52 +#: mediagoblin/edit/forms.py:86 mediagoblin/submit/forms.py:32 +#: mediagoblin/submit/forms.py:51 mediagoblin/user_pages/forms.py:49 +msgid "" +"You can use\n" +" <a href=\"http://daringfireball.net/projects/markdown/basics\">\n" +" Markdown</a> for formatting." +msgstr "您可以用 <a href=\"http://wowubuntu.com/markdown/\">Markdown</a> 来排版。" + +#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:36 +msgid "Tags" +msgstr "标签" + +#: mediagoblin/edit/forms.py:35 mediagoblin/submit/forms.py:38 +msgid "Separate tags by commas." +msgstr "用逗号分隔标签。" + +#: mediagoblin/edit/forms.py:38 mediagoblin/edit/forms.py:90 +msgid "Slug" +msgstr "简称" + +#: mediagoblin/edit/forms.py:39 mediagoblin/edit/forms.py:91 +msgid "The slug can't be empty" +msgstr "简称不能为空" + +#: mediagoblin/edit/forms.py:40 +msgid "" +"The title part of this media's address. You usually don't need to change " +"this." +msgstr "该媒体网址的标题部份。通常不需要修改。" + +#: mediagoblin/edit/forms.py:44 mediagoblin/submit/forms.py:41 +#: mediagoblin/templates/mediagoblin/utils/license.html:20 +msgid "License" +msgstr "许可证" + +#: mediagoblin/edit/forms.py:50 +msgid "Bio" +msgstr "个性签名" + +#: mediagoblin/edit/forms.py:56 +msgid "Website" +msgstr "网站" + +#: mediagoblin/edit/forms.py:58 +msgid "This address contains errors" +msgstr "本网址出错了" + +#: mediagoblin/edit/forms.py:63 +msgid "License preference" +msgstr "许可证偏好" + +#: mediagoblin/edit/forms.py:69 +msgid "This will be your default license on upload forms." +msgstr "这将是您上传界面的默认许可证。" + +#: mediagoblin/edit/forms.py:71 +msgid "Email me when others comment on my media" +msgstr "当有人对我的媒体评论时给我电子邮件" + +#: mediagoblin/edit/forms.py:83 +msgid "The title can't be empty" +msgstr "标题不能是空的" + +#: mediagoblin/edit/forms.py:85 mediagoblin/submit/forms.py:50 +#: mediagoblin/user_pages/forms.py:48 +msgid "Description of this collection" +msgstr "这个合集的描述" + +#: mediagoblin/edit/forms.py:92 +msgid "" +"The title part of this collection's address. You usually don't need to " +"change this." +msgstr "此合集网址的标题部份,通常不需要修改。" + +#: mediagoblin/edit/forms.py:99 +msgid "Old password" +msgstr "旧的密码" + +#: mediagoblin/edit/forms.py:101 +msgid "Enter your old password to prove you own this account." +msgstr "输入您的旧密码来证明您拥有这个账户。" + +#: mediagoblin/edit/forms.py:104 +msgid "New password" +msgstr "新密码" + +#: mediagoblin/edit/views.py:67 +msgid "An entry with that slug already exists for this user." +msgstr "这个简称已经被别人用了" + +#: mediagoblin/edit/views.py:85 +msgid "You are editing another user's media. Proceed with caution." +msgstr "您正在修改别人的媒体,请小心操作。" + +#: mediagoblin/edit/views.py:155 +#, python-format +msgid "You added the attachment %s!" +msgstr "您加上了附件“%s”!" + +#: mediagoblin/edit/views.py:182 +msgid "You can only edit your own profile." +msgstr "您只能修改自己的个人资料" + +#: mediagoblin/edit/views.py:188 +msgid "You are editing a user's profile. Proceed with caution." +msgstr "您正在修改别人的个人资料,请小心操作。" + +#: mediagoblin/edit/views.py:204 +msgid "Profile changes saved" +msgstr "个人资料已修改" + +#: mediagoblin/edit/views.py:240 +msgid "Account settings saved" +msgstr "账户设置已保存" + +#: mediagoblin/edit/views.py:274 +msgid "You need to confirm the deletion of your account." +msgstr "您需要确认删除您的账户。" + +#: mediagoblin/edit/views.py:310 mediagoblin/submit/views.py:138 +#: mediagoblin/user_pages/views.py:222 +#, python-format +msgid "You already have a collection called \"%s\"!" +msgstr "您已经有一个称做“%s”的合集了!" + +#: mediagoblin/edit/views.py:314 +msgid "A collection with that slug already exists for this user." +msgstr "该用户已经有使用该简称的合集了。" + +#: mediagoblin/edit/views.py:329 +msgid "You are editing another user's collection. Proceed with caution." +msgstr "您正在修改别人的合集,请小心操作。" + +#: mediagoblin/edit/views.py:348 +msgid "Wrong password" +msgstr "密码错误" + +#: mediagoblin/edit/views.py:363 +msgid "Your password was changed successfully" +msgstr "您的密码已成功修改" + +#: mediagoblin/gmg_commands/assetlink.py:60 +msgid "Cannot link theme... no theme set\n" +msgstr "无法链接到主题……未设置主题\n" + +#: mediagoblin/gmg_commands/assetlink.py:73 +msgid "No asset directory for this theme\n" +msgstr "此主题没有素材目录\n" + +#: mediagoblin/gmg_commands/assetlink.py:76 +msgid "However, old link directory symlink found; removed.\n" +msgstr "但是旧的目录链接已经找到并移除。\n" + +#: mediagoblin/gmg_commands/assetlink.py:112 +#, python-format +msgid "Could not link \"%s\": %s exists and is not a symlink\n" +msgstr "无法链接到“%s”:“%s”已存在且不是链接\n" + +#: mediagoblin/gmg_commands/assetlink.py:119 +#, python-format +msgid "Skipping \"%s\"; already set up.\n" +msgstr "跳过“%s”;已设置过了。\n" + +#: mediagoblin/gmg_commands/assetlink.py:124 +#, python-format +msgid "Old link found for \"%s\"; removing.\n" +msgstr "“%s”的旧链接已经找到并移除。\n" + +#: mediagoblin/meddleware/csrf.py:134 +msgid "" +"CSRF cookie not present. This is most likely the result of a cookie blocker " +"or somesuch.<br/>Make sure to permit the settings of cookies for this " +"domain." +msgstr "CSRF cookie 不存在。很可能是由类似 cookie 屏蔽器造成的。<br />请允许本域名的 cookie 设定。" + +#: mediagoblin/media_types/__init__.py:111 +#: mediagoblin/media_types/__init__.py:155 +msgid "Sorry, I don't support that file type :(" +msgstr "抱歉,我不支持这样的文件格式 :(" + +#: mediagoblin/media_types/pdf/processing.py:136 +msgid "unoconv failing to run, check log file" +msgstr "无法运行 unoconv,请检查日志" + +#: mediagoblin/media_types/video/processing.py:37 +msgid "Video transcoding failed" +msgstr "视频转码失败" + +#: mediagoblin/plugins/geolocation/templates/mediagoblin/plugins/geolocation/map.html:24 +msgid "Location" +msgstr "位置" + +#: mediagoblin/plugins/geolocation/templates/mediagoblin/plugins/geolocation/map.html:52 +#, python-format +msgid "View on <a href=\"%(osm_url)s\">OpenStreetMap</a>" +msgstr "在 <a href=\"%(osm_url)s\">OpenStreetMap</a> 上观看" + +#: mediagoblin/plugins/oauth/forms.py:29 +msgid "Allow" +msgstr "允许" + +#: mediagoblin/plugins/oauth/forms.py:30 +msgid "Deny" +msgstr "拒绝" + +#: mediagoblin/plugins/oauth/forms.py:34 +msgid "Name" +msgstr "名称" + +#: mediagoblin/plugins/oauth/forms.py:35 +msgid "The name of the OAuth client" +msgstr "OAuth client 的名称" + +#: mediagoblin/plugins/oauth/forms.py:36 +msgid "Description" +msgstr "描述" + +#: mediagoblin/plugins/oauth/forms.py:38 +msgid "" +"This will be visible to users allowing your\n" +" application to authenticate as them." +msgstr "本描述将会被进行应用程序认证的用户看到。" + +#: mediagoblin/plugins/oauth/forms.py:40 +msgid "Type" +msgstr "类型" + +#: mediagoblin/plugins/oauth/forms.py:45 +msgid "" +"<strong>Confidential</strong> - The client can\n" +" make requests to the GNU MediaGoblin instance that can not be\n" +" intercepted by the user agent (e.g. server-side client).<br />\n" +" <strong>Public</strong> - The client can't make confidential\n" +" requests to the GNU MediaGoblin instance (e.g. client-side\n" +" JavaScript client)." +msgstr "<strong>秘密</strong> — OAuth client 可以对 GNU MediaGoblin 站点发送不被用户代理拦截的请求(例如服务端上的 client)。\n<strong>公开</strong> — OAuth client 无法对 GNU MediaGoblin 站点发送秘密的请求(例如客户端的 JavaScript client)。" + +#: mediagoblin/plugins/oauth/forms.py:52 +msgid "Redirect URI" +msgstr "重定向 URI" + +#: mediagoblin/plugins/oauth/forms.py:54 +msgid "" +"The redirect URI for the applications, this field\n" +" is <strong>required</strong> for public clients." +msgstr "此应用程序的重定向 URI,本字段在公开类型的 OAuth client 为<strong>必填</strong>。" + +#: mediagoblin/plugins/oauth/forms.py:66 +msgid "This field is required for public clients" +msgstr "本字段在公开类型的 OAuth client 为必填" + +#: mediagoblin/plugins/oauth/views.py:56 +msgid "The client {0} has been registered!" +msgstr "OAuth client {0} 注册完成!" + +#: mediagoblin/plugins/oauth/templates/oauth/client/connections.html:22 +msgid "OAuth client connections" +msgstr "OAuth client 连接" + +#: mediagoblin/plugins/oauth/templates/oauth/client/list.html:22 +msgid "Your OAuth clients" +msgstr "您的 OAuth client" + +#: mediagoblin/plugins/oauth/templates/oauth/client/register.html:29 +#: mediagoblin/templates/mediagoblin/submit/collection.html:30 +#: mediagoblin/templates/mediagoblin/submit/start.html:34 +#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:68 +msgid "Add" +msgstr "增加" + +#: mediagoblin/processing/__init__.py:193 +msgid "Invalid file given for media type." +msgstr "提供文件的媒体类型错误。" + +#: mediagoblin/submit/forms.py:26 +msgid "File" +msgstr "文件" + +#: mediagoblin/submit/views.py:49 +msgid "You must provide a file." +msgstr "您必须提供一个文件" + +#: mediagoblin/submit/views.py:93 +msgid "Woohoo! Submitted!" +msgstr "啊哈!已提交!" + +#: mediagoblin/submit/views.py:144 +#, python-format +msgid "Collection \"%s\" added!" +msgstr "合集“%s”已新增!" + +#: mediagoblin/templates/mediagoblin/base.html:67 +msgid "Verify your email!" +msgstr "确认您的电子邮件!" + +#: mediagoblin/templates/mediagoblin/base.html:68 +msgid "log out" +msgstr "登出" + +#: mediagoblin/templates/mediagoblin/base.html:73 +#: mediagoblin/templates/mediagoblin/auth/login.html:28 +#: mediagoblin/templates/mediagoblin/auth/login.html:36 +#: mediagoblin/templates/mediagoblin/auth/login.html:54 +msgid "Log in" +msgstr "登录" + +#: mediagoblin/templates/mediagoblin/base.html:82 +#, python-format +msgid "<a href=\"%(user_url)s\">%(user_name)s</a>'s account" +msgstr "<a href=\"%(user_url)s\">%(user_name)s</a> 的账户" + +#: mediagoblin/templates/mediagoblin/base.html:89 +msgid "Change account settings" +msgstr "更改账户设置" + +#: mediagoblin/templates/mediagoblin/base.html:93 +#: mediagoblin/templates/mediagoblin/base.html:108 +#: mediagoblin/templates/mediagoblin/admin/panel.html:21 +#: mediagoblin/templates/mediagoblin/admin/panel.html:26 +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:21 +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:26 +msgid "Media processing panel" +msgstr "媒体处理面板" + +#: mediagoblin/templates/mediagoblin/base.html:96 +msgid "Log out" +msgstr "登出" + +#: mediagoblin/templates/mediagoblin/base.html:99 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:156 +msgid "Add media" +msgstr "新增媒体" + +#: mediagoblin/templates/mediagoblin/base.html:102 +#: mediagoblin/templates/mediagoblin/user_pages/collection_list.html:41 +msgid "Create new collection" +msgstr "新增合集" + +#: mediagoblin/templates/mediagoblin/error.html:24 +msgid "Image of goblin stressing out" +msgstr "满脸问号的哥布林" + +#: mediagoblin/templates/mediagoblin/root.html:32 +msgid "Most recent media" +msgstr "最新的媒体" + +#: mediagoblin/templates/mediagoblin/admin/panel.html:29 +msgid "" +"Here you can track the state of media being processed on this instance." +msgstr "此处您可以追踪本站点处理媒体的状态。" + +#: mediagoblin/templates/mediagoblin/admin/panel.html:32 +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:32 +msgid "Media in-processing" +msgstr "媒体处理中" + +#: mediagoblin/templates/mediagoblin/admin/panel.html:58 +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:56 +msgid "No media in-processing" +msgstr "没有正在处理中的媒体" + +#: mediagoblin/templates/mediagoblin/admin/panel.html:61 +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:59 +msgid "These uploads failed to process:" +msgstr "无法处理这些上传内容:" + +#: mediagoblin/templates/mediagoblin/admin/panel.html:90 +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:86 +msgid "No failed entries!" +msgstr "没有失败的纪录!" + +#: mediagoblin/templates/mediagoblin/admin/panel.html:92 +msgid "Last 10 successful uploads" +msgstr "最近 10 次成功上传的纪录" + +#: mediagoblin/templates/mediagoblin/admin/panel.html:112 +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:107 +msgid "No processed entries, yet!" +msgstr "现在还没有处理的纪录!" + +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:28 +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:36 +msgid "Set your new password" +msgstr "设置您的新密码" + +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:39 +msgid "Set password" +msgstr "设置新密码" + +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:23 +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:31 +msgid "Recover password" +msgstr "找回密码" + +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:34 +msgid "Send instructions" +msgstr "发送找回密码说明" + +#: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 +#, python-format +msgid "" +"Hi %(username)s,\n" +"\n" +"to change your GNU MediaGoblin password, open the following URL in \n" +"your web browser:\n" +"\n" +"%(verification_url)s\n" +"\n" +"If you think this is an error, just ignore this email and continue being\n" +"a happy goblin!" +msgstr "%(username)s 您好:\n\n要修改 GNU MediaGoblin 的密码,请在您的浏览器中打开下面的网址:\n\n%(verification_url)s\n\n如果您认为这个是个误会,请忽略此封信件,继续当个快乐的哥布林!" + +#: mediagoblin/templates/mediagoblin/auth/login.html:39 +msgid "Logging in failed!" +msgstr "登录失败!" + +#: mediagoblin/templates/mediagoblin/auth/login.html:44 +msgid "Don't have an account yet?" +msgstr "还没有账户吗?" + +#: mediagoblin/templates/mediagoblin/auth/login.html:45 +msgid "Create one here!" +msgstr "在这里建立一个吧!" + +#: mediagoblin/templates/mediagoblin/auth/login.html:51 +msgid "Forgot your password?" +msgstr "忘了密码吗?" + +#: mediagoblin/templates/mediagoblin/auth/register.html:28 +#: mediagoblin/templates/mediagoblin/auth/register.html:36 +msgid "Create an account!" +msgstr "建立一个账户!" + +#: mediagoblin/templates/mediagoblin/auth/register.html:40 +msgid "Create" +msgstr "建立" + +#: mediagoblin/templates/mediagoblin/auth/verification_email.txt:19 +#, python-format +msgid "" +"Hi %(username)s,\n" +"\n" +"to activate your GNU MediaGoblin account, open the following URL in\n" +"your web browser:\n" +"\n" +"%(verification_url)s" +msgstr "%(username)s 您好:\n\n要启动 GNU MediaGoblin 账户,请在您的浏览器中打开下面的网址:\n\n%(verification_url)s" + +#: mediagoblin/templates/mediagoblin/bits/base_footer.html:21 +#, python-format +msgid "" +"Powered by <a href=\"http://mediagoblin.org/\" title='Version " +"%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project." +msgstr "Powered by <a href=\"http://mediagoblin.org/\" title='Version %(version)s'>MediaGoblin</a>,一个 <a href=\"http://gnu.org/\">GNU</a> 项目。" + +#: mediagoblin/templates/mediagoblin/bits/base_footer.html:24 +#, python-format +msgid "" +"Released under the <a " +"href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a>. <a " +"href=\"%(source_link)s\">Source code</a> available." +msgstr "以 <a href=\"http://www.fsf.org/licensing/licenses/agpl-3.0.html\">AGPL</a> 授权发布。备有<a href=\"%(source_link)s\">源代码</a>。" + +#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:20 +msgid "Explore" +msgstr "探索" + +#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:22 +msgid "Hi there, welcome to this MediaGoblin site!" +msgstr "嘿!欢迎来到 MediaGoblin 站! " + +#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:24 +msgid "" +"This site is running <a href=\"http://mediagoblin.org\">MediaGoblin</a>, an " +"extraordinarily great piece of media hosting software." +msgstr "本站使用 <a href=\"http://mediagoblin.org\">MediaGoblin</a>——与众不同的媒体分享网站。" + +#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:25 +msgid "" +"To add your own media, place comments, and more, you can log in with your " +"MediaGoblin account." +msgstr "您可以登录您的 MediaGoblin 账户以上传媒体、张贴评论等等。" + +#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:27 +msgid "Don't have one yet? It's easy!" +msgstr "没有账户吗?开账户很简单!" + +#: mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html:28 +#, python-format +msgid "" +"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n" +" or\n" +" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>" +msgstr "<a class=\"button_action_highlight\" href=\"%(register_url)s\">在本站创建帐户</a>\n 或者\n <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">在您自己的服务器上搭建 MediaGoblin</a>" + +#: mediagoblin/templates/mediagoblin/bits/logo.html:23 +#: mediagoblin/themes/airy/templates/mediagoblin/bits/logo.html:23 +msgid "MediaGoblin logo" +msgstr "MediaGoblin 标志" + +#: mediagoblin/templates/mediagoblin/edit/attachments.html:23 +#: mediagoblin/templates/mediagoblin/edit/attachments.html:35 +#, python-format +msgid "Editing attachments for %(media_title)s" +msgstr "编辑 %(media_title)s 的附件" + +#: mediagoblin/templates/mediagoblin/edit/attachments.html:44 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:182 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:198 +msgid "Attachments" +msgstr "附件" + +#: mediagoblin/templates/mediagoblin/edit/attachments.html:57 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:204 +msgid "Add attachment" +msgstr "新增附件" + +#: mediagoblin/templates/mediagoblin/edit/attachments.html:61 +#: mediagoblin/templates/mediagoblin/edit/delete_account.html:42 +#: mediagoblin/templates/mediagoblin/edit/edit.html:41 +#: mediagoblin/templates/mediagoblin/edit/edit_collection.html:32 +#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:46 +#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:52 +#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:67 +#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:48 +msgid "Cancel" +msgstr "取消" + +#: mediagoblin/templates/mediagoblin/edit/attachments.html:63 +#: mediagoblin/templates/mediagoblin/edit/edit.html:42 +#: mediagoblin/templates/mediagoblin/edit/edit_account.html:55 +#: mediagoblin/templates/mediagoblin/edit/edit_collection.html:33 +#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:40 +msgid "Save changes" +msgstr "保存更改" + +#: mediagoblin/templates/mediagoblin/edit/change_pass.html:28 +#: mediagoblin/templates/mediagoblin/edit/change_pass.html:38 +#, python-format +msgid "Changing %(username)s's password" +msgstr "修改 %(username)s 的密码" + +#: mediagoblin/templates/mediagoblin/edit/change_pass.html:45 +msgid "Save" +msgstr "保存" + +#: mediagoblin/templates/mediagoblin/edit/delete_account.html:28 +#, python-format +msgid "Really delete user '%(user_name)s' and all related media/comments?" +msgstr "真的要删除用户 %(user_name)s 及所有相关媒体和评论吗?" + +#: mediagoblin/templates/mediagoblin/edit/delete_account.html:35 +msgid "Yes, really delete my account" +msgstr "是的,真的删除我的账户" + +#: mediagoblin/templates/mediagoblin/edit/delete_account.html:44 +#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:48 +#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:49 +msgid "Delete permanently" +msgstr "永久删除" + +#: mediagoblin/templates/mediagoblin/edit/edit.html:23 +#: mediagoblin/templates/mediagoblin/edit/edit.html:35 +#, python-format +msgid "Editing %(media_title)s" +msgstr "编辑 %(media_title)s" + +#: mediagoblin/templates/mediagoblin/edit/edit_account.html:28 +#: mediagoblin/templates/mediagoblin/edit/edit_account.html:40 +#, python-format +msgid "Changing %(username)s's account settings" +msgstr "正在改变 %(username)s 的账户设置" + +#: mediagoblin/templates/mediagoblin/edit/edit_account.html:46 +msgid "Change your password." +msgstr "修改您的密码。" + +#: mediagoblin/templates/mediagoblin/edit/edit_account.html:62 +msgid "Delete my account" +msgstr "删除我的帐户" + +#: mediagoblin/templates/mediagoblin/edit/edit_collection.html:29 +#, python-format +msgid "Editing %(collection_title)s" +msgstr "编辑 %(collection_title)s" + +#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:23 +#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:34 +#, python-format +msgid "Editing %(username)s's profile" +msgstr "编辑 %(username)s 的个人资料" + +#: mediagoblin/templates/mediagoblin/listings/collection.html:30 +#: mediagoblin/templates/mediagoblin/listings/collection.html:35 +#: mediagoblin/templates/mediagoblin/listings/tag.html:30 +#: mediagoblin/templates/mediagoblin/listings/tag.html:35 +#, python-format +msgid "Media tagged with: %(tag_name)s" +msgstr "此媒体被标记为:%(tag_name)s" + +#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34 +#: mediagoblin/templates/mediagoblin/media_displays/audio.html:56 +#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:65 +#: mediagoblin/templates/mediagoblin/media_displays/stl.html:136 +#: mediagoblin/templates/mediagoblin/media_displays/video.html:55 +msgid "Download" +msgstr "下载" + +#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:38 +msgid "Original" +msgstr "源文件" + +#: mediagoblin/templates/mediagoblin/media_displays/audio.html:44 +msgid "" +"Sorry, this audio will not work because \n" +"\tyour web browser does not support HTML5 \n" +"\taudio." +msgstr "抱歉,此声音无法播放,因为您的浏览器不支持 HTML5 音频。" + +#: mediagoblin/templates/mediagoblin/media_displays/audio.html:47 +msgid "" +"You can get a modern web browser that \n" +"\tcan play the audio at <a href=\"http://getfirefox.com\">\n" +"\t http://getfirefox.com</a>!" +msgstr "您可以在 <a href=\"http://getfirefox.com\">http://getfirefox.com</a> 取得可以播放此声音的浏览器!" + +#: mediagoblin/templates/mediagoblin/media_displays/audio.html:60 +#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:71 +#: mediagoblin/templates/mediagoblin/media_displays/video.html:61 +msgid "Original file" +msgstr "源文件" + +#: mediagoblin/templates/mediagoblin/media_displays/audio.html:63 +msgid "WebM file (Vorbis codec)" +msgstr "WebM 文件(Vorbis 编码)" + +#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:59 +#: mediagoblin/templates/mediagoblin/media_displays/stl.html:87 +#: mediagoblin/templates/mediagoblin/media_displays/stl.html:93 +#: mediagoblin/templates/mediagoblin/media_displays/stl.html:99 +#: mediagoblin/templates/mediagoblin/media_displays/stl.html:105 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:59 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:65 +#, python-format +msgid "Image for %(media_title)s" +msgstr "%(media_title)s 的照片" + +#: mediagoblin/templates/mediagoblin/media_displays/pdf.html:79 +msgid "PDF file" +msgstr "PDF 文件" + +#: mediagoblin/templates/mediagoblin/media_displays/stl.html:112 +msgid "Toggle Rotate" +msgstr "切换旋转" + +#: mediagoblin/templates/mediagoblin/media_displays/stl.html:113 +msgid "Perspective" +msgstr "透视" + +#: mediagoblin/templates/mediagoblin/media_displays/stl.html:116 +#: mediagoblin/templates/mediagoblin/media_displays/stl.html:117 +msgid "Front" +msgstr "正面" + +#: mediagoblin/templates/mediagoblin/media_displays/stl.html:120 +#: mediagoblin/templates/mediagoblin/media_displays/stl.html:121 +msgid "Top" +msgstr "顶面" + +#: mediagoblin/templates/mediagoblin/media_displays/stl.html:124 +#: mediagoblin/templates/mediagoblin/media_displays/stl.html:125 +msgid "Side" +msgstr "侧面" + +#: mediagoblin/templates/mediagoblin/media_displays/stl.html:130 +#: mediagoblin/templates/mediagoblin/media_displays/stl.html:131 +msgid "WebGL" +msgstr "WebGL" + +#: mediagoblin/templates/mediagoblin/media_displays/stl.html:138 +msgid "Download model" +msgstr "下载模型" + +#: mediagoblin/templates/mediagoblin/media_displays/stl.html:146 +msgid "File Format" +msgstr "文件格式" + +#: mediagoblin/templates/mediagoblin/media_displays/stl.html:148 +msgid "Object Height" +msgstr "对象高度" + +#: mediagoblin/templates/mediagoblin/media_displays/video.html:44 +msgid "" +"Sorry, this video will not work because\n" +" your web browser does not support HTML5 \n" +" video." +msgstr "抱歉,此视频无法播放,因为您的浏览器不支持 HTML5 视频。" + +#: mediagoblin/templates/mediagoblin/media_displays/video.html:47 +msgid "" +"You can get a modern web browser that \n" +" can play this video at <a href=\"http://getfirefox.com\">\n" +" http://getfirefox.com</a>!" +msgstr "您可以在 <a href=\"http://getfirefox.com\">http://getfirefox.com</a> 取得可以播放此视频的浏览器!" + +#: mediagoblin/templates/mediagoblin/media_displays/video.html:69 +msgid "WebM file (640p; VP8/Vorbis)" +msgstr "WebM 文件(640p;VP8/Vorbis)" + +#: mediagoblin/templates/mediagoblin/submit/collection.html:26 +msgid "Add a collection" +msgstr "新增合集" + +#: mediagoblin/templates/mediagoblin/submit/start.html:23 +#: mediagoblin/templates/mediagoblin/submit/start.html:30 +msgid "Add your media" +msgstr "加入您的媒体" + +#: mediagoblin/templates/mediagoblin/user_pages/collection.html:30 +#, python-format +msgid "%(collection_title)s (%(username)s's collection)" +msgstr "%(collection_title)s (%(username)s 的合集)" + +#: mediagoblin/templates/mediagoblin/user_pages/collection.html:39 +#, python-format +msgid "%(collection_title)s by <a href=\"%(user_url)s\">%(username)s</a>" +msgstr "%(collection_title)s by <a href=\"%(user_url)s\">%(username)s</a>" + +#: mediagoblin/templates/mediagoblin/user_pages/collection.html:52 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:79 +msgid "Edit" +msgstr "编辑" + +#: mediagoblin/templates/mediagoblin/user_pages/collection.html:56 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:83 +msgid "Delete" +msgstr "删除" + +#: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:30 +#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 +#, python-format +msgid "Really delete %(title)s?" +msgstr "真的要删除 %(title)s 吗?" + +#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:31 +#, python-format +msgid "Really remove %(media_title)s from %(collection_title)s?" +msgstr "确定要从 %(collection_title)s 移除 %(media_title)s 吗?" + +#: mediagoblin/templates/mediagoblin/user_pages/collection_item_confirm_remove.html:54 +msgid "Remove" +msgstr "移除" + +#: mediagoblin/templates/mediagoblin/user_pages/collection_list.html:21 +#, python-format +msgid "%(username)s's collections" +msgstr "%(username)s 的合集" + +#: mediagoblin/templates/mediagoblin/user_pages/collection_list.html:28 +#, python-format +msgid "<a href=\"%(user_url)s\">%(username)s</a>'s collections" +msgstr "<a href=\"%(user_url)s\">%(username)s</a> 的合集" + +#: mediagoblin/templates/mediagoblin/user_pages/comment_email.txt:19 +#, python-format +msgid "" +"Hi %(username)s,\n" +"%(comment_author)s commented on your post (%(comment_url)s) at %(instance_name)s\n" +msgstr "%(username)s 您好:\n%(comment_author)s 在 %(instance_name)s 对您的内容 (%(comment_url)s) 张贴评论\n" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 +#, python-format +msgid "%(username)s's media" +msgstr "%(username)s的媒体" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:38 +#, python-format +msgid "" +"<a href=\"%(user_url)s\">%(username)s</a>'s media with tag <a " +"href=\"%(tag_url)s\">%(tag)s</a>" +msgstr "<a href=\"%(user_url)s\">%(username)s</a> 的有 <a href=\"%(tag_url)s\">%(tag)s</a> 标签的媒体" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:48 +#, python-format +msgid "<a href=\"%(user_url)s\">%(username)s</a>'s media" +msgstr "<a href=\"%(user_url)s\">%(username)s</a> 的媒体" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:38 +#, python-format +msgid "❖ Browsing media by <a href=\"%(user_url)s\">%(username)s</a>" +msgstr "❖ 浏览 <a href=\"%(user_url)s\">%(username)s</a> 的媒体" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:95 +msgid "Add a comment" +msgstr "新增评论" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:104 +msgid "Add this comment" +msgstr "增加评论" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:132 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:152 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:164 +#, python-format +msgid "%(formatted_time)s ago" +msgstr "%(formatted_time)s前" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:150 +msgid "Added" +msgstr "已增加" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:161 +msgid "Created" +msgstr "已创建" + +#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:28 +#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:40 +#, python-format +msgid "Add “%(media_title)s” to a collection" +msgstr "把“%(media_title)s”加入合集" + +#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:54 +msgid "+" +msgstr "+" + +#: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:58 +msgid "Add a new collection" +msgstr "新增新的合集" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:29 +msgid "" +"You can track the state of media being processed for your gallery here." +msgstr "您可以在这里追踪您的艺廊中媒体处理的状态。" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:89 +msgid "Your last 10 successful uploads" +msgstr "您的最近 10 次成功上传的纪录" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:31 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:89 +#, python-format +msgid "%(username)s's profile" +msgstr "%(username)s 的个人资料" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:43 +msgid "Sorry, no such user found." +msgstr "抱歉,找不到该用户。" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:50 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:70 +msgid "Email verification needed" +msgstr "需要认证电子邮件地址" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:53 +msgid "Almost done! Your account still needs to be activated." +msgstr "快完成了!但您需要激活您的账户。" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:58 +msgid "" +"An email should arrive in a few moments with instructions on how to do so." +msgstr "账户激活说明将在稍后送达。" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 +msgid "In case it doesn't:" +msgstr "如果仍然无法认证,您可以:" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:65 +msgid "Resend verification email" +msgstr "重发认证邮件" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:73 +msgid "" +"Someone has registered an account with this username, but it still has to be" +" activated." +msgstr "有人用注册了该账户,但是该账户需要被启用。" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:79 +#, python-format +msgid "" +"If you are that person but you've lost your verification email, you can <a " +"href=\"%(login_url)s\">log in</a> and resend it." +msgstr "如果您就是本人但是未收到认证信,您可以<a href=\"%(login_url)s\">登录</a>然后重发一次。" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 +msgid "Here's a spot to tell others about yourself." +msgstr "这个地方能让您向他人介绍自己。" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:100 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:117 +msgid "Edit profile" +msgstr "编辑个人资料" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:105 +msgid "This user hasn't filled in their profile (yet)." +msgstr "这个用户(还)没有填写个人资料。" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:124 +msgid "Browse collections" +msgstr "浏览合集" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:137 +#, python-format +msgid "View all of %(username)s's media" +msgstr "查看 %(username)s 的全部媒体" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:150 +msgid "" +"This is where your media will appear, but you don't seem to have added " +"anything yet." +msgstr "此处是您的媒体会出现的地方,但是似乎还没有加入任何东西。" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:162 +#: mediagoblin/templates/mediagoblin/utils/collection_gallery.html:84 +#: mediagoblin/templates/mediagoblin/utils/object_gallery.html:70 +msgid "There doesn't seem to be any media here yet..." +msgstr "那里好像还没有任何的媒体……" + +#: mediagoblin/templates/mediagoblin/utils/collection_gallery.html:49 +msgid "(remove)" +msgstr "(移除)" + +#: mediagoblin/templates/mediagoblin/utils/collections.html:21 +msgid "Collected in" +msgstr "合集于" + +#: mediagoblin/templates/mediagoblin/utils/collections.html:40 +msgid "Add to a collection" +msgstr "添加到合集" + +#: mediagoblin/templates/mediagoblin/utils/feed_link.html:21 +#: mediagoblin/themes/airy/templates/mediagoblin/utils/feed_link.html:21 +msgid "feed icon" +msgstr "feed 图标" + +#: mediagoblin/templates/mediagoblin/utils/feed_link.html:23 +#: mediagoblin/themes/airy/templates/mediagoblin/utils/feed_link.html:23 +msgid "Atom feed" +msgstr "Atom feed" + +#: mediagoblin/templates/mediagoblin/utils/license.html:25 +msgid "All rights reserved" +msgstr "版权所有" + +#: mediagoblin/templates/mediagoblin/utils/pagination.html:39 +msgid "← Newer" +msgstr "← 更新的" + +#: mediagoblin/templates/mediagoblin/utils/pagination.html:45 +msgid "Older →" +msgstr "更旧的 →" + +#: mediagoblin/templates/mediagoblin/utils/pagination.html:48 +msgid "Go to page:" +msgstr "跳到页数:" + +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:28 +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:33 +msgid "newer" +msgstr "更新的" + +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:39 +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:44 +msgid "older" +msgstr "更旧的" + +#: mediagoblin/templates/mediagoblin/utils/tags.html:20 +msgid "Tagged with" +msgstr "标签" + +#: mediagoblin/tools/exif.py:83 +msgid "Could not read the image file." +msgstr "无法读取图片文件。" + +#: mediagoblin/tools/response.py:35 +msgid "Oops!" +msgstr "糟糕!" + +#: mediagoblin/tools/response.py:36 +msgid "An error occured" +msgstr "发生错误" + +#: mediagoblin/tools/response.py:51 +msgid "Operation not allowed" +msgstr "操作不允许" + +#: mediagoblin/tools/response.py:52 +msgid "" +"Sorry Dave, I can't let you do that!</p><p>You have tried to perform a " +"function that you are not allowed to. Have you been trying to delete all " +"user accounts again?" +msgstr "对不起老兄,我不能让你这样做!</p><p>您正在试着操作不允许您使用的功能。您难道想打算删除所有用户账户吗?" + +#: mediagoblin/tools/response.py:60 +msgid "" +"There doesn't seem to be a page at this address. Sorry!</p><p>If you're sure" +" the address is correct, maybe the page you're looking for has been moved or" +" deleted." +msgstr "不好意思,看起来这个网址上没有网页。</p><p>如果您确定这个网址是正确的,您在寻找的页面可能已经移动或是被删除了。" + +#: mediagoblin/tools/timesince.py:62 +msgid "year" +msgstr "年" + +#: mediagoblin/tools/timesince.py:63 +msgid "month" +msgstr "月" + +#: mediagoblin/tools/timesince.py:64 +msgid "week" +msgstr "周" + +#: mediagoblin/tools/timesince.py:65 +msgid "day" +msgstr "日" + +#: mediagoblin/tools/timesince.py:66 +msgid "hour" +msgstr "小时" + +#: mediagoblin/tools/timesince.py:67 +msgid "minute" +msgstr "分钟" + +#: mediagoblin/user_pages/forms.py:23 +msgid "Comment" +msgstr "评论" + +#: mediagoblin/user_pages/forms.py:25 +msgid "" +"You can use <a " +"href=\"http://daringfireball.net/projects/markdown/basics\">Markdown</a> for" +" formatting." +msgstr "您可以用 <a href=\"http://wowubuntu.com/markdown/\">Markdown</a> 来排版。" + +#: mediagoblin/user_pages/forms.py:31 +msgid "I am sure I want to delete this" +msgstr "我确定我要删除这个媒体" + +#: mediagoblin/user_pages/forms.py:35 +msgid "I am sure I want to remove this item from the collection" +msgstr "我确定我要从合集中移除此项目" + +#: mediagoblin/user_pages/forms.py:39 +msgid "Collection" +msgstr "合集" + +#: mediagoblin/user_pages/forms.py:40 +msgid "-- Select --" +msgstr "— 请选择 —" + +#: mediagoblin/user_pages/forms.py:42 +msgid "Include a note" +msgstr "加注" + +#: mediagoblin/user_pages/lib.py:58 +msgid "commented on your post" +msgstr "在您的内容张贴评论" + +#: mediagoblin/user_pages/views.py:169 +msgid "Sorry, comments are disabled." +msgstr "抱歉,不开放评论。" + +#: mediagoblin/user_pages/views.py:174 +msgid "Oops, your comment was empty." +msgstr "啊,您的评论是空的。" + +#: mediagoblin/user_pages/views.py:180 +msgid "Your comment has been posted!" +msgstr "您的评论已经张贴完成!" + +#: mediagoblin/user_pages/views.py:205 +msgid "Please check your entries and try again." +msgstr "请检查项目并重试。" + +#: mediagoblin/user_pages/views.py:245 +msgid "You have to select or add a collection" +msgstr "您需要选择或是新增一个合集" + +#: mediagoblin/user_pages/views.py:256 +#, python-format +msgid "\"%s\" already in collection \"%s\"" +msgstr "“%s”已经在“%s”合集" + +#: mediagoblin/user_pages/views.py:262 +#, python-format +msgid "\"%s\" added to collection \"%s\"" +msgstr "“%s”加入“%s”合集" + +#: mediagoblin/user_pages/views.py:282 +msgid "You deleted the media." +msgstr "您已经删除此媒体。" + +#: mediagoblin/user_pages/views.py:289 +msgid "The media was not deleted because you didn't check that you were sure." +msgstr "由于您没有勾选确认,该媒体没有被移除。" + +#: mediagoblin/user_pages/views.py:296 +msgid "You are about to delete another user's media. Proceed with caution." +msgstr "您正在删除别人的媒体,请小心操作。" + +#: mediagoblin/user_pages/views.py:370 +msgid "You deleted the item from the collection." +msgstr "您已经从该合集中删除该项目。" + +#: mediagoblin/user_pages/views.py:374 +msgid "The item was not removed because you didn't check that you were sure." +msgstr "由于您没有勾选确认,该项目没有被移除。" + +#: mediagoblin/user_pages/views.py:382 +msgid "" +"You are about to delete an item from another user's collection. Proceed with" +" caution." +msgstr "您正在从别人的合集中删除项目,请小心操作。" + +#: mediagoblin/user_pages/views.py:415 +#, python-format +msgid "You deleted the collection \"%s\"" +msgstr "您已经删除“%s”合集。" + +#: mediagoblin/user_pages/views.py:422 +msgid "" +"The collection was not deleted because you didn't check that you were sure." +msgstr "由于您没有勾选确认,该合集没有被移除。" + +#: mediagoblin/user_pages/views.py:430 +msgid "" +"You are about to delete another user's collection. Proceed with caution." +msgstr "您正在删除别人的合集,请小心操作。" diff --git a/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.mo Binary files differindex 3fd4911a..4b7a2398 100644 --- a/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.mo +++ 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 index e2a8e680..05ecd4b5 100644 --- a/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po @@ -5,14 +5,16 @@ # Translators: # <chc@citi.sinica.edu.tw>, 2011 # Harry Chen <harryhow@gmail.com>, 2011-2012 +# medicalwei <medicalwei@gmail.com>, 2013 # medicalwei <medicalwei@gmail.com>, 2012 +# m13253 <m13253@hotmail.com>, 2013 msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://issues.mediagoblin.org/\n" "POT-Creation-Date: 2013-05-27 13:54-0500\n" -"PO-Revision-Date: 2013-05-27 18:54+0000\n" -"Last-Translator: cwebber <cwebber@dustycloud.org>\n" +"PO-Revision-Date: 2013-06-16 01:40+0000\n" +"Last-Translator: m13253 <m13253@hotmail.com>\n" "Language-Team: Chinese (Taiwan) (http://www.transifex.com/projects/p/mediagoblin/language/zh_TW/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -36,7 +38,7 @@ msgstr "Email 位址" #: mediagoblin/auth/forms.py:41 msgid "Username or Email" -msgstr "" +msgstr "使用者名稱或 email" #: mediagoblin/auth/forms.py:52 msgid "Username or email" @@ -44,15 +46,15 @@ msgstr "使用者名稱或 email" #: mediagoblin/auth/tools.py:31 msgid "Invalid User name or email address." -msgstr "" +msgstr "無效的使用者名稱或 email 位置。" #: mediagoblin/auth/tools.py:32 msgid "This field does not take email addresses." -msgstr "" +msgstr "本欄位不接受 email 位置。" #: mediagoblin/auth/tools.py:33 msgid "This field requires an email address." -msgstr "" +msgstr "本欄位需要 email 位置。" #: mediagoblin/auth/views.py:54 msgid "Sorry, registration is disabled on this instance." @@ -92,11 +94,11 @@ msgstr "重送認證信。" msgid "" "If that email address (case sensitive!) is registered an email has been sent" " with instructions on how to change your password." -msgstr "" +msgstr "如果那 email 位置 (請注意大小寫) 已經註冊,寫有修改密碼步驟的 email 已經送出。" #: mediagoblin/auth/views.py:269 msgid "Couldn't find someone with that username." -msgstr "" +msgstr "找不到相關的使用者名稱。" #: mediagoblin/auth/views.py:272 msgid "" @@ -173,15 +175,15 @@ msgstr "本網址出錯了" #: mediagoblin/edit/forms.py:63 msgid "License preference" -msgstr "" +msgstr "授權偏好" #: mediagoblin/edit/forms.py:69 msgid "This will be your default license on upload forms." -msgstr "" +msgstr "在上傳頁面,這將會是您預設的授權模式。" #: mediagoblin/edit/forms.py:71 msgid "Email me when others comment on my media" -msgstr "當有人對我的媒體評論時寄信給我" +msgstr "當有人對我的媒體留言時寄信給我" #: mediagoblin/edit/forms.py:83 msgid "The title can't be empty" @@ -225,7 +227,7 @@ msgstr "您加上了附件「%s」!" #: mediagoblin/edit/views.py:182 msgid "You can only edit your own profile." -msgstr "" +msgstr "您只能修改您自己的個人檔案。" #: mediagoblin/edit/views.py:188 msgid "You are editing a user's profile. Proceed with caution." @@ -241,7 +243,7 @@ msgstr "帳號設定已儲存" #: mediagoblin/edit/views.py:274 msgid "You need to confirm the deletion of your account." -msgstr "" +msgstr "您必須要確認是否刪除您的帳號。" #: mediagoblin/edit/views.py:310 mediagoblin/submit/views.py:138 #: mediagoblin/user_pages/views.py:222 @@ -263,7 +265,7 @@ msgstr "密碼錯誤" #: mediagoblin/edit/views.py:363 msgid "Your password was changed successfully" -msgstr "" +msgstr "您的密碼已經成功修改" #: mediagoblin/gmg_commands/assetlink.py:60 msgid "Cannot link theme... no theme set\n" @@ -280,24 +282,24 @@ msgstr "但是舊的目錄連結已經找到並移除。\n" #: mediagoblin/gmg_commands/assetlink.py:112 #, python-format msgid "Could not link \"%s\": %s exists and is not a symlink\n" -msgstr "" +msgstr "無法連結「%s」:%s 存在,且不是符號連結\n" #: mediagoblin/gmg_commands/assetlink.py:119 #, python-format msgid "Skipping \"%s\"; already set up.\n" -msgstr "" +msgstr "跳過「%s」,已經建置完成。\n" #: mediagoblin/gmg_commands/assetlink.py:124 #, python-format msgid "Old link found for \"%s\"; removing.\n" -msgstr "" +msgstr "找到「%s」舊的連結,刪除中。\n" #: mediagoblin/meddleware/csrf.py:134 msgid "" "CSRF cookie not present. This is most likely the result of a cookie blocker " "or somesuch.<br/>Make sure to permit the settings of cookies for this " "domain." -msgstr "" +msgstr "跨網站存取 (CSRF) 的 cookie 不存在,有可能是 cookie 阻擋程式之類的程式導致的。<br/>請允許此網域的 cookie 設定。" #: mediagoblin/media_types/__init__.py:111 #: mediagoblin/media_types/__init__.py:155 @@ -306,7 +308,7 @@ msgstr "抱歉,我不支援這樣的檔案格式 :(" #: mediagoblin/media_types/pdf/processing.py:136 msgid "unoconv failing to run, check log file" -msgstr "" +msgstr "unoconv 無法執行,請檢查紀錄檔" #: mediagoblin/media_types/video/processing.py:37 msgid "Video transcoding failed" @@ -335,7 +337,7 @@ msgstr "名稱" #: mediagoblin/plugins/oauth/forms.py:35 msgid "The name of the OAuth client" -msgstr "OAuth client 的名稱" +msgstr "OAuth 用戶程式的名稱" #: mediagoblin/plugins/oauth/forms.py:36 msgid "Description" @@ -359,7 +361,7 @@ msgid "" " <strong>Public</strong> - The client can't make confidential\n" " requests to the GNU MediaGoblin instance (e.g. client-side\n" " JavaScript client)." -msgstr "<strong>秘密</strong> — OAuth client 可以對 GNU MediaGoblin 站台發送不被使用者代理攔截的請求 (例如伺服端的 client)。\n<strong>公開</strong> — OAuth client 無法對 GNU MediaGoblin 站台發送秘密的請求 (例如客戶端的 JavaScript client)。" +msgstr "<strong>秘密</strong> — OAuth 用戶程式可以對 GNU MediaGoblin 站台發送不被使用者代理攔截的請求 (例如伺服端的用戶程式)。\n<strong>公開</strong> — OAuth 用戶程式無法對 GNU MediaGoblin 站台發送秘密的請求 (例如客戶端的 JavaScript 用戶程式)。" #: mediagoblin/plugins/oauth/forms.py:52 msgid "Redirect URI" @@ -369,23 +371,23 @@ msgstr "重定向 URI" msgid "" "The redirect URI for the applications, this field\n" " is <strong>required</strong> for public clients." -msgstr "此應用程式的重定向 URI,本欄位在公開類型的 OAuth client 為必填。" +msgstr "此應用程式的重定向 URI,本欄位在公開類型的 OAuth 用戶程式為必填。" #: mediagoblin/plugins/oauth/forms.py:66 msgid "This field is required for public clients" -msgstr "本欄位在公開類型的 OAuth client 為必填" +msgstr "本欄位在公開類型的用戶程式為必填" #: mediagoblin/plugins/oauth/views.py:56 msgid "The client {0} has been registered!" -msgstr "OAuth client {0} 註冊完成!" +msgstr "OAuth 用戶程式 {0} 註冊完成!" #: mediagoblin/plugins/oauth/templates/oauth/client/connections.html:22 msgid "OAuth client connections" -msgstr "" +msgstr "OAuth 用戶程式連線" #: mediagoblin/plugins/oauth/templates/oauth/client/list.html:22 msgid "Your OAuth clients" -msgstr "" +msgstr "您的 OAuth 用戶程式" #: mediagoblin/plugins/oauth/templates/oauth/client/register.html:29 #: mediagoblin/templates/mediagoblin/submit/collection.html:30 @@ -450,7 +452,7 @@ msgstr "媒體處理面板" #: mediagoblin/templates/mediagoblin/base.html:96 msgid "Log out" -msgstr "" +msgstr "登出" #: mediagoblin/templates/mediagoblin/base.html:99 #: mediagoblin/templates/mediagoblin/user_pages/user.html:156 @@ -577,7 +579,7 @@ msgstr "%(username)s 您好:\n\n要啟動 GNU MediaGoblin 帳號,請在您 msgid "" "Powered by <a href=\"http://mediagoblin.org/\" title='Version " "%(version)s'>MediaGoblin</a>, a <a href=\"http://gnu.org/\">GNU</a> project." -msgstr "" +msgstr "本站使用 <a href=\"http://mediagoblin.org/\" title='Version %(version)s'>MediaGoblin</a>,這是一個 <a href=\"http://gnu.org/\">GNU</a> 專案。" #: mediagoblin/templates/mediagoblin/bits/base_footer.html:24 #, python-format @@ -617,7 +619,7 @@ msgid "" "<a class=\"button_action_highlight\" href=\"%(register_url)s\">Create an account at this site</a>\n" " or\n" " <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Set up MediaGoblin on your own server</a>" -msgstr "" +msgstr "<a class=\"button_action_highlight\" href=\"%(register_url)s\">在本站建立您的帳號</a>\n 或是\n <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">在您自己的伺服器上安裝 MediaGoblin</a>" #: mediagoblin/templates/mediagoblin/bits/logo.html:23 #: mediagoblin/themes/airy/templates/mediagoblin/bits/logo.html:23 @@ -664,20 +666,20 @@ msgstr "儲存變更" #: mediagoblin/templates/mediagoblin/edit/change_pass.html:38 #, python-format msgid "Changing %(username)s's password" -msgstr "" +msgstr "更改 %(username)s 的密碼" #: mediagoblin/templates/mediagoblin/edit/change_pass.html:45 msgid "Save" -msgstr "" +msgstr "儲存" #: mediagoblin/templates/mediagoblin/edit/delete_account.html:28 #, python-format msgid "Really delete user '%(user_name)s' and all related media/comments?" -msgstr "" +msgstr "真的要刪除使用者「%(user_name)s」以及相關的媒體與留言?" #: mediagoblin/templates/mediagoblin/edit/delete_account.html:35 msgid "Yes, really delete my account" -msgstr "" +msgstr "是的,我真的要把我的帳號刪除" #: mediagoblin/templates/mediagoblin/edit/delete_account.html:44 #: mediagoblin/templates/mediagoblin/user_pages/collection_confirm_delete.html:48 @@ -699,11 +701,11 @@ msgstr "正在改變 %(username)s 的帳號設定" #: mediagoblin/templates/mediagoblin/edit/edit_account.html:46 msgid "Change your password." -msgstr "" +msgstr "更改您的密碼。" #: mediagoblin/templates/mediagoblin/edit/edit_account.html:62 msgid "Delete my account" -msgstr "" +msgstr "刪除我的帳號" #: mediagoblin/templates/mediagoblin/edit/edit_collection.html:29 #, python-format @@ -722,7 +724,7 @@ msgstr "編輯 %(username)s 的個人檔案" #: mediagoblin/templates/mediagoblin/listings/tag.html:35 #, python-format msgid "Media tagged with: %(tag_name)s" -msgstr "此媒體被 tag 成:%(tag_name)s" +msgstr "這個媒體具有以下標籤:%(tag_name)s" #: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34 #: mediagoblin/templates/mediagoblin/media_displays/audio.html:56 @@ -773,7 +775,7 @@ msgstr " %(media_title)s 的照片" #: mediagoblin/templates/mediagoblin/media_displays/pdf.html:79 msgid "PDF file" -msgstr "" +msgstr "PDF 檔" #: mediagoblin/templates/mediagoblin/media_displays/stl.html:112 msgid "Toggle Rotate" @@ -781,7 +783,7 @@ msgstr "切換旋轉" #: mediagoblin/templates/mediagoblin/media_displays/stl.html:113 msgid "Perspective" -msgstr "視角" +msgstr "透視" #: mediagoblin/templates/mediagoblin/media_displays/stl.html:116 #: mediagoblin/templates/mediagoblin/media_displays/stl.html:117 @@ -820,14 +822,14 @@ msgid "" "Sorry, this video will not work because\n" " your web browser does not support HTML5 \n" " video." -msgstr "" +msgstr "抱歉,由於您的瀏覽器不支援 HTML5 影片,本影片無法播放" #: mediagoblin/templates/mediagoblin/media_displays/video.html:47 msgid "" "You can get a modern web browser that \n" " can play this video at <a href=\"http://getfirefox.com\">\n" " http://getfirefox.com</a>!" -msgstr "" +msgstr "您可以在 <a href=\"http://getfirefox.com\">http://getfirefox.com</a> 取得可以播放此影片的先進瀏覽器。" #: mediagoblin/templates/mediagoblin/media_displays/video.html:69 msgid "WebM file (640p; VP8/Vorbis)" @@ -880,19 +882,19 @@ msgstr "移除" #: mediagoblin/templates/mediagoblin/user_pages/collection_list.html:21 #, python-format msgid "%(username)s's collections" -msgstr "" +msgstr "%(username)s 的蒐藏" #: mediagoblin/templates/mediagoblin/user_pages/collection_list.html:28 #, python-format msgid "<a href=\"%(user_url)s\">%(username)s</a>'s collections" -msgstr "" +msgstr "<a href=\"%(user_url)s\">%(username)s</a> 的蒐藏" #: mediagoblin/templates/mediagoblin/user_pages/comment_email.txt:19 #, python-format msgid "" "Hi %(username)s,\n" "%(comment_author)s commented on your post (%(comment_url)s) at %(instance_name)s\n" -msgstr "%(username)s 您好:\n%(comment_author)s 在 %(instance_name)s 對您的內容 (%(comment_url)s) 張貼評論\n" +msgstr "%(username)s 您好:\n%(comment_author)s 在 %(instance_name)s 對您的內容 (%(comment_url)s) 張貼留言\n" #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 #, python-format @@ -904,7 +906,7 @@ msgstr "%(username)s的媒體" msgid "" "<a href=\"%(user_url)s\">%(username)s</a>'s media with tag <a " "href=\"%(tag_url)s\">%(tag)s</a>" -msgstr "" +msgstr "標籤為 <a href=\"%(tag_url)s\">%(tag)s</a> 的 <a href=\"%(user_url)s\">%(username)s</a> 的媒體" #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:48 #, python-format @@ -918,32 +920,32 @@ msgstr "❖ 瀏覽 <a href=\"%(user_url)s\">%(username)s</a> 的媒體" #: mediagoblin/templates/mediagoblin/user_pages/media.html:95 msgid "Add a comment" -msgstr "新增評論" +msgstr "新增留言" #: mediagoblin/templates/mediagoblin/user_pages/media.html:104 msgid "Add this comment" -msgstr "增加評論" +msgstr "增加留言" #: mediagoblin/templates/mediagoblin/user_pages/media.html:132 #: mediagoblin/templates/mediagoblin/user_pages/media.html:152 #: mediagoblin/templates/mediagoblin/user_pages/media.html:164 #, python-format msgid "%(formatted_time)s ago" -msgstr "" +msgstr "%(formatted_time)s 前" #: mediagoblin/templates/mediagoblin/user_pages/media.html:150 msgid "Added" -msgstr "" +msgstr "新增於" #: mediagoblin/templates/mediagoblin/user_pages/media.html:161 msgid "Created" -msgstr "" +msgstr "建立於" #: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:28 #: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:40 #, python-format msgid "Add “%(media_title)s” to a collection" -msgstr "" +msgstr "加入 “%(media_title)s” 至蒐藏" #: mediagoblin/templates/mediagoblin/user_pages/media_collect.html:54 msgid "+" @@ -1022,7 +1024,7 @@ msgstr "這個使用者(還)沒有填寫個人檔案。" #: mediagoblin/templates/mediagoblin/user_pages/user.html:124 msgid "Browse collections" -msgstr "" +msgstr "瀏覽蒐藏" #: mediagoblin/templates/mediagoblin/user_pages/user.html:137 #, python-format @@ -1047,11 +1049,11 @@ msgstr " (移除)" #: mediagoblin/templates/mediagoblin/utils/collections.html:21 msgid "Collected in" -msgstr "" +msgstr "蒐集了" #: mediagoblin/templates/mediagoblin/utils/collections.html:40 msgid "Add to a collection" -msgstr "" +msgstr "加入至蒐藏" #: mediagoblin/templates/mediagoblin/utils/feed_link.html:21 #: mediagoblin/themes/airy/templates/mediagoblin/utils/feed_link.html:21 @@ -1125,31 +1127,31 @@ msgstr "不好意思,看起來這個網址上沒有網頁。</p><p>如果您 #: mediagoblin/tools/timesince.py:62 msgid "year" -msgstr "" +msgstr "年" #: mediagoblin/tools/timesince.py:63 msgid "month" -msgstr "" +msgstr "月" #: mediagoblin/tools/timesince.py:64 msgid "week" -msgstr "" +msgstr "週" #: mediagoblin/tools/timesince.py:65 msgid "day" -msgstr "" +msgstr "日" #: mediagoblin/tools/timesince.py:66 msgid "hour" -msgstr "" +msgstr "小時" #: mediagoblin/tools/timesince.py:67 msgid "minute" -msgstr "" +msgstr "分" #: mediagoblin/user_pages/forms.py:23 msgid "Comment" -msgstr "" +msgstr "留言" #: mediagoblin/user_pages/forms.py:25 msgid "" @@ -1168,7 +1170,7 @@ msgstr "我確定我要從蒐藏中移除此項目" #: mediagoblin/user_pages/forms.py:39 msgid "Collection" -msgstr "" +msgstr "蒐藏" #: mediagoblin/user_pages/forms.py:40 msgid "-- Select --" @@ -1180,11 +1182,11 @@ msgstr "加註" #: mediagoblin/user_pages/lib.py:58 msgid "commented on your post" -msgstr "在您的內容張貼評論" +msgstr "在您的內容張貼留言" #: mediagoblin/user_pages/views.py:169 msgid "Sorry, comments are disabled." -msgstr "" +msgstr "抱歉,留言被關閉。" #: mediagoblin/user_pages/views.py:174 msgid "Oops, your comment was empty." diff --git a/mediagoblin/static/css/pdf_viewer.css b/mediagoblin/static/css/pdf_viewer.css deleted file mode 100644 index c04c8981..00000000 --- a/mediagoblin/static/css/pdf_viewer.css +++ /dev/null @@ -1,1448 +0,0 @@ -/* Copyright 2012 Mozilla Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -* { - padding: 0; - margin: 0; -} - -html { - height: 100%; -} - -body { - height: 100%; - background-color: #404040; - background-image: url(../extlib/pdf.js/web/images/texture.png); -} - -body, -input, -button, -select { - font: message-box; -} - -.hidden { - display: none; -} -[hidden] { - display: none !important; -} - -#viewerContainer:-webkit-full-screen { - top: 0px; - border-top: 2px solid transparent; - background-color: #404040; - background-image: url(../extlib/pdf.js/web/images/texture.png); - width: 100%; - height: 100%; - overflow: hidden; - cursor: none; -} - -#viewerContainer:-moz-full-screen { - top: 0px; - border-top: 2px solid transparent; - background-color: #404040; - background-image: url(../extlib/pdf.js/web/images/texture.png); - width: 100%; - height: 100%; - overflow: hidden; - cursor: none; -} - -#viewerContainer:fullscreen { - top: 0px; - border-top: 2px solid transparent; - background-color: #404040; - background-image: url(../extlib/pdf.js/web/images/texture.png); - width: 100%; - height: 100%; - overflow: hidden; - cursor: none; -} - - -:-webkit-full-screen .page { - margin-bottom: 100%; -} - -:-moz-full-screen .page { - margin-bottom: 100%; -} - -:fullscreen .page { - margin-bottom: 100%; -} - -#viewerContainer.presentationControls { - cursor: default; -} - -/* outer/inner center provides horizontal center */ -html[dir='ltr'] .outerCenter { - float: right; - position: relative; - right: 50%; -} -html[dir='rtl'] .outerCenter { - float: left; - position: relative; - left: 50%; -} -html[dir='ltr'] .innerCenter { - float: right; - position: relative; - right: -50%; -} -html[dir='rtl'] .innerCenter { - float: left; - position: relative; - left: -50%; -} - -#outerContainer { - width: 100%; - height: 100%; -} - -#sidebarContainer { - left: 0; - right: 0; - height: 200px; - visibility: hidden; - -webkit-transition-duration: 200ms; - -webkit-transition-timing-function: ease; - -moz-transition-duration: 200ms; - -moz-transition-timing-function: ease; - -ms-transition-duration: 200ms; - -ms-transition-timing-function: ease; - -o-transition-duration: 200ms; - -o-transition-timing-function: ease; - transition-duration: 200ms; - transition-timing-function: ease; - -} -html[dir='ltr'] #sidebarContainer { - -webkit-transition-property: top; - -moz-transition-property: top; - -ms-transition-property: top; - -o-transition-property: top; - transition-property: top; - top: -200px; -} -html[dir='rtl'] #sidebarContainer { - -webkit-transition-property: top; - -ms-transition-property: top; - -o-transition-property: top; - transition-property: top; - top: -200px; -} - -#outerContainer.sidebarMoving > #sidebarContainer, -#outerContainer.sidebarOpen > #sidebarContainer { - visibility: visible; -} -html[dir='ltr'] #outerContainer.sidebarOpen > #sidebarContainer { - left: 0px; -} -html[dir='rtl'] #outerContainer.sidebarOpen > #sidebarContainer { - right: 0px; -} - -#mainContainer { - top: 0; - right: 0; - bottom: 0; - left: 0; - min-width: 320px; - -webkit-transition-duration: 200ms; - -webkit-transition-timing-function: ease; - -moz-transition-duration: 200ms; - -moz-transition-timing-function: ease; - -ms-transition-duration: 200ms; - -ms-transition-timing-function: ease; - -o-transition-duration: 200ms; - -o-transition-timing-function: ease; - transition-duration: 200ms; - transition-timing-function: ease; -} -html[dir='ltr'] #outerContainer.sidebarOpen > #mainContainer { - -webkit-transition-property: left; - -moz-transition-property: left; - -ms-transition-property: left; - -o-transition-property: left; - transition-property: left; - left: 200px; -} -html[dir='rtl'] #outerContainer.sidebarOpen > #mainContainer { - -webkit-transition-property: right; - -moz-transition-property: right; - -ms-transition-property: right; - -o-transition-property: right; - transition-property: right; - right: 200px; -} - -#sidebarContent { - top: 32px; - bottom: 0; - overflow: auto; - height: 200px; - - background-color: hsla(0,0%,0%,.1); - box-shadow: inset -1px 0 0 hsla(0,0%,0%,.25); -} -html[dir='ltr'] #sidebarContent { - left: 0; -} -html[dir='rtl'] #sidebarContent { - right: 0; -} - -#viewerContainer { - overflow: auto; - box-shadow: inset 1px 0 0 hsla(0,0%,100%,.05); - top: 32px; - right: 0; - bottom: 0; - left: 0; - height: 480px; - width: 640px; -} - -.toolbar { - left: 0; - right: 0; - height: 32px; - z-index: 9999; - cursor: default; -} - -#toolbarContainer { - width: 100%; -} - -#toolbarSidebar { - width: 200px; - height: 32px; - background-image: url(../extlib/pdf.js/web/images/texture.png), - -webkit-linear-gradient(hsla(0,0%,30%,.99), hsla(0,0%,25%,.95)); - background-image: url(../extlib/pdf.js/web/images/texture.png), - -moz-linear-gradient(hsla(0,0%,30%,.99), hsla(0,0%,25%,.95)); - background-image: url(../extlib/pdf.js/web/images/texture.png), - -ms-linear-gradient(hsla(0,0%,30%,.99), hsla(0,0%,25%,.95)); - background-image: url(../extlib/pdf.js/web/images/texture.png), - -o-linear-gradient(hsla(0,0%,30%,.99), hsla(0,0%,25%,.95)); - background-image: url(../extlib/pdf.js/web/images/texture.png), - linear-gradient(hsla(0,0%,30%,.99), hsla(0,0%,25%,.95)); - box-shadow: inset -1px 0 0 rgba(0, 0, 0, 0.25), - - inset 0 -1px 0 hsla(0,0%,100%,.05), - 0 1px 0 hsla(0,0%,0%,.15), - 0 0 1px hsla(0,0%,0%,.1); -} - -#toolbarViewer, .findbar { - position: relative; - height: 32px; - background-color: #474747; /* IE9 */ - background-image: url(../extlib/pdf.js/web/images/texture.png), - -webkit-linear-gradient(hsla(0,0%,32%,.99), hsla(0,0%,27%,.95)); - background-image: url(../extlib/pdf.js/web/images/texture.png), - -moz-linear-gradient(hsla(0,0%,32%,.99), hsla(0,0%,27%,.95)); - background-image: url(../extlib/pdf.js/web/images/texture.png), - -ms-linear-gradient(hsla(0,0%,32%,.99), hsla(0,0%,27%,.95)); - background-image: url(../extlib/pdf.js/web/images/texture.png), - -o-linear-gradient(hsla(0,0%,32%,.99), hsla(0,0%,27%,.95)); - background-image: url(../extlib/pdf.js/web/images/texture.png), - linear-gradient(hsla(0,0%,32%,.99), hsla(0,0%,27%,.95)); - box-shadow: inset 1px 0 0 hsla(0,0%,100%,.08), - inset 0 1px 1px hsla(0,0%,0%,.15), - inset 0 -1px 0 hsla(0,0%,100%,.05), - 0 1px 0 hsla(0,0%,0%,.15), - 0 1px 1px hsla(0,0%,0%,.1); -} - -.findbar { - top: 64px; - z-index: 10000; - height: 32px; - - min-width: 16px; - padding: 0px 6px 0px 6px; - margin: 4px 2px 4px 2px; - color: hsl(0,0%,85%); - font-size: 12px; - line-height: 14px; - text-align: left; - cursor: default; -} - -html[dir='ltr'] .findbar { - left: 68px; -} - -html[dir='rtl'] .findbar { - right: 68px; -} - -.findbar label { - -webkit-user-select: none; - -moz-user-select: none; -} - -#findInput[data-status="pending"] { - background-image: url(../extlib/pdf.js/web/images/loading-small.png); - background-repeat: no-repeat; - background-position: right; -} - -.doorHanger { - border: 1px solid hsla(0,0%,0%,.5); - border-radius: 2px; - box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3); -} -.doorHanger:after, .doorHanger:before { - bottom: 100%; - border: solid transparent; - content: " "; - height: 0; - width: 0; - pointer-events: none; -} -.doorHanger:after { - border-bottom-color: hsla(0,0%,32%,.99); - border-width: 8px; -} -.doorHanger:before { - border-bottom-color: hsla(0,0%,0%,.5); - border-width: 9px; -} - -html[dir='ltr'] .doorHanger:after { - left: 13px; - margin-left: -8px; -} - -html[dir='ltr'] .doorHanger:before { - left: 13px; - margin-left: -9px; -} - -html[dir='rtl'] .doorHanger:after { - right: 13px; - margin-right: -8px; -} - -html[dir='rtl'] .doorHanger:before { - right: 13px; - margin-right: -9px; -} - -#findMsg { - font-style: italic; - color: #A6B7D0; -} - -.notFound { - background-color: rgb(255, 137, 153); -} - -html[dir='ltr'] #toolbarViewerLeft { - margin-left: -1px; -} -html[dir='rtl'] #toolbarViewerRight { - margin-left: -1px; -} - - -html[dir='ltr'] #toolbarViewerLeft, -html[dir='rtl'] #toolbarViewerRight { - position: absolute; - top: 0; - left: 0; -} -html[dir='ltr'] #toolbarViewerRight, -html[dir='rtl'] #toolbarViewerLeft { - position: absolute; - top: 0; - right: 0; -} -html[dir='ltr'] #toolbarViewerLeft > *, -html[dir='ltr'] #toolbarViewerMiddle > *, -html[dir='ltr'] #toolbarViewerRight > *, -html[dir='ltr'] .findbar > * { - float: left; -} -html[dir='rtl'] #toolbarViewerLeft > *, -html[dir='rtl'] #toolbarViewerMiddle > *, -html[dir='rtl'] #toolbarViewerRight > *, -html[dir='rtl'] .findbar > * { - float: right; -} - -html[dir='ltr'] .splitToolbarButton { - margin: 3px 2px 4px 0; - display: inline-block; -} -html[dir='rtl'] .splitToolbarButton { - margin: 3px 0 4px 2px; - display: inline-block; -} -html[dir='ltr'] .splitToolbarButton > .toolbarButton { - border-radius: 0; - float: left; -} -html[dir='rtl'] .splitToolbarButton > .toolbarButton { - border-radius: 0; - float: right; -} - -.toolbarButton { - border: 0 none; - background-color: rgba(0, 0, 0, 0); - width: 32px; - height: 25px; -} - -.toolbarButton > span { - display: inline-block; - width: 0; - height: 0; - overflow: hidden; -} - -.toolbarButton[disabled] { - opacity: .5; -} - -.toolbarButton.group { - margin-right: 0; -} - -.splitToolbarButton.toggled .toolbarButton { - margin: 0; -} - -.splitToolbarButton:hover > .toolbarButton, -.splitToolbarButton:focus > .toolbarButton, -.splitToolbarButton.toggled > .toolbarButton, -.toolbarButton.textButton { - background-color: hsla(0,0%,0%,.12); - background-image: -webkit-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0)); - background-image: -moz-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0)); - background-image: -ms-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0)); - background-image: -o-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0)); - background-image: linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0)); - background-clip: padding-box; - border: 1px solid hsla(0,0%,0%,.35); - border-color: hsla(0,0%,0%,.32) hsla(0,0%,0%,.38) hsla(0,0%,0%,.42); - box-shadow: 0 1px 0 hsla(0,0%,100%,.05) inset, - 0 0 1px hsla(0,0%,100%,.15) inset, - 0 1px 0 hsla(0,0%,100%,.05); - -webkit-transition-property: background-color, border-color, box-shadow; - -webkit-transition-duration: 150ms; - -webkit-transition-timing-function: ease; - -moz-transition-property: background-color, border-color, box-shadow; - -moz-transition-duration: 150ms; - -moz-transition-timing-function: ease; - -ms-transition-property: background-color, border-color, box-shadow; - -ms-transition-duration: 150ms; - -ms-transition-timing-function: ease; - -o-transition-property: background-color, border-color, box-shadow; - -o-transition-duration: 150ms; - -o-transition-timing-function: ease; - transition-property: background-color, border-color, box-shadow; - transition-duration: 150ms; - transition-timing-function: ease; - -} -.splitToolbarButton > .toolbarButton:hover, -.splitToolbarButton > .toolbarButton:focus, -.dropdownToolbarButton:hover, -.toolbarButton.textButton:hover, -.toolbarButton.textButton:focus { - background-color: hsla(0,0%,0%,.2); - box-shadow: 0 1px 0 hsla(0,0%,100%,.05) inset, - 0 0 1px hsla(0,0%,100%,.15) inset, - 0 0 1px hsla(0,0%,0%,.05); - z-index: 199; -} -html[dir='ltr'] .splitToolbarButton > .toolbarButton:first-child, -html[dir='rtl'] .splitToolbarButton > .toolbarButton:last-child { - position: relative; - margin: 0; - margin-right: -1px; - border-top-left-radius: 2px; - border-bottom-left-radius: 2px; - border-right-color: transparent; -} -html[dir='ltr'] .splitToolbarButton > .toolbarButton:last-child, -html[dir='rtl'] .splitToolbarButton > .toolbarButton:first-child { - position: relative; - margin: 0; - margin-left: -1px; - border-top-right-radius: 2px; - border-bottom-right-radius: 2px; - border-left-color: transparent; -} -.splitToolbarButtonSeparator { - padding: 8px 0; - width: 1px; - background-color: hsla(0,0%,00%,.5); - z-index: 99; - box-shadow: 0 0 0 1px hsla(0,0%,100%,.08); - display: inline-block; - margin: 5px 0; -} -html[dir='ltr'] .splitToolbarButtonSeparator { - float: left; -} -html[dir='rtl'] .splitToolbarButtonSeparator { - float: right; -} -.splitToolbarButton:hover > .splitToolbarButtonSeparator, -.splitToolbarButton.toggled > .splitToolbarButtonSeparator { - padding: 12px 0; - margin: 1px 0; - box-shadow: 0 0 0 1px hsla(0,0%,100%,.03); - -webkit-transition-property: padding; - -webkit-transition-duration: 10ms; - -webkit-transition-timing-function: ease; - -moz-transition-property: padding; - -moz-transition-duration: 10ms; - -moz-transition-timing-function: ease; - -ms-transition-property: padding; - -ms-transition-duration: 10ms; - -ms-transition-timing-function: ease; - -o-transition-property: padding; - -o-transition-duration: 10ms; - -o-transition-timing-function: ease; - transition-property: padding; - transition-duration: 10ms; - transition-timing-function: ease; -} - -.toolbarButton, -.dropdownToolbarButton { - min-width: 16px; - padding: 2px 6px 0; - border: 1px solid transparent; - border-radius: 2px; - color: hsl(0,0%,95%); - font-size: 12px; - line-height: 14px; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - /* Opera does not support user-select, use <... unselectable="on"> instead */ - cursor: default; - -webkit-transition-property: background-color, border-color, box-shadow; - -webkit-transition-duration: 150ms; - -webkit-transition-timing-function: ease; - -moz-transition-property: background-color, border-color, box-shadow; - -moz-transition-duration: 150ms; - -moz-transition-timing-function: ease; - -ms-transition-property: background-color, border-color, box-shadow; - -ms-transition-duration: 150ms; - -ms-transition-timing-function: ease; - -o-transition-property: background-color, border-color, box-shadow; - -o-transition-duration: 150ms; - -o-transition-timing-function: ease; - transition-property: background-color, border-color, box-shadow; - transition-duration: 150ms; - transition-timing-function: ease; -} - -html[dir='ltr'] .toolbarButton, -html[dir='ltr'] .dropdownToolbarButton { - margin: 3px 2px 4px 0; -} -html[dir='rtl'] .toolbarButton, -html[dir='rtl'] .dropdownToolbarButton { - margin: 3px 0 4px 2px; -} - -.toolbarButton:hover, -.toolbarButton:focus, -.dropdownToolbarButton { - background-color: hsla(0,0%,0%,.12); - background-image: -webkit-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0)); - background-image: -moz-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0)); - background-image: -ms-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0)); - background-image: -o-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0)); - background-image: linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0)); - background-clip: padding-box; - border: 1px solid hsla(0,0%,0%,.35); - border-color: hsla(0,0%,0%,.32) hsla(0,0%,0%,.38) hsla(0,0%,0%,.42); - box-shadow: 0 1px 0 hsla(0,0%,100%,.05) inset, - 0 0 1px hsla(0,0%,100%,.15) inset, - 0 1px 0 hsla(0,0%,100%,.05); -} - -.toolbarButton:hover:active, -.dropdownToolbarButton:hover:active { - background-color: hsla(0,0%,0%,.2); - background-image: -webkit-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0)); - background-image: -moz-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0)); - background-image: -ms-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0)); - background-image: -o-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0)); - background-image: linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0)); - border-color: hsla(0,0%,0%,.35) hsla(0,0%,0%,.4) hsla(0,0%,0%,.45); - box-shadow: 0 1px 1px hsla(0,0%,0%,.1) inset, - 0 0 1px hsla(0,0%,0%,.2) inset, - 0 1px 0 hsla(0,0%,100%,.05); - -webkit-transition-property: background-color, border-color, box-shadow; - -webkit-transition-duration: 10ms; - -webkit-transition-timing-function: linear; - -moz-transition-property: background-color, border-color, box-shadow; - -moz-transition-duration: 10ms; - -moz-transition-timing-function: linear; - -ms-transition-property: background-color, border-color, box-shadow; - -ms-transition-duration: 10ms; - -ms-transition-timing-function: linear; - -o-transition-property: background-color, border-color, box-shadow; - -o-transition-duration: 10ms; - -o-transition-timing-function: linear; - transition-property: background-color, border-color, box-shadow; - transition-duration: 10ms; - transition-timing-function: linear; -} - -.toolbarButton.toggled, -.splitToolbarButton.toggled > .toolbarButton.toggled { - background-color: hsla(0,0%,0%,.3); - background-image: -webkit-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0)); - background-image: -moz-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0)); - background-image: -ms-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0)); - background-image: -o-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0)); - background-image: linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0)); - border-color: hsla(0,0%,0%,.4) hsla(0,0%,0%,.45) hsla(0,0%,0%,.5); - box-shadow: 0 1px 1px hsla(0,0%,0%,.1) inset, - 0 0 1px hsla(0,0%,0%,.2) inset, - 0 1px 0 hsla(0,0%,100%,.05); - -webkit-transition-property: background-color, border-color, box-shadow; - -webkit-transition-duration: 10ms; - -webkit-transition-timing-function: linear; - -moz-transition-property: background-color, border-color, box-shadow; - -moz-transition-duration: 10ms; - -moz-transition-timing-function: linear; - -ms-transition-property: background-color, border-color, box-shadow; - -ms-transition-duration: 10ms; - -ms-transition-timing-function: linear; - -o-transition-property: background-color, border-color, box-shadow; - -o-transition-duration: 10ms; - -o-transition-timing-function: linear; - transition-property: background-color, border-color, box-shadow; - transition-duration: 10ms; - transition-timing-function: linear; -} - -.toolbarButton.toggled:hover:active, -.splitToolbarButton.toggled > .toolbarButton.toggled:hover:active { - background-color: hsla(0,0%,0%,.4); - border-color: hsla(0,0%,0%,.4) hsla(0,0%,0%,.5) hsla(0,0%,0%,.55); - box-shadow: 0 1px 1px hsla(0,0%,0%,.2) inset, - 0 0 1px hsla(0,0%,0%,.3) inset, - 0 1px 0 hsla(0,0%,100%,.05); -} - -.dropdownToolbarButton { - width: 120px; - max-width: 120px; - padding: 3px 2px 2px; - overflow: hidden; - background: url(../extlib/pdf.js/web/images/toolbarButton-menuArrows.png) no-repeat; -} -html[dir='ltr'] .dropdownToolbarButton { - background-position: 95%; -} -html[dir='rtl'] .dropdownToolbarButton { - background-position: 5%; -} - -.dropdownToolbarButton > select { - -webkit-appearance: none; - -moz-appearance: none; /* in the future this might matter, see bugzilla bug #649849 */ - min-width: 140px; - font-size: 12px; - color: hsl(0,0%,95%); - margin: 0; - padding: 0; - border: none; - background: rgba(0,0,0,0); /* Opera does not support 'transparent' <select> background */ -} - -.dropdownToolbarButton > select > option { - background: hsl(0,0%,24%); -} - -#customScaleOption { - display: none; -} - -#pageWidthOption { - border-bottom: 1px rgba(255, 255, 255, .5) solid; -} - -html[dir='ltr'] .splitToolbarButton:first-child, -html[dir='ltr'] .toolbarButton:first-child, -html[dir='rtl'] .splitToolbarButton:last-child, -html[dir='rtl'] .toolbarButton:last-child { - margin-left: 4px; -} -html[dir='ltr'] .splitToolbarButton:last-child, -html[dir='ltr'] .toolbarButton:last-child, -html[dir='rtl'] .splitToolbarButton:first-child, -html[dir='rtl'] .toolbarButton:first-child { - margin-right: 4px; -} - -.toolbarButtonSpacer { - width: 30px; - display: inline-block; - height: 1px; -} - -.toolbarButtonFlexibleSpacer { - -webkit-box-flex: 1; - -moz-box-flex: 1; - min-width: 30px; -} - -.toolbarButton#sidebarToggle::before { - display: inline-block; - content: url(../extlib/pdf.js/web/images/toolbarButton-sidebarToggle.png); -} - -html[dir='ltr'] #findPrevious { - margin-left: 3px; -} -html[dir='ltr'] #findNext { - margin-right: 3px; -} - -html[dir='rtl'] #findPrevious { - margin-right: 3px; -} -html[dir='rtl'] #findNext { - margin-left: 3px; -} - -html[dir='ltr'] .toolbarButton.findPrevious::before { - display: inline-block; - content: url(../extlib/pdf.js/web/images/findbarButton-previous.png); -} - -html[dir='rtl'] .toolbarButton.findPrevious::before { - display: inline-block; - content: url(../extlib/pdf.js/web/images/findbarButton-previous-rtl.png); -} - -html[dir='ltr'] .toolbarButton.findNext::before { - display: inline-block; - content: url(../extlib/pdf.js/web/images/findbarButton-next.png); -} - -html[dir='rtl'] .toolbarButton.findNext::before { - display: inline-block; - content: url(../extlib/pdf.js/web/images/findbarButton-next-rtl.png); -} - -html[dir='ltr'] .toolbarButton.pageUp::before { - display: inline-block; - content: url(../extlib/pdf.js/web/images/toolbarButton-pageUp.png); -} - -html[dir='rtl'] .toolbarButton.pageUp::before { - display: inline-block; - content: url(../extlib/pdf.js/web/images/toolbarButton-pageUp-rtl.png); -} - -html[dir='ltr'] .toolbarButton.pageDown::before { - display: inline-block; - content: url(../extlib/pdf.js/web/images/toolbarButton-pageDown.png); -} - -html[dir='rtl'] .toolbarButton.pageDown::before { - display: inline-block; - content: url(../extlib/pdf.js/web/images/toolbarButton-pageDown-rtl.png); -} - -.toolbarButton.zoomOut::before { - display: inline-block; - content: url(../extlib/pdf.js/web/images/toolbarButton-zoomOut.png); -} - -.toolbarButton.zoomIn::before { - display: inline-block; - content: url(../extlib/pdf.js/web/images/toolbarButton-zoomIn.png); -} - -.toolbarButton.fullscreen::before { - display: inline-block; - content: url(../extlib/pdf.js/web/images/toolbarButton-fullscreen.png); -} - -.toolbarButton.print::before { - display: inline-block; - content: url(../extlib/pdf.js/web/images/toolbarButton-print.png); -} - -.toolbarButton.openFile::before { - display: inline-block; - content: url(../extlib/pdf.js/web/images/toolbarButton-openFile.png); -} - -.toolbarButton.download::before { - display: inline-block; - content: url(../extlib/pdf.js/web/images/toolbarButton-download.png); -} - -.toolbarButton.bookmark { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - margin-top: 3px; - padding-top: 4px; -} - -#viewBookmark[href='#'] { - opacity: .5; - pointer-events: none; -} - -.toolbarButton.bookmark::before { - content: url(../extlib/pdf.js/web/images/toolbarButton-bookmark.png); -} - -#viewThumbnail.toolbarButton::before { - display: inline-block; - content: url(../extlib/pdf.js/web/images/toolbarButton-viewThumbnail.png); -} - -#viewOutline.toolbarButton::before { - display: inline-block; - content: url(../extlib/pdf.js/web/images/toolbarButton-viewOutline.png); -} - -#viewFind.toolbarButton::before { - display: inline-block; - content: url(../extlib/pdf.js/web/images/toolbarButton-search.png); -} - - -.toolbarField { - padding: 3px 6px; - margin: 4px 0 4px 0; - border: 1px solid transparent; - border-radius: 2px; - background-color: hsla(0,0%,100%,.09); - background-image: -moz-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0)); - background-clip: padding-box; - border: 1px solid hsla(0,0%,0%,.35); - border-color: hsla(0,0%,0%,.32) hsla(0,0%,0%,.38) hsla(0,0%,0%,.42); - box-shadow: 0 1px 0 hsla(0,0%,0%,.05) inset, - 0 1px 0 hsla(0,0%,100%,.05); - color: hsl(0,0%,95%); - font-size: 12px; - line-height: 14px; - outline-style: none; - -moz-transition-property: background-color, border-color, box-shadow; - -moz-transition-duration: 150ms; - -moz-transition-timing-function: ease; -} - -.toolbarField[type=checkbox] { - display: inline-block; - margin: 8px 0px; -} - -.toolbarField.pageNumber { - min-width: 16px; - text-align: right; - width: 40px; -} - -.toolbarField.pageNumber::-webkit-inner-spin-button, -.toolbarField.pageNumber::-webkit-outer-spin-button { - -webkit-appearance: none; - margin: 0; -} - -.toolbarField:hover { - background-color: hsla(0,0%,100%,.11); - border-color: hsla(0,0%,0%,.4) hsla(0,0%,0%,.43) hsla(0,0%,0%,.45); -} - -.toolbarField:focus { - background-color: hsla(0,0%,100%,.15); - border-color: hsla(204,100%,65%,.8) hsla(204,100%,65%,.85) hsla(204,100%,65%,.9); -} - -.toolbarLabel { - min-width: 16px; - padding: 3px 6px 3px 2px; - margin: 4px 2px 4px 0; - border: 1px solid transparent; - border-radius: 2px; - color: hsl(0,0%,85%); - font-size: 12px; - line-height: 14px; - text-align: left; - -webkit-user-select: none; - -moz-user-select: none; - cursor: default; -} - -#thumbnailView { - top: 0; - bottom: 0; - padding: 10px 10px 0; - overflow: auto; -} - -.thumbnail { - float: left; -} - -.thumbnail:not([data-loaded]) { - border: 1px dashed rgba(255, 255, 255, 0.5); - margin-bottom: 10px; -} - -.thumbnailImage { - -moz-transition-duration: 150ms; - border: 1px solid transparent; - box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.5), 0 2px 8px rgba(0, 0, 0, 0.3); - opacity: 0.8; - z-index: 99; -} - -.thumbnailSelectionRing { - border-radius: 2px; - padding: 7px; - -moz-transition-duration: 150ms; -} - -a:focus > .thumbnail > .thumbnailSelectionRing > .thumbnailImage, -.thumbnail:hover > .thumbnailSelectionRing > .thumbnailImage { - opacity: .9; -} - -a:focus > .thumbnail > .thumbnailSelectionRing, -.thumbnail:hover > .thumbnailSelectionRing { - background-color: hsla(0,0%,100%,.15); - background-image: -moz-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0)); - background-clip: padding-box; - box-shadow: 0 1px 0 hsla(0,0%,100%,.05) inset, - 0 0 1px hsla(0,0%,100%,.2) inset, - 0 0 1px hsla(0,0%,0%,.2); - color: hsla(0,0%,100%,.9); -} - -.thumbnail.selected > .thumbnailSelectionRing > .thumbnailImage { - box-shadow: 0 0 0 1px hsla(0,0%,0%,.5); - opacity: 1; -} - -.thumbnail.selected > .thumbnailSelectionRing { - background-color: hsla(0,0%,100%,.3); - background-image: -moz-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0)); - background-clip: padding-box; - box-shadow: 0 1px 0 hsla(0,0%,100%,.05) inset, - 0 0 1px hsla(0,0%,100%,.1) inset, - 0 0 1px hsla(0,0%,0%,.2); - color: hsla(0,0%,100%,1); -} - -#outlineView { - width: 192px; - top: 0; - bottom: 0; - padding: 4px 4px 0; - overflow: auto; - -webkit-user-select: none; - -moz-user-select: none; -} - -html[dir='ltr'] .outlineItem > .outlineItems { - margin-left: 20px; -} - -html[dir='rtl'] .outlineItem > .outlineItems { - margin-right: 20px; -} - -.outlineItem > a { - text-decoration: none; - display: inline-block; - min-width: 95%; - height: auto; - margin-bottom: 1px; - border-radius: 2px; - color: hsla(0,0%,100%,.8); - font-size: 13px; - line-height: 15px; - -moz-user-select: none; - white-space: normal; -} - -html[dir='ltr'] .outlineItem > a { - padding: 2px 0 5px 10px; -} - -html[dir='rtl'] .outlineItem > a { - padding: 2px 10px 5px 0; -} - -.outlineItem > a:hover { - background-color: hsla(0,0%,100%,.02); - background-image: -moz-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0)); - background-clip: padding-box; - box-shadow: 0 1px 0 hsla(0,0%,100%,.05) inset, - 0 0 1px hsla(0,0%,100%,.2) inset, - 0 0 1px hsla(0,0%,0%,.2); - color: hsla(0,0%,100%,.9); -} - -.outlineItem.selected { - background-color: hsla(0,0%,100%,.08); - background-image: -moz-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0)); - background-clip: padding-box; - box-shadow: 0 1px 0 hsla(0,0%,100%,.05) inset, - 0 0 1px hsla(0,0%,100%,.1) inset, - 0 0 1px hsla(0,0%,0%,.2); - color: hsla(0,0%,100%,1); -} - -.noOutline, -.noResults { - font-size: 12px; - color: hsla(0,0%,100%,.8); - font-style: italic; - cursor: default; -} - -#findScrollView { - position: absolute; - top: 10px; - bottom: 10px; - left: 10px; - width: 280px; -} - -#sidebarControls { - position:absolute; - width: 180px; - height: 32px; - left: 15px; - bottom: 35px; -} - -canvas { - margin: auto; - display: block; -} - -.page { - direction: ltr; - width: 816px; - height: 1056px; - margin: 1px auto -8px auto; - position: relative; - overflow: visible; - border: 9px solid transparent; - background-clip: content-box; - border-image: url(../extlib/pdf.js/web/images/shadow.png) 9 9 repeat; - background-color: white; -} - -.page > a { - display: block; - position: absolute; -} - -.page > a:hover { - opacity: 0.2; - background: #ff0; - box-shadow: 0px 2px 10px #ff0; -} - -.loadingIcon { - position: absolute; - display: block; - left: 0; - top: 0; - right: 0; - bottom: 0; - background: url('../extlib/pdf.js/web/images/loading-icon.gif') center no-repeat; -} - -#loadingBox { - position: absolute; - top: 50%; - margin-top: -25px; - left: 0; - right: 0; - text-align: center; - color: #ddd; - font-size: 14px; -} - -#loadingBar { - display: inline-block; - clear: both; - margin: 0px; - margin-top: 5px; - line-height: 0; - border-radius: 2px; - width: 200px; - height: 25px; - - background-color: hsla(0,0%,0%,.3); - background-image: -moz-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0)); - background-image: -webkit-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0)); - border: 1px solid #000; - box-shadow: 0 1px 1px hsla(0,0%,0%,.1) inset, - 0 0 1px hsla(0,0%,0%,.2) inset, - 0 0 1px 1px rgba(255, 255, 255, 0.1); -} - -#loadingBar .progress { - display: inline-block; - float: left; - - background: #666; - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#b2b2b2), color-stop(100%,#898989)); - background: -webkit-linear-gradient(top, #b2b2b2 0%,#898989 100%); - background: -moz-linear-gradient(top, #b2b2b2 0%,#898989 100%); - background: -ms-linear-gradient(top, #b2b2b2 0%,#898989 100%); - background: -o-linear-gradient(top, #b2b2b2 0%,#898989 100%); - background: linear-gradient(top, #b2b2b2 0%,#898989 100%); - - border-top-left-radius: 2px; - border-bottom-left-radius: 2px; - - width: 0%; - height: 100%; -} - -#loadingBar .progress.full { - border-top-right-radius: 2px; - border-bottom-right-radius: 2px; -} - -#loadingBar .progress.indeterminate { - width: 100%; - height: 25px; - background-image: -moz-linear-gradient( 30deg, #404040, #404040 15%, #898989, #404040 85%, #404040); - background-image: -webkit-linear-gradient( 30deg, #404040, #404040 15%, #898989, #404040 85%, #404040); - background-image: -ms-linear-gradient( 30deg, #404040, #404040 15%, #898989, #404040 85%, #404040); - background-image: -o-linear-gradient( 30deg, #404040, #404040 15%, #898989, #404040 85%, #404040); - background-size: 75px 25px; - -moz-animation: progressIndeterminate 1s linear infinite; - -webkit-animation: progressIndeterminate 1s linear infinite; -} - -@-moz-keyframes progressIndeterminate { - from { background-position: 0px 0px; } - to { background-position: 75px 0px; } -} - -@-webkit-keyframes progressIndeterminate { - from { background-position: 0px 0px; } - to { background-position: 75px 0px; } -} - -.textLayer { - position: absolute; - left: 0; - top: 0; - right: 0; - bottom: 0; - color: #000; - font-family: sans-serif; - overflow: hidden; -} - -.textLayer > div { - color: transparent; - position: absolute; - line-height: 1; - white-space: pre; - cursor: text; -} - -.textLayer .highlight { - margin: -1px; - padding: 1px; - - background-color: rgba(180, 0, 170, 0.2); - border-radius: 4px; -} - -.textLayer .highlight.begin { - border-radius: 4px 0px 0px 4px; -} - -.textLayer .highlight.end { - border-radius: 0px 4px 4px 0px; -} - -.textLayer .highlight.middle { - border-radius: 0px; -} - -.textLayer .highlight.selected { - background-color: rgba(0, 100, 0, 0.2); -} - -/* TODO: file FF bug to support ::-moz-selection:window-inactive - so we can override the opaque grey background when the window is inactive; - see https://bugzilla.mozilla.org/show_bug.cgi?id=706209 */ -::selection { background:rgba(0,0,255,0.3); } -::-moz-selection { background:rgba(0,0,255,0.3); } - -.annotText > div { - z-index: 200; - position: absolute; - padding: 0.6em; - max-width: 20em; - background-color: #FFFF99; - box-shadow: 0px 2px 10px #333; - border-radius: 7px; -} - -.annotText > img { - position: absolute; - opacity: 0.6; -} - -.annotText > img:hover { - cursor: pointer; - opacity: 1; -} - -.annotText > div > h1 { - font-size: 1.2em; - border-bottom: 1px solid #000000; - margin: 0px; -} - -#errorWrapper { - background: none repeat scroll 0 0 #FF5555; - color: white; - left: 0; - position: absolute; - right: 0; - top: 32px; - z-index: 1000; - padding: 3px; - font-size: 0.8em; -} - -#errorMessageLeft { - float: left; -} - -#errorMessageRight { - float: right; -} - -#errorMoreInfo { - background-color: #FFFFFF; - color: black; - padding: 3px; - margin: 3px; - width: 98%; -} - -.clearBoth { - clear: both; -} - -.fileInput { - background: white; - color: black; - margin-top: 5px; -} - -#PDFBug { - background: none repeat scroll 0 0 white; - border: 1px solid #666666; - position: fixed; - top: 32px; - right: 0; - bottom: 0; - font-size: 10px; - padding: 0; - width: 300px; -} -#PDFBug .controls { - background:#EEEEEE; - border-bottom: 1px solid #666666; - padding: 3px; -} -#PDFBug .panels { - bottom: 0; - left: 0; - overflow: auto; - position: absolute; - right: 0; - top: 27px; -} -#PDFBug button.active { - font-weight: bold; -} -.debuggerShowText { - background: none repeat scroll 0 0 yellow; - color: blue; - opacity: 0.3; -} -.debuggerHideText:hover { - background: none repeat scroll 0 0 yellow; - opacity: 0.3; -} -#PDFBug .stats { - font-family: courier; - font-size: 10px; - white-space: pre; -} -#PDFBug .stats .title { - font-weight: bold; -} -#PDFBug table { - font-size: 10px; -} - -#viewer.textLayer-visible .textLayer > div, -#viewer.textLayer-hover .textLayer > div:hover { - background-color: white; - color: black; -} - -#viewer.textLayer-shadow .textLayer > div { - background-color: rgba(255,255,255, .6); - color: black; -} - -@page { - margin: 0; -} - -#printContainer { - display: none; -} - -@media print { - /* Rules for browsers that don't support mozPrintCallback. */ - #sidebarContainer, .toolbar, #loadingBox, #errorWrapper, .textLayer { - display: none; - } - - #mainContainer, #viewerContainer, .page, .page canvas { - position: static; - padding: 0; - margin: 0; - } - - .page { - float: left; - display: none; - box-shadow: none; - } - - .page[data-loaded] { - display: block; - } - - /* Rules for browsers that support mozPrintCallback */ - body[data-mozPrintCallback] #outerContainer { - display: none; - } - body[data-mozPrintCallback] #printContainer { - display: block; - } - #printContainer canvas { - position: relative; - top: 0; - left: 0; - } -} - -@media all and (max-width: 950px) { - html[dir='ltr'] #outerContainer.sidebarMoving .outerCenter, - html[dir='ltr'] #outerContainer.sidebarOpen .outerCenter { - float: left; - left: 180px; - } - html[dir='rtl'] #outerContainer.sidebarMoving .outerCenter, - html[dir='rtl'] #outerContainer.sidebarOpen .outerCenter { - float: right; - right: 180px; - } -} - -@media all and (max-width: 770px) { - #sidebarContainer { - top: 33px; - z-index: 100; - } - #sidebarContent { - top: 32px; - background-color: hsla(0,0%,0%,.7); - } - - html[dir='ltr'] #outerContainer.sidebarOpen > #mainContainer { - left: 0px; - } - html[dir='rtl'] #outerContainer.sidebarOpen > #mainContainer { - right: 0px; - } - - html[dir='ltr'] .outerCenter { - float: left; - left: 180px; - } - html[dir='rtl'] .outerCenter { - float: right; - right: 180px; - } -} - -@media all and (max-width: 600px) { - .hiddenSmallView { - display: none; - } - html[dir='ltr'] .outerCenter { - left: 156px; - } - html[dir='rtr'] .outerCenter { - right: 156px; - } - .toolbarButtonSpacer { - width: 0; - } -} - -@media all and (max-width: 500px) { - #scaleSelectContainer, #pageNumberLabel { - display: none; - } -} - diff --git a/mediagoblin/static/js/pdf_viewer.js b/mediagoblin/static/js/pdf_viewer.js deleted file mode 100644 index 79c1e708..00000000 --- a/mediagoblin/static/js/pdf_viewer.js +++ /dev/null @@ -1,3615 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ -/* Copyright 2012 Mozilla Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* globals PDFJS, PDFBug, FirefoxCom, Stats */ - -'use strict'; - -var DEFAULT_SCALE = 'auto'; -var DEFAULT_SCALE_DELTA = 1.1; -var UNKNOWN_SCALE = 0; -var CACHE_SIZE = 20; -var CSS_UNITS = 96.0 / 72.0; -var SCROLLBAR_PADDING = 40; -var VERTICAL_PADDING = 5; -var MIN_SCALE = 0.25; -var MAX_SCALE = 4.0; -var IMAGE_DIR = './images/'; -var SETTINGS_MEMORY = 20; -var ANNOT_MIN_SIZE = 10; -var RenderingStates = { - INITIAL: 0, - RUNNING: 1, - PAUSED: 2, - FINISHED: 3 -}; -var FindStates = { - FIND_FOUND: 0, - FIND_NOTFOUND: 1, - FIND_WRAPPED: 2, - FIND_PENDING: 3 -}; - -//#if (FIREFOX || MOZCENTRAL || B2G || GENERIC || CHROME) -//PDFJS.workerSrc = '../build/pdf.js'; -//#endif - -var mozL10n = document.mozL10n || document.webL10n; - -function getFileName(url) { - var anchor = url.indexOf('#'); - var query = url.indexOf('?'); - var end = Math.min( - anchor > 0 ? anchor : url.length, - query > 0 ? query : url.length); - return url.substring(url.lastIndexOf('/', end) + 1, end); -} - -function scrollIntoView(element, spot) { - // Assuming offsetParent is available (it's not available when viewer is in - // hidden iframe or object). We have to scroll: if the offsetParent is not set - // producing the error. See also animationStartedClosure. - var parent = element.offsetParent; - var offsetY = element.offsetTop + element.clientTop; - if (!parent) { - console.error('offsetParent is not set -- cannot scroll'); - return; - } - while (parent.clientHeight == parent.scrollHeight) { - offsetY += parent.offsetTop; - parent = parent.offsetParent; - if (!parent) - return; // no need to scroll - } - if (spot) - offsetY += spot.top; - parent.scrollTop = offsetY; -} - -var Cache = function cacheCache(size) { - var data = []; - this.push = function cachePush(view) { - var i = data.indexOf(view); - if (i >= 0) - data.splice(i); - data.push(view); - if (data.length > size) - data.shift().destroy(); - }; -}; - -var ProgressBar = (function ProgressBarClosure() { - - function clamp(v, min, max) { - return Math.min(Math.max(v, min), max); - } - - function ProgressBar(id, opts) { - - // Fetch the sub-elements for later - this.div = document.querySelector(id + ' .progress'); - - // Get options, with sensible defaults - this.height = opts.height || 100; - this.width = opts.width || 100; - this.units = opts.units || '%'; - - // Initialize heights - this.div.style.height = this.height + this.units; - } - - ProgressBar.prototype = { - - updateBar: function ProgressBar_updateBar() { - if (this._indeterminate) { - this.div.classList.add('indeterminate'); - return; - } - - var progressSize = this.width * this._percent / 100; - - if (this._percent > 95) - this.div.classList.add('full'); - else - this.div.classList.remove('full'); - this.div.classList.remove('indeterminate'); - - this.div.style.width = progressSize + this.units; - }, - - get percent() { - return this._percent; - }, - - set percent(val) { - this._indeterminate = isNaN(val); - this._percent = clamp(val, 0, 100); - this.updateBar(); - } - }; - - return ProgressBar; -})(); - -//#if FIREFOX || MOZCENTRAL -//#include firefoxcom.js -//#endif - -// Settings Manager - This is a utility for saving settings -// First we see if localStorage is available -// If not, we use FUEL in FF -// Use asyncStorage for B2G -var Settings = (function SettingsClosure() { -//#if !(FIREFOX || MOZCENTRAL || B2G) - var isLocalStorageEnabled = (function localStorageEnabledTest() { - // Feature test as per http://diveintohtml5.info/storage.html - // The additional localStorage call is to get around a FF quirk, see - // bug #495747 in bugzilla - try { - return 'localStorage' in window && window['localStorage'] !== null && - localStorage; - } catch (e) { - return false; - } - })(); -//#endif - - function Settings(fingerprint) { - this.fingerprint = fingerprint; - this.initializedPromise = new PDFJS.Promise(); - - var resolvePromise = (function settingsResolvePromise(db) { - this.initialize(db || '{}'); - this.initializedPromise.resolve(); - }).bind(this); - -//#if B2G -// asyncStorage.getItem('database', resolvePromise); -//#endif - -//#if FIREFOX || MOZCENTRAL -// resolvePromise(FirefoxCom.requestSync('getDatabase', null)); -//#endif - -//#if !(FIREFOX || MOZCENTRAL || B2G) - if (isLocalStorageEnabled) - resolvePromise(localStorage.getItem('database')); -//#endif - } - - Settings.prototype = { - initialize: function settingsInitialize(database) { - database = JSON.parse(database); - if (!('files' in database)) - database.files = []; - if (database.files.length >= SETTINGS_MEMORY) - database.files.shift(); - var index; - for (var i = 0, length = database.files.length; i < length; i++) { - var branch = database.files[i]; - if (branch.fingerprint == this.fingerprint) { - index = i; - break; - } - } - if (typeof index != 'number') - index = database.files.push({fingerprint: this.fingerprint}) - 1; - this.file = database.files[index]; - this.database = database; - }, - - set: function settingsSet(name, val) { - if (!this.initializedPromise.isResolved) - return; - - var file = this.file; - file[name] = val; - var database = JSON.stringify(this.database); - -//#if B2G -// asyncStorage.setItem('database', database); -//#endif - -//#if FIREFOX || MOZCENTRAL -// FirefoxCom.requestSync('setDatabase', database); -//#endif - -//#if !(FIREFOX || MOZCENTRAL || B2G) - if (isLocalStorageEnabled) - localStorage.setItem('database', database); -//#endif - }, - - get: function settingsGet(name, defaultValue) { - if (!this.initializedPromise.isResolved) - return defaultValue; - - return this.file[name] || defaultValue; - } - }; - - return Settings; -})(); - -var cache = new Cache(CACHE_SIZE); -var currentPageNumber = 1; - -var PDFFindController = { - startedTextExtraction: false, - - extractTextPromises: [], - - // If active, find results will be highlighted. - active: false, - - // Stores the text for each page. - pageContents: [], - - pageMatches: [], - - // Currently selected match. - selected: { - pageIdx: -1, - matchIdx: -1 - }, - - // Where find algorithm currently is in the document. - offset: { - pageIdx: null, - matchIdx: null - }, - - resumePageIdx: null, - - resumeCallback: null, - - state: null, - - dirtyMatch: false, - - findTimeout: null, - - initialize: function() { - var events = [ - 'find', - 'findagain', - 'findhighlightallchange', - 'findcasesensitivitychange' - ]; - - this.handleEvent = this.handleEvent.bind(this); - - for (var i = 0; i < events.length; i++) { - window.addEventListener(events[i], this.handleEvent); - } - }, - - calcFindMatch: function(pageIndex) { - var pageContent = this.pageContents[pageIndex]; - var query = this.state.query; - var caseSensitive = this.state.caseSensitive; - var queryLen = query.length; - - if (queryLen === 0) { - // Do nothing the matches should be wiped out already. - return; - } - - if (!caseSensitive) { - pageContent = pageContent.toLowerCase(); - query = query.toLowerCase(); - } - - var matches = []; - - var matchIdx = -queryLen; - while (true) { - matchIdx = pageContent.indexOf(query, matchIdx + queryLen); - if (matchIdx === -1) { - break; - } - - matches.push(matchIdx); - } - this.pageMatches[pageIndex] = matches; - this.updatePage(pageIndex); - if (this.resumePageIdx === pageIndex) { - var callback = this.resumeCallback; - this.resumePageIdx = null; - this.resumeCallback = null; - callback(); - } - }, - - extractText: function() { - if (this.startedTextExtraction) { - return; - } - this.startedTextExtraction = true; - - this.pageContents = []; - for (var i = 0, ii = PDFView.pdfDocument.numPages; i < ii; i++) { - this.extractTextPromises.push(new PDFJS.Promise()); - } - - var self = this; - function extractPageText(pageIndex) { - PDFView.pages[pageIndex].getTextContent().then( - function textContentResolved(data) { - // Build the find string. - var bidiTexts = data.bidiTexts; - var str = ''; - - for (var i = 0; i < bidiTexts.length; i++) { - str += bidiTexts[i].str; - } - - // Store the pageContent as a string. - self.pageContents.push(str); - - self.extractTextPromises[pageIndex].resolve(pageIndex); - if ((pageIndex + 1) < PDFView.pages.length) - extractPageText(pageIndex + 1); - } - ); - } - extractPageText(0); - return this.extractTextPromise; - }, - - handleEvent: function(e) { - if (this.state === null || e.type !== 'findagain') { - this.dirtyMatch = true; - } - this.state = e.detail; - this.updateUIState(FindStates.FIND_PENDING); - - this.extractText(); - - clearTimeout(this.findTimeout); - if (e.type === 'find') { - // Only trigger the find action after 250ms of silence. - this.findTimeout = setTimeout(this.nextMatch.bind(this), 250); - } else { - this.nextMatch(); - } - }, - - updatePage: function(idx) { - var page = PDFView.pages[idx]; - - if (this.selected.pageIdx === idx) { - // If the page is selected, scroll the page into view, which triggers - // rendering the page, which adds the textLayer. Once the textLayer is - // build, it will scroll onto the selected match. - page.scrollIntoView(); - } - - if (page.textLayer) { - page.textLayer.updateMatches(); - } - }, - - nextMatch: function() { - var pages = PDFView.pages; - var previous = this.state.findPrevious; - var numPages = PDFView.pages.length; - - this.active = true; - - if (this.dirtyMatch) { - // Need to recalculate the matches, reset everything. - this.dirtyMatch = false; - this.selected.pageIdx = this.selected.matchIdx = -1; - this.offset.pageIdx = previous ? numPages - 1 : 0; - this.offset.matchIdx = null; - this.hadMatch = false; - this.resumeCallback = null; - this.resumePageIdx = null; - this.pageMatches = []; - var self = this; - - for (var i = 0; i < numPages; i++) { - // Wipe out any previous highlighted matches. - this.updatePage(i); - - // As soon as the text is extracted start finding the matches. - this.extractTextPromises[i].onData(function(pageIdx) { - // Use a timeout since all the pages may already be extracted and we - // want to start highlighting before finding all the matches. - setTimeout(function() { - self.calcFindMatch(pageIdx); - }); - }); - } - } - - // If there's no query there's no point in searching. - if (this.state.query === '') { - this.updateUIState(FindStates.FIND_FOUND); - return; - } - - // If we're waiting on a page, we return since we can't do anything else. - if (this.resumeCallback) { - return; - } - - var offset = this.offset; - // If there's already a matchIdx that means we are iterating through a - // page's matches. - if (offset.matchIdx !== null) { - var numPageMatches = this.pageMatches[offset.pageIdx].length; - if ((!previous && offset.matchIdx + 1 < numPageMatches) || - (previous && offset.matchIdx > 0)) { - // The simple case, we just have advance the matchIdx to select the next - // match on the page. - this.hadMatch = true; - offset.matchIdx = previous ? offset.matchIdx - 1 : offset.matchIdx + 1; - this.updateMatch(true); - return; - } - // We went beyond the current page's matches, so we advance to the next - // page. - this.advanceOffsetPage(previous); - } - // Start searching through the page. - this.nextPageMatch(); - }, - - nextPageMatch: function() { - if (this.resumePageIdx !== null) - console.error('There can only be one pending page.'); - - var matchesReady = function(matches) { - var offset = this.offset; - var numMatches = matches.length; - var previous = this.state.findPrevious; - if (numMatches) { - // There were matches for the page, so initialize the matchIdx. - this.hadMatch = true; - offset.matchIdx = previous ? numMatches - 1 : 0; - this.updateMatch(true); - } else { - // No matches attempt to search the next page. - this.advanceOffsetPage(previous); - if (offset.wrapped) { - offset.matchIdx = null; - if (!this.hadMatch) { - // No point in wrapping there were no matches. - this.updateMatch(false); - return; - } - } - // Search the next page. - this.nextPageMatch(); - } - }.bind(this); - - var pageIdx = this.offset.pageIdx; - var pageMatches = this.pageMatches; - if (!pageMatches[pageIdx]) { - // The matches aren't ready setup a callback so we can be notified, - // when they are ready. - this.resumeCallback = function() { - matchesReady(pageMatches[pageIdx]); - }; - this.resumePageIdx = pageIdx; - return; - } - // The matches are finished already. - matchesReady(pageMatches[pageIdx]); - }, - - advanceOffsetPage: function(previous) { - var offset = this.offset; - var numPages = this.extractTextPromises.length; - offset.pageIdx = previous ? offset.pageIdx - 1 : offset.pageIdx + 1; - offset.matchIdx = null; - if (offset.pageIdx >= numPages || offset.pageIdx < 0) { - offset.pageIdx = previous ? numPages - 1 : 0; - offset.wrapped = true; - return; - } - }, - - updateMatch: function(found) { - var state = FindStates.FIND_NOTFOUND; - var wrapped = this.offset.wrapped; - this.offset.wrapped = false; - if (found) { - var previousPage = this.selected.pageIdx; - this.selected.pageIdx = this.offset.pageIdx; - this.selected.matchIdx = this.offset.matchIdx; - state = wrapped ? FindStates.FIND_WRAPPED : FindStates.FIND_FOUND; - // Update the currently selected page to wipe out any selected matches. - if (previousPage !== -1 && previousPage !== this.selected.pageIdx) { - this.updatePage(previousPage); - } - } - this.updateUIState(state, this.state.findPrevious); - if (this.selected.pageIdx !== -1) { - this.updatePage(this.selected.pageIdx, true); - } - }, - - updateUIState: function(state, previous) { - if (PDFView.supportsIntegratedFind) { - FirefoxCom.request('updateFindControlState', - {result: state, findPrevious: previous}); - return; - } - PDFFindBar.updateUIState(state, previous); - } -}; - -var PDFFindBar = { - // TODO: Enable the FindBar *AFTER* the pagesPromise in the load function - // got resolved - - opened: false, - - initialize: function() { - this.bar = document.getElementById('findbar'); - this.toggleButton = document.getElementById('viewFind'); - this.findField = document.getElementById('findInput'); - this.highlightAll = document.getElementById('findHighlightAll'); - this.caseSensitive = document.getElementById('findMatchCase'); - this.findMsg = document.getElementById('findMsg'); - this.findStatusIcon = document.getElementById('findStatusIcon'); - - var self = this; - this.toggleButton.addEventListener('click', function() { - self.toggle(); - }); - - this.findField.addEventListener('input', function() { - self.dispatchEvent(''); - }); - - this.bar.addEventListener('keydown', function(evt) { - switch (evt.keyCode) { - case 13: // Enter - if (evt.target === self.findField) { - self.dispatchEvent('again', evt.shiftKey); - } - break; - case 27: // Escape - self.close(); - break; - } - }); - - document.getElementById('findPrevious').addEventListener('click', - function() { self.dispatchEvent('again', true); } - ); - - document.getElementById('findNext').addEventListener('click', function() { - self.dispatchEvent('again', false); - }); - - this.highlightAll.addEventListener('click', function() { - self.dispatchEvent('highlightallchange'); - }); - - this.caseSensitive.addEventListener('click', function() { - self.dispatchEvent('casesensitivitychange'); - }); - }, - - dispatchEvent: function(aType, aFindPrevious) { - var event = document.createEvent('CustomEvent'); - event.initCustomEvent('find' + aType, true, true, { - query: this.findField.value, - caseSensitive: this.caseSensitive.checked, - highlightAll: this.highlightAll.checked, - findPrevious: aFindPrevious - }); - return window.dispatchEvent(event); - }, - - updateUIState: function(state, previous) { - var notFound = false; - var findMsg = ''; - var status = ''; - - switch (state) { - case FindStates.FIND_FOUND: - break; - - case FindStates.FIND_PENDING: - status = 'pending'; - break; - - case FindStates.FIND_NOTFOUND: - findMsg = mozL10n.get('find_not_found', null, 'Phrase not found'); - notFound = true; - break; - - case FindStates.FIND_WRAPPED: - if (previous) { - findMsg = mozL10n.get('find_reached_top', null, - 'Reached top of document, continued from bottom'); - } else { - findMsg = mozL10n.get('find_reached_bottom', null, - 'Reached end of document, continued from top'); - } - break; - } - - if (notFound) { - this.findField.classList.add('notFound'); - } else { - this.findField.classList.remove('notFound'); - } - - this.findField.setAttribute('data-status', status); - this.findMsg.textContent = findMsg; - }, - - open: function() { - if (this.opened) return; - - this.opened = true; - this.toggleButton.classList.add('toggled'); - this.bar.classList.remove('hidden'); - this.findField.select(); - this.findField.focus(); - }, - - close: function() { - if (!this.opened) return; - - this.opened = false; - this.toggleButton.classList.remove('toggled'); - this.bar.classList.add('hidden'); - - PDFFindController.active = false; - }, - - toggle: function() { - if (this.opened) { - this.close(); - } else { - this.open(); - } - } -}; - -var PDFView = { - pages: [], - thumbnails: [], - currentScale: UNKNOWN_SCALE, - currentScaleValue: null, - initialBookmark: document.location.hash.substring(1), - startedTextExtraction: false, - pageText: [], - container: null, - thumbnailContainer: null, - initialized: false, - fellback: false, - pdfDocument: null, - sidebarOpen: false, - pageViewScroll: null, - thumbnailViewScroll: null, - isFullscreen: false, - previousScale: null, - pageRotation: 0, - mouseScrollTimeStamp: 0, - mouseScrollDelta: 0, - lastScroll: 0, - previousPageNumber: 1, - - // called once when the document is loaded - initialize: function pdfViewInitialize() { - var self = this; - var container = this.container = document.getElementById('viewerContainer'); - this.pageViewScroll = {}; - this.watchScroll(container, this.pageViewScroll, updateViewarea); - - var thumbnailContainer = this.thumbnailContainer = - document.getElementById('thumbnailView'); - this.thumbnailViewScroll = {}; - this.watchScroll(thumbnailContainer, this.thumbnailViewScroll, - this.renderHighestPriority.bind(this)); - - PDFFindBar.initialize(); - PDFFindController.initialize(); - - this.initialized = true; - container.addEventListener('scroll', function() { - self.lastScroll = Date.now(); - }, false); - }, - - getPage: function pdfViewGetPage(n) { - return this.pdfDocument.getPage(n); - }, - - // Helper function to keep track whether a div was scrolled up or down and - // then call a callback. - watchScroll: function pdfViewWatchScroll(viewAreaElement, state, callback) { - state.down = true; - state.lastY = viewAreaElement.scrollTop; - viewAreaElement.addEventListener('scroll', function webViewerScroll(evt) { - var currentY = viewAreaElement.scrollTop; - var lastY = state.lastY; - if (currentY > lastY) - state.down = true; - else if (currentY < lastY) - state.down = false; - // else do nothing and use previous value - state.lastY = currentY; - callback(); - }, true); - }, - - setScale: function pdfViewSetScale(val, resetAutoSettings, noScroll) { - if (val == this.currentScale) - return; - - var pages = this.pages; - for (var i = 0; i < pages.length; i++) - pages[i].update(val * CSS_UNITS); - - if (!noScroll && this.currentScale != val) - this.pages[this.page - 1].scrollIntoView(); - this.currentScale = val; - - var event = document.createEvent('UIEvents'); - event.initUIEvent('scalechange', false, false, window, 0); - event.scale = val; - event.resetAutoSettings = resetAutoSettings; - window.dispatchEvent(event); - }, - - parseScale: function pdfViewParseScale(value, resetAutoSettings, noScroll) { - if ('custom' == value) - return; - - var scale = parseFloat(value); - this.currentScaleValue = value; - if (scale) { - this.setScale(scale, true, noScroll); - return; - } - - var container = this.container; - var currentPage = this.pages[this.page - 1]; - if (!currentPage) { - return; - } - - var pageWidthScale = (container.clientWidth - SCROLLBAR_PADDING) / - currentPage.width * currentPage.scale / CSS_UNITS; - var pageHeightScale = (container.clientHeight - VERTICAL_PADDING) / - currentPage.height * currentPage.scale / CSS_UNITS; - switch (value) { - case 'page-actual': - scale = 1; - break; - case 'page-width': - scale = pageWidthScale; - break; - case 'page-height': - scale = pageHeightScale; - break; - case 'page-fit': - scale = Math.min(pageWidthScale, pageHeightScale); - break; - case 'auto': - scale = Math.min(1.0, pageWidthScale); - break; - } - this.setScale(scale, resetAutoSettings, noScroll); - - selectScaleOption(value); - }, - - zoomIn: function pdfViewZoomIn() { - var newScale = (this.currentScale * DEFAULT_SCALE_DELTA).toFixed(2); - newScale = Math.ceil(newScale * 10) / 10; - newScale = Math.min(MAX_SCALE, newScale); - this.parseScale(newScale, true); - }, - - zoomOut: function pdfViewZoomOut() { - var newScale = (this.currentScale / DEFAULT_SCALE_DELTA).toFixed(2); - newScale = Math.floor(newScale * 10) / 10; - newScale = Math.max(MIN_SCALE, newScale); - this.parseScale(newScale, true); - }, - - set page(val) { - var pages = this.pages; - var input = document.getElementById('pageNumber'); - var event = document.createEvent('UIEvents'); - event.initUIEvent('pagechange', false, false, window, 0); - - if (!(0 < val && val <= pages.length)) { - this.previousPageNumber = val; - event.pageNumber = this.page; - window.dispatchEvent(event); - return; - } - - pages[val - 1].updateStats(); - this.previousPageNumber = currentPageNumber; - currentPageNumber = val; - event.pageNumber = val; - window.dispatchEvent(event); - - // checking if the this.page was called from the updateViewarea function: - // avoiding the creation of two "set page" method (internal and public) - if (updateViewarea.inProgress) - return; - - // Avoid scrolling the first page during loading - if (this.loading && val == 1) - return; - - pages[val - 1].scrollIntoView(); - }, - - get page() { - return currentPageNumber; - }, - - get supportsPrinting() { - var canvas = document.createElement('canvas'); - var value = 'mozPrintCallback' in canvas; - // shadow - Object.defineProperty(this, 'supportsPrinting', { value: value, - enumerable: true, - configurable: true, - writable: false }); - return value; - }, - - get supportsFullscreen() { - var doc = document.documentElement; - var support = doc.requestFullscreen || doc.mozRequestFullScreen || - doc.webkitRequestFullScreen; - - // Disable fullscreen button if we're in an iframe - if (!!window.frameElement) - support = false; - - Object.defineProperty(this, 'supportsFullScreen', { value: support, - enumerable: true, - configurable: true, - writable: false }); - return support; - }, - - get supportsIntegratedFind() { - var support = false; -//#if !(FIREFOX || MOZCENTRAL) -//#else -// support = FirefoxCom.requestSync('supportsIntegratedFind'); -//#endif - Object.defineProperty(this, 'supportsIntegratedFind', { value: support, - enumerable: true, - configurable: true, - writable: false }); - return support; - }, - - get supportsDocumentFonts() { - var support = true; -//#if !(FIREFOX || MOZCENTRAL) -//#else -// support = FirefoxCom.requestSync('supportsDocumentFonts'); -//#endif - Object.defineProperty(this, 'supportsDocumentFonts', { value: support, - enumerable: true, - configurable: true, - writable: false }); - return support; - }, - - get isHorizontalScrollbarEnabled() { - var div = document.getElementById('viewerContainer'); - return div.scrollWidth > div.clientWidth; - }, - - initPassiveLoading: function pdfViewInitPassiveLoading() { - if (!PDFView.loadingBar) { - PDFView.loadingBar = new ProgressBar('#loadingBar', {}); - } - - window.addEventListener('message', function window_message(e) { - var args = e.data; - - if (typeof args !== 'object' || !('pdfjsLoadAction' in args)) - return; - switch (args.pdfjsLoadAction) { - case 'progress': - PDFView.progress(args.loaded / args.total); - break; - case 'complete': - if (!args.data) { - PDFView.error(mozL10n.get('loading_error', null, - 'An error occurred while loading the PDF.'), e); - break; - } - PDFView.open(args.data, 0); - break; - } - }); - FirefoxCom.requestSync('initPassiveLoading', null); - }, - - setTitleUsingUrl: function pdfViewSetTitleUsingUrl(url) { - this.url = url; - try { - this.setTitle(decodeURIComponent(getFileName(url)) || url); - } catch (e) { - // decodeURIComponent may throw URIError, - // fall back to using the unprocessed url in that case - this.setTitle(url); - } - }, - - setTitle: function pdfViewSetTitle(title) { - document.title = title; -//#if B2G -// document.getElementById('activityTitle').textContent = title; -//#endif - }, - - open: function pdfViewOpen(url, scale, password) { - var parameters = {password: password}; - if (typeof url === 'string') { // URL - this.setTitleUsingUrl(url); - parameters.url = url; - } else if (url && 'byteLength' in url) { // ArrayBuffer - parameters.data = url; - } - - if (!PDFView.loadingBar) { - PDFView.loadingBar = new ProgressBar('#loadingBar', {}); - } - - this.pdfDocument = null; - var self = this; - self.loading = true; - PDFJS.getDocument(parameters).then( - function getDocumentCallback(pdfDocument) { - self.load(pdfDocument, scale); - self.loading = false; - }, - function getDocumentError(message, exception) { - if (exception && exception.name === 'PasswordException') { - if (exception.code === 'needpassword') { - var promptString = mozL10n.get('request_password', null, - 'PDF is protected by a password:'); - password = prompt(promptString); - if (password && password.length > 0) { - return PDFView.open(url, scale, password); - } - } - } - - var loadingErrorMessage = mozL10n.get('loading_error', null, - 'An error occurred while loading the PDF.'); - - if (exception && exception.name === 'InvalidPDFException') { - // change error message also for other builds - var loadingErrorMessage = mozL10n.get('invalid_file_error', null, - 'Invalid or corrupted PDF file.'); -//#if B2G -// window.alert(loadingErrorMessage); -// return window.close(); -//#endif - } - - if (exception && exception.name === 'MissingPDFException') { - // special message for missing PDF's - var loadingErrorMessage = mozL10n.get('missing_file_error', null, - 'Missing PDF file.'); - -//#if B2G -// window.alert(loadingErrorMessage); -// return window.close(); -//#endif - } - - var loadingIndicator = document.getElementById('loading'); - loadingIndicator.textContent = mozL10n.get('loading_error_indicator', - null, 'Error'); - var moreInfo = { - message: message - }; - self.error(loadingErrorMessage, moreInfo); - self.loading = false; - }, - function getDocumentProgress(progressData) { - self.progress(progressData.loaded / progressData.total); - } - ); - }, - - download: function pdfViewDownload() { - function noData() { - FirefoxCom.request('download', { originalUrl: url }); - } - var url = this.url.split('#')[0]; -//#if !(FIREFOX || MOZCENTRAL) - url += '#pdfjs.action=download'; - window.open(url, '_parent'); -//#else -// // Document isn't ready just try to download with the url. -// if (!this.pdfDocument) { -// noData(); -// return; -// } -// this.pdfDocument.getData().then( -// function getDataSuccess(data) { -// var blob = PDFJS.createBlob(data.buffer, 'application/pdf'); -// var blobUrl = window.URL.createObjectURL(blob); -// -// FirefoxCom.request('download', { blobUrl: blobUrl, originalUrl: url }, -// function response(err) { -// if (err) { -// // This error won't really be helpful because it's likely the -// // fallback won't work either (or is already open). -// PDFView.error('PDF failed to download.'); -// } -// window.URL.revokeObjectURL(blobUrl); -// } -// ); -// }, -// noData // Error occurred try downloading with just the url. -// ); -//#endif - }, - - fallback: function pdfViewFallback() { -//#if !(FIREFOX || MOZCENTRAL) -// return; -//#else -// // Only trigger the fallback once so we don't spam the user with messages -// // for one PDF. -// if (this.fellback) -// return; -// this.fellback = true; -// var url = this.url.split('#')[0]; -// FirefoxCom.request('fallback', url, function response(download) { -// if (!download) -// return; -// PDFView.download(); -// }); -//#endif - }, - - navigateTo: function pdfViewNavigateTo(dest) { - if (typeof dest === 'string') - dest = this.destinations[dest]; - if (!(dest instanceof Array)) - return; // invalid destination - // dest array looks like that: <page-ref> </XYZ|FitXXX> <args..> - var destRef = dest[0]; - var pageNumber = destRef instanceof Object ? - this.pagesRefMap[destRef.num + ' ' + destRef.gen + ' R'] : (destRef + 1); - if (pageNumber > this.pages.length) - pageNumber = this.pages.length; - if (pageNumber) { - this.page = pageNumber; - var currentPage = this.pages[pageNumber - 1]; - if (!this.isFullscreen) { // Avoid breaking fullscreen mode. - currentPage.scrollIntoView(dest); - } - } - }, - - getDestinationHash: function pdfViewGetDestinationHash(dest) { - if (typeof dest === 'string') - return PDFView.getAnchorUrl('#' + escape(dest)); - if (dest instanceof Array) { - var destRef = dest[0]; // see navigateTo method for dest format - var pageNumber = destRef instanceof Object ? - this.pagesRefMap[destRef.num + ' ' + destRef.gen + ' R'] : - (destRef + 1); - if (pageNumber) { - var pdfOpenParams = PDFView.getAnchorUrl('#page=' + pageNumber); - var destKind = dest[1]; - if (typeof destKind === 'object' && 'name' in destKind && - destKind.name == 'XYZ') { - var scale = (dest[4] || this.currentScale); - pdfOpenParams += '&zoom=' + (scale * 100); - if (dest[2] || dest[3]) { - pdfOpenParams += ',' + (dest[2] || 0) + ',' + (dest[3] || 0); - } - } - return pdfOpenParams; - } - } - return ''; - }, - - /** - * For the firefox extension we prefix the full url on anchor links so they - * don't come up as resource:// urls and so open in new tab/window works. - * @param {String} anchor The anchor hash include the #. - */ - getAnchorUrl: function getAnchorUrl(anchor) { -//#if !(FIREFOX || MOZCENTRAL) - return anchor; -//#else -// return this.url.split('#')[0] + anchor; -//#endif - }, - - /** - * Returns scale factor for the canvas. It makes sense for the HiDPI displays. - * @return {Object} The object with horizontal (sx) and vertical (sy) - scales. The scaled property is set to false if scaling is - not required, true otherwise. - */ - getOutputScale: function pdfViewGetOutputDPI() { - var pixelRatio = 'devicePixelRatio' in window ? window.devicePixelRatio : 1; - return { - sx: pixelRatio, - sy: pixelRatio, - scaled: pixelRatio != 1 - }; - }, - - /** - * Show the error box. - * @param {String} message A message that is human readable. - * @param {Object} moreInfo (optional) Further information about the error - * that is more technical. Should have a 'message' - * and optionally a 'stack' property. - */ - error: function pdfViewError(message, moreInfo) { - var moreInfoText = mozL10n.get('error_version_info', - {version: PDFJS.version || '?', build: PDFJS.build || '?'}, - 'PDF.js v{{version}} (build: {{build}})') + '\n'; - if (moreInfo) { - moreInfoText += - mozL10n.get('error_message', {message: moreInfo.message}, - 'Message: {{message}}'); - if (moreInfo.stack) { - moreInfoText += '\n' + - mozL10n.get('error_stack', {stack: moreInfo.stack}, - 'Stack: {{stack}}'); - } else { - if (moreInfo.filename) { - moreInfoText += '\n' + - mozL10n.get('error_file', {file: moreInfo.filename}, - 'File: {{file}}'); - } - if (moreInfo.lineNumber) { - moreInfoText += '\n' + - mozL10n.get('error_line', {line: moreInfo.lineNumber}, - 'Line: {{line}}'); - } - } - } - - var loadingBox = document.getElementById('loadingBox'); - loadingBox.setAttribute('hidden', 'true'); - -//#if !(FIREFOX || MOZCENTRAL) - var errorWrapper = document.getElementById('errorWrapper'); - errorWrapper.removeAttribute('hidden'); - - var errorMessage = document.getElementById('errorMessage'); - errorMessage.textContent = message; - - var closeButton = document.getElementById('errorClose'); - closeButton.onclick = function() { - errorWrapper.setAttribute('hidden', 'true'); - }; - - var errorMoreInfo = document.getElementById('errorMoreInfo'); - var moreInfoButton = document.getElementById('errorShowMore'); - var lessInfoButton = document.getElementById('errorShowLess'); - moreInfoButton.onclick = function() { - errorMoreInfo.removeAttribute('hidden'); - moreInfoButton.setAttribute('hidden', 'true'); - lessInfoButton.removeAttribute('hidden'); - }; - lessInfoButton.onclick = function() { - errorMoreInfo.setAttribute('hidden', 'true'); - moreInfoButton.removeAttribute('hidden'); - lessInfoButton.setAttribute('hidden', 'true'); - }; - moreInfoButton.removeAttribute('hidden'); - lessInfoButton.setAttribute('hidden', 'true'); - errorMoreInfo.value = moreInfoText; - - errorMoreInfo.rows = moreInfoText.split('\n').length - 1; -//#else -// console.error(message + '\n' + moreInfoText); -// this.fallback(); -//#endif - }, - - progress: function pdfViewProgress(level) { - var percent = Math.round(level * 100); - PDFView.loadingBar.percent = percent; - }, - - load: function pdfViewLoad(pdfDocument, scale) { - function bindOnAfterDraw(pageView, thumbnailView) { - // when page is painted, using the image as thumbnail base - pageView.onAfterDraw = function pdfViewLoadOnAfterDraw() { - thumbnailView.setImage(pageView.canvas); - }; - } - - this.pdfDocument = pdfDocument; - - var errorWrapper = document.getElementById('errorWrapper'); - errorWrapper.setAttribute('hidden', 'true'); - - var loadingBox = document.getElementById('loadingBox'); - loadingBox.setAttribute('hidden', 'true'); - var loadingIndicator = document.getElementById('loading'); - loadingIndicator.textContent = ''; - - var thumbsView = document.getElementById('thumbnailView'); - thumbsView.parentNode.scrollTop = 0; - - while (thumbsView.hasChildNodes()) - thumbsView.removeChild(thumbsView.lastChild); - - if ('_loadingInterval' in thumbsView) - clearInterval(thumbsView._loadingInterval); - - var container = document.getElementById('viewer'); - while (container.hasChildNodes()) - container.removeChild(container.lastChild); - - var pagesCount = pdfDocument.numPages; - var id = pdfDocument.fingerprint; - document.getElementById('numPages').textContent = - mozL10n.get('page_of', {pageCount: pagesCount}, 'of {{pageCount}}'); - document.getElementById('pageNumber').max = pagesCount; - - PDFView.documentFingerprint = id; - var store = PDFView.store = new Settings(id); - - this.pageRotation = 0; - - var pages = this.pages = []; - this.pageText = []; - this.startedTextExtraction = false; - var pagesRefMap = this.pagesRefMap = {}; - var thumbnails = this.thumbnails = []; - - var pagesPromise = new PDFJS.Promise(); - var self = this; - - var firstPagePromise = pdfDocument.getPage(1); - - // Fetch a single page so we can get a viewport that will be the default - // viewport for all pages - firstPagePromise.then(function(pdfPage) { - var viewport = pdfPage.getViewport(scale || 1.0); - var pagePromises = []; - for (var pageNum = 1; pageNum <= pagesCount; ++pageNum) { - var viewportClone = viewport.clone(); - var pageView = new PageView(container, pageNum, scale, - self.navigateTo.bind(self), - viewportClone); - var thumbnailView = new ThumbnailView(thumbsView, pageNum, - viewportClone); - bindOnAfterDraw(pageView, thumbnailView); - pages.push(pageView); - thumbnails.push(thumbnailView); - } - - var event = document.createEvent('CustomEvent'); - event.initCustomEvent('documentload', true, true, {}); - window.dispatchEvent(event); - - for (var pageNum = 1; pageNum <= pagesCount; ++pageNum) { - var pagePromise = pdfDocument.getPage(pageNum); - pagePromise.then(function(pdfPage) { - var pageNum = pdfPage.pageNumber; - var pageView = pages[pageNum - 1]; - if (!pageView.pdfPage) { - // The pdfPage might already be set if we've already entered - // pageView.draw() - pageView.setPdfPage(pdfPage); - } - var thumbnailView = thumbnails[pageNum - 1]; - if (!thumbnailView.pdfPage) { - thumbnailView.setPdfPage(pdfPage); - } - - var pageRef = pdfPage.ref; - var refStr = pageRef.num + ' ' + pageRef.gen + ' R'; - pagesRefMap[refStr] = pdfPage.pageNumber; - }); - pagePromises.push(pagePromise); - } - - PDFJS.Promise.all(pagePromises).then(function(pages) { - pagesPromise.resolve(pages); - }); - }); - - var storePromise = store.initializedPromise; - PDFJS.Promise.all([firstPagePromise, storePromise]).then(function() { - var storedHash = null; - if (store.get('exists', false)) { - var pageNum = store.get('page', '1'); - var zoom = store.get('zoom', PDFView.currentScale); - var left = store.get('scrollLeft', '0'); - var top = store.get('scrollTop', '0'); - - storedHash = 'page=' + pageNum + '&zoom=' + zoom + ',' + - left + ',' + top; - } - self.setInitialView(storedHash, scale); - }); - - pagesPromise.then(function() { - if (PDFView.supportsPrinting) { - pdfDocument.getJavaScript().then(function(javaScript) { - if (javaScript.length) { - console.warn('Warning: JavaScript is not supported'); - PDFView.fallback(); - } - // Hack to support auto printing. - var regex = /\bprint\s*\(/g; - for (var i = 0, ii = javaScript.length; i < ii; i++) { - var js = javaScript[i]; - if (js && regex.test(js)) { - setTimeout(function() { - window.print(); - }); - return; - } - } - }); - } - }); - - var destinationsPromise = pdfDocument.getDestinations(); - destinationsPromise.then(function(destinations) { - self.destinations = destinations; - }); - - // outline depends on destinations and pagesRefMap - var promises = [pagesPromise, destinationsPromise, - PDFView.animationStartedPromise]; - PDFJS.Promise.all(promises).then(function() { - pdfDocument.getOutline().then(function(outline) { - self.outline = new DocumentOutlineView(outline); - }); - - // Make all navigation keys work on document load, - // unless the viewer is embedded in another page. - if (window.parent.location === window.location) { - PDFView.container.focus(); - } - }); - - pdfDocument.getMetadata().then(function(data) { - var info = data.info, metadata = data.metadata; - self.documentInfo = info; - self.metadata = metadata; - - // Provides some basic debug information - console.log('PDF ' + pdfDocument.fingerprint + ' [' + - info.PDFFormatVersion + ' ' + (info.Producer || '-') + - ' / ' + (info.Creator || '-') + ']' + - (PDFJS.version ? ' (PDF.js: ' + PDFJS.version + ')' : '')); - - var pdfTitle; - if (metadata) { - if (metadata.has('dc:title')) - pdfTitle = metadata.get('dc:title'); - } - - if (!pdfTitle && info && info['Title']) - pdfTitle = info['Title']; - - if (pdfTitle) - self.setTitle(pdfTitle + ' - ' + document.title); - - if (info.IsAcroFormPresent) { - console.warn('Warning: AcroForm/XFA is not supported'); - PDFView.fallback(); - } - }); - }, - - setInitialView: function pdfViewSetInitialView(storedHash, scale) { - // Reset the current scale, as otherwise the page's scale might not get - // updated if the zoom level stayed the same. - this.currentScale = 0; - this.currentScaleValue = null; - if (this.initialBookmark) { - this.setHash(this.initialBookmark); - this.initialBookmark = null; - } - else if (storedHash) - this.setHash(storedHash); - else if (scale) { - this.parseScale(scale, true); - this.page = 1; - } - - if (PDFView.currentScale === UNKNOWN_SCALE) { - // Scale was not initialized: invalid bookmark or scale was not specified. - // Setting the default one. - this.parseScale(DEFAULT_SCALE, true); - } - }, - - renderHighestPriority: function pdfViewRenderHighestPriority() { - // Pages have a higher priority than thumbnails, so check them first. - var visiblePages = this.getVisiblePages(); - var pageView = this.getHighestPriority(visiblePages, this.pages, - this.pageViewScroll.down); - if (pageView) { - this.renderView(pageView, 'page'); - return; - } - // No pages needed rendering so check thumbnails. - if (this.sidebarOpen) { - var visibleThumbs = this.getVisibleThumbs(); - var thumbView = this.getHighestPriority(visibleThumbs, - this.thumbnails, - this.thumbnailViewScroll.down); - if (thumbView) - this.renderView(thumbView, 'thumbnail'); - } - }, - - getHighestPriority: function pdfViewGetHighestPriority(visible, views, - scrolledDown) { - // The state has changed figure out which page has the highest priority to - // render next (if any). - // Priority: - // 1 visible pages - // 2 if last scrolled down page after the visible pages - // 2 if last scrolled up page before the visible pages - var visibleViews = visible.views; - - var numVisible = visibleViews.length; - if (numVisible === 0) { - return false; - } - for (var i = 0; i < numVisible; ++i) { - var view = visibleViews[i].view; - if (!this.isViewFinished(view)) - return view; - } - - // All the visible views have rendered, try to render next/previous pages. - if (scrolledDown) { - var nextPageIndex = visible.last.id; - // ID's start at 1 so no need to add 1. - if (views[nextPageIndex] && !this.isViewFinished(views[nextPageIndex])) - return views[nextPageIndex]; - } else { - var previousPageIndex = visible.first.id - 2; - if (views[previousPageIndex] && - !this.isViewFinished(views[previousPageIndex])) - return views[previousPageIndex]; - } - // Everything that needs to be rendered has been. - return false; - }, - - isViewFinished: function pdfViewNeedsRendering(view) { - return view.renderingState === RenderingStates.FINISHED; - }, - - // Render a page or thumbnail view. This calls the appropriate function based - // on the views state. If the view is already rendered it will return false. - renderView: function pdfViewRender(view, type) { - var state = view.renderingState; - switch (state) { - case RenderingStates.FINISHED: - return false; - case RenderingStates.PAUSED: - PDFView.highestPriorityPage = type + view.id; - view.resume(); - break; - case RenderingStates.RUNNING: - PDFView.highestPriorityPage = type + view.id; - break; - case RenderingStates.INITIAL: - PDFView.highestPriorityPage = type + view.id; - view.draw(this.renderHighestPriority.bind(this)); - break; - } - return true; - }, - - setHash: function pdfViewSetHash(hash) { - if (!hash) - return; - - if (hash.indexOf('=') >= 0) { - var params = PDFView.parseQueryString(hash); - // borrowing syntax from "Parameters for Opening PDF Files" - if ('nameddest' in params) { - PDFView.navigateTo(params.nameddest); - return; - } - if ('page' in params) { - var pageNumber = (params.page | 0) || 1; - if ('zoom' in params) { - var zoomArgs = params.zoom.split(','); // scale,left,top - // building destination array - - // If the zoom value, it has to get divided by 100. If it is a string, - // it should stay as it is. - var zoomArg = zoomArgs[0]; - var zoomArgNumber = parseFloat(zoomArg); - if (zoomArgNumber) - zoomArg = zoomArgNumber / 100; - - var dest = [null, {name: 'XYZ'}, - zoomArgs.length > 1 ? (zoomArgs[1] | 0) : null, - zoomArgs.length > 2 ? (zoomArgs[2] | 0) : null, - zoomArg]; - var currentPage = this.pages[pageNumber - 1]; - currentPage.scrollIntoView(dest); - } else { - this.page = pageNumber; // simple page - } - } - if ('pagemode' in params) { - var toggle = document.getElementById('sidebarToggle'); - if (params.pagemode === 'thumbs' || params.pagemode === 'bookmarks') { - if (!this.sidebarOpen) { - toggle.click(); - } - this.switchSidebarView(params.pagemode === 'thumbs' ? - 'thumbs' : 'outline'); - } else if (params.pagemode === 'none' && this.sidebarOpen) { - toggle.click(); - } - } - } else if (/^\d+$/.test(hash)) // page number - this.page = hash; - else // named destination - PDFView.navigateTo(unescape(hash)); - }, - - switchSidebarView: function pdfViewSwitchSidebarView(view) { - var thumbsView = document.getElementById('thumbnailView'); - var outlineView = document.getElementById('outlineView'); - - var thumbsButton = document.getElementById('viewThumbnail'); - var outlineButton = document.getElementById('viewOutline'); - - switch (view) { - case 'thumbs': - var wasOutlineViewVisible = thumbsView.classList.contains('hidden'); - - thumbsButton.classList.add('toggled'); - outlineButton.classList.remove('toggled'); - thumbsView.classList.remove('hidden'); - outlineView.classList.add('hidden'); - - PDFView.renderHighestPriority(); - - if (wasOutlineViewVisible) { - // Ensure that the thumbnail of the current page is visible - // when switching from the outline view. - scrollIntoView(document.getElementById('thumbnailContainer' + - this.page)); - } - break; - - case 'outline': - thumbsButton.classList.remove('toggled'); - outlineButton.classList.add('toggled'); - thumbsView.classList.add('hidden'); - outlineView.classList.remove('hidden'); - - if (outlineButton.getAttribute('disabled')) - return; - break; - } - }, - - getVisiblePages: function pdfViewGetVisiblePages() { - if (!this.isFullscreen) { - return this.getVisibleElements(this.container, this.pages, true); - } else { - // The algorithm in getVisibleElements is broken in fullscreen mode. - var visible = [], page = this.page; - var currentPage = this.pages[page - 1]; - visible.push({ id: currentPage.id, view: currentPage }); - - return { first: currentPage, last: currentPage, views: visible}; - } - }, - - getVisibleThumbs: function pdfViewGetVisibleThumbs() { - return this.getVisibleElements(this.thumbnailContainer, this.thumbnails); - }, - - // Generic helper to find out what elements are visible within a scroll pane. - getVisibleElements: function pdfViewGetVisibleElements( - scrollEl, views, sortByVisibility) { - var top = scrollEl.scrollTop, bottom = top + scrollEl.clientHeight; - var left = scrollEl.scrollLeft, right = left + scrollEl.clientWidth; - - var visible = [], view; - var currentHeight, viewHeight, hiddenHeight, percentHeight; - var currentWidth, viewWidth; - for (var i = 0, ii = views.length; i < ii; ++i) { - view = views[i]; - currentHeight = view.el.offsetTop + view.el.clientTop; - viewHeight = view.el.clientHeight; - if ((currentHeight + viewHeight) < top) { - continue; - } - if (currentHeight > bottom) { - break; - } - currentWidth = view.el.offsetLeft + view.el.clientLeft; - viewWidth = view.el.clientWidth; - if ((currentWidth + viewWidth) < left || currentWidth > right) { - continue; - } - hiddenHeight = Math.max(0, top - currentHeight) + - Math.max(0, currentHeight + viewHeight - bottom); - percentHeight = ((viewHeight - hiddenHeight) * 100 / viewHeight) | 0; - - visible.push({ id: view.id, y: currentHeight, - view: view, percent: percentHeight }); - } - - var first = visible[0]; - var last = visible[visible.length - 1]; - - if (sortByVisibility) { - visible.sort(function(a, b) { - var pc = a.percent - b.percent; - if (Math.abs(pc) > 0.001) { - return -pc; - } - return a.id - b.id; // ensure stability - }); - } - return {first: first, last: last, views: visible}; - }, - - // Helper function to parse query string (e.g. ?param1=value&parm2=...). - parseQueryString: function pdfViewParseQueryString(query) { - var parts = query.split('&'); - var params = {}; - for (var i = 0, ii = parts.length; i < parts.length; ++i) { - var param = parts[i].split('='); - var key = param[0]; - var value = param.length > 1 ? param[1] : null; - params[unescape(key)] = unescape(value); - } - return params; - }, - - beforePrint: function pdfViewSetupBeforePrint() { - if (!this.supportsPrinting) { - var printMessage = mozL10n.get('printing_not_supported', null, - 'Warning: Printing is not fully supported by this browser.'); - this.error(printMessage); - return; - } - - var alertNotReady = false; - if (!this.pages.length) { - alertNotReady = true; - } else { - for (var i = 0, ii = this.pages.length; i < ii; ++i) { - if (!this.pages[i].pdfPage) { - alertNotReady = true; - break; - } - } - } - if (alertNotReady) { - var notReadyMessage = mozL10n.get('printing_not_ready', null, - 'Warning: The PDF is not fully loaded for printing.'); - window.alert(notReadyMessage); - return; - } - - var body = document.querySelector('body'); - body.setAttribute('data-mozPrintCallback', true); - for (var i = 0, ii = this.pages.length; i < ii; ++i) { - this.pages[i].beforePrint(); - } - }, - - afterPrint: function pdfViewSetupAfterPrint() { - var div = document.getElementById('printContainer'); - while (div.hasChildNodes()) - div.removeChild(div.lastChild); - }, - - fullscreen: function pdfViewFullscreen() { - var isFullscreen = document.fullscreenElement || document.mozFullScreen || - document.webkitIsFullScreen; - - if (isFullscreen) { - return false; - } - - var wrapper = document.getElementById('viewerContainer'); - if (document.documentElement.requestFullscreen) { - wrapper.requestFullscreen(); - } else if (document.documentElement.mozRequestFullScreen) { - wrapper.mozRequestFullScreen(); - } else if (document.documentElement.webkitRequestFullScreen) { - wrapper.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT); - } else { - return false; - } - - this.isFullscreen = true; - var currentPage = this.pages[this.page - 1]; - this.previousScale = this.currentScaleValue; - this.parseScale('page-fit', true); - - // Wait for fullscreen to take effect - setTimeout(function() { - currentPage.scrollIntoView(); - }, 0); - - this.showPresentationControls(); - return true; - }, - - exitFullscreen: function pdfViewExitFullscreen() { - this.isFullscreen = false; - this.parseScale(this.previousScale); - this.page = this.page; - this.clearMouseScrollState(); - this.hidePresentationControls(); - - // Ensure that the thumbnail of the current page is visible - // when exiting fullscreen mode. - scrollIntoView(document.getElementById('thumbnailContainer' + this.page)); - }, - - showPresentationControls: function pdfViewShowPresentationControls() { - var DELAY_BEFORE_HIDING_CONTROLS = 3000; - var wrapper = document.getElementById('viewerContainer'); - if (this.presentationControlsTimeout) { - clearTimeout(this.presentationControlsTimeout); - } else { - wrapper.classList.add('presentationControls'); - } - this.presentationControlsTimeout = setTimeout(function hideControls() { - wrapper.classList.remove('presentationControls'); - delete PDFView.presentationControlsTimeout; - }, DELAY_BEFORE_HIDING_CONTROLS); - }, - - hidePresentationControls: function pdfViewShowPresentationControls() { - if (!this.presentationControlsTimeout) { - return; - } - clearTimeout(this.presentationControlsTimeout); - delete this.presentationControlsTimeout; - - var wrapper = document.getElementById('viewerContainer'); - wrapper.classList.remove('presentationControls'); - }, - - rotatePages: function pdfViewPageRotation(delta) { - - this.pageRotation = (this.pageRotation + 360 + delta) % 360; - - for (var i = 0, l = this.pages.length; i < l; i++) { - var page = this.pages[i]; - page.update(page.scale, this.pageRotation); - } - - for (var i = 0, l = this.thumbnails.length; i < l; i++) { - var thumb = this.thumbnails[i]; - thumb.update(this.pageRotation); - } - - this.parseScale(this.currentScaleValue, true); - - this.renderHighestPriority(); - - var currentPage = this.pages[this.page - 1]; - if (!currentPage) { - return; - } - - // Wait for fullscreen to take effect - setTimeout(function() { - currentPage.scrollIntoView(); - }, 0); - }, - - /** - * This function flips the page in presentation mode if the user scrolls up - * or down with large enough motion and prevents page flipping too often. - * - * @this {PDFView} - * @param {number} mouseScrollDelta The delta value from the mouse event. - */ - mouseScroll: function pdfViewMouseScroll(mouseScrollDelta) { - var MOUSE_SCROLL_COOLDOWN_TIME = 50; - - var currentTime = (new Date()).getTime(); - var storedTime = this.mouseScrollTimeStamp; - - // In case one page has already been flipped there is a cooldown time - // which has to expire before next page can be scrolled on to. - if (currentTime > storedTime && - currentTime - storedTime < MOUSE_SCROLL_COOLDOWN_TIME) - return; - - // In case the user decides to scroll to the opposite direction than before - // clear the accumulated delta. - if ((this.mouseScrollDelta > 0 && mouseScrollDelta < 0) || - (this.mouseScrollDelta < 0 && mouseScrollDelta > 0)) - this.clearMouseScrollState(); - - this.mouseScrollDelta += mouseScrollDelta; - - var PAGE_FLIP_THRESHOLD = 120; - if (Math.abs(this.mouseScrollDelta) >= PAGE_FLIP_THRESHOLD) { - - var PageFlipDirection = { - UP: -1, - DOWN: 1 - }; - - // In fullscreen mode scroll one page at a time. - var pageFlipDirection = (this.mouseScrollDelta > 0) ? - PageFlipDirection.UP : - PageFlipDirection.DOWN; - this.clearMouseScrollState(); - var currentPage = this.page; - - // In case we are already on the first or the last page there is no need - // to do anything. - if ((currentPage == 1 && pageFlipDirection == PageFlipDirection.UP) || - (currentPage == this.pages.length && - pageFlipDirection == PageFlipDirection.DOWN)) - return; - - this.page += pageFlipDirection; - this.mouseScrollTimeStamp = currentTime; - } - }, - - /** - * This function clears the member attributes used with mouse scrolling in - * presentation mode. - * - * @this {PDFView} - */ - clearMouseScrollState: function pdfViewClearMouseScrollState() { - this.mouseScrollTimeStamp = 0; - this.mouseScrollDelta = 0; - } -}; - -var PageView = function pageView(container, id, scale, - navigateTo, defaultViewport) { - this.id = id; - - this.rotation = 0; - this.scale = scale || 1.0; - this.viewport = defaultViewport; - this.pdfPageRotate = defaultViewport.rotate; - - this.renderingState = RenderingStates.INITIAL; - this.resume = null; - - this.textContent = null; - this.textLayer = null; - - var anchor = document.createElement('a'); - anchor.name = '' + this.id; - - var div = this.el = document.createElement('div'); - div.id = 'pageContainer' + this.id; - div.className = 'page'; - div.style.width = Math.floor(this.viewport.width) + 'px'; - div.style.height = Math.floor(this.viewport.height) + 'px'; - - container.appendChild(anchor); - container.appendChild(div); - - this.setPdfPage = function pageViewSetPdfPage(pdfPage) { - this.pdfPage = pdfPage; - this.pdfPageRotate = pdfPage.rotate; - this.viewport = pdfPage.getViewport(this.scale); - this.stats = pdfPage.stats; - this.update(); - }; - - this.destroy = function pageViewDestroy() { - this.update(); - if (this.pdfPage) { - this.pdfPage.destroy(); - } - }; - - this.update = function pageViewUpdate(scale, rotation) { - this.renderingState = RenderingStates.INITIAL; - this.resume = null; - - if (typeof rotation !== 'undefined') { - this.rotation = rotation; - } - - this.scale = scale || this.scale; - - var totalRotation = (this.rotation + this.pdfPageRotate) % 360; - this.viewport = this.viewport.clone({ - scale: this.scale, - rotation: totalRotation - }); - - div.style.width = Math.floor(this.viewport.width) + 'px'; - div.style.height = Math.floor(this.viewport.height) + 'px'; - - while (div.hasChildNodes()) - div.removeChild(div.lastChild); - div.removeAttribute('data-loaded'); - - delete this.canvas; - - this.loadingIconDiv = document.createElement('div'); - this.loadingIconDiv.className = 'loadingIcon'; - div.appendChild(this.loadingIconDiv); - }; - - Object.defineProperty(this, 'width', { - get: function PageView_getWidth() { - return this.viewport.width; - }, - enumerable: true - }); - - Object.defineProperty(this, 'height', { - get: function PageView_getHeight() { - return this.viewport.height; - }, - enumerable: true - }); - - function setupAnnotations(pdfPage, viewport) { - function bindLink(link, dest) { - link.href = PDFView.getDestinationHash(dest); - link.onclick = function pageViewSetupLinksOnclick() { - if (dest) - PDFView.navigateTo(dest); - return false; - }; - } - function createElementWithStyle(tagName, item, rect) { - if (!rect) { - rect = viewport.convertToViewportRectangle(item.rect); - rect = PDFJS.Util.normalizeRect(rect); - } - var element = document.createElement(tagName); - element.style.left = Math.floor(rect[0]) + 'px'; - element.style.top = Math.floor(rect[1]) + 'px'; - element.style.width = Math.ceil(rect[2] - rect[0]) + 'px'; - element.style.height = Math.ceil(rect[3] - rect[1]) + 'px'; - return element; - } - function createTextAnnotation(item) { - var container = document.createElement('section'); - container.className = 'annotText'; - - var rect = viewport.convertToViewportRectangle(item.rect); - rect = PDFJS.Util.normalizeRect(rect); - // sanity check because of OOo-generated PDFs - if ((rect[3] - rect[1]) < ANNOT_MIN_SIZE) { - rect[3] = rect[1] + ANNOT_MIN_SIZE; - } - if ((rect[2] - rect[0]) < ANNOT_MIN_SIZE) { - rect[2] = rect[0] + (rect[3] - rect[1]); // make it square - } - var image = createElementWithStyle('img', item, rect); - var iconName = item.name; - image.src = IMAGE_DIR + 'annotation-' + - iconName.toLowerCase() + '.svg'; - image.alt = mozL10n.get('text_annotation_type', {type: iconName}, - '[{{type}} Annotation]'); - var content = document.createElement('div'); - content.setAttribute('hidden', true); - var title = document.createElement('h1'); - var text = document.createElement('p'); - content.style.left = Math.floor(rect[2]) + 'px'; - content.style.top = Math.floor(rect[1]) + 'px'; - title.textContent = item.title; - - if (!item.content && !item.title) { - content.setAttribute('hidden', true); - } else { - var e = document.createElement('span'); - var lines = item.content.split(/(?:\r\n?|\n)/); - for (var i = 0, ii = lines.length; i < ii; ++i) { - var line = lines[i]; - e.appendChild(document.createTextNode(line)); - if (i < (ii - 1)) - e.appendChild(document.createElement('br')); - } - text.appendChild(e); - image.addEventListener('mouseover', function annotationImageOver() { - content.removeAttribute('hidden'); - }, false); - - image.addEventListener('mouseout', function annotationImageOut() { - content.setAttribute('hidden', true); - }, false); - } - - content.appendChild(title); - content.appendChild(text); - container.appendChild(image); - container.appendChild(content); - - return container; - } - - pdfPage.getAnnotations().then(function(items) { - for (var i = 0; i < items.length; i++) { - var item = items[i]; - switch (item.type) { - case 'Link': - var link = createElementWithStyle('a', item); - link.href = item.url || ''; - if (!item.url) - bindLink(link, ('dest' in item) ? item.dest : null); - div.appendChild(link); - break; - case 'Text': - var textAnnotation = createTextAnnotation(item); - if (textAnnotation) - div.appendChild(textAnnotation); - break; - } - } - }); - } - - this.getPagePoint = function pageViewGetPagePoint(x, y) { - return this.viewport.convertToPdfPoint(x, y); - }; - - this.scrollIntoView = function pageViewScrollIntoView(dest) { - if (!dest) { - scrollIntoView(div); - return; - } - - var x = 0, y = 0; - var width = 0, height = 0, widthScale, heightScale; - var scale = 0; - switch (dest[1].name) { - case 'XYZ': - x = dest[2]; - y = dest[3]; - scale = dest[4]; - // If x and/or y coordinates are not supplied, default to - // _top_ left of the page (not the obvious bottom left, - // since aligning the bottom of the intended page with the - // top of the window is rarely helpful). - x = x !== null ? x : 0; - y = y !== null ? y : this.height / this.scale; - break; - case 'Fit': - case 'FitB': - scale = 'page-fit'; - break; - case 'FitH': - case 'FitBH': - y = dest[2]; - scale = 'page-width'; - break; - case 'FitV': - case 'FitBV': - x = dest[2]; - scale = 'page-height'; - break; - case 'FitR': - x = dest[2]; - y = dest[3]; - width = dest[4] - x; - height = dest[5] - y; - widthScale = (this.container.clientWidth - SCROLLBAR_PADDING) / - width / CSS_UNITS; - heightScale = (this.container.clientHeight - SCROLLBAR_PADDING) / - height / CSS_UNITS; - scale = Math.min(widthScale, heightScale); - break; - default: - return; - } - - if (scale && scale !== PDFView.currentScale) - PDFView.parseScale(scale, true, true); - else if (PDFView.currentScale === UNKNOWN_SCALE) - PDFView.parseScale(DEFAULT_SCALE, true, true); - - var boundingRect = [ - this.viewport.convertToViewportPoint(x, y), - this.viewport.convertToViewportPoint(x + width, y + height) - ]; - setTimeout(function pageViewScrollIntoViewRelayout() { - // letting page to re-layout before scrolling - var scale = PDFView.currentScale; - var x = Math.min(boundingRect[0][0], boundingRect[1][0]); - var y = Math.min(boundingRect[0][1], boundingRect[1][1]); - var width = Math.abs(boundingRect[0][0] - boundingRect[1][0]); - var height = Math.abs(boundingRect[0][1] - boundingRect[1][1]); - - scrollIntoView(div, {left: x, top: y, width: width, height: height}); - }, 0); - }; - - this.getTextContent = function pageviewGetTextContent() { - if (!this.textContent) { - this.textContent = this.pdfPage.getTextContent(); - } - return this.textContent; - }; - - this.draw = function pageviewDraw(callback) { - var pdfPage = this.pdfPage; - - if (!pdfPage) { - var promise = PDFView.getPage(this.id); - promise.then(function(pdfPage) { - this.setPdfPage(pdfPage); - this.draw(callback); - }.bind(this)); - return; - } - - if (this.renderingState !== RenderingStates.INITIAL) { - console.error('Must be in new state before drawing'); - } - - this.renderingState = RenderingStates.RUNNING; - - var canvas = document.createElement('canvas'); - canvas.id = 'page' + this.id; - div.appendChild(canvas); - this.canvas = canvas; - - var scale = this.scale, viewport = this.viewport; - var outputScale = PDFView.getOutputScale(); - canvas.width = Math.floor(viewport.width) * outputScale.sx; - canvas.height = Math.floor(viewport.height) * outputScale.sy; - - var textLayerDiv = null; - if (!PDFJS.disableTextLayer) { - textLayerDiv = document.createElement('div'); - textLayerDiv.className = 'textLayer'; - textLayerDiv.style.width = canvas.width + 'px'; - textLayerDiv.style.height = canvas.height + 'px'; - div.appendChild(textLayerDiv); - } - var textLayer = this.textLayer = - textLayerDiv ? new TextLayerBuilder(textLayerDiv, this.id - 1) : null; - - if (outputScale.scaled) { - var cssScale = 'scale(' + (1 / outputScale.sx) + ', ' + - (1 / outputScale.sy) + ')'; - CustomStyle.setProp('transform' , canvas, cssScale); - CustomStyle.setProp('transformOrigin' , canvas, '0% 0%'); - if (textLayerDiv) { - CustomStyle.setProp('transform' , textLayerDiv, cssScale); - CustomStyle.setProp('transformOrigin' , textLayerDiv, '0% 0%'); - } - } - - var ctx = canvas.getContext('2d'); - ctx.clearRect(0, 0, canvas.width, canvas.height); - // TODO(mack): use data attributes to store these - ctx._scaleX = outputScale.sx; - ctx._scaleY = outputScale.sy; - if (outputScale.scaled) { - ctx.scale(outputScale.sx, outputScale.sy); - } -//#if (FIREFOX || MOZCENTRAL) -// // Checking if document fonts are used only once -// var checkIfDocumentFontsUsed = !PDFView.pdfDocument.embeddedFontsUsed; -//#endif - - // Rendering area - - var self = this; - var renderingWasReset = false; - function pageViewDrawCallback(error) { - if (renderingWasReset) { - return; - } - - self.renderingState = RenderingStates.FINISHED; - - if (self.loadingIconDiv) { - div.removeChild(self.loadingIconDiv); - delete self.loadingIconDiv; - } - -//#if (FIREFOX || MOZCENTRAL) -// if (checkIfDocumentFontsUsed && PDFView.pdfDocument.embeddedFontsUsed && -// !PDFView.supportsDocumentFonts) { -// console.error(mozL10n.get('web_fonts_disabled', null, -// 'Web fonts are disabled: unable to use embedded PDF fonts.')); -// PDFView.fallback(); -// } -//#endif - if (error) { - PDFView.error(mozL10n.get('rendering_error', null, - 'An error occurred while rendering the page.'), error); - } - - self.stats = pdfPage.stats; - self.updateStats(); - if (self.onAfterDraw) - self.onAfterDraw(); - - cache.push(self); - - var event = document.createEvent('CustomEvent'); - event.initCustomEvent('pagerender', true, true, { - pageNumber: pdfPage.pageNumber - }); - div.dispatchEvent(event); - - callback(); - } - - var renderContext = { - canvasContext: ctx, - viewport: this.viewport, - textLayer: textLayer, - continueCallback: function pdfViewcContinueCallback(cont) { - if (self.renderingState === RenderingStates.INITIAL) { - // The page update() was called, we just need to abort any rendering. - renderingWasReset = true; - return; - } - - if (PDFView.highestPriorityPage !== 'page' + self.id) { - self.renderingState = RenderingStates.PAUSED; - self.resume = function resumeCallback() { - self.renderingState = RenderingStates.RUNNING; - cont(); - }; - return; - } - cont(); - } - }; - this.pdfPage.render(renderContext).then( - function pdfPageRenderCallback() { - pageViewDrawCallback(null); - }, - function pdfPageRenderError(error) { - pageViewDrawCallback(error); - } - ); - - if (textLayer) { - this.getTextContent().then( - function textContentResolved(textContent) { - textLayer.setTextContent(textContent); - } - ); - } - - setupAnnotations(this.pdfPage, this.viewport); - div.setAttribute('data-loaded', true); - }; - - this.beforePrint = function pageViewBeforePrint() { - var pdfPage = this.pdfPage; - - var viewport = pdfPage.getViewport(1); - // Use the same hack we use for high dpi displays for printing to get better - // output until bug 811002 is fixed in FF. - var PRINT_OUTPUT_SCALE = 2; - var canvas = this.canvas = document.createElement('canvas'); - canvas.width = Math.floor(viewport.width) * PRINT_OUTPUT_SCALE; - canvas.height = Math.floor(viewport.height) * PRINT_OUTPUT_SCALE; - canvas.style.width = (PRINT_OUTPUT_SCALE * viewport.width) + 'pt'; - canvas.style.height = (PRINT_OUTPUT_SCALE * viewport.height) + 'pt'; - var cssScale = 'scale(' + (1 / PRINT_OUTPUT_SCALE) + ', ' + - (1 / PRINT_OUTPUT_SCALE) + ')'; - CustomStyle.setProp('transform' , canvas, cssScale); - CustomStyle.setProp('transformOrigin' , canvas, '0% 0%'); - - var printContainer = document.getElementById('printContainer'); - printContainer.appendChild(canvas); - - var self = this; - canvas.mozPrintCallback = function(obj) { - var ctx = obj.context; - - ctx.save(); - ctx.fillStyle = 'rgb(255, 255, 255)'; - ctx.fillRect(0, 0, canvas.width, canvas.height); - ctx.restore(); - ctx.scale(PRINT_OUTPUT_SCALE, PRINT_OUTPUT_SCALE); - - var renderContext = { - canvasContext: ctx, - viewport: viewport - }; - - pdfPage.render(renderContext).then(function() { - // Tell the printEngine that rendering this canvas/page has finished. - obj.done(); - self.pdfPage.destroy(); - }, function(error) { - console.error(error); - // Tell the printEngine that rendering this canvas/page has failed. - // This will make the print proces stop. - if ('abort' in obj) - obj.abort(); - else - obj.done(); - self.pdfPage.destroy(); - }); - }; - }; - - this.updateStats = function pageViewUpdateStats() { - if (!this.stats) { - return; - } - - if (PDFJS.pdfBug && Stats.enabled) { - var stats = this.stats; - Stats.add(this.id, stats); - } - }; -}; - -var ThumbnailView = function thumbnailView(container, id, defaultViewport) { - var anchor = document.createElement('a'); - anchor.href = PDFView.getAnchorUrl('#page=' + id); - anchor.title = mozL10n.get('thumb_page_title', {page: id}, 'Page {{page}}'); - anchor.onclick = function stopNavigation() { - PDFView.page = id; - return false; - }; - - - this.pdfPage = undefined; - this.viewport = defaultViewport; - this.pdfPageRotate = defaultViewport.rotate; - - this.rotation = 0; - this.pageWidth = this.viewport.width; - this.pageHeight = this.viewport.height; - this.pageRatio = this.pageWidth / this.pageHeight; - this.id = id; - - this.canvasWidth = 98; - this.canvasHeight = this.canvasWidth / this.pageWidth * this.pageHeight; - this.scale = (this.canvasWidth / this.pageWidth); - - var div = this.el = document.createElement('div'); - div.id = 'thumbnailContainer' + id; - div.className = 'thumbnail'; - - if (id === 1) { - // Highlight the thumbnail of the first page when no page number is - // specified (or exists in cache) when the document is loaded. - div.classList.add('selected'); - } - - var ring = document.createElement('div'); - ring.className = 'thumbnailSelectionRing'; - ring.style.width = this.canvasWidth + 'px'; - ring.style.height = this.canvasHeight + 'px'; - - div.appendChild(ring); - anchor.appendChild(div); - container.appendChild(anchor); - - this.hasImage = false; - this.renderingState = RenderingStates.INITIAL; - - this.setPdfPage = function thumbnailViewSetPdfPage(pdfPage) { - this.pdfPage = pdfPage; - this.pdfPageRotate = pdfPage.rotate; - this.viewport = pdfPage.getViewport(1); - this.update(); - }; - - this.update = function thumbnailViewUpdate(rot) { - if (!this.pdfPage) { - return; - } - - if (rot !== undefined) { - this.rotation = rot; - } - - var totalRotation = (this.rotation + this.pdfPage.rotate) % 360; - this.viewport = this.viewport.clone({ - scale: 1, - rotation: totalRotation - }); - this.pageWidth = this.viewport.width; - this.pageHeight = this.viewport.height; - this.pageRatio = this.pageWidth / this.pageHeight; - - this.canvasHeight = this.canvasWidth / this.pageWidth * this.pageHeight; - this.scale = (this.canvasWidth / this.pageWidth); - - div.removeAttribute('data-loaded'); - ring.textContent = ''; - ring.style.width = this.canvasWidth + 'px'; - ring.style.height = this.canvasHeight + 'px'; - - this.hasImage = false; - this.renderingState = RenderingStates.INITIAL; - this.resume = null; - }; - - this.getPageDrawContext = function thumbnailViewGetPageDrawContext() { - var canvas = document.createElement('canvas'); - canvas.id = 'thumbnail' + id; - - canvas.width = this.canvasWidth; - canvas.height = this.canvasHeight; - canvas.className = 'thumbnailImage'; - canvas.setAttribute('aria-label', mozL10n.get('thumb_page_canvas', - {page: id}, 'Thumbnail of Page {{page}}')); - - div.setAttribute('data-loaded', true); - - ring.appendChild(canvas); - - var ctx = canvas.getContext('2d'); - ctx.save(); - ctx.fillStyle = 'rgb(255, 255, 255)'; - ctx.fillRect(0, 0, this.canvasWidth, this.canvasHeight); - ctx.restore(); - return ctx; - }; - - this.drawingRequired = function thumbnailViewDrawingRequired() { - return !this.hasImage; - }; - - this.draw = function thumbnailViewDraw(callback) { - if (!this.pdfPage) { - var promise = PDFView.getPage(this.id); - promise.then(function(pdfPage) { - this.setPdfPage(pdfPage); - this.draw(callback); - }.bind(this)); - return; - } - - if (this.renderingState !== RenderingStates.INITIAL) { - console.error('Must be in new state before drawing'); - } - - this.renderingState = RenderingStates.RUNNING; - if (this.hasImage) { - callback(); - return; - } - - var self = this; - var ctx = this.getPageDrawContext(); - var drawViewport = this.viewport.clone({ scale: this.scale }); - var renderContext = { - canvasContext: ctx, - viewport: drawViewport, - continueCallback: function(cont) { - if (PDFView.highestPriorityPage !== 'thumbnail' + self.id) { - self.renderingState = RenderingStates.PAUSED; - self.resume = function() { - self.renderingState = RenderingStates.RUNNING; - cont(); - }; - return; - } - cont(); - } - }; - this.pdfPage.render(renderContext).then( - function pdfPageRenderCallback() { - self.renderingState = RenderingStates.FINISHED; - callback(); - }, - function pdfPageRenderError(error) { - self.renderingState = RenderingStates.FINISHED; - callback(); - } - ); - this.hasImage = true; - }; - - this.setImage = function thumbnailViewSetImage(img) { - if (this.hasImage || !img) - return; - this.renderingState = RenderingStates.FINISHED; - var ctx = this.getPageDrawContext(); - ctx.drawImage(img, 0, 0, img.width, img.height, - 0, 0, ctx.canvas.width, ctx.canvas.height); - - this.hasImage = true; - }; -}; - -var DocumentOutlineView = function documentOutlineView(outline) { - var outlineView = document.getElementById('outlineView'); - while (outlineView.firstChild) - outlineView.removeChild(outlineView.firstChild); - - function bindItemLink(domObj, item) { - domObj.href = PDFView.getDestinationHash(item.dest); - domObj.onclick = function documentOutlineViewOnclick(e) { - PDFView.navigateTo(item.dest); - return false; - }; - } - - if (!outline) { - var noOutline = document.createElement('div'); - noOutline.classList.add('noOutline'); - noOutline.textContent = mozL10n.get('no_outline', null, - 'No Outline Available'); - outlineView.appendChild(noOutline); - return; - } - - var queue = [{parent: outlineView, items: outline}]; - while (queue.length > 0) { - var levelData = queue.shift(); - var i, n = levelData.items.length; - for (i = 0; i < n; i++) { - var item = levelData.items[i]; - var div = document.createElement('div'); - div.className = 'outlineItem'; - var a = document.createElement('a'); - bindItemLink(a, item); - a.textContent = item.title; - div.appendChild(a); - - if (item.items.length > 0) { - var itemsDiv = document.createElement('div'); - itemsDiv.className = 'outlineItems'; - div.appendChild(itemsDiv); - queue.push({parent: itemsDiv, items: item.items}); - } - - levelData.parent.appendChild(div); - } - } -}; - -// optimised CSS custom property getter/setter -var CustomStyle = (function CustomStyleClosure() { - - // As noted on: http://www.zachstronaut.com/posts/2009/02/17/ - // animate-css-transforms-firefox-webkit.html - // in some versions of IE9 it is critical that ms appear in this list - // before Moz - var prefixes = ['ms', 'Moz', 'Webkit', 'O']; - var _cache = { }; - - function CustomStyle() { - } - - CustomStyle.getProp = function get(propName, element) { - // check cache only when no element is given - if (arguments.length == 1 && typeof _cache[propName] == 'string') { - return _cache[propName]; - } - - element = element || document.documentElement; - var style = element.style, prefixed, uPropName; - - // test standard property first - if (typeof style[propName] == 'string') { - return (_cache[propName] = propName); - } - - // capitalize - uPropName = propName.charAt(0).toUpperCase() + propName.slice(1); - - // test vendor specific properties - for (var i = 0, l = prefixes.length; i < l; i++) { - prefixed = prefixes[i] + uPropName; - if (typeof style[prefixed] == 'string') { - return (_cache[propName] = prefixed); - } - } - - //if all fails then set to undefined - return (_cache[propName] = 'undefined'); - }; - - CustomStyle.setProp = function set(propName, element, str) { - var prop = this.getProp(propName); - if (prop != 'undefined') - element.style[prop] = str; - }; - - return CustomStyle; -})(); - -var TextLayerBuilder = function textLayerBuilder(textLayerDiv, pageIdx) { - var textLayerFrag = document.createDocumentFragment(); - - this.textLayerDiv = textLayerDiv; - this.layoutDone = false; - this.divContentDone = false; - this.pageIdx = pageIdx; - this.matches = []; - - this.beginLayout = function textLayerBuilderBeginLayout() { - this.textDivs = []; - this.textLayerQueue = []; - this.renderingDone = false; - }; - - this.endLayout = function textLayerBuilderEndLayout() { - this.layoutDone = true; - this.insertDivContent(); - }; - - this.renderLayer = function textLayerBuilderRenderLayer() { - var self = this; - var textDivs = this.textDivs; - var bidiTexts = this.textContent.bidiTexts; - var textLayerDiv = this.textLayerDiv; - var canvas = document.createElement('canvas'); - var ctx = canvas.getContext('2d'); - - // No point in rendering so many divs as it'd make the browser unusable - // even after the divs are rendered - var MAX_TEXT_DIVS_TO_RENDER = 100000; - if (textDivs.length > MAX_TEXT_DIVS_TO_RENDER) - return; - - for (var i = 0, ii = textDivs.length; i < ii; i++) { - var textDiv = textDivs[i]; - if ('isWhitespace' in textDiv.dataset) { - continue; - } - textLayerFrag.appendChild(textDiv); - - ctx.font = textDiv.style.fontSize + ' ' + textDiv.style.fontFamily; - var width = ctx.measureText(textDiv.textContent).width; - - if (width > 0) { - var textScale = textDiv.dataset.canvasWidth / width; - - var transform = 'scale(' + textScale + ', 1)'; - if (bidiTexts[i].dir === 'ttb') { - transform = 'rotate(90deg) ' + transform; - } - CustomStyle.setProp('transform' , textDiv, transform); - CustomStyle.setProp('transformOrigin' , textDiv, '0% 0%'); - - textLayerDiv.appendChild(textDiv); - } - } - - this.renderingDone = true; - this.updateMatches(); - - textLayerDiv.appendChild(textLayerFrag); - }; - - this.setupRenderLayoutTimer = function textLayerSetupRenderLayoutTimer() { - // Schedule renderLayout() if user has been scrolling, otherwise - // run it right away - var RENDER_DELAY = 200; // in ms - var self = this; - if (Date.now() - PDFView.lastScroll > RENDER_DELAY) { - // Render right away - this.renderLayer(); - } else { - // Schedule - if (this.renderTimer) - clearTimeout(this.renderTimer); - this.renderTimer = setTimeout(function() { - self.setupRenderLayoutTimer(); - }, RENDER_DELAY); - } - }; - - this.appendText = function textLayerBuilderAppendText(geom) { - var textDiv = document.createElement('div'); - - // vScale and hScale already contain the scaling to pixel units - var fontHeight = geom.fontSize * Math.abs(geom.vScale); - textDiv.dataset.canvasWidth = geom.canvasWidth * geom.hScale; - textDiv.dataset.fontName = geom.fontName; - - textDiv.style.fontSize = fontHeight + 'px'; - textDiv.style.fontFamily = geom.fontFamily; - textDiv.style.left = geom.x + 'px'; - textDiv.style.top = (geom.y - fontHeight) + 'px'; - - // The content of the div is set in the `setTextContent` function. - - this.textDivs.push(textDiv); - }; - - this.insertDivContent = function textLayerUpdateTextContent() { - // Only set the content of the divs once layout has finished, the content - // for the divs is available and content is not yet set on the divs. - if (!this.layoutDone || this.divContentDone || !this.textContent) - return; - - this.divContentDone = true; - - var textDivs = this.textDivs; - var bidiTexts = this.textContent.bidiTexts; - - for (var i = 0; i < bidiTexts.length; i++) { - var bidiText = bidiTexts[i]; - var textDiv = textDivs[i]; - if (!/\S/.test(bidiText.str)) { - textDiv.dataset.isWhitespace = true; - continue; - } - - textDiv.textContent = bidiText.str; - // bidiText.dir may be 'ttb' for vertical texts. - textDiv.dir = bidiText.dir === 'rtl' ? 'rtl' : 'ltr'; - } - - this.setupRenderLayoutTimer(); - }; - - this.setTextContent = function textLayerBuilderSetTextContent(textContent) { - this.textContent = textContent; - this.insertDivContent(); - }; - - this.convertMatches = function textLayerBuilderConvertMatches(matches) { - var i = 0; - var iIndex = 0; - var bidiTexts = this.textContent.bidiTexts; - var end = bidiTexts.length - 1; - var queryLen = PDFFindController.state.query.length; - - var lastDivIdx = -1; - var pos; - - var ret = []; - - // Loop over all the matches. - for (var m = 0; m < matches.length; m++) { - var matchIdx = matches[m]; - // # Calculate the begin position. - - // Loop over the divIdxs. - while (i !== end && matchIdx >= (iIndex + bidiTexts[i].str.length)) { - iIndex += bidiTexts[i].str.length; - i++; - } - - // TODO: Do proper handling here if something goes wrong. - if (i == bidiTexts.length) { - console.error('Could not find matching mapping'); - } - - var match = { - begin: { - divIdx: i, - offset: matchIdx - iIndex - } - }; - - // # Calculate the end position. - matchIdx += queryLen; - - // Somewhat same array as above, but use a > instead of >= to get the end - // position right. - while (i !== end && matchIdx > (iIndex + bidiTexts[i].str.length)) { - iIndex += bidiTexts[i].str.length; - i++; - } - - match.end = { - divIdx: i, - offset: matchIdx - iIndex - }; - ret.push(match); - } - - return ret; - }; - - this.renderMatches = function textLayerBuilder_renderMatches(matches) { - // Early exit if there is nothing to render. - if (matches.length === 0) { - return; - } - - var bidiTexts = this.textContent.bidiTexts; - var textDivs = this.textDivs; - var prevEnd = null; - var isSelectedPage = this.pageIdx === PDFFindController.selected.pageIdx; - var selectedMatchIdx = PDFFindController.selected.matchIdx; - var highlightAll = PDFFindController.state.highlightAll; - - var infty = { - divIdx: -1, - offset: undefined - }; - - function beginText(begin, className) { - var divIdx = begin.divIdx; - var div = textDivs[divIdx]; - div.textContent = ''; - - var content = bidiTexts[divIdx].str.substring(0, begin.offset); - var node = document.createTextNode(content); - if (className) { - var isSelected = isSelectedPage && - divIdx === selectedMatchIdx; - var span = document.createElement('span'); - span.className = className + (isSelected ? ' selected' : ''); - span.appendChild(node); - div.appendChild(span); - return; - } - div.appendChild(node); - } - - function appendText(from, to, className) { - var divIdx = from.divIdx; - var div = textDivs[divIdx]; - - var content = bidiTexts[divIdx].str.substring(from.offset, to.offset); - var node = document.createTextNode(content); - if (className) { - var span = document.createElement('span'); - span.className = className; - span.appendChild(node); - div.appendChild(span); - return; - } - div.appendChild(node); - } - - function highlightDiv(divIdx, className) { - textDivs[divIdx].className = className; - } - - var i0 = selectedMatchIdx, i1 = i0 + 1, i; - - if (highlightAll) { - i0 = 0; - i1 = matches.length; - } else if (!isSelectedPage) { - // Not highlighting all and this isn't the selected page, so do nothing. - return; - } - - for (i = i0; i < i1; i++) { - var match = matches[i]; - var begin = match.begin; - var end = match.end; - - var isSelected = isSelectedPage && i === selectedMatchIdx; - var highlightSuffix = (isSelected ? ' selected' : ''); - if (isSelected) - scrollIntoView(textDivs[begin.divIdx], {top: -50}); - - // Match inside new div. - if (!prevEnd || begin.divIdx !== prevEnd.divIdx) { - // If there was a previous div, then add the text at the end - if (prevEnd !== null) { - appendText(prevEnd, infty); - } - // clears the divs and set the content until the begin point. - beginText(begin); - } else { - appendText(prevEnd, begin); - } - - if (begin.divIdx === end.divIdx) { - appendText(begin, end, 'highlight' + highlightSuffix); - } else { - appendText(begin, infty, 'highlight begin' + highlightSuffix); - for (var n = begin.divIdx + 1; n < end.divIdx; n++) { - highlightDiv(n, 'highlight middle' + highlightSuffix); - } - beginText(end, 'highlight end' + highlightSuffix); - } - prevEnd = end; - } - - if (prevEnd) { - appendText(prevEnd, infty); - } - }; - - this.updateMatches = function textLayerUpdateMatches() { - // Only show matches, once all rendering is done. - if (!this.renderingDone) - return; - - // Clear out all matches. - var matches = this.matches; - var textDivs = this.textDivs; - var bidiTexts = this.textContent.bidiTexts; - var clearedUntilDivIdx = -1; - - // Clear out all current matches. - for (var i = 0; i < matches.length; i++) { - var match = matches[i]; - var begin = Math.max(clearedUntilDivIdx, match.begin.divIdx); - for (var n = begin; n <= match.end.divIdx; n++) { - var div = textDivs[n]; - div.textContent = bidiTexts[n].str; - div.className = ''; - } - clearedUntilDivIdx = match.end.divIdx + 1; - } - - if (!PDFFindController.active) - return; - - // Convert the matches on the page controller into the match format used - // for the textLayer. - this.matches = matches = - this.convertMatches(PDFFindController.pageMatches[this.pageIdx] || []); - - this.renderMatches(this.matches); - }; -}; - -document.addEventListener('DOMContentLoaded', function webViewerLoad(evt) { - PDFView.initialize(); - var params = PDFView.parseQueryString(document.location.search.substring(1)); - -//#if !(FIREFOX || MOZCENTRAL) - var file = params.file || DEFAULT_URL; -//#else -//var file = window.location.toString() -//#endif - -//#if !(FIREFOX || MOZCENTRAL) - if (!window.File || !window.FileReader || !window.FileList || !window.Blob) { - document.getElementById('openFile').setAttribute('hidden', 'true'); - } else { - document.getElementById('fileInput').value = null; - } -//#else -//document.getElementById('openFile').setAttribute('hidden', 'true'); -//#endif - - // Special debugging flags in the hash section of the URL. - var hash = document.location.hash.substring(1); - var hashParams = PDFView.parseQueryString(hash); - - if ('disableWorker' in hashParams) - PDFJS.disableWorker = (hashParams['disableWorker'] === 'true'); - -//#if !(FIREFOX || MOZCENTRAL) - var locale = navigator.language; - if ('locale' in hashParams) - locale = hashParams['locale']; - mozL10n.setLanguage(locale); -//#endif - - if ('textLayer' in hashParams) { - switch (hashParams['textLayer']) { - case 'off': - PDFJS.disableTextLayer = true; - break; - case 'visible': - case 'shadow': - case 'hover': - var viewer = document.getElementById('viewer'); - viewer.classList.add('textLayer-' + hashParams['textLayer']); - break; - } - } - -//#if !(FIREFOX || MOZCENTRAL) - if ('pdfBug' in hashParams) { -//#else -//if ('pdfBug' in hashParams && FirefoxCom.requestSync('pdfBugEnabled')) { -//#endif - PDFJS.pdfBug = true; - var pdfBug = hashParams['pdfBug']; - var enabled = pdfBug.split(','); - PDFBug.enable(enabled); - PDFBug.init(); - } - - if (!PDFView.supportsPrinting) { - document.getElementById('print').classList.add('hidden'); - } - - if (!PDFView.supportsFullscreen) { - document.getElementById('fullscreen').classList.add('hidden'); - } - - if (PDFView.supportsIntegratedFind) { - document.querySelector('#viewFind').classList.add('hidden'); - } - - // Listen for warnings to trigger the fallback UI. Errors should be caught - // and call PDFView.error() so we don't need to listen for those. - PDFJS.LogManager.addLogger({ - warn: function() { - PDFView.fallback(); - } - }); - - var mainContainer = document.getElementById('mainContainer'); - var outerContainer = document.getElementById('outerContainer'); - mainContainer.addEventListener('transitionend', function(e) { - if (e.target == mainContainer) { - var event = document.createEvent('UIEvents'); - event.initUIEvent('resize', false, false, window, 0); - window.dispatchEvent(event); - outerContainer.classList.remove('sidebarMoving'); - } - }, true); - - document.getElementById('sidebarToggle').addEventListener('click', - function() { - this.classList.toggle('toggled'); - outerContainer.classList.add('sidebarMoving'); - outerContainer.classList.toggle('sidebarOpen'); - PDFView.sidebarOpen = outerContainer.classList.contains('sidebarOpen'); - PDFView.renderHighestPriority(); - }); - - document.getElementById('viewThumbnail').addEventListener('click', - function() { - PDFView.switchSidebarView('thumbs'); - }); - - document.getElementById('viewOutline').addEventListener('click', - function() { - PDFView.switchSidebarView('outline'); - }); - - document.getElementById('previous').addEventListener('click', - function() { - PDFView.page--; - }); - - document.getElementById('next').addEventListener('click', - function() { - PDFView.page++; - }); - - document.querySelector('.zoomIn').addEventListener('click', - function() { - PDFView.zoomIn(); - }); - - document.querySelector('.zoomOut').addEventListener('click', - function() { - PDFView.zoomOut(); - }); - - document.getElementById('fullscreen').addEventListener('click', - function() { - PDFView.fullscreen(); - }); - - document.getElementById('openFile').addEventListener('click', - function() { - document.getElementById('fileInput').click(); - }); - - document.getElementById('print').addEventListener('click', - function() { - window.print(); - }); - - document.getElementById('download').addEventListener('click', - function() { - PDFView.download(); - }); - - document.getElementById('pageNumber').addEventListener('click', - function() { - this.select(); - }); - - document.getElementById('pageNumber').addEventListener('change', - function() { - // Handle the user inputting a floating point number. - PDFView.page = (this.value | 0); - - if (this.value !== (this.value | 0).toString()) { - this.value = PDFView.page; - } - }); - - document.getElementById('scaleSelect').addEventListener('change', - function() { - PDFView.parseScale(this.value); - }); - - document.getElementById('first_page').addEventListener('click', - function() { - PDFView.page = 1; - }); - - document.getElementById('last_page').addEventListener('click', - function() { - PDFView.page = PDFView.pdfDocument.numPages; - }); - - document.getElementById('page_rotate_ccw').addEventListener('click', - function() { - PDFView.rotatePages(-90); - }); - - document.getElementById('page_rotate_cw').addEventListener('click', - function() { - PDFView.rotatePages(90); - }); - -//#if (FIREFOX || MOZCENTRAL) -//if (FirefoxCom.requestSync('getLoadingType') == 'passive') { -// PDFView.setTitleUsingUrl(file); -// PDFView.initPassiveLoading(); -// return; -//} -//#endif - -//#if !B2G - PDFView.open(file, 0); -//#endif -}, true); - -function updateViewarea() { - - if (!PDFView.initialized) - return; - var visible = PDFView.getVisiblePages(); - var visiblePages = visible.views; - if (visiblePages.length === 0) { - return; - } - - PDFView.renderHighestPriority(); - - var currentId = PDFView.page; - var firstPage = visible.first; - - for (var i = 0, ii = visiblePages.length, stillFullyVisible = false; - i < ii; ++i) { - var page = visiblePages[i]; - - if (page.percent < 100) - break; - - if (page.id === PDFView.page) { - stillFullyVisible = true; - break; - } - } - - if (!stillFullyVisible) { - currentId = visiblePages[0].id; - } - - if (!PDFView.isFullscreen) { - updateViewarea.inProgress = true; // used in "set page" - PDFView.page = currentId; - updateViewarea.inProgress = false; - } - - var currentScale = PDFView.currentScale; - var currentScaleValue = PDFView.currentScaleValue; - var normalizedScaleValue = currentScaleValue == currentScale ? - currentScale * 100 : currentScaleValue; - - var pageNumber = firstPage.id; - var pdfOpenParams = '#page=' + pageNumber; - pdfOpenParams += '&zoom=' + normalizedScaleValue; - var currentPage = PDFView.pages[pageNumber - 1]; - var topLeft = currentPage.getPagePoint(PDFView.container.scrollLeft, - (PDFView.container.scrollTop - firstPage.y)); - pdfOpenParams += ',' + Math.round(topLeft[0]) + ',' + Math.round(topLeft[1]); - - var store = PDFView.store; - store.initializedPromise.then(function() { - store.set('exists', true); - store.set('page', pageNumber); - store.set('zoom', normalizedScaleValue); - store.set('scrollLeft', Math.round(topLeft[0])); - store.set('scrollTop', Math.round(topLeft[1])); - }); - var href = PDFView.getAnchorUrl(pdfOpenParams); - document.getElementById('viewBookmark').href = href; -} - -window.addEventListener('resize', function webViewerResize(evt) { - if (PDFView.initialized && - (document.getElementById('pageWidthOption').selected || - document.getElementById('pageFitOption').selected || - document.getElementById('pageAutoOption').selected)) - PDFView.parseScale(document.getElementById('scaleSelect').value); - updateViewarea(); -}); - -window.addEventListener('hashchange', function webViewerHashchange(evt) { - PDFView.setHash(document.location.hash.substring(1)); -}); - -window.addEventListener('change', function webViewerChange(evt) { - var files = evt.target.files; - if (!files || files.length === 0) - return; - - // Read the local file into a Uint8Array. - var fileReader = new FileReader(); - fileReader.onload = function webViewerChangeFileReaderOnload(evt) { - var buffer = evt.target.result; - var uint8Array = new Uint8Array(buffer); - PDFView.open(uint8Array, 0); - }; - - var file = files[0]; - fileReader.readAsArrayBuffer(file); - PDFView.setTitleUsingUrl(file.name); - - // URL does not reflect proper document location - hiding some icons. - document.getElementById('viewBookmark').setAttribute('hidden', 'true'); - document.getElementById('download').setAttribute('hidden', 'true'); -}, true); - -function selectScaleOption(value) { - var options = document.getElementById('scaleSelect').options; - var predefinedValueFound = false; - for (var i = 0; i < options.length; i++) { - var option = options[i]; - if (option.value != value) { - option.selected = false; - continue; - } - option.selected = true; - predefinedValueFound = true; - } - return predefinedValueFound; -} - -window.addEventListener('localized', function localized(evt) { - document.getElementsByTagName('html')[0].dir = mozL10n.getDirection(); - - // Adjust the width of the zoom box to fit the content. - PDFView.animationStartedPromise.then( - function() { - var container = document.getElementById('scaleSelectContainer'); - var select = document.getElementById('scaleSelect'); - select.setAttribute('style', 'min-width: inherit;'); - var width = select.clientWidth + 8; - select.setAttribute('style', 'min-width: ' + (width + 20) + 'px;'); - container.setAttribute('style', 'min-width: ' + width + 'px; ' + - 'max-width: ' + width + 'px;'); - }); -}, true); - -window.addEventListener('scalechange', function scalechange(evt) { - var customScaleOption = document.getElementById('customScaleOption'); - customScaleOption.selected = false; - - if (!evt.resetAutoSettings && - (document.getElementById('pageWidthOption').selected || - document.getElementById('pageFitOption').selected || - document.getElementById('pageAutoOption').selected)) { - updateViewarea(); - return; - } - - var predefinedValueFound = selectScaleOption('' + evt.scale); - if (!predefinedValueFound) { - customScaleOption.textContent = Math.round(evt.scale * 10000) / 100 + '%'; - customScaleOption.selected = true; - } - - document.getElementById('zoom_out').disabled = (evt.scale === MIN_SCALE); - document.getElementById('zoom_in').disabled = (evt.scale === MAX_SCALE); - - updateViewarea(); -}, true); - -window.addEventListener('pagechange', function pagechange(evt) { - var page = evt.pageNumber; - if (PDFView.previousPageNumber !== page) { - document.getElementById('pageNumber').value = page; - var selected = document.querySelector('.thumbnail.selected'); - if (selected) - selected.classList.remove('selected'); - var thumbnail = document.getElementById('thumbnailContainer' + page); - thumbnail.classList.add('selected'); - var visibleThumbs = PDFView.getVisibleThumbs(); - var numVisibleThumbs = visibleThumbs.views.length; - // If the thumbnail isn't currently visible scroll it into view. - if (numVisibleThumbs > 0) { - var first = visibleThumbs.first.id; - // Account for only one thumbnail being visible. - var last = numVisibleThumbs > 1 ? - visibleThumbs.last.id : first; - if (page <= first || page >= last) - scrollIntoView(thumbnail); - } - - } - document.getElementById('previous').disabled = (page <= 1); - document.getElementById('next').disabled = (page >= PDFView.pages.length); -}, true); - -// Firefox specific event, so that we can prevent browser from zooming -window.addEventListener('DOMMouseScroll', function(evt) { - if (evt.ctrlKey) { - evt.preventDefault(); - - var ticks = evt.detail; - var direction = (ticks > 0) ? 'zoomOut' : 'zoomIn'; - for (var i = 0, length = Math.abs(ticks); i < length; i++) - PDFView[direction](); - } else if (PDFView.isFullscreen) { - var FIREFOX_DELTA_FACTOR = -40; - PDFView.mouseScroll(evt.detail * FIREFOX_DELTA_FACTOR); - } -}, false); - -window.addEventListener('mousemove', function mousemove(evt) { - if (PDFView.isFullscreen) { - PDFView.showPresentationControls(); - } -}, false); - -window.addEventListener('mousedown', function mousedown(evt) { - if (PDFView.isFullscreen && evt.button === 0) { - // Enable clicking of links in fullscreen mode. - // Note: Only links that point to the currently loaded PDF document works. - var targetHref = evt.target.href; - var internalLink = targetHref && (targetHref.replace(/#.*$/, '') === - window.location.href.replace(/#.*$/, '')); - if (!internalLink) { - // Unless an internal link was clicked, advance a page in fullscreen mode. - evt.preventDefault(); - PDFView.page++; - } - } -}, false); - -window.addEventListener('click', function click(evt) { - if (PDFView.isFullscreen && evt.button === 0) { - // Necessary since preventDefault() in 'mousedown' won't stop - // the event propagation in all circumstances. - evt.preventDefault(); - } -}, false); - -window.addEventListener('keydown', function keydown(evt) { - var handled = false; - var cmd = (evt.ctrlKey ? 1 : 0) | - (evt.altKey ? 2 : 0) | - (evt.shiftKey ? 4 : 0) | - (evt.metaKey ? 8 : 0); - - // First, handle the key bindings that are independent whether an input - // control is selected or not. - if (cmd === 1 || cmd === 8 || cmd === 5 || cmd === 12) { - // either CTRL or META key with optional SHIFT. - switch (evt.keyCode) { - case 70: - if (!PDFView.supportsIntegratedFind) { - PDFFindBar.toggle(); - handled = true; - } - break; - case 61: // FF/Mac '=' - case 107: // FF '+' and '=' - case 187: // Chrome '+' - case 171: // FF with German keyboard - PDFView.zoomIn(); - handled = true; - break; - case 173: // FF/Mac '-' - case 109: // FF '-' - case 189: // Chrome '-' - PDFView.zoomOut(); - handled = true; - break; - case 48: // '0' - case 96: // '0' on Numpad of Swedish keyboard - PDFView.parseScale(DEFAULT_SCALE, true); - handled = false; // keeping it unhandled (to restore page zoom to 100%) - break; - } - } - - // CTRL or META with or without SHIFT. - if (cmd == 1 || cmd == 8 || cmd == 5 || cmd == 12) { - switch (evt.keyCode) { - case 71: // g - if (!PDFView.supportsIntegratedFind) { - PDFFindBar.dispatchEvent('again', cmd == 5 || cmd == 12); - handled = true; - } - break; - } - } - - if (handled) { - evt.preventDefault(); - return; - } - - // Some shortcuts should not get handled if a control/input element - // is selected. - var curElement = document.activeElement; - if (curElement && (curElement.tagName == 'INPUT' || - curElement.tagName == 'SELECT')) { - return; - } - var controlsElement = document.getElementById('toolbar'); - while (curElement) { - if (curElement === controlsElement && !PDFView.isFullscreen) - return; // ignoring if the 'toolbar' element is focused - curElement = curElement.parentNode; - } - - if (cmd === 0) { // no control key pressed at all. - switch (evt.keyCode) { - case 38: // up arrow - case 33: // pg up - case 8: // backspace - if (!PDFView.isFullscreen && PDFView.currentScaleValue !== 'page-fit') { - break; - } - /* in fullscreen mode */ - /* falls through */ - case 37: // left arrow - // horizontal scrolling using arrow keys - if (PDFView.isHorizontalScrollbarEnabled) { - break; - } - /* falls through */ - case 75: // 'k' - case 80: // 'p' - PDFView.page--; - handled = true; - break; - case 27: // esc key - if (!PDFView.supportsIntegratedFind && PDFFindBar.opened) { - PDFFindBar.close(); - handled = true; - } - break; - case 40: // down arrow - case 34: // pg down - case 32: // spacebar - if (!PDFView.isFullscreen && PDFView.currentScaleValue !== 'page-fit') { - break; - } - /* falls through */ - case 39: // right arrow - // horizontal scrolling using arrow keys - if (PDFView.isHorizontalScrollbarEnabled) { - break; - } - /* falls through */ - case 74: // 'j' - case 78: // 'n' - PDFView.page++; - handled = true; - break; - - case 36: // home - if (PDFView.isFullscreen) { - PDFView.page = 1; - handled = true; - } - break; - case 35: // end - if (PDFView.isFullscreen) { - PDFView.page = PDFView.pdfDocument.numPages; - handled = true; - } - break; - - case 82: // 'r' - PDFView.rotatePages(90); - break; - } - } - - if (cmd == 4) { // shift-key - switch (evt.keyCode) { - case 82: // 'r' - PDFView.rotatePages(-90); - break; - } - } - - if (handled) { - evt.preventDefault(); - PDFView.clearMouseScrollState(); - } -}); - -window.addEventListener('beforeprint', function beforePrint(evt) { - PDFView.beforePrint(); -}); - -window.addEventListener('afterprint', function afterPrint(evt) { - PDFView.afterPrint(); -}); - -(function fullscreenClosure() { - function fullscreenChange(e) { - var isFullscreen = document.fullscreenElement || document.mozFullScreen || - document.webkitIsFullScreen; - - if (!isFullscreen) { - PDFView.exitFullscreen(); - } - } - - window.addEventListener('fullscreenchange', fullscreenChange, false); - window.addEventListener('mozfullscreenchange', fullscreenChange, false); - window.addEventListener('webkitfullscreenchange', fullscreenChange, false); -})(); - -(function animationStartedClosure() { - // The offsetParent is not set until the pdf.js iframe or object is visible. - // Waiting for first animation. - var requestAnimationFrame = window.requestAnimationFrame || - window.mozRequestAnimationFrame || - window.webkitRequestAnimationFrame || - window.oRequestAnimationFrame || - window.msRequestAnimationFrame || - function startAtOnce(callback) { callback(); }; - PDFView.animationStartedPromise = new PDFJS.Promise(); - requestAnimationFrame(function onAnimationFrame() { - PDFView.animationStartedPromise.resolve(); - }); -})(); - -//#if B2G -//window.navigator.mozSetMessageHandler('activity', function(activity) { -// var url = activity.source.data.url; -// PDFView.open(url); -// var cancelButton = document.getElementById('activityClose'); -// cancelButton.addEventListener('click', function() { -// activity.postResult('close'); -// }); -//}); -//#endif diff --git a/mediagoblin/templates/mediagoblin/edit/edit_account.html b/mediagoblin/templates/mediagoblin/edit/edit_account.html index 4c4aaf95..461dd6df 100644 --- a/mediagoblin/templates/mediagoblin/edit/edit_account.html +++ b/mediagoblin/templates/mediagoblin/edit/edit_account.html @@ -46,6 +46,7 @@ {% trans %}Change your password.{% endtrans %} </a> </p> + {{ wtforms_util.render_field_div(form.new_email) }} <div class="form_field_input"> <p>{{ form.wants_comment_notification }} {{ wtforms_util.render_label(form.wants_comment_notification) }}</p> diff --git a/mediagoblin/templates/mediagoblin/edit/verification.txt b/mediagoblin/templates/mediagoblin/edit/verification.txt new file mode 100644 index 00000000..d53cd5e8 --- /dev/null +++ b/mediagoblin/templates/mediagoblin/edit/verification.txt @@ -0,0 +1,29 @@ +{# +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +-#} + +{% trans username=username, verification_url=verification_url|safe -%} +Hi, + +We wanted to verify that you are {{ username }}. If this is the case, then +please follow the link below to verify your new email address. + +{{ verification_url }} + +If you are not {{ username }} or didn't request an email change, you can ignore +this email. +{%- endtrans %} diff --git a/mediagoblin/templates/mediagoblin/media_displays/pdf.html b/mediagoblin/templates/mediagoblin/media_displays/pdf.html index e946f3ab..9319e87c 100644 --- a/mediagoblin/templates/mediagoblin/media_displays/pdf.html +++ b/mediagoblin/templates/mediagoblin/media_displays/pdf.html @@ -46,19 +46,21 @@ {%- endblock %} {% block mediagoblin_media %} -{% if pdf_js %} -<iframe width=640px height=480px - src="{{ request.staticdirect('/extlib/pdf.js/web/viewer.html') }}?file={{ pdf_view }} "> -</iframe> - -{% else %} - <a href="{{ pdf_view }}"> - <img id="medium" - class="media_image" - src="{{ medium_view }}" - alt="{% trans media_title=media.title -%} Image for {{ media_title}}{% endtrans %}"/> - </a> -{% endif %} + {% if pdf_js %} + <iframe width="640px" height="480px" + src="{{ request.staticdirect('/extlib/pdf.js/web/viewer.html') }}?file={{ pdf_view }} "> + </iframe> + {% else %} + <a href="{{ pdf_view }}"> + <img id="medium" + class="media_image" + src="{{ medium_view }}" + alt=" + {%- trans media_title=media.title -%} + Image for {{ media_title}} + {%- endtrans %}"/> + </a> + {% endif %} {% endblock %} {% block mediagoblin_sidebar %} diff --git a/mediagoblin/tests/test_auth.py b/mediagoblin/tests/test_auth.py index 755727f9..48b148dd 100644 --- a/mediagoblin/tests/test_auth.py +++ b/mediagoblin/tests/test_auth.py @@ -156,20 +156,15 @@ def test_register_views(test_app): assert path == u'/auth/verify_email/' parsed_get_params = urlparse.parse_qs(get_params) - ### user should have these same parameters - assert parsed_get_params['userid'] == [ - unicode(new_user.id)] - assert parsed_get_params['token'] == [ - new_user.verification_key] - ## Try verifying with bs verification key, shouldn't work template.clear_test_template_context() response = test_app.get( - "/auth/verify_email/?userid=%s&token=total_bs" % unicode( - new_user.id)) + "/auth/verify_email/?token=total_bs") response.follow() - context = template.TEMPLATE_TEST_CONTEXT[ - 'mediagoblin/user_pages/user.html'] + + # Correct redirect? + assert urlparse.urlsplit(response.location)[2] == '/' + # assert context['verification_successful'] == True # TODO: Would be good to test messages here when we can do so... new_user = mg_globals.database.User.find_one( @@ -233,35 +228,17 @@ def test_register_views(test_app): path = urlparse.urlsplit(email_context['verification_url'])[2] get_params = urlparse.urlsplit(email_context['verification_url'])[3] - assert path == u'/auth/forgot_password/verify/' parsed_get_params = urlparse.parse_qs(get_params) - - # user should have matching parameters - new_user = mg_globals.database.User.find_one({'username': u'happygirl'}) - assert parsed_get_params['userid'] == [unicode(new_user.id)] - assert parsed_get_params['token'] == [new_user.fp_verification_key] - - ### The forgotten password token should be set to expire in ~ 10 days - # A few ticks have expired so there are only 9 full days left... - assert (new_user.fp_token_expire - datetime.datetime.now()).days == 9 + assert path == u'/auth/forgot_password/verify/' ## Try using a bs password-changing verification key, shouldn't work template.clear_test_template_context() response = test_app.get( - "/auth/forgot_password/verify/?userid=%s&token=total_bs" % unicode( - new_user.id), status=404) - assert response.status.split()[0] == u'404' # status="404 NOT FOUND" + "/auth/forgot_password/verify/?token=total_bs") + response.follow() - ## Try using an expired token to change password, shouldn't work - template.clear_test_template_context() - new_user = mg_globals.database.User.find_one({'username': u'happygirl'}) - real_token_expiration = new_user.fp_token_expire - new_user.fp_token_expire = datetime.datetime.now() - new_user.save() - response = test_app.get("%s?%s" % (path, get_params), status=404) - assert response.status.split()[0] == u'404' # status="404 NOT FOUND" - new_user.fp_token_expire = real_token_expiration - new_user.save() + # Correct redirect? + assert urlparse.urlsplit(response.location)[2] == '/' ## Verify step 1 of password-change works -- can see form to change password template.clear_test_template_context() @@ -272,7 +249,6 @@ def test_register_views(test_app): template.clear_test_template_context() response = test_app.post( '/auth/forgot_password/verify/', { - 'userid': parsed_get_params['userid'], 'password': 'iamveryveryhappy', 'token': parsed_get_params['token']}) response.follow() diff --git a/mediagoblin/tests/test_edit.py b/mediagoblin/tests/test_edit.py index 08b4f8cf..2afc519a 100644 --- a/mediagoblin/tests/test_edit.py +++ b/mediagoblin/tests/test_edit.py @@ -15,14 +15,14 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. import urlparse -import pytest from mediagoblin import mg_globals from mediagoblin.db.models import User from mediagoblin.tests.tools import fixture_add_user -from mediagoblin.tools import template +from mediagoblin.tools import template, mail from mediagoblin.auth.lib import bcrypt_check_password + class TestUserEdit(object): def setup(self): # set up new user @@ -141,4 +141,68 @@ class TestUserEdit(object): assert form.url.errors == [ u'This address contains errors'] + def test_email_change(self, test_app): + self.login(test_app) + + # Test email already in db + template.clear_test_template_context() + test_app.post( + '/edit/account/', { + 'new_email': 'chris@example.com', + 'password': 'toast'}) + + # Check form errors + context = template.TEMPLATE_TEST_CONTEXT[ + 'mediagoblin/edit/edit_account.html'] + assert context['form'].new_email.errors == [ + u'Sorry, a user with that email address already exists.'] + + # Test successful email change + template.clear_test_template_context() + res = test_app.post( + '/edit/account/', { + 'new_email': 'new@example.com', + 'password': 'toast'}) + res.follow() + + # Correct redirect? + assert urlparse.urlsplit(res.location)[2] == '/u/chris/' + + # Make sure we get email verification and try verifying + assert len(mail.EMAIL_TEST_INBOX) == 1 + message = mail.EMAIL_TEST_INBOX.pop() + assert message['To'] == 'new@example.com' + email_context = template.TEMPLATE_TEST_CONTEXT[ + 'mediagoblin/edit/verification.txt'] + assert email_context['verification_url'] in \ + message.get_payload(decode=True) + + path = urlparse.urlsplit(email_context['verification_url'])[2] + assert path == u'/edit/verify_email/' + + ## Try verifying with bs verification key, shouldn't work + template.clear_test_template_context() + res = test_app.get( + "/edit/verify_email/?token=total_bs") + res.follow() + + # Correct redirect? + assert urlparse.urlsplit(res.location)[2] == '/' + + # Email shouldn't be saved + email_in_db = mg_globals.database.User.find_one( + {'email': 'new@example.com'}) + email = User.query.filter_by(username='chris').first().email + assert email_in_db is None + assert email == 'chris@example.com' + + # Verify email activation works + template.clear_test_template_context() + get_params = urlparse.urlsplit(email_context['verification_url'])[3] + res = test_app.get('%s?%s' % (path, get_params)) + res.follow() + + # New email saved? + email = User.query.filter_by(username='chris').first().email + assert email == 'new@example.com' # test changing the url inproperly diff --git a/mediagoblin/tools/response.py b/mediagoblin/tools/response.py index aaf31d0b..0be1f835 100644 --- a/mediagoblin/tools/response.py +++ b/mediagoblin/tools/response.py @@ -77,7 +77,7 @@ def render_http_exception(request, exc, description): elif stock_desc and exc.code == 404: return render_404(request) - return render_error(request, title=exc.args[0], + return render_error(request, title='{0} {1}'.format(exc.code, exc.name), err_msg=description, status=exc.code) |