diff options
author | Evgeny Fadeev <evgeny.fadeev@gmail.com> | 2014-04-01 22:46:43 -0300 |
---|---|---|
committer | Evgeny Fadeev <evgeny.fadeev@gmail.com> | 2014-04-01 22:46:43 -0300 |
commit | dbe93591ae5bbf4f43b025e78d0b837fca8a1789 (patch) | |
tree | 5621cddcb6aa68ef816028ca1be7edadd4331f08 | |
parent | be9f9fc3f5e7b684d849279765ffd048d3a87c55 (diff) | |
parent | 3c125297edfe588dc195925c43c6a1ea54ac7060 (diff) | |
download | askbot-dbe93591ae5bbf4f43b025e78d0b837fca8a1789.tar.gz askbot-dbe93591ae5bbf4f43b025e78d0b837fca8a1789.tar.bz2 askbot-dbe93591ae5bbf4f43b025e78d0b837fca8a1789.zip |
Merge branch 'master' into user-questions-pagination
201 files changed, 8590 insertions, 5117 deletions
@@ -17,6 +17,8 @@ settings.py *.iml lint env +.vagrant +/Vagrantfile /custom_settings /static django @@ -2,14 +2,39 @@ Askbot - Q&A forum =================== -This is Askbot project - open source Q&A system, like StackOverflow, Yahoo Answers and some others +This is Askbot project - open source Q&A system, like StackOverflow, Yahoo Answers and some others. +Askbot is based on code of CNPROG, originally created by Mike Chen +and Sailing Cai and some code written for OSQA. Demos and hosting are available at http://askbot.com. -**Translators:** please translate at https://www.transifex.com/projects/p/askbot/. +How to contribute +================= + +**Translators: DO NOT use git to contribute translations!!!** instead - translate at https://www.transifex.com/projects/p/askbot/. All documentation is in the directory askbot/doc -Askbot is based on code of CNPROG, originally created by Mike Chen -and Sailing Cai and some code written for OSQA. Askbot had officially launched -in April 2010. +To contribute code, please fork and make pull requests. + +If you are planning to add a new feature, please bring it up for discussion at our forum +(http://askbot.org/en/questions/) and mention that are willing to develop this feature. + +We will merge obvious bug fixes without questions, for more complex fixes +please add a test case that fails before and passes after applying your fix. + +**Notes on using git for Askbot.** Please use topic branches only - one per feature or bugfix. +Do not add multiple features and fixes into the same branch - +those are much harder to understand and merge. + +Follow https://help.github.com/articles/fork-a-repo to to learn how to use +`fetch` and `push` as well as other help on using git. + +License, copyright and trademarks +================================= +Askbot software is licensed under GPL, version 3. + +Copyright Askbot S.p.A and the project contributors, 2010-2013. + +"Askbot" is a trademark and service mark registered in the United States, number 4323777. + diff --git a/askbot/__init__.py b/askbot/__init__.py index e96719c1..2ac9b6fb 100644 --- a/askbot/__init__.py +++ b/askbot/__init__.py @@ -7,7 +7,7 @@ basic actions on behalf of the forum application import os import platform -VERSION = (0, 7, 48) +VERSION = (0, 7, 49) #keys are module names used by python imports, #values - the package qualifier to use for pip @@ -33,7 +33,7 @@ REQUIREMENTS = { 'recaptcha_works': 'django-recaptcha-works', 'openid': 'python-openid', 'pystache': 'pystache==0.3.1', - 'pytz': 'pytz', + 'pytz': 'pytz==2013b', 'tinymce': 'django-tinymce==1.5.1b2', 'longerusername': 'longerusername', 'bs4': 'beautifulsoup4', diff --git a/askbot/conf/__init__.py b/askbot/conf/__init__.py index 0f92bf99..c1ed6ef0 100644 --- a/askbot/conf/__init__.py +++ b/askbot/conf/__init__.py @@ -28,6 +28,7 @@ import askbot.conf.badges import askbot.conf.login_providers import askbot.conf.access_control import askbot.conf.site_modes +import askbot.conf.words #import main settings object from askbot.conf.settings_wrapper import settings diff --git a/askbot/conf/access_control.py b/askbot/conf/access_control.py index 0e3dcb54..c339da6d 100644 --- a/askbot/conf/access_control.py +++ b/askbot/conf/access_control.py @@ -1,6 +1,8 @@ from askbot.conf.settings_wrapper import settings from askbot.conf.super_groups import LOGIN_USERS_COMMUNICATION from askbot.deps import livesettings +from askbot.deps.livesettings import BooleanValue +from askbot.deps.livesettings import StringValue from django.utils.translation import ugettext_lazy as _ ACCESS_CONTROL = livesettings.ConfigurationGroup( @@ -10,6 +12,26 @@ ACCESS_CONTROL = livesettings.ConfigurationGroup( ) settings.register( + BooleanValue( + ACCESS_CONTROL, + 'READ_ONLY_MODE_ENABLED', + default=False, + description=_('Make site read-only'), + ) +) + +settings.register( + StringValue( + ACCESS_CONTROL, + 'READ_ONLY_MESSAGE', + default=_( + 'The site is temporarily read-only. ' + 'Only viewing of the content is possible at the moment.' + ) + ) +) + +settings.register( livesettings.BooleanValue( ACCESS_CONTROL, 'ASKBOT_CLOSED_FORUM_MODE', diff --git a/askbot/conf/group_settings.py b/askbot/conf/group_settings.py index 804b5502..cacbdacb 100644 --- a/askbot/conf/group_settings.py +++ b/askbot/conf/group_settings.py @@ -19,6 +19,7 @@ settings.register( ) ) +""" def group_name_update_callback(old_name, new_name): from askbot.models.tag import clean_group_name from askbot.models import Group @@ -32,6 +33,7 @@ def group_name_update_callback(old_name, new_name): group.name = cleaned_new_name group.save() return new_name +""" settings.register( @@ -41,7 +43,7 @@ settings.register( default = _('everyone'), description = _('Global user group name'), help_text = _('All users belong to this group automatically'), - update_callback=group_name_update_callback + #update_callback=group_name_update_callback ) ) diff --git a/askbot/conf/login_providers.py b/askbot/conf/login_providers.py index 36f71502..faa6ae8c 100644 --- a/askbot/conf/login_providers.py +++ b/askbot/conf/login_providers.py @@ -62,6 +62,59 @@ settings.register( ) ) +settings.register( + livesettings.BooleanValue( + LOGIN_PROVIDERS, + 'SIGNIN_CUSTOM_OPENID_ENABLED', + default=False, + description=_('Enable custom OpenID login') + ) +) + +settings.register( + livesettings.StringValue( + LOGIN_PROVIDERS, + 'SIGNIN_CUSTOM_OPENID_NAME', + default=_('Custom OpenID'), + description=_('Short name for the custom OpenID provider') + ) +) + +CUSTOM_OPENID_MODE_CHOICES = ( + ('openid-direct', _('Direct button login')), + ('openid-username', _('Requires username')) +) + +settings.register( + livesettings.StringValue( + LOGIN_PROVIDERS, + 'SIGNIN_CUSTOM_OPENID_MODE', + default='openid-direct', + description=_('Type of OpenID login'), + choices=CUSTOM_OPENID_MODE_CHOICES + ) +) + +settings.register( + livesettings.ImageValue( + LOGIN_PROVIDERS, + 'SIGNIN_CUSTOM_OPENID_LOGIN_BUTTON', + default='/images/logo.gif', + description=_('Upload custom OpenID icon'), + url_resolver=skin_utils.get_media_url + ) +) + +settings.register( + livesettings.StringValue( + LOGIN_PROVIDERS, + 'SIGNIN_CUSTOM_OPENID_ENDPOINT', + default='http://example.com', + description=_('Custom OpenID endpoint'), + help_text=_('Important: with the "username" mode must have a %%(username)s placeholder e.g. http://example.com/%%(username)s/'), + ) +) + providers = ( 'local', 'AOL', diff --git a/askbot/conf/minimum_reputation.py b/askbot/conf/minimum_reputation.py index fd4df4b3..58b41c18 100644 --- a/askbot/conf/minimum_reputation.py +++ b/askbot/conf/minimum_reputation.py @@ -132,15 +132,6 @@ settings.register( settings.register( livesettings.IntegerValue( MIN_REP, - 'MIN_REP_TO_CLOSE_OWN_QUESTIONS', - default=25, - description=_('Close own questions'), - ) -) - -settings.register( - livesettings.IntegerValue( - MIN_REP, 'MIN_REP_TO_RETAG_OTHERS_QUESTIONS', default=50, description=_('Retag questions posted by other people') @@ -148,15 +139,6 @@ settings.register( ) settings.register( - livesettings.IntegerValue( - MIN_REP, - 'MIN_REP_TO_REOPEN_OWN_QUESTIONS', - default=50, - description=_('Reopen own questions') - ) -) - -settings.register( livesettings.IntegerValue( MIN_REP, 'MIN_REP_TO_EDIT_WIKI', @@ -188,7 +170,7 @@ settings.register( MIN_REP, 'MIN_REP_TO_CLOSE_OTHERS_QUESTIONS', default=200, - description=_('Close questions asked by others') + description=_('Close and reopen questions') ) ) diff --git a/askbot/conf/settings_wrapper.py b/askbot/conf/settings_wrapper.py index 0a4ba45f..7fc9540d 100644 --- a/askbot/conf/settings_wrapper.py +++ b/askbot/conf/settings_wrapper.py @@ -20,6 +20,7 @@ at run time askbot.deps.livesettings is a module developed for satchmo project """ +from django.conf import settings as django_settings from django.core.cache import cache from askbot.deps.livesettings import SortedDotDict, config_register from askbot.deps.livesettings.functions import config_get @@ -47,7 +48,11 @@ class ConfigSettings(object): will be required in code to convert an app depending on django.conf.settings to askbot.deps.livesettings """ - return getattr(self.__instance, key).value + hardcoded_setting = getattr(django_settings, 'ASKBOT_' + key, None) + if hardcoded_setting is None: + return getattr(self.__instance, key).value + else: + return hardcoded_setting def get_default(self, key): """return the defalut value for the setting""" @@ -93,24 +98,39 @@ class ConfigSettings(object): self.__group_map[key] = group_key def as_dict(self): - settings = cache.get('askbot-livesettings') + cache_key = get_bulk_cache_key() + settings = cache.get(cache_key) if settings: return settings else: - self.prime_cache() - return cache.get('askbot-livesettings') + self.prime_cache(cache_key) + return cache.get(cache_key) @classmethod - def prime_cache(cls, **kwargs): + def prime_cache(cls, cache_key, **kwargs): """reload all settings into cache as dictionary """ out = dict() for key in cls.__instance.keys(): #todo: this is odd that I could not use self.__instance.items() mapping here - out[key] = cls.__instance[key].value - cache.set('askbot-livesettings', out) + hardcoded_setting = getattr(django_settings, 'ASKBOT_' + key, None) + if hardcoded_setting is None: + out[key] = cls.__instance[key].value + else: + out[key] = hardcoded_setting + cache.set(cache_key, out) + + +def get_bulk_cache_key(): + from askbot.utils.translation import get_language + return 'askbot-settings-' + get_language() + + +def prime_cache_handler(*args, **kwargs): + cache_key = get_bulk_cache_key() + ConfigSettings.prime_cache(cache_key) -signals.configuration_value_changed.connect(ConfigSettings.prime_cache) +signals.configuration_value_changed.connect(prime_cache_handler) #settings instance to be used elsewhere in the project settings = ConfigSettings() diff --git a/askbot/conf/site_modes.py b/askbot/conf/site_modes.py index feadd32b..29e537db 100644 --- a/askbot/conf/site_modes.py +++ b/askbot/conf/site_modes.py @@ -6,7 +6,8 @@ Site modes settings: """ from askbot.conf.settings_wrapper import settings from askbot.conf.super_groups import REP_AND_BADGES -from askbot.deps.livesettings import ConfigurationGroup, BooleanValue +from askbot.deps.livesettings import ConfigurationGroup +from askbot.deps.livesettings import BooleanValue from django.utils.translation import ugettext_lazy as _ LARGE_SITE_MODE_SETTINGS = { @@ -20,9 +21,7 @@ LARGE_SITE_MODE_SETTINGS = { 'MIN_REP_TO_DELETE_OTHERS_COMMENTS': 2000, 'MIN_REP_TO_DELETE_OTHERS_POSTS': 5000, 'MIN_REP_TO_UPLOAD_FILES': 60, - 'MIN_REP_TO_CLOSE_OWN_QUESTIONS': 250, 'MIN_REP_TO_RETAG_OTHERS_QUESTIONS': 500, - 'MIN_REP_TO_REOPEN_OWN_QUESTIONS': 500, 'MIN_REP_TO_EDIT_WIKI': 750, 'MIN_REP_TO_EDIT_OTHERS_POSTS': 2000, 'MIN_REP_TO_VIEW_OFFENSIVE_FLAGS': 2000, diff --git a/askbot/conf/site_settings.py b/askbot/conf/site_settings.py index 805cc5dc..0ac5b081 100644 --- a/askbot/conf/site_settings.py +++ b/askbot/conf/site_settings.py @@ -7,8 +7,11 @@ from askbot.conf.super_groups import CONTENT_AND_UI from askbot.deps import livesettings from django.utils.translation import ugettext_lazy as _ from django.conf import settings as django_settings +from django.core.validators import ValidationError, validate_email +import re from urlparse import urlparse + QA_SITE_SETTINGS = livesettings.ConfigurationGroup( 'QA_SITE_SETTINGS', _('URLS, keywords & greetings'), @@ -132,3 +135,30 @@ settings.register( ) ) ) + +def feedback_emails_callback(old_value, new_value): + """validates the fedback emails list""" + emails = [] + for value in re.split('\s*,\s*', new_value): + if not value: + continue + try: + validate_email(value) + emails.append(value) + except ValidationError: + raise ValueError( + _("'%(value)s' is not a valid email") % {'value': value}) + return ", ".join(emails) + +settings.register( + livesettings.StringValue( + QA_SITE_SETTINGS, + 'FEEDBACK_EMAILS', + description=_('Internal feedback form email recipients'), + help_text=_( + 'Comma separated list. If left empty, feedback mails are sent ' + 'to admins and moderators' + ), + update_callback=feedback_emails_callback + ) +) diff --git a/askbot/conf/user_settings.py b/askbot/conf/user_settings.py index a2d8d386..d29e9278 100644 --- a/askbot/conf/user_settings.py +++ b/askbot/conf/user_settings.py @@ -37,8 +37,17 @@ settings.register( livesettings.BooleanValue( USER_SETTINGS, 'EDITABLE_SCREEN_NAME', - default = True, - description = _('Allow editing user screen name') + default=True, + description=_('Allow editing user screen name') + ) +) + +settings.register( + livesettings.BooleanValue( + USER_SETTINGS, + 'SHOW_ADMINS_PRIVATE_USER_DATA', + default=False, + description=_('Show email addresses to moderators') ) ) diff --git a/askbot/conf/words.py b/askbot/conf/words.py new file mode 100644 index 00000000..be4eb191 --- /dev/null +++ b/askbot/conf/words.py @@ -0,0 +1,912 @@ +""" +General skin settings +""" +from askbot.conf.settings_wrapper import settings +from askbot.deps.livesettings import ConfigurationGroup +from askbot.deps.livesettings import values +from django.utils.translation import ugettext_lazy as _ +from askbot.skins import utils as skin_utils +from askbot import const +from askbot.conf.super_groups import CONTENT_AND_UI + +WORDS = ConfigurationGroup( + 'WORDS', + _('Site terms vocabulary'), + super_group = CONTENT_AND_UI + ) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_ASK_YOUR_QUESTION', + default=_('Ask Your Question'), + description=_('Ask Your Question'), + help_text=_('Used on a button') + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_PLEASE_ENTER_YOUR_QUESTION', + default=_('Please enter your question'), + description=_('Please enter your question'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_ASK_THE_GROUP', + default=_('Ask the Group'), + description=_('Ask the Group'), + help_text=_('Used on a button') + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_POST_YOUR_ANSWER', + default=_('Post Your Answer'), + description=_('Post Your Answer'), + help_text=_('Used on a button') + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_ANSWER_YOUR_OWN_QUESTION', + default=_('Answer Your Own Question'), + description=_('Answer Your Own Question'), + help_text=_('Used on a button') + ) +) + +settings.register( + values.LongStringValue( + WORDS, + 'WORDS_INSTRUCTION_TO_ANSWER_OWN_QUESTION', + default=_( + '<span class="big strong">You are welcome to answer your own question</span>, ' + 'but please make sure to give an <strong>answer</strong>. ' + 'Remember that you can always <strong>revise your original question</strong>.' + ), + description=_('Instruction to answer own questions'), + help_text=_('HTML is allowed') + ) +) + +settings.register( + values.LongStringValue( + WORDS, + 'WORDS_INSTRUCTION_TO_POST_ANONYMOUSLY', + default=_( + '<span class="strong big">Please start posting anonymously</span> - ' + 'your entry will be published after you log in or create a new account.' + ), + description=_('Instruction to post anonymously'), + help_text=_('HTML is allowed') + ) +) + +settings.register( + values.LongStringValue( + WORDS, + 'WORDS_INSTRUCTION_TO_GIVE_ANSWERS', + default=_( + 'Please try to <strong>give a substantial answer</strong>, ' + 'for discussions, <strong>please use comments</strong> and ' + '<strong>do remember to vote</strong>.' + ), + description=_('Instruction to give answers'), + help_text=_('HTML is allowed') + ) +) + +settings.register( + values.LongStringValue( + WORDS, + 'WORDS_INSTRUCTION_FOR_THE_CATEGORY_SELECTOR', + default=_( + 'Categorize your question using this tag selector or ' + 'entering text in tag box.' + ), + description=_('Instruction for the catogory selector'), + help_text=_('Plain text only') + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_EDIT_YOUR_PREVIOUS_ANSWER', + default=_('Edit Your Previous Answer'), + description=_('Edit Your Previous Answer'), + help_text=_('Used on a button') + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_ASK_QUESTIONS', + default=_('ask questions'), + description=_('ask questions') + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_ASKED', + default=_('asked'), + description=_('asked'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_ASKED_FIRST_QUESTION', + default=_('Asked first question'), + description=_('Asked first question') + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_ASKED_BY_ME', + default=_('Asked by me'), + description=_('Asked by me') + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_ASKED_A_QUESTION', + default=_('Asked a question'), + description=_('Asked a question') + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_ANSWERED_A_QUESTION', + default=_('Answered a question'), + description=_('Answered a question') + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_ANSWERED_BY_ME', + default=_('Answered by me'), + description=_('Answered by me') + ) +) + + +settings.register( + values.StringValue( + WORDS, + 'WORDS_ACCEPTED_AN_ANSWER', + default=_('accepted an answer'), + description=_('accepted an answer') + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_GAVE_ACCEPTED_ANSWER', + default=_('Gave accepted answer'), + description=_('Gave accepted answer') + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_ANSWERED', + default=_('answered'), + description=_('answered'), + ) +) + +settings.register( + values.LongStringValue( + WORDS, + 'WORDS_QUESTIONS_COUNTABLE_FORMS', + default='question\nquestions', + description=_('Countable plural forms for "queston"'), + help_text=_('Enter one form per line, pay attention') + ) +) + +settings.register( + values.LongStringValue( + WORDS, + 'WORDS_ANSWERS_COUNTABLE_FORMS', + default='answer\nanswers', + description=_('Countable plural forms for "answer"'), + help_text=_('Enter one form per line, pay attention') + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_QUESTION_SINGULAR', + default=_('question'), + description=_('question (noun, singular)'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_QUESTION_PLURAL', + default=_('questions'), + description=_('questions (noun, plural)'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_UNANSWERED_QUESTION_SINGULAR', + default=_('unanswered question'), + description=_('unanswered question (singular)'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_UNANSWERED_QUESTION_PLURAL', + default=_('unanswered questions'), + description=_('unanswered questions (plural)'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_ANSWER_SINGULAR', + default=_('answer'), + description=_('answer (noun, sungular)'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_QUESTION_VOTED_UP', + default=_('Question voted up'), + description=_('Question voted up'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_ANSWER_VOTED_UP', + default=_('Answer voted up'), + description=_('Answer voted up'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_UPVOTED_ANSWER', + default=_('upvoted answer'), + description=_('upvoted answer'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_NICE_ANSWER', + default=_('Nice Answer'), + description=_('Nice Answer'), + help_text='Badge name' + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_NICE_QUESTION', + default=_('Nice Question'), + description=_('Nice Question'), + help_text='Badge name' + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_GOOD_ANSWER', + default=_('Good Answer'), + description=_('Good Answer'), + help_text='Badge name' + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_GOOD_QUESTION', + default=_('Good Question'), + description=_('Good Question'), + help_text='Badge name' + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_GREAT_ANSWER', + default=_('Great Answer'), + description=_('Great Answer'), + help_text='Badge name' + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_GREAT_QUESTION', + default=_('Great Question'), + description=_('Great Question'), + help_text='Badge name' + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_POPULAR_QUESTION', + default=_('Popular Question'), + description=_('Popular Question'), + help_text='Badge name' + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_NOTABLE_QUESTION', + default=_('Notable Question'), + description=_('Notable Question'), + help_text='Badge name' + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_FAMOUS_QUESTION', + default=_('Famous Question'), + description=_('Famous Question'), + help_text='Badge name' + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_STELLAR_QUESTION', + default=_('Stellar Question'), + description=_('Stellar Question'), + help_text='Badge name' + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_FAVORITE_QUESTION', + default=_('Favorite Question'), + description=_('Favorite Question'), + help_text='Badge name' + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_UPVOTED_ANSWERS', + default=_('upvoted answers'), + description=_('upvoted answers'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_SHOW_ONLY_QUESTIONS_FROM', + default=_('Show only questions from'), + description=_('Show only questions from'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_PLEASE_ASK_YOUR_QUESTION_HERE', + default=_('Please ask your question here'), + description=_('Please ask your question here'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_THIS_QUESTION_HAS_BEEN_DELETED', + default=_( + 'Sorry, this question has been ' + 'deleted and is no longer accessible' + ), + description=_('This question has been deleted') + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_PLEASE_ENTER_YOUR_QUESTION', + default=_('Please enter your question'), + description=_('Please enter your question'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_DELETE_YOUR_QUESTION', + default=_('delete your question'), + description=_('delete your question'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_ASK_A_QUESTION_INTERESTING_TO_THIS_COMMUNITY', + default=_('ask a question interesting to this community'), + description=_('ask a question interesting to this community'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_NO_QUESTIONS_HERE', + default=_('No questions here.'), + description=_('No questions here.'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_PLEASE_FOLLOW_QUESTIONS', + default=_('Please follow some questions or follow some users.'), + description=_('Please follow some questions or follow some users.'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_PLEASE_FEEL_FREE_TO_ASK_YOUR_QUESTION', + default=_('Please feel free to ask your question!'), + description=_('Please feel free to ask your question!'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_SWAP_WITH_QUESTION', + default=_('swap with question'), + description=_('swap with question'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_REPOST_AS_A_QUESTION_COMMENT', + default=_('repost as a question comment'), + description=_('repost as a question comment'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_ONLY_ONE_ANSWER_PER_USER_IS_ALLOWED', + default=_('(only one answer per user is allowed)'), + description=_('Only one answer per user is allowed'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_ACCEPT_BEST_ANSWERS_FOR_YOUR_QUESTIONS', + default=_('Accept the best answers for your questions'), + description=_('Accept the best answers for your questions') + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_AUTHOR_OF_THE_QUESTION', + default=_('author of the question'), + description=_('author of the question') + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_ACCEPT_OR_UNACCEPT_THE_BEST_ANSWER', + default=_('accept or unaccept the best answer'), + description=_('accept or unaccept the best answer') + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_ACCEPT_OR_UNACCEPT_OWN_ANSWER', + default=_('accept or unaccept your own answer'), + description=_('accept or unaccept your own answer'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_YOU_ALREADY_GAVE_AN_ANSWER', + default=_('you already gave an answer'), + description=_('you already gave an answer'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_GAVE_AN_ANSWER', + default=_('gave an answer'), + description=_('gave an answer'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_ANSWER_OWN_QUESTIONS', + default=_('answer own questions'), + description=_('answer own questions'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_ANSWERED_OWN_QUESTION', + default=_('Answered own question'), + description=_('Answered own question'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_REPOST_AS_A_COMMENT_UNDER_THE_OLDER_ANSWER', + default=_('repost as a comment under older answer'), + description=_('repost as a comment under older answer'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_INVITE_OTHERS_TO_HELP_ANSWER_THIS_QUESTION', + default=_('invite other to help answer this question'), + description=_('invite other to help answer this question'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_RELATED_QUESTIONS', + default=_('Related questions'), + description=_('Related questions'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_QUESTION_TOOLS', + default=_('Question Tools'), + description=_('Question Tools'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_THIS_QUESTION_IS_CURRENTLY_SHARED_ONLY_WITH', + default=_('Phrase: this question is currently shared only with:'), + description=_('Phrase: this question is currently shared only with:'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_BE_THE_FIRST_TO_ANSWER_THIS_QUESTION', + default=_('Be the first one to answer this question!'), + description=_('Be the first one to answer this question!'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_FOLLOWED_QUESTIONS', + default=_('followed questions'), + description=_('followed questions'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_FOLLOW_QUESTIONS', + default=_('follow questions'), + description=_('follow questions'), + help_text=_('Indefinite form') + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_COMMENTS_AND_ANSWERS_TO_OTHERS_QUESTIONS', + default = '', + description = _('Phrase: comments and answers to others questions'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_YOU_CAN_POST_QUESTIONS_BY_EMAILING_THEM_AT', + default=_('You can post questions by emailing them at'), + description=_('You can post questions by emailing them at'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_LIST_OF_QUESTIONS', + default=_('List of questions'), + description=_('List of questions'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_COMMUNITY_GIVES_YOU_AWARDS', + default=_('Community gives you awards for your questions, answers and votes'), + description=_('Community gives you awards for your questions, answers and votes'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_CLOSE_QUESTION', + default=_('Close question'), + description=_('Close question'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_CLOSE_QUESTIONS', + default=_('close questions'), + description=_('close questions'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_EDIT_QUESTION', + default=_('Edit question'), + description=_('Edit question'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_QUESTION_IN_ONE_SENTENCE', + default=_('Question - in one sentence'), + description=_('Question - in one sentence'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_RETAG_QUESTION', + default=_('Retag question'), + description=_('Retag question'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_RETAG_QUESTIONS', + default=_('retag questions'), + description=_('retag questions'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_REOPEN_QUESTION', + default=_('Reopen question'), + description=_('Reopen question'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_THERE_ARE_NO_UNANSWERED_QUESTIONS_HERE', + default=_('There are no unanswered questions here'), + description=_('There are no unanswered questions here'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_THIS_ANSWER_HAS_BEEN_SELECTED_AS_CORRECT', + default=_('this answer has been selected as correct'), + description=_('this answer has been selected as correct'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_MARK_THIS_ANSWER_AS_CORRECT', + default=_('mark this answer as correct'), + description=_('mark this answer as correct'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_LOGIN_SIGNUP_TO_ANSWER', + default=_('Login/Signup to Answer'), + description=_('Login/Signup to Answer'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_YOUR_ANSWER', + default=_('Your Answer'), + description=_('Your Answer'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_ADD_ANSWER', + default=_('Add Answer'), + description=_('Add Answer'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_GIVE_AN_ANSWER_INTERESTING_TO_THIS_COMMUNITY', + default=_('give an answer interesting to this community'), + description=_('give an answer interesting to this community'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_GIVE_AN_ANSWER_INTERESTING_TO_THIS_COMMUNITY', + default=_('give an answer interesting to this community'), + description=_('give an answer interesting to this community'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_GIVE_A_GOOD_ANSWER', + default=_('give a substantial answer'), + description=_('give a substantial answer'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_TRY_TO_GIVE_AN_ANSWER', + default=_('try to give an answer, rather than engage into a discussion'), + description=_('try to give an answer, rather than engage into a discussion'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_SHOW_ONLY_SELECTED_ANSWERS_TO_ENQUIRERS', + default=_('show only selected answers to enquirers'), + description=_('show only selected answers to enquirers'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_UNANSWERED', + default = _('UNANSWERED'), + description = _('UNANSWERED'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_EDIT_ANSWER', + default=_('Edit Answer'), + description=_('Edit Answer'), + ) +) + +settings.register( + values.StringValue( + WORDS, + 'WORDS_ANSWERED', + default=_('Answered'), + description=_('Answered'), + ) +) diff --git a/askbot/const/__init__.py b/askbot/const/__init__.py index ff1d0883..35f9b26b 100644 --- a/askbot/const/__init__.py +++ b/askbot/const/__init__.py @@ -7,6 +7,7 @@ text in this project, all unicode text go here. from django.utils.translation import ugettext_lazy as _ import re +#todo: customize words CLOSE_REASONS = ( (1, _('duplicate question')), (2, _('question is off-topic or not relevant')), @@ -122,6 +123,7 @@ DEFAULT_ANSWER_SORT_METHOD = 'votes' #of Q.run_advanced_search DEFAULT_POST_SORT_METHOD = 'activity-desc' +#todo: customize words POST_SCOPE_LIST = ( ('all', _('all')), ('unanswered', _('unanswered')), @@ -155,7 +157,9 @@ UNANSWERED_QUESTION_MEANING_CHOICES = ( #to do full string match #IMPRTANT: tag related regexes must be portable between js and python TAG_CHARS = r'\w+.#-' -TAG_REGEX_BARE = r'[%s]+' % TAG_CHARS +TAG_FIRST_CHARS = r'\w' +TAG_FORBIDDEN_FIRST_CHARS = r'#' +TAG_REGEX_BARE = r'%s[%s]+' % (TAG_FIRST_CHARS, TAG_CHARS) TAG_REGEX = r'^%s$' % TAG_REGEX_BARE TAG_SPLIT_REGEX = r'[ ,]+' TAG_SEP = ',' # has to be valid TAG_SPLIT_REGEX char and MUST NOT be in const.TAG_CHARS @@ -301,13 +305,6 @@ assert( == set(RESPONSE_ACTIVITY_TYPE_MAP_FOR_TEMPLATES.keys()) ) -TYPE_RESPONSE = { - 'QUESTION_ANSWERED' : _('answered question'), - 'QUESTION_COMMENTED': _('commented question'), - 'ANSWER_COMMENTED' : _('commented answer'), - 'ANSWER_ACCEPTED' : _('accepted answer'), -} - POST_STATUS = { 'closed': _('[closed]'), 'deleted': _('[deleted]'), @@ -433,12 +430,12 @@ AVATAR_STATUS_CHOICE = ( SEARCH_ORDER_BY = ( ('-added_at', _('date descendant')), ('added_at', _('date ascendant')), - ('-last_activity_at', _('activity descendant')), - ('last_activity_at', _('activity ascendant')), - ('-answer_count', _('answers descendant')), - ('answer_count', _('answers ascendant')), - ('-points', _('votes descendant')), - ('points', _('votes ascendant')), + ('-last_activity_at', _('most recently active')), + ('last_activity_at', _('least recently active')), + ('-answer_count', _('more responses')), + ('answer_count', _('fewer responses')), + ('-points', _('more votes')), + ('points', _('less votes')), ) DEFAULT_QUESTION_WIDGET_STYLE = """ diff --git a/askbot/const/message_keys.py b/askbot/const/message_keys.py index 291381cb..bb990d5e 100644 --- a/askbot/const/message_keys.py +++ b/askbot/const/message_keys.py @@ -4,12 +4,6 @@ that are used as variables it is important that a dummy _() function is used here this way message key will be pulled into django.po and can still be used as a variable in python files. - -In addition, some messages are repeated too many times -in the code, so we need to be able to retreive them -by a key. Therefore we have a function here, called -get_i18n_message(). Possibly all messages included in -this file could be implemented this way. ''' _ = lambda v:v @@ -40,18 +34,14 @@ TAGS_ARE_REQUIRED_MESSAGE = _('tags are required') TAG_WRONG_CHARS_MESSAGE = _( 'please use letters, numbers and characters "-+.#"' ) - -def get_i18n_message(key): - messages = { - 'BLOCKED_USERS_CANNOT_POST': _( - 'Sorry, your account appears to be blocked and you cannot make new posts ' - 'until this issue is resolved. Please contact the forum administrator to ' - 'reach a resolution.' - ), - 'SUSPENDED_USERS_CANNOT_POST': _( - 'Sorry, your account appears to be suspended and you cannot make new posts ' - 'until this issue is resolved. You can, however edit your existing posts. ' - 'Please contact the forum administrator to reach a resolution.' - ) - } - return messages[key] +TAG_WRONG_FIRST_CHAR_MESSAGE = _( + '# is not a valid character at the beginning of tags, use only letters and numbers' +) +ACCOUNT_CANNOT_PERFORM_ACTION = _( + 'Sorry, you cannot %(perform_action)s because %(your_account_is)s' +) +MIN_REP_REQUIRED_TO_PERFORM_ACTION = _('>%(min_rep)s points required to %(perform_action)s') +CANNOT_PERFORM_ACTION_UNTIL = _('Sorry, you will be able to %(perform_action)s after %(until)s') +MODERATORS_OR_AUTHOR_CAN_PEFROM_ACTION = _( + 'Sorry, only moderators or the %(post_author)s %(perform_action)s' +) diff --git a/askbot/deps/django_authopenid/forms.py b/askbot/deps/django_authopenid/forms.py index 97cc90ba..1f08b23c 100644 --- a/askbot/deps/django_authopenid/forms.py +++ b/askbot/deps/django_authopenid/forms.py @@ -30,6 +30,7 @@ # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import logging +import cgi from django import forms from django.contrib.auth.models import User from django.utils.translation import ugettext as _ @@ -75,7 +76,7 @@ class LoginProviderField(forms.CharField): if value in providers: return value else: - error_message = 'unknown provider name %s' % value + error_message = 'unknown provider name %s' % cgi.escape(value) logging.critical(error_message) raise forms.ValidationError(error_message) diff --git a/askbot/deps/django_authopenid/util.py b/askbot/deps/django_authopenid/util.py index 06379e1d..deb9ad27 100644 --- a/askbot/deps/django_authopenid/util.py +++ b/askbot/deps/django_authopenid/util.py @@ -35,9 +35,9 @@ except: import time, base64, hmac, hashlib, operator, logging from models import Association, Nonce -__all__ = ['OpenID', 'DjangoOpenIDStore', 'from_openid_response', 'clean_next'] +__all__ = ['OpenID', 'DjangoOpenIDStore', 'from_openid_response'] -ALLOWED_LOGIN_TYPES = ('password', 'oauth', 'openid-direct', 'openid-username', 'wordpress') +ALLOWED_LOGIN_TYPES = ('password', 'oauth', 'oauth2', 'openid-direct', 'openid-username', 'wordpress') class OpenID: def __init__(self, openid_, issued, attrs=None, sreg_=None): @@ -273,6 +273,15 @@ class LoginMethod(object): self.oauth_authorize_url = self.get_required_attr('OAUTH_AUTHORIZE_URL', for_what) self.oauth_get_user_id_function = self.get_required_attr('oauth_get_user_id_function', for_what) + if self.login_type == 'oauth2': + for_what = 'custom OAuth2 login' + self.auth_endpoint = self.get_required_attr('OAUTH_ENDPOINT', for_what) + self.token_endpoint = self.get_required_attr('OAUTH_TOKEN_ENDPOINT', for_what) + self.resource_endpoint = self.get_required_attr('OAUTH_RESOURCE_ENDPOINT', for_what) + self.oauth_get_user_id_function = self.get_required_attr('oauth_get_user_id_function', for_what) + self.response_parser = getattr(self.mod, 'response_parser', None) + self.token_transport = getattr(self.mod, 'token_transport', None) + if self.login_type.startswith('openid'): self.openid_endpoint = self.get_required_attr('OPENID_ENDPOINT', 'custom OpenID login') if self.login_type == 'openid-username': @@ -294,7 +303,8 @@ class LoginMethod(object): 'change_password_prompt', 'consumer_key', 'consumer_secret', 'request_token_url', 'access_token_url', 'authorize_url', 'get_user_id_function', 'openid_endpoint', 'tooltip_text', - 'check_password', + 'check_password', 'auth_endpoint', 'token_endpoint', + 'resource_endpoint', 'response_parser', 'token_transport' ) #some parameters in the class have different names from those #in the dictionary @@ -388,6 +398,18 @@ def get_enabled_major_login_providers(): 'password_changeable': True } + if askbot_settings.SIGNIN_CUSTOM_OPENID_ENABLED: + context_dict = {'login_name': askbot_settings.SIGNIN_CUSTOM_OPENID_NAME} + data['custom_openid'] = { + 'name': 'custom_openid', + 'display_name': askbot_settings.SIGNIN_CUSTOM_OPENID_NAME, + 'type': askbot_settings.SIGNIN_CUSTOM_OPENID_MODE, + 'icon_media_path': askbot_settings.SIGNIN_CUSTOM_OPENID_LOGIN_BUTTON, + 'tooltip_text': _('Login with %(login_name)s') % context_dict, + 'openid_endpoint': askbot_settings.SIGNIN_CUSTOM_OPENID_ENDPOINT, + 'extra_token_name': _('%(login_name)s username') % context_dict + } + def get_facebook_user_id(client): """returns facebook user id given the access token""" profile = client.request('me') diff --git a/askbot/deps/django_authopenid/views.py b/askbot/deps/django_authopenid/views.py index 58c33fea..04b5deca 100644 --- a/askbot/deps/django_authopenid/views.py +++ b/askbot/deps/django_authopenid/views.py @@ -30,6 +30,7 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +import cgi import datetime from django.http import HttpResponseRedirect, Http404 from django.http import HttpResponse @@ -212,6 +213,7 @@ def ask_openid( try: auth_request = consumer.begin(openid_url) except DiscoveryFailure: + openid_url = cgi.escape(openid_url) msg = _(u"OpenID %(openid_url)s is invalid" % {'openid_url':openid_url}) logging.debug(msg) return on_failure(request, msg) @@ -292,12 +294,12 @@ def complete_oauth2_signin(request): client_id = getattr( askbot_settings, - provider_name.upper() + '_KEY' + provider_name.upper() + '_KEY', ) client_secret = getattr( askbot_settings, - provider_name.upper() + '_SECRET' + provider_name.upper() + '_SECRET', ) client = OAuth2Client( @@ -305,12 +307,13 @@ def complete_oauth2_signin(request): resource_endpoint=params['resource_endpoint'], redirect_uri=site_url(reverse('user_complete_oauth2_signin')), client_id=client_id, - client_secret=client_secret + client_secret=client_secret, + token_transport=params.get('token_transport', None) ) client.request_token( code=request.GET['code'], - parser=params['response_parser'] + parser=params.get('response_parser', None) ) #todo: possibly set additional parameters here @@ -327,6 +330,11 @@ def complete_oauth2_signin(request): request.session['email'] = ''#todo: pull from profile request.session['username'] = ''#todo: pull from profile + if (provider_name == 'facebook'): + profile = client.request("me") + request.session['email'] = profile['email'] + request.session['username'] = profile['username'] + return finalize_generic_signin( request = request, user = user, @@ -735,8 +743,8 @@ def show_signin_view( 'page_class': 'openid-signin', 'view_subtype': view_subtype, #add_openid|default 'page_title': page_title, - 'question':question, - 'answer':answer, + 'question': question, + 'answer': answer, 'login_form': login_form, 'use_password_login': util.use_password_login(), 'account_recovery_form': account_recovery_form, @@ -1352,16 +1360,3 @@ def account_recover(request): return show_signin_view(request, view_subtype = 'bad_key') return HttpResponseRedirect(get_next_url(request)) - -#internal server view used as return value by other views -def validation_email_sent(request): - """this function is called only if EMAIL_VALIDATION setting is - set to True bolean value""" - assert(askbot_settings.EMAIL_VALIDATION == True) - logging.debug('') - data = { - 'email': request.user.email, - 'change_email_url': reverse('user_changeemail'), - 'action_type': 'validate' - } - return render(request, 'authopenid/changeemail.html', data) diff --git a/askbot/deps/livesettings/views.py b/askbot/deps/livesettings/views.py index 3beae8de..0c64d23d 100644 --- a/askbot/deps/livesettings/views.py +++ b/askbot/deps/livesettings/views.py @@ -62,7 +62,7 @@ def group_settings(request, group, template='livesettings/group_settings.html'): return render_to_response(template, { 'all_super_groups': mgr.get_super_groups(), 'title': title, - 'group' : settings, + 'settings_group' : settings, 'form': form, 'use_db' : use_db }, context_instance=RequestContext(request)) diff --git a/askbot/doc/source/askbot/layout.html b/askbot/doc/source/askbot/layout.html index f1c8b509..6fd6b0d1 100644 --- a/askbot/doc/source/askbot/layout.html +++ b/askbot/doc/source/askbot/layout.html @@ -10,10 +10,10 @@ <div class="ab-proj-header"> <a href="/">Home</a> | <a href="/en/questions/" title="Ask Questions">Ask Questions</a> | - <a href="/hire-us" alt='Hire Us'>Hire Us</a> | + <a href="https://askbot.com/hire-us/" alt='Hire Us'>Consulting Services</a> | <a href="/doc/index.html" alt="Documentation">Documentation</a> | - <a href="/contribute" alt='Contribute'>Contribute</a> | - <a href="/feedback/" alt='contact'>Contact</a> + <a href="https://askbot.com/contribute" alt='Contribute'>Contribute</a> | + <a href="https://askbot.com/feedback/" alt='contact'>Contact</a> </div> {% endblock %} {% block relbar2 %} diff --git a/askbot/doc/source/changelog.rst b/askbot/doc/source/changelog.rst index 00accbe0..c450ac95 100644 --- a/askbot/doc/source/changelog.rst +++ b/askbot/doc/source/changelog.rst @@ -1,8 +1,19 @@ Changes in Askbot ================= -Development version -------------------- +Development master branch (only on github) +------------------------------------------ +* Allowed configurable custom OpenID login button +* Allowed custom list of feedback recipients (Keto) +* Added option to show user's emails to the moderators +* Added Read-Only mode for the site in the "access control" section. +* Added `askbot_add_osqa_content` management command. +* Management command to add data from other Askbot site. +* Allowed simple overrides of livesettings with `ASKBOT_...` prefixed + variables in the `settings.py` file. + +0.7.49 (Sep 19, 2013) +--------------------- * Support for Solr search backend (Adolfo) * Allowed read-only access user groups (Adolfo) * Added simple read-only API (Adolfo) diff --git a/askbot/doc/source/contributors.rst b/askbot/doc/source/contributors.rst index 5e97b608..0dfb942b 100644 --- a/askbot/doc/source/contributors.rst +++ b/askbot/doc/source/contributors.rst @@ -49,6 +49,11 @@ Programming, bug fixes and documentation * `Kevin Porterfield <http://www.shotgunsoftware.com>_` * `Robert Martin <https://github.com/bobbydavid>_` * `Director <http://codeflow.co.kr>`_ +* `Stéphane Klein <http://stephane-klein.info>`_ +* `Andrew Chen <https://github.com/yongjhih>`_ +* `Benjamin Abel <https://github.com/BenjaminABEL>`_ +* `Pami Ketolainen <https://github.com/keto>`_ +* `Hamdi <https://github.com/Hamdy>`_ Translations ------------ @@ -66,6 +71,8 @@ please let us know at support@askbot.com. * Pekka Järvinen - Finnish * Adi Robian - Romanian * `Stefano Mancini <https://github.com/xponrails>`_, Dario Ghilardi, Federico Poloni, `Luca Ferroni <http://www.linkedin.com/in/lucaferroni>`_ - Italian -* `Jordi Bofill <https://github.com/jbofill>`_ - Catalan +* Cong It, Nguyen Long, ppranhh - Vietnamese +* `Jordi Bofill <https://github.gom/jbofill>`_ - Catalan * VaÅ¡ek ChalupnÃÄek - Chech * Dario Kolak - Croatian +. diff --git a/askbot/doc/source/index.rst b/askbot/doc/source/index.rst index 680ba0aa..d6703775 100644 --- a/askbot/doc/source/index.rst +++ b/askbot/doc/source/index.rst @@ -28,7 +28,9 @@ at the forum_ or by email at admin@askbot.org Appendix E: Askbot as reusable Django application <askbot-as-reusable-django-application> Appendix F: Customizing skin in askbot <customizing-skin-in-askbot> Appendix G: Intranet setup <intranet-setup> - Appendix H: Haystack with Solr and Apache Tomcat <solr> + Appendix H: Language support in Askbot <localization> + Appendix I: Configuration of text search <text-search> + Appendix J: Migration from MySQL to PostgreSQL <mysql-to-postgres> Footnotes <footnotes> Contributors <contributors> Changelog <changelog> diff --git a/askbot/doc/source/live-settings.rst b/askbot/doc/source/live-settings.rst index 12546e6c..bc0d3d72 100644 --- a/askbot/doc/source/live-settings.rst +++ b/askbot/doc/source/live-settings.rst @@ -24,7 +24,22 @@ Entering live settings in settings.py file ========================================== You might want to bypass live settings and enter them directly -in the ``settings.py`` file in the ``LIVESETTINGS_OPTIONS`` dictionary. +in the ``settings.py`` file. + +Currently there are two ways to do this: + +1. Simply add variable with the same name as defined in `askbot/conf` files, + but prefixed with `ASKBOT_` and the corresponding value. + For example, add `ASKBOT_RSS_ENABLED = False` to disable the rss. + In `askbot/conf` this value is defined simply as `RSS_ENABLED`. + +2. Put settings into the ``LIVESETTINGS_OPTIONS`` dictionary, + this way you can assign livesettings values to specific site by ID, + which may or may not be useful for the multi-portal (multi-site) askbot setup. + +The first method above overrides the second. + +Here is a more detailed description on how to use the `LIVESETTINGS_OPTIONS` method: Having live settings overridden from the ``settings.py`` file may somewhat speed up your site diff --git a/askbot/doc/source/localization.rst b/askbot/doc/source/localization.rst new file mode 100644 index 00000000..fbf51da6 --- /dev/null +++ b/askbot/doc/source/localization.rst @@ -0,0 +1,81 @@ +.. _localization: +====================================== +Configuring language support in Askbot +====================================== + +There are several things to consider when localizing askbot: + +* :ref:`setting the site language <default-lang>` +* :ref:`translation and display of the urls <translate-urls>` +* :ref:`translation of the strings in the user interface <strings>` +* :ref:`enabling the multilingual setup <multilingual>` +* :ref:`configuring the language-specific text search <text-search>` + +.. _default-lang: + +Setting the site language +========================= + +Specify the language code with the value of `LANGUAGE_CODE` parameter +in the `settings.py` file:: + + LANGUAGE_CODE='es' + +.. note:: + In the :ref:`multi-lingual configuration <multilingual>` + this language will be the default and the complete list of + language codes and their verbose names + is specified with the `LANGUAGES` parameter. + +.. _translate-urls: + +Translation of the URLs +======================= + +There are also `settings.py` options to translate the urls: +`ASKBOT_TRANSLATE_URL` and `ALLOW_UNICODE_SLUGS`. + +When the `ASKBOT_TRANSLATE_URL` is `True`, most urls will be translated, +otherwise urls will be in English. +When the `ALLOW_UNICODE_SLUGS` is `True` the question titles and user names +will be presented as Unicode, e.g. with the Cyrillic, Chinese +or Arabic characters, otherwise they will be transliterated into ASCII. + +If you are translating URLs (in the transifex you will probably +find them as strings containing forward slashes) - +take the following, in order to prevent broken links: + +* translation of multiple urls cannot be the same + (e.g. /question/ and /questions/ must have different translations) +* if the same url is present in more than one translation file + those translation must be exactly the same + +.. _strings: + +Translation of strings in Askbot +================================ + +Translation of Askbot strings is performed at the `Transifex service <transifex>`_. +Please `register there <transifex>`_ and work on the localization that interests you. +We periodically update the source language strings on Transifex and pull +the translations back into the project. Thanks! + +If you intend to translate urls - please :ref:`look here <translate-urls>`. + +Please *do not* translate via github (if you know what it means), +as it's better to have just one source of strings. + +The remaining part will will most likely interest developers, +therefore here we tell what is specific to Askbot and +refer the developer to the documentation of tools +used in Askbot. + +Firstly - Askbot uses `Jinja2 <http://jinja.pocoo.org/docs/>`_ templates, +not the Django templates and an Jinja2 adapter module for Django, called +`Coffin <https://github.com/coffin/coffin/>`_. Please look at how translation +tags are added to the templates processed by the `coffin` module. + +Secondly - instead of the django `makemessages` command - use `jinja2_makemessages`. + +Finally - to pull strings from the transifex use the `tx` program from +`transifex-client pypi package <https://pypi.python.org/pypi/transifex-client>`_. diff --git a/askbot/doc/source/management-commands.rst b/askbot/doc/source/management-commands.rst index a56aa47a..1f5c3fa1 100644 --- a/askbot/doc/source/management-commands.rst +++ b/askbot/doc/source/management-commands.rst @@ -46,9 +46,6 @@ The bulk of the management commands fall into this group and will probably be th | `merge_users <from_id> | Merges user accounts and all related data from one user | | <to_id>` | to another, the "from user" account is deleted. | +---------------------------------+-------------------------------------------------------------+ -| `dump_forum [--dump-name | Save forum contents into a file. `--dump-name` parameter is | -| some_name]` | optional | -+---------------------------------+-------------------------------------------------------------+ | `get_tag_stats [-u|-t] [-e]` | Print tag subscription statistics, per tag (option -t) | | | or per user (option -u), if option -e is given, empty | | | records will be shown too (longer versions of the options | @@ -56,16 +53,6 @@ The bulk of the management commands fall into this group and will probably be th | | --per-user-tag-subscription-counts for -u, and --print-empty| | | for -e). | +---------------------------------+-------------------------------------------------------------+ -| `load_forum <file_name>` | Load forum data from a file saved by the `dump_forum` | -| | command | -+---------------------------------+-------------------------------------------------------------+ -| `load_stackexchange <file.zip>` | Load SackExchange dump into Askbot. It is best to run this | -| | command on empty database. Also - before running, make sure | -| | that `askbot.importers.stackexchange` is in the list of | -| | installed apps within your settings.py file (it might also | -| | be necessary to run `syncdb` command to initiate the | -| | SE importer tables). | -+---------------------------------+-------------------------------------------------------------+ | `rename_tags --from <from_tags> | Rename, merge or split tags. User ID is the id of the user | | --to <to_tags> --user-id | who will be assigned as the performer of the retag action. | | <user_id>` | If more than is in the `--from` or the `--to` parameters | @@ -101,6 +88,32 @@ The bulk of the management commands fall into this group and will probably be th | | foreign key to that object is still present. | +---------------------------------+-------------------------------------------------------------+ +.. _data-import-commands: + +Data import commands +==================== + +These commands import or add data to the Askbot forum. + ++---------------------------------+-------------------------------------------------------------+ +| command | purpose | ++=================================+=============================================================+ +| `load_stackexchange <file.zip>` | Load SackExchange dump into Askbot. It is best to run this | +| | command on empty database. Also - before running, make sure | +| | that `askbot.importers.stackexchange` is in the list of | +| | installed apps within your settings.py file (it might also | +| | be necessary to run `syncdb` command to initiate the | +| | SE importer tables). | ++---------------------------------+-------------------------------------------------------------+ +| `askbot_add_xml_content | Add xml Askbot data dumped with the Django command | +| <file.xml>` | `dumpdata` | ++---------------------------------+-------------------------------------------------------------+ +| `askbot_add_osqa_content | Add xml OSQA data dumped with the Django command | +| <file.xml>` | `export_osqa` | ++---------------------------------+-------------------------------------------------------------+ +| `askbot_import_jive <file.xml> | Import xml Jive data | ++---------------------------------+-------------------------------------------------------------+ + .. _email-related-commands: Email-related commands diff --git a/askbot/doc/source/multilingual.rst b/askbot/doc/source/multilingual.rst new file mode 100644 index 00000000..75f93f0a --- /dev/null +++ b/askbot/doc/source/multilingual.rst @@ -0,0 +1,46 @@ +.. _multilingual: +==================================== +Setting up multilingual Askbot sites +==================================== + +Askbot can support multiple languages on a single site, in which case +urls are modified by a prefix made of a language code, e.g. +base url /questions/ becomes /de/questions/ for the German localization. + +.. note:: + If you want to learn about configuration of individual languages + please look :ref:`here <localization>` + +In order to enable the multilingual setup add the following to the +`settings.py` file:: + + ASKBOT_MULTILINGUAL=True + +Also, activate the django's locale middleware by adding to the +`MIDDLEWARE_CLASSES` the following entry:: + + 'django.middleware.locale.LocaleMiddleware', + +There is a standard Django setting `LANGUAGES`, which enables specific languages. +By default this setting contains very many languages. +You will likely want to narrow in the `settings.py` file +the choice of the available languages:: + + #it's important to use ugettext_lazy or ugettext_noop + #in the settings.py file + from django.utils.translation import ugettext_lazy as _ + LANGUAGES = ( + ('de', _('German')), + ('en', _('English')) + ) + +More on the usage of this setting can be read in the +`Django documentation <https://docs.djangoproject.com/en/dev/ref/settings/#languages>`_. + +The default language should be specified with the setting `LANGUAGE_CODE`. +Users will be automatically redirected to the corresponding default language +page from the non-prefixed urls. + +There are a number of `settings.py` options that control the various +aspects of the site localization - the behaviour of the software depending on the +currently active language.. Please read more about the :ref:`Localization of Askbot <localization>`. diff --git a/askbot/doc/source/mysql-to-postgres.rst b/askbot/doc/source/mysql-to-postgres.rst new file mode 100644 index 00000000..c9c0e477 --- /dev/null +++ b/askbot/doc/source/mysql-to-postgres.rst @@ -0,0 +1,114 @@ +.. _mysql-to-postgres: + +=========================================================== +Migrating data from MySQL to Postgresql +=========================================================== + +In this document we explain how to migrate from MySQL to Postgresql with different approaches. + +Askbot is optimized for Postgresql as search functionality works better with this database engine. + +.. note:: + As a general advice, to reduce the database size - run the **cleanup** management command before starting the migration. + + +Simple Migration of small database +================================== + +If your database is small with few users and questions you can follow this steps: + +With MySQL as your database engine in your settings.py file run the following command:: + + python manage.py dumpdata > data.json + +After that change your database engine to Postgresql in settings.py and do:: + + python manage.py syncdb --migrate --noinput #create the database structure + python manage.py loaddata data.json + + +.. note:: + This won't work with large datasets because django will load all your + data into memory and you might run out of memory if the site data is too large. + + This process can produce warnings that can be ignored. + + +Data migration with py-mysql2pgsql +================================== + +If the database is large this tool will come handy, to install it run:: + + pip install py-mysql2pgsql + +Create a configuration file called config.yml with the following contents:: + + mysql: + hostname: localhost + port: 3306 + username: your_user + password: your_password + database: your_database + + destination: + file: + postgres: + hostname: localhost + port: 5432 + username: your_user + password: your_password + database: your_database + +Then run:: + + py-mysql2pgsql -v -f config.yml + +The script will start migrating the data and might take a while, depending on the database size. + +After the process is finished there are a couple of things left to do. + +Enable Postgresql full text search +---------------------------------- + +Askbot relies on special postgresql features for better search, in this case the py-mysql2pgsql tool will not +add these features, so it requires to be added manually. + +To fix it run the command:: + + python manage.py init_postgresql_full_text_search + +This may also take some time, depending on the database size. +Test this by running a search query on the askbot site. + +.. + If you have an issue with the above command, it is possible to run the search setup sql script manually: + 1. Download `thread_and_post_models_10032013.plsql <https://raw.github.com/ASKBOT/askbot-devel/master/askbot/search/postgresql/thread_and_post_models_10032013.plsql>`_ + 2. Download `user_profile_search_08312012.plsql <https://raw.github.com/ASKBOT/askbot-devel/master/askbot/search/postgresql/user_profile_search_08312012.plsql>`_ + 3. Apply the scripts to your postgres database:: + psql your_database < thread_and_post_models_10032013.plsql + psql your_database < user_profile_search_08312012.plsql + + +Fixing data types +----------------- + +The py-mysql2pgsql translates datatype a bit different than Django ORM do, to keep the same +datatypes do the following: + +1. Create a new postgresql database and run sync and migrate commands the following way:: + + python manage.py syncdb --migrate --noinput --no-initial-data + +2. Dump the converted database data with binary format:: + + pg_dump --format=c -a database_name > dump_name + +3. Restore it into your current Django database:: + + pg_restore -a --disable-triggers -d django_database dump_name + + +Links +===== + +* `py-mysql2pgsql <https://github.com/philipsoutham/py-mysql2pgsql>`_ diff --git a/askbot/doc/source/solr.rst b/askbot/doc/source/solr.rst index 9db6ba2f..8a1de0c2 100644 --- a/askbot/doc/source/solr.rst +++ b/askbot/doc/source/solr.rst @@ -8,22 +8,26 @@ Installing Apache Solr with Apache Tomcat 7 in Ubuntu 12.04 This document describes the process of instalation of Apache Solr search engine in Ubuntu Server 12.04 for askbot use. To follow this steps you must have already askbot installed and running. -Getting the requirements -======================== +Installation of the required packages +===================================== -We need the following packages installed:: +Install packages `tomcat7` and `tomcat7-admin`:: sudo apt-get install tomcat7 tomcat7-admin -We need to download Apache Solr from the `official site <http://lucene.apache.org/solr/downloads.html>`_:: +Download Apache Solr from the `official site <http://lucene.apache.org/solr/downloads.html>`_:: wget http://www.bizdirusa.com/mirrors/apache/lucene/solr/3.6.2/apache-solr-3.6.2.tgz +Install `django-haystack` module in your Python environment:: + + pip install django-haystack + Setting up Tomcat ================= -After installing tomcat there are some configuration required to make it work. First we are going to add -Tomcat users. Edit /etc/tomcat7/tomcat-users.xml and add the following:: +After installing Tomcat, add users to the Tomcat server. +Edit `/etc/tomcat7/tomcat-users.xml` and add the following:: <?xml version='1.0' encoding='utf-8'?> <tomcat-users> @@ -31,15 +35,17 @@ Tomcat users. Edit /etc/tomcat7/tomcat-users.xml and add the following:: <role rolename="admin"/> <role rolename="admin-gui"/> <role rolename="manager-gui"/> - <user username="tomcat" password="tomcat" roles="manager,admin,manager-gui,admin-gui"/> + <user username="tomcat" password="tomcat" + roles="manager,admin,manager-gui,admin-gui"/> </tomcat-users> -This will allow you to connect to the web management interface. After doing it restart the service: +Then restart the service:: service tomcat7 restart -To make see if it works go to: http://youripaddress:8080/manager it will ask for your tomcat user password -described in the tomcat-users.xml +Now you should be able to connect to the web management interface +via http://youripaddress:8080/manager +and entering there user name and password. Installing Solr under Tomcat ============================ @@ -48,28 +54,30 @@ Extract the solr tar archive from the previous download:: tar -xzf apache-solr-3.6.2.tgz -Copy the example/ directory from the source to /opt/solr/. Open the file /opt/solr/example/solr/conf/solrconfig.xml +Copy the `example/` directory from the source to `/opt/solr/`. +Open the file `/opt/solr/example/solr/conf/solrconfig.xml` and Modify the dataDir parameter as:: <dataDir>${solr.data.dir:/opt/solr/example/solr/data}</dataDir> -Copy the .war file in dist directory to /opt/solr:: +Copy the `.war` file in dist directory to `/opt/solr`:: cp dist/apache-solr-3.6.2.war /opt/solr -Create solr.xml inside of /etc/tomcat/Catalina/localhost/ with the following contents:: +Create `solr.xml` inside of `/etc/tomcat/Catalina/localhost/` with the following contents:: <?xml version="1.0" encoding="utf-8"?> <Context docBase="/opt/solr/apache-solr-3.6.2.war" debug="0" crossContext="true"> - <Environment name="solr/home" type="java.lang.String" value="/opt/solr/example/solr" override="true"/> + <Environment name="solr/home" type="java.lang.String" + value="/opt/solr/example/solr" override="true"/> </Context> -Restart tomcat server:: +Restart the tomcat server:: service tomcat7 restart -By now you should be able to see the "solr" application in the tomcat manager and also access it in /solr/admin. - +Now you should be able to access the "solr" application +in the Tomcat manager at `/solr/admin`. Configuring Askbot with Solr ============================ @@ -103,14 +111,18 @@ The output should be something like:: Indexing 101 posts. Indexing 101 threads. -You must be good to go after this, just restart the askbot application and test the search with haystack and solr +Now all should be ready, +just restart the askbot application +and test the search with haystack and solr. +.. _solr-multilingual: Multilingual Setup ================== .. note:: - This is experimental feature, currently xml generation works for: English, Spanish, Chinese, Japanese, Korean and French. + This is experimental feature, currently xml generation works for: + English, Spanish, Chinese, Japanese, Korean and French. Add the following to settings.py:: @@ -129,7 +141,6 @@ Configure the HAYSTACK_CONNECTIONS settings with the following format for each l }, } - Generate xml files according to language:: python manage.py askbot_build_solr_schema -l <language_code> > /opt/solr/example/solr/conf/schema-<language_code>.xml @@ -141,12 +152,13 @@ For each language that you want to support you will need to add a solr core like http://127.0.0.1:8080/solr/admin/cores?action=CREATE&name=core-<language_code>&instanceDir=.&config=solrconfig.xml&schema=schema-<language_code>.xml&dataDir=data -For more information on how to handle Solr cores visit `the oficial Solr documetation wiki. <http://wiki.apache.org/solr/CoreAdmin>`_ +For more information on how to handle Solr cores visit the +`Solr documetation <http://wiki.apache.org/solr/CoreAdmin>`_. Build the index according to language ------------------------------------- -For every language supported you'll need to rebuild the index the following way:: +For every active language rebuild the index:: python manage.py askbot_rebuild_index -l <language_code> @@ -159,24 +171,32 @@ There are several ways to keep the index fresh in askbot with haystack. Cronjob ------- -Create a cronjob that executes *askbot_update_index* command for each language installed (in case of multilingual setup). +Create a cronjob that executes *askbot_update_index* command +for each of the activated languages. Real Time Signal ---------------- -The real time signal method updates the index synchronously after each object it's saved or deleted, to enable it add this to settings.py:: +The *real time* signal method updates the index synchronously +after each object it's saved or deleted, +to enable it add this to settings.py:: HAYSTACK_SIGNAL_PROCESSOR = 'askbot.search.haystack.signals.AskbotRealtimeSignalProcessor' -this can delay the requests time of your page, if you have a high traffic site this is not recommended. +Use of synchronous index updates may slow down your site +which may not be acceptable for the high traffic sites. + +Updating the Index asyncronously with Celery +-------------------------------------------- -Updating the Index with Celery ------------------------------- +The *asynchronous signal* method updates the index by adding delayed job to the queue +after each object is saved or deleted. -The real time signal method updates the index asynchronously after each object it's saved or deleted using Celery as queue to enable it add this to settings.py:: +To make this work, +`django-celery <http://celery.readthedocs.org/en/latest/django/first-steps-with-django.html>`_ +must be installed, enabled and configured and the Haystack signal processor configured +in the `settings.py` file:: HAYSTACK_SIGNAL_PROCESSOR = 'askbot.search.haystack.signals.AskbotCelerySignalProcessor' #modify CELERY_ALWAYS_EAGER to: CELERY_ALWAYS_EAGER = False - -You will need to enable Celery to make this work. diff --git a/askbot/doc/source/text-search.rst b/askbot/doc/source/text-search.rst new file mode 100644 index 00000000..b18e3f33 --- /dev/null +++ b/askbot/doc/source/text-search.rst @@ -0,0 +1,48 @@ +.. _text-search: +====================================== +Configuring full text search in Askbot +====================================== + +Currently there are two supported language-aware mechanisms for full text search: + +* :ref:`postgresql full text search <postgresql-text-search>` +* :ref:`Solr search engine <solr-text-search>` + +MySQL supports text search only for English and only for the MyISAM storage engine. +MyISAM engine lacks support of the database transactions, +therefore it is strongly recommended to use Postgresql. + +.. _postgresql-text-search: + +Postgresql full text search +=========================== + +Postgresql supports full text search in the following languages: + +Danish, Dutch, English, Finnish, French, German, Hungarian, +Italian, Japanese (requires postgresql package `textsearch_ja`), Norwegian, +Portugese, Romanian, Russian, Spanish, Swedish, Turkish. + +To enable this option - just use the postgresql database and +add in the `settings.py` file +the corresponding entry in the +`LANGUAGES setting <https://docs.djangoproject.com/en/dev/ref/settings/#languages>`_. + +.. note:: + Japanese language search in Postgresql requires installation + of a "contrib" package called `textsearch_ja` + +.. _solr-text-search: + +Solr full text search +===================== + +Apache Solr search supports more languages and Askbot supports Solr via the +module called Haystack. + +:ref:`Here <solr>` are detailed instructions on how to enable Solr on +Ubuntu system version 12.04, which may be helpful for users of other +distributions of Linux. + +In addition to the basic set up of Solr, it will be necessary to configure +:ref:`multilingual search <solr-multilingual>` under solr. diff --git a/askbot/feed.py b/askbot/feed.py index 03e7c7e1..b8f7efb7 100644 --- a/askbot/feed.py +++ b/askbot/feed.py @@ -32,7 +32,7 @@ class RssIndividualQuestionFeed(Feed): def title(self): return askbot_settings.APP_TITLE + _(' - ') + \ - _('Individual question feed') + _('Individual %(question)s feed') % {'question': askbot_settings.WORDS_QUESTION_SINGULAR} def feed_copyright(self): return askbot_settings.APP_COPYRIGHT @@ -85,13 +85,12 @@ class RssIndividualQuestionFeed(Feed): def item_title(self, item): """returns the title for the item """ - title = item if item.post_type == "question": - self.title = item + title = item.thread.title elif item.post_type == "answer": - title = "Answer by %s for %s " % (item.author, self.title) + title = u'Answer by %s for %s ' % (item.author, item.thread._question_post().summary) elif item.post_type == "comment": - title = "Comment by %s for %s" % (item.author, self.title) + title = u'Comment by %s for %s' % (item.author, item.parent.summary) return title def item_description(self, item): @@ -106,7 +105,7 @@ class RssLastestQuestionsFeed(Feed): def title(self): return askbot_settings.APP_TITLE + _(' - ') + \ - _('Individual question feed') + _('Latest %(question)s feed') % {'question': askbot_settings.WORDS_QUESTION_SINGULAR} def feed_copyright(self): return askbot_settings.APP_COPYRIGHT @@ -143,6 +142,9 @@ class RssLastestQuestionsFeed(Feed): """ return site_url(item.get_absolute_url(no_slug = True)) + def item_title(self, item): + return item.thread.title + def item_description(self, item): """returns the description for the item """ @@ -177,11 +179,3 @@ class RssLastestQuestionsFeed(Feed): def get_feed(self, obj, request): self.request = request return super(RssLastestQuestionsFeed, self).get_feed(obj, request) - -def main(): - """main function for use as a script - """ - pass - -if __name__ == '__main__': - main() diff --git a/askbot/forms.py b/askbot/forms.py index 0c4e15c5..471559bb 100644 --- a/askbot/forms.py +++ b/askbot/forms.py @@ -9,6 +9,7 @@ from django.conf import settings as django_settings from django.core.exceptions import PermissionDenied from django.forms.util import ErrorList from django.utils.html import strip_tags +from django.utils.datastructures import SortedDict from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ungettext_lazy, string_concat from django.utils.text import get_text_list @@ -245,9 +246,7 @@ class TitleField(forms.CharField): ) self.max_length = 255 self.label = _('title') - self.help_text = _( - 'Please enter your question' - ) + self.help_text = askbot_settings.WORDS_PLEASE_ENTER_YOUR_QUESTION self.initial = '' def clean(self, value): @@ -263,20 +262,21 @@ class TitleField(forms.CharField): ) % askbot_settings.MIN_TITLE_LENGTH raise forms.ValidationError(msg) encoded_value = value.encode('utf-8') + question_term = askbot_settings.WORDS_QUESTION_SINGULAR if len(value) == len(encoded_value): if len(value) > self.max_length: raise forms.ValidationError( _( - 'The question is too long, maximum allowed size is ' - '%d characters' - ) % self.max_length + 'The %(question)s is too long, maximum allowed size is ' + '%(length)d characters' + ) % {'question': question_term, 'length': self.max_length} ) elif len(encoded_value) > self.max_length: raise forms.ValidationError( _( - 'The question is too long, maximum allowed size is ' - '%d bytes' - ) % self.max_length + 'The %(question)s is too long, maximum allowed size is ' + '%(length)d bytes' + ) % {'question': question_term, 'length': self.max_length} ) return value.strip() # TODO: test me @@ -286,9 +286,6 @@ class EditorField(forms.CharField): """EditorField is subclassed by the :class:`QuestionEditorField` and :class:`AnswerEditorField` """ - length_error_template_singular = 'post content must be > %d character', - length_error_template_plural = 'post content must be > %d characters', - min_length = 10 # sentinel default value def __init__(self, *args, **kwargs): user = kwargs.pop('user', None) @@ -309,16 +306,18 @@ class EditorField(forms.CharField): self.label = _('content') self.help_text = u'' self.initial = '' + self.min_length = 10 + self.post_term_name = _('post') def clean(self, value): if value is None: value = '' if len(value) < self.min_length: msg = ungettext_lazy( - self.length_error_template_singular, - self.length_error_template_plural, + '%(post)s content must be > %(count)d character', + '%(post)s content must be > %(count)d characters', self.min_length - ) % self.min_length + ) % {'post': unicode(self.post_term_name), 'count': self.min_length} raise forms.ValidationError(msg) if self.user.is_anonymous(): @@ -342,11 +341,8 @@ class QuestionEditorField(EditorField): super(QuestionEditorField, self).__init__( user=user, *args, **kwargs ) - self.length_error_template_singular = \ - 'question body must be > %d character' - self.length_error_template_plural = \ - 'question body must be > %d characters' self.min_length = askbot_settings.MIN_QUESTION_BODY_LENGTH + self.post_term_name = askbot_settings.WORDS_QUESTION_SINGULAR class AnswerEditorField(EditorField): @@ -354,8 +350,7 @@ class AnswerEditorField(EditorField): def __init__(self, *args, **kwargs): super(AnswerEditorField, self).__init__(*args, **kwargs) - self.length_error_template_singular = 'answer must be > %d character' - self.length_error_template_plural = 'answer must be > %d characters' + self.post_term_name = askbot_settings.WORDS_ANSWER_SINGULAR self.min_length = askbot_settings.MIN_ANSWER_BODY_LENGTH @@ -376,9 +371,14 @@ def clean_tag(tag_name): #todo - this needs to come from settings tagname_re = re.compile(const.TAG_REGEX, re.UNICODE) if not tagname_re.search(tag_name): - raise forms.ValidationError( - _(message_keys.TAG_WRONG_CHARS_MESSAGE) - ) + if tag_name[0] in const.TAG_FORBIDDEN_FIRST_CHARS: + raise forms.ValidationError( + _(message_keys.TAG_WRONG_FIRST_CHAR_MESSAGE) + ) + else: + raise forms.ValidationError( + _(message_keys.TAG_WRONG_CHARS_MESSAGE) + ) if askbot_settings.FORCE_LOWERCASE_TAGS: #a simpler way to handle tags - just lowercase thew all @@ -475,11 +475,6 @@ class WikiField(forms.BooleanField): 'community wiki (karma is not awarded & ' 'many others can edit wiki post)' ) - self.help_text = _( - 'if you choose community wiki option, the question ' - 'and answer do not generate points and name of ' - 'author will not be shown' - ) def clean(self, value): return value and askbot_settings.WIKI_ON @@ -730,7 +725,6 @@ class FeedbackForm(forms.Form): email = forms.EmailField(label=_('Email:'), required=False) message = forms.CharField( label=_('Your message:'), - max_length=800, widget=forms.Textarea(attrs={'cols': 60}) ) no_email = forms.BooleanField( @@ -751,6 +745,11 @@ class FeedbackForm(forms.Form): private_key=askbot_settings.RECAPTCHA_SECRET, public_key=askbot_settings.RECAPTCHA_KEY ) + def clean_message(self): + message = self.cleaned_data.get('message', '').strip() + if not message: + raise forms.ValidationError(_('Message is required')) + return message def clean(self): super(FeedbackForm, self).clean() @@ -908,18 +907,9 @@ class AskForm(PostAsSomeoneForm, PostPrivatelyForm): in the cleaned data, and will evaluate to False if the settings forbids anonymous asking """ - title = TitleField() tags = TagNamesField() wiki = WikiField() group_id = forms.IntegerField(required = False, widget = forms.HiddenInput) - ask_anonymously = forms.BooleanField( - label=_('ask anonymously'), - help_text=_( - 'Check if you do not want to reveal your name ' - 'when asking this question' - ), - required=False, - ) openid = forms.CharField( required=False, max_length=255, widget=forms.TextInput(attrs={'size': 40, 'class': 'openid-input'}) @@ -929,7 +919,14 @@ class AskForm(PostAsSomeoneForm, PostPrivatelyForm): user = kwargs.pop('user', None) super(AskForm, self).__init__(*args, **kwargs) #it's important that this field is set up dynamically + self.fields['title'] = TitleField() self.fields['text'] = QuestionEditorField(user=user) + + self.fields['ask_anonymously'] = forms.BooleanField( + label=_('post anonymously'), + required=False, + ) + #hide ask_anonymously field if getattr(django_settings, 'ASKBOT_MULTILINGUAL', False): self.fields['language'] = LanguageField() @@ -954,19 +951,15 @@ ASK_BY_EMAIL_SUBJECT_HELP = _( class AskWidgetForm(forms.Form, FormWithHideableFields): '''Simple form with just the title to ask a question''' - title = TitleField() ask_anonymously = forms.BooleanField( label=_('ask anonymously'), - help_text=_( - 'Check if you do not want to reveal your name ' - 'when asking this question' - ), required=False, ) def __init__(self, include_text=True, *args, **kwargs): user = kwargs.pop('user', None) super(AskWidgetForm, self).__init__(*args, **kwargs) + self.fields['title'] = TitleField() #hide ask_anonymously field if not askbot_settings.ALLOW_ASK_ANONYMOUSLY: self.hide_field('ask_anonymously') @@ -1206,16 +1199,10 @@ class RevisionForm(forms.Form): self.fields['revision'].initial = latest_revision.revision class EditQuestionForm(PostAsSomeoneForm, PostPrivatelyForm): - title = TitleField() tags = TagNamesField() summary = SummaryField() wiki = WikiField() reveal_identity = forms.BooleanField( - help_text=_( - 'You have asked this question anonymously, ' - 'if you decide to reveal your identity, please check ' - 'this box.' - ), label=_('reveal identity'), required=False, ) @@ -1230,6 +1217,7 @@ class EditQuestionForm(PostAsSomeoneForm, PostPrivatelyForm): super(EditQuestionForm, self).__init__(*args, **kwargs) #it is important to add this field dynamically self.fields['text'] = QuestionEditorField(user=self.user) + self.fields['title'] = TitleField() self.fields['title'].initial = revision.title self.fields['text'].initial = revision.text self.fields['tags'].initial = revision.tagnames @@ -1520,22 +1508,15 @@ class EditUserEmailFeedsForm(forms.Form): 'mentions_and_comments': 'i', } - asked_by_me = EmailFeedSettingField( - label=_('Asked by me') - ) - answered_by_me = EmailFeedSettingField( - label=_('Answered by me') - ) - individually_selected = EmailFeedSettingField( - label=_('Individually selected') - ) - all_questions = EmailFeedSettingField( - label=_('Entire forum (tag filtered)'), - ) - - mentions_and_comments = EmailFeedSettingField( - label=_('Comments and posts mentioning me'), - ) + def __init__(self, *args, **kwargs): + super(EditUserEmailFeedsForm, self).__init__(*args, **kwargs) + self.fields = SortedDict(( + ('asked_by_me', EmailFeedSettingField(label=askbot_settings.WORDS_ASKED_BY_ME)), + ('answered_by_me', EmailFeedSettingField(label=askbot_settings.WORDS_ANSWERED_BY_ME)), + ('individually_selected', EmailFeedSettingField(label=_('Individually selected'))), + ('all_questions', EmailFeedSettingField(label=_('Entire forum (tag filtered)'))), + ('mentions_and_comments', EmailFeedSettingField(label=_('Comments and posts mentioning me'))) + )) def set_initial_values(self, user=None): from askbot import models diff --git a/askbot/locale/ar/LC_MESSAGES/django.mo b/askbot/locale/ar/LC_MESSAGES/django.mo Binary files differindex b53e71b5..22f09343 100644 --- a/askbot/locale/ar/LC_MESSAGES/django.mo +++ b/askbot/locale/ar/LC_MESSAGES/django.mo diff --git a/askbot/locale/ar/LC_MESSAGES/django.po b/askbot/locale/ar/LC_MESSAGES/django.po index 039bc5b2..f09eab69 100644 --- a/askbot/locale/ar/LC_MESSAGES/django.po +++ b/askbot/locale/ar/LC_MESSAGES/django.po @@ -6,6 +6,7 @@ # Ahmad Khayyat <akhayyat@gmail.com>, 2013 # Ahmad Khayyat <akhayyat@gmail.com>, 2012 # AminosAmigos <aminosamigos@gmail.com>, 2012 +# evgeny <evgeny.fadeev@gmail.com>, 2009 # Fahad Al-Fattani <fahadaaf@gmail.com>, 2012 # Husam M. ALFarra <husamfarra@gmail.com>, 2013 # Khalid A Sam <kifcaliph@hotmail.com>, 2012 @@ -17,7 +18,7 @@ msgstr "" "Project-Id-Version: askbot\n" "Report-Msgid-Bugs-To: http://askbot.org/\n" "POT-Creation-Date: 2013-07-13 14:06-0500\n" -"PO-Revision-Date: 2013-08-02 10:49+0000\n" +"PO-Revision-Date: 2013-09-11 05:36+0000\n" "Last-Translator: mustafaalbazy <mustafa@albazy.com>\n" "Language-Team: Arabic (http://www.transifex.com/projects/p/askbot/language/ar/)\n" "MIME-Version: 1.0\n" @@ -74,7 +75,7 @@ msgstr[5] "" #: forms.py:220 msgid "minor edit (don't send alerts)" -msgstr "" +msgstr "تعديل بسيط (لا ترسل تنبيهات)" #: forms.py:247 templates/widgets/markdown_help.html:20 #: templates/widgets/markdown_help.html:24 @@ -83,7 +84,7 @@ msgstr "العنوان" #: forms.py:249 templates/embed/ask_by_widget.html:170 msgid "Please enter your question" -msgstr "" +msgstr "عنوان السؤال" #: forms.py:260 #, python-format @@ -99,12 +100,12 @@ msgstr[5] "" #: forms.py:270 #, python-format msgid "The question is too long, maximum allowed size is %d characters" -msgstr "" +msgstr "هذا السؤال كبير جداً، الØد الأقصى Ø§Ù„Ù…Ø³Ù…ÙˆØ Ø¨Ù‡ هو %d ØرÙ" #: forms.py:277 #, python-format msgid "The question is too long, maximum allowed size is %d bytes" -msgstr "" +msgstr "هذا السؤال كبير جداً، الØد الأقصى Ø§Ù„Ù…Ø³Ù…ÙˆØ Ø¨Ù‡ هو %d بايت" #: forms.py:309 msgid "content" @@ -125,7 +126,7 @@ msgstr[5] "يجب أن تتكون كل بطاقة من %(max_chars)d ØرÙاً msgid "" "We ran out of space for recording the tags. Please shorten or delete some of" " them." -msgstr "" +msgstr "لقد تجاوزت المساØØ© Ø§Ù„Ù…Ø³Ù…ÙˆØ Ø¨Ù‡Ø§ للموضوع، Ùضلاً قصرهم او اØذ٠بعضهم." #: forms.py:410 forms.py:1006 models/widgets.py:27 #: templates/widgets/edit_post.html:32 templates/widgets/meta_nav.html:6 @@ -171,7 +172,7 @@ msgstr "ويكي مجتمع (لا يتم Ù…Ù†Ø ÙƒØ§Ø±Ù…Ø§ ويمكن للآخر msgid "" "if you choose community wiki option, the question and answer do not generate" " points and name of author will not be shown" -msgstr "" +msgstr "إذا أخترت أن يكون السؤال ويكي، السؤال والأجوبة لن ÙŠØصلا على نقاط كما ان أسم الكاتب لن يظهر، Øيث يعتبر ان الويكي مساهمة جماعية." #: forms.py:496 msgid "update summary:" @@ -252,7 +253,7 @@ msgstr "نص الرسالة" #: forms.py:727 msgid "Your name (optional):" -msgstr "اسمك (إختياري):" +msgstr "أسمك (إختياري):" #: forms.py:728 msgid "Email:" @@ -264,11 +265,11 @@ msgstr "رسالتك" #: forms.py:735 msgid "I don't want to give my email or receive a response:" -msgstr "لا أريد إعطاء البريد الإلكتروني Ùˆ لا أريد إستلام رد:" +msgstr "لا أريد أعطاء بريدي او أستقبال رد:" #: forms.py:758 msgid "Please mark \"I dont want to give my mail\" field." -msgstr "يرجى وضع علامة \"أنا لا أريد أن إعطاء بريدي\" للØقل." +msgstr "Ùضلاً Øدد Øقل \"لا أريد أعطاء بريدي\"" #: forms.py:791 msgid "keep private within your groups" @@ -276,7 +277,7 @@ msgstr "" #: forms.py:830 msgid "User name:" -msgstr "" +msgstr "أسم المستخدم" #: forms.py:832 msgid "Enter name to post on behalf of someone else. Can create new accounts." @@ -284,11 +285,11 @@ msgstr "" #: forms.py:839 msgid "Email address:" -msgstr "" +msgstr "عنوان البريد" #: forms.py:889 msgid "User name is required with the email" -msgstr "" +msgstr "أسمك مطلوب مع البريد" #: forms.py:894 msgid "Email is required if user name is added" @@ -414,14 +415,14 @@ msgstr "العنوان" #: forms.py:1676 templates/groups.html:32 msgid "Description" -msgstr "" +msgstr "الوصÙ" #: forms.py:1695 templates/tags.html:3 templates/tags/header.html:9 #: templates/tags/list_bulk_tag_subscription.html:12 #: templates/widgets/edit_post.html:26 templates/widgets/related_tags.html:3 #: templates/widgets/tag_category_selector.html:2 msgid "Tags" -msgstr "علامات" +msgstr "المواضيع" #: tasks.py:98 msgid "An edit for my answer" @@ -434,11 +435,11 @@ msgstr "" #: tasks.py:119 #, python-format msgid "Your post at %(site_name)s is now published" -msgstr "" +msgstr "تم نشرك مشاركتك ÙÙŠ %(site_name)s" #: urls.py:44 msgid "questions" -msgstr "أسئلة" +msgstr "questions" #: urls.py:56 msgid "question/" @@ -454,7 +455,7 @@ msgstr "users/" #: urls.py:71 msgid "by-group/" -msgstr "" +msgstr "by-group/" #: urls.py:78 urls.py:159 urls.py:226 urls.py:520 msgid "edit/" @@ -466,11 +467,11 @@ msgstr "subscriptions/" #: urls.py:94 msgid "select_languages/" -msgstr "" +msgstr "select_languages/" #: urls.py:105 msgid "groups/" -msgstr "" +msgstr "groups/" #: urls.py:110 msgid "users/update_has_custom_avatar/" @@ -498,7 +499,7 @@ msgstr "privacy/" #: urls.py:157 msgid "help/" -msgstr "مساعدة/" +msgstr "help/" #: urls.py:159 urls.py:164 msgid "answers/" @@ -535,23 +536,23 @@ msgstr "answer/" #: urls.py:314 msgid "tags/subscriptions/" -msgstr "" +msgstr "topcis/subscriptions/" #: urls.py:319 msgid "tags/subscriptions/delete/" -msgstr "" +msgstr "topics/subscriptions/delete/" #: urls.py:324 msgid "tags/subscriptions/create/" -msgstr "" +msgstr "topics/subscriptions/create/" #: urls.py:329 msgid "tags/subscriptions/edit/" -msgstr "" +msgstr "topics/subscriptions/edit/" #: urls.py:334 msgid "suggested-tags/" -msgstr "" +msgstr "suggested-topics/" #: urls.py:459 msgid "messages/" @@ -564,19 +565,19 @@ msgstr "markread/" #: urls.py:490 urls.py:495 urls.py:500 urls.py:505 urls.py:510 urls.py:515 #: urls.py:520 urls.py:525 urls.py:530 msgid "widgets/" -msgstr "ودجة/" +msgstr "widgets/" #: urls.py:510 deps/django_authopenid/urls.py:20 msgid "complete/" -msgstr "" +msgstr "complete/" #: urls.py:515 msgid "create/" -msgstr "" +msgstr "create/" #: urls.py:525 msgid "delete/" -msgstr "" +msgstr "delete/" #: urls.py:560 msgid "upload/" @@ -589,39 +590,39 @@ msgstr "account/" #: conf/access_control.py:8 msgid "Access control settings" -msgstr "" +msgstr "إعدادات الوصول" #: conf/access_control.py:17 msgid "Allow only registered user to access the forum" -msgstr "Ø§Ù„Ø³Ù…Ø§Ø Ùقط للمستخدمين المسجلين بالدخول الى المنتدى" +msgstr "Ø§Ù„Ø³Ù…Ø§Ø Ùقط للأعضاء المسجلين لدخول هذا المنتدى" #: conf/access_control.py:22 msgid "nothing - not required" -msgstr "" +msgstr "لا شيء - غير مطلوب" #: conf/access_control.py:23 msgid "access to content" -msgstr "" +msgstr "الوصول للمØتوى" #: conf/access_control.py:34 msgid "Require valid email for" -msgstr "" +msgstr "البريد مطلوب من اجل" #: conf/access_control.py:44 msgid "Allowed email addresses" -msgstr "" +msgstr "عناوين البريد Ø§Ù„Ù…Ø³Ù…ÙˆØ Ø¨Ù‡Ø§" #: conf/access_control.py:45 msgid "Please use space to separate the entries" -msgstr "" +msgstr "أستخدم المساÙØ© للÙصل بينهم" #: conf/access_control.py:54 msgid "Allowed email domain names" -msgstr "" +msgstr "عنوان نطاقات البريد Ø§Ù„Ù…Ø³Ù…ÙˆØ Ø¨Ù‡Ø§" #: conf/access_control.py:55 msgid "Please use space to separate the entries, do not use the @ symbol!" -msgstr "" +msgstr "يرجى إستخدام المساÙات Ù„Ùصل المدخلات، لا تستخدم رمز @" #: conf/badges.py:13 msgid "Badge settings" @@ -629,15 +630,15 @@ msgstr "إعدادات الشارات" #: conf/badges.py:23 msgid "Disciplined: minimum upvotes for deleted post" -msgstr "" +msgstr "Disciplined: minimum upvotes for deleted post" #: conf/badges.py:32 msgid "Peer Pressure: minimum downvotes for deleted post" -msgstr "" +msgstr "Peer Pressure: minimum downvotes for deleted post" #: conf/badges.py:41 msgid "Teacher: minimum upvotes for the answer" -msgstr "" +msgstr "Teacher: minimum upvotes for the answer" #: conf/badges.py:50 msgid "Nice Answer: minimum upvotes for the answer" @@ -665,43 +666,43 @@ msgstr "سؤال عظيم: الØد الأدني من الأصوات للسؤا٠#: conf/badges.py:104 msgid "Popular Question: minimum views" -msgstr "" +msgstr "Popular Question: minimum views" #: conf/badges.py:113 msgid "Notable Question: minimum views" -msgstr "" +msgstr "Notable Question: minimum views" #: conf/badges.py:122 msgid "Famous Question: minimum views" -msgstr "" +msgstr "Famous Question: minimum views" #: conf/badges.py:131 msgid "Self-Learner: minimum answer upvotes" -msgstr "" +msgstr "Self-Learner: minimum answer upvotes" #: conf/badges.py:140 msgid "Civic Duty: minimum votes" -msgstr "" +msgstr "Civic Duty: minimum votes" #: conf/badges.py:149 msgid "Enlightened Duty: minimum upvotes" -msgstr "" +msgstr "Enlightened Duty: minimum upvotes" #: conf/badges.py:158 msgid "Guru: minimum upvotes" -msgstr "" +msgstr "Guru: minimum upvotes" #: conf/badges.py:167 msgid "Necromancer: minimum upvotes" -msgstr "" +msgstr "Necromancer: minimum upvotes" #: conf/badges.py:176 msgid "Necromancer: minimum delay in days" -msgstr "" +msgstr "Necromancer: minimum delay in days" #: conf/badges.py:185 msgid "Associate Editor: minimum number of edits" -msgstr "" +msgstr "Associate Editor: minimum number of edits" #: conf/badges.py:194 msgid "Favorite Question: minimum stars" @@ -709,19 +710,19 @@ msgstr "سؤال Ù…Ùضل: الØد الأدني من النجوم" #: conf/badges.py:203 msgid "Stellar Question: minimum stars" -msgstr "" +msgstr "Stellar Question: minimum stars" #: conf/badges.py:212 msgid "Commentator: minimum comments" -msgstr "" +msgstr "Commentator: minimum comments" #: conf/badges.py:221 msgid "Taxonomist: minimum tag use count" -msgstr "" +msgstr "Taxonomist: minimum tag use count" #: conf/badges.py:230 msgid "Enthusiast: minimum days" -msgstr "" +msgstr "Enthusiast: minimum days" #: conf/email.py:15 msgid "Email and email alert settings" @@ -735,15 +736,15 @@ msgstr "تصدير سطر العنوان للرسائل الإلكترونية" msgid "" "This setting takes default from the django settingEMAIL_SUBJECT_PREFIX. A " "value entered here will overridethe default." -msgstr "" +msgstr "This setting takes default from the django settingEMAIL_SUBJECT_PREFIX. A value entered here will overridethe default." #: conf/email.py:44 msgid "Site administrator email address" -msgstr "" +msgstr "عنوان بريد مدير الموقع" #: conf/email.py:53 msgid "Enable email alerts" -msgstr "تÙعيل تنبهات البريد" +msgstr "تÙعيل تنبيهات البريد" #: conf/email.py:62 msgid "Maximum number of news entries in an email alert" @@ -751,54 +752,54 @@ msgstr "العدد الأقصى من الأخبار لكل رسالة تنبيه #: conf/email.py:72 msgid "Default notification frequency all questions" -msgstr "" +msgstr "Default notification frequency all questions" #: conf/email.py:74 msgid "Option to define frequency of emailed updates for: all questions." -msgstr "" +msgstr "Option to define frequency of emailed updates for: all questions." #: conf/email.py:86 msgid "Default notification frequency questions asked by the user" -msgstr "" +msgstr "Default notification frequency questions asked by the user" #: conf/email.py:88 msgid "" "Option to define frequency of emailed updates for: Question asked by the " "user." -msgstr "" +msgstr "Option to define frequency of emailed updates for: Question asked by the user." #: conf/email.py:100 msgid "Default notification frequency questions answered by the user" -msgstr "" +msgstr "Default notification frequency questions answered by the user" #: conf/email.py:102 msgid "" "Option to define frequency of emailed updates for: Question answered by the " "user." -msgstr "" +msgstr "Option to define frequency of emailed updates for: Question answered by the user." #: conf/email.py:114 msgid "" "Default notification frequency questions individually" " selected by the user" -msgstr "" +msgstr "Default notification frequency questions individually selected by the user" #: conf/email.py:117 msgid "" "Option to define frequency of emailed updates for: Question individually " "selected by the user." -msgstr "" +msgstr "Option to define frequency of emailed updates for: Question individually selected by the user." #: conf/email.py:129 msgid "" "Default notification frequency for mentions and " "comments" -msgstr "" +msgstr "Default notification frequency for mentions and comments" #: conf/email.py:132 msgid "" "Option to define frequency of emailed updates for: Mentions and comments." -msgstr "" +msgstr "Option to define frequency of emailed updates for: Mentions and comments." #: conf/email.py:143 msgid "Send periodic reminders about unanswered questions" @@ -809,7 +810,7 @@ msgid "" "NOTE: in order to use this feature, it is necessary to run the management " "command \"send_unanswered_question_reminders\" (for example, via a cron job " "- with an appropriate frequency) " -msgstr "" +msgstr "NOTE: in order to use this feature, it is necessary to run the management command \"send_unanswered_question_reminders\" (for example, via a cron job - with an appropriate frequency) " #: conf/email.py:158 msgid "Days before starting to send reminders about unanswered questions" @@ -827,28 +828,28 @@ msgstr "العدد الأقصى من الرسائل التذكيرية Ù„Ù„Ø£Ø³Ø #: conf/email.py:192 msgid "Send periodic reminders to accept the best answer" -msgstr "ارسل تنبيه دوري للمواÙقة على Ø£Ùضل إجابة" +msgstr "Send periodic reminders to accept the best answer" #: conf/email.py:194 msgid "" "NOTE: in order to use this feature, it is necessary to run the management " "command \"send_accept_answer_reminders\" (for example, via a cron job - with" " an appropriate frequency) " -msgstr "" +msgstr "NOTE: in order to use this feature, it is necessary to run the management command \"send_accept_answer_reminders\" (for example, via a cron job - with an appropriate frequency) " #: conf/email.py:207 msgid "Days before starting to send reminders to accept an answer" -msgstr "" +msgstr "الأيام قبل البدء بإرسال تنبيهات لقبول Ø£Ùضل إجابة للسؤال" #: conf/email.py:218 msgid "" "How often to send accept answer reminders (in days between the reminders " "sent)." -msgstr "" +msgstr "How often to send accept answer reminders (in days between the reminders sent)." #: conf/email.py:230 msgid "Max. number of reminders to send to accept the best answer" -msgstr "" +msgstr "الØد الأقصى للتنبيهات على قبول Ø£Ùضل إجابة للسؤال" #: conf/email.py:242 msgid "Require email verification before allowing to post" @@ -857,29 +858,29 @@ msgstr "اشتراط التØقق من البريد الإلكتروني قبل #: conf/email.py:243 msgid "" "Active email verification is done by sending a verification key in email" -msgstr "" +msgstr "Active email verification is done by sending a verification key in email" #: conf/email.py:252 msgid "Fake email for anonymous user" -msgstr "" +msgstr "البريد المزي٠للأعضاء المجهولون" #: conf/email.py:253 msgid "Use this setting to control gravatar for email-less user" -msgstr "" +msgstr "Use this setting to control gravatar for email-less user" #: conf/email.py:262 msgid "Allow posting questions by email" -msgstr "" +msgstr "Ø§Ù„Ø³Ù…Ø§Ø Ø¨Ù†Ø´Ø± الأسئلة عبر البريد" #: conf/email.py:264 msgid "" "Before enabling this setting - please fill out IMAP settings in the " "settings.py file" -msgstr "" +msgstr "Before enabling this setting - please fill out IMAP settings in the settings.py file" #: conf/email.py:275 msgid "Replace space in emailed tags with dash" -msgstr "" +msgstr "تبديل المساÙØ© بالبريد للمواضيع بعلامة ( _ ) " #: conf/email.py:277 msgid "" @@ -889,29 +890,29 @@ msgstr "يطبق هذا الإعداد على الوسوم المذكورة ÙÙŠ #: conf/email.py:288 msgid "Enable posting answers and comments by email" -msgstr "" +msgstr "تÙعيل نشر الأسئلة والتعليقات عبر البريد" #: conf/email.py:291 msgid "To enable this feature make sure lamson is running" -msgstr "" +msgstr "لتÙعيل هذه الخاصية تأكد من أن lamson Ùعال ويعمل." #: conf/email.py:302 msgid "Emailed post: when to notify author about publishing" -msgstr "" +msgstr "Emailed post: when to notify author about publishing" #: conf/email.py:327 msgid "Reply by email hostname" -msgstr "" +msgstr "Reply by email hostname" #: conf/email.py:338 msgid "" "Email replies having fewer words than this number will be posted as comments" " instead of answers" -msgstr "" +msgstr "Email replies having fewer words than this number will be posted as comments instead of answers" #: conf/external_keys.py:11 msgid "Keys for external services" -msgstr "" +msgstr "Ù…ÙØ§ØªÙŠØ Ø§Ù„Ø®Ø¯Ù…Ø§Øª الخارجية" #: conf/external_keys.py:19 msgid "Google site verification key" @@ -922,22 +923,22 @@ msgstr "Ù…ÙØªØ§Ø Google للتØقق من الموقع" msgid "" "This key helps google index your site please obtain is at <a " "href=\"%(url)s?hl=%(lang)s\">google webmasters tools site</a>" -msgstr "" +msgstr "This key helps google index your site please obtain is at <a href=\"%(url)s?hl=%(lang)s\">google webmasters tools site</a>" #: conf/external_keys.py:36 msgid "Google Analytics key" -msgstr "Ù…ÙØªØ§Ø Ø¬ÙˆØ¬Ù„ Analytics" +msgstr "Google Analytics key" #: conf/external_keys.py:38 #, python-format msgid "" "Obtain is at <a href=\"%(url)s\">Google Analytics</a> site, if you wish to " "use Google Analytics to monitor your site" -msgstr "" +msgstr "Obtain is at <a href=\"%(url)s\">Google Analytics</a> site, if you wish to use Google Analytics to monitor your site" #: conf/external_keys.py:51 msgid "Enable recaptcha (keys below are required)" -msgstr "" +msgstr "تÙعيل recaptcha (المÙØ§ØªÙŠØ ÙÙŠ الأسÙÙ„ مطلوبة)" #: conf/external_keys.py:62 msgid "Recaptcha public key" @@ -953,11 +954,11 @@ msgid "" "Recaptcha is a tool that helps distinguish real people from annoying spam " "robots. Please get this and a public key at the <a " "href=\"%(url)s\">%(url)s</a>" -msgstr "" +msgstr "Recaptcha is a tool that helps distinguish real people from annoying spam robots. Please get this and a public key at the <a href=\"%(url)s\">%(url)s</a>" #: conf/external_keys.py:84 msgid "Facebook public API key" -msgstr "Ù…ÙØªØ§Ø Facebook العام" +msgstr "Facebook public API key" #: conf/external_keys.py:86 #, python-format @@ -965,135 +966,135 @@ msgid "" "Facebook API key and Facebook secret allow to use Facebook Connect login " "method at your site. Please obtain these keys at <a " "href=\"%(url)s\">facebook create app</a> site" -msgstr "" +msgstr "Facebook API key and Facebook secret allow to use Facebook Connect login method at your site. Please obtain these keys at <a href=\"%(url)s\">facebook create app</a> site" #: conf/external_keys.py:99 msgid "Facebook secret key" -msgstr "" +msgstr "Facebook secret key" #: conf/external_keys.py:107 msgid "Twitter consumer key" -msgstr "" +msgstr "Twitter consumer key" #: conf/external_keys.py:109 #, python-format msgid "" "Please register your forum at <a href=\"%(url)s\">twitter applications " "site</a>" -msgstr "" +msgstr "Please register your forum at <a href=\"%(url)s\">twitter applications site</a>" #: conf/external_keys.py:120 msgid "Twitter consumer secret" -msgstr "" +msgstr "Twitter consumer secret" #: conf/external_keys.py:128 msgid "LinkedIn consumer key" -msgstr "" +msgstr "LinkedIn consumer key" #: conf/external_keys.py:130 #, python-format msgid "" "Please register your forum at <a href=\"%(url)s\">LinkedIn developer " "site</a>" -msgstr "" +msgstr "Please register your forum at <a href=\"%(url)s\">LinkedIn developer site</a>" #: conf/external_keys.py:141 msgid "LinkedIn consumer secret" -msgstr "" +msgstr "LinkedIn consumer secret" #: conf/external_keys.py:149 msgid "ident.ca consumer key" -msgstr "" +msgstr "ident.ca consumer key" #: conf/external_keys.py:151 #, python-format msgid "" "Please register your forum at <a href=\"%(url)s\">Identi.ca applications " "site</a>" -msgstr "" +msgstr "Please register your forum at <a href=\"%(url)s\">Identi.ca applications site</a>" #: conf/external_keys.py:162 msgid "ident.ca consumer secret" -msgstr "" +msgstr "ident.ca consumer secret" #: conf/flatpages.py:11 msgid "Messages and pages - about, privacy policy, etc." -msgstr "" +msgstr "الرسائل والصÙØات - عن الموقع، الخصوصية...الخ." #: conf/flatpages.py:19 msgid "Text of the Q&A forum About page (html format)" -msgstr "" +msgstr "Text of the Q&A forum About page (html format)" #: conf/flatpages.py:22 msgid "" "Save, then <a href=\"http://validator.w3.org/\">use HTML validator</a> on " "the \"about\" page to check your input." -msgstr "" +msgstr "Save, then <a href=\"http://validator.w3.org/\">use HTML validator</a> on the \"about\" page to check your input." #: conf/flatpages.py:32 msgid "Text of the Q&A forum FAQ page (html format)" -msgstr "" +msgstr "Text of the Q&A forum FAQ page (html format)" #: conf/flatpages.py:35 msgid "" "Save, then <a href=\"http://validator.w3.org/\">use HTML validator</a> on " "the \"faq\" page to check your input." -msgstr "" +msgstr "Save, then <a href=\"http://validator.w3.org/\">use HTML validator</a> on the \"faq\" page to check your input." #: conf/flatpages.py:45 msgid "Instructions on how to ask questions" -msgstr "" +msgstr "Instructions on how to ask questions" #: conf/flatpages.py:48 msgid "" "HTML is allowed. Save, then <a href=\"http://validator.w3.org/\">use HTML " "validator</a> on the \"ask\" page to check your input." -msgstr "" +msgstr "HTML is allowed. Save, then <a href=\"http://validator.w3.org/\">use HTML validator</a> on the \"ask\" page to check your input." #: conf/flatpages.py:59 msgid "Text of the Q&A forum Privacy Policy (html format)" -msgstr "" +msgstr "Text of the Q&A forum Privacy Policy (html format)" #: conf/flatpages.py:62 msgid "" "Save, then <a href=\"http://validator.w3.org/\">use HTML validator</a> on " "the \"privacy\" page to check your input." -msgstr "" +msgstr "Save, then <a href=\"http://validator.w3.org/\">use HTML validator</a> on the \"privacy\" page to check your input." #: conf/flatpages.py:75 msgid "Do not edit this field manually!!!" -msgstr "" +msgstr "Do not edit this field manually!!!" #: conf/forum_data_rules.py:12 msgid "Data entry and display rules" -msgstr "" +msgstr "Data entry and display rules" #: conf/forum_data_rules.py:27 msgid "Editor for the posts" -msgstr "" +msgstr "Editor for the posts" #: conf/forum_data_rules.py:42 msgid "Editor for the comments" -msgstr "" +msgstr "Editor for the comments" #: conf/forum_data_rules.py:51 msgid "Enable big Ask button" -msgstr "" +msgstr "Enable big Ask button" #: conf/forum_data_rules.py:53 msgid "" "Disabling this button will reduce number of new questions. If this button is" " disabled, the ask button in the search menu will still be available." -msgstr "" +msgstr "Disabling this button will reduce number of new questions. If this button is disabled, the ask button in the search menu will still be available." #: conf/forum_data_rules.py:66 msgid "Enable embedding videos. " -msgstr "" +msgstr "Enable embedding videos. " #: conf/forum_data_rules.py:68 #, python-format msgid "<em>Note: please read <a href=\"%(url)s\">read this</a> first.</em>" -msgstr "" +msgstr "<em>Note: please read <a href=\"%(url)s\">read this</a> first.</em>" #: conf/forum_data_rules.py:78 msgid "Check to enable community wiki feature" @@ -1107,11 +1108,11 @@ msgstr "Ø§Ù„Ø³Ù…Ø§Ø Ø¨Ø§Ù„Ø³Ø¤Ø§Ù„ دون تØديد الهوية" msgid "" "Users do not accrue reputation for anonymous questions and their identity is" " not revealed until they change their mind" -msgstr "" +msgstr "Users do not accrue reputation for anonymous questions and their identity is not revealed until they change their mind" #: conf/forum_data_rules.py:101 msgid "Allow posting before logging in" -msgstr "" +msgstr "Allow posting before logging in" #: conf/forum_data_rules.py:103 msgid "" @@ -1119,39 +1120,39 @@ msgid "" "logging in. Enabling this may require adjustments in the user login system " "to check for pending posts every time the user logs in. The builtin Askbot " "login system supports this feature." -msgstr "" +msgstr "Check if you want to allow users start posting questions or answers before logging in. Enabling this may require adjustments in the user login system to check for pending posts every time the user logs in. The builtin Askbot login system supports this feature." #: conf/forum_data_rules.py:118 msgid "Auto-follow questions by the Author" -msgstr "" +msgstr "Auto-follow questions by the Author" #: conf/forum_data_rules.py:123 msgid "Fully open by default" -msgstr "" +msgstr "Fully open by default" #: conf/forum_data_rules.py:124 msgid "Folded by default" -msgstr "" +msgstr "Folded by default" #: conf/forum_data_rules.py:133 msgid "Question details/body editor should be" -msgstr "" +msgstr "Question details/body editor should be" #: conf/forum_data_rules.py:135 msgid "" "To use folded mode, please first set minimum question body length to 0. Also" " - please make tags optional." -msgstr "" +msgstr "To use folded mode, please first set minimum question body length to 0. Also - please make tags optional." #: conf/forum_data_rules.py:147 msgid "Allow swapping answer with question" -msgstr "انشر إجابتك" +msgstr "Allow swapping answer with question" #: conf/forum_data_rules.py:149 msgid "" "This setting will help import data from other forums such as zendesk, when " "automatic data import fails to detect the original question correctly." -msgstr "" +msgstr "This setting will help import data from other forums such as zendesk, when automatic data import fails to detect the original question correctly." #: conf/forum_data_rules.py:161 msgid "Maximum length of tag (number of characters)" @@ -1159,35 +1160,35 @@ msgstr "الØد الأقصى لطول الوسم (عدد الØروÙ)" #: conf/forum_data_rules.py:170 msgid "Minimum length of title (number of characters)" -msgstr "" +msgstr "Minimum length of title (number of characters)" #: conf/forum_data_rules.py:180 msgid "Minimum length of question body (number of characters)" -msgstr "" +msgstr "Minimum length of question body (number of characters)" #: conf/forum_data_rules.py:191 msgid "Minimum length of answer body (number of characters)" -msgstr "" +msgstr "Minimum length of answer body (number of characters)" #: conf/forum_data_rules.py:202 msgid "Minimum length of comment (number of characters)" -msgstr "" +msgstr "Minimum length of comment (number of characters)" #: conf/forum_data_rules.py:213 msgid "Limit one answer per question per user" -msgstr "" +msgstr "Limit one answer per question per user" #: conf/forum_data_rules.py:223 msgid "Enable accepting best answer" -msgstr "" +msgstr "Enable accepting best answer" #: conf/forum_data_rules.py:231 msgid "Are tags required?" -msgstr "" +msgstr "Are tags required?" #: conf/forum_data_rules.py:237 msgid "category tree" -msgstr "" +msgstr "category tree" #: conf/forum_data_rules.py:238 msgid "user input" @@ -1195,7 +1196,7 @@ msgstr "" #: conf/forum_data_rules.py:245 msgid "Source of tags" -msgstr "" +msgstr "Source of tags" #: conf/forum_data_rules.py:256 msgid "Mandatory tags" @@ -1205,7 +1206,7 @@ msgstr "وسوم إلزامية" msgid "" "At least one of these tags will be required for any new or newly edited " "question. A mandatory tag may be wildcard, if the wildcard tags are active." -msgstr "" +msgstr "At least one of these tags will be required for any new or newly edited question. A mandatory tag may be wildcard, if the wildcard tags are active." #: conf/forum_data_rules.py:271 msgid "Force lowercase the tags" @@ -1216,7 +1217,7 @@ msgid "" "Attention: after checking this, please back up the database, and run a " "management command: <code>python manage.py fix_question_tags</code> to " "globally rename the tags" -msgstr "" +msgstr "Attention: after checking this, please back up the database, and run a management command: <code>python manage.py fix_question_tags</code> to globally rename the tags" #: conf/forum_data_rules.py:287 msgid "Format of tag list" @@ -1230,43 +1231,43 @@ msgstr "اختر طريقة عرض الوسوم، إما كقائمة بسيطة #: conf/forum_data_rules.py:301 msgid "Use wildcard tags" -msgstr "البطاقات" +msgstr "Use wildcard tags" #: conf/forum_data_rules.py:303 msgid "" "Wildcard tags can be used to follow or ignore many tags at once, a valid " "wildcard tag has a single wildcard at the very end" -msgstr "" +msgstr "Wildcard tags can be used to follow or ignore many tags at once, a valid wildcard tag has a single wildcard at the very end" #: conf/forum_data_rules.py:315 msgid "Use separate set for subscribed tags" -msgstr "" +msgstr "Use separate set for subscribed tags" #: conf/forum_data_rules.py:317 msgid "" "If enabled, users will have a third set of tag selections - \"subscribed\" " "(by email) in additon to \"interesting\" and \"ignored\"" -msgstr "" +msgstr "If enabled, users will have a third set of tag selections - \"subscribed\" (by email) in additon to \"interesting\" and \"ignored\"" #: conf/forum_data_rules.py:325 msgid "Always, for all users" -msgstr "" +msgstr "Always, for all users" #: conf/forum_data_rules.py:326 msgid "Never, for all users" -msgstr "" +msgstr "Never, for all users" #: conf/forum_data_rules.py:327 msgid "Let users decide" -msgstr "" +msgstr "Let users decide" #: conf/forum_data_rules.py:335 msgid "Publicly show user tag selections" -msgstr "" +msgstr "Publicly show user tag selections" #: conf/forum_data_rules.py:344 msgid "Enable separate tag search box on main page" -msgstr "" +msgstr "Enable separate tag search box on main page" #: conf/forum_data_rules.py:354 msgid "Default max number of comments to display under posts" @@ -1301,26 +1302,26 @@ msgstr "Ù„ØÙظ التعليق، اضغظ على زر <Enter>" msgid "" "This may be useful when only one-line comments are desired. Will not work " "with TinyMCE editor." -msgstr "" +msgstr "This may be useful when only one-line comments are desired. Will not work with TinyMCE editor." #: conf/forum_data_rules.py:411 msgid "Minimum length of search term for Ajax search" -msgstr "" +msgstr "Minimum length of search term for Ajax search" #: conf/forum_data_rules.py:412 msgid "Must match the corresponding database backend setting" -msgstr "" +msgstr "Must match the corresponding database backend setting" #: conf/forum_data_rules.py:421 msgid "Do not make text query sticky in search" -msgstr "" +msgstr "Do not make text query sticky in search" #: conf/forum_data_rules.py:423 msgid "" "Check to disable the \"sticky\" behavior of the search query. This may be " "useful if you want to move the search bar away from the default position or " "do not like the default sticky behavior of the text search query." -msgstr "" +msgstr "Check to disable the \"sticky\" behavior of the search query. This may be useful if you want to move the search bar away from the default position or do not like the default sticky behavior of the text search query." #: conf/forum_data_rules.py:436 msgid "Maximum number of tags per question" @@ -1332,121 +1333,121 @@ msgstr "العدد الاÙتراضي للأسئلة المعروضة" #: conf/forum_data_rules.py:458 msgid "What should \"unanswered question\" mean?" -msgstr "" +msgstr "What should \"unanswered question\" mean?" #: conf/group_settings.py:9 msgid "Group settings" -msgstr "" +msgstr "Group settings" #: conf/group_settings.py:18 msgid "Enable user groups" -msgstr "" +msgstr "Enable user groups" #: conf/group_settings.py:41 msgid "everyone" -msgstr "" +msgstr "عامة" #: conf/group_settings.py:42 msgid "Global user group name" -msgstr "" +msgstr "Global user group name" #: conf/group_settings.py:43 msgid "All users belong to this group automatically" -msgstr "" +msgstr "All users belong to this group automatically" #: conf/group_settings.py:53 msgid "Enable group email adddresses" -msgstr "" +msgstr "Enable group email adddresses" #: conf/group_settings.py:55 msgid "If selected, users can post to groups by email \"group-name@domain.com\"" -msgstr "" +msgstr "If selected, users can post to groups by email \"group-name@domain.com\"" #: conf/karma_and_badges_visibility.py:12 msgid "Karma & Badge visibility" -msgstr "" +msgstr "Karma & Badge visibility" #: conf/karma_and_badges_visibility.py:27 msgid "Visibility of karma" -msgstr "" +msgstr "Visibility of karma" #: conf/karma_and_badges_visibility.py:30 msgid "User's karma may be shown publicly or only to the owners" -msgstr "" +msgstr "User's karma may be shown publicly or only to the owners" #: conf/karma_and_badges_visibility.py:44 msgid "Visibility of badges" -msgstr "" +msgstr "Visibility of badges" #: conf/karma_and_badges_visibility.py:47 msgid "Badges can be either publicly shown or completely hidden" -msgstr "" +msgstr "Badges can be either publicly shown or completely hidden" #: conf/ldap.py:9 msgid "LDAP login configuration" -msgstr "" +msgstr "LDAP login configuration" #: conf/ldap.py:17 msgid "Use LDAP authentication for the password login" -msgstr "" +msgstr "Use LDAP authentication for the password login" #: conf/ldap.py:26 msgid "Automatically create user accounts when possible" -msgstr "" +msgstr "Automatically create user accounts when possible" #: conf/ldap.py:29 msgid "" "Potentially reduces number of steps in the registration process but can " "expose personal information, e.g. when LDAP login name is the same as email " "address or real name." -msgstr "" +msgstr "Potentially reduces number of steps in the registration process but can expose personal information, e.g. when LDAP login name is the same as email address or real name." #: conf/ldap.py:37 msgid "Version 3" -msgstr "" +msgstr "Version 3" #: conf/ldap.py:38 msgid "Version 2 (insecure and deprecated)!!!" -msgstr "" +msgstr "Version 2 (insecure and deprecated)!!!" #: conf/ldap.py:47 msgid "LDAP protocol version" -msgstr "" +msgstr "LDAP protocol version" #: conf/ldap.py:49 msgid "" "Note that Version 2 protocol is not secure!!! Do not use it on unprotected " "network." -msgstr "" +msgstr "Note that Version 2 protocol is not secure!!! Do not use it on unprotected network." #: conf/ldap.py:59 msgid "LDAP URL" -msgstr "" +msgstr "LDAP URL" #: conf/ldap.py:68 msgid "LDAP encoding" -msgstr "" +msgstr "LDAP encoding" #: conf/ldap.py:71 msgid "" "This value in almost all cases is \"utf-8\". Change it if yours is " "different. This field is required" -msgstr "" +msgstr "This value in almost all cases is \"utf-8\". Change it if yours is different. This field is required" #: conf/ldap.py:82 msgid "Base DN (distinguished name)" -msgstr "" +msgstr "Base DN (distinguished name)" #: conf/ldap.py:85 msgid "" "Usually base DN mirrors domain name of your organization, e.g. " "\"dn=example,dn=com\" when your site url is \"example.com\".This value is " "the \"root\" address of your LDAP directory." -msgstr "" +msgstr "Usually base DN mirrors domain name of your organization, e.g. \"dn=example,dn=com\" when your site url is \"example.com\".This value is the \"root\" address of your LDAP directory." #: conf/ldap.py:96 msgid "User search filter template" -msgstr "" +msgstr "User search filter template" #: conf/ldap.py:99 msgid "" @@ -1454,7 +1455,7 @@ msgid "" "should be left in the intact format. First placeholder will be used for the " "user id field name, and the second - for the user id value. The template can" " be extended to match schema of your LDAP directory." -msgstr "" +msgstr "Python string format template, must have two string placeholders, which should be left in the intact format. First placeholder will be used for the user id field name, and the second - for the user id value. The template can be extended to match schema of your LDAP directory." #: conf/ldap.py:113 msgid "UserID/login field" @@ -1464,76 +1465,76 @@ msgstr "" msgid "" "This field is required. For Microsoft Active Directory this value usually is" " \"sAMAccountName\"." -msgstr "" +msgstr "This field is required. For Microsoft Active Directory this value usually is \"sAMAccountName\"." #: conf/ldap.py:127 msgid "\"Common Name\" field" -msgstr "" +msgstr "\"Common Name\" field" #: conf/ldap.py:129 msgid "" "Common name is a formal or informal name of a person, can be blank. Use it " "only if surname and given names are not available." -msgstr "" +msgstr "Common name is a formal or informal name of a person, can be blank. Use it only if surname and given names are not available." #: conf/ldap.py:139 msgid "First name, Last name" -msgstr "" +msgstr "First name, Last name" #: conf/ldap.py:140 msgid "Last name, First name" -msgstr "" +msgstr "Last name, First name" #: conf/ldap.py:147 msgid "\"Common Name\" field format" -msgstr "" +msgstr "\"Common Name\" field format" #: conf/ldap.py:150 msgid "Use this only if \"Common Name\" field is used." -msgstr "" +msgstr "Use this only if \"Common Name\" field is used." #: conf/ldap.py:158 msgid "Given (First) name" -msgstr "" +msgstr "Given (First) name" #: conf/ldap.py:160 conf/ldap.py:170 msgid "This field can be blank" -msgstr "" +msgstr "This field can be blank" #: conf/ldap.py:168 msgid "Surname (last) name" -msgstr "" +msgstr "Surname (last) name" #: conf/ldap.py:178 msgid "LDAP Server EMAIL field name" -msgstr "" +msgstr "LDAP Server EMAIL field name" #: conf/ldap.py:180 msgid "This field is required" -msgstr "" +msgstr "This field is required" #: conf/leading_sidebar.py:12 msgid "Common left sidebar" -msgstr "" +msgstr "Common left sidebar" #: conf/leading_sidebar.py:20 msgid "Enable left sidebar" -msgstr "" +msgstr "Enable left sidebar" #: conf/leading_sidebar.py:29 msgid "HTML for the left sidebar" -msgstr "" +msgstr "HTML for the left sidebar" #: conf/leading_sidebar.py:32 msgid "" "Use this area to enter content at the LEFT sidebarin HTML format. When " "using this option, please use the HTML validation service to make sure that " "your input is valid and works well in all browsers." -msgstr "" +msgstr "Use this area to enter content at the LEFT sidebarin HTML format. When using this option, please use the HTML validation service to make sure that your input is valid and works well in all browsers." #: conf/license.py:13 msgid "Content License" -msgstr "رخصة المØتوي" +msgstr "Content License" #: conf/license.py:21 msgid "Show license clause in the site footer" @@ -1549,7 +1550,7 @@ msgstr "الاسم الكامل للرخصة" #: conf/license.py:40 msgid "Creative Commons Attribution Share Alike 3.0" -msgstr "" +msgstr "Creative Commons Attribution Share Alike 3.0" #: conf/license.py:48 msgid "Add link to the license page" @@ -1591,19 +1592,19 @@ msgstr "تنشيط Ø§Ù„Ø³Ù…Ø§Ø Ø¨ØªØ³Ø¬ÙŠÙ„ الدخول باستخدام مو٠msgid "" "to activate this feature you must fill out the wordpress xml-rpc setting " "bellow" -msgstr "" +msgstr "to activate this feature you must fill out the wordpress xml-rpc setting bellow" #: conf/login_providers.py:50 msgid "" "Fill it with the wordpress url to the xml-rpc, normally " "http://mysite.com/xmlrpc.php" -msgstr "" +msgstr "Fill it with the wordpress url to the xml-rpc, normally http://mysite.com/xmlrpc.php" #: conf/login_providers.py:51 msgid "" "To enable, go to Settings->Writing->Remote Publishing and check the box for " "XML-RPC" -msgstr "" +msgstr "To enable, go to Settings->Writing->Remote Publishing and check the box for XML-RPC" #: conf/login_providers.py:60 msgid "Upload your icon" @@ -1611,7 +1612,7 @@ msgstr "رÙع الأيقونة" #: conf/login_providers.py:93 msgid "local password" -msgstr "" +msgstr "local password" #: conf/login_providers.py:98 #, python-format @@ -1627,11 +1628,11 @@ msgstr "ملاØظة: لإتمام تنشيط تسجيل الدخول باستخ #: conf/markup.py:15 msgid "Markup in posts" -msgstr "" +msgstr "Markup in posts" #: conf/markup.py:41 msgid "Enable code-friendly Markdown" -msgstr "" +msgstr "Enable code-friendly Markdown" #: conf/markup.py:43 msgid "" @@ -1639,43 +1640,43 @@ msgid "" " - bold and italic text can still be marked up with asterisks. Note that " "\"MathJax support\" implicitly turns this feature on, because underscores " "are heavily used in LaTeX input." -msgstr "" +msgstr "If checked, underscore characters will not trigger italic or bold formatting - bold and italic text can still be marked up with asterisks. Note that \"MathJax support\" implicitly turns this feature on, because underscores are heavily used in LaTeX input." #: conf/markup.py:58 msgid "Mathjax support (rendering of LaTeX)" -msgstr "" +msgstr "Mathjax support (rendering of LaTeX)" #: conf/markup.py:60 #, python-format msgid "" "If you enable this feature, <a href=\"%(url)s\">mathjax</a> must be " "installed on your server in its own directory." -msgstr "" +msgstr "If you enable this feature, <a href=\"%(url)s\">mathjax</a> must be installed on your server in its own directory." #: conf/markup.py:74 msgid "Base url of MathJax deployment" -msgstr "" +msgstr "Base url of MathJax deployment" #: conf/markup.py:76 msgid "" "Note - <strong>MathJax is not included with askbot</strong> - you should " "deploy it yourself, preferably at a separate domain and enter url pointing " "to the \"mathjax\" directory (for example: http://mysite.com/mathjax)" -msgstr "" +msgstr "Note - <strong>MathJax is not included with askbot</strong> - you should deploy it yourself, preferably at a separate domain and enter url pointing to the \"mathjax\" directory (for example: http://mysite.com/mathjax)" #: conf/markup.py:91 msgid "Enable autolinking with specific patterns" -msgstr "" +msgstr "Enable autolinking with specific patterns" #: conf/markup.py:93 msgid "" "If you enable this feature, the application will be able to detect patterns" " and auto link to URLs" -msgstr "" +msgstr "If you enable this feature, the application will be able to detect patterns and auto link to URLs" #: conf/markup.py:106 msgid "Regexes to detect the link patterns" -msgstr "" +msgstr "Regexes to detect the link patterns" #: conf/markup.py:108 msgid "" @@ -1684,11 +1685,11 @@ msgid "" "The numbers captured by the pattern in the parentheses will be transferred " "to the link url template. Please look up more information about regular " "expressions elsewhere." -msgstr "" +msgstr "Enter valid regular expressions for the patters, one per line. For example to detect a bug pattern like #bug123, use the following regex: #bug(\\d+). The numbers captured by the pattern in the parentheses will be transferred to the link url template. Please look up more information about regular expressions elsewhere." #: conf/markup.py:127 msgid "URLs for autolinking" -msgstr "" +msgstr "URLs for autolinking" #: conf/markup.py:129 msgid "" @@ -1698,11 +1699,11 @@ msgid "" " https://bugzilla.redhat.com/show_bug.cgi?id=\\1 together with the pattern " "shown above and the entry in the post #123 will produce link to the bug 123 " "in the redhat bug tracker." -msgstr "" +msgstr "Here, please enter url templates for the patterns entered in the previous setting, also one entry per line. <strong>Make sure that number of lines in this setting and the previous one are the same</strong> For example template https://bugzilla.redhat.com/show_bug.cgi?id=\\1 together with the pattern shown above and the entry in the post #123 will produce link to the bug 123 in the redhat bug tracker." #: conf/minimum_reputation.py:12 msgid "Karma thresholds" -msgstr "" +msgstr "Karma thresholds" #: conf/minimum_reputation.py:22 msgid "Upvote" @@ -1714,7 +1715,7 @@ msgstr "تصويت للأسÙÙ„" #: conf/minimum_reputation.py:40 msgid "Answer own question immediately" -msgstr "تسليم إجابتك" +msgstr "الإجابة على سؤالك Ùوراً" #: conf/minimum_reputation.py:49 msgid "Accept own answer" @@ -1722,7 +1723,7 @@ msgstr "قبول إجابتي" #: conf/minimum_reputation.py:58 msgid "Accept any answer" -msgstr "" +msgstr "قبول أي إجابة" #: conf/minimum_reputation.py:67 msgid "Flag offensive" @@ -1742,17 +1743,17 @@ msgstr "رÙع الملÙات" #: conf/minimum_reputation.py:115 msgid "Insert clickable links" -msgstr "" +msgstr "نشر رابط قابل للضغط" #: conf/minimum_reputation.py:124 msgid "Insert link suggestions as plain text" -msgstr "" +msgstr "نشر رابط نصي (غير قابل للضغط)" #: conf/minimum_reputation.py:126 msgid "" "This value should be smaller than that for \"insert clickable links\". This " "setting should stop link-spamming by newly registered users." -msgstr "" +msgstr "This value should be smaller than that for \"insert clickable links\". This setting should stop link-spamming by newly registered users." #: conf/minimum_reputation.py:137 msgid "Close own questions" @@ -1768,7 +1769,7 @@ msgstr "إعادة ÙØªØ Ø£Ø³Ø¦Ù„ØªÙŠ" #: conf/minimum_reputation.py:164 msgid "Edit community wiki posts" -msgstr "" +msgstr "تعديل مشاركات الويكي" #: conf/minimum_reputation.py:173 msgid "Edit posts authored by other people" @@ -1776,7 +1777,7 @@ msgstr "تØرير مشاركات الآخرين" #: conf/minimum_reputation.py:182 msgid "View offensive flags" -msgstr "" +msgstr "الإطلاع على تبليغات الإساءة" #: conf/minimum_reputation.py:191 msgid "Close questions asked by others" @@ -1784,156 +1785,156 @@ msgstr "إغلاق أسئلة الآخرين" #: conf/minimum_reputation.py:200 msgid "Remove rel=nofollow from own homepage" -msgstr "" +msgstr "إزالة وسم rel=nofollow عن صÙØتك الشخصية" #: conf/minimum_reputation.py:202 msgid "" "When a search engine crawler will see a rel=nofollow attribute on a link - " "the link will not count towards the rank of the users personal site." -msgstr "" +msgstr "عندما تقوم Ù…Øركات البØØ« بارشÙØ© الصÙØات وتجد وسم rel=nofollow على الرابط Ùانها بهذه الØالة تتجاهل الرابط تماماً. " #: conf/minimum_reputation.py:214 msgid "Make posts by email" -msgstr "" +msgstr "نشر مشاركات عبر البريد" #: conf/minimum_reputation.py:223 msgid "Trigger email notifications" -msgstr "" +msgstr "Trigger email notifications" #: conf/minimum_reputation.py:224 conf/minimum_reputation.py:234 msgid "Reduces spam" -msgstr "" +msgstr "Reduces spam" #: conf/minimum_reputation.py:233 msgid "Trigger tweets on others accounts" -msgstr "" +msgstr "Trigger tweets on others accounts" #: conf/moderation.py:19 msgid "Content moderation" -msgstr "" +msgstr "Content moderation" #: conf/moderation.py:28 msgid "Enable content moderation" -msgstr "" +msgstr "Enable content moderation" #: conf/moderation.py:38 msgid "Enable tag moderation" -msgstr "" +msgstr "Enable tag moderation" #: conf/moderation.py:40 msgid "" "If enabled, any new tags will not be applied to the questions, but emailed " "to the moderators. To use this feature, tags must be optional." -msgstr "" +msgstr "If enabled, any new tags will not be applied to the questions, but emailed to the moderators. To use this feature, tags must be optional." #: conf/question_lists.py:11 msgid "Listings of questions" -msgstr "" +msgstr "Listings of questions" #: conf/question_lists.py:20 msgid "Enable \"All Questions\" selector" -msgstr "" +msgstr "Enable \"All Questions\" selector" #: conf/question_lists.py:21 conf/question_lists.py:31 #: conf/question_lists.py:41 msgid "At least one of these selectors must be enabled" -msgstr "" +msgstr "At least one of these selectors must be enabled" #: conf/question_lists.py:30 msgid "Enable \"Unanswered Questions\" selector" -msgstr "" +msgstr "Enable \"Unanswered Questions\" selector" #: conf/question_lists.py:40 msgid "Enable \"Followed Questions\" selector" -msgstr "" +msgstr "Enable \"Followed Questions\" selector" #: conf/question_lists.py:53 conf/question_lists.py:70 msgid "All Questions" -msgstr "" +msgstr "All Questions" #: conf/question_lists.py:54 conf/question_lists.py:71 msgid "Unanswered Questions" -msgstr "" +msgstr "Unanswered Questions" #: conf/question_lists.py:55 msgid "Followed Questions" -msgstr "" +msgstr "Followed Questions" #: conf/question_lists.py:64 msgid "Default questions selector for the authenticated users" -msgstr "" +msgstr "Default questions selector for the authenticated users" #: conf/question_lists.py:80 msgid "Default questions selector for the anonymous users" -msgstr "" +msgstr "Default questions selector for the anonymous users" #: conf/reputation_changes.py:13 msgid "Karma loss and gain rules" -msgstr "" +msgstr "Karma loss and gain rules" #: conf/reputation_changes.py:23 msgid "Maximum daily reputation gain per user" -msgstr "" +msgstr "Maximum daily reputation gain per user" #: conf/reputation_changes.py:32 msgid "Gain for receiving an upvote" -msgstr "" +msgstr "Gain for receiving an upvote" #: conf/reputation_changes.py:41 msgid "Gain for the author of accepted answer" -msgstr "" +msgstr "Gain for the author of accepted answer" #: conf/reputation_changes.py:50 msgid "Gain for accepting best answer" -msgstr "" +msgstr "Gain for accepting best answer" #: conf/reputation_changes.py:59 msgid "Gain for post owner on canceled downvote" -msgstr "" +msgstr "Gain for post owner on canceled downvote" #: conf/reputation_changes.py:68 msgid "Gain for voter on canceling downvote" -msgstr "" +msgstr "Gain for voter on canceling downvote" #: conf/reputation_changes.py:78 msgid "Loss for voter for canceling of answer acceptance" -msgstr "" +msgstr "Loss for voter for canceling of answer acceptance" #: conf/reputation_changes.py:88 msgid "Loss for author whose answer was \"un-accepted\"" -msgstr "" +msgstr "Loss for author whose answer was \"un-accepted\"" #: conf/reputation_changes.py:98 msgid "Loss for giving a downvote" -msgstr "" +msgstr "Loss for giving a downvote" #: conf/reputation_changes.py:108 msgid "Loss for owner of post that was flagged offensive" -msgstr "" +msgstr "Loss for owner of post that was flagged offensive" #: conf/reputation_changes.py:118 msgid "Loss for owner of post that was downvoted" -msgstr "" +msgstr "Loss for owner of post that was downvoted" #: conf/reputation_changes.py:128 msgid "Loss for owner of post that was flagged 3 times per same revision" -msgstr "" +msgstr "Loss for owner of post that was flagged 3 times per same revision" #: conf/reputation_changes.py:138 msgid "Loss for owner of post that was flagged 5 times per same revision" -msgstr "" +msgstr "Loss for owner of post that was flagged 5 times per same revision" #: conf/reputation_changes.py:148 msgid "Loss for post owner when upvote is canceled" -msgstr "" +msgstr "Loss for post owner when upvote is canceled" #: conf/sidebar_main.py:12 msgid "Main page sidebar" -msgstr "" +msgstr "Main page sidebar" #: conf/sidebar_main.py:20 conf/sidebar_question.py:67 msgid "Custom sidebar header" -msgstr "" +msgstr "Custom sidebar header" #: conf/sidebar_main.py:23 conf/sidebar_profile.py:23 msgid "" @@ -1941,25 +1942,25 @@ msgid "" "When using this option (as well as the sidebar footer), please use the HTML " "validation service to make sure that your input is valid and works well in " "all browsers." -msgstr "" +msgstr "Use this area to enter content at the TOP of the sidebarin HTML format. When using this option (as well as the sidebar footer), please use the HTML validation service to make sure that your input is valid and works well in all browsers." #: conf/sidebar_main.py:36 conf/sidebar_main.py:111 conf/sidebar_profile.py:37 #: conf/sidebar_question.py:34 conf/sidebar_question.py:58 #: conf/sidebar_question.py:84 conf/sidebar_question.py:149 msgid "Show above only to anonymous users" -msgstr "" +msgstr "Show above only to anonymous users" #: conf/sidebar_main.py:45 msgid "Show avatar block in sidebar" -msgstr "" +msgstr "Show avatar block in sidebar" #: conf/sidebar_main.py:47 msgid "Uncheck this if you want to hide the avatar block from the sidebar " -msgstr "" +msgstr "Uncheck this if you want to hide the avatar block from the sidebar " #: conf/sidebar_main.py:58 msgid "Limit how many avatars will be displayed on the sidebar" -msgstr "" +msgstr "Limit how many avatars will be displayed on the sidebar" #: conf/sidebar_main.py:68 msgid "Show tag selector in sidebar" @@ -1969,16 +1970,16 @@ msgstr "عرض منتقي الوسوم ÙÙŠ الشريط الجانبي" msgid "" "Uncheck this if you want to hide the options for choosing interesting and " "ignored tags " -msgstr "" +msgstr "Uncheck this if you want to hide the options for choosing interesting and ignored tags " #: conf/sidebar_main.py:81 msgid "Show tag list/cloud in sidebar" -msgstr "" +msgstr "Show tag list/cloud in sidebar" #: conf/sidebar_main.py:83 msgid "" "Uncheck this if you want to hide the tag cloud or tag list from the sidebar " -msgstr "" +msgstr "Uncheck this if you want to hide the tag cloud or tag list from the sidebar " #: conf/sidebar_main.py:94 conf/sidebar_question.py:132 msgid "Custom sidebar footer" @@ -1990,40 +1991,40 @@ msgid "" " When using this option (as well as the sidebar header), please use the " "HTML validation service to make sure that your input is valid and works well" " in all browsers." -msgstr "" +msgstr "Use this area to enter content at the BOTTOM of the sidebarin HTML format. When using this option (as well as the sidebar header), please use the HTML validation service to make sure that your input is valid and works well in all browsers." #: conf/sidebar_profile.py:12 msgid "User profile sidebar" -msgstr "" +msgstr "User profile sidebar" #: conf/sidebar_profile.py:20 msgid "Custom sidebar" -msgstr "" +msgstr "Custom sidebar" #: conf/sidebar_question.py:11 msgid "Question page banners and sidebar" -msgstr "" +msgstr "Question page banners and sidebar" #: conf/sidebar_question.py:19 msgid "Top banner" -msgstr "" +msgstr "Top banner" #: conf/sidebar_question.py:22 msgid "" "When using this option, please use the HTML validation service to make sure " "that your input is valid and works well in all browsers." -msgstr "" +msgstr "When using this option, please use the HTML validation service to make sure that your input is valid and works well in all browsers." #: conf/sidebar_question.py:42 msgid "Answers banner" -msgstr "" +msgstr "Answers banner" #: conf/sidebar_question.py:45 msgid "" "This banner will show above the second answer. When using this option, " "please use the HTML validation service to make sure that your input is valid" " and works well in all browsers." -msgstr "" +msgstr "This banner will show above the second answer. When using this option, please use the HTML validation service to make sure that your input is valid and works well in all browsers." #: conf/sidebar_question.py:70 msgid "" @@ -2031,7 +2032,7 @@ msgid "" " using this option (as well as the sidebar footer), please use the HTML " "validation service to make sure that your input is valid and works well in " "all browsers." -msgstr "" +msgstr "Use this area to enter content at the TOP of the sidebarin HTML format. When using this option (as well as the sidebar footer), please use the HTML validation service to make sure that your input is valid and works well in all browsers." #: conf/sidebar_question.py:92 msgid "Show tag list in sidebar" @@ -2039,7 +2040,7 @@ msgstr "عرض قائمة الأوسمة ÙÙŠ الشريط الجانبي" #: conf/sidebar_question.py:94 msgid "Uncheck this if you want to hide the tag list from the sidebar " -msgstr "" +msgstr "Uncheck this if you want to hide the tag list from the sidebar " #: conf/sidebar_question.py:105 msgid "Show meta information in sidebar" @@ -2049,7 +2050,7 @@ msgstr "عرض المعلومات الوصÙية ÙÙŠ الشريط الجانب٠msgid "" "Uncheck this if you want to hide the meta information about the question " "(post date, views, last updated). " -msgstr "" +msgstr "Uncheck this if you want to hide the meta information about the question (post date, views, last updated). " #: conf/sidebar_question.py:119 msgid "Show related questions in sidebar" @@ -2057,15 +2058,15 @@ msgstr "عرض الأسئلة ذات الصلة ÙÙŠ الشريط الجانبي #: conf/sidebar_question.py:121 msgid "Uncheck this if you want to hide the list of related questions. " -msgstr "" +msgstr "Uncheck this if you want to hide the list of related questions. " #: conf/site_modes.py:63 msgid "Bootstrap mode" -msgstr "" +msgstr "Bootstrap mode" #: conf/site_modes.py:73 msgid "Activate a \"Large site\" mode" -msgstr "" +msgstr "Activate a \"Large site\" mode" #: conf/site_modes.py:75 msgid "" @@ -2073,19 +2074,19 @@ msgid "" "values, more suitable for the larger communities, <strong>WARNING:</strong> " "your current values for Minimum reputation, Badge Settings and Vote Rules " "will be changed after you modify this setting." -msgstr "" +msgstr "\"Large site\" mode increases reputation and certain badge thresholds, to values, more suitable for the larger communities, <strong>WARNING:</strong> your current values for Minimum reputation, Badge Settings and Vote Rules will be changed after you modify this setting." #: conf/site_settings.py:14 msgid "URLS, keywords & greetings" -msgstr "" +msgstr "URLS, keywords & greetings" #: conf/site_settings.py:23 msgid "Site title for the Q&A forum" -msgstr "" +msgstr "Site title for the Q&A forum" #: conf/site_settings.py:32 msgid "Comma separated list of Q&A site keywords" -msgstr "" +msgstr "Comma separated list of Q&A site keywords" #: conf/site_settings.py:41 msgid "Copyright message to show in the footer" @@ -2101,131 +2102,131 @@ msgstr "الاسم المختصر لمنتدى الأسئلة والأجوبة" #: conf/site_settings.py:70 msgid "Please enter url of your site" -msgstr "" +msgstr "Please enter url of your site" #: conf/site_settings.py:73 msgid "Url must start either from http or https" -msgstr "" +msgstr "Url must start either from http or https" #: conf/site_settings.py:92 msgid "Base URL for your Q&A forum, must start with http or https" -msgstr "" +msgstr "Base URL for your Q&A forum, must start with http or https" #: conf/site_settings.py:104 msgid "Check to enable greeting for anonymous user" -msgstr "" +msgstr "Check to enable greeting for anonymous user" #: conf/site_settings.py:115 msgid "Text shown in the greeting message shown to the anonymous user" -msgstr "" +msgstr "Text shown in the greeting message shown to the anonymous user" #: conf/site_settings.py:119 msgid "Use HTML to format the message " -msgstr "" +msgstr "Use HTML to format the message " #: conf/site_settings.py:128 msgid "Feedback site URL" -msgstr "" +msgstr "Feedback site URL" #: conf/site_settings.py:130 msgid "If left empty, a simple internal feedback form will be used instead" -msgstr "" +msgstr "If left empty, a simple internal feedback form will be used instead" #: conf/skin_general_settings.py:15 msgid "Skin, logos and HTML <head> parts" -msgstr "" +msgstr "Skin, logos and HTML <head> parts" #: conf/skin_general_settings.py:23 msgid "Q&A site logo" -msgstr "" +msgstr "Q&A site logo" #: conf/skin_general_settings.py:25 msgid "To change the logo, select new file, then submit this whole form." -msgstr "" +msgstr "To change the logo, select new file, then submit this whole form." #: conf/skin_general_settings.py:34 msgid "English" -msgstr "" +msgstr "إنجليزي" #: conf/skin_general_settings.py:35 msgid "Spanish" -msgstr "" +msgstr "إسباني" #: conf/skin_general_settings.py:36 msgid "Catalan" -msgstr "" +msgstr "Catalan" #: conf/skin_general_settings.py:37 msgid "German" -msgstr "" +msgstr "ألماني" #: conf/skin_general_settings.py:38 msgid "Greek" -msgstr "" +msgstr "يوناني" #: conf/skin_general_settings.py:39 msgid "Finnish" -msgstr "" +msgstr "Finnish" #: conf/skin_general_settings.py:40 msgid "French" -msgstr "" +msgstr "Ùرنسي" #: conf/skin_general_settings.py:41 msgid "Hindi" -msgstr "" +msgstr "هندي" #: conf/skin_general_settings.py:42 msgid "Hungarian" -msgstr "" +msgstr "هنجاري" #: conf/skin_general_settings.py:43 msgid "Italian" -msgstr "" +msgstr "إيطالي" #: conf/skin_general_settings.py:44 msgid "Japanese" -msgstr "" +msgstr "ياباني" #: conf/skin_general_settings.py:45 msgid "Korean" -msgstr "" +msgstr "كوري" #: conf/skin_general_settings.py:46 msgid "Portuguese" -msgstr "" +msgstr "برتغالي" #: conf/skin_general_settings.py:47 msgid "Brazilian Portuguese" -msgstr "" +msgstr "برازيلي برتغالي" #: conf/skin_general_settings.py:48 msgid "Romanian" -msgstr "" +msgstr "روماني" #: conf/skin_general_settings.py:49 msgid "Russian" -msgstr "" +msgstr "روسي" #: conf/skin_general_settings.py:50 msgid "Serbian" -msgstr "" +msgstr "صربي" #: conf/skin_general_settings.py:51 msgid "Turkish" -msgstr "" +msgstr "تركي" #: conf/skin_general_settings.py:52 msgid "Vietnamese" -msgstr "" +msgstr "Ùيتنامي" #: conf/skin_general_settings.py:53 msgid "Chinese" -msgstr "" +msgstr "صيني" #: conf/skin_general_settings.py:54 msgid "Chinese (Taiwan)" -msgstr "" +msgstr "صيني (تايوان)" #: conf/skin_general_settings.py:73 msgid "Show logo" @@ -2235,7 +2236,7 @@ msgstr "عرض الشعار" msgid "" "Check if you want to show logo in the forum header or uncheck in the case " "you do not want the logo to appear in the default location" -msgstr "" +msgstr "Check if you want to show logo in the forum header or uncheck in the case you do not want the logo to appear in the default location" #: conf/skin_general_settings.py:87 msgid "Site favicon" @@ -2247,28 +2248,28 @@ msgid "" "A small 16x16 or 32x32 pixel icon image used to distinguish your site in the" " browser user interface. Please find more information about favicon at <a " "href=\"%(favicon_info_url)s\">this page</a>." -msgstr "" +msgstr "A small 16x16 or 32x32 pixel icon image used to distinguish your site in the browser user interface. Please find more information about favicon at <a href=\"%(favicon_info_url)s\">this page</a>." #: conf/skin_general_settings.py:105 msgid "Password login button" -msgstr "" +msgstr "Password login button" #: conf/skin_general_settings.py:107 msgid "" "An 88x38 pixel image that is used on the login screen for the password login" " button." -msgstr "" +msgstr "An 88x38 pixel image that is used on the login screen for the password login button." #: conf/skin_general_settings.py:120 msgid "Show all UI functions to all users" -msgstr "" +msgstr "Show all UI functions to all users" #: conf/skin_general_settings.py:122 msgid "" "If checked, all forum functions will be shown to users, regardless of their " "reputation. However to use those functions, moderation rules, reputation and" " other limits will still apply." -msgstr "" +msgstr "If checked, all forum functions will be shown to users, regardless of their reputation. However to use those functions, moderation rules, reputation and other limits will still apply." #: conf/skin_general_settings.py:137 msgid "Select skin" @@ -2276,11 +2277,11 @@ msgstr "اختيار السمة" #: conf/skin_general_settings.py:148 msgid "Customize HTML <HEAD>" -msgstr "" +msgstr "Customize HTML <HEAD>" #: conf/skin_general_settings.py:157 msgid "Custom portion of the HTML <HEAD>" -msgstr "" +msgstr "Custom portion of the HTML <HEAD>" #: conf/skin_general_settings.py:159 msgid "" @@ -2292,11 +2293,11 @@ msgid "" "of the pages. Instead, it will be more efficient to place links to the " "javascript files into the footer. <strong>Note:</strong> if you do use this " "setting, please test the site with the W3C HTML validator service." -msgstr "" +msgstr "<strong>To use this option</strong>, check \"Customize HTML <HEAD>\" above. Contents of this box will be inserted into the <HEAD> portion of the HTML output, where elements such as <script>, <link>, <meta> may be added. Please, keep in mind that adding external javascript to the <HEAD> is not recommended because it slows loading of the pages. Instead, it will be more efficient to place links to the javascript files into the footer. <strong>Note:</strong> if you do use this setting, please test the site with the W3C HTML validator service." #: conf/skin_general_settings.py:181 msgid "Custom header additions" -msgstr "" +msgstr "Custom header additions" #: conf/skin_general_settings.py:183 msgid "" @@ -2305,21 +2306,21 @@ msgid "" "headerin the HTML format. When customizing the site header (as well as " "footer and the HTML <HEAD>), use the HTML validation service to make " "sure that your input is valid and works well in all browsers." -msgstr "" +msgstr "Header is the bar at the top of the content that contains user info and site links, and is common to all pages. Use this area to enter contents of the headerin the HTML format. When customizing the site header (as well as footer and the HTML <HEAD>), use the HTML validation service to make sure that your input is valid and works well in all browsers." #: conf/skin_general_settings.py:198 msgid "Site footer mode" -msgstr "" +msgstr "Site footer mode" #: conf/skin_general_settings.py:200 msgid "" "Footer is the bottom portion of the content, which is common to all pages. " "You can disable, customize, or use the default footer." -msgstr "" +msgstr "Footer is the bottom portion of the content, which is common to all pages. You can disable, customize, or use the default footer." #: conf/skin_general_settings.py:217 msgid "Custom footer (HTML format)" -msgstr "" +msgstr "Custom footer (HTML format)" #: conf/skin_general_settings.py:219 msgid "" @@ -2328,21 +2329,21 @@ msgid "" "footer in the HTML format. When customizing the site footer (as well as the " "header and HTML <HEAD>), use the HTML validation service to make sure " "that your input is valid and works well in all browsers." -msgstr "" +msgstr "<strong>To enable this function</strong>, please select option 'customize' in the \"Site footer mode\" above. Use this area to enter contents of the footer in the HTML format. When customizing the site footer (as well as the header and HTML <HEAD>), use the HTML validation service to make sure that your input is valid and works well in all browsers." #: conf/skin_general_settings.py:234 msgid "Apply custom style sheet (CSS)" -msgstr "" +msgstr "Apply custom style sheet (CSS)" #: conf/skin_general_settings.py:236 msgid "" "Check if you want to change appearance of your form by adding custom style " "sheet rules (please see the next item)" -msgstr "" +msgstr "Check if you want to change appearance of your form by adding custom style sheet rules (please see the next item)" #: conf/skin_general_settings.py:248 msgid "Custom style sheet (CSS)" -msgstr "" +msgstr "Custom style sheet (CSS)" #: conf/skin_general_settings.py:250 msgid "" @@ -2351,7 +2352,7 @@ msgid "" "default style sheet rules. The custom style sheet will be served dynamically" " at url \"<forum url>/custom.css\", where the \"<forum url> part" " depends (default is empty string) on the url configuration in your urls.py." -msgstr "" +msgstr "<strong>To use this function</strong>, check \"Apply custom style sheet\" option above. The CSS rules added in this window will be applied after the default style sheet rules. The custom style sheet will be served dynamically at url \"<forum url>/custom.css\", where the \"<forum url> part depends (default is empty string) on the url configuration in your urls.py." #: conf/skin_general_settings.py:266 msgid "Add custom javascript" @@ -2359,11 +2360,11 @@ msgstr "إضاÙØ© javascript مخصص" #: conf/skin_general_settings.py:269 msgid "Check to enable javascript that you can enter in the next field" -msgstr "" +msgstr "Check to enable javascript that you can enter in the next field" #: conf/skin_general_settings.py:279 msgid "Custom javascript" -msgstr "" +msgstr "Custom javascript" #: conf/skin_general_settings.py:281 msgid "" @@ -2374,156 +2375,156 @@ msgid "" "that the behavior may not be consistent across different browsers " "(<strong>to enable your custom code</strong>, check \"Add custom " "javascript\" option above)." -msgstr "" +msgstr "Type or paste plain javascript that you would like to run on your site. Link to the script will be inserted at the bottom of the HTML output and will be served at the url \"<forum url>/custom.js\". Please, bear in mind that your javascript code may break other functionalities of the site and that the behavior may not be consistent across different browsers (<strong>to enable your custom code</strong>, check \"Add custom javascript\" option above)." #: conf/skin_general_settings.py:299 msgid "Skin media revision number" -msgstr "" +msgstr "Skin media revision number" #: conf/skin_general_settings.py:301 msgid "Will be set automatically but you can modify it if necessary." -msgstr "" +msgstr "Will be set automatically but you can modify it if necessary." #: conf/skin_general_settings.py:312 msgid "Hash to update the media revision number automatically." -msgstr "" +msgstr "Hash to update the media revision number automatically." #: conf/skin_general_settings.py:316 msgid "Will be set automatically, it is not necesary to modify manually." -msgstr "" +msgstr "Will be set automatically, it is not necesary to modify manually." #: conf/social_sharing.py:11 msgid "Content sharing" -msgstr "" +msgstr "Content sharing" #: conf/social_sharing.py:20 msgid "Check to enable RSS feeds" -msgstr "" +msgstr "Check to enable RSS feeds" #: conf/social_sharing.py:29 msgid "Hashtag or suffix to sharing messages" -msgstr "" +msgstr "Hashtag or suffix to sharing messages" #: conf/social_sharing.py:38 msgid "Check to enable sharing of questions on Twitter" -msgstr "" +msgstr "Check to enable sharing of questions on Twitter" #: conf/social_sharing.py:40 msgid "" "Important - to actually start sharing on twitter, it is required to set up " "Twitter consumer key and secret in the \"keys to external services\" " "section." -msgstr "" +msgstr "Important - to actually start sharing on twitter, it is required to set up Twitter consumer key and secret in the \"keys to external services\" section." #: conf/social_sharing.py:52 msgid "Check to enable sharing of questions on Facebook" -msgstr "" +msgstr "Check to enable sharing of questions on Facebook" #: conf/social_sharing.py:61 msgid "Check to enable sharing of questions on LinkedIn" -msgstr "" +msgstr "Check to enable sharing of questions on LinkedIn" #: conf/social_sharing.py:70 msgid "Check to enable sharing of questions on Identi.ca" -msgstr "" +msgstr "Check to enable sharing of questions on Identi.ca" #: conf/social_sharing.py:79 msgid "Check to enable sharing of questions on Google+" -msgstr "" +msgstr "Check to enable sharing of questions on Google+" #: conf/spam_and_moderation.py:10 msgid "Akismet spam protection" -msgstr "" +msgstr "Akismet spam protection" #: conf/spam_and_moderation.py:18 msgid "Enable Akismet spam detection(keys below are required)" -msgstr "" +msgstr "Enable Akismet spam detection(keys below are required)" #: conf/spam_and_moderation.py:21 #, python-format msgid "To get an Akismet key please visit <a href=\"%(url)s\">Akismet site</a>" -msgstr "" +msgstr "To get an Akismet key please visit <a href=\"%(url)s\">Akismet site</a>" #: conf/spam_and_moderation.py:31 msgid "Akismet key for spam detection" -msgstr "" +msgstr "Akismet key for spam detection" #: conf/super_groups.py:5 msgid "Reputation, Badges, Votes & Flags" -msgstr "" +msgstr "Reputation, Badges, Votes & Flags" #: conf/super_groups.py:6 msgid "Static Content, URLS & UI" -msgstr "" +msgstr "Static Content, URLS & UI" #: conf/super_groups.py:7 msgid "Data rules & Formatting" -msgstr "" +msgstr "Data rules & Formatting" #: conf/super_groups.py:8 msgid "External Services" -msgstr "" +msgstr "External Services" #: conf/super_groups.py:9 msgid "Login, Users & Communication" -msgstr "" +msgstr "Login, Users & Communication" #: conf/user_settings.py:14 msgid "User settings" -msgstr "إعدادات المستخدم" +msgstr "User settings" #: conf/user_settings.py:23 msgid "On-screen greeting shown to the new users" -msgstr "" +msgstr "On-screen greeting shown to the new users" #: conf/user_settings.py:32 msgid "Allow anonymous users send feedback" -msgstr "" +msgstr "Allow anonymous users send feedback" #: conf/user_settings.py:41 msgid "Allow editing user screen name" -msgstr "" +msgstr "Allow editing user screen name" #: conf/user_settings.py:50 msgid "Auto-fill user name, email, etc on registration" -msgstr "" +msgstr "Auto-fill user name, email, etc on registration" #: conf/user_settings.py:51 msgid "Implemented only for LDAP logins at this point" -msgstr "" +msgstr "Implemented only for LDAP logins at this point" #: conf/user_settings.py:60 msgid "Allow users change own email addresses" -msgstr "" +msgstr "Allow users change own email addresses" #: conf/user_settings.py:69 msgid "Allow email address in user name" -msgstr "" +msgstr "Allow email address in user name" #: conf/user_settings.py:78 msgid "Allow account recovery by email" -msgstr "" +msgstr "Allow account recovery by email" #: conf/user_settings.py:87 msgid "Allow adding and removing login methods" -msgstr "" +msgstr "Allow adding and removing login methods" #: conf/user_settings.py:97 msgid "Minimum allowed length for screen name" -msgstr "" +msgstr "Minimum allowed length for screen name" #: conf/user_settings.py:105 msgid "Default avatar for users" -msgstr "" +msgstr "Default avatar for users" #: conf/user_settings.py:107 msgid "" "To change the avatar image, select new file, then submit this whole form." -msgstr "" +msgstr "To change the avatar image, select new file, then submit this whole form." #: conf/user_settings.py:120 msgid "Use automatic avatars from gravatar.com" -msgstr "" +msgstr "Use automatic avatars from gravatar.com" #: conf/user_settings.py:122 msgid "" @@ -2532,72 +2533,72 @@ msgid "" "effective. You will have to enable uploaded avatars as well. For more " "information, please visit <a href=\"http://askbot.org/doc/optional-" "modules.html#uploaded-avatars\">this page</a>." -msgstr "" +msgstr "Check this option if you want to allow the use of gravatar.com for avatars. Please, note that this feature might take about 10 minutes to become fully effective. You will have to enable uploaded avatars as well. For more information, please visit <a href=\"http://askbot.org/doc/optional-modules.html#uploaded-avatars\">this page</a>." #: conf/user_settings.py:134 msgid "Default Gravatar icon type" -msgstr "" +msgstr "Default Gravatar icon type" #: conf/user_settings.py:136 msgid "" "This option allows you to set the default avatar type for email addresses " "without associated gravatar images. For more information, please visit <a " "href=\"http://en.gravatar.com/site/implement/images/\">this page</a>." -msgstr "" +msgstr "This option allows you to set the default avatar type for email addresses without associated gravatar images. For more information, please visit <a href=\"http://en.gravatar.com/site/implement/images/\">this page</a>." #: conf/user_settings.py:146 msgid "Name for the Anonymous user" -msgstr "" +msgstr "Name for the Anonymous user" #: conf/vote_rules.py:14 msgid "Vote and flag limits" -msgstr "" +msgstr "Vote and flag limits" #: conf/vote_rules.py:24 msgid "Number of votes a user can cast per day" -msgstr "" +msgstr "Number of votes a user can cast per day" #: conf/vote_rules.py:33 msgid "Maximum number of flags per user per day" -msgstr "" +msgstr "Maximum number of flags per user per day" #: conf/vote_rules.py:42 msgid "Threshold for warning about remaining daily votes" -msgstr "" +msgstr "Threshold for warning about remaining daily votes" #: conf/vote_rules.py:51 msgid "Number of days to allow canceling votes" -msgstr "" +msgstr "Number of days to allow canceling votes" #: conf/vote_rules.py:60 msgid "Number of days required before answering own question" -msgstr "" +msgstr "Number of days required before answering own question" #: conf/vote_rules.py:69 msgid "Number of flags required to automatically hide posts" -msgstr "" +msgstr "Number of flags required to automatically hide posts" #: conf/vote_rules.py:78 msgid "Number of flags required to automatically delete posts" -msgstr "" +msgstr "Number of flags required to automatically delete posts" #: conf/vote_rules.py:87 msgid "" "Minimum days to accept an answer, if it has not been accepted by the " "question poster" -msgstr "" +msgstr "Minimum days to accept an answer, if it has not been accepted by the question poster" #: const/__init__.py:11 msgid "duplicate question" -msgstr "" +msgstr "سؤال مكرر" #: const/__init__.py:12 msgid "question is off-topic or not relevant" -msgstr "" +msgstr "السؤال خارج موضوع الموقع او ليس ذو صلة" #: const/__init__.py:13 msgid "too subjective and argumentative" -msgstr "" +msgstr "شخصي جداً وجدلي" #: const/__init__.py:14 msgid "not a real question" @@ -2621,23 +2622,23 @@ msgstr "دعاية أو مادة غير مرغوب Ùيها" #: const/__init__.py:19 msgid "too localized" -msgstr "" +msgstr "لهجة Ù…Øلية غير Ù…Ùهومة" #: const/__init__.py:29 msgid "disable sharing" -msgstr "" +msgstr "تعطيل المشاركة" #: const/__init__.py:30 #: templates/user_profile/twitter_sharing_controls.html:13 #: templates/user_profile/twitter_sharing_controls.html:17 msgid "my posts" -msgstr "" +msgstr "مشاركاتي" #: const/__init__.py:31 #: templates/user_profile/twitter_sharing_controls.html:14 #: templates/user_profile/twitter_sharing_controls.html:16 msgid "all posts" -msgstr "" +msgstr "كل المشاركات" #: const/__init__.py:54 templates/question/answer_tab_bar.html:18 msgid "newest" @@ -2658,11 +2659,11 @@ msgstr "غير نشط" #: const/__init__.py:58 msgid "hottest" -msgstr "أكثر إثارة" +msgstr "الأكثر Ùعالية" #: const/__init__.py:59 msgid "coldest" -msgstr "أكثر برودة" +msgstr "الأقل Ùعالية" #: const/__init__.py:60 templates/question/answer_tab_bar.html:21 msgid "most voted" @@ -2678,7 +2679,7 @@ msgstr "الملاءمة" #: const/__init__.py:74 msgid "Never" -msgstr "" +msgstr "أبداً" #: const/__init__.py:75 msgid "When new post is published" @@ -2705,7 +2706,7 @@ msgstr "غير مجاب" #: const/__init__.py:124 msgid "followed" -msgstr "" +msgstr "أسئلة Ù…Ùتابعة" #: const/__init__.py:129 msgid "list" @@ -2749,7 +2750,7 @@ msgstr "Øرر إجابة" #: const/__init__.py:201 msgid "received badge" -msgstr "تلقي شارة" +msgstr "Øصل على وسام" #: const/__init__.py:202 msgid "marked best answer" @@ -2805,7 +2806,7 @@ msgstr "" #: const/__init__.py:220 msgid "reminder about accepting the best answer sent" -msgstr "" +msgstr "تم إرسال تذكير لقبول Ø£Ùضل إجابة للسؤال" #: const/__init__.py:222 msgid "mentioned in the post" @@ -2813,19 +2814,19 @@ msgstr "ذكر ÙÙŠ المشاركة" #: const/__init__.py:225 msgid "created tag description" -msgstr "" +msgstr "كتب وص٠الموضوع" #: const/__init__.py:229 msgid "updated tag description" -msgstr "" +msgstr "Øدث وص٠الموضوع" #: const/__init__.py:231 msgid "made a new post" -msgstr "" +msgstr "نشر مشاركة جديدة" #: const/__init__.py:234 msgid "made an edit" -msgstr "" +msgstr "عدل" #: const/__init__.py:238 msgid "created post reject reason" @@ -2857,28 +2858,28 @@ msgstr "النسخة الأولى" #: const/__init__.py:310 msgid "retagged" -msgstr "" +msgstr "تم إعادة تعيين المواضيع" #: const/__init__.py:311 msgid "[private]" -msgstr "" +msgstr "[خاص]" #: const/__init__.py:320 msgid "show all tags" -msgstr "" +msgstr "جميع المواضيع" #: const/__init__.py:321 const/__init__.py:330 const/__init__.py:336 #: const/__init__.py:342 msgid "exclude ignored tags" -msgstr "" +msgstr "إخÙاء المواضيع المستبعدة" #: const/__init__.py:322 const/__init__.py:331 const/__init__.py:343 msgid "only interesting tags" -msgstr "" +msgstr "Ùقط المواضيع المهتم بها" #: const/__init__.py:326 const/__init__.py:337 const/__init__.py:344 msgid "only subscribed tags" -msgstr "" +msgstr "Ùقط المواضيع المشترك بها" #: const/__init__.py:329 const/__init__.py:335 const/__init__.py:341 msgid "email for all tags" @@ -2902,23 +2903,23 @@ msgstr "لا بريد" #: const/__init__.py:358 msgid "identicon" -msgstr "" +msgstr "identicon" #: const/__init__.py:359 msgid "mystery-man" -msgstr "" +msgstr "mystery-man" #: const/__init__.py:360 msgid "monsterid" -msgstr "" +msgstr "monsterid" #: const/__init__.py:361 msgid "wavatar" -msgstr "" +msgstr "wavatar" #: const/__init__.py:362 msgid "retro" -msgstr "" +msgstr "retro" #: const/__init__.py:409 templates/badges.html:33 msgid "gold" @@ -2938,43 +2939,43 @@ msgstr "لا شئ" #: const/__init__.py:424 msgid "Gravatar" -msgstr "" +msgstr "Gravatar" #: const/__init__.py:425 msgid "Uploaded Avatar" -msgstr "" +msgstr "رÙع صورة رمزية" #: const/__init__.py:429 msgid "date descendant" -msgstr "" +msgstr "التاريخ المنØدر" #: const/__init__.py:430 msgid "date ascendant" -msgstr "" +msgstr "التاريخ الصاعد" #: const/__init__.py:431 msgid "activity descendant" -msgstr "" +msgstr "الأنشطة المنØدرة" #: const/__init__.py:432 msgid "activity ascendant" -msgstr "" +msgstr "الأنشطة الصاعدة" #: const/__init__.py:433 msgid "answers descendant" -msgstr "" +msgstr "الأجوبة المنØدرة" #: const/__init__.py:434 msgid "answers ascendant" -msgstr "" +msgstr "الأجوبة الصاعدة" #: const/__init__.py:435 msgid "votes descendant" -msgstr "" +msgstr "الأصوات المنØدرة" #: const/__init__.py:436 msgid "votes ascendant" -msgstr "" +msgstr "الأصوات الصاعدة" #: const/message_keys.py:21 msgid "most relevant questions" @@ -2986,7 +2987,7 @@ msgstr "انقر لرؤية الأسئلة الأكثر ارتباطاً" #: const/message_keys.py:23 msgid "by relevance" -msgstr "بالإنتماء" +msgstr "ذات الصلة" #: const/message_keys.py:24 msgid "click to see the oldest questions" @@ -2994,7 +2995,7 @@ msgstr "انقر لرؤية أقدم الأسئلة" #: const/message_keys.py:25 msgid "by date" -msgstr "بالتاريخ" +msgstr "التاريخ" #: const/message_keys.py:26 msgid "click to see the newest questions" @@ -3002,15 +3003,15 @@ msgstr "انقر لرؤية Ø£Øدث الأسئلة" #: const/message_keys.py:27 msgid "click to see the least recently updated questions" -msgstr "" +msgstr "أضغط لمشاهدة أقل الأسئلة تØديثاً" #: const/message_keys.py:28 msgid "by activity" -msgstr "بالنشاط" +msgstr "النشاط" #: const/message_keys.py:29 msgid "click to see the most recently updated questions" -msgstr "" +msgstr "أضغط لمشاهدة Ø£Øدث الأسئلة تØديثاً" #: const/message_keys.py:30 msgid "click to see the least answered questions" @@ -3018,7 +3019,7 @@ msgstr "انقر لرؤية الأسئلة الأقل إجابات" #: const/message_keys.py:31 msgid "by answers" -msgstr "بالإجابات" +msgstr "الأجوبة" #: const/message_keys.py:32 msgid "click to see the most answered questions" @@ -3026,15 +3027,15 @@ msgstr "انقر لرؤية الأسئلة الأكثر إجابات" #: const/message_keys.py:33 msgid "click to see least voted questions" -msgstr "" +msgstr "أضغط لمشاهدة أقل أسئلة Øاصلة على أصوات" #: const/message_keys.py:34 msgid "by votes" -msgstr "بالأصوات" +msgstr "الأصوات" #: const/message_keys.py:35 msgid "click to see most voted questions" -msgstr "" +msgstr "أضغط لمشاهدة أكثر الأسئلة Øاصلة على أصوات" #: const/message_keys.py:36 models/tag.py:311 msgid "interesting" @@ -3078,12 +3079,12 @@ msgstr "" #: deps/django_authopenid/forms.py:112 deps/django_authopenid/views.py:206 msgid "i-names are not supported" -msgstr "" +msgstr "خدمة i-names غير مدعمة" #: deps/django_authopenid/forms.py:236 #, python-format msgid "Please enter your %(username_token)s" -msgstr "" +msgstr "يرجى إدخال %(username_token)s" #: deps/django_authopenid/forms.py:262 msgid "Please, enter your user name" @@ -3104,7 +3105,7 @@ msgstr "كلمات السر لم تتطابق" #: deps/django_authopenid/forms.py:300 #, python-format msgid "Please choose password > %(len)s characters" -msgstr "" +msgstr "يرجى إختيار كلمة مرور مكونة من %(len)s Øر٠ورقم" #: deps/django_authopenid/forms.py:338 msgid "Current password" @@ -3114,7 +3115,7 @@ msgstr "كلمة السر الØالية" msgid "" "Old password is incorrect. Please enter the correct " "password." -msgstr "" +msgstr "كلمة المرور القديمة غير صØÙŠØØ©. يرجى إدخال كلمة المرور الصØÙŠØØ©." #: deps/django_authopenid/forms.py:399 msgid "Sorry, we don't have this email address in the database" @@ -3126,7 +3127,7 @@ msgstr "اسم المستخدم (<i>مطلوب</i>)" #: deps/django_authopenid/forms.py:455 msgid "sorry, there is no such user name" -msgstr "عÙواً، لا يوجد اسم الدخول هذا" +msgstr "لا يوجد أسم مستخدم!" #: deps/django_authopenid/urls.py:14 deps/django_authopenid/urls.py:20 #: deps/django_authopenid/urls.py:23 setup_templates/settings.py:229 @@ -3135,7 +3136,7 @@ msgstr "signin/" #: deps/django_authopenid/urls.py:15 msgid "widget/signin/" -msgstr "" +msgstr "widget/signin/" #: deps/django_authopenid/urls.py:18 msgid "signout/" @@ -3143,37 +3144,37 @@ msgstr "signout/" #: deps/django_authopenid/urls.py:23 msgid "complete-oauth/" -msgstr "" +msgstr "complete-oauth/" #: deps/django_authopenid/urls.py:32 msgid "register/" -msgstr "" +msgstr "register/" #: deps/django_authopenid/urls.py:34 msgid "signup/" -msgstr "" +msgstr "signup/" #: deps/django_authopenid/urls.py:38 msgid "logout/" -msgstr "" +msgstr "logout/" #: deps/django_authopenid/urls.py:43 msgid "recover/" -msgstr "" +msgstr "recover/" #: deps/django_authopenid/urls.py:45 msgid "verify-email/" -msgstr "" +msgstr "verify-email/" #: deps/django_authopenid/util.py:379 #, python-format msgid "%(site)s user name and password" -msgstr "" +msgstr "تسجيل دخول بعضوية %(site)s" #: deps/django_authopenid/util.py:385 templates/authopenid/signin.html:117 #: templates/authopenid/widget_signin.html:120 msgid "Create a password-protected account" -msgstr "" +msgstr "تسجيل عضوية جديدة" #: deps/django_authopenid/util.py:386 msgid "Change your password" @@ -3185,77 +3186,77 @@ msgstr "الدخول بØساب Yahoo" #: deps/django_authopenid/util.py:493 msgid "AOL screen name" -msgstr "" +msgstr "AOL screen name" #: deps/django_authopenid/util.py:502 msgid "Sign in with LaunchPad" -msgstr "" +msgstr "Sign in with LaunchPad" #: deps/django_authopenid/util.py:509 msgid "OpenID url" -msgstr "" +msgstr "OpenID url" #: deps/django_authopenid/util.py:538 msgid "Flickr user name" -msgstr "" +msgstr "Flickr user name" #: deps/django_authopenid/util.py:546 msgid "Technorati user name" -msgstr "" +msgstr "Technorati user name" #: deps/django_authopenid/util.py:554 msgid "WordPress blog name" -msgstr "" +msgstr "WordPress blog name" #: deps/django_authopenid/util.py:562 msgid "Blogger blog name" -msgstr "" +msgstr "Blogger blog name" #: deps/django_authopenid/util.py:570 msgid "LiveJournal blog name" -msgstr "" +msgstr "LiveJournal blog name" #: deps/django_authopenid/util.py:578 msgid "ClaimID user name" -msgstr "" +msgstr "ClaimID user name" #: deps/django_authopenid/util.py:586 msgid "Vidoop user name" -msgstr "" +msgstr "Vidoop user name" #: deps/django_authopenid/util.py:594 msgid "Verisign user name" -msgstr "" +msgstr "Verisign user name" #: deps/django_authopenid/util.py:629 #, python-format msgid "Change your %(provider)s password" -msgstr "" +msgstr "تغيير كلمة مرور %(provider)s " #: deps/django_authopenid/util.py:633 #, python-format msgid "Click to see if your %(provider)s signin still works for %(site_name)s" -msgstr "" +msgstr "أضغط لمعرÙØ© أن مازال %(provider)s يعمل ويمكنك تسجيل الدخول من خلاله ÙÙŠ %(site_name)s" #: deps/django_authopenid/util.py:642 #, python-format msgid "Create password for %(provider)s" -msgstr "" +msgstr "إنشاء كلمة مرور لـ %(provider)s" #: deps/django_authopenid/util.py:646 #, python-format msgid "Connect your %(provider)s account to %(site_name)s" -msgstr "" +msgstr "ربط %(provider)s بØسابك ÙÙŠ %(site_name)s" #: deps/django_authopenid/util.py:655 #, python-format msgid "Signin with %(provider)s user name and password" -msgstr "" +msgstr "تسجيل الدخول بأسم المستخدم وكلمة المرور بواسطة %(provider)s" #: deps/django_authopenid/util.py:662 #, python-format msgid "Sign in with your %(provider)s account" -msgstr "" +msgstr "سجيل دخول بØسابك ÙÙŠ %(provider)s" #: deps/django_authopenid/views.py:213 #, python-format @@ -3270,7 +3271,7 @@ msgstr "" #: deps/django_authopenid/views.py:520 msgid "Your new password saved" -msgstr "" +msgstr "تم ØÙظ كلمة المرور الجديدة" #: deps/django_authopenid/views.py:568 deps/django_authopenid/views.py:583 #, python-format @@ -3285,11 +3286,11 @@ msgstr "" #: deps/django_authopenid/views.py:717 msgid "Please click any of the icons below to sign in" -msgstr "" +msgstr "يمكنك تسجيل الدخول بØسابك ÙÙŠ المواقع الإجتماعية" #: deps/django_authopenid/views.py:719 msgid "Account recovery email sent" -msgstr "" +msgstr "تم إرسال بريد إستعادة الØساب" #: deps/django_authopenid/views.py:722 msgid "Please add one or more login methods." @@ -3297,7 +3298,7 @@ msgstr "" #: deps/django_authopenid/views.py:724 msgid "If you wish, please add, remove or re-validate your login methods" -msgstr "" +msgstr "إدارة وسائل الدخول للØساب" #: deps/django_authopenid/views.py:726 msgid "Please wait a second! Your account is recovered, but ..." @@ -3305,12 +3306,12 @@ msgstr "" #: deps/django_authopenid/views.py:728 msgid "Sorry, this account recovery key has expired or is invalid" -msgstr "" +msgstr "عذراً، Ù…ÙØªØ§Ø Ø¥Ø³ØªØ¹Ø§Ø¯Ø© الØساب هذا قد أنتهى ÙˆØ§ØµØ¨Ø ØºÙŠØ± صالØ" #: deps/django_authopenid/views.py:801 #, python-format msgid "Login method %(provider_name)s does not exist" -msgstr "" +msgstr "إمكانية الدخول عبر %(provider_name)s غير متاØØ©" #: deps/django_authopenid/views.py:807 msgid "Oops, sorry - there was some error - please try again" @@ -3336,15 +3337,15 @@ msgstr "" #: deps/django_authopenid/views.py:1257 #, python-format msgid "Recover your %(site)s account" -msgstr "" +msgstr "إستعادة Øساب ÙÙŠ %(site)s" #: deps/django_authopenid/views.py:1292 msgid "Please check your email and visit the enclosed link." -msgstr "" +msgstr "راجع بريدك، وأضغط على الرابط المرسل بالبريد." #: deps/group_messaging/models.py:356 msgid "Re: " -msgstr "" +msgstr "رد:" #: deps/livesettings/models.py:107 deps/livesettings/models.py:153 msgid "Site" @@ -3352,37 +3353,37 @@ msgstr "الموقع" #: deps/livesettings/values.py:72 msgid "Main" -msgstr "الرئيسي" +msgstr "Main" #: deps/livesettings/values.py:133 msgid "Base Settings" -msgstr "" +msgstr "Base Settings" #: deps/livesettings/values.py:244 msgid "Default value: \"\"" -msgstr "" +msgstr "Default value: \"\"" #: deps/livesettings/values.py:251 msgid "Default value: " -msgstr "" +msgstr "Default value: " #: deps/livesettings/values.py:254 #, python-format msgid "Default value: %s" -msgstr "" +msgstr "Default value: %s" #: deps/livesettings/values.py:641 #, python-format msgid "Allowed image file types are %(types)s" -msgstr "" +msgstr "صيغ الصور Ø§Ù„Ù…Ø³Ù…ÙˆØ Ø¨Ù‡Ø§: %(types)s" #: importers/stackexchange/management/commands/load_stackexchange.py:150 msgid "Congratulations, you are now an Administrator" -msgstr "" +msgstr "تهانياً، أنت الأن مشر٠عام" #: mail/__init__.py:183 msgid "<p>To ask by email, please:</p>" -msgstr "" +msgstr "<p>Ù„Ø·Ø±Ø Ø§Ù„Ø³Ø¤Ø§Ù„ عبر البريد:</p>" #: mail/__init__.py:185 msgid "<li>Type title in the subject line</li>" @@ -3440,7 +3441,7 @@ msgstr "" #: mail/lamson_handlers.py:251 #, python-format msgid "Re: Welcome to %(site_name)s" -msgstr "" +msgstr "رد: مرØباً ÙÙŠ %(site_name)s" #: mail/lamson_handlers.py:258 msgid "Please reply to the welcome email without editing it" @@ -3458,11 +3459,11 @@ msgstr "" #: management/commands/send_accept_answer_reminders.py:66 msgid "Please accept the best answer for this question:" -msgstr "" +msgstr "Ùضلاً أقبل Ø£Ùضل إجابة للسؤال:" #: management/commands/send_accept_answer_reminders.py:68 msgid "Please accept the best answer for these questions:" -msgstr "" +msgstr "Ùضلاً إختار Ø£Ùضل إجابة لهذه الأسئلة:" #: management/commands/send_email_alerts.py:434 #, python-format @@ -3477,7 +3478,7 @@ msgstr[5] "" #: management/commands/send_email_alerts.py:455 msgid "new question" -msgstr "" +msgstr "سؤال جديد" #: management/commands/send_unanswered_question_reminders.py:67 #, python-format @@ -3493,11 +3494,11 @@ msgstr[5] "" #: middleware/forum_mode.py:63 #, python-format msgid "Please log in to use %s" -msgstr "" +msgstr "سجل دخول لإستخدام %s" #: models/__init__.py:569 models/__init__.py:1388 views/writers.py:226 msgid "Sorry, but you have only read access" -msgstr "" +msgstr "عذراً، لديك صلاØية القراءة Ùقط" #: models/__init__.py:573 msgid "Sorry, this operation is not allowed" @@ -3507,76 +3508,76 @@ msgstr "" msgid "" "Sorry, you cannot accept or unaccept best answers because your account is " "blocked" -msgstr "" +msgstr "عذراً، لا يمكنك قبول او رÙض الإجابات لأن Øسابك Ù…Øجوب" #: models/__init__.py:627 msgid "" "Sorry, you cannot accept or unaccept best answers because your account is " "suspended" -msgstr "" +msgstr "عذراً، لا يمكنك قبول او رÙض الإجابات لأن Øسابك Ù…Ùصول" #: models/__init__.py:641 #, python-format msgid "" ">%(points)s points required to accept or unaccept your own answer to your " "own question" -msgstr "" +msgstr ">%(points)s نقطة مطلوبة لقبول او رÙض إجابتك على سؤالك" #: models/__init__.py:665 #, python-format msgid "" "Sorry, you will be able to accept this answer only after %(will_be_able_at)s" -msgstr "" +msgstr "سو٠تستطيع قبول هذه الإجابة بعد %(will_be_able_at)s" #: models/__init__.py:674 #, python-format msgid "" "Sorry, only moderators or original author of the question - %(username)s - " "can accept or unaccept the best answer" -msgstr "" +msgstr "Ùقط المشرÙين والكاتب الأصلي للسؤال - %(username)s - يستطيعون قبول او رÙض Ø£Ùضل إجابة" #: models/__init__.py:697 msgid "Sorry, you cannot vote for your own posts" -msgstr "" +msgstr "لا يمكنك التصويت على مشاركتك!" #: models/__init__.py:701 msgid "Sorry your account appears to be blocked " -msgstr "" +msgstr "عذراً، يبدو أن Øسابك Ù…Øجوب" #: models/__init__.py:706 msgid "Sorry your account appears to be suspended " -msgstr "" +msgstr "عذراً، يبدو أن Øسابك Ù…Ùصول" #: models/__init__.py:716 #, python-format msgid ">%(points)s points required to upvote" -msgstr "" +msgstr ">%(points)s نقطة مطلوبة لإعطاء أصوات إيجابية" #: models/__init__.py:722 #, python-format msgid ">%(points)s points required to downvote" -msgstr "" +msgstr ">%(points)s نقطة مطلوبة لإعطاء أصوات سلبية" #: models/__init__.py:737 msgid "Sorry, blocked users cannot upload files" -msgstr "" +msgstr "عذراً، الأعضاء المØجوبين لا يمكنهم رÙع الملÙات" #: models/__init__.py:738 msgid "Sorry, suspended users cannot upload files" -msgstr "" +msgstr "عذراً، الأعضاء المÙصولين لا يمكنهم رÙع الملÙات" #: models/__init__.py:740 #, python-format msgid "sorry, file uploading requires karma >%(min_rep)s" -msgstr "" +msgstr "لرÙع الملÙات يجب أن يكون لديك %(min_rep)s نقطة على الأقل" #: models/__init__.py:759 msgid "Could not post, because your karma is insufficient to publish links" -msgstr "" +msgstr "لا يمكن نشر المشاركة، عدد نقاطك المكتسبة لا ØªØ³Ù…Ø Ø¨Ø¹Ø¯ بإضاÙØ© الروابط" #: models/__init__.py:785 msgid "Sorry, you already gave an answer, please edit it instead." -msgstr "" +msgstr "لقد قمت أصلاً بإعطاء إجابة، Ùضلاً عدل إجابتك السابقة بدل نشر إجابة جديدة" #: models/__init__.py:809 #, python-format @@ -3595,12 +3596,12 @@ msgstr[5] "" #: models/__init__.py:821 msgid "Sorry, but only post owners or moderators can edit comments" -msgstr "" +msgstr "Ùقط كتاب التعليقات والمشرÙين لهم صلاØية التعديل" #: models/__init__.py:850 msgid "" "Sorry, since your account is suspended you can comment only your own posts" -msgstr "" +msgstr "بسبب أن Øسابك Ù…Ùصول يمكنك كتابة التعليقات على مشاركاتك Ùقط" #: models/__init__.py:854 #, python-format @@ -3613,35 +3614,35 @@ msgstr "" msgid "" "This post has been deleted and can be seen only by post owners, site " "administrators and moderators" -msgstr "" +msgstr "هذه المشاركة Ù…ØذوÙØ©ØŒ يمكن مشاهدة من قبل الكاتب الأصلي والمشرÙين Ùقط" #: models/__init__.py:901 msgid "" "Sorry, only moderators, site administrators and post owners can edit deleted" " posts" -msgstr "" +msgstr "Ùقط الكاتب الأًصلي والمشرÙين يمكنهم تعديل المشاركات الØذوÙØ©" #: models/__init__.py:917 msgid "Sorry, since your account is blocked you cannot edit posts" -msgstr "" +msgstr "بسبب أن Øسابك Ù…Øجوب لا يمكنك تعديل المشاركات" #: models/__init__.py:921 msgid "" "Sorry, since your account is suspended you can edit only your own posts" -msgstr "" +msgstr "بسبب أن Øسابك Ù…Ùصول يمكنك Ùقط تعديل مشاركاتك" #: models/__init__.py:926 #, python-format msgid "" "Sorry, to edit wiki posts, a minimum reputation of %(min_rep)s is required" -msgstr "" +msgstr "لتعديل مشاركات الويكي يجب ان يكون لديك على الأقل %(min_rep)s نقطة" #: models/__init__.py:933 #, python-format msgid "" "Sorry, to edit other people's posts, a minimum reputation of %(min_rep)s is " "required" -msgstr "" +msgstr "لتعديل مشاركات الغير يجب أن يكون لديك على الأقل %(min_rep)s نقطة" #: models/__init__.py:996 msgid "" @@ -3659,78 +3660,78 @@ msgstr[5] "" #: models/__init__.py:1011 msgid "Sorry, since your account is blocked you cannot delete posts" -msgstr "" +msgstr "بسبب أن Øسابك Ù…Øجوب لا يمكنك Øذ٠المشاركات" #: models/__init__.py:1015 msgid "" "Sorry, since your account is suspended you can delete only your own posts" -msgstr "" +msgstr "بسبب أن Øسابك Ù…Ùصول يمكنك Ùقط تعديل مشاركاتك" #: models/__init__.py:1019 #, python-format msgid "" "Sorry, to delete other people's posts, a minimum reputation of %(min_rep)s " "is required" -msgstr "" +msgstr "Ù„Øذ٠مشاركات الغير يجب أن يكون لديك على الأقل %(min_rep)s نقطة" #: models/__init__.py:1040 msgid "Sorry, since your account is blocked you cannot close questions" -msgstr "" +msgstr "بسبب أن Øسابك Ù…Øجوب لا يمكنك إغلاق الأسئلة" #: models/__init__.py:1044 msgid "Sorry, since your account is suspended you cannot close questions" -msgstr "" +msgstr "بسبب أن Øسابك Ù…Ùصول يمكنك إغلاق اسألتك Ùقط" #: models/__init__.py:1048 #, python-format msgid "" "Sorry, to close other people' posts, a minimum reputation of %(min_rep)s is " "required" -msgstr "" +msgstr "لإغلاق مشاركات الغير يجب أن يكون لديك على الاقل %(min_rep)s نقطة" #: models/__init__.py:1057 #, python-format msgid "" "Sorry, to close own question a minimum reputation of %(min_rep)s is required" -msgstr "" +msgstr "لإغلاق أسالتك يجب أن يكون لديك على الأقل %(min_rep)s نقطة" #: models/__init__.py:1084 #, python-format msgid "" "Sorry, only administrators, moderators or post owners with reputation > " "%(min_rep)s can reopen questions." -msgstr "" +msgstr "Ùقط المشرÙين او الكاتب الأًصلي ÙÙŠ Øالة كان لديه على الأقل %(min_rep)s نقطة يمكنهم إعادة ÙØªØ Ø§Ù„Ø³Ø¤Ø§Ù„." #: models/__init__.py:1090 #, python-format msgid "" "Sorry, to reopen own question a minimum reputation of %(min_rep)s is " "required" -msgstr "" +msgstr "لإعادة ÙØªØ Ø³Ø¤Ø§Ù„Ùƒ يجب أن يكون لديك على الأقل %(min_rep)s نقطة" #: models/__init__.py:1095 msgid "Sorry, you cannot reopen questions because your account is blocked" -msgstr "" +msgstr "بسبب أن Øسابك Ù…Øجوب لا يمكنك إعادة ÙØªØ Ø§Ù„Ø³Ø¤Ø§Ù„" #: models/__init__.py:1100 msgid "Sorry, you cannot reopen questions because your account is suspended" -msgstr "" +msgstr "بسبب أن Øسابك Ù…Ùصول لا يمكنك إعادة ÙØªØ Ø§Ù„Ø³Ø¤Ø§Ù„" #: models/__init__.py:1123 msgid "You have flagged this question before and cannot do it more than once" -msgstr "" +msgstr "لقد قمت من قبل بالتبليغ على هذا السؤال، لا يمكنك التبليغ أكثر من مرة" #: models/__init__.py:1131 msgid "" "Sorry, since your account is blocked you cannot flag posts as offensive" -msgstr "" +msgstr "بسبب أن Øسابك Ù…Øجوب لا يمكنك التبليغ على المشاركات" #: models/__init__.py:1142 #, python-format msgid "" "Sorry, to flag posts as offensive a minimum reputation of %(min_rep)s is " "required" -msgstr "" +msgstr "للتبليغ على المشاركات يجب أن يكون لديك على الأقل %(min_rep)s نقطة" #: models/__init__.py:1163 #, python-format @@ -3745,13 +3746,13 @@ msgstr "" #: models/__init__.py:1181 msgid "Sorry, since your account is blocked you cannot remove flags" -msgstr "" +msgstr "بسبب أن Øسابك Ù…Øجوب لا يمكنك إزالة التبليغات" #: models/__init__.py:1185 msgid "" "Sorry, your account appears to be suspended and you cannot remove flags. " "Please contact the forum administrator to reach a resolution." -msgstr "" +msgstr "Øسابك Ù…Ùصول لا يمكنك إزالة التبليغات، Ùضلاً راسل إدارة المجتمع" #: models/__init__.py:1191 #, python-format @@ -3767,50 +3768,50 @@ msgstr[5] "" #: models/__init__.py:1210 msgid "you don't have the permission to remove all flags" -msgstr "" +msgstr "ليس لديك الصلاØية لإزالة كل التبليغات" #: models/__init__.py:1211 msgid "no flags for this entry" -msgstr "" +msgstr "لا يوجد تبليغات على هذا المØتوى" #: models/__init__.py:1235 msgid "" "Sorry, only question owners, site administrators and moderators can retag " "deleted questions" -msgstr "" +msgstr "Ùقط الكاتب الأصلي والمشرÙين لديهم صلاØية إعادة تعيين مواضيع السؤال المØذوÙ" #: models/__init__.py:1243 msgid "Sorry, since your account is blocked you cannot retag questions" -msgstr "" +msgstr "بسبب أن Øسابك Ù…Øجوب لا يمكنك إعادة تعيين مواضيع السؤال" #: models/__init__.py:1247 msgid "" "Sorry, since your account is suspended you can retag only your own questions" -msgstr "" +msgstr "بسبب أن Øسابك Ù…Ùصول يمكنك Ùقط إعادة تعيين مواضيع أسالتك" #: models/__init__.py:1251 #, python-format msgid "" "Sorry, to retag questions a minimum reputation of %(min_rep)s is required" -msgstr "" +msgstr "لإعادة تعيين مواضيع السؤال يجب أن يكون لديك على الأقل %(min_rep)s نقطة" #: models/__init__.py:1270 msgid "Sorry, since your account is blocked you cannot delete comment" -msgstr "" +msgstr "بسبب أن Øسابك Ù…Øجوب لا يمكنك Øذ٠التعليق" #: models/__init__.py:1274 msgid "" "Sorry, since your account is suspended you can delete only your own comments" -msgstr "" +msgstr "بسب أن Øسابك Ù…Ùصول يمكنك Ùقط Øذ٠تعليقاتك" #: models/__init__.py:1278 #, python-format msgid "Sorry, to delete comments reputation of %(min_rep)s is required" -msgstr "" +msgstr "Ù„Øذ٠تعليق يجب أن يكون لديك على الأقل %(min_rep)s نقطة" #: models/__init__.py:1303 msgid "sorry, but older votes cannot be revoked" -msgstr "" +msgstr "الأصوات القديمة لا يمكن التراجع عنها" #: models/__init__.py:1995 utils/functions.py:98 #, python-format @@ -3891,7 +3892,7 @@ msgstr "مستخدم مسجل" #: models/__init__.py:2308 msgid "Watched User" -msgstr "" +msgstr "Watched" #: models/__init__.py:2310 msgid "Approved User" @@ -3900,7 +3901,7 @@ msgstr "مستخدم مقبول" #: models/__init__.py:2495 #, python-format msgid "%(username)s karma is %(reputation)s" -msgstr "نقاط العضو %(username)s هي %(reputation)s" +msgstr "سمعة %(username)s: %(reputation)s" #: models/__init__.py:2508 #, python-format @@ -3938,12 +3939,12 @@ msgstr[5] "" #: models/__init__.py:2533 #, python-format msgid "%(item1)s and %(item2)s" -msgstr "" +msgstr "%(item1)s Ùˆ %(item2)s" #: models/__init__.py:2535 #, python-format msgid "%(user)s has %(badges)s" -msgstr "" +msgstr "%(user)s لديه %(badges)s" #: models/__init__.py:2682 #, python-format @@ -3959,32 +3960,32 @@ msgstr[5] "" #: models/__init__.py:3159 #, python-format msgid "%(user)s shared a %(post_link)s." -msgstr "" +msgstr "%(user)s شارك %(post_link)s." #: models/__init__.py:3162 models/__init__.py:3172 #, python-format msgid "%(user)s edited a %(post_link)s." -msgstr "" +msgstr "%(user)s عدل %(post_link)s." #: models/__init__.py:3164 #, python-format msgid "%(user)s posted a %(post_link)s" -msgstr "" +msgstr "%(user)s نشر %(post_link)s" #: models/__init__.py:3167 #, python-format msgid "%(user)s edited an %(post_link)s." -msgstr "" +msgstr "%(user)s عدل %(post_link)s." #: models/__init__.py:3169 #, python-format msgid "%(user)s posted an %(post_link)s." -msgstr "" +msgstr "%(user)s نشر %(post_link)s." #: models/__init__.py:3174 #, python-format msgid "%(user)s posted a %(post_link)s." -msgstr "" +msgstr "%(user)s نشر %(post_link)s." #: models/__init__.py:3190 msgid "To reply, PLEASE WRITE ABOVE THIS LINE." @@ -3993,7 +3994,7 @@ msgstr "" #: models/__init__.py:3232 #, python-format msgid "\"%(title)s\"" -msgstr "" +msgstr "\"%(title)s\"" #: models/__init__.py:3384 #, python-format @@ -4005,7 +4006,7 @@ msgstr "" #: models/__init__.py:3657 #, python-format msgid "Welcome to %(site_name)s" -msgstr "" +msgstr "مرØباً ÙÙŠ %(site_name)s" #: models/__init__.py:3678 views/commands.py:697 msgid "Your tag subscription was saved, thanks!" @@ -4014,72 +4015,72 @@ msgstr "" #: models/badges.py:129 #, python-format msgid "Deleted own post with %(votes)s or more upvotes" -msgstr "" +msgstr "Øذ٠مشاركتك مع وجود %(votes)s صوت إيجابي أو أكثر" #: models/badges.py:133 msgid "Disciplined" -msgstr "" +msgstr "منضبط" #: models/badges.py:151 #, python-format msgid "Deleted own post with %(votes)s or more downvotes" -msgstr "" +msgstr "Øذ٠مشاركتك مع وجود %(votes)s صوت سلبي أو أكثر" #: models/badges.py:155 msgid "Peer Pressure" -msgstr "" +msgstr "مضغوط" #: models/badges.py:174 #, python-format msgid "Received at least %(votes)s upvote for an answer for the first time" -msgstr "" +msgstr "الØصول على أول %(votes)s صوت إيجابي لأØد الأجوبة" #: models/badges.py:178 msgid "Teacher" -msgstr "" +msgstr "أستاذ" #: models/badges.py:218 msgid "Supporter" -msgstr "" +msgstr "داعم" #: models/badges.py:219 msgid "First upvote" -msgstr "" +msgstr "أول تصويت إيجابي" #: models/badges.py:227 msgid "Critic" -msgstr "" +msgstr "ناقد" #: models/badges.py:228 msgid "First downvote" -msgstr "" +msgstr "أول تصويت سلبي" #: models/badges.py:237 msgid "Civic Duty" -msgstr "" +msgstr "مؤدي الواجب" #: models/badges.py:238 #, python-format msgid "Voted %(num)s times" -msgstr "" +msgstr "صوت %(num)s مرة" #: models/badges.py:252 #, python-format msgid "Answered own question with at least %(num)s up votes" -msgstr "" +msgstr "الإجابة على سؤالك مع على الأقل %(num)s صوت إيجابي" #: models/badges.py:256 msgid "Self-Learner" -msgstr "" +msgstr "متعلم ذاتياً" #: models/badges.py:304 msgid "Nice Answer" -msgstr "إجابة رائعة" +msgstr "إجابة جميلة" #: models/badges.py:309 models/badges.py:321 models/badges.py:333 #, python-format msgid "Answer voted up %(num)s times" -msgstr "" +msgstr "التصويت الإيجابي على الإجابة %(num)s مرة" #: models/badges.py:316 msgid "Good Answer" @@ -4087,7 +4088,7 @@ msgstr "إجابة جيدة" #: models/badges.py:328 msgid "Great Answer" -msgstr "إجابة عظيمة" +msgstr "إجابة ممتازة" #: models/badges.py:340 msgid "Nice Question" @@ -4096,7 +4097,7 @@ msgstr "سؤال جميل" #: models/badges.py:345 models/badges.py:357 models/badges.py:369 #, python-format msgid "Question voted up %(num)s times" -msgstr "" +msgstr "التصويت الإيجابي على السؤال %(num)s مرة" #: models/badges.py:352 msgid "Good Question" @@ -4112,20 +4113,20 @@ msgstr "طالب" #: models/badges.py:381 msgid "Asked first question with at least one up vote" -msgstr "" +msgstr "Ø·Ø±Ø Ø£ÙˆÙ„ سؤال مع وجود تصويت إيجابي واØد على الأقل" #: models/badges.py:414 msgid "Popular Question" -msgstr "" +msgstr "سؤال شعبي" #: models/badges.py:418 models/badges.py:429 models/badges.py:441 #, python-format msgid "Asked a question with %(views)s views" -msgstr "" +msgstr "Ø·Ø±Ø Ø³Ø¤Ø§Ù„ مع %(views)s مشاهدة" #: models/badges.py:425 msgid "Notable Question" -msgstr "" +msgstr "سؤال ملØوظ" #: models/badges.py:436 msgid "Famous Question" @@ -4133,157 +4134,157 @@ msgstr "سؤال مشهور" #: models/badges.py:450 msgid "Asked a question and accepted an answer" -msgstr "" +msgstr "Ø·Ø±Ø Ø³Ø¤Ø§Ù„ وقبول إجابة" #: models/badges.py:453 msgid "Scholar" -msgstr "" +msgstr "مثقÙ" #: models/badges.py:495 msgid "Enlightened" -msgstr "" +msgstr "مستنير" #: models/badges.py:499 #, python-format msgid "First answer was accepted with %(num)s or more votes" -msgstr "" +msgstr "أول إجابة تم قبولها مع %(num)s صوت أو أكثر" #: models/badges.py:507 msgid "Guru" -msgstr "" +msgstr "Ù…Ùعلم" #: models/badges.py:510 #, python-format msgid "Answer accepted with %(num)s or more votes" -msgstr "" +msgstr "إجابة تم قبولها مع %(num)s صوت أو أكثر" #: models/badges.py:518 #, python-format msgid "" "Answered a question more than %(days)s days later with at least %(votes)s " "votes" -msgstr "" +msgstr "الإجابة على سؤال بعد %(days)s يوم مع على الأقل وجود %(votes)s صوت" #: models/badges.py:525 msgid "Necromancer" -msgstr "" +msgstr "قسم الأرشيÙ" #: models/badges.py:548 msgid "Citizen Patrol" -msgstr "" +msgstr "قائد لجنة شعبية" #: models/badges.py:551 msgid "First flagged post" -msgstr "" +msgstr "أول تبليغ على مشاركة" #: models/badges.py:563 msgid "Cleanup" -msgstr "" +msgstr "تراجع" #: models/badges.py:566 msgid "First rollback" -msgstr "" +msgstr "تراجع عن تصويت" #: models/badges.py:577 msgid "Pundit" -msgstr "" +msgstr "ناقد إيجابي" #: models/badges.py:580 msgid "Left 10 comments with score of 10 or more" -msgstr "" +msgstr "ترك 10 تعليقات مع 10 أصوات أو أكثر" #: models/badges.py:612 msgid "Editor" -msgstr "" +msgstr "Ù…Øرر" #: models/badges.py:615 msgid "First edit" -msgstr "" +msgstr "أول تعديل" #: models/badges.py:623 msgid "Associate Editor" -msgstr "" +msgstr "كبير المØررين" #: models/badges.py:627 #, python-format msgid "Edited %(num)s entries" -msgstr "" +msgstr "تعديل %(num)s مشاركة" #: models/badges.py:634 msgid "Organizer" -msgstr "" +msgstr "شخص منظم" #: models/badges.py:637 msgid "First retag" -msgstr "" +msgstr "أول إعادة تعيين مواضيع" #: models/badges.py:644 msgid "Autobiographer" -msgstr "" +msgstr "شخص معروÙ" #: models/badges.py:647 msgid "Completed all user profile fields" -msgstr "" +msgstr "إكمال جميع Øقول المل٠الشخصي" #: models/badges.py:663 #, python-format msgid "Question favorited by %(num)s users" -msgstr "" +msgstr "تم تÙضيل السؤال من قبل %(num)s عضو" #: models/badges.py:689 msgid "Stellar Question" -msgstr "" +msgstr "سؤال مهم" #: models/badges.py:698 msgid "Favorite Question" -msgstr "" +msgstr "سؤال Ù…Ùضل" #: models/badges.py:710 msgid "Enthusiast" -msgstr "" +msgstr "متØمس" #: models/badges.py:714 #, python-format msgid "Visited site every day for %(num)s days in a row" -msgstr "" +msgstr "زيارة الموقع كل يوم لمدة %(num)s أيام متتابعة" #: models/badges.py:732 msgid "Commentator" -msgstr "" +msgstr "معلق" #: models/badges.py:736 #, python-format msgid "Posted %(num_comments)s comments" -msgstr "" +msgstr "نشر %(num_comments)s تعليقات" #: models/badges.py:752 msgid "Taxonomist" -msgstr "" +msgstr "مصن٠المواضيع" #: models/badges.py:756 #, python-format msgid "Created a tag used by %(num)s questions" -msgstr "" +msgstr "إنشاء موضوع وتم إستخدامة ÙÙŠ %(num)s سؤال" #: models/badges.py:774 msgid "Expert" -msgstr "" +msgstr "خبير متخصص" #: models/badges.py:777 msgid "Very active in one tag" -msgstr "" +msgstr "نشط جداً ÙÙŠ موضوع واØد" #: models/message.py:16 msgid "message" -msgstr "" +msgstr "رسالة" #: models/post.py:414 msgid "Question: " -msgstr "" +msgstr "سؤال:" #: models/post.py:416 msgid "Answer: " -msgstr "" +msgstr "جواب:" #: models/post.py:1570 msgid "Sorry, this question has been deleted and is no longer accessible" @@ -4336,7 +4337,7 @@ msgstr "" #: models/question.py:108 #, python-format msgid "\" and \"%s\"" -msgstr "" +msgstr "\" Ùˆ \"%s\"" #: models/question.py:111 msgid "\" and more" @@ -4370,15 +4371,15 @@ msgstr "" #: models/reply_by_email.py:38 msgid "Post an answer" -msgstr "" +msgstr "نشر إجابة" #: models/reply_by_email.py:39 msgid "Post a comment" -msgstr "" +msgstr "نشر تعليق" #: models/reply_by_email.py:40 msgid "Edit post" -msgstr "" +msgstr "تعديل المشاركة" #: models/reply_by_email.py:41 msgid "Append to post" @@ -4403,7 +4404,7 @@ msgstr "التØرير بالبريد" #: models/repute.py:207 #, python-format msgid "<em>Changed by moderator. Reason:</em> %(reason)s" -msgstr "" +msgstr "<em>تم التعديل بواسطة المشرÙ. السبب:</em> %(reason)s" #: models/repute.py:218 #, python-format @@ -4430,11 +4431,11 @@ msgstr "" #: models/user.py:317 msgid "Questions that I asked" -msgstr "" +msgstr "الأسئلة التي سألتها" #: models/user.py:318 msgid "Questions that I answered" -msgstr "" +msgstr "أسئلة جاوبت عليها" #: models/user.py:319 msgid "Individually selected questions" @@ -4442,11 +4443,11 @@ msgstr "" #: models/user.py:320 msgid "Mentions and comment responses" -msgstr "" +msgstr "التنبيهات والتعليقات" #: models/user.py:323 msgid "Instantly" -msgstr "Ùوري" +msgstr "Ùوراً" #: models/user.py:324 msgid "Daily" @@ -4458,7 +4459,7 @@ msgstr "أسبوعي" #: models/user.py:326 msgid "No email" -msgstr "لا بريد" +msgstr "بدون بريد" #: models/user.py:566 msgid "Can join when they want" @@ -4474,98 +4475,98 @@ msgstr "" #: models/user.py:617 msgid "Please give a list of valid email addresses." -msgstr "" +msgstr "Please give a list of valid email addresses." #: models/user.py:627 msgid "Please give a list of valid email domain names." -msgstr "" +msgstr "Please give a list of valid email domain names." #: models/widgets.py:34 msgid "css for the widget" -msgstr "" +msgstr "css for the widget" #: templates/404.html:3 templates/404.html.py:10 msgid "Page not found" -msgstr "" +msgstr "لم يتم العثور على الصÙØØ©" #: templates/404.html:13 msgid "Sorry, could not find the page you requested." -msgstr "" +msgstr "عذراً، لم نجد الصÙØØ© المطلوبة." #: templates/404.html:15 msgid "This might have happened for the following reasons:" -msgstr "" +msgstr "قد يكون هذا Øصل للأسباب التالية:" #: templates/404.html:17 msgid "this question or answer has been deleted;" -msgstr "" +msgstr "السؤال أو الإجابة تم ØØ°Ùها؛" #: templates/404.html:18 msgid "url has error - please check it;" -msgstr "" +msgstr "الرابط ÙŠØتوي أخطاء - Ùضلاً تأكد؛" #: templates/404.html:19 msgid "" "the page you tried to visit is protected or you don't have sufficient " "points, see" -msgstr "" +msgstr "الصÙØØ© التي تØاول طلبها تطلب صلاØيات خاصية او نقاط معينة، راجع" #: templates/404.html:19 templates/widgets/footer.html:39 msgid "faq" -msgstr "أسئلة شائعة" +msgstr "أشئلة شائعة" #: templates/404.html:20 msgid "if you believe this error 404 should not have occured, please" -msgstr "" +msgstr "إذا كنت متأكد ان الخطأ 404 يجب أن لا يظهر لك، Ùضلاً" #: templates/404.html:21 msgid "report this problem" -msgstr "" +msgstr "بلغ عن هذه المشكلة" #: templates/404.html:30 templates/500.html:11 msgid "back to previous page" -msgstr "" +msgstr "الرجوع للصÙØØ© السابقة" #: templates/404.html:31 templates/widgets/scope_nav.html:17 msgid "see all questions" -msgstr "" +msgstr "مشاهدة جميع الأسئلة" #: templates/404.html:32 msgid "see all tags" -msgstr "" +msgstr "مشاهدة جميع المواضيع" #: templates/500.html:3 templates/500.html.py:5 msgid "Internal server error" -msgstr "" +msgstr "خطأ سيرÙر داخلي" #: templates/500.html:8 msgid "system error log is recorded, error will be fixed as soon as possible" -msgstr "" +msgstr "تم تسجيل الخطأ ÙÙŠ السيرÙر، سو٠تتم المراجعة ÙˆØ¥ØµÙ„Ø§Ø Ø§Ù„Ù…Ø´ÙƒÙ„Ø© ÙÙŠ أسرع وقت ممكن" #: templates/500.html:9 msgid "please report the error to the site administrators if you wish" -msgstr "" +msgstr "Ùضلاً بلغ عن هذا الخطأ للمشر٠العام" #: templates/500.html:12 msgid "see latest questions" -msgstr "" +msgstr "مشاهدة أخر الأسئلة" #: templates/500.html:13 msgid "see tags" -msgstr "أنظر العلامات" +msgstr "مشاهدة المواضيع" #: templates/answer_edit.html:4 templates/answer_edit.html.py:10 msgid "Edit answer" -msgstr "تØرير الإجابة" +msgstr "تعديل الإجابة" #: templates/answer_edit.html:10 templates/question_edit.html:9 #: templates/question_retag.html:5 templates/revisions.html:7 msgid "back" -msgstr "" +msgstr "رجوع" #: templates/answer_edit.html:41 templates/question_edit.html:61 msgid "Save edit" -msgstr "ØÙظ التØرير" +msgstr "ØÙظ التعديلات" #: templates/answer_edit.html:46 templates/close.html:16 #: templates/feedback.html:64 templates/question_edit.html:62 @@ -4584,23 +4585,23 @@ msgstr "إلغاء" #: templates/question/javascript.html:72 templates/question/javascript.html:75 #: templates/widgets/edit_post.html:73 msgid "hide preview" -msgstr "" +msgstr "إخÙاء العرض المسبق" #: templates/answer_edit.html:89 templates/ask.html:84 #: templates/question_edit.html:103 templates/question/javascript.html:75 msgid "show preview" -msgstr "معاينة" +msgstr "مشاهدة العرض المسبق" #: templates/ask.html:4 templates/widgets/ask_button.html:9 #: templates/widgets/ask_form.html:67 msgid "Ask Your Question" -msgstr "أسأل" +msgstr "Ø£Ø·Ø±Ø Ø³Ø¤Ø§Ù„Ùƒ" #: templates/ask.html:21 msgid "" "since you are not logged in right now, you will be asked to sign in or " "register after posting your question" -msgstr "" +msgstr "كونك غير مسجل دخول Øالياً، سو٠يطلب منك تسجيل الدخول أو التسجيل بعد كتابة سؤالك" #: templates/ask.html:25 #, python-format @@ -4613,22 +4614,22 @@ msgstr "" #: templates/ask.html:29 msgid "please, try to make your question interesting to this community" -msgstr "" +msgstr "Ùضلاً، أجعل سؤال مهم ومÙيد للمجتمع لتØصل على Ø£Ùضل تÙاعل" #: templates/ask.html:30 templates/widgets/answer_edit_tips.html:12 #: templates/widgets/question_edit_tips.html:8 msgid "provide enough details" -msgstr "قم بتوÙير ما يكÙÙŠ من التÙاصيل" +msgstr "ÙˆÙر تÙاصيل قدر الأمكان، Øتى لا نظطر لسؤالك عنها وبالتالي يضيع وقت الطرÙين" #: templates/ask.html:31 templates/widgets/answer_edit_tips.html:15 #: templates/widgets/question_edit_tips.html:11 msgid "be clear and concise" -msgstr "كن ÙˆØ§Ø¶Ø Ùˆ موجز" +msgstr "كن ÙˆØ§Ø¶Ø ÙˆØ£Ø³ØªØ®Ø¯Ù… لغة نضيÙØ© خالية من الأخطاء، واهتم جيداً بالتنسيق العام" #: templates/ask.html:36 templates/widgets/answer_edit_tips.html:20 #: templates/widgets/question_edit_tips.html:16 msgid "see frequently asked questions" -msgstr "أنظر الأسئلة الشائعة" +msgstr "شاهد الأسئلة الشائعة" #: templates/ask.html:36 templates/faq_static.html:3 #: templates/faq_static.html.py:5 templates/widgets/answer_edit_tips.html:20 @@ -4645,12 +4646,12 @@ msgstr "%(name)s" #: templates/badge.html:5 msgid "Badge" -msgstr "الشارة" +msgstr "وسام" #: templates/badge.html:7 #, python-format msgid "Badge \"%(name)s\"" -msgstr "شارة \"%(name)s\"" +msgstr "الوسام \"%(name)s\"" #: templates/badge.html:9 templates/user_profile/user_recent.html:16 #: templates/user_profile/user_stats.html:71 @@ -4670,21 +4671,21 @@ msgstr[5] "" #: templates/badges.html:3 templates/badges.html.py:5 msgid "Badges" -msgstr "شارات" +msgstr "الأوسمة" #: templates/badges.html:7 msgid "Community gives you awards for your questions, answers and votes." -msgstr "" +msgstr "يتم تكريم الأعضاء المساهمين ÙÙŠ هذا المجتمع من خلال الأوسمة، ويØصل العضو على الأوسمة بناء على مشاركاتة ÙÙŠ Ø·Ø±Ø Ø§Ù„Ø£Ø³Ø¦Ù„Ø©ØŒ الأجوبة والتصويت على المØتوى الجيد والسيء." #: templates/badges.html:8 msgid "" "Below is the list of available badges and number of times each type of badge" " has been awarded." -msgstr "" +msgstr "ÙÙŠ الأسÙÙ„ تجد قائمة الأوسمة المتاØØ© Øالياً، مع ذكر شرط الØصول على كل وسام، بالإضاÙØ© لعدد مرات Øصول الأعضاء لكل وسام." #: templates/badges.html:31 msgid "Community badges" -msgstr "" +msgstr "رتب الأوسمة" #: templates/badges.html:33 msgid "gold badge: the highest honor and is very rare" @@ -4694,29 +4695,29 @@ msgstr "" msgid "" "Gold badge is the highest award in this community. To obtain it you have to show \n" "profound knowledge and ability in addition to your active participation." -msgstr "" +msgstr "الوسام الذهبي: هو أعلى وأرقى مستويات التكريم ÙÙŠ مجتمع ServerHang. للØصول عليها لا بد من أن يثبت الشخص مستوى خبرتة الكبيرة من خلال المساهمة بمØتوى Ùريد وخاص ومن خلال مساعدة الأعضاء." #: templates/badges.html:42 templates/badges.html.py:46 msgid "" "silver badge: occasionally awarded for the very high quality contributions" -msgstr "" +msgstr "الوسام الÙضي: هو الدرجة الثانية من مستويات التكريم، ويكرم بها المساهمين الجادين والذين يخصصون وقت من يومهم لمساعدة الآخرين." #: templates/badges.html:49 templates/badges.html.py:53 msgid "bronze badge: often given as a special honor" -msgstr "" +msgstr "الوسام البرونزي: هو أول مستويات التكريم على مساهمتك ÙÙŠ بناء هذا المجتمع، وعلى الÙائدة التي تقدمها للمجتمع." #: templates/base.html:23 #, python-format msgid "RSS feed from %(site_title)s" -msgstr "" +msgstr "خلاصات RSS لموقع %(site_title)s" #: templates/close.html:3 templates/close.html.py:5 msgid "Close question" -msgstr "إغلاق سؤال" +msgstr "إغلاق السؤال" #: templates/close.html:6 msgid "Close the question" -msgstr "إغلاق السؤال" +msgstr "إغلاق هذا السؤال" #: templates/close.html:11 msgid "Reasons" @@ -4724,41 +4725,41 @@ msgstr "الأسباب" #: templates/close.html:15 msgid "OK to close" -msgstr "تم، Ùˆ أغلق" +msgstr "نعم للإغلاق" #: templates/faq_static.html:5 msgid "Frequently Asked Questions " -msgstr "" +msgstr "الأسئلة الأكثر شيوعاً" #: templates/faq_static.html:6 msgid "What kinds of questions can I ask here?" -msgstr "" +msgstr "ما نوع الأسئلة التي أستطيع طرØها هنا؟" #: templates/faq_static.html:7 msgid "" "Most importantly - questions should be <strong>relevant</strong> to this " "community." -msgstr "" +msgstr "أهم أمر - يجب ان تكون الأسئلة <strong>ذات صلة</strong> بموضوع المجتمع." #: templates/faq_static.html:8 msgid "" "Before you ask - please make sure to search for a similar question. You can " "search questions by their title or tags." -msgstr "" +msgstr "قبل أن تسأل - أبØØ« جيداً عن سؤالك، يمكنك البØØ« عن الأسئلة بواسطة العنوان أو الموضوع. لا داعي للمØتوى المكرر." #: templates/faq_static.html:10 msgid "What kinds of questions should be avoided?" -msgstr "" +msgstr "مانوع الأسئلة التي علي تجنبها؟" #: templates/faq_static.html:11 msgid "" "Please avoid asking questions that are not relevant to this community, too " "subjective and argumentative." -msgstr "" +msgstr "تجنب Ø·Ø±Ø Ø§Ù„Ø£Ø³Ø¦Ù„Ø© الغير الخارجة عن نطاق تخصص المجتمع، ايضاً تجنب الأسئلة الجدلية التي لا يمكن ان تكون عبارة عن سؤال وجواب بل تطلب النقاش والأخذ والعطاء بالكلام، هذا النوع من المØتوى ÙŠØØ°Ù Ùوراً كونه غير متناسب مع آلية عمل المجتمع هذا." #: templates/faq_static.html:13 msgid "What should I avoid in my answers?" -msgstr "" +msgstr "ماذا علي أن أتجنب ÙÙŠ أجوبتي؟" #: templates/faq_static.html:14 msgid "" @@ -4766,29 +4767,29 @@ msgid "" "discussion group</strong>. Please avoid holding debates in your answers as " "they tend to dilute the essense of questions and answers. For the brief " "discussions please use commenting facility." -msgstr "" +msgstr "is a <strong>question and answer</strong> site - <strong>it is not a discussion group</strong>. Please avoid holding debates in your answers as they tend to dilute the essense of questions and answers. For the brief discussions please use commenting facility." #: templates/faq_static.html:15 msgid "Who moderates this community?" -msgstr "" +msgstr "من إدارة ومشرÙين هذا المجتمع؟" #: templates/faq_static.html:16 msgid "The short answer is: <strong>you</strong>." -msgstr "" +msgstr "بشكل بسيط <strong>أنــت</strong>." #: templates/faq_static.html:17 msgid "This website is moderated by the users." -msgstr "" +msgstr "هذا الموقع يدار من قبل الأعضاء المسجلين." #: templates/faq_static.html:18 msgid "" "Karma system allows users to earn rights to perform a variety of moderation " "tasks" -msgstr "" +msgstr "نظام النقاط والسمعة ÙŠØ³Ù…Ø Ù„Ù„Ø£Ø¹Ø¶Ø§Ø¡ بالØصول على صلاØيات أشراÙية تمكنهم من إدارة الموقع" #: templates/faq_static.html:20 msgid "How does karma system work?" -msgstr "" +msgstr "كي٠يعمل نظام النقاط والسمعة؟" #: templates/faq_static.html:21 msgid "" @@ -4796,7 +4797,7 @@ msgid "" "some points, which are called \\\"karma points\\\". These points serve as a " "rough measure of the community trust to him/her. Various moderation tasks " "are gradually assigned to the users based on those points." -msgstr "" +msgstr "When a question or answer is upvoted, the user who posted them will gain some points, which are called \\\"karma points\\\". These points serve as a rough measure of the community trust to him/her. Various moderation tasks are gradually assigned to the users based on those points." #: templates/faq_static.html:22 #, python-format @@ -4810,39 +4811,39 @@ msgid "" "points that can be accumulated for a question or answer per day. The table " "below explains reputation point requirements for each type of moderation " "task." -msgstr "" +msgstr "For example, if you ask an interesting question or give a helpful answer, your input will be upvoted. On the other hand if the answer is misleading - it will be downvoted. Each vote in favor will generate <strong>%(REP_GAIN_FOR_RECEIVING_UPVOTE)s</strong> points, each vote against will subtract <strong>%(REP_LOSS_FOR_RECEIVING_DOWNVOTE)s</strong> points. There is a limit of <strong>%(MAX_REP_GAIN_PER_USER_PER_DAY)s</strong> points that can be accumulated for a question or answer per day. The table below explains reputation point requirements for each type of moderation task." #: templates/faq_static.html:32 templates/user_profile/user_votes.html:14 msgid "upvote" -msgstr "" +msgstr "تصويت إيجابي" #: templates/faq_static.html:37 msgid "add comments" -msgstr "أض٠تعليقات" +msgstr "إضاÙØ© تعليقات" #: templates/faq_static.html:42 templates/user_profile/user_votes.html:16 msgid "downvote" -msgstr "" +msgstr "تصويت سلبي" #: templates/faq_static.html:45 msgid " accept own answer to own questions" -msgstr "" +msgstr "قبول إجابتك على سؤالك" #: templates/faq_static.html:49 msgid "open and close own questions" -msgstr "" +msgstr "ÙØªØ ÙˆØ¥ØºÙ„Ø§Ù‚ الأسئلة الخاصة" #: templates/faq_static.html:53 msgid "retag other's questions" -msgstr "" +msgstr "إعادة تعيين مواضيع أسئلة الغير" #: templates/faq_static.html:58 msgid "edit community wiki questions" -msgstr "" +msgstr "تعديل أسئلة الويكي" #: templates/faq_static.html:63 msgid "edit any answer" -msgstr "تØرير أي إجابة" +msgstr "تعديل أي إجابة" #: templates/faq_static.html:67 msgid "delete any comment" @@ -4850,7 +4851,7 @@ msgstr "Øذ٠أي تعليق" #: templates/faq_static.html:71 msgid "How to change my picture (gravatar) and what is gravatar?" -msgstr "" +msgstr "كي٠يمكنني تغيير صورتي الرمزية، وماهي خدمة gravatar ØŸ" #: templates/faq_static.html:72 msgid "" @@ -4868,59 +4869,59 @@ msgid "" "href='http://gravatar.com'><strong>gravatar.com</strong></a> (just please be" " sure to use the same email address that you used to register with us). " "Default image that looks like a kitchen tile is generated automatically.</p>" -msgstr "" +msgstr "<p>The picture that appears on the users profiles is called <strong>gravatar</strong> (which means <strong>g</strong>lobally <strong>r</strong>ecognized <strong>avatar</strong>).</p><p>Here is how it works: a <strong>cryptographic key</strong> (unbreakable code) is calculated from your email address. You upload your picture (or your favorite alter ego image) the website <a href='http://gravatar.com'><strong>gravatar.com</strong></a> from where we later retreive your image using the key.</p><p>This way all the websites you trust can show your image next to your posts and your email address remains private.</p><p>Please <strong>personalize your account</strong> with an image - just register at <a href='http://gravatar.com'><strong>gravatar.com</strong></a> (just please be sure to use the same email address that you used to register with us). Default image that looks like a kitchen tile is generated automatically.</p>" #: templates/faq_static.html:73 msgid "To register, do I need to create new password?" -msgstr "" +msgstr "To register, do I need to create new password?" #: templates/faq_static.html:74 msgid "" "No, you don't have to. You can login through any service that supports " "OpenID, e.g. Google, Yahoo, AOL, etc." -msgstr "" +msgstr "No, you don't have to. You can login through any service that supports OpenID, e.g. Google, Yahoo, AOL, etc." #: templates/faq_static.html:75 msgid "\"Login now!\"" -msgstr "" +msgstr "\"سجل دخول\"" #: templates/faq_static.html:77 msgid "Why other people can edit my questions/answers?" -msgstr "" +msgstr "لماذا يستطيع الأخرين تعديل أسألتي وأجوبتي؟" #: templates/faq_static.html:78 msgid "Goal of this site is..." -msgstr "الهد٠من هذا الموقع..." +msgstr "هد٠هذا الموقع هو..." #: templates/faq_static.html:78 msgid "" "So questions and answers can be edited like wiki pages by experienced users " "of this site and this improves the overall quality of the knowledge base " "content." -msgstr "" +msgstr "So questions and answers can be edited like wiki pages by experienced users of this site and this improves the overall quality of the knowledge base content." #: templates/faq_static.html:79 msgid "If this approach is not for you, we respect your choice." -msgstr "" +msgstr "If this approach is not for you, we respect your choice." #: templates/faq_static.html:81 msgid "Still have questions?" -msgstr "" +msgstr "مازال لديك أسئلة؟" #: templates/faq_static.html:82 #, python-format msgid "" "Please <a href='%(ask_question_url)s'>ask</a> your question, help make our " "community better!" -msgstr "" +msgstr "Please <a href='%(ask_question_url)s'>ask</a> your question, help make our community better!" #: templates/feedback.html:3 msgid "Feedback" -msgstr "رأيك" +msgstr "مقترØات" #: templates/feedback.html:5 msgid "Give us your feedback!" -msgstr "" +msgstr "ماذا لديك من مقترØات لتطوير هذا المجتمع؟" #: templates/feedback.html:14 #, python-format @@ -4937,59 +4938,59 @@ msgid "" " <span class='big strong'>Dear visitor</span>, we look forward to hearing your feedback.\n" " Please type and send us your message below.\n" " " -msgstr "" +msgstr "\n <span class='big strong'>عزيزي الزائر</span>, الموقع هذا يعمل كمجتمع يقوم على اعضاءة والÙائدة التي يقدمونها للغير.\n ان كان لديك أي مقترØات لتطوير المجتمع هذا، أستخدم نموذج المراسلة هذا.\n " #: templates/feedback.html:30 msgid "(to hear from us please enter a valid email or check the box below)" -msgstr "" +msgstr "(لنتمكن من الرد عليك، يرجى إستخدام بريد Øقيقي)" #: templates/feedback.html:37 templates/feedback.html.py:46 msgid "(this field is required)" -msgstr "(Øقل مطلوب)" +msgstr "(هذا الØقل مطلوب)" #: templates/feedback.html:55 msgid "(Please solve the captcha)" -msgstr "(من Ùضلك أكتب الØرو٠بشكل صØÙŠØ)" +msgstr "(يرجى ØÙ„ الكاباتشا)" #: templates/feedback.html:63 msgid "Send Feedback" -msgstr "إبداء رأيك" +msgstr "إرسال المقترØات" #: templates/groups.html:3 templates/groups.html.py:6 #: templates/question/sidebar.html:108 #: templates/tags/list_bulk_tag_subscription.html:15 msgid "Groups" -msgstr "" +msgstr "المجموعات" #: templates/groups.html:11 msgid "All groups" -msgstr "" +msgstr "كل المجمعات" #: templates/groups.html:13 msgid "all groups" -msgstr "" +msgstr "كل المجموعات" #: templates/groups.html:15 msgid "My groups" -msgstr "" +msgstr "مجموعاتي" #: templates/groups.html:17 msgid "my groups" -msgstr "" +msgstr "مجموعات" #: templates/groups.html:25 msgid "" "Tip: to create a new group - please go to some user profile and add the new " "group there. That user will be the first member of the group" -msgstr "" +msgstr "Tip: to create a new group - please go to some user profile and add the new group there. That user will be the first member of the group" #: templates/groups.html:30 msgid "Group" -msgstr "" +msgstr "مجموعة" #: templates/groups.html:31 msgid "Number of members" -msgstr "" +msgstr "عدد الأعضاء" #: templates/help.html:2 templates/help.html.py:4 msgid "Help" @@ -5002,120 +5003,120 @@ msgstr "مرØباً %(username)sØŒ" #: templates/help.html:9 msgid "Welcome," -msgstr "مرØبا،" +msgstr "مرØباً،" #: templates/help.html:13 #, python-format msgid "Thank you for using %(app_name)s, here is how it works." -msgstr "" +msgstr "شكراً لإستخدامك %(app_name)sØŒ أليك كي٠يعمل المجتمع." #: templates/help.html:16 msgid "How questions, answers and comments work" -msgstr "" +msgstr "كي٠تعمل الأسئلة، الأجوبة والتعليقات" #: templates/help.html:18 msgid "" "This site is for asking and answering questions, not for open-ended " "discussions." -msgstr "" +msgstr "هذا المجتمع Ù„Ø·Ø±Ø Ø§Ù„Ø£Ø³Ø¦Ù„Ø© والإجابة عليها، وليس Ù„ÙØªØ Ø§Ù„Ù†Ù‚Ø§Ø´Ø§Øª التي لا نهاية لها." #: templates/help.html:19 msgid "" "We encourage everyone to use “question†space for asking and “answer†for " "answering." -msgstr "" +msgstr "Ù†ØÙ† ننتظر من الجميع إستخدام مساØØ© â€œØ§Ù„Ø³Ø¤Ø§Ù„â€ Ù„Ø·Ø±Ø Ø§Ù„Ø£Ø³Ø¦Ù„Ø© ومساØØ© “الإجابة†للإجابة على هذه الأسئلة." #: templates/help.html:22 msgid "" "Despite that, each question and answer can be commented – \n" " the comments are good for the limited discussions." -msgstr "" +msgstr "بالإضاÙØ© لهذا، يمكن إستخدام خاصية التعليقات على السؤال او الإجابة Ù„ÙØªØ Ù†Ù‚Ø§Ø´ ضيق وقصير Øول Ù…Øتوى السؤال او الإجابة Ù†Ùسها لا غير." #: templates/help.html:26 msgid "Please search before asking your questions" -msgstr "" +msgstr "يرجى البØØ« والبØØ« قبل Ø·Ø±Ø Ø£ÙŠ سؤال بالمجتمع" #: templates/help.html:27 msgid "" "Type your question in the search bar and see whether a similar question has " "been asked before" -msgstr "" +msgstr "أستخدم Øقل البØØ« للبØØ« عن سؤالك أو المواضيع المتعلقة به، ÙˆØاول تغيير الكلمات المستخدمة عدة مرات إذا لم تصل للسؤال من أول مرة، لا داعي لوجود أسئلة متكررة، علماً أن الأسئلة المكررة يتم ØØ°Ùها Ùوراً." #: templates/help.html:29 msgid "Search has advanced capabilities:" -msgstr "" +msgstr "نظام البØØ« ÙŠØتوي على خصائص متقدمة:" #: templates/help.html:31 msgid "to search in title - enter [title: your text]" -msgstr "" +msgstr "للبØØ« ÙÙŠ عناوين الأسئلة Ùقط استخدم: [title: your text]" #: templates/help.html:32 msgid "to search by tags - enter [tag: sometag] or #sometag" -msgstr "" +msgstr "للØبث عن المواضيع مثلا عن linux أستخدم: #linux" #: templates/help.html:33 msgid "to search by user - enter [user: somename] or @somename or @\"some name\"" -msgstr "" +msgstr "للبØØ« عن عضو مثلا mustafa أستخدم: @mustafa" #: templates/help.html:35 msgid "" "In addition, it is possible to click on tags to add them to the search " "query." -msgstr "" +msgstr "كما يمكنك الضغط على اØدى المواضيع للبØØ« عن الأسئلة المتعلقة بها." #: templates/help.html:37 msgid "" "Finally, a separate tag search box is available in the side bar of the main " "page, where the search tags can be entered as well" -msgstr "" +msgstr "Finally, a separate tag search box is available in the side bar of the main page, where the search tags can be entered as well" #: templates/help.html:40 msgid "" "<em>Important!!!</em> All search terms are combined with a logical \"AND\" " "expression - to narrow the search by adding new terms." -msgstr "" +msgstr "<em>هام</em>ØŒ نظام البØØ« يعتمد على المنطق، لهذا Øاول ان تقلل الكلمات المستخدمة بالبØØ« واستخدم الدقة لتصل لأÙضل نتيجة." #: templates/help.html:42 msgid "Voting" -msgstr "" +msgstr "التصويت" #: templates/help.html:44 #, python-format msgid "" "Voting in %(app_name)s helps to select best answers and thank most helpful " "users." -msgstr "" +msgstr "التصويت ÙÙŠ %(app_name)s يساعد على برز المØتوى الجيد للغير وطمر Ù…Øتوى السيء عنهم، ويساعد على تØديد Ø£Ùضل إجابة لكل سؤال ليكون الوصول للمعلومة الصØÙŠØØ© أسرع، " #: templates/help.html:47 #, python-format msgid "" "Please vote when you find helpful information,\n" " it really helps the %(app_name)s community." -msgstr "" +msgstr "Ùضلاً صوت عندما تجد معلومات Ù…Ùيدة، وتجنب التصويت الإيجابي او السلبي بناء على المجاملات والأصدقاء Ùهذا يقلل من سمعتك بالموقع ويقل من قوة Ù…Øتوى مجتمع %(app_name)s." #: templates/help.html:51 msgid "Other topics" -msgstr "" +msgstr "أمور أخرى" #: templates/help.html:53 msgid "" "You can @mention users anywhere in the text to point their attention,\n" " follow users and conversations and report inappropriate content by flagging it." -msgstr "" +msgstr "يمكنك متابعة أعضاء المجتمع عن طريق زيارة مل٠العضو الشخصي والضغط على زر متابعة، نظام المتابعة يمكنك من متابعة أنشطة ومشاركات الأعضاء المهمين بالنسبة لك.\nكما يمكنك أستخدام خاصية Ù„Ùت الإنتباه لعضو معين بداخل الأسئلة، الإجابات والتعليقات عن طريق إستخدام @username (أستبدل username بأسم المستخدم للعضو المطلوب تنبيهه)." #: templates/help.html:56 msgid "Enjoy." -msgstr "" +msgstr "الآن يمكنك الإنطلاق بهذا المجتمع لتبدأ وتعمل ÙˆÙÙ‚ مبدأ Ùيد وأستÙيد، Ùهذا هد٠مجتمع ServerHang. شكراً لك على القراءة. " #: templates/import_data.html:2 templates/import_data.html.py:4 msgid "Import StackExchange data" -msgstr "" +msgstr "Import StackExchange data" #: templates/import_data.html:13 msgid "" "<em>Warning:</em> if your database is not empty, please back it up\n" " before attempting this operation." -msgstr "" +msgstr "<em>Warning:</em> if your database is not empty, please back it up\n before attempting this operation." #: templates/import_data.html:16 msgid "" @@ -5123,21 +5124,21 @@ msgid "" " the data import completes. This process may take several minutes.\n" " Please note that feedback will be printed in plain text.\n" " " -msgstr "" +msgstr "Upload your stackexchange dump .zip file, then wait until\n the data import completes. This process may take several minutes.\n Please note that feedback will be printed in plain text.\n " #: templates/import_data.html:25 msgid "Import data" -msgstr "إستيراد بيانات" +msgstr "Import data" #: templates/import_data.html:27 msgid "" "In the case you experience any difficulties in using this import tool,\n" " please try importing your data via command line: <code>python manage.py load_stackexchange path/to/your-data.zip</code>" -msgstr "" +msgstr "In the case you experience any difficulties in using this import tool,\n please try importing your data via command line: <code>python manage.py load_stackexchange path/to/your-data.zip</code>" #: templates/list_suggested_tags.html:11 msgid "Tag" -msgstr "" +msgstr "موضوع" #: templates/list_suggested_tags.html:12 msgid "Suggested by" @@ -5153,11 +5154,11 @@ msgstr "" #: templates/list_suggested_tags.html:34 templates/list_suggested_tags.html:45 msgid "Accept" -msgstr "" +msgstr "قبول" #: templates/list_suggested_tags.html:35 templates/list_suggested_tags.html:46 msgid "Reject" -msgstr "" +msgstr "رÙض" #: templates/list_suggested_tags.html:38 msgid "There are no questions with this tag yet" @@ -5175,7 +5176,7 @@ msgstr "" #: templates/list_suggested_tags.html:71 templates/tags/content.html:5 #: templates/tags/content.html.py:31 msgid "Nothing found" -msgstr "لم يعثر علي شئ" +msgstr "لم يتم العثور على شيء" #: templates/macros.html:5 #, python-format @@ -5184,23 +5185,23 @@ msgstr "" #: templates/macros.html:44 msgid "current number of votes" -msgstr "عدد الأصوات الØالي" +msgstr "عدد الأصوات Øالياً" #: templates/macros.html:57 msgid "anonymous user" -msgstr "مستخدم مجهول" +msgstr "عضو مجهول" #: templates/macros.html:91 templates/macros.html.py:110 msgid "asked" -msgstr "" +msgstr "سأل" #: templates/macros.html:93 templates/macros.html.py:112 msgid "answered" -msgstr "مجاب" +msgstr "أجاب" #: templates/macros.html:95 templates/macros.html.py:114 msgid "posted" -msgstr "" +msgstr "نشر" #: templates/macros.html:101 msgid "this post is marked as community wiki" @@ -5211,20 +5212,20 @@ msgstr "" msgid "" "This post is a wiki.\n" " Anyone with karma >%(wiki_min_rep)s is welcome to improve it." -msgstr "" +msgstr "هذه المشاركة ويكي.\n أي عضو مع قوة سمعة +%(wiki_min_rep)s بإمكانة تØسين المØتوى." #: templates/macros.html:146 msgid "updated" -msgstr "" +msgstr "Øدث" #: templates/macros.html:261 templates/macros.html.py:267 msgid "Leave this group" -msgstr "" +msgstr "ترك هذه المجموعة" #: templates/macros.html:262 templates/macros.html.py:264 #: templates/macros.html:283 msgid "Join this group" -msgstr "" +msgstr "الإنضمام لهذه المجموعة" #: templates/macros.html:263 templates/macros.html.py:268 #: templates/macros.html:278 @@ -5242,40 +5243,40 @@ msgstr "" #: templates/macros.html:273 templates/macros.html.py:274 #: templates/macros.html:285 msgid "Ask to join" -msgstr "" +msgstr "طلب إنضمام" #: templates/macros.html:314 #, python-format msgid "see questions tagged '%(tag)s'" -msgstr "" +msgstr "مشاهدة الأسئلة المتعلقة بموضوع '%(tag)s'" #: templates/macros.html:395 msgid "Comments" -msgstr "" +msgstr "التعليقات" #: templates/macros.html:430 msgid "delete this comment" -msgstr "إزالة هذا التعليق" +msgstr "Øذ٠هذا التعليق" #: templates/macros.html:443 templates/revisions.html:38 #: templates/revisions.html.py:41 templates/question/answer_controls.html:5 #: templates/question/question_controls.html:1 msgid "edit" -msgstr "تØرير" +msgstr "تعديل" #: templates/macros.html:452 msgid "convert to answer" -msgstr "" +msgstr "تØويل لإجابة" #: templates/macros.html:579 #, python-format msgid "follow %(alias)s" -msgstr "متابعة %(alias)s" +msgstr "تابع %(alias)s" #: templates/macros.html:582 #, python-format msgid "unfollow %(alias)s" -msgstr "إيقا٠المتابعة %(alias)s" +msgstr "إلغاء متابعة %(alias)s" #: templates/macros.html:583 #, python-format @@ -5285,17 +5286,17 @@ msgstr "متابع %(alias)s" #: templates/macros.html:662 templatetags/extra_tags.py:44 #, python-format msgid "%(username)s gravatar image" -msgstr "" +msgstr "الصورة الرمزية للعضو %(username)s" #: templates/macros.html:671 #, python-format msgid "%(username)s's website is %(url)s" -msgstr "" +msgstr "موقع %(username)s هو %(url)s" #: templates/macros.html:686 templates/macros.html.py:687 #: templates/macros.html:725 templates/macros.html.py:726 msgid "previous" -msgstr "السابق" +msgstr "السابقة" #: templates/macros.html:698 templates/macros.html.py:737 msgid "current page" @@ -5329,7 +5330,7 @@ msgstr[5] "" #: templates/macros.html:768 msgid "no new responses yet" -msgstr "" +msgstr "لايوجد ردود بعد" #: templates/macros.html:783 templates/macros.html.py:784 #, python-format @@ -5352,27 +5353,27 @@ msgstr "الأسئلة" #: templates/question.html:230 msgid "see more comments" -msgstr "" +msgstr "المزيد من التعليقات" #: templates/question.html:232 templates/question.html.py:335 msgid "add a comment" -msgstr "" +msgstr "أض٠تعليق" #: templates/question.html:245 templates/question/content.html:46 msgid "Answer Your Own Question" -msgstr "قم بالإجابة علي سؤالك" +msgstr "أجب على سؤالك" #: templates/question.html:250 msgid "Post Your Answer" -msgstr "إرسال إجابتك" +msgstr "نشر إجابتك" #: templates/question.html:256 templates/widgets/ask_form.html:65 msgid "Login/Signup to Post" -msgstr "" +msgstr "سجل دخول للنشر" #: templates/question_edit.html:4 templates/question_edit.html.py:9 msgid "Edit question" -msgstr "تØرير السؤال" +msgstr "تعديل السؤال" #: templates/question_edit.html:16 msgid "Question - in one sentence" @@ -5380,19 +5381,19 @@ msgstr "" #: templates/question_edit.html:23 msgid "Details" -msgstr "" +msgstr "التÙاصيل" #: templates/question_edit.html:56 msgid "Change language" -msgstr "" +msgstr "تغيير اللغة" #: templates/question_retag.html:3 templates/question_retag.html.py:5 msgid "Retag question" -msgstr "" +msgstr "إعادة تعيين مواضيع السؤال" #: templates/question_retag.html:21 msgid "Retag" -msgstr "" +msgstr "تعديل المواضيع" #: templates/question_retag.html:28 msgid "Why use and modify tags?" @@ -5419,7 +5420,7 @@ msgstr "إعادة ÙØªØ Ø§Ù„Ø³Ø¤Ø§Ù„" msgid "" "This question has been closed by \n" " <a href=\"%(closed_by_profile_url)s\">%(username)s</a>\n" -msgstr "" +msgstr "تم إغلاق هذا السؤال بواسطة \n <a href=\"%(closed_by_profile_url)s\">%(username)s</a>\n" #: templates/reopen.html:17 msgid "Close reason:" @@ -5427,11 +5428,11 @@ msgstr "سبب الإغلاق:" #: templates/reopen.html:20 msgid "When:" -msgstr "Øين:" +msgstr "متى:" #: templates/reopen.html:23 msgid "Reopen this question?" -msgstr "إعادة ÙØªØ Ø§Ù„Ø³Ø¤Ø§Ù„ØŸ" +msgstr "إعادة ÙØªØ Ù‡Ø°Ø§ السؤال؟" #: templates/reopen.html:27 msgid "Reopen this question" @@ -5443,16 +5444,16 @@ msgstr "تاريخ المراجعة" #: templates/revisions.html:23 msgid "click to hide/show revision" -msgstr "" +msgstr "أضغط لمشاهدة/إخÙاء المراجعة" #: templates/revisions.html:29 #, python-format msgid "revision %(number)s" -msgstr "إصدار رقم %(number)s" +msgstr "مراجعة %(number)s" #: templates/subscribe_for_tags.html:3 templates/subscribe_for_tags.html:5 msgid "Subscribe for tags" -msgstr "" +msgstr "الإشتراك بالمواضيع" #: templates/subscribe_for_tags.html:6 msgid "Please, subscribe for the following tags:" @@ -5460,16 +5461,16 @@ msgstr "" #: templates/subscribe_for_tags.html:15 msgid "Subscribe" -msgstr "اشترك" +msgstr "أشترك" #: templates/tags.html:17 msgid "search for tags" -msgstr "" +msgstr "البØØ« عن مواضيع" #: templates/users.html:8 templates/users.html.py:18 #: templates/tags/list_bulk_tag_subscription.html:13 msgid "Users" -msgstr "المستخدمون" +msgstr "الأعضاء" #: templates/users.html:16 #, python-format @@ -5488,37 +5489,37 @@ msgstr "" #: templates/users.html:33 templates/main_page/tab_bar.html:17 #: templates/tags/header.html:14 msgid "Sort by »" -msgstr "" +msgstr "رتب بواسطة »" #: templates/users.html:40 msgid "see people with the highest reputation" -msgstr "" +msgstr "مشاهدة الأعضاء Øسب قوة عطائهم" #: templates/users.html:41 templates/user_profile/user_info.html:25 #: templates/user_profile/user_reputation.html:5 #: templates/user_profile/user_tabs.html:24 msgid "karma" -msgstr "النقاط" +msgstr "قوة السمعة" #: templates/users.html:47 msgid "see people who joined most recently" -msgstr "" +msgstr "مشاهدة أخر الاعضاء المسجلين بالموقع" #: templates/users.html:48 msgid "recent" -msgstr "آخر الأØداث" +msgstr "الأخير" #: templates/users.html:53 msgid "see people who joined the site first" -msgstr "" +msgstr "مشاهدة أول الأعضاء تسجيلاً بالموقع" #: templates/users.html:59 msgid "see people sorted by name" -msgstr "" +msgstr "مشاهدة الأعضاء بواسطة الأسم" #: templates/users.html:60 msgid "by username" -msgstr "باسم المستخدم" +msgstr "الأسم" #: templates/users.html:66 #, python-format @@ -5527,7 +5528,7 @@ msgstr "" #: templates/users.html:69 msgid "Nothing found." -msgstr "لم يعثر علي شئ." +msgstr "لم يتم العثور على شيء." #: templates/authopenid/authopenid_macros.html:63 msgid "Please enter your <span>user name</span>, then sign in" @@ -5542,15 +5543,15 @@ msgstr "" #: templates/authopenid/signin.html:115 #: templates/authopenid/widget_signin.html:118 msgid "Sign in" -msgstr "تسجيل الدخول" +msgstr "تسجيل دخول" #: templates/authopenid/changeemail.html:2 msgid "Change Email" -msgstr "تغيير البريد" +msgstr "تعديل البريد" #: templates/authopenid/changeemail.html:6 msgid "Validate email" -msgstr "" +msgstr "التØقق من البريد" #: templates/authopenid/changeemail.html:9 #, python-format @@ -5565,7 +5566,7 @@ msgstr "" #: templates/authopenid/changeemail.html:18 msgid "Email verified" -msgstr "" +msgstr "تم تأكيد البريد" #: templates/authopenid/changeemail.html:21 msgid "" @@ -5578,40 +5579,40 @@ msgstr "" #: templates/authopenid/complete.html:21 msgid "Registration" -msgstr "" +msgstr "تسجيل" #: templates/authopenid/complete.html:23 msgid "User registration" -msgstr "" +msgstr "تسجيل عضو" #: templates/authopenid/complete.html:47 msgid "<strong>Screen Name</strong> (<i>will be shown to others</i>)" -msgstr "" +msgstr "<strong>أسم المستخدم</strong> (<i>ظاهر للجميع</i>)" #: templates/authopenid/complete.html:56 msgid "" "<strong>Email Address</strong> (<i>will <strong>not</strong> be shared with \n" "anyone, must be valid</i>)\n" " " -msgstr "" +msgstr "<strong>البريد الإلكتروني</strong> (<i>مخÙÙŠØŒ غير ظار للأعضاء والزوار، ويجب ان يكون صØÙŠØ</i>)" #: templates/authopenid/complete.html:71 #: templates/authopenid/signup_with_password.html:5 #: templates/authopenid/signup_with_password.html:45 msgid "Signup" -msgstr "التسجيل" +msgstr "تسجيل" #: templates/authopenid/confirm_email.txt:1 msgid "Thank you for registering at our Q&A forum!" -msgstr "" +msgstr "شكراً للتسجيل ÙÙŠ ServerHangØŒ الآن يمكنك المساهمة ÙÙŠ بناء المØتوى العربي على الإنترنت!" #: templates/authopenid/confirm_email.txt:3 msgid "Your account details are:" -msgstr "تÙاصيل Øسابك هي" +msgstr "بيانات Øسابك:" #: templates/authopenid/confirm_email.txt:5 msgid "Username:" -msgstr "اسم المستخدم:" +msgstr "أسم المستخدم:" #: templates/authopenid/confirm_email.txt:6 msgid "Password:" @@ -5619,14 +5620,14 @@ msgstr "كلمة المرور:" #: templates/authopenid/confirm_email.txt:8 msgid "Please sign in here:" -msgstr "رجاء تسجيل الدخول هنا:" +msgstr "يرجى تسجيل الدخول هنا" #: templates/authopenid/confirm_email.txt:11 #: templates/authopenid/email_validation.txt:13 msgid "" "Sincerely,\n" "Q&A Forum Administrator" -msgstr "" +msgstr "أطيب تØية،\nÙريق عمل ServerHang" #: templates/authopenid/email_validation.html:2 #: templates/authopenid/email_validation.html:3 @@ -5658,22 +5659,22 @@ msgstr "" #: templates/authopenid/logout.html:3 msgid "Logout" -msgstr "تسجيل الخروج" +msgstr "تسجيل خروج" #: templates/authopenid/logout.html:5 msgid "You have successfully logged out" -msgstr "" +msgstr "تم تسجيل الخروج بنجاØ" #: templates/authopenid/logout.html:7 msgid "" "However, you still may be logged in to your OpenID provider. Please logout " "of your provider if you wish to do so." -msgstr "" +msgstr "قد تكون مازلت مسجل دخول ÙÙŠ خدمة OpenID التي تستخدمها (مثل تويتر، Ùيسبوك)ØŒ يمكنك التاكد وتسجيل الخروج ان اØببت ذلك." #: templates/authopenid/signin.html:5 #: templates/authopenid/widget_signin.html:5 msgid "User login" -msgstr "" +msgstr "دخول عضو" #: templates/authopenid/signin.html:15 #: templates/authopenid/widget_signin.html:19 @@ -5682,7 +5683,7 @@ msgid "" "\n" " Your answer to %(title)s %(summary)s will be posted once you log in\n" " " -msgstr "" +msgstr "\n<span class=\"strong big\">Your answer to </span> <i>\"<strong>%(title)s</strong> %(summary)s...\"</i> <span class=\"strong big\">is saved and will be posted once you log in.</span>" #: templates/authopenid/signin.html:22 #: templates/authopenid/widget_signin.html:26 @@ -5691,7 +5692,7 @@ msgid "" "Your question \n" " %(title)s %(summary)s will be posted once you log in\n" " " -msgstr "" +msgstr "<span class=\"strong big\">Your question</span> <i>\"<strong>%(title)s</strong> %(summary)s...\"</i> <span class=\"strong big\">is saved and will be posted once you log in.</span>" #: templates/authopenid/signin.html:31 #: templates/authopenid/widget_signin.html:36 @@ -5713,7 +5714,7 @@ msgstr "" msgid "" "Click on one of the icons below to add a new login method or re-validate an " "existing one." -msgstr "" +msgstr "أضغط على ايقونة أي من هذه الخدمات لإضاÙتها او إزالتها، كما يمكنك ايضاً من إعادة تأكيد المزود." #: templates/authopenid/signin.html:39 #: templates/authopenid/widget_signin.html:44 @@ -5727,7 +5728,7 @@ msgstr "" msgid "" "Please check your email and visit the enclosed link to re-connect to your " "account" -msgstr "" +msgstr "يرجى مراجعة بريدك الإلكتروني، والضغط على الرابط الخاص الذي ارسلناه لك لتتمكن من إستعادة Øسابك." #: templates/authopenid/signin.html:90 msgid "or enter your <span>user name and password</span>" @@ -5736,27 +5737,27 @@ msgstr "" #: templates/authopenid/signin.html:94 #: templates/authopenid/widget_signin.html:98 msgid "Please, sign in" -msgstr "Ùضلا، الدخول" +msgstr "يرجى تسجيل الدخول" #: templates/authopenid/signin.html:101 #: templates/authopenid/widget_signin.html:105 msgid "Login failed, please try again" -msgstr "" +msgstr "Ùشل الدخول، يرجى تكرار المØاولة" #: templates/authopenid/signin.html:106 #: templates/authopenid/widget_signin.html:109 msgid "Login or email" -msgstr "" +msgstr "البريد الإلكتروني" #: templates/authopenid/signin.html:110 #: templates/authopenid/widget_signin.html:113 utils/forms.py:264 msgid "Password" -msgstr "كلمة مرور" +msgstr "كلمة المرور" #: templates/authopenid/signin.html:122 #: templates/authopenid/widget_signin.html:125 msgid "To change your password - please enter the new one twice, then submit" -msgstr "" +msgstr "لتغيير كلمة المرور، يرجى إدخال كلمة مرور جديدة مرتبين ثم أرسل." #: templates/authopenid/signin.html:126 #: templates/authopenid/widget_signin.html:129 @@ -5766,33 +5767,33 @@ msgstr "كلمة مرور جديدة" #: templates/authopenid/signin.html:135 #: templates/authopenid/widget_signin.html:138 msgid "Please, retype" -msgstr "" +msgstr "يرجى إعادة الكتابة" #: templates/authopenid/signin.html:145 #: templates/authopenid/widget_signin.html:148 #: templates/livesettings/site_settings.html:24 msgid "Change password" -msgstr "" +msgstr "تغيير كلمة المرور" #: templates/authopenid/signin.html:159 #: templates/authopenid/widget_signin.html:162 msgid "Here are your current login methods" -msgstr "" +msgstr "وسائل الدخول المستخدمة Øالياً" #: templates/authopenid/signin.html:163 #: templates/authopenid/widget_signin.html:166 msgid "provider" -msgstr "" +msgstr "المزود" #: templates/authopenid/signin.html:164 #: templates/authopenid/widget_signin.html:167 msgid "last used" -msgstr "" +msgstr "آخر إستخدام" #: templates/authopenid/signin.html:165 #: templates/authopenid/widget_signin.html:168 msgid "delete, if you like" -msgstr "" +msgstr "Øذ٠الوسيلة" #: templates/authopenid/signin.html:179 #: templates/authopenid/widget_signin.html:182 @@ -5804,45 +5805,45 @@ msgstr "ØØ°Ù" #: templates/authopenid/signin.html:181 #: templates/authopenid/widget_signin.html:184 msgid "cannot be deleted" -msgstr "" +msgstr "لا يمكن ØØ°Ùها" #: templates/authopenid/signin.html:194 #: templates/authopenid/widget_signin.html:197 msgid "Still have trouble signing in?" -msgstr "" +msgstr "مازال لديك مشكلة بتسجيل الدخول؟" #: templates/authopenid/signin.html:199 #: templates/authopenid/widget_signin.html:202 msgid "Please, enter your email address below and obtain a new key" -msgstr "" +msgstr "يرجى إدخال البريد الخاص بك هنا لإرسال كود جديد" #: templates/authopenid/signin.html:201 #: templates/authopenid/widget_signin.html:204 msgid "Please, enter your email address below to recover your account" -msgstr "" +msgstr "يرجى إدخال البريد الخاص بك هنا لإستعادة الØساب" #: templates/authopenid/signin.html:204 #: templates/authopenid/widget_signin.html:207 msgid "recover your account via email" -msgstr "" +msgstr "إستعادة Øسابك عبر البريد" #: templates/authopenid/signin.html:215 #: templates/authopenid/widget_signin.html:217 msgid "Send a new recovery key" -msgstr "" +msgstr "إرسال Ù…ÙØªØ§Ø Ø¥Ø³ØªØ¹Ø§Ø¯Ø© جديد" #: templates/authopenid/signin.html:217 #: templates/authopenid/widget_signin.html:219 msgid "Recover your account via email" -msgstr "" +msgstr "إستعادة Øسابك عبر البرد" #: templates/authopenid/signup_with_password.html:11 msgid "Please register by clicking on any of the icons below" -msgstr "" +msgstr "يمكنك التسجيل من خلال Ø£Øدى هذه الخدمات الإجتماعية" #: templates/authopenid/signup_with_password.html:24 msgid "or create a new user name and password here" -msgstr "" +msgstr "كما يمكنك تسجيل Øساب خاص من خلال النموذج بالأسÙÙ„" #: templates/authopenid/signup_with_password.html:26 msgid "Create login name and password" @@ -5861,7 +5862,7 @@ msgstr "" msgid "" "Please read and type in the two words below to help us prevent automated " "account creation." -msgstr "" +msgstr "Ùضلاً أدخل كلمة التØقق البشري، تساعدنا هذه الطريقة بمنع التسجيل العشوائي والتلقائي." #: templates/authopenid/signup_with_password.html:47 msgid "or" @@ -5874,17 +5875,17 @@ msgstr "" #: templates/authopenid/verify_email.html:2 #: templates/authopenid/verify_email.html:4 msgid "Confirm email address" -msgstr "" +msgstr "تأكيد البريد الإلكتروني" #: templates/authopenid/verify_email.html:6 msgid "" "Validation email sent. Please find it and follow the enclosed link.<br/>\n" " If the link doesn't work - enter the code below:" -msgstr "" +msgstr "تم إرسال بريد للتØقق من صØØ© البريد. يرجى ÙØªØ Ø§Ù„Ø±Ø³Ø§Ù„Ø© واضغط على الرابط المرÙÙ‚.<br/>\n واذا لم يعمل، انسخ الكود Ùقط والصق ÙÙŠ الØقل هنا: " #: templates/authopenid/verify_email.html:11 msgid "Confirm email" -msgstr "" +msgstr "تأكيد البريد" #: templates/authopenid/widget_signin.html:33 msgid "" @@ -5899,27 +5900,27 @@ msgstr "" #: templates/avatar/add.html:3 msgid "add avatar" -msgstr "إضاÙØ© صورة" +msgstr "أض٠صورة رمزية" #: templates/avatar/add.html:5 msgid "Change avatar" -msgstr "تغيير الصورة" +msgstr "تعديل الصورة الرمزية" #: templates/avatar/add.html:6 templates/avatar/change.html:7 msgid "Your current avatar: " -msgstr "صورتك الØالية:" +msgstr "الصورة الرمزية الØالية" #: templates/avatar/add.html:9 templates/avatar/change.html:11 msgid "You haven't uploaded an avatar yet. Please upload one now." -msgstr "" +msgstr "لم تقم برÙع أي صورة رمزية بعد، يرجى رÙع واØدة الآن." #: templates/avatar/add.html:13 msgid "Upload New Image" -msgstr "تØميل صورة جديدة" +msgstr "رÙع صورة جديدة" #: templates/avatar/change.html:4 msgid "change avatar" -msgstr "" +msgstr "تعديل الصورة الرمزية" #: templates/avatar/change.html:17 msgid "Choose new Default" @@ -5927,11 +5928,11 @@ msgstr "" #: templates/avatar/change.html:22 msgid "Upload" -msgstr "تØميل" +msgstr "رÙع" #: templates/avatar/confirm_delete.html:2 msgid "delete avatar" -msgstr "Øذ٠صورة" +msgstr "Øذ٠الصورة الرمزية" #: templates/avatar/confirm_delete.html:4 msgid "Please select the avatars that you would like to delete." @@ -6000,7 +6001,7 @@ msgstr "" #: templates/email/delayed_email_alert.html:2 #, python-format msgid "Dear %(name)s," -msgstr "" +msgstr "عزيزي %(name)sØŒ" #: templates/email/delayed_email_alert.html:3 #, python-format @@ -6045,7 +6046,7 @@ msgstr "" #: templates/email/macros.html:19 #, python-format msgid "Question by %(author)s:" -msgstr "" +msgstr "سؤال بواسطة %(author)s:" #: templates/email/macros.html:21 #, python-format @@ -6062,11 +6063,11 @@ msgstr "" #: templates/email/macros.html:33 #, python-format msgid "Asked by %(author)s:" -msgstr "" +msgstr "سÙأل بواسطة %(author)s: " #: templates/email/macros.html:40 msgid "Tags:" -msgstr "" +msgstr "مواضيع:" #: templates/email/macros.html:48 #, python-format @@ -6190,7 +6191,7 @@ msgstr "" #: templates/email/welcome_lamson_on.html:4 #, python-format msgid "Welcome to %(site_name)s!" -msgstr "" +msgstr "مرØباً بك ÙÙŠ %(site_name)s" #: templates/email/welcome_lamson_on.html:11 msgid "" @@ -6208,19 +6209,19 @@ msgstr "" #: templates/embed/list_widgets.html:44 msgid "How to use?" -msgstr "" +msgstr "How to use?" #: templates/embed/list_widgets.html:45 msgid "" "\n" " Just copy the <script> tag provided and paste it in the site where you wan to put it.\n" " " -msgstr "" +msgstr "\n Just copy the <script> tag provided and paste it in the site where you wan to put it.\n " #: templates/embed/widget_form.html:3 templates/embed/widget_form.html.py:5 #, python-format msgid "%(action)s an %(widget_name)s widget" -msgstr "" +msgstr "%(action)s an %(widget_name)s widget" #: templates/embed/widget_form.html:14 #: templates/user_profile/user_moderate.html:20 @@ -6229,33 +6230,33 @@ msgstr "ØÙظ" #: templates/embed/widgets.html:3 templates/embed/widgets.html.py:5 msgid "Widgets" -msgstr "" +msgstr "Widgets" #: templates/embed/widgets.html:11 msgid "" "Create and embed widgets into your sites, here a list of available widgets." -msgstr "" +msgstr "Create and embed widgets into your sites, here a list of available widgets." #: templates/embed/widgets.html:16 msgid "Ask a question" -msgstr "" +msgstr "Ø£Ø·Ø±Ø Ø³Ø¤Ø§Ù„Ùƒ معنا" #: templates/embed/widgets.html:17 templates/embed/widgets.html.py:26 msgid "create" -msgstr "" +msgstr "create" #: templates/embed/widgets.html:20 templates/embed/widgets.html.py:29 msgid "view list" -msgstr "" +msgstr "عرض القائمة" #: templates/embed/widgets.html:25 msgid "List of questions" -msgstr "" +msgstr "قائمة الأسئلة" #: templates/group_messaging/email_alert.html:7 #, python-format msgid "%(author)s wrote:" -msgstr "" +msgstr "%(author)s كتب:" #: templates/group_messaging/email_alert.html:11 msgid "" @@ -6266,12 +6267,12 @@ msgstr "" #: templates/group_messaging/home.html:7 #: templates/group_messaging/home_thread_details.html:7 msgid "compose" -msgstr "" +msgstr "تØرير" #: templates/group_messaging/macros.html:5 #, python-format msgid "You wrote on %(date)s:" -msgstr "" +msgstr "لقد كتبت ÙÙŠ %(date)s:" #: templates/group_messaging/senders_list.html:3 msgid "Messages by sender:" @@ -6280,19 +6281,19 @@ msgstr "" #: templates/group_messaging/senders_list.html:5 #: templates/user_inbox/base.html:6 templates/user_profile/user_tabs.html:12 msgid "inbox" -msgstr "الوارد" +msgstr "الرسائل" #: templates/group_messaging/senders_list.html:9 msgid "sent" -msgstr "" +msgstr "المرسلة" #: templates/group_messaging/senders_list.html:16 msgid "trash" -msgstr "" +msgstr "السلة" #: templates/group_messaging/threads_list.html:25 msgid "there are no messages yet..." -msgstr "" +msgstr "لا يوجد رسائل بعد..." #: templates/livesettings/_admin_site_views.html:4 msgid "Sites" @@ -6300,7 +6301,7 @@ msgstr "مواقع" #: templates/livesettings/group_settings.html:4 msgid "Settings" -msgstr "" +msgstr "إعدادات" #: templates/livesettings/group_settings.html:9 #: templates/livesettings/site_settings.html:51 @@ -6321,15 +6322,15 @@ msgstr "" #: templates/livesettings/group_settings.html:50 #: templates/livesettings/site_settings.html:98 msgid "You don't have permission to edit values." -msgstr "" +msgstr "ليس لديك صلاØيات لتعديل هذه القيم." #: templates/livesettings/site_settings.html:24 msgid "Documentation" -msgstr "" +msgstr "الوثائق" #: templates/livesettings/site_settings.html:24 msgid "Log out" -msgstr "سجيل الخروج" +msgstr "تسجيل خروج" #: templates/livesettings/site_settings.html:27 msgid "Home" @@ -6337,20 +6338,20 @@ msgstr "الرئيسية" #: templates/livesettings/site_settings.html:28 msgid "Edit Site Settings" -msgstr "" +msgstr "تعديل إعدادات الموقع" #: templates/livesettings/site_settings.html:44 msgid "Livesettings are disabled for this site." -msgstr "" +msgstr "Livesettings are disabled for this site." #: templates/livesettings/site_settings.html:45 msgid "All configuration options must be edited in the site settings.py file" -msgstr "" +msgstr "All configuration options must be edited in the site settings.py file" #: templates/livesettings/site_settings.html:67 #, python-format msgid "Group settings: %(name)s" -msgstr "" +msgstr "إعدادات مجموعة: %(name)s" #: templates/livesettings/site_settings.html:94 msgid "Uncollapse all" @@ -6374,11 +6375,11 @@ msgstr "" #: templates/main_page/headline.html:11 msgid "Tagged" -msgstr "معلّم" +msgstr "المواضيع" #: templates/main_page/headline.html:22 msgid "Search tips:" -msgstr "" +msgstr "Ù†ØµØ§Ø¦Ø Ø§Ù„Ø¨ØØ«:" #: templates/main_page/headline.html:25 msgid "reset author" @@ -6396,7 +6397,7 @@ msgstr "" #: templates/main_page/headline.html:31 templates/main_page/headline.html:34 msgid "start over" -msgstr "" +msgstr "إبدأ من جديد" #: templates/main_page/headline.html:36 msgid " - to expand, or dig in by adding more tags and revising the query." @@ -6404,7 +6405,7 @@ msgstr "" #: templates/main_page/headline.html:39 msgid "Search tip:" -msgstr "بØØ« الإرشادات" +msgstr "Ù†ØµØ§Ø¦Ø Ø§Ù„Ø¨ØØ«:" #: templates/main_page/headline.html:39 msgid "add tags and a query to focus your search" @@ -6420,7 +6421,7 @@ msgstr "لا يوجد أسئلة هنا." #: templates/main_page/nothing_found.html:8 msgid "Please follow some questions or follow some users." -msgstr "" +msgstr "Ùضلا تابع بعض الأسئلة أو بعض الأعضاء." #: templates/main_page/nothing_found.html:13 msgid "You can expand your search by " @@ -6437,35 +6438,35 @@ msgstr "" #: templates/main_page/nothing_found.html:22 #: templates/main_page/nothing_found.html:25 msgid "starting over" -msgstr "" +msgstr "إبدأ من جديد" #: templates/main_page/nothing_found.html:30 msgid "Please always feel free to ask your question!" -msgstr "" +msgstr "Ø£Ø·Ø±Ø Ø³Ø¤Ø§Ù„Ùƒ بكل Øرية أن لم يكن قد كتب من قبل!" #: templates/main_page/questions_loop.html:9 msgid "Did not find what you were looking for?" -msgstr "لم تجد ما تبØØ« عنه؟" +msgstr "لم تجد إجابة لسؤالك بعد؟" #: templates/main_page/questions_loop.html:10 msgid "Ask your question!" -msgstr "" +msgstr "أنشر سؤالك الآن لتØصل على الإجابة!" #: templates/main_page/tab_bar.html:11 msgid "subscribe to the questions feed" -msgstr "" +msgstr "الإشتراك بخلاصة RSS لمتابعة آخر الأسئلة المطروØØ©" #: templates/main_page/tab_bar.html:12 msgid "RSS" -msgstr "" +msgstr "خلاصة RSS" #: templates/main_page/tag_search.html:2 msgid "Tag search" -msgstr "" +msgstr "بØØ« عن موضوع" #: templates/main_page/tag_search.html:5 msgid "search" -msgstr "" +msgstr "بØØ«" #: templates/meta/bottom_scripts.html:7 #, python-format @@ -6501,11 +6502,11 @@ msgstr[5] "" #, python-format msgid "" "please use up to %(tag_count)s tags, less than %(max_chars)s characters each" -msgstr "" +msgstr "يمكنك بإستخدام %(tag_count)s مواضيع ÙƒØد أقصى، وأن لا يتجاوز كل موضوع عن %(max_chars)s ØرÙ." #: templates/question/answer_card.html:21 msgid "This response is published" -msgstr "" +msgstr "تم نشر الرد" #: templates/question/answer_controls.html:2 msgid "swap with question" @@ -6513,12 +6514,12 @@ msgstr "" #: templates/question/answer_controls.html:11 msgid "remove offensive flag" -msgstr "" +msgstr "إلغاء تبليغ الإساءة" #: templates/question/answer_controls.html:13 #: templates/question/question_controls.html:12 msgid "remove flag" -msgstr "إزالة العلم" +msgstr "إزالة التبليغ" #: templates/question/answer_controls.html:18 #: templates/question/answer_controls.html:26 @@ -6527,14 +6528,14 @@ msgstr "إزالة العلم" #: templates/question/question_controls.html:23 msgid "" "report as offensive (i.e containing spam, advertising, malicious text, etc.)" -msgstr "" +msgstr "التبليغ على المØتوى (مثلا سبام، دعائي، ÙŠØتوي روابط ضارة، ÙŠØتوي مواد سيئة...الخ.)" #: templates/question/answer_controls.html:20 #: templates/question/answer_controls.html:28 #: templates/question/question_controls.html:18 #: templates/question/question_controls.html:25 msgid "flag offensive" -msgstr "ضع علم كعدواني" +msgstr "تبليغ إساءة" #: templates/question/answer_controls.html:33 #: templates/question/question_controls.html:36 @@ -6543,15 +6544,15 @@ msgstr "إلغاء الØØ°Ù" #: templates/question/answer_controls.html:43 msgid "unpublish" -msgstr "" +msgstr "إلغاء النشر" #: templates/question/answer_controls.html:48 msgid "publish" -msgstr "" +msgstr "نشر" #: templates/question/answer_controls.html:54 msgid "permanent link" -msgstr "" +msgstr "الرابط الدائم" #: templates/question/answer_controls.html:55 #: templates/widgets/markdown_help.html:20 @@ -6560,15 +6561,15 @@ msgstr "رابط" #: templates/question/answer_controls.html:58 msgid "more" -msgstr "" +msgstr "المزيد" #: templates/question/answer_controls.html:71 msgid "repost as a question comment" -msgstr "" +msgstr "إعادة النشر كتعليق على السؤال" #: templates/question/answer_controls.html:85 msgid "repost as a comment under the older answer" -msgstr "" +msgstr "إعادة النشر كتعليق على الإجابة الأقدم" #: templates/question/answer_tab_bar.html:3 #, python-format @@ -6589,52 +6590,52 @@ msgstr[5] "" #: templates/question/answer_tab_bar.html:11 msgid "Sort by »" -msgstr "ترتيب Øسب >> " +msgstr "رتب »" #: templates/question/answer_tab_bar.html:14 msgid "oldest answers will be shown first" -msgstr "" +msgstr "الإجابات الأقدم أولاً" #: templates/question/answer_tab_bar.html:17 msgid "newest answers will be shown first" -msgstr "" +msgstr "الإجابات الأØدث أولاً" #: templates/question/answer_tab_bar.html:20 msgid "most voted answers will be shown first" -msgstr "" +msgstr "الإجابات الأكثر تصويت أولاً" #: templates/question/answer_vote_buttons.html:8 #: templates/user_profile/users_answers.html:7 msgid "this answer has been selected as correct" -msgstr "" +msgstr "تم إختيار هذه الإجابة كصØÙŠØØ©" #: templates/question/answer_vote_buttons.html:10 msgid "mark this answer as correct (click again to undo)" -msgstr "" +msgstr "إختيار إجابة صØÙŠØØ© (أعد أضغط للتراجع)" #: templates/question/closed_question_info.html:2 #, python-format msgid "" "The question has been closed for the following reason " "<b>\"%(close_reason)s\"</b> <i>by" -msgstr "" +msgstr "هذا السؤال تم إغلاقة للأسباب التالية <b>\"%(close_reason)s\"</b> <i> بواسطة" #: templates/question/closed_question_info.html:4 #, python-format msgid "close date %(closed_at)s" -msgstr "" +msgstr "تاريخ الإغلاق %(closed_at)s" #: templates/question/content.html:33 msgid "Edit Your Previous Answer" -msgstr "" +msgstr "تعديل إجابتك" #: templates/question/content.html:34 msgid "(only one answer per user is allowed)" -msgstr "" +msgstr "(ÙŠØ³Ù…Ø Ø¨Ø¥Ø¬Ø§Ø¨Ø© واØدة لكل عضو)" #: templates/question/new_answer_form.html:12 msgid "Login/Signup to Answer" -msgstr "" +msgstr "دخول/تسجيل للإجابة" #: templates/question/new_answer_form.html:20 msgid "Your answer" @@ -6642,7 +6643,7 @@ msgstr "إجابتك" #: templates/question/new_answer_form.html:22 msgid "Be the first one to answer this question!" -msgstr "لتكن أول من يجيب هذا السؤال!" +msgstr "ÙƒÙÙ† الأول ليجيب على هذا السؤال وأØصل على قوة سمعة إضاÙية!" #: templates/question/new_answer_form.html:28 msgid "" @@ -6651,7 +6652,7 @@ msgid "" "you log in or create a new account. Please try to give a <strong>substantial" " answer</strong>, for discussions, <strong>please use comments</strong> and " "<strong>please do remember to vote</strong> (after you log in)!" -msgstr "" +msgstr "يمكنك كتابة إجابتك الآن، وبعد تسجيل الدخول سو٠يتم نشر الإجابة بشكل تلقائي. تأكد أنك سو٠تقوم Ø¨Ø·Ø±Ø Ø¥Ø¬Ø§Ø¨Ø© كاملة وصØÙŠØØ©. كما يمكنك دائماً مراجعة وتعديل إجابتك. Ùضلاً <strong>أستخدم خاصية التعليقات للنقاش</strong>. كما يرجى <strong>التصويت للإجابات الصØÙŠØØ©</strong> دائماً، ايضاً صوت بالسالب على الإجابات الخاطئة." #: templates/question/new_answer_form.html:32 msgid "" @@ -6661,7 +6662,7 @@ msgid "" "<strong>use comments for discussions</strong> and <strong>please don't " "forget to vote :)</strong> for the answers that you liked (or perhaps did " "not like)!" -msgstr "" +msgstr "بإمكانك دائماً الإجابة على سؤالك، لكن تأكد أنك سو٠تقوم Ø¨Ø·Ø±Ø Ø¥Ø¬Ø§Ø¨Ø© كاملة وصØÙŠØØ©. علماً انه يمكنك دائماً مراجعة وتعديل صيغة سؤالك الأصلي وضاÙØ© المزيد من المعلومات Ùيه أو كتابتها على شكل تعليق. Ùضلاً <strong>أستخدم التعليقات للنقاش</strong> ويرجى <strong>التصويت للإجابات الصØÙŠØØ©</strong> دائماً، ايضاً صوت بالسالب على الإجابات الخاطئة، Øيث ان التصويت يساعد المØتوى الجيد على الظهور بترتيب اÙضل وهذا يساعد الغير ÙÙŠ الØصول على المعلومة بشكل اسرع." #: templates/question/new_answer_form.html:34 msgid "" @@ -6671,15 +6672,15 @@ msgid "" " your answers</strong> - no need to answer the same question twice. Also, " "please <strong>don't forget to vote</strong> - it really helps to select the" " best questions and answers!" -msgstr "" +msgstr "Øاول قدر الإمكان ان تعطي إجابة كاملة دقيقة Øول السؤال، الإجابات الصØÙŠØØ© والدقيقة دائماً تأخذ تصويت اعلى، واهتم جيداً بالتنسيق. <strong>للنقاش أستخدم خاصية التعليقات على السؤال او الإجابة</strong>. كما يرجى <strong>التصويت للإجابات الصØÙŠØØ©</strong> دائماً، ايضاً صوت بالسالب على الإجابات الخاطئة، التصويت يساعد المØتوى الجيد على الظهور وبالتالي ايجاد المعلومة الصØÙŠØØ© من قبل الغير بشكل اسرع. كن مساهم إيجابي!" #: templates/question/new_answer_form.html:39 msgid "Add answer" -msgstr "" +msgstr "أض٠إجابة" #: templates/question/question_controls.html:5 msgid "retag" -msgstr "" +msgstr "إعادة تعيين المواضيع" #: templates/question/question_controls.html:29 msgid "reopen" @@ -6687,31 +6688,31 @@ msgstr "إعادة ÙتØ" #: templates/question/question_controls.html:31 msgid "close" -msgstr "غلق" +msgstr "إغلاق" #: templates/question/sidebar.html:8 msgid "Question tools" -msgstr "" +msgstr "أدوات السؤال" #: templates/question/sidebar.html:11 msgid "click to unfollow this question" -msgstr "انقر لإلغاء المتابعة" +msgstr "أضغط هنا لإلغاء المتابعة" #: templates/question/sidebar.html:12 msgid "Following" -msgstr "متابع" +msgstr "Ù…Ùتابع" #: templates/question/sidebar.html:13 msgid "Unfollow" -msgstr "إيقا٠المتابعة" +msgstr "إلغاء المتابعة" #: templates/question/sidebar.html:17 msgid "click to follow this question" -msgstr "أنقر لمتابعة هذا السؤال" +msgstr "أضغط هنا لمتابعة هذا السؤال" #: templates/question/sidebar.html:18 msgid "Follow" -msgstr "متابعة" +msgstr "تابع" #: templates/question/sidebar.html:25 #, python-format @@ -6726,15 +6727,15 @@ msgstr[5] "" #: templates/question/sidebar.html:33 msgid "subscribe to this question rss feed" -msgstr "" +msgstr "متابعة هذا السؤال عبر خلاصات RSS" #: templates/question/sidebar.html:34 msgid "subscribe to rss feed" -msgstr "" +msgstr "الإشتراك بخلاصة RSS" #: templates/question/sidebar.html:44 msgid "Invite" -msgstr "" +msgstr "دعوة" #: templates/question/sidebar.html:50 templates/question/sidebar.html.py:56 #: templates/user_profile/user_email_subscriptions.html:59 @@ -6742,11 +6743,11 @@ msgstr "" #: templates/widgets/tag_selector.html:37 #: templates/widgets/tag_selector.html:56 msgid "add" -msgstr "إضاÙØ©" +msgstr "أضÙ" #: templates/question/sidebar.html:52 templates/question/sidebar.html.py:58 msgid "- or -" -msgstr "" +msgstr "- أو -" #: templates/question/sidebar.html:70 msgid "share with everyone" @@ -6762,16 +6763,16 @@ msgstr "" #: templates/question/sidebar.html:88 msgid "You" -msgstr "" +msgstr "أنت" #: templates/question/sidebar.html:95 templates/question/sidebar.html:115 msgid "and" -msgstr "" +msgstr "Ùˆ" #: templates/question/sidebar.html:120 #, python-format msgid "%(more_count)s more" -msgstr "" +msgstr "%(more_count)s المزيد" #: templates/question/sidebar.html:126 msgid "Public thread" @@ -6785,35 +6786,35 @@ msgstr "" #: templates/question/sidebar.html:135 msgid "Stats" -msgstr "Ø¥Øصائيات" +msgstr "Ø¥Øصاءات" #: templates/question/sidebar.html:137 msgid "Asked" -msgstr "" +msgstr "سأل" #: templates/question/sidebar.html:140 msgid "Seen" -msgstr "" +msgstr "شوهد" #: templates/question/sidebar.html:140 msgid "times" -msgstr "مرات" +msgstr "مرة" #: templates/question/sidebar.html:143 msgid "Last updated" -msgstr "آخر تØديث" +msgstr "آخر تعديل" #: templates/question/sidebar.html:151 msgid "Related questions" -msgstr "الأسئلة المرتبطة" +msgstr "أسئلة ذات صلة" #: templates/tags/form_bulk_tag_subscription.html:4 msgid "Tag subscriptions" -msgstr "" +msgstr "الإشتراك بالمواضيع" #: templates/tags/form_bulk_tag_subscription.html:6 msgid "Tag Subscriptions" -msgstr "" +msgstr "الإشتراك بالمواضيع" #: templates/tags/header.html:7 #, python-format @@ -6822,19 +6823,19 @@ msgstr "" #: templates/tags/header.html:19 msgid "sorted alphabetically" -msgstr "" +msgstr "ترتيب أبجدي" #: templates/tags/header.html:20 msgid "by name" -msgstr "بالاسم" +msgstr "الأسم" #: templates/tags/header.html:25 msgid "sorted by frequency of tag use" -msgstr "" +msgstr "الترتيب بمعدل إستخدام الموضوع بالأسئلة" #: templates/tags/header.html:26 msgid "by popularity" -msgstr "بالشعبية" +msgstr "الشعبية" #: templates/tags/header.html:34 templates/tags/header.html.py:35 msgid "suggested" @@ -6842,39 +6843,39 @@ msgstr "" #: templates/tags/header.html:42 templates/tags/header.html.py:43 msgid "manage subscriptions" -msgstr "" +msgstr "إدارة الإشتراكات" #: templates/tags/list_bulk_tag_subscription.html:4 msgid "Manage Tag subscriptions" -msgstr "" +msgstr "إدارة إشتراكات المواضيع" #: templates/tags/list_bulk_tag_subscription.html:6 msgid "Manage Tag subscription</a> " -msgstr "" +msgstr "إدارة إشتراكات المواضيع</a> " #: templates/tags/list_bulk_tag_subscription.html:6 msgid "Create New" -msgstr "" +msgstr "إنشاء جديد" #: templates/tags/list_bulk_tag_subscription.html:11 msgid "Date" -msgstr "" +msgstr "التاريخ" #: templates/tags/list_bulk_tag_subscription.html:17 msgid "Action" -msgstr "" +msgstr "الÙعل" #: templates/tags/list_bulk_tag_subscription.html:48 views/commands.py:759 msgid "Edit" -msgstr "" +msgstr "تعديل" #: templates/user_inbox/base.html:14 msgid "Sections:" -msgstr "أقسام:" +msgstr "الأقسام:" #: templates/user_inbox/base.html:19 msgid "messages" -msgstr "" +msgstr "الرسائل" #: templates/user_inbox/base.html:24 #, python-format @@ -6896,27 +6897,27 @@ msgstr "" #: templates/user_inbox/group_join_requests.html:26 msgid "Approve" -msgstr "" +msgstr "صرØ" #: templates/user_inbox/group_join_requests.html:41 msgid "Deny" -msgstr "" +msgstr "Ø£Øجب" #: templates/user_inbox/messages.html:104 msgid "inbox - messages" -msgstr "" +msgstr "صندوق الرسائل" #: templates/user_inbox/responses_and_flags.html:4 msgid "inbox - responses" -msgstr "" +msgstr "صندوق الردود" #: templates/user_inbox/responses_and_flags.html:8 msgid "select:" -msgstr "تØديد:" +msgstr "إختيار:" #: templates/user_inbox/responses_and_flags.html:10 msgid "seen" -msgstr "" +msgstr "شوهد" #: templates/user_inbox/responses_and_flags.html:11 msgid "new" @@ -6924,11 +6925,11 @@ msgstr "جديد" #: templates/user_inbox/responses_and_flags.html:12 msgid "none" -msgstr "لا شئ" +msgstr "لاشيء" #: templates/user_inbox/responses_and_flags.html:15 msgid "mark as seen" -msgstr "تعليم كمشاهد" +msgstr "تعليم كشوهد" #: templates/user_inbox/responses_and_flags.html:16 msgid "mark as new" @@ -6936,7 +6937,7 @@ msgstr "تعليم كجديد" #: templates/user_inbox/responses_and_flags.html:17 msgid "dismiss" -msgstr "" +msgstr "تم الإطلاع" #: templates/user_inbox/responses_and_flags.html:19 msgid "remove flags/approve" @@ -6966,27 +6967,27 @@ msgstr "" #: templates/user_profile/reject_post_dialog.html:27 #: templates/user_profile/reject_post_dialog.html:95 msgid "Use other reason" -msgstr "" +msgstr "إختيار سبب آخر" #: templates/user_profile/reject_post_dialog.html:33 msgid "Save reason, but do not reject" -msgstr "" +msgstr "Ø£ØÙظ السبب دون ان ترÙض" #: templates/user_profile/reject_post_dialog.html:43 msgid "Please, choose a reason for the rejection." -msgstr "" +msgstr "يرجى إختيار سبب لهذا الرÙض." #: templates/user_profile/reject_post_dialog.html:58 msgid "Select this reason" -msgstr "" +msgstr "إختيار هذا السبب" #: templates/user_profile/reject_post_dialog.html:65 msgid "Delete this reason" -msgstr "" +msgstr "Øذ٠هذا السبب" #: templates/user_profile/reject_post_dialog.html:71 msgid "Add a new reason" -msgstr "" +msgstr "أض٠سبب جديد" #: templates/user_profile/reject_post_dialog.html:81 msgid "" @@ -6997,7 +6998,7 @@ msgstr "" #: templates/user_profile/reject_post_dialog.html:101 msgid "Edit this reason" -msgstr "" +msgstr "تعديل هذا السبب" #: templates/user_profile/twitter_sharing_controls.html:8 #, python-format @@ -7006,45 +7007,45 @@ msgstr "" #: templates/user_profile/twitter_sharing_controls.html:19 msgid "stop tweeting" -msgstr "" +msgstr "إيقا٠التغريد" #: templates/user_profile/twitter_sharing_controls.html:23 msgid "Auto-tweeting is inactive" -msgstr "" +msgstr "التغريد التلقائي معطل" #: templates/user_profile/twitter_sharing_controls.html:26 msgid "Select twitter account" -msgstr "" +msgstr "إختيار Øساب تويتر" #: templates/user_profile/twitter_sharing_controls.html:28 msgid "use another account" -msgstr "" +msgstr "إستخدام Øساب آخر" #: templates/user_profile/twitter_sharing_controls.html:32 msgid "Auto-tweeting is off" -msgstr "" +msgstr "التغريد التلقائي موقÙ" #: templates/user_profile/twitter_sharing_controls.html:33 msgid "Start tweeting" -msgstr "" +msgstr "إبدأ بالتغريد" #: templates/user_profile/user.html:12 #, python-format msgid "%(username)s's profile" -msgstr "صÙØØ© %(username)s" +msgstr "الصÙØØ© الشخصية للعضو %(username)s" #: templates/user_profile/user_edit.html:4 msgid "Edit user profile" -msgstr "تØرير صÙØتك الخاصة" +msgstr "تعديل المل٠العضو الشخصي" #: templates/user_profile/user_edit.html:7 msgid "edit profile" -msgstr "تØرير المل٠الشخصي:" +msgstr "تعديل المل٠الشخصي" #: templates/user_profile/user_edit.html:21 #: templates/user_profile/user_info.html:14 msgid "change picture" -msgstr "تغيير الصورة" +msgstr "تعديل الصورة" #: templates/user_profile/user_edit.html:25 #: templates/user_profile/user_info.html:18 @@ -7057,11 +7058,11 @@ msgstr "عضو مسجل" #: templates/user_profile/user_edit.html:39 msgid "Screen Name" -msgstr "الاسم الظاهر" +msgstr "أسم المستخدم" #: templates/user_profile/user_edit.html:59 msgid "(cannot be changed)" -msgstr "(لا يمكن تعديلها)" +msgstr "(لا يمكن تعديلة)" #: templates/user_profile/user_edit.html:109 #: templates/user_profile/user_email_subscriptions.html:23 @@ -7071,11 +7072,11 @@ msgstr "تØديث" #: templates/user_profile/user_email_subscriptions.html:5 #: templates/user_profile/user_tabs.html:44 msgid "subscriptions" -msgstr "إشتراكات" +msgstr "النشرات والتنبيهات" #: templates/user_profile/user_email_subscriptions.html:8 msgid "Email subscription settings" -msgstr "" +msgstr "إعدادات النشرات والتنبيهات البريدية" #: templates/user_profile/user_email_subscriptions.html:10 msgid "" @@ -7084,7 +7085,7 @@ msgid "" "community</strong> by answering questions of your colleagues. If you do not " "wish to receive emails - select 'no email' on all items below.<br/>Updates " "are only sent when there is any new activity on selected items." -msgstr "" +msgstr "ÙÙŠ هذه الصÙØØ© يمكنك إدارة إشتراكات البريد ومعدل إرسال التنبيهات على بريدك. التنبيهات التي تصلك هي غالباً Øول الأسئلة التي أنت مهتم بها Øسب نوع مشاركتك معها، وتعتبر وسيلة جيدة لمتابعة هذه الأسئلة والبقاء على تØديث Øول مايØدث Ùيها. لن تصلك رسالة مالم يكن هناك جديد، <b>لا يتم إرسال نشرات دعائية ابداً، Ù†ØÙ† لا Ù†Øب هذا الامر، مثلك تمامأً</b>. " #: templates/user_profile/user_email_subscriptions.html:24 msgid "Stop Email" @@ -7096,7 +7097,7 @@ msgstr "" #: templates/user_profile/user_email_subscriptions.html:43 msgid "Save languages" -msgstr "" +msgstr "ØÙظ اللغات" #: templates/user_profile/user_email_subscriptions.html:48 msgid "Subscribed Tags" @@ -7105,27 +7106,27 @@ msgstr "" #: templates/user_profile/user_favorites.html:4 #: templates/user_profile/user_tabs.html:29 msgid "followed questions" -msgstr "" +msgstr "الأسئلة المÙتابعة" #: templates/user_profile/user_info.html:37 msgid "update profile" -msgstr "" +msgstr "تعديل المل٠الشخصي" #: templates/user_profile/user_info.html:41 msgid "manage login methods" -msgstr "" +msgstr "إدارة وسائل الدخول" #: templates/user_profile/user_info.html:54 msgid "real name" -msgstr "الاسم الØقيقي" +msgstr "الأسم الØقيقي" #: templates/user_profile/user_info.html:60 msgid "groups" -msgstr "" +msgstr "المجموعات" #: templates/user_profile/user_info.html:71 msgid "add group" -msgstr "" +msgstr "أض٠مجموعة" #: templates/user_profile/user_info.html:77 msgid "member since" @@ -7133,7 +7134,7 @@ msgstr "عضو منذ" #: templates/user_profile/user_info.html:82 msgid "last seen" -msgstr "" +msgstr "أخر تواجد" #: templates/user_profile/user_info.html:88 msgid "website" @@ -7141,7 +7142,7 @@ msgstr "الموقع" #: templates/user_profile/user_info.html:101 msgid "location" -msgstr "المكان" +msgstr "الموقع الجغراÙÙŠ" #: templates/user_profile/user_info.html:108 msgid "age" @@ -7150,56 +7151,56 @@ msgstr "العمر" #: templates/user_profile/user_info.html:109 #, python-format msgid "%(age)s years old" -msgstr "" +msgstr "%(age)s سنة" #: templates/user_profile/user_info.html:114 msgid "todays unused votes" -msgstr "" +msgstr "أصوات اليوم الغير مستخدمة" #: templates/user_profile/user_info.html:115 msgid "votes left" -msgstr "الأصوات المتبقية" +msgstr "صوت" #: templates/user_profile/user_moderate.html:4 #: templates/user_profile/user_tabs.html:50 msgid "moderation" -msgstr "" +msgstr "الإشراÙ" #: templates/user_profile/user_moderate.html:8 #, python-format msgid "%(username)s's current status is \"%(status)s\"" -msgstr "" +msgstr "%(username)s Øالته Øالياً هي \"%(status)s\"" #: templates/user_profile/user_moderate.html:11 msgid "User status changed" -msgstr "" +msgstr "تم تغيير Øالة العضو" #: templates/user_profile/user_moderate.html:25 #, python-format msgid "Your current reputation is %(reputation)s points" -msgstr "" +msgstr "قوة سمعتك Øالياً %(reputation)s نقطة" #: templates/user_profile/user_moderate.html:27 #, python-format msgid "User's current reputation is %(reputation)s points" -msgstr "" +msgstr "قوة سمعة العضو Øالياً %(reputation)s نقطة" #: templates/user_profile/user_moderate.html:31 msgid "User reputation changed" -msgstr "" +msgstr "تم تعديل سمعة العضو" #: templates/user_profile/user_moderate.html:38 msgid "Subtract" -msgstr "" +msgstr "نقص" #: templates/user_profile/user_moderate.html:39 msgid "Add" -msgstr "إضاÙØ©" +msgstr "أضÙ" #: templates/user_profile/user_moderate.html:43 #, python-format msgid "Send message to %(username)s" -msgstr "" +msgstr "إرسال رسالة للعضو %(username)s" #: templates/user_profile/user_moderate.html:44 msgid "" @@ -7209,11 +7210,11 @@ msgstr "" #: templates/user_profile/user_moderate.html:46 msgid "Message sent" -msgstr "تم الإرسال" +msgstr "الرسالة أرسلت" #: templates/user_profile/user_moderate.html:64 msgid "Send message" -msgstr "أرسل الرسالة" +msgstr "إرسال رسالة" #: templates/user_profile/user_moderate.html:74 msgid "" @@ -7245,7 +7246,7 @@ msgstr "" #: templates/user_profile/user_network.html:5 #: templates/user_profile/user_tabs.html:18 msgid "network" -msgstr "شبكة" +msgstr "شبكة المتابعة" #: templates/user_profile/user_network.html:10 #, python-format @@ -7273,18 +7274,18 @@ msgstr[5] "" msgid "" "Your network is empty. Would you like to follow someone? - Just visit their " "profiles and click \"follow\"" -msgstr "" +msgstr "شبكتك Ùارغة Øالياً. هل تريد متابعة عضو ما؟ تصÙØ Ù…Ù„ÙÙ‡ الشخصي واضغط على زر (تابع)" #: templates/user_profile/user_network.html:33 #, python-format msgid "%(username)s's network is empty" -msgstr "" +msgstr "شبكة %(username)s Ùارغة" #: templates/user_profile/user_recent.html:5 #: templates/user_profile/user_tabs.html:31 #: templates/user_profile/user_tabs.html:33 msgid "activity" -msgstr "نشاط" +msgstr "سجل التÙاعل" #: templates/user_profile/user_recent.html:23 #: templates/user_profile/user_recent.html:27 @@ -7293,12 +7294,12 @@ msgstr "مصدر" #: templates/user_profile/user_reputation.html:12 msgid "Your karma change log." -msgstr "" +msgstr "سجل تغيرات السمعة" #: templates/user_profile/user_reputation.html:14 #, python-format msgid "%(user_name)s's karma change log" -msgstr "" +msgstr "سجل تغيرات سمعة %(user_name)s" #: templates/user_profile/user_stats.html:6 #: templates/user_profile/user_tabs.html:7 @@ -7365,45 +7366,45 @@ msgstr "مجاب لـ:" #: templates/user_profile/user_tabs.html:5 msgid "User profile" -msgstr "المل٠الشخصي للمستخدم" +msgstr "مل٠العضو" #: templates/user_profile/user_tabs.html:10 views/users.py:819 msgid "comments and answers to others questions" -msgstr "" +msgstr "التعليق والإجابة على أسئلة الأخرين" #: templates/user_profile/user_tabs.html:16 msgid "followers and followed users" -msgstr "" +msgstr "الأعضاء المتابعين والمÙتابعون" #: templates/user_profile/user_tabs.html:22 msgid "Graph of user karma" -msgstr "الرسم البياني لمستخدم النقاط" +msgstr "رسم بياني لسمعة العضو" #: templates/user_profile/user_tabs.html:27 msgid "questions that user is following" -msgstr "" +msgstr "الأسئلة التي يتابعها العضو" #: templates/user_profile/user_tabs.html:36 views/users.py:861 msgid "user vote record" -msgstr "" +msgstr "سجل أصوات العضو" #: templates/user_profile/user_tabs.html:38 #: templates/user_profile/user_votes.html:5 msgid "votes" -msgstr "أصوات" +msgstr "الأصوات" #: templates/user_profile/user_tabs.html:42 views/users.py:973 msgid "email subscription settings" -msgstr "" +msgstr "إعدادات نشرات وتنبيهات البريد" #: templates/user_profile/user_tabs.html:48 views/users.py:286 msgid "moderate this user" -msgstr "" +msgstr "الإشرا٠على هذا العضو" #: templates/user_profile/users_answers.html:7 #, python-format msgid "the answer has been voted for %(answer_score)s times" -msgstr "" +msgstr "تم التصويت على الإجابة %(answer_score)s مرة" #: templates/user_profile/users_answers.html:17 #, python-format @@ -7419,43 +7420,43 @@ msgstr[5] "" #: templates/widgets/answer_edit_tips.html:3 #: templates/widgets/question_edit_tips.html:3 msgid "Tips" -msgstr "إرشادات" +msgstr "نصائØ" #: templates/widgets/answer_edit_tips.html:6 msgid "give an answer interesting to this community" -msgstr "" +msgstr "أعطي جواب يهم هذا المجتمع" #: templates/widgets/answer_edit_tips.html:9 msgid "try to give an answer, rather than engage into a discussion" -msgstr "Øاول إعطاء جواب، بدلاً من الانخراط ÙÙŠ نقاش" +msgstr "Øاول أن تعطي إجابة شاÙية، بدل من الدخول ÙÙŠ نقاش Øول السؤال او موضوعة" #: templates/widgets/ask_button.html:9 msgid "Ask the Group" -msgstr "" +msgstr "أسأل المجموعة" #: templates/widgets/ask_form.html:22 templates/widgets/ask_form.html.py:24 msgid "Add details (optional)" -msgstr "" +msgstr "أضاÙØ© التÙاصيل (إختياري)" #: templates/widgets/ask_form.html:26 msgid "Add details" -msgstr "" +msgstr "إضاÙØ© التÙاصيل" #: templates/widgets/ask_form.html:59 msgid "Select language" -msgstr "" +msgstr "إختيار اللغة" #: templates/widgets/contributors.html:3 msgid "Contributors" -msgstr "المساهمين" +msgstr "المساهمون" #: templates/widgets/edit_post.html:33 msgid ", one of these is required" -msgstr "" +msgstr "ØŒ واØدة من هذه مطلوبة" #: templates/widgets/edit_post.html:42 templates/widgets/edit_post.html:47 msgid "tags:" -msgstr "" +msgstr "المواضيع:" #: templates/widgets/edit_post.html:43 msgid "(required)" @@ -7469,7 +7470,7 @@ msgstr "" msgid "" "To post on behalf of someone else, enter user name <strong>and</strong> " "email below." -msgstr "" +msgstr "للنشر بالنيابة عن عضو أخر، يرجى كتابة أسم المستخدم والبريد بالأسÙÙ„." #: templates/widgets/footer.html:33 #, python-format @@ -7478,7 +7479,7 @@ msgstr "هذا الموقع مرخص تØت %(license)s" #: templates/widgets/footer.html:38 msgid "about" -msgstr "عن" +msgstr "عن الموقع" #: templates/widgets/footer.html:40 templates/widgets/user_navigation.html:26 msgid "help" @@ -7486,31 +7487,31 @@ msgstr "مساعدة" #: templates/widgets/footer.html:42 msgid "privacy policy" -msgstr "av,' hgow,wdm" +msgstr "بيان الخصوصية" #: templates/widgets/footer.html:51 msgid "give feedback" -msgstr "إبداء رأيك" +msgstr "مقترØات" #: templates/widgets/group_info.html:3 msgid "Group info" -msgstr "" +msgstr "معلومات المجموعة" #: templates/widgets/group_info.html:26 msgid "edit description" -msgstr "" +msgstr "تعديل الوصÙ" #: templates/widgets/group_info.html:30 msgid "change logo" -msgstr "" +msgstr "تعديل اللوجو" #: templates/widgets/group_info.html:32 msgid "delete logo" -msgstr "" +msgstr "Øذ٠اللوجو" #: templates/widgets/group_info.html:36 msgid "add logo" -msgstr "" +msgstr "أض٠لوجو" #: templates/widgets/group_info.html:46 msgid "moderate emailed questions" @@ -7522,7 +7523,7 @@ msgstr "" #: templates/widgets/group_info.html:63 msgid "How users join this group?" -msgstr "" +msgstr "كي٠ينضم الأعضاء لهذه المجموعة؟" #: templates/widgets/group_info.html:87 msgid "Can moderate site" @@ -7530,7 +7531,7 @@ msgstr "" #: templates/widgets/group_info.html:97 msgid "Allow only read access" -msgstr "" +msgstr "Ø§Ù„Ø³Ù…Ø§Ø Ùقط بالقراءة" #: templates/widgets/group_info.html:102 msgid "list of email addresses of pre-approved users" @@ -7574,32 +7575,32 @@ msgstr "العودة للرئيسية" #: templates/widgets/logo.html:4 #, python-format msgid "%(site)s logo" -msgstr "الشعار %(site)s" +msgstr "لوجو %(site)s" #: templates/widgets/markdown_help.html:2 msgid "Markdown basics" -msgstr "أساسيات Markdown" +msgstr "أساسيات المØرر" #: templates/widgets/markdown_help.html:6 msgid "*italic*" -msgstr "*مائل*" +msgstr "*نص مائل هنا*" #: templates/widgets/markdown_help.html:9 msgid "**bold**" -msgstr "**غليظ**" +msgstr "**نص بارز هنا**" #: templates/widgets/markdown_help.html:13 msgid "*italic* or _italic_" -msgstr "*مائل* أو _مائل_" +msgstr "*italic* أو _italic_" #: templates/widgets/markdown_help.html:16 msgid "**bold** or __bold__" -msgstr "**غليظ** أو __غليظ__" +msgstr "**bold** او __bold__" #: templates/widgets/markdown_help.html:20 #: templates/widgets/markdown_help.html:24 msgid "text" -msgstr "نص" +msgstr "text" #: templates/widgets/markdown_help.html:24 msgid "image" @@ -7611,27 +7612,27 @@ msgstr "قائمة مرقمة:" #: templates/widgets/markdown_help.html:33 msgid "basic HTML tags are also supported" -msgstr "" +msgstr "بعض وسوم HTML البسيطة Ù…Ø³Ù…ÙˆØ Ø¨Ù‡Ø§" #: templates/widgets/markdown_help.html:38 msgid "learn more about Markdown" -msgstr "معرÙØ© المزيد عن Markdown" +msgstr "أعر٠المزيد Øول Ù…Øرر Markdown" #: templates/widgets/meta_nav.html:12 msgid "people & groups" -msgstr "" +msgstr "الأعضاء والمجموعات" #: templates/widgets/meta_nav.html:20 msgid "users" -msgstr "مستخدمين" +msgstr "الأعضاء" #: templates/widgets/meta_nav.html:27 msgid "badges" -msgstr "شارات" +msgstr "أوسمة الأعضاء" #: templates/widgets/question_edit_tips.html:5 msgid "ask a question interesting to this community" -msgstr "Ø§Ø·Ø±Ø Ø³Ø¤Ø§Ù„ مهم ÙÙŠ هذا المجتمع" +msgstr "Ø£Ø·Ø±Ø Ø³Ø¤Ø§Ù„ يخص هذا المجتمع" #: templates/widgets/question_summary.html:12 msgid "view" @@ -7669,31 +7670,31 @@ msgstr "الكل" #: templates/widgets/scope_nav.html:22 msgid "see unanswered questions" -msgstr "أنظر الأسئلة الغير مجابة" +msgstr "مشاهدة الأسئلة الغير مجاب عليها بعد. Ùضلاً ساعدنا بالإجابة عليها" #: templates/widgets/scope_nav.html:22 msgid "UNANSWERED" -msgstr "غير مجاب" +msgstr "غير مجابة" #: templates/widgets/scope_nav.html:27 msgid "see your followed questions" -msgstr "أنظر للأسئلة التي تتابعها" +msgstr "مشاهدة الأسئلة التي تهمك وقد قمت بمتابتعها او التÙاعل معها" #: templates/widgets/scope_nav.html:27 msgid "FOLLOWED" -msgstr "تتم متابعته" +msgstr "المتابعة" #: templates/widgets/scope_nav.html:30 msgid "Please ask your question here" -msgstr "قم بالسؤال هنا من Ùضلك" +msgstr "يمكنك كتابة سؤالك هنا" #: templates/widgets/tag_selector.html:4 msgid "Interesting tags" -msgstr "" +msgstr "المواضيع المهمة" #: templates/widgets/tag_selector.html:22 msgid "Ignored tags" -msgstr "" +msgstr "المواضيع الغير مهمة" #: templates/widgets/tag_selector.html:40 msgid "Subscribed tags" @@ -7701,11 +7702,11 @@ msgstr "" #: templates/widgets/tag_selector.html:59 msgid "Show only questions from" -msgstr "" +msgstr "أظهر Ùقط الأسئلة من" #: templates/widgets/tag_selector.html:70 msgid "Send me email alerts for" -msgstr "" +msgstr "أرسل لي تنبيهات بالبريد بخصوص" #: templates/widgets/tag_selector.html:86 msgid "Change frequency of emails" @@ -7726,27 +7727,27 @@ msgstr "" #: templates/widgets/three_column_category_selector.html:9 #: templates/widgets/three_column_category_selector.html:11 msgid "(edit categories)" -msgstr "" +msgstr "(تعديل التصانيÙ)" #: templates/widgets/user_long_score_and_badge_summary.html:3 msgid "read only access" -msgstr "" +msgstr "صلاØية القراءة Ùقط" #: templates/widgets/user_long_score_and_badge_summary.html:10 msgid "karma:" -msgstr "نقاط:" +msgstr "السمعة:" #: templates/widgets/user_long_score_and_badge_summary.html:15 msgid "badges:" -msgstr "الشارات:" +msgstr "الأوسمة:" #: templates/widgets/user_navigation.html:17 msgid "sign out" -msgstr "تسجيل الخروج" +msgstr "تسجيل خروج" #: templates/widgets/user_navigation.html:20 msgid "Hi there! Please sign in" -msgstr "" +msgstr "تسجيل دخول" #: templates/widgets/user_navigation.html:23 msgid "settings" @@ -7759,34 +7760,34 @@ msgstr "" #: templates/widgets/user_perms.html:1 #, python-format msgid "Your karma is %(karma)s" -msgstr "" +msgstr "قوة سمعتك %(karma)s" #: templates/widgets/user_perms.html:4 msgid "Karma reflects the value of your contribution to this community." -msgstr "" +msgstr "نقاط السمعة هي مقياس لمدى مساهمتك ÙÙŠ بناء هذا المجتمع، ومدى Ùائدتك له." #: templates/widgets/user_perms.html:13 #, python-format msgid "" "Since you are the site %(role)s, you have access to all functions regardless" " of your karma." -msgstr "" +msgstr "بسبب أنك %(role)s ÙÙŠ هذا المجتمع، لك إمكانية إستخدام جميع الصلاØيات، عدى التØكم بمعدل سمعتك." #: templates/widgets/user_perms.html:15 msgid "The higher is your karma, the more rights you have on this site." -msgstr "" +msgstr "كل مازادت نقاط سمعتك كل مازادت صلاØياتك ÙÙŠ هذا المجتمع." #: templates/widgets/user_perms.html:19 msgid "Currently, you can:" -msgstr "" +msgstr "Øالياً، لديك الصلاØيات على" #: templates/widgets/user_perms.html:21 msgid "Post questions, answers and comments" -msgstr "" +msgstr "نشر أسئلة، أجوبة وتعليقات" #: templatetags/extra_filters_jinja.py:332 msgid "no" -msgstr "كلا" +msgstr "0" #: utils/decorators.py:104 views/commands.py:146 msgid "Oops, apologies - there was some error" @@ -7794,7 +7795,7 @@ msgstr "" #: utils/decorators.py:123 msgid "Please login to post" -msgstr "قم بالدخول للإرسال" +msgstr "يرجى تسجيل الدخول للنشر" #: utils/decorators.py:219 msgid "Spam was detected on your post, sorry for if this is a mistake" @@ -7802,7 +7803,7 @@ msgstr "" #: utils/decorators.py:243 msgid "This function is limited to moderators and administrators" -msgstr "" +msgstr "هذه الصلاØية مقتصرة على المراقبين" #: utils/forms.py:66 msgid "this field is required" @@ -7810,23 +7811,23 @@ msgstr "هذا الØقل مطلوب" #: utils/forms.py:93 msgid "Choose a screen name" -msgstr "اختر اسم للظهور به" +msgstr "إختيار أسم مستخدم" #: utils/forms.py:103 msgid "user name is required" -msgstr "اسم المستخدم مطلوب" +msgstr "أسم العضو مطلوب" #: utils/forms.py:104 msgid "sorry, this name is taken, please choose another" -msgstr "عÙواً، الاسم مستخدم، اختر اسم آخر" +msgstr "المعذرة، هذا الأسم مستخدم، يرجى إختيار أسم آخر" #: utils/forms.py:105 msgid "sorry, this name is not allowed, please choose another" -msgstr "عÙواً، الاسم غير مقبول، اختر اسم آخر" +msgstr "المعذرة، هذا الأسم غير Ù…Ø³Ù…ÙˆØ Ø¨Ù‡ØŒ يرجى إختيار أسم آخر" #: utils/forms.py:106 msgid "sorry, there is no user with this name" -msgstr "عÙواً، لا يوجد اسم مستخدم بهذا الاسم" +msgstr "المعذرة، لا يوجد عضو بهذا الأسم" #: utils/forms.py:107 msgid "sorry, we have a serious error - user name is taken by several users" @@ -7834,19 +7835,19 @@ msgstr "" #: utils/forms.py:108 msgid "user name can only consist of letters, empty space and underscore" -msgstr "" +msgstr "أسم المستØدم ممكن أن يتكون من Ø£Øر٠ومساÙات Ùارغة Ùˆ علامة \"_\"" #: utils/forms.py:109 msgid "please use at least some alphabetic characters in the user name" -msgstr "" +msgstr "Ùضلا إستخدام بعض الأØر٠لأسم المستخدم/العضو" #: utils/forms.py:110 msgid "symbol \"@\" is not allowed" -msgstr "" +msgstr "علامة \"@\" غير Ù…Ø³Ù…ÙˆØ Ø¨Ù‡Ø§" #: utils/forms.py:222 msgid "Your email <i>(never shared)</i>" -msgstr "بريدك <i>(لن يتم نشره)</i>" +msgstr "بريدك <i>(غير ظاهر للغير)</i>" #: utils/forms.py:224 msgid "email address is required" @@ -7854,15 +7855,15 @@ msgstr "البريد مطلوب" #: utils/forms.py:225 msgid "please enter a valid email address" -msgstr "من Ùضلك قم بإختيار بريد صØÙŠØ" +msgstr "يرجى إدخال بريد صØÙŠØ" #: utils/forms.py:226 msgid "this email is already used by someone else, please choose another" -msgstr "هذا البريد مستخدم من قبل، اختر بريد آخر" +msgstr "هذا البريد مستخدم مسبقاً من قبل عضو آخر، يرجى إستخدام بريد آخر." #: utils/forms.py:227 msgid "this email address is not authorized" -msgstr "" +msgstr "هذا البريد غير Ù…ØµØ±Ø Ù„Ù‡" #: utils/forms.py:265 msgid "password is required" @@ -7870,19 +7871,19 @@ msgstr "كلمة المرور مطلوبة" #: utils/forms.py:268 msgid "Password <i>(please retype)</i>" -msgstr "كلمة المرور <i>(مرة أخري)</i>" +msgstr "كلمة المرور <i>(أعد كتابتها)</i>" #: utils/forms.py:269 msgid "please, retype your password" -msgstr "من Ùضلك، أعد كلمة المرور" +msgstr "Ùضلاً قم بإعادة كتابة كلمة المرور" #: utils/forms.py:270 msgid "sorry, entered passwords did not match, please try again" -msgstr "عÙواً، كلمة المرور ليست مطابقة التأكيد" +msgstr "المعذرة، كلمة المرور المدخولة غير متطابقة، يرجى التأكد وإعادة المØاولة" #: utils/functions.py:102 msgid "2 days ago" -msgstr "منذ يومان" +msgstr "منذ يومين" #: utils/functions.py:104 msgid "yesterday" @@ -7912,44 +7913,44 @@ msgstr[5] "منذ %(min)d دقائق" #: views/avatar_views.py:103 msgid "Successfully uploaded a new avatar." -msgstr "تم تØميل الصورة الجديدة." +msgstr "تم Ø¨Ù†Ø¬Ø§Ø Ø±Ùع صورة مصغرة جديدة." #: views/avatar_views.py:144 msgid "Successfully updated your avatar." -msgstr "تم Ø¨Ù†Ø¬Ø§Ø ØªØ¬Ø¯ÙŠØ« صورتك." +msgstr "تم Ø¨Ù†Ø¬Ø§Ø ØªØ¹Ø¯ÙŠÙ„ الصورة المصغرة." #: views/avatar_views.py:184 msgid "Successfully deleted the requested avatars." -msgstr "تم Øذ٠الصورة المطلوبة." +msgstr "تم Ø¨Ù†Ø¬Ø§Ø Øذ٠الصورة الرمزية" #: views/commands.py:123 msgid "your post was not accepted" -msgstr "" +msgstr "مشاركتك لم تقبل" #: views/commands.py:136 msgid "Sorry, but anonymous users cannot access the inbox" -msgstr "" +msgstr "المعذرة، الزوار لا يمكنهم الوصول لصندوق الوارد" #: views/commands.py:165 msgid "Sorry, anonymous users cannot vote" -msgstr "" +msgstr "الزوار لا يمكنهم التصويت" #: views/commands.py:182 msgid "Sorry you ran out of votes for today" -msgstr "عذرا،استنÙذت كل Ùرص التصويت لهذا اليوم" +msgstr "لقد أستنÙذت الØد الأقصى من الأصوات باليوم الواØد" #: views/commands.py:188 #, python-format msgid "You have %(votes_left)s votes left for today" -msgstr "" +msgstr "تبقى لديك %(votes_left)s صوت لهذا اليوم" #: views/commands.py:263 msgid "Sorry, something is not right here..." -msgstr "" +msgstr "المعذرة، شيء غير صØÙŠØ Ù‡Ù†Ø§..." #: views/commands.py:286 msgid "Sorry, but anonymous users cannot accept answers" -msgstr "" +msgstr "الزوار لا يمكنهم قبول الأجوبة" #: views/commands.py:396 #, python-format @@ -7964,7 +7965,7 @@ msgstr "" #: views/commands.py:628 msgid "Sorry, could not delete tag" -msgstr "" +msgstr "المعذرة، لا يمكن Øذ٠الموضوع" #: views/commands.py:701 #, python-format @@ -7974,7 +7975,7 @@ msgstr "" #: views/commands.py:710 #, python-format msgid "Please sign in to subscribe for: %(tags)s" -msgstr "" +msgstr "يرجى تسجيل الدخول للإشتراك بالموضوع %(tags)s" #: views/commands.py:729 msgid "Create" @@ -7982,16 +7983,16 @@ msgstr "" #: views/commands.py:959 msgid "Please sign in to vote" -msgstr "قم بالدخول للتصويت" +msgstr "يرجى تسجيل الدخول للتصويت" #: views/commands.py:980 msgid "Please sign in to delete/restore posts" -msgstr "" +msgstr "يرجى تسجيل الدخول Ù„ØØ°Ù/إستعادة هذه المشاركة" #: views/commands.py:1042 #, python-format msgid "Group %(name)s does not exist" -msgstr "" +msgstr "المجموعة %(name)s غير موجودة" #: views/commands.py:1408 views/commands.py:1441 msgid "Sorry, looks like sharing request was invalid" @@ -8000,7 +8001,7 @@ msgstr "" #: views/commands.py:1464 #, python-format msgid "%(user)s, welcome to group %(group)s!" -msgstr "" +msgstr "%(user)sØŒ مرØباً بك ÙÙŠ مجموعة %(group)s" #: views/commands.py:1521 msgid "Sorry, only thread moderators can use this function" @@ -8008,28 +8009,28 @@ msgstr "" #: views/commands.py:1536 msgid "The answer is now unpublished" -msgstr "" +msgstr "هذه الإجابة الآن غير منشورة" #: views/commands.py:1540 msgid "The answer is now published" -msgstr "" +msgstr "هذه الإجابة الآن منشورة" #: views/meta.py:47 #, python-format msgid "About %(site)s" -msgstr "عن الموقع %(site)s" +msgstr "عن %(site)s" #: views/meta.py:91 msgid "Please sign in or register to send your feedback" -msgstr "" +msgstr "Ùضلاً سجل دخول او سجل عضوية جديدة لإرسال مقترØاتك" #: views/meta.py:118 msgid "Q&A forum feedback" -msgstr "" +msgstr "المقترØات" #: views/meta.py:122 msgid "Thanks for the feedback!" -msgstr "شكراً لتعليقك!" +msgstr "شكراً على مقترØاتك!" #: views/meta.py:131 msgid "We look forward to hearing your feedback! Please, give it next time :)" @@ -8037,11 +8038,11 @@ msgstr "" #: views/meta.py:135 msgid "Privacy policy" -msgstr "شروط الخصوصية" +msgstr "بيان الخصوصية" #: views/meta.py:216 msgid "Suggested tags" -msgstr "" +msgstr "المواضيع المقترØØ©" #: views/readers.py:256 #, python-format @@ -8058,23 +8059,23 @@ msgstr "عÙوأ، التعليق تم ØØ°ÙÙ‡ Ùˆ لا يمكن الوصول Ø¥ #: views/users.py:287 msgid "moderate user" -msgstr "" +msgstr "إدارة المستخدم" #: views/users.py:529 msgid "user profile" -msgstr "مل٠المستخدم" +msgstr "المل٠الشخصي" #: views/users.py:530 msgid "user profile overview" -msgstr "مل٠المستخدم عامة" +msgstr "نظرة عامة للمل٠الشخصي للعضو" #: views/users.py:650 msgid "recent user activity" -msgstr "آخر الأنشطة للمستخدم" +msgstr "أخر أنشطة العضو" #: views/users.py:651 msgid "profile - recent activity" -msgstr "مل٠شخصي - آخر التØديثات" +msgstr "المل٠الشخصي - أخر الأنشطة" #: views/users.py:682 msgid "group joining requests" @@ -8082,15 +8083,15 @@ msgstr "" #: views/users.py:683 msgid "profile - moderation" -msgstr "" +msgstr "المل٠الشخصي - الإشراÙ" #: views/users.py:739 msgid "private messages" -msgstr "" +msgstr "الرسائل الخاصة" #: views/users.py:740 msgid "profile - messages" -msgstr "" +msgstr "المل٠الشخصي - الرسائل" #: views/users.py:820 msgid "profile - responses" @@ -8098,15 +8099,15 @@ msgstr "مل٠شخصي - الردود" #: views/users.py:862 msgid "profile - votes" -msgstr "مل٠شخصي - الأصوات" +msgstr "المل٠الشخصي - التصويت" #: views/users.py:883 msgid "user karma" -msgstr "نقاط المستخدم" +msgstr "عطاء العضو" #: views/users.py:884 msgid "Profile - User's Karma" -msgstr "مل٠شخصي - نقاط المستخدم" +msgstr "المل٠الشخصي - قوة سمعة العضو" #: views/users.py:902 msgid "users favorite questions" @@ -8114,11 +8115,11 @@ msgstr "الأسئلة المÙضلة للمستخدمين" #: views/users.py:903 msgid "profile - favorite questions" -msgstr "مل٠شخصي - الأسئلة المÙضلة" +msgstr "المل٠الشخصي - الأسئلة المÙضلة" #: views/users.py:944 views/users.py:948 msgid "changes saved" -msgstr "تم الØÙظ" +msgstr "تم ØÙظ التعديلات" #: views/users.py:954 msgid "email updates canceled" @@ -8126,7 +8127,7 @@ msgstr "تØديثات البريد ألغيت" #: views/users.py:974 msgid "profile - email subscriptions" -msgstr "مل٠شخصي - إشتراكات البريد" +msgstr "المل٠الشخصي - إشتراكات البريد" #: views/users.py:995 #, python-format @@ -8135,7 +8136,7 @@ msgstr "" #: views/writers.py:73 msgid "Sorry, anonymous users cannot upload files" -msgstr "عÙواً، لا يمكن للمستخدم المجهول تØميل أي ملÙات" +msgstr "المعذرة، الزوار لا يمكنهم رÙع الملÙات" #: views/writers.py:91 #, python-format @@ -8150,7 +8151,7 @@ msgstr "الجد الأقصي Ù„Øجم المل٠%(file_size)s كيلو Ø¨Ø§ÙŠØ #: views/writers.py:112 msgid "" "Error uploading file. Please contact the site administrator. Thank you." -msgstr "خطأ أثناء التØميل، قم بالإتصال بالمشر٠العام، شكراً لك." +msgstr "خطأ ÙÙŠ رÙع الملÙØŒ يرجى مراسلة إدارة المجتمع. شكراً." #: views/writers.py:209 msgid "" @@ -8163,7 +8164,7 @@ msgstr "<span class=\"strong big\">مرØباً بك يمكن إرسال Ø§Ù„Ø³Ø #: views/writers.py:582 msgid "Please log in to answer questions" -msgstr "من Ùضلك قم بالدخول لإجابة الأسئلة" +msgstr "Ùضلاً سجل دخول للإجابة على الأسئلة" #: views/writers.py:708 msgid "This content is forbidden" @@ -8171,7 +8172,7 @@ msgstr "" #: views/writers.py:717 msgid "Post not found" -msgstr "" +msgstr "لم يتم العثور على المشاركة" #: views/writers.py:725 #, python-format diff --git a/askbot/locale/ar/LC_MESSAGES/djangojs.mo b/askbot/locale/ar/LC_MESSAGES/djangojs.mo Binary files differindex 354fc455..39941002 100644 --- a/askbot/locale/ar/LC_MESSAGES/djangojs.mo +++ b/askbot/locale/ar/LC_MESSAGES/djangojs.mo diff --git a/askbot/locale/ar/LC_MESSAGES/djangojs.po b/askbot/locale/ar/LC_MESSAGES/djangojs.po index 38a926ec..66d8d8bc 100644 --- a/askbot/locale/ar/LC_MESSAGES/djangojs.po +++ b/askbot/locale/ar/LC_MESSAGES/djangojs.po @@ -11,8 +11,8 @@ msgstr "" "Project-Id-Version: askbot\n" "Report-Msgid-Bugs-To: http://askbot.org/\n" "POT-Creation-Date: 2013-07-13 14:07-0500\n" -"PO-Revision-Date: 2013-07-20 23:44+0000\n" -"Last-Translator: Ahmad Khayyat <akhayyat@gmail.com>\n" +"PO-Revision-Date: 2013-09-10 07:48+0000\n" +"Last-Translator: mustafaalbazy <mustafa@albazy.com>\n" "Language-Team: Arabic (http://www.transifex.com/projects/p/askbot/language/ar/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -155,7 +155,7 @@ msgstr[5] "" #: media/js/post.js:154 media/js/post.js.c:1269 msgid "tags cannot be empty" -msgstr "" +msgstr "Ùضلاً Øدد المواضيع (مطلوب)" #: media/js/post.js:160 msgid "details are required" @@ -279,7 +279,7 @@ msgstr[5] "" #: media/js/post.js:845 msgid "<div>Following</div><div class=\"unfollow\">Unfollow</div>" -msgstr "" +msgstr "<div>Ù…Ùتابع</div><div class=\"unfollow\">إلغاء المتابعة</div>" #: media/js/post.js:901 msgid "remove flag" @@ -299,7 +299,7 @@ msgstr "تم Øذ٠المشاركة" #: media/js/post.js:1218 media/js/post.js.c:1445 msgid "sorry, something is not right here" -msgstr "" +msgstr "عذراً، شيء غير صØÙŠØ Ù‡Ù†Ø§" #: media/js/post.js:1665 msgid "add comment" @@ -326,7 +326,7 @@ msgstr "" #: media/js/post.js:1823 msgid "minor edit (don't send alerts)" -msgstr "" +msgstr "تعديل بسيط (لا ترسل تنبيهات بريد)" #: media/js/post.js:1855 msgid "Are you sure you don't want to post this comment?" @@ -501,7 +501,7 @@ msgstr "انظر هل يوجد شئ لتصليØÙ‡ :" #: media/js/user.js:443 msgid "Please provide description." -msgstr "" +msgstr "Ùضل ضع وصÙ." #: media/js/user.js:446 msgid "Please provide details." @@ -513,7 +513,7 @@ msgstr "يجب ان تختار سبب Ù„Øذ٠الاخر " #: media/js/user.js:659 msgid "A reason must be selected to reject post." -msgstr "" +msgstr "يجب إختيار سبب لرÙض المشاركة." #: media/js/user.js:708 msgid "Please <a href=\"%(signin_url)s\">signin</a> to follow %(username)s" @@ -544,7 +544,7 @@ msgstr "إضاÙØ©" #: media/js/utils.js:99 msgid "and" -msgstr "" +msgstr "Ùˆ" #: media/js/utils.js:117 msgid "click to close" @@ -556,7 +556,7 @@ msgstr "انقر لتعديل التعليق" #: media/js/utils.js:905 msgid "convert to answer" -msgstr "" +msgstr "تØويل لإجابة" #: media/js/utils.js:958 msgid "Ok" @@ -569,7 +569,7 @@ msgstr "إلغاء" #: media/js/utils.js:1219 #, c-format msgid "Uploaded file: %s" -msgstr "" +msgstr "الملÙات المرÙوعة: %s" #: media/js/utils.js:1234 msgid "Choose a different image" @@ -610,7 +610,7 @@ msgstr "ØÙظت" #: media/js/utils.js:1602 msgid "enabled" -msgstr "" +msgstr "Ù…Ùعل" #: media/js/utils.js:1604 msgid "disabled" @@ -626,7 +626,7 @@ msgstr "إضاÙØ© مجموعة" #: media/js/utils.js:2138 msgid "Group %(name)s already exists. Group names are case-insensitive." -msgstr "" +msgstr "أسم المجموعة %(name)s Ù…Øجوز، أسماء المجموعات غير Øساسة Ù„Øالة الأØرÙ." #: media/js/utils.js:2311 #, c-format @@ -635,7 +635,7 @@ msgstr "" #: media/js/utils.js:3358 msgid "ago" -msgstr "" +msgstr "منذ" #: media/js/utils.js:3359 msgid "from now" @@ -648,7 +648,7 @@ msgstr "ÙÙŠ Øدود دقيقة" #: media/js/utils.js:3362 #, c-format msgid "%d minutes" -msgstr "" +msgstr "%d دقيقة" #: media/js/utils.js:3363 msgid "about an hour" @@ -657,7 +657,7 @@ msgstr "ساعة تÙريباً" #: media/js/utils.js:3364 #, c-format msgid "%d hours" -msgstr "" +msgstr "%d ساعة" #: media/js/utils.js:3365 media/js/utils.js.c:3493 msgid "yesterday" @@ -666,7 +666,7 @@ msgstr "البارØØ©" #: media/js/utils.js:3366 #, c-format msgid "%d days" -msgstr "" +msgstr "%d يوم" #: media/js/utils.js:3367 msgid "about a month" @@ -675,7 +675,7 @@ msgstr "شهر تÙريباً" #: media/js/utils.js:3368 #, c-format msgid "%d months" -msgstr "" +msgstr "%d أشهر" #: media/js/utils.js:3369 msgid "about a year" @@ -684,55 +684,55 @@ msgstr "سنة تقريباً" #: media/js/utils.js:3370 #, c-format msgid "%d years" -msgstr "" +msgstr "%d سنة" #: media/js/utils.js:3468 msgid "Jan" -msgstr "" +msgstr "يناير" #: media/js/utils.js:3469 msgid "Feb" -msgstr "" +msgstr "Ùبراير" #: media/js/utils.js:3470 msgid "Mar" -msgstr "" +msgstr "مارس" #: media/js/utils.js:3471 msgid "Apr" -msgstr "" +msgstr "أبريل" #: media/js/utils.js:3472 msgid "May" -msgstr "" +msgstr "مايو" #: media/js/utils.js:3473 msgid "Jun" -msgstr "" +msgstr "يونيو" #: media/js/utils.js:3474 msgid "Jul" -msgstr "" +msgstr "يوليو" #: media/js/utils.js:3475 msgid "Aug" -msgstr "" +msgstr "أغسطس" #: media/js/utils.js:3476 msgid "Sep" -msgstr "" +msgstr "سبتمبر" #: media/js/utils.js:3477 msgid "Oct" -msgstr "" +msgstr "أكتوبر" #: media/js/utils.js:3478 msgid "Nov" -msgstr "" +msgstr "نوÙمبر" #: media/js/utils.js:3479 msgid "Dec" -msgstr "" +msgstr "ديسمبر" #: media/js/utils.js:3491 msgid "2 days ago" diff --git a/askbot/locale/de/LC_MESSAGES/django.mo b/askbot/locale/de/LC_MESSAGES/django.mo Binary files differindex b0fbf9b9..aedd55b1 100644 --- a/askbot/locale/de/LC_MESSAGES/django.mo +++ b/askbot/locale/de/LC_MESSAGES/django.mo diff --git a/askbot/locale/de/LC_MESSAGES/django.po b/askbot/locale/de/LC_MESSAGES/django.po index 70777dfc..fdd51aa5 100644 --- a/askbot/locale/de/LC_MESSAGES/django.po +++ b/askbot/locale/de/LC_MESSAGES/django.po @@ -14,7 +14,7 @@ msgstr "" "Project-Id-Version: askbot\n" "Report-Msgid-Bugs-To: http://askbot.org/\n" "POT-Creation-Date: 2013-07-13 14:06-0500\n" -"PO-Revision-Date: 2013-08-03 14:46+0000\n" +"PO-Revision-Date: 2013-09-13 16:15+0000\n" "Last-Translator: Alexander Lieder <enormitas@gmail.com>\n" "Language-Team: German (http://www.transifex.com/projects/p/askbot/language/de/)\n" "MIME-Version: 1.0\n" @@ -111,7 +111,7 @@ msgstr "" #: forms.py:410 forms.py:1006 models/widgets.py:27 #: templates/widgets/edit_post.html:32 templates/widgets/meta_nav.html:6 msgid "tags" -msgstr "Schlagwörter" +msgstr "Tags" #: forms.py:412 #, python-format @@ -2026,7 +2026,7 @@ msgstr "" #: conf/sidebar_question.py:119 msgid "Show related questions in sidebar" -msgstr "Verwandte / ähnliche Fragen in der Seitenleiste anzeigen" +msgstr "Verwandte Fragen in der Seitenleiste anzeigen" #: conf/sidebar_question.py:121 msgid "Uncheck this if you want to hide the list of related questions. " @@ -6376,8 +6376,8 @@ msgstr "Bitte beachte: %(app_name)s benötigt javascript um korrekt zu funktioni #, python-format msgid "each tag must be shorter that %(max_chars)s character" msgid_plural "each tag must be shorter than %(max_chars)s characters" -msgstr[0] "Jeder Tag muss länger sein als %(max_chars)s Zeichen" -msgstr[1] "Jeder Tag muss länger sein als %(max_chars)s Zeichen" +msgstr[0] "Jedes Schlagwort muss kürzer sein als %(max_chars)s Zeichen" +msgstr[1] "Jedes Schlagwort muss kürzer sein als %(max_chars)s Zeichen" #: templates/meta/editor_data.html:7 #, python-format @@ -6686,7 +6686,7 @@ msgstr "Letztes Update" #: templates/question/sidebar.html:151 msgid "Related questions" -msgstr "Verwandte / ähnliche Fragen" +msgstr "Verwandte Fragen" #: templates/tags/form_bulk_tag_subscription.html:4 msgid "Tag subscriptions" diff --git a/askbot/locale/en/LC_MESSAGES/django.mo b/askbot/locale/en/LC_MESSAGES/django.mo Binary files differindex 9af75244..92662132 100644 --- a/askbot/locale/en/LC_MESSAGES/django.mo +++ b/askbot/locale/en/LC_MESSAGES/django.mo diff --git a/askbot/locale/en/LC_MESSAGES/django.po b/askbot/locale/en/LC_MESSAGES/django.po index cdff3a26..bbab876b 100644 --- a/askbot/locale/en/LC_MESSAGES/django.po +++ b/askbot/locale/en/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.7\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-07-13 14:06-0500\n" +"POT-Creation-Date: 2013-10-16 16:34-0500\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: Evgeny Fadeev <evgeny.fadeev@gmail.com>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -25,8 +25,14 @@ msgstr "" msgid " - " msgstr "" -#: feed.py:35 feed.py:109 -msgid "Individual question feed" +#: feed.py:35 +#, python-format +msgid "Individual %(question)s feed" +msgstr "" + +#: feed.py:109 +#, python-format +msgid "Latest %(question)s feed" msgstr "" #: forms.py:140 @@ -64,8 +70,9 @@ msgstr "" msgid "title" msgstr "" -#: forms.py:249 templates/embed/ask_by_widget.html:170 -msgid "Please enter your question" +#: forms.py:249 +#, python-format +msgid "Please enter your %(question)s" msgstr "" #: forms.py:260 @@ -75,39 +82,51 @@ msgid_plural "must have > %d characters" msgstr[0] "" msgstr[1] "" -#: forms.py:270 +#: forms.py:271 #, python-format -msgid "The question is too long, maximum allowed size is %d characters" +msgid "" +"The %(question)s is too long, maximum allowed size is %(length)d characters" msgstr "" -#: forms.py:277 +#: forms.py:278 #, python-format -msgid "The question is too long, maximum allowed size is %d bytes" +msgid "The %(question)s is too long, maximum allowed size is %(length)d bytes" msgstr "" -#: forms.py:309 +#: forms.py:307 msgid "content" msgstr "" -#: forms.py:370 +#: forms.py:311 +msgid "post" +msgstr "" + +#: forms.py:318 +#, python-format +msgid "%(post)s content must be > %(count)d character" +msgid_plural "%(post)s content must be > %(count)d characters" +msgstr[0] "" +msgstr[1] "" + +#: forms.py:366 #, python-format msgid "each tag must be shorter than %(max_chars)d character" msgid_plural "each tag must be shorter than %(max_chars)d characters" msgstr[0] "" msgstr[1] "" -#: forms.py:407 +#: forms.py:403 msgid "" "We ran out of space for recording the tags. Please shorten or delete some of " "them." msgstr "" -#: forms.py:410 forms.py:1006 models/widgets.py:27 +#: forms.py:406 forms.py:1006 models/widgets.py:27 #: templates/widgets/edit_post.html:32 templates/widgets/meta_nav.html:6 msgid "tags" msgstr "" -#: forms.py:412 +#: forms.py:408 #, python-format msgid "" "Tags are short keywords, with no spaces within. Up to %(max_tags)d tag can " @@ -118,156 +137,163 @@ msgid_plural "" msgstr[0] "" msgstr[1] "" -#: forms.py:439 +#: forms.py:435 #, python-format msgid "please use %(tag_count)d tag or less" msgid_plural "please use %(tag_count)d tags or less" msgstr[0] "" msgstr[1] "" -#: forms.py:447 +#: forms.py:443 #, python-format msgid "At least one of the following tags is required : %(tags)s" msgstr "" -#: forms.py:475 +#: forms.py:471 msgid "community wiki (karma is not awarded & many others can edit wiki post)" msgstr "" -#: forms.py:479 +#: forms.py:475 +#, python-format msgid "" -"if you choose community wiki option, the question and answer do not generate " -"points and name of author will not be shown" +"if you choose community wiki option, the %(question)s and answer do not " +"generate points and name of author will not be shown" +msgstr "" + +#: forms.py:478 conf/words.py:90 +msgid "question" msgstr "" -#: forms.py:496 +#: forms.py:492 msgid "update summary:" msgstr "" -#: forms.py:498 +#: forms.py:494 msgid "" "enter a brief summary of your revision (e.g. fixed spelling, grammar, " "improved style, this field is optional)" msgstr "" -#: forms.py:585 +#: forms.py:583 msgid "Enter number of points to add or subtract" msgstr "" -#: forms.py:600 const/__init__.py:375 +#: forms.py:598 const/__init__.py:380 msgid "approved" msgstr "" -#: forms.py:601 const/__init__.py:376 +#: forms.py:599 const/__init__.py:381 msgid "watched" msgstr "" -#: forms.py:602 const/__init__.py:377 +#: forms.py:600 const/__init__.py:382 msgid "suspended" msgstr "" -#: forms.py:603 const/__init__.py:378 +#: forms.py:601 const/__init__.py:383 msgid "blocked" msgstr "" -#: forms.py:605 +#: forms.py:603 msgid "administrator" msgstr "" -#: forms.py:606 const/__init__.py:374 +#: forms.py:604 const/__init__.py:379 msgid "moderator" msgstr "" -#: forms.py:625 +#: forms.py:623 msgid "Change status to" msgstr "" -#: forms.py:652 +#: forms.py:650 msgid "which one?" msgstr "" -#: forms.py:673 +#: forms.py:671 msgid "Cannot change own status" msgstr "" -#: forms.py:679 +#: forms.py:677 msgid "Cannot turn other user to moderator" msgstr "" -#: forms.py:686 +#: forms.py:684 msgid "Cannot change status of another moderator" msgstr "" -#: forms.py:692 +#: forms.py:690 msgid "Cannot change status to admin" msgstr "" -#: forms.py:698 +#: forms.py:696 #, python-format msgid "" "If you wish to change %(username)s's status, please make a meaningful " "selection." msgstr "" -#: forms.py:708 +#: forms.py:706 msgid "Subject line" msgstr "" -#: forms.py:713 +#: forms.py:711 msgid "Message text" msgstr "" -#: forms.py:727 +#: forms.py:725 msgid "Your name (optional):" msgstr "" -#: forms.py:728 +#: forms.py:726 msgid "Email:" msgstr "" -#: forms.py:730 +#: forms.py:728 msgid "Your message:" msgstr "" -#: forms.py:735 +#: forms.py:733 msgid "I don't want to give my email or receive a response:" msgstr "" -#: forms.py:758 +#: forms.py:756 msgid "Please mark \"I dont want to give my mail\" field." msgstr "" -#: forms.py:791 +#: forms.py:789 msgid "keep private within your groups" msgstr "" -#: forms.py:830 +#: forms.py:828 templates/ask.html:58 templates/question.html:338 #, fuzzy msgid "User name:" msgstr "User login" -#: forms.py:832 +#: forms.py:830 msgid "Enter name to post on behalf of someone else. Can create new accounts." msgstr "" -#: forms.py:839 +#: forms.py:837 templates/question.html:339 msgid "Email address:" msgstr "" -#: forms.py:889 +#: forms.py:887 msgid "User name is required with the email" msgstr "" -#: forms.py:894 +#: forms.py:892 msgid "Email is required if user name is added" msgstr "" -#: forms.py:914 forms.py:957 -msgid "ask anonymously" +#: forms.py:923 +msgid "post anonymously" msgstr "" -#: forms.py:916 forms.py:959 -msgid "Check if you do not want to reveal your name when asking this question" +#: forms.py:925 +#, python-format +msgid "" +"Check if you do not want to reveal your name when posting this %(question)s" msgstr "" #: forms.py:947 @@ -275,6 +301,14 @@ msgid "" "Subject line is expected in the format: [tag1, tag2, tag3,...] question title" msgstr "" +#: forms.py:957 +msgid "ask anonymously" +msgstr "" + +#: forms.py:959 +msgid "Check if you do not want to reveal your name when asking this question" +msgstr "" + #: forms.py:1213 msgid "" "You have asked this question anonymously, if you decide to reveal your " @@ -403,154 +437,154 @@ msgstr "" msgid "Your post at %(site_name)s is now published" msgstr "" -#: urls.py:44 +#: urls.py:44 conf/words.py:99 msgid "questions" msgstr "" -#: urls.py:56 +#: urls.py:57 msgid "question/" msgstr "" -#: urls.py:61 +#: urls.py:62 msgid "tags/" msgstr "" -#: urls.py:66 urls.py:71 urls.py:78 urls.py:84 urls.py:93 urls.py:100 +#: urls.py:67 urls.py:72 urls.py:79 urls.py:85 urls.py:94 urls.py:101 msgid "users/" msgstr "" -#: urls.py:71 +#: urls.py:72 msgid "by-group/" msgstr "" -#: urls.py:78 urls.py:159 urls.py:226 urls.py:520 +#: urls.py:79 urls.py:160 urls.py:237 urls.py:531 msgid "edit/" msgstr "" -#: urls.py:85 +#: urls.py:86 msgid "subscriptions/" msgstr "" -#: urls.py:94 +#: urls.py:95 msgid "select_languages/" msgstr "" -#: urls.py:105 +#: urls.py:106 msgid "groups/" msgstr "" -#: urls.py:110 +#: urls.py:111 msgid "users/update_has_custom_avatar/" msgstr "" -#: urls.py:115 urls.py:120 +#: urls.py:116 urls.py:121 msgid "badges/" msgstr "" -#: urls.py:133 +#: urls.py:134 msgid "feedback/" msgstr "" -#: urls.py:154 +#: urls.py:155 msgid "about/" msgstr "" -#: urls.py:155 +#: urls.py:156 msgid "faq/" msgstr "" -#: urls.py:156 +#: urls.py:157 msgid "privacy/" msgstr "" -#: urls.py:157 +#: urls.py:158 msgid "help/" msgstr "" -#: urls.py:159 urls.py:164 +#: urls.py:160 urls.py:165 msgid "answers/" msgstr "" -#: urls.py:164 urls.py:256 +#: urls.py:165 urls.py:267 msgid "revisions/" msgstr "" -#: urls.py:221 urls.py:226 urls.py:231 urls.py:236 urls.py:241 urls.py:246 -#: urls.py:256 +#: urls.py:232 urls.py:237 urls.py:242 urls.py:247 urls.py:252 urls.py:257 +#: urls.py:267 msgid "questions/" msgstr "" -#: urls.py:221 urls.py:495 urls.py:500 urls.py:505 urls.py:510 +#: urls.py:232 urls.py:506 urls.py:511 urls.py:516 urls.py:521 msgid "ask/" msgstr "" -#: urls.py:231 +#: urls.py:242 msgid "retag/" msgstr "" -#: urls.py:236 +#: urls.py:247 msgid "close/" msgstr "" -#: urls.py:241 +#: urls.py:252 msgid "reopen/" msgstr "" -#: urls.py:246 +#: urls.py:257 msgid "answer/" msgstr "" -#: urls.py:314 +#: urls.py:325 msgid "tags/subscriptions/" msgstr "" -#: urls.py:319 +#: urls.py:330 msgid "tags/subscriptions/delete/" msgstr "" -#: urls.py:324 +#: urls.py:335 msgid "tags/subscriptions/create/" msgstr "" -#: urls.py:329 +#: urls.py:340 msgid "tags/subscriptions/edit/" msgstr "" -#: urls.py:334 +#: urls.py:345 msgid "suggested-tags/" msgstr "" -#: urls.py:459 +#: urls.py:470 msgid "messages/" msgstr "" -#: urls.py:459 +#: urls.py:470 msgid "markread/" msgstr "" -#: urls.py:490 urls.py:495 urls.py:500 urls.py:505 urls.py:510 urls.py:515 -#: urls.py:520 urls.py:525 urls.py:530 +#: urls.py:501 urls.py:506 urls.py:511 urls.py:516 urls.py:521 urls.py:526 +#: urls.py:531 urls.py:536 urls.py:541 msgid "widgets/" msgstr "" -#: urls.py:510 deps/django_authopenid/urls.py:20 +#: urls.py:521 deps/django_authopenid/urls.py:20 msgid "complete/" msgstr "" -#: urls.py:515 +#: urls.py:526 msgid "create/" msgstr "" -#: urls.py:525 +#: urls.py:536 msgid "delete/" msgstr "" -#: urls.py:560 +#: urls.py:571 msgid "upload/" msgstr "" -#: urls.py:585 setup_templates/settings.py:229 -#: templates/authopenid/providers_javascript.html:7 +#: urls.py:596 setup_templates/settings.py:232 +#: templates/authopenid/providers_javascript.html:8 msgid "account/" msgstr "" @@ -713,164 +747,172 @@ msgid "Enable email alerts" msgstr "" #: conf/email.py:62 -msgid "Maximum number of news entries in an email alert" +msgid "Enable HTML-formatted email" +msgstr "" + +#: conf/email.py:63 +msgid "May not be supported by some email clients" msgstr "" #: conf/email.py:72 +msgid "Maximum number of news entries in an email alert" +msgstr "" + +#: conf/email.py:82 msgid "Default notification frequency all questions" msgstr "" -#: conf/email.py:74 +#: conf/email.py:84 msgid "Option to define frequency of emailed updates for: all questions." msgstr "" -#: conf/email.py:86 +#: conf/email.py:96 msgid "Default notification frequency questions asked by the user" msgstr "" -#: conf/email.py:88 +#: conf/email.py:98 msgid "" "Option to define frequency of emailed updates for: Question asked by the " "user." msgstr "" -#: conf/email.py:100 +#: conf/email.py:110 msgid "Default notification frequency questions answered by the user" msgstr "" -#: conf/email.py:102 +#: conf/email.py:112 msgid "" "Option to define frequency of emailed updates for: Question answered by the " "user." msgstr "" -#: conf/email.py:114 +#: conf/email.py:124 msgid "" "Default notification frequency questions individually " "selected by the user" msgstr "" -#: conf/email.py:117 +#: conf/email.py:127 msgid "" "Option to define frequency of emailed updates for: Question individually " "selected by the user." msgstr "" -#: conf/email.py:129 +#: conf/email.py:139 msgid "" "Default notification frequency for mentions and " "comments" msgstr "" -#: conf/email.py:132 +#: conf/email.py:142 msgid "" "Option to define frequency of emailed updates for: Mentions and comments." msgstr "" -#: conf/email.py:143 +#: conf/email.py:153 msgid "Send periodic reminders about unanswered questions" msgstr "" -#: conf/email.py:145 +#: conf/email.py:155 msgid "" "NOTE: in order to use this feature, it is necessary to run the management " "command \"send_unanswered_question_reminders\" (for example, via a cron job " "- with an appropriate frequency) " msgstr "" -#: conf/email.py:158 +#: conf/email.py:168 msgid "Days before starting to send reminders about unanswered questions" msgstr "" -#: conf/email.py:169 +#: conf/email.py:179 msgid "" "How often to send unanswered question reminders (in days between the " "reminders sent)." msgstr "" -#: conf/email.py:181 +#: conf/email.py:191 msgid "Max. number of reminders to send about unanswered questions" msgstr "" -#: conf/email.py:192 +#: conf/email.py:202 msgid "Send periodic reminders to accept the best answer" msgstr "" -#: conf/email.py:194 +#: conf/email.py:204 msgid "" "NOTE: in order to use this feature, it is necessary to run the management " "command \"send_accept_answer_reminders\" (for example, via a cron job - with " "an appropriate frequency) " msgstr "" -#: conf/email.py:207 +#: conf/email.py:217 msgid "Days before starting to send reminders to accept an answer" msgstr "" -#: conf/email.py:218 +#: conf/email.py:228 msgid "" "How often to send accept answer reminders (in days between the reminders " "sent)." msgstr "" -#: conf/email.py:230 +#: conf/email.py:240 msgid "Max. number of reminders to send to accept the best answer" msgstr "" -#: conf/email.py:242 +#: conf/email.py:252 msgid "Require email verification before allowing to post" msgstr "" -#: conf/email.py:243 +#: conf/email.py:253 msgid "" "Active email verification is done by sending a verification key in email" msgstr "" -#: conf/email.py:252 +#: conf/email.py:262 msgid "Fake email for anonymous user" msgstr "" -#: conf/email.py:253 +#: conf/email.py:263 msgid "Use this setting to control gravatar for email-less user" msgstr "" -#: conf/email.py:262 +#: conf/email.py:272 msgid "Allow posting questions by email" msgstr "" -#: conf/email.py:264 +#: conf/email.py:274 msgid "" "Before enabling this setting - please fill out IMAP settings in the settings." "py file" msgstr "" -#: conf/email.py:275 +#: conf/email.py:285 msgid "Replace space in emailed tags with dash" msgstr "" -#: conf/email.py:277 +#: conf/email.py:287 msgid "" "This setting applies to tags written in the subject line of questions asked " "by email" msgstr "" -#: conf/email.py:288 +#: conf/email.py:298 msgid "Enable posting answers and comments by email" msgstr "" -#: conf/email.py:291 +#: conf/email.py:301 msgid "To enable this feature make sure lamson is running" msgstr "" -#: conf/email.py:302 +#: conf/email.py:312 msgid "Emailed post: when to notify author about publishing" msgstr "" -#: conf/email.py:327 +#: conf/email.py:337 msgid "Reply by email hostname" msgstr "" -#: conf/email.py:338 +#: conf/email.py:348 msgid "" "Email replies having fewer words than this number will be posted as comments " "instead of answers" @@ -1105,8 +1147,8 @@ msgstr "" #: conf/forum_data_rules.py:135 msgid "" -"To use folded mode, please first set minimum question body length to 0. Also " -"- please make tags optional." +"<b style=\"color:red;\">To use folded mode, please first set minimum " +"question body length to 0. Also - please make tags optional.</b>" msgstr "" #: conf/forum_data_rules.py:147 @@ -1147,156 +1189,160 @@ msgstr "" msgid "Enable accepting best answer" msgstr "" -#: conf/forum_data_rules.py:231 +#: conf/forum_data_rules.py:233 +msgid "How to sort answers by default" +msgstr "" + +#: conf/forum_data_rules.py:241 msgid "Are tags required?" msgstr "" -#: conf/forum_data_rules.py:237 +#: conf/forum_data_rules.py:247 msgid "category tree" msgstr "" -#: conf/forum_data_rules.py:238 +#: conf/forum_data_rules.py:248 #, fuzzy msgid "user input" msgstr "User login" -#: conf/forum_data_rules.py:245 +#: conf/forum_data_rules.py:255 msgid "Source of tags" msgstr "" -#: conf/forum_data_rules.py:256 +#: conf/forum_data_rules.py:266 msgid "Mandatory tags" msgstr "" -#: conf/forum_data_rules.py:259 +#: conf/forum_data_rules.py:269 msgid "" "At least one of these tags will be required for any new or newly edited " "question. A mandatory tag may be wildcard, if the wildcard tags are active." msgstr "" -#: conf/forum_data_rules.py:271 +#: conf/forum_data_rules.py:281 msgid "Force lowercase the tags" msgstr "" -#: conf/forum_data_rules.py:273 +#: conf/forum_data_rules.py:283 msgid "" "Attention: after checking this, please back up the database, and run a " "management command: <code>python manage.py fix_question_tags</code> to " "globally rename the tags" msgstr "" -#: conf/forum_data_rules.py:287 +#: conf/forum_data_rules.py:297 msgid "Format of tag list" msgstr "" -#: conf/forum_data_rules.py:289 +#: conf/forum_data_rules.py:299 msgid "" "Select the format to show tags in, either as a simple list, or as a tag cloud" msgstr "" -#: conf/forum_data_rules.py:301 +#: conf/forum_data_rules.py:311 msgid "Use wildcard tags" msgstr "" -#: conf/forum_data_rules.py:303 +#: conf/forum_data_rules.py:313 msgid "" "Wildcard tags can be used to follow or ignore many tags at once, a valid " "wildcard tag has a single wildcard at the very end" msgstr "" -#: conf/forum_data_rules.py:315 +#: conf/forum_data_rules.py:325 msgid "Use separate set for subscribed tags" msgstr "" -#: conf/forum_data_rules.py:317 +#: conf/forum_data_rules.py:327 msgid "" "If enabled, users will have a third set of tag selections - \"subscribed" "\" (by email) in additon to \"interesting\" and \"ignored\"" msgstr "" -#: conf/forum_data_rules.py:325 +#: conf/forum_data_rules.py:335 msgid "Always, for all users" msgstr "" -#: conf/forum_data_rules.py:326 +#: conf/forum_data_rules.py:336 msgid "Never, for all users" msgstr "" -#: conf/forum_data_rules.py:327 +#: conf/forum_data_rules.py:337 msgid "Let users decide" msgstr "" -#: conf/forum_data_rules.py:335 +#: conf/forum_data_rules.py:345 msgid "Publicly show user tag selections" msgstr "" -#: conf/forum_data_rules.py:344 +#: conf/forum_data_rules.py:354 msgid "Enable separate tag search box on main page" msgstr "" -#: conf/forum_data_rules.py:354 +#: conf/forum_data_rules.py:364 msgid "Default max number of comments to display under posts" msgstr "" -#: conf/forum_data_rules.py:365 +#: conf/forum_data_rules.py:375 #, python-format msgid "Maximum comment length, must be < %(max_len)s" msgstr "" -#: conf/forum_data_rules.py:375 +#: conf/forum_data_rules.py:385 msgid "Limit time to edit comments" msgstr "" -#: conf/forum_data_rules.py:377 +#: conf/forum_data_rules.py:387 msgid "If unchecked, there will be no time limit to edit the comments" msgstr "" -#: conf/forum_data_rules.py:388 +#: conf/forum_data_rules.py:398 msgid "Minutes allowed to edit a comment" msgstr "" -#: conf/forum_data_rules.py:389 +#: conf/forum_data_rules.py:399 msgid "To enable this setting, check the previous one" msgstr "" -#: conf/forum_data_rules.py:398 +#: conf/forum_data_rules.py:408 msgid "Save comment by pressing <Enter> key" msgstr "" -#: conf/forum_data_rules.py:400 +#: conf/forum_data_rules.py:410 msgid "" "This may be useful when only one-line comments are desired. Will not work " "with TinyMCE editor." msgstr "" -#: conf/forum_data_rules.py:411 +#: conf/forum_data_rules.py:421 msgid "Minimum length of search term for Ajax search" msgstr "" -#: conf/forum_data_rules.py:412 +#: conf/forum_data_rules.py:422 msgid "Must match the corresponding database backend setting" msgstr "" -#: conf/forum_data_rules.py:421 +#: conf/forum_data_rules.py:431 msgid "Do not make text query sticky in search" msgstr "" -#: conf/forum_data_rules.py:423 +#: conf/forum_data_rules.py:433 msgid "" "Check to disable the \"sticky\" behavior of the search query. This may be " "useful if you want to move the search bar away from the default position or " "do not like the default sticky behavior of the text search query." msgstr "" -#: conf/forum_data_rules.py:436 +#: conf/forum_data_rules.py:446 msgid "Maximum number of tags per question" msgstr "" -#: conf/forum_data_rules.py:448 +#: conf/forum_data_rules.py:458 msgid "Number of questions to list by default" msgstr "" -#: conf/forum_data_rules.py:458 +#: conf/forum_data_rules.py:468 msgid "What should \"unanswered question\" mean?" msgstr "" @@ -1900,7 +1946,7 @@ msgstr "" msgid "Main page sidebar" msgstr "" -#: conf/sidebar_main.py:20 conf/sidebar_question.py:67 +#: conf/sidebar_main.py:20 conf/sidebar_question.py:76 msgid "Custom sidebar header" msgstr "" @@ -1914,7 +1960,7 @@ msgstr "" #: conf/sidebar_main.py:36 conf/sidebar_main.py:111 conf/sidebar_profile.py:37 #: conf/sidebar_question.py:34 conf/sidebar_question.py:58 -#: conf/sidebar_question.py:84 conf/sidebar_question.py:149 +#: conf/sidebar_question.py:93 conf/sidebar_question.py:158 msgid "Show above only to anonymous users" msgstr "" @@ -1949,11 +1995,11 @@ msgid "" "Uncheck this if you want to hide the tag cloud or tag list from the sidebar " msgstr "" -#: conf/sidebar_main.py:94 conf/sidebar_question.py:132 +#: conf/sidebar_main.py:94 conf/sidebar_question.py:141 msgid "Custom sidebar footer" msgstr "" -#: conf/sidebar_main.py:97 conf/sidebar_question.py:135 +#: conf/sidebar_main.py:97 conf/sidebar_question.py:144 msgid "" "Use this area to enter content at the BOTTOM of the sidebarin HTML format. " "When using this option (as well as the sidebar header), please use the HTML " @@ -1989,12 +2035,16 @@ msgstr "" #: conf/sidebar_question.py:45 msgid "" -"This banner will show above the second answer. When using this option, " -"please use the HTML validation service to make sure that your input is valid " -"and works well in all browsers." +"This banner will show under the first answer. When using this option, please " +"use the HTML validation service to make sure that your input is valid and " +"works well in all browsers." msgstr "" -#: conf/sidebar_question.py:70 +#: conf/sidebar_question.py:67 +msgid "Show answers banner even if there are no answers" +msgstr "" + +#: conf/sidebar_question.py:79 msgid "" "Use this area to enter content at the TOP of the sidebarin HTML format. When " "using this option (as well as the sidebar footer), please use the HTML " @@ -2002,29 +2052,29 @@ msgid "" "all browsers." msgstr "" -#: conf/sidebar_question.py:92 +#: conf/sidebar_question.py:101 msgid "Show tag list in sidebar" msgstr "" -#: conf/sidebar_question.py:94 +#: conf/sidebar_question.py:103 msgid "Uncheck this if you want to hide the tag list from the sidebar " msgstr "" -#: conf/sidebar_question.py:105 +#: conf/sidebar_question.py:114 msgid "Show meta information in sidebar" msgstr "" -#: conf/sidebar_question.py:107 +#: conf/sidebar_question.py:116 msgid "" "Uncheck this if you want to hide the meta information about the question " "(post date, views, last updated). " msgstr "" -#: conf/sidebar_question.py:119 +#: conf/sidebar_question.py:128 msgid "Show related questions in sidebar" msgstr "" -#: conf/sidebar_question.py:121 +#: conf/sidebar_question.py:130 msgid "Uncheck this if you want to hide the list of related questions. " msgstr "" @@ -2112,105 +2162,25 @@ msgstr "" msgid "To change the logo, select new file, then submit this whole form." msgstr "" -#: conf/skin_general_settings.py:34 -msgid "English" -msgstr "" - -#: conf/skin_general_settings.py:35 -msgid "Spanish" -msgstr "" - -#: conf/skin_general_settings.py:36 -msgid "Catalan" -msgstr "" - -#: conf/skin_general_settings.py:37 -msgid "German" -msgstr "" - -#: conf/skin_general_settings.py:38 -msgid "Greek" -msgstr "" - -#: conf/skin_general_settings.py:39 -msgid "Finnish" -msgstr "" - -#: conf/skin_general_settings.py:40 -msgid "French" -msgstr "" - -#: conf/skin_general_settings.py:41 -msgid "Hindi" -msgstr "" - #: conf/skin_general_settings.py:42 -msgid "Hungarian" -msgstr "" - -#: conf/skin_general_settings.py:43 -msgid "Italian" -msgstr "" - -#: conf/skin_general_settings.py:44 -msgid "Japanese" -msgstr "" - -#: conf/skin_general_settings.py:45 -msgid "Korean" -msgstr "" - -#: conf/skin_general_settings.py:46 -msgid "Portuguese" -msgstr "" - -#: conf/skin_general_settings.py:47 -msgid "Brazilian Portuguese" -msgstr "" - -#: conf/skin_general_settings.py:48 -msgid "Romanian" -msgstr "" - -#: conf/skin_general_settings.py:49 -msgid "Russian" +msgid "Select Language" msgstr "" #: conf/skin_general_settings.py:50 -msgid "Serbian" -msgstr "" - -#: conf/skin_general_settings.py:51 -msgid "Turkish" -msgstr "" - -#: conf/skin_general_settings.py:52 -msgid "Vietnamese" -msgstr "" - -#: conf/skin_general_settings.py:53 -msgid "Chinese" -msgstr "" - -#: conf/skin_general_settings.py:54 -msgid "Chinese (Taiwan)" -msgstr "" - -#: conf/skin_general_settings.py:73 msgid "Show logo" msgstr "" -#: conf/skin_general_settings.py:75 +#: conf/skin_general_settings.py:52 msgid "" "Check if you want to show logo in the forum header or uncheck in the case " "you do not want the logo to appear in the default location" msgstr "" -#: conf/skin_general_settings.py:87 +#: conf/skin_general_settings.py:64 msgid "Site favicon" msgstr "" -#: conf/skin_general_settings.py:89 +#: conf/skin_general_settings.py:66 #, python-format msgid "" "A small 16x16 or 32x32 pixel icon image used to distinguish your site in the " @@ -2218,40 +2188,40 @@ msgid "" "href=\"%(favicon_info_url)s\">this page</a>." msgstr "" -#: conf/skin_general_settings.py:105 +#: conf/skin_general_settings.py:82 msgid "Password login button" msgstr "" -#: conf/skin_general_settings.py:107 +#: conf/skin_general_settings.py:84 msgid "" "An 88x38 pixel image that is used on the login screen for the password login " "button." msgstr "" -#: conf/skin_general_settings.py:120 +#: conf/skin_general_settings.py:97 msgid "Show all UI functions to all users" msgstr "" -#: conf/skin_general_settings.py:122 +#: conf/skin_general_settings.py:99 msgid "" "If checked, all forum functions will be shown to users, regardless of their " "reputation. However to use those functions, moderation rules, reputation and " "other limits will still apply." msgstr "" -#: conf/skin_general_settings.py:137 +#: conf/skin_general_settings.py:114 msgid "Select skin" msgstr "" -#: conf/skin_general_settings.py:148 +#: conf/skin_general_settings.py:125 msgid "Customize HTML <HEAD>" msgstr "" -#: conf/skin_general_settings.py:157 +#: conf/skin_general_settings.py:134 msgid "Custom portion of the HTML <HEAD>" msgstr "" -#: conf/skin_general_settings.py:159 +#: conf/skin_general_settings.py:136 msgid "" "<strong>To use this option</strong>, check \"Customize HTML <HEAD>\" " "above. Contents of this box will be inserted into the <HEAD> portion " @@ -2263,11 +2233,11 @@ msgid "" "please test the site with the W3C HTML validator service." msgstr "" -#: conf/skin_general_settings.py:181 +#: conf/skin_general_settings.py:158 msgid "Custom header additions" msgstr "" -#: conf/skin_general_settings.py:183 +#: conf/skin_general_settings.py:160 msgid "" "Header is the bar at the top of the content that contains user info and site " "links, and is common to all pages. Use this area to enter contents of the " @@ -2276,21 +2246,21 @@ msgid "" "sure that your input is valid and works well in all browsers." msgstr "" -#: conf/skin_general_settings.py:198 +#: conf/skin_general_settings.py:175 msgid "Site footer mode" msgstr "" -#: conf/skin_general_settings.py:200 +#: conf/skin_general_settings.py:177 msgid "" "Footer is the bottom portion of the content, which is common to all pages. " "You can disable, customize, or use the default footer." msgstr "" -#: conf/skin_general_settings.py:217 +#: conf/skin_general_settings.py:194 msgid "Custom footer (HTML format)" msgstr "" -#: conf/skin_general_settings.py:219 +#: conf/skin_general_settings.py:196 msgid "" "<strong>To enable this function</strong>, please select option 'customize' " "in the \"Site footer mode\" above. Use this area to enter contents of the " @@ -2299,21 +2269,21 @@ msgid "" "that your input is valid and works well in all browsers." msgstr "" -#: conf/skin_general_settings.py:234 +#: conf/skin_general_settings.py:211 msgid "Apply custom style sheet (CSS)" msgstr "" -#: conf/skin_general_settings.py:236 +#: conf/skin_general_settings.py:213 msgid "" "Check if you want to change appearance of your form by adding custom style " "sheet rules (please see the next item)" msgstr "" -#: conf/skin_general_settings.py:248 +#: conf/skin_general_settings.py:225 msgid "Custom style sheet (CSS)" msgstr "" -#: conf/skin_general_settings.py:250 +#: conf/skin_general_settings.py:227 msgid "" "<strong>To use this function</strong>, check \"Apply custom style sheet\" " "option above. The CSS rules added in this window will be applied after the " @@ -2322,19 +2292,19 @@ msgid "" "depends (default is empty string) on the url configuration in your urls.py." msgstr "" -#: conf/skin_general_settings.py:266 +#: conf/skin_general_settings.py:243 msgid "Add custom javascript" msgstr "" -#: conf/skin_general_settings.py:269 +#: conf/skin_general_settings.py:246 msgid "Check to enable javascript that you can enter in the next field" msgstr "" -#: conf/skin_general_settings.py:279 +#: conf/skin_general_settings.py:256 msgid "Custom javascript" msgstr "" -#: conf/skin_general_settings.py:281 +#: conf/skin_general_settings.py:258 msgid "" "Type or paste plain javascript that you would like to run on your site. Link " "to the script will be inserted at the bottom of the HTML output and will be " @@ -2345,19 +2315,19 @@ msgid "" "above)." msgstr "" -#: conf/skin_general_settings.py:299 +#: conf/skin_general_settings.py:276 msgid "Skin media revision number" msgstr "" -#: conf/skin_general_settings.py:301 +#: conf/skin_general_settings.py:278 msgid "Will be set automatically but you can modify it if necessary." msgstr "" -#: conf/skin_general_settings.py:312 +#: conf/skin_general_settings.py:289 msgid "Hash to update the media revision number automatically." msgstr "" -#: conf/skin_general_settings.py:316 +#: conf/skin_general_settings.py:293 msgid "Will be set automatically, it is not necesary to modify manually." msgstr "" @@ -2555,6 +2525,208 @@ msgid "" "question poster" msgstr "" +#: conf/words.py:14 +msgid "Site term vocalbulary" +msgstr "" + +#: conf/words.py:22 conf/words.py:23 templates/ask.html:4 +msgid "Ask Your Question" +msgstr "" + +#: conf/words.py:24 conf/words.py:34 conf/words.py:44 conf/words.py:54 +#: conf/words.py:64 +msgid "Used on a button" +msgstr "" + +#: conf/words.py:32 conf/words.py:33 +msgid "Ask the Group" +msgstr "" + +#: conf/words.py:42 conf/words.py:43 +msgid "Post Your Answer" +msgstr "" + +#: conf/words.py:52 conf/words.py:53 +msgid "Answer Your Own Question" +msgstr "" + +#: conf/words.py:62 conf/words.py:63 +msgid "Edit Your Previous Answer" +msgstr "" + +#: conf/words.py:72 conf/words.py:73 +msgid "asked" +msgstr "" + +#: conf/words.py:81 conf/words.py:82 +msgid "answered" +msgstr "" + +#: conf/words.py:91 +msgid "question (noun, singular)" +msgstr "" + +#: conf/words.py:100 +msgid "questions (noun, plural)" +msgstr "" + +#: conf/words.py:108 templates/widgets/question_summary.html:30 +msgid "answer" +msgstr "" + +#: conf/words.py:109 +msgid "answer (noun, sungular)" +msgstr "" + +#: conf/words.py:117 conf/words.py:118 +msgid "Show only questions from" +msgstr "" + +#: conf/words.py:126 conf/words.py:127 +msgid "Please ask your question here" +msgstr "" + +#: conf/words.py:135 conf/words.py:136 +msgid "Please enter your question" +msgstr "" + +#: conf/words.py:144 conf/words.py:145 +msgid "ask a question interesting to this community" +msgstr "" + +#: conf/words.py:153 conf/words.py:154 +msgid "No questions here." +msgstr "" + +#: conf/words.py:162 conf/words.py:163 +msgid "Please follow some questions or follow some users." +msgstr "" + +#: conf/words.py:171 conf/words.py:172 +msgid "Please feel free to ask your question!" +msgstr "" + +#: conf/words.py:180 conf/words.py:181 +msgid "swap with question" +msgstr "" + +#: conf/words.py:189 conf/words.py:190 +msgid "repost as a question comment" +msgstr "" + +#: conf/words.py:198 conf/words.py:199 +msgid "repost as a comment under older answer" +msgstr "" + +#: conf/words.py:207 conf/words.py:208 +msgid "invite other to help answer this question" +msgstr "" + +#: conf/words.py:216 conf/words.py:217 +msgid "Related questions" +msgstr "" + +#: conf/words.py:225 conf/words.py:226 +msgid "Question Tools" +msgstr "" + +#: conf/words.py:234 conf/words.py:235 +msgid "Phrase: this question is currently shared only with:" +msgstr "" + +#: conf/words.py:243 conf/words.py:244 +msgid "Be the first one to answer this question!" +msgstr "" + +#: conf/words.py:252 conf/words.py:253 +msgid "followed questions" +msgstr "" + +#: conf/words.py:262 +msgid "Phrase: comments and answers to others questions" +msgstr "" + +#: conf/words.py:270 conf/words.py:271 +msgid "You can post questions by emailing them at" +msgstr "" + +#: conf/words.py:279 conf/words.py:280 +msgid "List of questions" +msgstr "" + +#: conf/words.py:288 conf/words.py:289 +msgid "Community gives you awards for your questions, answers and votes" +msgstr "" + +#: conf/words.py:297 conf/words.py:298 +msgid "Close question" +msgstr "" + +#: conf/words.py:306 conf/words.py:307 +msgid "Edit question" +msgstr "" + +#: conf/words.py:315 conf/words.py:316 +msgid "Question - in one sentence" +msgstr "" + +#: conf/words.py:324 conf/words.py:325 +msgid "Retag question" +msgstr "" + +#: conf/words.py:333 conf/words.py:334 +msgid "Reopen question" +msgstr "" + +#: conf/words.py:342 conf/words.py:343 +msgid "There are no unanswered questions here" +msgstr "" + +#: conf/words.py:351 conf/words.py:352 +#: templates/user_profile/user_answers_list.html:5 +msgid "this answer has been selected as correct" +msgstr "" + +#: conf/words.py:360 conf/words.py:361 +msgid "mark this answer as correct" +msgstr "" + +#: conf/words.py:369 conf/words.py:370 +msgid "Login/Signup to Answer" +msgstr "" + +#: conf/words.py:378 conf/words.py:379 +msgid "Your Answer" +msgstr "" + +#: conf/words.py:387 conf/words.py:388 +msgid "Add Answer" +msgstr "" + +#: conf/words.py:396 conf/words.py:397 +msgid "give an answer interesting to this community" +msgstr "" + +#: conf/words.py:405 conf/words.py:406 +msgid "try to give an answer, rather than engage into a discussion" +msgstr "" + +#: conf/words.py:414 conf/words.py:415 +msgid "show only selected answers to enquirers" +msgstr "" + +#: conf/words.py:423 conf/words.py:424 +msgid "UNANSWERED" +msgstr "" + +#: conf/words.py:432 conf/words.py:433 +msgid "Edit Answer" +msgstr "" + +#: conf/words.py:441 conf/words.py:442 +msgid "Answered" +msgstr "" + #: const/__init__.py:11 msgid "duplicate question" msgstr "" @@ -2663,284 +2835,296 @@ msgid "" "%(subject)s\">this link</a>" msgstr "" -#: const/__init__.py:122 templates/user_inbox/responses_and_flags.html:9 +#: const/__init__.py:114 +msgid "latest first" +msgstr "" + +#: const/__init__.py:115 +msgid "oldest first" +msgstr "" + +#: const/__init__.py:116 +msgid "most voted first" +msgstr "" + +#: const/__init__.py:126 templates/user_inbox/responses_and_flags.html:9 msgid "all" msgstr "" -#: const/__init__.py:123 +#: const/__init__.py:127 msgid "unanswered" msgstr "" -#: const/__init__.py:124 +#: const/__init__.py:128 msgid "followed" msgstr "" -#: const/__init__.py:129 +#: const/__init__.py:133 msgid "list" msgstr "" -#: const/__init__.py:130 +#: const/__init__.py:134 msgid "cloud" msgstr "" -#: const/__init__.py:138 +#: const/__init__.py:143 msgid "Question has no answers" msgstr "" -#: const/__init__.py:139 +#: const/__init__.py:144 msgid "Question has no accepted answers" msgstr "" -#: const/__init__.py:195 +#: const/__init__.py:200 msgid "asked a question" msgstr "" -#: const/__init__.py:196 +#: const/__init__.py:201 msgid "answered a question" msgstr "" -#: const/__init__.py:197 const/__init__.py:301 +#: const/__init__.py:202 const/__init__.py:306 msgid "commented question" msgstr "" -#: const/__init__.py:198 const/__init__.py:302 +#: const/__init__.py:203 const/__init__.py:307 msgid "commented answer" msgstr "" -#: const/__init__.py:199 +#: const/__init__.py:204 msgid "edited question" msgstr "" -#: const/__init__.py:200 +#: const/__init__.py:205 msgid "edited answer" msgstr "" -#: const/__init__.py:201 +#: const/__init__.py:206 msgid "received badge" msgstr "" -#: const/__init__.py:202 +#: const/__init__.py:207 msgid "marked best answer" msgstr "" -#: const/__init__.py:203 +#: const/__init__.py:208 msgid "upvoted" msgstr "" -#: const/__init__.py:204 +#: const/__init__.py:209 msgid "downvoted" msgstr "" -#: const/__init__.py:205 +#: const/__init__.py:210 msgid "canceled vote" msgstr "" -#: const/__init__.py:206 +#: const/__init__.py:211 msgid "deleted question" msgstr "" -#: const/__init__.py:207 +#: const/__init__.py:212 msgid "deleted answer" msgstr "" -#: const/__init__.py:208 +#: const/__init__.py:213 msgid "marked offensive" msgstr "" -#: const/__init__.py:209 +#: const/__init__.py:214 msgid "updated tags" msgstr "" -#: const/__init__.py:210 +#: const/__init__.py:215 msgid "selected favorite" msgstr "" -#: const/__init__.py:211 +#: const/__init__.py:216 msgid "completed user profile" msgstr "" -#: const/__init__.py:212 +#: const/__init__.py:217 msgid "email update sent to user" msgstr "" -#: const/__init__.py:213 +#: const/__init__.py:218 msgid "a post was shared" msgstr "" -#: const/__init__.py:216 +#: const/__init__.py:221 msgid "reminder about unanswered questions sent" msgstr "" -#: const/__init__.py:220 +#: const/__init__.py:225 msgid "reminder about accepting the best answer sent" msgstr "" -#: const/__init__.py:222 +#: const/__init__.py:227 msgid "mentioned in the post" msgstr "" -#: const/__init__.py:225 +#: const/__init__.py:230 msgid "created tag description" msgstr "" -#: const/__init__.py:229 +#: const/__init__.py:234 msgid "updated tag description" msgstr "" -#: const/__init__.py:231 +#: const/__init__.py:236 msgid "made a new post" msgstr "" -#: const/__init__.py:234 +#: const/__init__.py:239 msgid "made an edit" msgstr "" -#: const/__init__.py:238 +#: const/__init__.py:243 msgid "created post reject reason" msgstr "" -#: const/__init__.py:242 +#: const/__init__.py:247 msgid "updated post reject reason" msgstr "" -#: const/__init__.py:300 +#: const/__init__.py:305 msgid "answered question" msgstr "" -#: const/__init__.py:303 +#: const/__init__.py:308 msgid "accepted answer" msgstr "" -#: const/__init__.py:307 +#: const/__init__.py:312 msgid "[closed]" msgstr "" -#: const/__init__.py:308 +#: const/__init__.py:313 msgid "[deleted]" msgstr "" -#: const/__init__.py:309 views/readers.py:642 +#: const/__init__.py:314 views/readers.py:681 msgid "initial version" msgstr "" -#: const/__init__.py:310 +#: const/__init__.py:315 msgid "retagged" msgstr "" -#: const/__init__.py:311 +#: const/__init__.py:316 msgid "[private]" msgstr "" -#: const/__init__.py:320 +#: const/__init__.py:325 msgid "show all tags" msgstr "" -#: const/__init__.py:321 const/__init__.py:330 const/__init__.py:336 -#: const/__init__.py:342 +#: const/__init__.py:326 const/__init__.py:335 const/__init__.py:341 +#: const/__init__.py:347 msgid "exclude ignored tags" msgstr "" -#: const/__init__.py:322 const/__init__.py:331 const/__init__.py:343 +#: const/__init__.py:327 const/__init__.py:336 const/__init__.py:348 msgid "only interesting tags" msgstr "" -#: const/__init__.py:326 const/__init__.py:337 const/__init__.py:344 +#: const/__init__.py:331 const/__init__.py:342 const/__init__.py:349 msgid "only subscribed tags" msgstr "" -#: const/__init__.py:329 const/__init__.py:335 const/__init__.py:341 +#: const/__init__.py:334 const/__init__.py:340 const/__init__.py:346 msgid "email for all tags" msgstr "" -#: const/__init__.py:348 +#: const/__init__.py:353 msgid "instantly" msgstr "" -#: const/__init__.py:349 +#: const/__init__.py:354 msgid "daily" msgstr "" -#: const/__init__.py:350 +#: const/__init__.py:355 msgid "weekly" msgstr "" -#: const/__init__.py:351 +#: const/__init__.py:356 msgid "no email" msgstr "" -#: const/__init__.py:358 +#: const/__init__.py:363 msgid "identicon" msgstr "" -#: const/__init__.py:359 +#: const/__init__.py:364 msgid "mystery-man" msgstr "" -#: const/__init__.py:360 +#: const/__init__.py:365 msgid "monsterid" msgstr "" -#: const/__init__.py:361 +#: const/__init__.py:366 msgid "wavatar" msgstr "" -#: const/__init__.py:362 +#: const/__init__.py:367 msgid "retro" msgstr "" -#: const/__init__.py:409 templates/badges.html:33 +#: const/__init__.py:414 templates/badges.html:34 msgid "gold" msgstr "" -#: const/__init__.py:410 templates/badges.html:43 +#: const/__init__.py:415 templates/badges.html:44 msgid "silver" msgstr "" -#: const/__init__.py:411 templates/badges.html:50 +#: const/__init__.py:416 templates/badges.html:51 msgid "bronze" msgstr "" -#: const/__init__.py:423 +#: const/__init__.py:428 msgid "None" msgstr "" -#: const/__init__.py:424 +#: const/__init__.py:429 msgid "Gravatar" msgstr "" -#: const/__init__.py:425 +#: const/__init__.py:430 msgid "Uploaded Avatar" msgstr "" -#: const/__init__.py:429 +#: const/__init__.py:434 msgid "date descendant" msgstr "" -#: const/__init__.py:430 +#: const/__init__.py:435 msgid "date ascendant" msgstr "" -#: const/__init__.py:431 +#: const/__init__.py:436 msgid "activity descendant" msgstr "" -#: const/__init__.py:432 +#: const/__init__.py:437 msgid "activity ascendant" msgstr "" -#: const/__init__.py:433 +#: const/__init__.py:438 msgid "answers descendant" msgstr "" -#: const/__init__.py:434 +#: const/__init__.py:439 msgid "answers ascendant" msgstr "" -#: const/__init__.py:435 +#: const/__init__.py:440 msgid "votes descendant" msgstr "" -#: const/__init__.py:436 +#: const/__init__.py:441 msgid "votes ascendant" msgstr "" @@ -3031,7 +3215,7 @@ msgid "" "reach a resolution." msgstr "" -#: const/message_keys.py:52 models/__init__.py:1136 +#: const/message_keys.py:52 models/__init__.py:1158 msgid "" "Sorry, your account appears to be suspended and you cannot make new posts " "until this issue is resolved. You can, however edit your existing posts. " @@ -3044,7 +3228,7 @@ msgid "" "screen name, if necessary." msgstr "" -#: deps/django_authopenid/forms.py:112 deps/django_authopenid/views.py:206 +#: deps/django_authopenid/forms.py:112 deps/django_authopenid/views.py:208 msgid "i-names are not supported" msgstr "" @@ -3069,35 +3253,37 @@ msgstr "" msgid "Passwords did not match" msgstr "" -#: deps/django_authopenid/forms.py:300 +#: deps/django_authopenid/forms.py:300 deps/django_authopenid/forms.py:355 #, python-format -msgid "Please choose password > %(len)s characters" +msgid "choose password > %(len)s characters" msgstr "" -#: deps/django_authopenid/forms.py:338 -msgid "Current password" +#: deps/django_authopenid/forms.py:340 utils/forms.py:265 +msgid "password is required" msgstr "" -#: deps/django_authopenid/forms.py:349 -msgid "" -"Old password is incorrect. Please enter the correct " -"password." +#: deps/django_authopenid/forms.py:346 +msgid "retype your password" +msgstr "" + +#: deps/django_authopenid/forms.py:366 utils/forms.py:270 +msgid "entered passwords did not match, please try again" msgstr "" -#: deps/django_authopenid/forms.py:399 +#: deps/django_authopenid/forms.py:416 msgid "Sorry, we don't have this email address in the database" msgstr "" -#: deps/django_authopenid/forms.py:438 +#: deps/django_authopenid/forms.py:455 msgid "Your user name (<i>required</i>)" msgstr "" -#: deps/django_authopenid/forms.py:455 +#: deps/django_authopenid/forms.py:472 msgid "sorry, there is no such user name" msgstr "" #: deps/django_authopenid/urls.py:14 deps/django_authopenid/urls.py:20 -#: deps/django_authopenid/urls.py:23 setup_templates/settings.py:229 +#: deps/django_authopenid/urls.py:23 setup_templates/settings.py:232 msgid "signin/" msgstr "" @@ -3121,15 +3307,15 @@ msgstr "" msgid "signup/" msgstr "" -#: deps/django_authopenid/urls.py:38 +#: deps/django_authopenid/urls.py:43 msgid "logout/" msgstr "" -#: deps/django_authopenid/urls.py:43 +#: deps/django_authopenid/urls.py:48 msgid "recover/" msgstr "" -#: deps/django_authopenid/urls.py:45 +#: deps/django_authopenid/urls.py:50 msgid "verify-email/" msgstr "" @@ -3138,7 +3324,7 @@ msgstr "" msgid "%(site)s user name and password" msgstr "" -#: deps/django_authopenid/util.py:385 templates/authopenid/signin.html:117 +#: deps/django_authopenid/util.py:385 templates/authopenid/signin.html:120 #: templates/authopenid/widget_signin.html:120 msgid "Create a password-protected account" msgstr "" @@ -3225,88 +3411,88 @@ msgstr "" msgid "Sign in with your %(provider)s account" msgstr "" -#: deps/django_authopenid/views.py:213 +#: deps/django_authopenid/views.py:215 #, python-format msgid "OpenID %(openid_url)s is invalid" msgstr "" -#: deps/django_authopenid/views.py:391 +#: deps/django_authopenid/views.py:394 msgid "" "Sorry, there was some problem connecting to the login provider, please try " "again or use another login method" msgstr "" -#: deps/django_authopenid/views.py:520 +#: deps/django_authopenid/views.py:523 deps/django_authopenid/views.py:798 msgid "Your new password is saved" msgstr "" -#: deps/django_authopenid/views.py:568 deps/django_authopenid/views.py:583 +#: deps/django_authopenid/views.py:571 deps/django_authopenid/views.py:586 #, python-format msgid "" "Unfortunately, there was some problem when connecting to %(provider)s, " "please try again or use another provider" msgstr "" -#: deps/django_authopenid/views.py:613 +#: deps/django_authopenid/views.py:616 msgid "The login password combination was not correct" msgstr "" -#: deps/django_authopenid/views.py:717 +#: deps/django_authopenid/views.py:720 msgid "Please click any of the icons below to sign in" msgstr "" -#: deps/django_authopenid/views.py:719 +#: deps/django_authopenid/views.py:722 msgid "Account recovery email sent" msgstr "" -#: deps/django_authopenid/views.py:722 +#: deps/django_authopenid/views.py:725 msgid "Please add one or more login methods." msgstr "" -#: deps/django_authopenid/views.py:724 +#: deps/django_authopenid/views.py:727 msgid "If you wish, please add, remove or re-validate your login methods" msgstr "" -#: deps/django_authopenid/views.py:726 +#: deps/django_authopenid/views.py:729 msgid "Please wait a second! Your account is recovered, but ..." msgstr "" -#: deps/django_authopenid/views.py:728 +#: deps/django_authopenid/views.py:731 msgid "Sorry, this account recovery key has expired or is invalid" msgstr "" -#: deps/django_authopenid/views.py:801 +#: deps/django_authopenid/views.py:818 #, python-format msgid "Login method %(provider_name)s does not exist" msgstr "" -#: deps/django_authopenid/views.py:807 +#: deps/django_authopenid/views.py:824 msgid "Oops, sorry - there was some error - please try again" msgstr "" -#: deps/django_authopenid/views.py:882 +#: deps/django_authopenid/views.py:905 msgid "" "If you are trying to sign in to another account, please sign out first. " "Otherwise, please report the incident to the site administrator." msgstr "" -#: deps/django_authopenid/views.py:914 +#: deps/django_authopenid/views.py:937 #, python-format msgid "Your %(provider)s login works fine" msgstr "" -#: deps/django_authopenid/views.py:1112 +#: deps/django_authopenid/views.py:1135 msgid "" "Sorry, registration failed. The token can be already used or has expired. " "Please try again" msgstr "" -#: deps/django_authopenid/views.py:1257 +#: deps/django_authopenid/views.py:1280 #, python-format msgid "Recover your %(site)s account" msgstr "" -#: deps/django_authopenid/views.py:1292 +#: deps/django_authopenid/views.py:1315 msgid "Please check your email and visit the enclosed link." msgstr "" @@ -3398,23 +3584,23 @@ msgid "" "of your user account</p>" msgstr "" -#: mail/lamson_handlers.py:160 +#: mail/lamson_handlers.py:162 msgid "" "You were replying to an email address unknown to the system or " "you were replying from a different address from the one where " "you received the notification." msgstr "" -#: mail/lamson_handlers.py:251 +#: mail/lamson_handlers.py:265 #, python-format msgid "Re: Welcome to %(site_name)s" msgstr "" -#: mail/lamson_handlers.py:258 +#: mail/lamson_handlers.py:272 msgid "Please reply to the welcome email without editing it" msgstr "" -#: mail/lamson_handlers.py:318 +#: mail/lamson_handlers.py:340 #, python-format msgid "Re: %s" msgstr "" @@ -3432,14 +3618,14 @@ msgstr "" msgid "Please accept the best answer for these questions:" msgstr "" -#: management/commands/send_email_alerts.py:434 +#: management/commands/send_email_alerts.py:436 #, python-format msgid "%(question_count)d updated question about %(topics)s" msgid_plural "%(question_count)d updated questions about %(topics)s" msgstr[0] "" msgstr[1] "" -#: management/commands/send_email_alerts.py:455 +#: management/commands/send_email_alerts.py:457 msgid "new question" msgstr "" @@ -3455,90 +3641,94 @@ msgstr[1] "" msgid "Please log in to use %s" msgstr "" -#: models/__init__.py:569 models/__init__.py:1388 views/writers.py:226 +#: models/__init__.py:591 models/__init__.py:1410 views/writers.py:226 msgid "Sorry, but you have only read access" msgstr "" -#: models/__init__.py:573 +#: models/__init__.py:595 msgid "Sorry, this operation is not allowed" msgstr "" -#: models/__init__.py:623 +#: models/__init__.py:645 msgid "" "Sorry, you cannot accept or unaccept best answers because your account is " "blocked" msgstr "" -#: models/__init__.py:627 +#: models/__init__.py:649 msgid "" "Sorry, you cannot accept or unaccept best answers because your account is " "suspended" msgstr "" -#: models/__init__.py:641 +#: models/__init__.py:663 #, python-format msgid "" ">%(points)s points required to accept or unaccept your own answer to your " "own question" msgstr "" -#: models/__init__.py:665 +#: models/__init__.py:687 #, python-format msgid "" "Sorry, you will be able to accept this answer only after %(will_be_able_at)s" msgstr "" -#: models/__init__.py:674 +#: models/__init__.py:696 #, python-format msgid "" "Sorry, only moderators or original author of the question - %(username)s - " "can accept or unaccept the best answer" msgstr "" -#: models/__init__.py:697 +#: models/__init__.py:719 msgid "Sorry, you cannot vote for your own posts" msgstr "" -#: models/__init__.py:701 -msgid "Sorry your account appears to be blocked " +#: models/__init__.py:723 +msgid "" +"Sorry your account appears to be blocked and you cannot vote - please " +"contact the site administrator to resolve the issue" msgstr "" -#: models/__init__.py:706 -msgid "Sorry your account appears to be suspended " +#: models/__init__.py:728 +msgid "" +"Sorry your account appears to be suspended and you cannot vote - please " +"contact the site administrator to resolve the issue" msgstr "" -#: models/__init__.py:716 +#: models/__init__.py:738 #, python-format msgid ">%(points)s points required to upvote" msgstr "" -#: models/__init__.py:722 +#: models/__init__.py:744 #, python-format msgid ">%(points)s points required to downvote" msgstr "" -#: models/__init__.py:737 +#: models/__init__.py:759 msgid "Sorry, blocked users cannot upload files" msgstr "" -#: models/__init__.py:738 +#: models/__init__.py:760 msgid "Sorry, suspended users cannot upload files" msgstr "" -#: models/__init__.py:740 +#: models/__init__.py:762 #, python-format msgid "sorry, file uploading requires karma >%(min_rep)s" msgstr "" -#: models/__init__.py:759 +#: models/__init__.py:781 msgid "Could not post, because your karma is insufficient to publish links" msgstr "" -#: models/__init__.py:785 +#: models/__init__.py:807 msgid "Sorry, you already gave an answer, please edit it instead." msgstr "" -#: models/__init__.py:809 +#: models/__init__.py:831 #, python-format msgid "" "Sorry, comments (except the last one) are editable only within %(minutes)s " @@ -3549,56 +3739,56 @@ msgid_plural "" msgstr[0] "" msgstr[1] "" -#: models/__init__.py:821 +#: models/__init__.py:843 msgid "Sorry, but only post owners or moderators can edit comments" msgstr "" -#: models/__init__.py:850 +#: models/__init__.py:872 msgid "" "Sorry, since your account is suspended you can comment only your own posts" msgstr "" -#: models/__init__.py:854 +#: models/__init__.py:876 #, python-format msgid "" "Sorry, to comment any post a minimum reputation of %(min_rep)s points is " "required. You can still comment your own posts and answers to your questions" msgstr "" -#: models/__init__.py:884 +#: models/__init__.py:906 msgid "" "This post has been deleted and can be seen only by post owners, site " "administrators and moderators" msgstr "" -#: models/__init__.py:901 +#: models/__init__.py:923 msgid "" "Sorry, only moderators, site administrators and post owners can edit deleted " "posts" msgstr "" -#: models/__init__.py:917 +#: models/__init__.py:939 msgid "Sorry, since your account is blocked you cannot edit posts" msgstr "" -#: models/__init__.py:921 +#: models/__init__.py:943 msgid "Sorry, since your account is suspended you can edit only your own posts" msgstr "" -#: models/__init__.py:926 +#: models/__init__.py:948 #, python-format msgid "" "Sorry, to edit wiki posts, a minimum reputation of %(min_rep)s is required" msgstr "" -#: models/__init__.py:933 +#: models/__init__.py:955 #, python-format msgid "" "Sorry, to edit other people's posts, a minimum reputation of %(min_rep)s is " "required" msgstr "" -#: models/__init__.py:996 +#: models/__init__.py:1018 msgid "" "Sorry, cannot delete your question since it has an upvoted answer posted by " "someone else" @@ -3608,101 +3798,101 @@ msgid_plural "" msgstr[0] "" msgstr[1] "" -#: models/__init__.py:1011 +#: models/__init__.py:1033 msgid "Sorry, since your account is blocked you cannot delete posts" msgstr "" -#: models/__init__.py:1015 +#: models/__init__.py:1037 msgid "" "Sorry, since your account is suspended you can delete only your own posts" msgstr "" -#: models/__init__.py:1019 +#: models/__init__.py:1041 #, python-format msgid "" "Sorry, to delete other people's posts, a minimum reputation of %(min_rep)s " "is required" msgstr "" -#: models/__init__.py:1040 +#: models/__init__.py:1062 msgid "Sorry, since your account is blocked you cannot close questions" msgstr "" -#: models/__init__.py:1044 +#: models/__init__.py:1066 msgid "Sorry, since your account is suspended you cannot close questions" msgstr "" -#: models/__init__.py:1048 +#: models/__init__.py:1070 #, python-format msgid "" "Sorry, to close other people' posts, a minimum reputation of %(min_rep)s is " "required" msgstr "" -#: models/__init__.py:1057 +#: models/__init__.py:1079 #, python-format msgid "" "Sorry, to close own question a minimum reputation of %(min_rep)s is required" msgstr "" -#: models/__init__.py:1084 +#: models/__init__.py:1106 #, python-format msgid "" "Sorry, only administrators, moderators or post owners with reputation > " "%(min_rep)s can reopen questions." msgstr "" -#: models/__init__.py:1090 +#: models/__init__.py:1112 #, python-format msgid "" "Sorry, to reopen own question a minimum reputation of %(min_rep)s is required" msgstr "" -#: models/__init__.py:1095 +#: models/__init__.py:1117 msgid "Sorry, you cannot reopen questions because your account is blocked" msgstr "" -#: models/__init__.py:1100 +#: models/__init__.py:1122 msgid "Sorry, you cannot reopen questions because your account is suspended" msgstr "" -#: models/__init__.py:1123 +#: models/__init__.py:1145 msgid "You have flagged this question before and cannot do it more than once" msgstr "" -#: models/__init__.py:1131 +#: models/__init__.py:1153 msgid "Sorry, since your account is blocked you cannot flag posts as offensive" msgstr "" -#: models/__init__.py:1142 +#: models/__init__.py:1164 #, python-format msgid "" "Sorry, to flag posts as offensive a minimum reputation of %(min_rep)s is " "required" msgstr "" -#: models/__init__.py:1163 +#: models/__init__.py:1185 #, python-format msgid "" "Sorry, you have exhausted the maximum number of %(max_flags_per_day)s " "offensive flags per day." msgstr "" -#: models/__init__.py:1175 +#: models/__init__.py:1197 msgid "cannot remove non-existing flag" msgstr "" -#: models/__init__.py:1181 +#: models/__init__.py:1203 msgid "Sorry, since your account is blocked you cannot remove flags" msgstr "" -#: models/__init__.py:1185 +#: models/__init__.py:1207 msgid "" "Sorry, your account appears to be suspended and you cannot remove flags. " "Please contact the forum administrator to reach a resolution." msgstr "" -#: models/__init__.py:1191 +#: models/__init__.py:1213 #, python-format msgid "Sorry, to flag posts a minimum reputation of %(min_rep)d is required" msgid_plural "" @@ -3710,221 +3900,221 @@ msgid_plural "" msgstr[0] "" msgstr[1] "" -#: models/__init__.py:1210 +#: models/__init__.py:1232 msgid "you don't have the permission to remove all flags" msgstr "" -#: models/__init__.py:1211 +#: models/__init__.py:1233 msgid "no flags for this entry" msgstr "" -#: models/__init__.py:1235 +#: models/__init__.py:1257 msgid "" "Sorry, only question owners, site administrators and moderators can retag " "deleted questions" msgstr "" -#: models/__init__.py:1243 +#: models/__init__.py:1265 msgid "Sorry, since your account is blocked you cannot retag questions" msgstr "" -#: models/__init__.py:1247 +#: models/__init__.py:1269 msgid "" "Sorry, since your account is suspended you can retag only your own questions" msgstr "" -#: models/__init__.py:1251 +#: models/__init__.py:1273 #, python-format msgid "" "Sorry, to retag questions a minimum reputation of %(min_rep)s is required" msgstr "" -#: models/__init__.py:1270 +#: models/__init__.py:1292 msgid "Sorry, since your account is blocked you cannot delete comment" msgstr "" -#: models/__init__.py:1274 +#: models/__init__.py:1296 msgid "" "Sorry, since your account is suspended you can delete only your own comments" msgstr "" -#: models/__init__.py:1278 +#: models/__init__.py:1300 #, python-format msgid "Sorry, to delete comments reputation of %(min_rep)s is required" msgstr "" -#: models/__init__.py:1303 +#: models/__init__.py:1325 msgid "sorry, but older votes cannot be revoked" msgstr "" -#: models/__init__.py:1995 utils/functions.py:98 +#: models/__init__.py:2045 utils/functions.py:98 #, python-format msgid "on %(date)s" msgstr "" -#: models/__init__.py:1997 +#: models/__init__.py:2047 msgid "in two days" msgstr "" -#: models/__init__.py:1999 +#: models/__init__.py:2049 msgid "tomorrow" msgstr "" -#: models/__init__.py:2001 +#: models/__init__.py:2051 #, python-format msgid "in %(hr)d hour" msgid_plural "in %(hr)d hours" msgstr[0] "" msgstr[1] "" -#: models/__init__.py:2003 +#: models/__init__.py:2053 #, python-format msgid "in %(min)d min" msgid_plural "in %(min)d mins" msgstr[0] "" msgstr[1] "" -#: models/__init__.py:2004 +#: models/__init__.py:2054 #, python-format msgid "%(days)d day" msgid_plural "%(days)d days" msgstr[0] "" msgstr[1] "" -#: models/__init__.py:2006 +#: models/__init__.py:2056 #, python-format msgid "" "New users must wait %(days)s before answering their own question. You can " "post an answer %(left)s" msgstr "" -#: models/__init__.py:2194 templates/email/feedback_email.txt:9 +#: models/__init__.py:2244 templates/email/feedback_email.txt:9 msgid "Anonymous" msgstr "" -#: models/__init__.py:2298 +#: models/__init__.py:2348 msgid "Site Adminstrator" msgstr "" -#: models/__init__.py:2300 +#: models/__init__.py:2350 msgid "Forum Moderator" msgstr "" -#: models/__init__.py:2302 +#: models/__init__.py:2352 msgid "Suspended User" msgstr "" -#: models/__init__.py:2304 +#: models/__init__.py:2354 msgid "Blocked User" msgstr "" -#: models/__init__.py:2306 +#: models/__init__.py:2356 msgid "Registered User" msgstr "" -#: models/__init__.py:2308 +#: models/__init__.py:2358 msgid "Watched User" msgstr "" -#: models/__init__.py:2310 +#: models/__init__.py:2360 msgid "Approved User" msgstr "" -#: models/__init__.py:2495 +#: models/__init__.py:2551 #, python-format msgid "%(username)s karma is %(reputation)s" msgstr "" -#: models/__init__.py:2508 +#: models/__init__.py:2564 #, python-format msgid "one gold badge" msgid_plural "%(count)d gold badges" msgstr[0] "" msgstr[1] "" -#: models/__init__.py:2515 +#: models/__init__.py:2571 #, python-format msgid "one silver badge" msgid_plural "%(count)d silver badges" msgstr[0] "" msgstr[1] "" -#: models/__init__.py:2522 +#: models/__init__.py:2578 #, python-format msgid "one bronze badge" msgid_plural "%(count)d bronze badges" msgstr[0] "" msgstr[1] "" -#: models/__init__.py:2533 +#: models/__init__.py:2589 #, python-format msgid "%(item1)s and %(item2)s" msgstr "" -#: models/__init__.py:2535 +#: models/__init__.py:2591 #, python-format msgid "%(user)s has %(badges)s" msgstr "" -#: models/__init__.py:2682 +#: models/__init__.py:2738 #, python-format msgid "At least %d karma point is required to post links" msgid_plural "At least %d karma points is required to post links" msgstr[0] "" msgstr[1] "" -#: models/__init__.py:3159 +#: models/__init__.py:3221 #, python-format msgid "%(user)s shared a %(post_link)s." msgstr "" -#: models/__init__.py:3162 models/__init__.py:3172 +#: models/__init__.py:3224 models/__init__.py:3234 #, python-format msgid "%(user)s edited a %(post_link)s." msgstr "" -#: models/__init__.py:3164 +#: models/__init__.py:3226 #, python-format msgid "%(user)s posted a %(post_link)s" msgstr "" -#: models/__init__.py:3167 +#: models/__init__.py:3229 #, python-format msgid "%(user)s edited an %(post_link)s." msgstr "" -#: models/__init__.py:3169 +#: models/__init__.py:3231 #, python-format msgid "%(user)s posted an %(post_link)s." msgstr "" -#: models/__init__.py:3174 +#: models/__init__.py:3236 #, python-format msgid "%(user)s posted a %(post_link)s." msgstr "" -#: models/__init__.py:3190 +#: models/__init__.py:3252 msgid "To reply, PLEASE WRITE ABOVE THIS LINE." msgstr "" -#: models/__init__.py:3232 +#: models/__init__.py:3294 #, python-format msgid "\"%(title)s\"" msgstr "" -#: models/__init__.py:3384 +#: models/__init__.py:3446 #, python-format msgid "" "Congratulations, you have received a badge '%(badge_name)s'. Check out <a " "href=\"%(user_profile)s\">your profile</a>." msgstr "" -#: models/__init__.py:3657 +#: models/__init__.py:3725 #, python-format msgid "Welcome to %(site_name)s" msgstr "" -#: models/__init__.py:3678 views/commands.py:697 +#: models/__init__.py:3746 views/commands.py:697 msgid "Your tag subscription was saved, thanks!" msgstr "" @@ -4194,57 +4384,62 @@ msgstr "" msgid "message" msgstr "" -#: models/post.py:414 +#: models/post.py:418 msgid "Question: " msgstr "" -#: models/post.py:416 +#: models/post.py:420 msgid "Answer: " msgstr "" -#: models/post.py:1570 +#: models/post.py:912 templates/question/answer_controls.html:58 +#: templatetags/extra_filters_jinja.py:128 +msgid "more" +msgstr "" + +#: models/post.py:1602 msgid "Sorry, this question has been deleted and is no longer accessible" msgstr "" -#: models/post.py:1586 +#: models/post.py:1618 msgid "" "Sorry, the answer you are looking for is no longer available, because the " "parent question has been removed" msgstr "" -#: models/post.py:1593 +#: models/post.py:1625 msgid "Sorry, this answer has been removed and is no longer accessible" msgstr "" -#: models/post.py:1609 +#: models/post.py:1641 msgid "" "Sorry, the comment you are looking for is no longer accessible, because the " "parent question has been removed" msgstr "" -#: models/post.py:1616 +#: models/post.py:1648 msgid "" "Sorry, the comment you are looking for is no longer accessible, because the " "parent answer has been removed" msgstr "" -#: models/post.py:1638 +#: models/post.py:1670 msgid "This post is temporarily not available" msgstr "" -#: models/post.py:2147 +#: models/post.py:2179 #, python-format msgid "" "Thank you for your post to %(site)s. It will be published after the " "moderators review." msgstr "" -#: models/post.py:2151 +#: models/post.py:2183 #, python-format msgid "your post to %(site)s" msgstr "" -#: models/post.py:2158 +#: models/post.py:2190 msgid "" "Your post was placed on the moderation queue and will be published after the " "moderator approval." @@ -4259,24 +4454,24 @@ msgstr "" msgid "\" and more" msgstr "" -#: models/question.py:834 +#: models/question.py:840 #, python-format msgid "%(count)d answer:" msgid_plural "%(count)d answers:" msgstr[0] "" msgstr[1] "" -#: models/question.py:1346 +#: models/question.py:1359 #, python-format msgid "Tag %s is new and will be submitted for the moderators approval" msgstr "" -#: models/question.py:1351 models/tag.py:217 +#: models/question.py:1364 models/tag.py:217 #, python-format msgid "Tags %s are new and will be submitted for the moderators approval" msgstr "" -#: models/question.py:1590 +#: models/question.py:1603 #, python-format msgid "Please, <a href=\"%s\">review your question</a>." msgstr "" @@ -4410,7 +4605,7 @@ msgid "This might have happened for the following reasons:" msgstr "" #: templates/404.html:17 -msgid "this question or answer has been deleted;" +msgid "This page has been deleted" msgstr "" #: templates/404.html:18 @@ -4435,18 +4630,6 @@ msgstr "" msgid "report this problem" msgstr "" -#: templates/404.html:30 templates/500.html:11 -msgid "back to previous page" -msgstr "" - -#: templates/404.html:31 templates/widgets/scope_nav.html:17 -msgid "see all questions" -msgstr "" - -#: templates/404.html:32 -msgid "see all tags" -msgstr "" - #: templates/500.html:3 templates/500.html.py:5 msgid "Internal server error" msgstr "" @@ -4456,34 +4639,23 @@ msgid "system error log is recorded, error will be fixed as soon as possible" msgstr "" #: templates/500.html:9 -msgid "please report the error to the site administrators if you wish" -msgstr "" - -#: templates/500.html:12 -msgid "see latest questions" -msgstr "" - -#: templates/500.html:13 -msgid "see tags" -msgstr "" - -#: templates/answer_edit.html:4 templates/answer_edit.html.py:10 -msgid "Edit answer" +msgid "please report the error to the site administrators" msgstr "" -#: templates/answer_edit.html:10 templates/question_edit.html:9 +#: templates/answer_edit.html:11 templates/question_edit.html:9 #: templates/question_retag.html:5 templates/revisions.html:7 msgid "back" msgstr "" -#: templates/answer_edit.html:41 templates/question_edit.html:61 +#: templates/answer_edit.html:42 templates/question_edit.html:61 msgid "Save edit" msgstr "" -#: templates/answer_edit.html:46 templates/close.html:16 +#: templates/answer_edit.html:47 templates/close.html:16 #: templates/feedback.html:64 templates/question_edit.html:62 -#: templates/question_retag.html:22 templates/reopen.html:28 -#: templates/subscribe_for_tags.html:16 +#: templates/question_retag.html:22 templates/reopen.html:26 +#: templates/subscribe_for_tags.html:16 templates/avatar/add.html:17 +#: templates/avatar/change.html:26 templates/avatar/confirm_delete.html:16 #: templates/user_profile/reject_post_dialog.html:36 #: templates/user_profile/reject_post_dialog.html:74 #: templates/user_profile/reject_post_dialog.html:104 @@ -4491,24 +4663,19 @@ msgstr "" msgid "Cancel" msgstr "" -#: templates/answer_edit.html:86 templates/answer_edit.html.py:89 -#: templates/ask.html:81 templates/ask.html.py:84 +#: templates/answer_edit.html:87 templates/answer_edit.html.py:90 +#: templates/ask.html:82 templates/ask.html.py:85 #: templates/question_edit.html:100 templates/question_edit.html.py:103 -#: templates/question/javascript.html:72 templates/question/javascript.html:75 -#: templates/widgets/edit_post.html:73 +#: templates/question/javascript.html:103 +#: templates/question/javascript.html:106 templates/widgets/edit_post.html:73 msgid "hide preview" msgstr "" -#: templates/answer_edit.html:89 templates/ask.html:84 -#: templates/question_edit.html:103 templates/question/javascript.html:75 +#: templates/answer_edit.html:90 templates/ask.html:85 +#: templates/question_edit.html:103 templates/question/javascript.html:106 msgid "show preview" msgstr "" -#: templates/ask.html:4 templates/widgets/ask_button.html:9 -#: templates/widgets/ask_form.html:67 -msgid "Ask Your Question" -msgstr "" - #: templates/ask.html:21 msgid "" "since you are not logged in right now, you will be asked to sign in or " @@ -4524,34 +4691,28 @@ msgid "" "that. Meanwhile, your question will saved as pending." msgstr "" -#: templates/ask.html:29 -msgid "please, try to make your question interesting to this community" -msgstr "" - -#: templates/ask.html:30 templates/widgets/answer_edit_tips.html:12 -#: templates/widgets/question_edit_tips.html:8 +#: templates/ask.html:30 templates/widgets/answer_edit_tips.html:8 +#: templates/widgets/question_edit_tips.html:6 msgid "provide enough details" msgstr "" -#: templates/ask.html:31 templates/widgets/answer_edit_tips.html:15 -#: templates/widgets/question_edit_tips.html:11 +#: templates/ask.html:31 templates/widgets/answer_edit_tips.html:9 +#: templates/widgets/question_edit_tips.html:7 msgid "be clear and concise" msgstr "" -#: templates/ask.html:36 templates/widgets/answer_edit_tips.html:20 -#: templates/widgets/question_edit_tips.html:16 +#: templates/ask.html:36 msgid "see frequently asked questions" msgstr "" #: templates/ask.html:36 templates/faq_static.html:3 -#: templates/faq_static.html.py:5 templates/widgets/answer_edit_tips.html:20 -#: templates/widgets/question_edit_tips.html:16 views/meta.py:71 +#: templates/faq_static.html.py:5 views/meta.py:71 msgid "FAQ" msgstr "" #: templates/badge.html:5 templates/badge.html.py:9 #: templates/user_profile/user_recent.html:18 -#: templates/user_profile/user_stats.html:73 +#: templates/user_profile/user_stats.html:72 #, python-format msgid "%(name)s" msgstr "" @@ -4566,7 +4727,7 @@ msgid "Badge \"%(name)s\"" msgstr "" #: templates/badge.html:9 templates/user_profile/user_recent.html:16 -#: templates/user_profile/user_stats.html:71 +#: templates/user_profile/user_stats.html:70 #, python-format msgid "%(description)s" msgstr "" @@ -4581,37 +4742,33 @@ msgstr[1] "" msgid "Badges" msgstr "" -#: templates/badges.html:7 -msgid "Community gives you awards for your questions, answers and votes." -msgstr "" - -#: templates/badges.html:8 +#: templates/badges.html:9 msgid "" "Below is the list of available badges and number of times each type of badge " "has been awarded." msgstr "" -#: templates/badges.html:31 +#: templates/badges.html:32 msgid "Community badges" msgstr "Badge levels" -#: templates/badges.html:33 +#: templates/badges.html:34 msgid "gold badge: the highest honor and is very rare" msgstr "" -#: templates/badges.html:36 +#: templates/badges.html:37 msgid "" "Gold badge is the highest award in this community. To obtain it you have to " "show \n" "profound knowledge and ability in addition to your active participation." msgstr "" -#: templates/badges.html:42 templates/badges.html.py:46 +#: templates/badges.html:43 templates/badges.html.py:47 msgid "" "silver badge: occasionally awarded for the very high quality contributions" msgstr "" -#: templates/badges.html:49 templates/badges.html.py:53 +#: templates/badges.html:50 templates/badges.html.py:54 msgid "bronze badge: often given as a special honor" msgstr "" @@ -4620,14 +4777,6 @@ msgstr "" msgid "RSS feed from %(site_title)s" msgstr "" -#: templates/close.html:3 templates/close.html.py:5 -msgid "Close question" -msgstr "" - -#: templates/close.html:6 -msgid "Close the question" -msgstr "" - #: templates/close.html:11 msgid "Reasons" msgstr "" @@ -4866,7 +5015,7 @@ msgid "Send Feedback" msgstr "" #: templates/groups.html:3 templates/groups.html.py:6 -#: templates/question/sidebar.html:108 +#: templates/question/sidebar.html:107 #: templates/tags/list_bulk_tag_subscription.html:15 msgid "Groups" msgstr "" @@ -5075,23 +5224,23 @@ msgstr "" msgid "There are no questions with this tag yet" msgstr "" -#: templates/list_suggested_tags.html:62 +#: templates/list_suggested_tags.html:61 #, python-format msgid "Apply tag \"%(name)s\" to all above questions" msgstr "" -#: templates/list_suggested_tags.html:63 +#: templates/list_suggested_tags.html:62 msgid "Reject tag" msgstr "" -#: templates/list_suggested_tags.html:71 templates/tags/content.html:5 +#: templates/list_suggested_tags.html:70 templates/tags/content.html:5 #: templates/tags/content.html.py:31 msgid "Nothing found" msgstr "" #: templates/macros.html:5 #, python-format -msgid "Share this question on %(site)s" +msgid "Share this content on %(site)s" msgstr "" #: templates/macros.html:44 @@ -5102,14 +5251,6 @@ msgstr "" msgid "anonymous user" msgstr "" -#: templates/macros.html:91 templates/macros.html.py:110 -msgid "asked" -msgstr "" - -#: templates/macros.html:93 templates/macros.html.py:112 -msgid "answered" -msgstr "" - #: templates/macros.html:95 templates/macros.html.py:114 msgid "posted" msgstr "" @@ -5165,91 +5306,95 @@ msgstr "" msgid "Comments" msgstr "" -#: templates/macros.html:430 +#: templates/macros.html:433 msgid "delete this comment" msgstr "" -#: templates/macros.html:443 templates/revisions.html:38 +#: templates/macros.html:446 templates/revisions.html:38 #: templates/revisions.html.py:41 templates/question/answer_controls.html:5 #: templates/question/question_controls.html:1 msgid "edit" msgstr "" -#: templates/macros.html:452 +#: templates/macros.html:455 msgid "convert to answer" msgstr "" -#: templates/macros.html:579 +#: templates/macros.html:582 #, python-format msgid "follow %(alias)s" msgstr "" -#: templates/macros.html:582 +#: templates/macros.html:585 #, python-format msgid "unfollow %(alias)s" msgstr "" -#: templates/macros.html:583 +#: templates/macros.html:586 #, python-format msgid "following %(alias)s" msgstr "" -#: templates/macros.html:662 templatetags/extra_tags.py:44 +#: templates/macros.html:667 templatetags/extra_tags.py:44 #, python-format msgid "%(username)s gravatar image" msgstr "" -#: templates/macros.html:671 +#: templates/macros.html:676 #, python-format msgid "%(username)s's website is %(url)s" msgstr "" -#: templates/macros.html:686 templates/macros.html.py:687 -#: templates/macros.html:725 templates/macros.html.py:726 +#: templates/macros.html:697 templates/macros.html.py:698 +#: templates/macros.html:759 templates/macros.html.py:760 msgid "previous" msgstr "" -#: templates/macros.html:698 templates/macros.html.py:737 +#: templates/macros.html:716 templates/macros.html.py:771 msgid "current page" msgstr "" -#: templates/macros.html:700 templates/macros.html.py:707 -#: templates/macros.html:739 templates/macros.html.py:746 +#: templates/macros.html:722 templates/macros.html.py:735 +#: templates/macros.html:773 templates/macros.html.py:780 #, python-format msgid "page %(num)s" msgstr "" -#: templates/macros.html:711 templates/macros.html.py:750 +#: templates/macros.html:744 templates/macros.html.py:784 msgid "next page" msgstr "" -#: templates/macros.html:762 +#: templates/macros.html:745 +msgid "next" +msgstr "" + +#: templates/macros.html:796 #, python-format msgid "responses for %(username)s" msgstr "" -#: templates/macros.html:765 +#: templates/macros.html:799 #, python-format msgid "you have %(response_count)s new response" msgid_plural "you have %(response_count)s new responses" msgstr[0] "" msgstr[1] "" -#: templates/macros.html:768 +#: templates/macros.html:802 msgid "no new responses yet" msgstr "" -#: templates/macros.html:783 templates/macros.html.py:784 +#: templates/macros.html:817 templates/macros.html.py:818 #, python-format msgid "%(new)s new flagged posts and %(seen)s previous" msgstr "" -#: templates/macros.html:786 templates/macros.html.py:787 +#: templates/macros.html:820 templates/macros.html.py:821 #, python-format msgid "%(new)s new flagged posts" msgstr "" -#: templates/macros.html:792 templates/macros.html.py:793 +#: templates/macros.html:826 templates/macros.html.py:827 #, python-format msgid "%(seen)s flagged posts" msgstr "" @@ -5258,34 +5403,18 @@ msgstr "" msgid "Questions" msgstr "" -#: templates/question.html:230 +#: templates/question.html:232 msgid "see more comments" msgstr "" -#: templates/question.html:232 templates/question.html.py:335 +#: templates/question.html:234 templates/question.html.py:337 msgid "add a comment" msgstr "" -#: templates/question.html:245 templates/question/content.html:46 -msgid "Answer Your Own Question" -msgstr "" - -#: templates/question.html:250 -msgid "Post Your Answer" -msgstr "" - -#: templates/question.html:256 templates/widgets/ask_form.html:65 +#: templates/question.html:258 templates/widgets/ask_form.html:65 msgid "Login/Signup to Post" msgstr "" -#: templates/question_edit.html:4 templates/question_edit.html.py:9 -msgid "Edit question" -msgstr "" - -#: templates/question_edit.html:16 -msgid "Question - in one sentence" -msgstr "" - #: templates/question_edit.html:23 msgid "Details" msgstr "" @@ -5294,10 +5423,6 @@ msgstr "" msgid "Change language" msgstr "" -#: templates/question_retag.html:3 templates/question_retag.html.py:5 -msgid "Retag question" -msgstr "" - #: templates/question_retag.html:21 msgid "Retag" msgstr "" @@ -5318,10 +5443,6 @@ msgstr "" msgid "up to 5 tags, less than 20 characters each" msgstr "" -#: templates/reopen.html:4 templates/reopen.html.py:6 -msgid "Reopen question" -msgstr "" - #: templates/reopen.html:12 #, python-format msgid "" @@ -5337,14 +5458,6 @@ msgstr "" msgid "When:" msgstr "" -#: templates/reopen.html:23 -msgid "Reopen this question?" -msgstr "" - -#: templates/reopen.html:27 -msgid "Reopen this question" -msgstr "" - #: templates/revisions.html:4 templates/revisions.html.py:7 msgid "Revision history" msgstr "" @@ -5404,7 +5517,7 @@ msgstr "" #: templates/users.html:41 templates/user_profile/user_info.html:25 #: templates/user_profile/user_reputation.html:5 -#: templates/user_profile/user_tabs.html:24 +#: templates/user_profile/user_tabs.html:20 msgid "karma" msgstr "" @@ -5447,7 +5560,7 @@ msgid "(or select another login method above)" msgstr "" #: templates/authopenid/authopenid_macros.html:66 -#: templates/authopenid/signin.html:115 +#: templates/authopenid/signin.html:118 #: templates/authopenid/widget_signin.html:118 msgid "Sign in" msgstr "" @@ -5495,15 +5608,15 @@ msgstr "" msgid "Registration" msgstr "" -#: templates/authopenid/complete.html:23 +#: templates/authopenid/complete.html:24 msgid "User registration" msgstr "" -#: templates/authopenid/complete.html:47 +#: templates/authopenid/complete.html:48 msgid "<strong>Screen Name</strong> (<i>will be shown to others</i>)" msgstr "" -#: templates/authopenid/complete.html:56 +#: templates/authopenid/complete.html:57 msgid "" "<strong>Email Address</strong> (<i>will <strong>not</strong> be shared " "with \n" @@ -5511,7 +5624,7 @@ msgid "" " " msgstr "" -#: templates/authopenid/complete.html:71 +#: templates/authopenid/complete.html:72 #: templates/authopenid/signup_with_password.html:5 #: templates/authopenid/signup_with_password.html:45 msgid "Signup" @@ -5593,10 +5706,10 @@ msgstr "User login" #: templates/authopenid/signin.html:15 #: templates/authopenid/widget_signin.html:19 -#, python-format +#, fuzzy, python-format msgid "" "\n" -" Your answer to %(title)s %(summary)s will be posted once you log in\n" +" Your answer to %(title)s will be posted once you log in\n" " " msgstr "" "\n" @@ -5606,10 +5719,10 @@ msgstr "" #: templates/authopenid/signin.html:22 #: templates/authopenid/widget_signin.html:26 -#, python-format +#, fuzzy, python-format msgid "" "Your question \n" -" %(title)s %(summary)s will be posted once you log in\n" +" %(title)s will be posted once you log in\n" " " msgstr "" "<span class=\"strong big\">Your question</span> <i>\"<strong>%(title)s</" @@ -5652,109 +5765,109 @@ msgid "" "account" msgstr "" -#: templates/authopenid/signin.html:90 +#: templates/authopenid/signin.html:93 msgid "or enter your <span>user name and password</span>" msgstr "" -#: templates/authopenid/signin.html:94 +#: templates/authopenid/signin.html:97 #: templates/authopenid/widget_signin.html:98 msgid "Please, sign in" msgstr "" -#: templates/authopenid/signin.html:101 +#: templates/authopenid/signin.html:104 #: templates/authopenid/widget_signin.html:105 msgid "Login failed, please try again" msgstr "" -#: templates/authopenid/signin.html:106 +#: templates/authopenid/signin.html:109 #: templates/authopenid/widget_signin.html:109 msgid "Login or email" msgstr "" -#: templates/authopenid/signin.html:110 +#: templates/authopenid/signin.html:113 #: templates/authopenid/widget_signin.html:113 utils/forms.py:264 msgid "Password" msgstr "" -#: templates/authopenid/signin.html:122 +#: templates/authopenid/signin.html:125 #: templates/authopenid/widget_signin.html:125 msgid "To change your password - please enter the new one twice, then submit" msgstr "" -#: templates/authopenid/signin.html:126 +#: templates/authopenid/signin.html:129 #: templates/authopenid/widget_signin.html:129 msgid "New password" msgstr "" -#: templates/authopenid/signin.html:135 +#: templates/authopenid/signin.html:138 #: templates/authopenid/widget_signin.html:138 msgid "Please, retype" msgstr "" -#: templates/authopenid/signin.html:145 +#: templates/authopenid/signin.html:148 #: templates/authopenid/widget_signin.html:148 #: templates/livesettings/site_settings.html:24 msgid "Change password" msgstr "" -#: templates/authopenid/signin.html:159 +#: templates/authopenid/signin.html:162 #: templates/authopenid/widget_signin.html:162 msgid "Here are your current login methods" msgstr "" -#: templates/authopenid/signin.html:163 +#: templates/authopenid/signin.html:166 #: templates/authopenid/widget_signin.html:166 msgid "provider" msgstr "" -#: templates/authopenid/signin.html:164 +#: templates/authopenid/signin.html:167 #: templates/authopenid/widget_signin.html:167 msgid "last used" msgstr "" -#: templates/authopenid/signin.html:165 +#: templates/authopenid/signin.html:168 #: templates/authopenid/widget_signin.html:168 msgid "delete, if you like" msgstr "" -#: templates/authopenid/signin.html:179 +#: templates/authopenid/signin.html:182 #: templates/authopenid/widget_signin.html:182 #: templates/question/answer_controls.html:33 #: templates/question/question_controls.html:36 msgid "delete" msgstr "" -#: templates/authopenid/signin.html:181 +#: templates/authopenid/signin.html:184 #: templates/authopenid/widget_signin.html:184 msgid "cannot be deleted" msgstr "" -#: templates/authopenid/signin.html:194 +#: templates/authopenid/signin.html:197 #: templates/authopenid/widget_signin.html:197 msgid "Still have trouble signing in?" msgstr "" -#: templates/authopenid/signin.html:199 +#: templates/authopenid/signin.html:202 #: templates/authopenid/widget_signin.html:202 -msgid "Please, enter your email address below and obtain a new key" +msgid "Enter your email address below and obtain a new key" msgstr "" -#: templates/authopenid/signin.html:201 +#: templates/authopenid/signin.html:204 #: templates/authopenid/widget_signin.html:204 -msgid "Please, enter your email address below to recover your account" +msgid "Enter your email address below to recover your account" msgstr "" -#: templates/authopenid/signin.html:204 +#: templates/authopenid/signin.html:207 #: templates/authopenid/widget_signin.html:207 msgid "recover your account via email" msgstr "" -#: templates/authopenid/signin.html:215 +#: templates/authopenid/signin.html:218 #: templates/authopenid/widget_signin.html:217 msgid "Send a new recovery key" msgstr "" -#: templates/authopenid/signin.html:217 +#: templates/authopenid/signin.html:220 #: templates/authopenid/widget_signin.html:219 msgid "Recover your account via email" msgstr "" @@ -5836,7 +5949,7 @@ msgstr "" msgid "You haven't uploaded an avatar yet. Please upload one now." msgstr "" -#: templates/avatar/add.html:13 +#: templates/avatar/add.html:14 msgid "Upload New Image" msgstr "" @@ -5848,7 +5961,7 @@ msgstr "" msgid "Choose new Default" msgstr "" -#: templates/avatar/change.html:22 +#: templates/avatar/change.html:23 msgid "Upload" msgstr "" @@ -5867,7 +5980,7 @@ msgid "" "\">upload one</a> now." msgstr "" -#: templates/avatar/confirm_delete.html:12 +#: templates/avatar/confirm_delete.html:13 msgid "Delete These" msgstr "" @@ -5947,7 +6060,7 @@ msgstr "" #: templates/email/insufficient_rep_to_post_by_email.html:10 #, python-format -msgid "%(username)s, your question could not be posted by email just yet." +msgid "%(username)s, your content could not be posted by email just yet." msgstr "" #: templates/email/insufficient_rep_to_post_by_email.html:14 @@ -5958,7 +6071,7 @@ msgstr "" #: templates/email/insufficient_rep_to_post_by_email.html:15 #, python-format -msgid "At this time, please post your question at %(link)s" +msgid "At this time, please post your content at %(link)s" msgstr "" #: templates/email/macros.html:19 @@ -5974,10 +6087,6 @@ msgid "" " " msgstr "" -#: templates/email/macros.html:26 -msgid "Question :" -msgstr "" - #: templates/email/macros.html:33 #, python-format msgid "Asked by %(author)s:" @@ -6055,11 +6164,6 @@ msgstr[1] "" msgid "Great, you are ready to use %(site_name)s!" msgstr "" -#: templates/email/re_welcome_lamson_on.html:7 -#, python-format -msgid "You can post questions by emailing them at %(ask_address)s." -msgstr "" - #: templates/email/re_welcome_lamson_on.html:8 msgid "" "When you receive update notifications, you will be able to respond to them, " @@ -6118,8 +6222,8 @@ msgstr "" #: templates/email/welcome_lamson_on.html:14 #, python-format msgid "" -"Until we receive the response from you, you will not be able ask or answer " -"questions on %(site_name)s by email." +"Until we receive the response from you, you will not be able to post content " +"on %(site_name)s by email." msgstr "" #: templates/embed/list_widgets.html:44 @@ -6153,10 +6257,6 @@ msgid "" "Create and embed widgets into your sites, here a list of available widgets." msgstr "" -#: templates/embed/widgets.html:16 -msgid "Ask a question" -msgstr "" - #: templates/embed/widgets.html:17 templates/embed/widgets.html.py:26 msgid "create" msgstr "" @@ -6165,10 +6265,6 @@ msgstr "" msgid "view list" msgstr "" -#: templates/embed/widgets.html:25 -msgid "List of questions" -msgstr "" - #: templates/group_messaging/email_alert.html:7 #, python-format msgid "%(author)s wrote:" @@ -6195,7 +6291,7 @@ msgid "Messages by sender:" msgstr "" #: templates/group_messaging/senders_list.html:5 -#: templates/user_inbox/base.html:6 templates/user_profile/user_tabs.html:12 +#: templates/user_inbox/base.html:6 templates/user_profile/user_tabs.html:10 msgid "inbox" msgstr "" @@ -6269,7 +6365,7 @@ msgstr "" msgid "Uncollapse all" msgstr "" -#: templates/main_page/headline.html:4 views/readers.py:151 +#: templates/main_page/headline.html:4 views/readers.py:157 #, python-format msgid "%(q_num)s question" msgid_plural "%(q_num)s questions" @@ -6319,18 +6415,6 @@ msgstr "" msgid "add tags and a query to focus your search" msgstr "" -#: templates/main_page/nothing_found.html:4 -msgid "There are no unanswered questions here" -msgstr "" - -#: templates/main_page/nothing_found.html:7 -msgid "No questions here. " -msgstr "" - -#: templates/main_page/nothing_found.html:8 -msgid "Please follow some questions or follow some users." -msgstr "" - #: templates/main_page/nothing_found.html:13 msgid "You can expand your search by " msgstr "" @@ -6348,20 +6432,12 @@ msgstr "" msgid "starting over" msgstr "" -#: templates/main_page/nothing_found.html:30 -msgid "Please always feel free to ask your question!" -msgstr "" - #: templates/main_page/questions_loop.html:9 msgid "Did not find what you were looking for?" msgstr "" -#: templates/main_page/questions_loop.html:10 -msgid "Ask your question!" -msgstr "" - #: templates/main_page/tab_bar.html:11 -msgid "subscribe to the questions feed" +msgid "subscribe to the feed" msgstr "" #: templates/main_page/tab_bar.html:12 @@ -6408,10 +6484,6 @@ msgstr "" msgid "This response is published" msgstr "" -#: templates/question/answer_controls.html:2 -msgid "swap with question" -msgstr "" - #: templates/question/answer_controls.html:11 msgid "remove offensive flag" msgstr "" @@ -6459,18 +6531,6 @@ msgstr "" msgid "link" msgstr "" -#: templates/question/answer_controls.html:58 -msgid "more" -msgstr "" - -#: templates/question/answer_controls.html:71 -msgid "repost as a question comment" -msgstr "" - -#: templates/question/answer_controls.html:85 -msgid "repost as a comment under the older answer" -msgstr "" - #: templates/question/answer_tab_bar.html:3 #, python-format msgid "" @@ -6500,47 +6560,34 @@ msgstr "" msgid "most voted answers will be shown first" msgstr "" -#: templates/question/answer_vote_buttons.html:8 -#: templates/user_profile/users_answers.html:7 -msgid "this answer has been selected as correct" -msgstr "" - #: templates/question/answer_vote_buttons.html:10 -msgid "mark this answer as correct (click again to undo)" +msgid "(click again to undo)" msgstr "" #: templates/question/closed_question_info.html:2 +msgid "Closed for the following reason" +msgstr "" + +#: templates/question/closed_question_info.html:3 +msgid "by" +msgstr "" + +#: templates/question/closed_question_info.html:5 #, python-format msgid "" "The question has been closed for the following reason <b>\"%(close_reason)s" "\"</b> <i>by" msgstr "" -#: templates/question/closed_question_info.html:4 +#: templates/question/closed_question_info.html:8 #, python-format msgid "close date %(closed_at)s" msgstr "" -#: templates/question/content.html:33 -msgid "Edit Your Previous Answer" -msgstr "" - -#: templates/question/content.html:34 +#: templates/question/content.html:39 msgid "(only one answer per user is allowed)" msgstr "" -#: templates/question/new_answer_form.html:12 -msgid "Login/Signup to Answer" -msgstr "" - -#: templates/question/new_answer_form.html:20 -msgid "Your answer" -msgstr "" - -#: templates/question/new_answer_form.html:22 -msgid "Be the first one to answer this question!" -msgstr "" - #: templates/question/new_answer_form.html:28 msgid "" "<span class='strong big'>Please start posting your answer anonymously</span> " @@ -6570,10 +6617,6 @@ msgid "" "best questions and answers!" msgstr "" -#: templates/question/new_answer_form.html:39 -msgid "Add answer" -msgstr "" - #: templates/question/question_controls.html:5 msgid "retag" msgstr "" @@ -6586,12 +6629,8 @@ msgstr "" msgid "close" msgstr "" -#: templates/question/sidebar.html:8 -msgid "Question tools" -msgstr "" - #: templates/question/sidebar.html:11 -msgid "click to unfollow this question" +msgid "click to unfollow " msgstr "" #: templates/question/sidebar.html:12 @@ -6603,7 +6642,7 @@ msgid "Unfollow" msgstr "" #: templates/question/sidebar.html:17 -msgid "click to follow this question" +msgid "click to follow " msgstr "" #: templates/question/sidebar.html:18 @@ -6618,7 +6657,7 @@ msgstr[0] "" msgstr[1] "" #: templates/question/sidebar.html:33 -msgid "subscribe to this question rss feed" +msgid "subscribe to the rss feed" msgstr "" #: templates/question/sidebar.html:34 @@ -6629,7 +6668,7 @@ msgstr "" msgid "Invite" msgstr "" -#: templates/question/sidebar.html:50 templates/question/sidebar.html.py:56 +#: templates/question/sidebar.html:49 templates/question/sidebar.html.py:55 #: templates/user_profile/user_email_subscriptions.html:59 #: templates/widgets/tag_selector.html:20 #: templates/widgets/tag_selector.html:37 @@ -6637,68 +6676,60 @@ msgstr "" msgid "add" msgstr "" -#: templates/question/sidebar.html:52 templates/question/sidebar.html.py:58 +#: templates/question/sidebar.html:51 templates/question/sidebar.html.py:57 msgid "- or -" msgstr "" -#: templates/question/sidebar.html:70 +#: templates/question/sidebar.html:69 msgid "share with everyone" msgstr "" -#: templates/question/sidebar.html:81 -msgid "This question is currently shared only with:" -msgstr "" - -#: templates/question/sidebar.html:83 +#: templates/question/sidebar.html:82 msgid "Individual users" msgstr "" -#: templates/question/sidebar.html:88 +#: templates/question/sidebar.html:87 msgid "You" msgstr "" -#: templates/question/sidebar.html:95 templates/question/sidebar.html:115 +#: templates/question/sidebar.html:94 templates/question/sidebar.html:114 msgid "and" msgstr "" -#: templates/question/sidebar.html:120 +#: templates/question/sidebar.html:119 #, python-format msgid "%(more_count)s more" msgstr "" -#: templates/question/sidebar.html:126 +#: templates/question/sidebar.html:125 msgid "Public thread" msgstr "" -#: templates/question/sidebar.html:127 +#: templates/question/sidebar.html:126 #, python-format msgid "This thread is public, all members of %(site_name)s can read this page." msgstr "" -#: templates/question/sidebar.html:135 +#: templates/question/sidebar.html:134 msgid "Stats" msgstr "" -#: templates/question/sidebar.html:137 +#: templates/question/sidebar.html:136 msgid "Asked" msgstr "" -#: templates/question/sidebar.html:140 +#: templates/question/sidebar.html:139 msgid "Seen" msgstr "" -#: templates/question/sidebar.html:140 +#: templates/question/sidebar.html:139 msgid "times" msgstr "" -#: templates/question/sidebar.html:143 +#: templates/question/sidebar.html:142 msgid "Last updated" msgstr "" -#: templates/question/sidebar.html:151 -msgid "Related questions" -msgstr "" - #: templates/tags/form_bulk_tag_subscription.html:4 msgid "Tag subscriptions" msgstr "" @@ -6925,6 +6956,18 @@ msgstr "" msgid "%(username)s's profile" msgstr "" +#: templates/user_profile/user_answers_list.html:5 +#, python-format +msgid "the answer has been voted for %(answer_score)s times" +msgstr "" + +#: templates/user_profile/user_answers_list.html:15 +#, python-format +msgid "(%(comment_count)s comment)" +msgid_plural "the answer has been commented %(comment_count)s times" +msgstr[0] "" +msgstr[1] "" + #: templates/user_profile/user_edit.html:4 msgid "Edit user profile" msgstr "" @@ -6961,7 +7004,7 @@ msgid "Update" msgstr "" #: templates/user_profile/user_email_subscriptions.html:5 -#: templates/user_profile/user_tabs.html:44 +#: templates/user_profile/user_tabs.html:36 msgid "subscriptions" msgstr "" @@ -6994,11 +7037,6 @@ msgstr "" msgid "Subscribed Tags" msgstr "" -#: templates/user_profile/user_favorites.html:4 -#: templates/user_profile/user_tabs.html:29 -msgid "followed questions" -msgstr "" - #: templates/user_profile/user_info.html:37 msgid "update profile" msgstr "" @@ -7053,7 +7091,7 @@ msgid "votes left" msgstr "" #: templates/user_profile/user_moderate.html:4 -#: templates/user_profile/user_tabs.html:50 +#: templates/user_profile/user_tabs.html:41 msgid "moderation" msgstr "" @@ -7135,7 +7173,7 @@ msgid "" msgstr "" #: templates/user_profile/user_network.html:5 -#: templates/user_profile/user_tabs.html:18 +#: templates/user_profile/user_tabs.html:15 msgid "network" msgstr "" @@ -7165,13 +7203,12 @@ msgid "%(username)s's network is empty" msgstr "" #: templates/user_profile/user_recent.html:5 -#: templates/user_profile/user_tabs.html:31 -#: templates/user_profile/user_tabs.html:33 +#: templates/user_profile/user_tabs.html:27 msgid "activity" msgstr "" -#: templates/user_profile/user_recent.html:23 -#: templates/user_profile/user_recent.html:27 +#: templates/user_profile/user_recent.html:25 +#: templates/user_profile/user_recent.html:30 msgid "source" msgstr "" @@ -7185,7 +7222,7 @@ msgid "%(user_name)s's karma change log" msgstr "" #: templates/user_profile/user_stats.html:6 -#: templates/user_profile/user_tabs.html:7 +#: templates/user_profile/user_tabs.html:6 msgid "overview" msgstr "" @@ -7202,97 +7239,41 @@ msgid_plural "Answers" msgstr[0] "" msgstr[1] "" -#: templates/user_profile/user_stats.html:23 +#: templates/user_profile/user_stats.html:22 #, python-format msgid "<span class=\"count\">%(cnt)s</span> Vote" msgid_plural "<span class=\"count\">%(cnt)s</span> Votes " msgstr[0] "" msgstr[1] "" -#: templates/user_profile/user_stats.html:31 +#: templates/user_profile/user_stats.html:30 #, python-format msgid "<span class=\"count\">%(counter)s</span> Tag" msgid_plural "<span class=\"count\">%(counter)s</span> Tags" msgstr[0] "" msgstr[1] "" -#: templates/user_profile/user_stats.html:65 +#: templates/user_profile/user_stats.html:64 #, python-format msgid "<span class=\"count\">%(counter)s</span> Badge" msgid_plural "<span class=\"count\">%(counter)s</span> Badges" msgstr[0] "" msgstr[1] "" -#: templates/user_profile/user_stats.html:85 +#: templates/user_profile/user_stats.html:84 msgid "Answer to:" msgstr "" -#: templates/user_profile/user_tabs.html:5 -msgid "User profile" -msgstr "" - -#: templates/user_profile/user_tabs.html:10 views/users.py:819 -msgid "comments and answers to others questions" -msgstr "" - -#: templates/user_profile/user_tabs.html:16 -msgid "followers and followed users" -msgstr "" - -#: templates/user_profile/user_tabs.html:22 -msgid "Graph of user karma" -msgstr "" - -#: templates/user_profile/user_tabs.html:27 -msgid "questions that user is following" -msgstr "" - -#: templates/user_profile/user_tabs.html:36 views/users.py:861 -msgid "user vote record" -msgstr "" - -#: templates/user_profile/user_tabs.html:38 +#: templates/user_profile/user_tabs.html:31 #: templates/user_profile/user_votes.html:5 msgid "votes" msgstr "" -#: templates/user_profile/user_tabs.html:42 views/users.py:973 -msgid "email subscription settings" -msgstr "" - -#: templates/user_profile/user_tabs.html:48 views/users.py:286 -msgid "moderate this user" -msgstr "" - -#: templates/user_profile/users_answers.html:7 -#, python-format -msgid "the answer has been voted for %(answer_score)s times" -msgstr "" - -#: templates/user_profile/users_answers.html:17 -#, python-format -msgid "(%(comment_count)s comment)" -msgid_plural "the answer has been commented %(comment_count)s times" -msgstr[0] "" -msgstr[1] "" - #: templates/widgets/answer_edit_tips.html:3 #: templates/widgets/question_edit_tips.html:3 msgid "Tips" msgstr "" -#: templates/widgets/answer_edit_tips.html:6 -msgid "give an answer interesting to this community" -msgstr "" - -#: templates/widgets/answer_edit_tips.html:9 -msgid "try to give an answer, rather than engage into a discussion" -msgstr "" - -#: templates/widgets/ask_button.html:9 -msgid "Ask the Group" -msgstr "" - #: templates/widgets/ask_form.html:22 templates/widgets/ask_form.html.py:24 msgid "Add details (optional)" msgstr "" @@ -7340,7 +7321,7 @@ msgstr "" msgid "about" msgstr "" -#: templates/widgets/footer.html:40 templates/widgets/user_navigation.html:26 +#: templates/widgets/footer.html:40 templates/widgets/user_navigation.html:27 msgid "help" msgstr "" @@ -7373,11 +7354,7 @@ msgid "add logo" msgstr "" #: templates/widgets/group_info.html:46 -msgid "moderate emailed questions" -msgstr "" - -#: templates/widgets/group_info.html:58 -msgid "show only selected answers to enquirers" +msgid "moderate emailed content" msgstr "" #: templates/widgets/group_info.html:63 @@ -7392,38 +7369,30 @@ msgstr "" msgid "Allow only read access" msgstr "" -#: templates/widgets/group_info.html:102 -msgid "list of email addresses of pre-approved users" -msgstr "" - -#: templates/widgets/group_info.html:107 +#: templates/widgets/group_info.html:106 msgid "List of preapproved email addresses" msgstr "" -#: templates/widgets/group_info.html:108 +#: templates/widgets/group_info.html:107 msgid "" "Users with these email adderesses will be added to the group automatically." msgstr "" -#: templates/widgets/group_info.html:109 +#: templates/widgets/group_info.html:108 msgid "edit preapproved emails" msgstr "" -#: templates/widgets/group_info.html:113 -msgid "list of preapproved email address domain names" -msgstr "" - -#: templates/widgets/group_info.html:118 +#: templates/widgets/group_info.html:116 msgid "List of preapproved email domain names" msgstr "" -#: templates/widgets/group_info.html:119 +#: templates/widgets/group_info.html:117 msgid "" "Users whose email adderesses belong to these domains will be added to the " "group automatically." msgstr "" -#: templates/widgets/group_info.html:120 +#: templates/widgets/group_info.html:118 msgid "edit preapproved email domains" msgstr "" @@ -7477,34 +7446,24 @@ msgstr "" msgid "learn more about Markdown" msgstr "" -#: templates/widgets/meta_nav.html:12 +#: templates/widgets/meta_nav.html:13 msgid "people & groups" msgstr "" -#: templates/widgets/meta_nav.html:20 +#: templates/widgets/meta_nav.html:21 msgid "users" msgstr "people" -#: templates/widgets/meta_nav.html:27 +#: templates/widgets/meta_nav.html:28 msgid "badges" msgstr "" -#: templates/widgets/question_edit_tips.html:5 -msgid "ask a question interesting to this community" -msgstr "" - #: templates/widgets/question_summary.html:12 msgid "view" msgid_plural "views" msgstr[0] "" msgstr[1] "" -#: templates/widgets/question_summary.html:30 -msgid "answer" -msgid_plural "answers" -msgstr[0] "" -msgstr[1] "" - #: templates/widgets/question_summary.html:41 msgid "vote" msgid_plural "votes" @@ -7515,26 +7474,10 @@ msgstr[1] "" msgid "ALL" msgstr "" -#: templates/widgets/scope_nav.html:22 -msgid "see unanswered questions" -msgstr "" - -#: templates/widgets/scope_nav.html:22 -msgid "UNANSWERED" -msgstr "" - -#: templates/widgets/scope_nav.html:27 -msgid "see your followed questions" -msgstr "" - #: templates/widgets/scope_nav.html:27 msgid "FOLLOWED" msgstr "" -#: templates/widgets/scope_nav.html:30 -msgid "Please ask your question here" -msgstr "" - #: templates/widgets/tag_selector.html:4 msgid "Interesting tags" msgstr "" @@ -7547,10 +7490,6 @@ msgstr "" msgid "Subscribed tags" msgstr "" -#: templates/widgets/tag_selector.html:59 -msgid "Show only questions from" -msgstr "" - #: templates/widgets/tag_selector.html:70 msgid "Send me email alerts for" msgstr "" @@ -7587,19 +7526,19 @@ msgstr "" msgid "badges:" msgstr "" -#: templates/widgets/user_navigation.html:17 +#: templates/widgets/user_navigation.html:18 msgid "sign out" msgstr "" -#: templates/widgets/user_navigation.html:20 +#: templates/widgets/user_navigation.html:21 msgid "Hi there! Please sign in" msgstr "" -#: templates/widgets/user_navigation.html:23 +#: templates/widgets/user_navigation.html:24 msgid "settings" msgstr "" -#: templates/widgets/user_navigation.html:24 +#: templates/widgets/user_navigation.html:25 msgid "widgets" msgstr "" @@ -7631,7 +7570,7 @@ msgstr "" msgid "Post questions, answers and comments" msgstr "" -#: templatetags/extra_filters_jinja.py:332 +#: templatetags/extra_filters_jinja.py:342 msgid "no" msgstr "" @@ -7711,10 +7650,6 @@ msgstr "" msgid "this email address is not authorized" msgstr "" -#: utils/forms.py:265 -msgid "password is required" -msgstr "" - #: utils/forms.py:268 msgid "Password <i>(please retype)</i>" msgstr "" @@ -7723,10 +7658,6 @@ msgstr "" msgid "please, retype your password" msgstr "" -#: utils/forms.py:270 -msgid "sorry, entered passwords did not match, please try again" -msgstr "" - #: utils/functions.py:102 msgid "2 days ago" msgstr "" @@ -7882,92 +7813,108 @@ msgstr "" msgid "Suggested tags" msgstr "" -#: views/readers.py:256 +#: views/readers.py:278 #, python-format msgid "" "Please go to <a href=\"%s\">\"settings->URLs, keywords and greetings\"</a> " "and set the base url for your site to function properly" msgstr "" -#: views/readers.py:421 +#: views/readers.py:460 msgid "" "Sorry, the comment you are looking for has been deleted and is no longer " "accessible" msgstr "" +#: views/users.py:286 +msgid "moderate this user" +msgstr "" + #: views/users.py:287 msgid "moderate user" msgstr "" -#: views/users.py:529 +#: views/users.py:532 msgid "user profile" msgstr "" -#: views/users.py:530 +#: views/users.py:533 msgid "user profile overview" msgstr "" -#: views/users.py:650 +#: views/users.py:656 msgid "recent user activity" msgstr "" -#: views/users.py:651 +#: views/users.py:657 msgid "profile - recent activity" msgstr "" -#: views/users.py:682 +#: views/users.py:688 msgid "group joining requests" msgstr "" -#: views/users.py:683 +#: views/users.py:689 msgid "profile - moderation" msgstr "" -#: views/users.py:739 +#: views/users.py:745 msgid "private messages" msgstr "" -#: views/users.py:740 +#: views/users.py:746 msgid "profile - messages" msgstr "" -#: views/users.py:820 +#: views/users.py:825 +msgid "comments and answers to others questions" +msgstr "" + +#: views/users.py:826 msgid "profile - responses" msgstr "" -#: views/users.py:862 +#: views/users.py:867 +msgid "user vote record" +msgstr "" + +#: views/users.py:868 msgid "profile - votes" msgstr "" -#: views/users.py:883 +#: views/users.py:889 msgid "user karma" msgstr "" -#: views/users.py:884 +#: views/users.py:890 msgid "Profile - User's Karma" msgstr "" -#: views/users.py:902 +#: views/users.py:925 msgid "users favorite questions" msgstr "" -#: views/users.py:903 +#: views/users.py:926 msgid "profile - favorite questions" msgstr "" -#: views/users.py:944 views/users.py:948 +#: views/users.py:970 views/users.py:974 msgid "changes saved" msgstr "" -#: views/users.py:954 +#: views/users.py:980 msgid "email updates canceled" msgstr "" -#: views/users.py:974 +#: views/users.py:999 +msgid "email subscription settings" +msgstr "" + +#: views/users.py:1000 msgid "profile - email subscriptions" msgstr "" -#: views/users.py:995 +#: views/users.py:1021 #, python-format msgid "profile - %(section)s" msgstr "" @@ -8033,11 +7980,11 @@ msgstr "" msgid "sorry, we seem to have some technical difficulties" msgstr "" -#: views/writers.py:888 +#: views/writers.py:869 msgid "Error - could not find the destination post" msgstr "" -#: views/writers.py:912 +#: views/writers.py:893 #, python-format msgid "" "Cannot convert, because text has more characters than %(max_chars)s - " @@ -8065,17 +8012,17 @@ msgstr "" #~ msgstr "Verification Email from Q&A forum" #~ msgid "" -#~ "how to validate email info with %(send_email_key_url)s %(gravatar_faq_url)" -#~ "s" +#~ "how to validate email info with %(send_email_key_url)s " +#~ "%(gravatar_faq_url)s" #~ msgstr "" -#~ "<form style='margin:0;padding:0;' action='%(send_email_key_url)" -#~ "s'><p><span class=\"bigger strong\">How?</span> If you have just set or " -#~ "changed your email address - <strong>check your email and click the " -#~ "included link</strong>.<br>The link contains a key generated specifically " -#~ "for you. You can also <button style='display:inline' " -#~ "type='submit'><strong>get a new key</strong></button> and check your " -#~ "email again.</p></form><span class=\"bigger strong\">Why?</span> Email " -#~ "validation is required to make sure that <strong>only you can post " +#~ "<form style='margin:0;padding:0;' " +#~ "action='%(send_email_key_url)s'><p><span class=\"bigger strong\">How?</" +#~ "span> If you have just set or changed your email address - <strong>check " +#~ "your email and click the included link</strong>.<br>The link contains a " +#~ "key generated specifically for you. You can also <button style='display:" +#~ "inline' type='submit'><strong>get a new key</strong></button> and check " +#~ "your email again.</p></form><span class=\"bigger strong\">Why?</span> " +#~ "Email validation is required to make sure that <strong>only you can post " #~ "messages</strong> on your behalf and to <strong>minimize spam</strong> " #~ "posts.<br>With email you can <strong>subscribe for updates</strong> on " #~ "the most interesting questions. Also, when you sign up for the first time " diff --git a/askbot/locale/en/LC_MESSAGES/djangojs.mo b/askbot/locale/en/LC_MESSAGES/djangojs.mo Binary files differindex 3eead943..f158cafd 100644 --- a/askbot/locale/en/LC_MESSAGES/djangojs.mo +++ b/askbot/locale/en/LC_MESSAGES/djangojs.mo diff --git a/askbot/locale/en/LC_MESSAGES/djangojs.po b/askbot/locale/en/LC_MESSAGES/djangojs.po index f3ea106e..e1245db1 100644 --- a/askbot/locale/en/LC_MESSAGES/djangojs.po +++ b/askbot/locale/en/LC_MESSAGES/djangojs.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.7\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-07-13 14:07-0500\n" +"POT-Creation-Date: 2013-10-16 16:35-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" @@ -312,7 +312,7 @@ msgstr "" msgid "Are you sure you don't want to post this comment?" msgstr "Are you sure you do not want to post this comment?" -#: media/js/post.js:1890 media/js/utils.js:3360 media/js/utils.js.c:3515 +#: media/js/post.js:1890 media/js/utils.js:3804 media/js/utils.js.c:3959 msgid "just now" msgstr "" @@ -374,7 +374,7 @@ msgstr[1] "" msgid "Delete category?" msgstr "" -#: media/js/post.js:3888 media/js/utils.js:881 +#: media/js/post.js:3888 media/js/utils.js:1320 msgid "edit" msgstr "edit" @@ -395,10 +395,6 @@ msgstr "" msgid "save tags" msgstr "" -#: media/js/post.js:4689 media/js/post.js.c:4723 -msgid "User name:" -msgstr "" - #: media/js/post.js:4710 msgid "Group name:" msgstr "" @@ -519,202 +515,207 @@ msgstr "" msgid "click to close" msgstr "" -#: media/js/utils.js:880 +#: media/js/utils.js:619 +#, c-format +msgid "page %s" +msgstr "" + +#: media/js/utils.js:1319 msgid "click to edit this comment" msgstr "click to edit this comment" -#: media/js/utils.js:905 +#: media/js/utils.js:1344 msgid "convert to answer" msgstr "" -#: media/js/utils.js:958 +#: media/js/utils.js:1397 msgid "Ok" msgstr "" -#: media/js/utils.js:959 media/js/utils.js.c:1407 +#: media/js/utils.js:1398 media/js/utils.js.c:1851 msgid "Cancel" msgstr "" -#: media/js/utils.js:1219 +#: media/js/utils.js:1663 #, c-format msgid "Uploaded file: %s" msgstr "" -#: media/js/utils.js:1234 +#: media/js/utils.js:1678 msgid "Choose a different image" msgstr "" -#: media/js/utils.js:1236 +#: media/js/utils.js:1680 msgid "Choose a different file" msgstr "" -#: media/js/utils.js:1250 +#: media/js/utils.js:1694 msgid "Oops, looks like we had an error. Sorry." msgstr "" -#: media/js/utils.js:1311 +#: media/js/utils.js:1755 msgid "Choose an image to insert" msgstr "" -#: media/js/utils.js:1313 +#: media/js/utils.js:1757 msgid "Choose a file to insert" msgstr "" -#: media/js/utils.js:1326 +#: media/js/utils.js:1770 msgid "Allowed file types are:" msgstr "" -#: media/js/utils.js:1332 +#: media/js/utils.js:1776 #: media/js/tinymce/plugins/askbot_attachment/editor_plugin.js:35 msgid "Or paste file url here" msgstr "" -#: media/js/utils.js:1406 +#: media/js/utils.js:1850 msgid "Save" msgstr "" -#: media/js/utils.js:1478 +#: media/js/utils.js:1922 msgid "saved" msgstr "" -#: media/js/utils.js:1602 +#: media/js/utils.js:2046 msgid "enabled" msgstr "" -#: media/js/utils.js:1604 +#: media/js/utils.js:2048 msgid "disabled" msgstr "" -#: media/js/utils.js:2038 +#: media/js/utils.js:2482 msgid "group name" msgstr "" -#: media/js/utils.js:2046 +#: media/js/utils.js:2490 msgid "add new group" msgstr "" -#: media/js/utils.js:2138 +#: media/js/utils.js:2582 msgid "Group %(name)s already exists. Group names are case-insensitive." msgstr "" -#: media/js/utils.js:2311 +#: media/js/utils.js:2755 #, c-format msgid "see questions tagged '%s'" msgstr "" -#: media/js/utils.js:3358 +#: media/js/utils.js:3802 msgid "ago" msgstr "" -#: media/js/utils.js:3359 +#: media/js/utils.js:3803 msgid "from now" msgstr "" -#: media/js/utils.js:3361 +#: media/js/utils.js:3805 msgid "about a minute" msgstr "" -#: media/js/utils.js:3362 +#: media/js/utils.js:3806 #, c-format msgid "%d minutes" msgstr "" -#: media/js/utils.js:3363 +#: media/js/utils.js:3807 msgid "about an hour" msgstr "" -#: media/js/utils.js:3364 +#: media/js/utils.js:3808 #, c-format msgid "%d hours" msgstr "" -#: media/js/utils.js:3365 media/js/utils.js.c:3493 +#: media/js/utils.js:3809 media/js/utils.js.c:3937 msgid "yesterday" msgstr "" -#: media/js/utils.js:3366 +#: media/js/utils.js:3810 #, c-format msgid "%d days" msgstr "" -#: media/js/utils.js:3367 +#: media/js/utils.js:3811 msgid "about a month" msgstr "" -#: media/js/utils.js:3368 +#: media/js/utils.js:3812 #, c-format msgid "%d months" msgstr "" -#: media/js/utils.js:3369 +#: media/js/utils.js:3813 msgid "about a year" msgstr "" -#: media/js/utils.js:3370 +#: media/js/utils.js:3814 #, c-format msgid "%d years" msgstr "" -#: media/js/utils.js:3468 +#: media/js/utils.js:3912 msgid "Jan" msgstr "" -#: media/js/utils.js:3469 +#: media/js/utils.js:3913 msgid "Feb" msgstr "" -#: media/js/utils.js:3470 +#: media/js/utils.js:3914 msgid "Mar" msgstr "" -#: media/js/utils.js:3471 +#: media/js/utils.js:3915 msgid "Apr" msgstr "" -#: media/js/utils.js:3472 +#: media/js/utils.js:3916 msgid "May" msgstr "" -#: media/js/utils.js:3473 +#: media/js/utils.js:3917 msgid "Jun" msgstr "" -#: media/js/utils.js:3474 +#: media/js/utils.js:3918 msgid "Jul" msgstr "" -#: media/js/utils.js:3475 +#: media/js/utils.js:3919 msgid "Aug" msgstr "" -#: media/js/utils.js:3476 +#: media/js/utils.js:3920 msgid "Sep" msgstr "" -#: media/js/utils.js:3477 +#: media/js/utils.js:3921 msgid "Oct" msgstr "" -#: media/js/utils.js:3478 +#: media/js/utils.js:3922 msgid "Nov" msgstr "" -#: media/js/utils.js:3479 +#: media/js/utils.js:3923 msgid "Dec" msgstr "" -#: media/js/utils.js:3491 +#: media/js/utils.js:3935 msgid "2 days ago" msgstr "" -#: media/js/utils.js:3498 +#: media/js/utils.js:3942 #, c-format msgid "%s hour ago" msgid_plural "%s hours ago" msgstr[0] "" msgstr[1] "" -#: media/js/utils.js:3508 +#: media/js/utils.js:3952 #, c-format msgid "%s min ago" msgid_plural "%s mins ago" diff --git a/askbot/locale/es/LC_MESSAGES/django.mo b/askbot/locale/es/LC_MESSAGES/django.mo Binary files differindex db1375a0..cc2d8161 100644 --- a/askbot/locale/es/LC_MESSAGES/django.mo +++ b/askbot/locale/es/LC_MESSAGES/django.mo diff --git a/askbot/locale/es/LC_MESSAGES/django.po b/askbot/locale/es/LC_MESSAGES/django.po index c69723e9..fcc1d1a0 100644 --- a/askbot/locale/es/LC_MESSAGES/django.po +++ b/askbot/locale/es/LC_MESSAGES/django.po @@ -4,6 +4,7 @@ # # Translators: # Adolfo Fitoria <adolfo.fitoria@gmail.com>, 2013 +# fmmainere <fmmainere@gmail.com>, 2013 # Gustavo Gómez <gustavo.gomez@nuevosmedios.ws>, 2013 # Gustavo Gómez <gustavo.gomez@nuevosmedios.ws>, 2013 # Victor Trujillo <>, 2012 @@ -12,8 +13,8 @@ msgstr "" "Project-Id-Version: askbot\n" "Report-Msgid-Bugs-To: http://askbot.org/\n" "POT-Creation-Date: 2013-07-13 14:06-0500\n" -"PO-Revision-Date: 2013-08-08 15:45+0000\n" -"Last-Translator: Adolfo Fitoria <adolfo.fitoria@gmail.com>\n" +"PO-Revision-Date: 2013-08-27 19:14+0000\n" +"Last-Translator: fmmainere <fmmainere@gmail.com>\n" "Language-Team: Spanish (http://www.transifex.com/projects/p/askbot/language/es/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -82,12 +83,12 @@ msgstr[1] "debe de ser > %d caracteres" #: forms.py:270 #, python-format msgid "The question is too long, maximum allowed size is %d characters" -msgstr "" +msgstr "La pregunta es muy larga, el tamaño máximo permitido es de %d caracteres" #: forms.py:277 #, python-format msgid "The question is too long, maximum allowed size is %d bytes" -msgstr "" +msgstr "La pregunta es muy larga, el maximo permitido es de %d bytes" #: forms.py:309 msgid "content" @@ -710,7 +711,7 @@ msgstr "Este parámetro toma su valor predeterminado de la configuración de dja #: conf/email.py:44 msgid "Site administrator email address" -msgstr "" +msgstr "Dirección de correo electronico del administrador del sitio" #: conf/email.py:53 msgid "Enable email alerts" @@ -1094,25 +1095,25 @@ msgstr "Marca la casilla para permitir a los usuarios enviar preguntas o respues #: conf/forum_data_rules.py:118 msgid "Auto-follow questions by the Author" -msgstr "" +msgstr "Auto-seguir preguntas hechas por el Autor" #: conf/forum_data_rules.py:123 msgid "Fully open by default" -msgstr "" +msgstr "Abierto del todo por defecto" #: conf/forum_data_rules.py:124 msgid "Folded by default" -msgstr "" +msgstr "Plegado por defecto" #: conf/forum_data_rules.py:133 msgid "Question details/body editor should be" -msgstr "" +msgstr "El editor de detalles/cuerpo de la pregunta debe ser" #: conf/forum_data_rules.py:135 msgid "" "To use folded mode, please first set minimum question body length to 0. Also" " - please make tags optional." -msgstr "" +msgstr "Para usar el modo plegado, por favor establezca el largo mÃnimo del cuerpo de la respuesta a 0. Ademas, haga las etiquetas opcionales." #: conf/forum_data_rules.py:147 msgid "Allow swapping answer with question" @@ -1142,7 +1143,7 @@ msgstr "Tamaño minimo de la respuesta (numero de caracteres)" #: conf/forum_data_rules.py:202 msgid "Minimum length of comment (number of characters)" -msgstr "" +msgstr "Longitud mÃnima del comentario(numero de caracteres)" #: conf/forum_data_rules.py:213 msgid "Limit one answer per question per user" @@ -1311,7 +1312,7 @@ msgstr "Configuración de grupos" #: conf/group_settings.py:18 msgid "Enable user groups" -msgstr "" +msgstr "Habilitar grupos de usuarios" #: conf/group_settings.py:41 msgid "everyone" @@ -1335,7 +1336,7 @@ msgstr "Si está seleccionada, los usuarios pueden publicar a los grupos con el #: conf/karma_and_badges_visibility.py:12 msgid "Karma & Badge visibility" -msgstr "" +msgstr "Visibilidad de Karma y Medallas" #: conf/karma_and_badges_visibility.py:27 msgid "Visibility of karma" @@ -1343,7 +1344,7 @@ msgstr "Visibilidad de reputacion" #: conf/karma_and_badges_visibility.py:30 msgid "User's karma may be shown publicly or only to the owners" -msgstr "" +msgstr "El Karma del usuario puede ser mostrado públicamente solo a sus dueños" #: conf/karma_and_badges_visibility.py:44 msgid "Visibility of badges" @@ -1769,7 +1770,7 @@ msgstr "Hacer publicaciones por email" #: conf/minimum_reputation.py:223 msgid "Trigger email notifications" -msgstr "" +msgstr "Disparar notificaciones por correo electrónico " #: conf/minimum_reputation.py:224 conf/minimum_reputation.py:234 msgid "Reduces spam" @@ -1777,7 +1778,7 @@ msgstr "Reduce spam" #: conf/minimum_reputation.py:233 msgid "Trigger tweets on others accounts" -msgstr "" +msgstr "Disparar tweets en otras cuentas" #: conf/moderation.py:19 msgid "Content moderation" @@ -1808,15 +1809,15 @@ msgstr "" #: conf/question_lists.py:21 conf/question_lists.py:31 #: conf/question_lists.py:41 msgid "At least one of these selectors must be enabled" -msgstr "" +msgstr "Por lo menos uno de estos selectores debe estar habilitado" #: conf/question_lists.py:30 msgid "Enable \"Unanswered Questions\" selector" -msgstr "" +msgstr "Habilitar el selector \"Preguntas sin contestar\"" #: conf/question_lists.py:40 msgid "Enable \"Followed Questions\" selector" -msgstr "" +msgstr "Habilitar el selector \"Preguntas Seguidas\"" #: conf/question_lists.py:53 conf/question_lists.py:70 msgid "All Questions" @@ -1832,11 +1833,11 @@ msgstr "Preguntas seguidas" #: conf/question_lists.py:64 msgid "Default questions selector for the authenticated users" -msgstr "" +msgstr "Selector de preguntas por defecto para usuarios autenticados" #: conf/question_lists.py:80 msgid "Default questions selector for the anonymous users" -msgstr "" +msgstr "Selector de preguntas por defecto para usuarios anonimos" #: conf/reputation_changes.py:13 msgid "Karma loss and gain rules" @@ -1918,7 +1919,7 @@ msgstr "Utiliza este area para introducir el contenido en la parte superior de #: conf/sidebar_question.py:34 conf/sidebar_question.py:58 #: conf/sidebar_question.py:84 conf/sidebar_question.py:149 msgid "Show above only to anonymous users" -msgstr "" +msgstr "Abajo mostrar solo a los usuarios anonimos" #: conf/sidebar_main.py:45 msgid "Show avatar block in sidebar" @@ -1969,11 +1970,11 @@ msgstr "Barra lateral del perfil de usuario" #: conf/sidebar_profile.py:20 msgid "Custom sidebar" -msgstr "" +msgstr "Barra lateral personalizada" #: conf/sidebar_question.py:11 msgid "Question page banners and sidebar" -msgstr "" +msgstr "Barra lateral y carteles de la página de pregunta" #: conf/sidebar_question.py:19 msgid "Top banner" @@ -1983,7 +1984,7 @@ msgstr "Banner superior" msgid "" "When using this option, please use the HTML validation service to make sure " "that your input is valid and works well in all browsers." -msgstr "" +msgstr "Cuando utilice esta opción, por favor use el servicio de validación de HTML para asegurarse de que lo que usted ingresó es válido y funciona bien en todos los navegadores." #: conf/sidebar_question.py:42 msgid "Answers banner" @@ -2076,7 +2077,7 @@ msgstr "Por favor introduzca la URL de su sitio" #: conf/site_settings.py:73 msgid "Url must start either from http or https" -msgstr "" +msgstr "La url debe empezar o con http o con https" #: conf/site_settings.py:92 msgid "Base URL for your Q&A forum, must start with http or https" @@ -2384,7 +2385,7 @@ msgid "" "Important - to actually start sharing on twitter, it is required to set up " "Twitter consumer key and secret in the \"keys to external services\" " "section." -msgstr "" +msgstr "Importante - para empezar a compartir en twitter, es requerido que ingrese su Twitter consumer key y secret en la sección de \"claves de servicios externos\"" #: conf/social_sharing.py:52 msgid "Check to enable sharing of questions on Facebook" @@ -3237,7 +3238,7 @@ msgstr "OpenID %(openid_url)s incorrecto" msgid "" "Sorry, there was some problem connecting to the login provider, please try " "again or use another login method" -msgstr "" +msgstr "Lo lamentamos, hubo un problema conectándonos con el proveedor de acceso, por favor intente de nuevo usando otro método de acceso" #: deps/django_authopenid/views.py:520 msgid "Your new password saved" @@ -3291,7 +3292,7 @@ msgstr "Lo siento, se ha producido un error, inténtalo de nuevo." msgid "" "If you are trying to sign in to another account, please sign out first. " "Otherwise, please report the incident to the site administrator." -msgstr "" +msgstr "Si está intentando ingresar en otra cuenta, cierre esta cuenta primero. Si no es asÃ, por favor reporte el incidente al administrador del sitio." #: deps/django_authopenid/views.py:914 #, python-format @@ -3302,7 +3303,7 @@ msgstr "Tu login de %(provider)s funciona correctamente" msgid "" "Sorry, registration failed. The token can be already used or has expired. " "Please try again" -msgstr "" +msgstr "Lo lamentamos, el registro fallo. Su token ya fue usado o ha expirado. Por favor intente nuevamente" #: deps/django_authopenid/views.py:1257 #, python-format @@ -3876,8 +3877,8 @@ msgstr "%(user)s tiene %(badges)s" #, python-format msgid "At least %d karma point is required to post links" msgid_plural "At least %d karma points is required to post links" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Como mÃnimo %d punto de karma es requerido para publicar enlaces" +msgstr[1] "Como mÃnimo %d puntos de karma son requeridos para publicar enlaces" #: models/__init__.py:3159 #, python-format @@ -5504,7 +5505,7 @@ msgid "" "<strong>Email Address</strong> (<i>will <strong>not</strong> be shared with \n" "anyone, must be valid</i>)\n" " " -msgstr "" +msgstr "<strong>Dirección de correo electrónico</strong> (<i><strong>no</strong> va a ser compartida con \nnadie, debe ser valida</i>)\n " #: templates/authopenid/complete.html:71 #: templates/authopenid/signup_with_password.html:5 @@ -5642,7 +5643,7 @@ msgstr "Por favor, comprueba tu email y haz click en el link que te enviamos par #: templates/authopenid/signin.html:90 msgid "or enter your <span>user name and password</span>" -msgstr "" +msgstr "o ingrese su <span>nombre de usuario y contraseña</span>" #: templates/authopenid/signin.html:94 #: templates/authopenid/widget_signin.html:98 @@ -5891,14 +5892,14 @@ msgstr "Trataremos de detectar la firma en tu respuesta y deberás podes publica msgid "" "To change frequency, language and content of these alerts, please visit <a " "href=\"%(url)s\">your user profile</a>." -msgstr "" +msgstr "Para cambiar la frecuencia, el lenguaje y el contenido de las alertas, por favor visite <a href=\"%(url)s\">su perfil de usuario</a>." #: templates/email/change_settings_info.html:6 #, python-format msgid "" "To change freqency and content of these alerts, please visit <a " "href=\"%(url)s\">your user profile</a>." -msgstr "" +msgstr "Para cambiar la frecuencia, el lenguaje y el contenido de las alertas, por favor visite <a href=\"%(url)s\">su perfil de usuario</a>." #: templates/email/change_settings_info.html:10 #, python-format @@ -5906,7 +5907,7 @@ msgid "" "If you believe that this message was sent in an error, please email about it" " the forum administrator at <a " "href=\"mailto:%(admin_email)s\">%(admin_email)s</a>." -msgstr "" +msgstr "Si usted piensa que este mensaje ha sido enviado por error, por favor envié un correo electronico al administrador del sitio a <a href=\"mailto:%(admin_email)s\">%(admin_email)s</a>." #: templates/email/delayed_email_alert.html:2 #, python-format @@ -6052,7 +6053,7 @@ msgstr "Puedes publicar pregutnas mandandolas por correo a %(ask_address)s." msgid "" "When you receive update notifications, you will be able to respond to them, " "also by email." -msgstr "" +msgstr "Cuando recibas notificaciones, podrás contestarlas, también por correo electrónico." #: templates/email/re_welcome_lamson_on.html:9 #, python-format @@ -6100,14 +6101,14 @@ msgid "" "Important: <em>Please reply</em> to this message, without editing it. We " "need this to determine your email signature and that the email address is " "valid and was typed correctly." -msgstr "" +msgstr "Importante: <em>Por favor responda</em> a este mensaje, sin editarlo. Necesitamos determinar que la firma de su correo electronico y su dirección son válidas y fueron tipeadas correctamente." #: templates/email/welcome_lamson_on.html:14 #, python-format msgid "" "Until we receive the response from you, you will not be able ask or answer " "questions on %(site_name)s by email." -msgstr "" +msgstr "Hasta que recibamos una respuesta de usted, no le será posible preguntar o responder preguntas en %(site_name)s por correo electronico." #: templates/embed/list_widgets.html:44 msgid "How to use?" @@ -6118,12 +6119,12 @@ msgid "" "\n" " Just copy the <script> tag provided and paste it in the site where you wan to put it.\n" " " -msgstr "" +msgstr "\n Just copy the <script> tag provided and paste it in the site where you wan to put it.\n " #: templates/embed/widget_form.html:3 templates/embed/widget_form.html.py:5 #, python-format msgid "%(action)s an %(widget_name)s widget" -msgstr "" +msgstr "%(action)s un widget %(widget_name)s " #: templates/embed/widget_form.html:14 #: templates/user_profile/user_moderate.html:20 @@ -6137,7 +6138,7 @@ msgstr "Widgets" #: templates/embed/widgets.html:11 msgid "" "Create and embed widgets into your sites, here a list of available widgets." -msgstr "" +msgstr "Cree y embeba widgets a sus sitios, aquà hay una lista de widgets disponibles" #: templates/embed/widgets.html:16 msgid "Ask a question" @@ -6158,27 +6159,27 @@ msgstr "Lista de preguntas" #: templates/group_messaging/email_alert.html:7 #, python-format msgid "%(author)s wrote:" -msgstr "" +msgstr "%(author)s escribió:" #: templates/group_messaging/email_alert.html:11 msgid "" "To reply please <a class=\"thread-link\" href=\"THREAD_URL_HOLE\">visit your" " message inbox</a>" -msgstr "" +msgstr "Para contestar por favor <a class=\"thread-link\" href=\"THREAD_URL_HOLE\">visite su bandeja de entrada</a>" #: templates/group_messaging/home.html:7 #: templates/group_messaging/home_thread_details.html:7 msgid "compose" -msgstr "" +msgstr "escribir" #: templates/group_messaging/macros.html:5 #, python-format msgid "You wrote on %(date)s:" -msgstr "" +msgstr "Usted escribió el dia %(date)s:" #: templates/group_messaging/senders_list.html:3 msgid "Messages by sender:" -msgstr "" +msgstr "Mensajes por remitente:" #: templates/group_messaging/senders_list.html:5 #: templates/user_inbox/base.html:6 templates/user_profile/user_tabs.html:12 @@ -6430,7 +6431,7 @@ msgstr "revivir" #: templates/question/answer_controls.html:43 msgid "unpublish" -msgstr "" +msgstr "no publicar" #: templates/question/answer_controls.html:48 msgid "publish" @@ -6509,11 +6510,11 @@ msgstr "fecha de cierre %(closed_at)s" #: templates/question/content.html:33 msgid "Edit Your Previous Answer" -msgstr "" +msgstr "Editar tu respuesta anterior" #: templates/question/content.html:34 msgid "(only one answer per user is allowed)" -msgstr "" +msgstr "(Solo una respuesta por usuario es permitida)" #: templates/question/new_answer_form.html:12 msgid "Login/Signup to Answer" @@ -6660,7 +6661,7 @@ msgstr "Hilo público" #, python-format msgid "" "This thread is public, all members of %(site_name)s can read this page." -msgstr "" +msgstr "Este hilo es publico, todos los miembros de %(site_name)s pueden leer esta página." #: templates/question/sidebar.html:135 msgid "Stats" @@ -6692,12 +6693,12 @@ msgstr "Subscripciones de etiqueta" #: templates/tags/form_bulk_tag_subscription.html:6 msgid "Tag Subscriptions" -msgstr "" +msgstr "Etiquetar suscripciones" #: templates/tags/header.html:7 #, python-format msgid "Tags, matching \"%(tag_query)s\"" -msgstr "" +msgstr "Etiquetas que coinciden con \"%(tag_query)s\"" #: templates/tags/header.html:19 msgid "sorted alphabetically" @@ -6729,7 +6730,7 @@ msgstr "Administrar subscripciones de etiquetas" #: templates/tags/list_bulk_tag_subscription.html:6 msgid "Manage Tag subscription</a> " -msgstr "" +msgstr "Editar suscripción a etiquetas\n</a>" #: templates/tags/list_bulk_tag_subscription.html:6 msgid "Create New" @@ -6763,15 +6764,15 @@ msgstr "respuestas (%(re_count)s)" #: templates/user_inbox/base.html:31 #, python-format msgid "flagged items (%(flags_count)s)" -msgstr "" +msgstr "Elementos marcados (%(flags_count)s)" #: templates/user_inbox/base.html:38 msgid "group join requests" -msgstr "" +msgstr "solicitudes de adhesion a grupos" #: templates/user_inbox/group_join_requests.html:4 msgid "inbox - group join requests" -msgstr "" +msgstr "Bandeja de entrada - solicitudes de adhesión a grupos" #: templates/user_inbox/group_join_requests.html:26 msgid "Approve" @@ -6783,11 +6784,11 @@ msgstr "Denegar" #: templates/user_inbox/messages.html:104 msgid "inbox - messages" -msgstr "" +msgstr "Bandeja de entrada - mensajes" #: templates/user_inbox/responses_and_flags.html:4 msgid "inbox - responses" -msgstr "" +msgstr "Bandeja de entrada - Respuestas" #: templates/user_inbox/responses_and_flags.html:8 msgid "select:" @@ -6819,7 +6820,7 @@ msgstr "cancelar" #: templates/user_inbox/responses_and_flags.html:19 msgid "remove flags/approve" -msgstr "" +msgstr "quitar marcas/aprobar" #: templates/user_inbox/responses_and_flags.html:23 msgid "delete post" @@ -6831,16 +6832,16 @@ msgstr "Rechazar la(s) publicación(es)?" #: templates/user_profile/reject_post_dialog.html:11 msgid "1) Enter a brief description of why you are rejecting the post." -msgstr "" +msgstr "1) Ingrese una breve descripcion de porque usted está rechazando esta publicación" #: templates/user_profile/reject_post_dialog.html:14 msgid "2) Please enter details here. This text will be sent to the user." -msgstr "" +msgstr "2) Por favor ingrese detalles aqui. Este texto será enviado al usuario." #: templates/user_profile/reject_post_dialog.html:20 #: templates/user_profile/reject_post_dialog.html:88 msgid "Use this reason & reject" -msgstr "" +msgstr "Usar esta razón & rechazar" #: templates/user_profile/reject_post_dialog.html:27 #: templates/user_profile/reject_post_dialog.html:95 @@ -6853,7 +6854,7 @@ msgstr "Guardar razón pero no rechazar" #: templates/user_profile/reject_post_dialog.html:43 msgid "Please, choose a reason for the rejection." -msgstr "" +msgstr "Por favor, elija una razón para el rechazo." #: templates/user_profile/reject_post_dialog.html:58 msgid "Select this reason" @@ -6881,7 +6882,7 @@ msgstr "Editar esta razón" #: templates/user_profile/twitter_sharing_controls.html:8 #, python-format msgid "Auto-tweeting to @%(handle)s" -msgstr "" +msgstr "Auto-tweeteando a @%(handle)s" #: templates/user_profile/twitter_sharing_controls.html:19 msgid "stop tweeting" @@ -7119,7 +7120,7 @@ msgstr "Los usuarios suspendidos solo pueden editar o eliminar sus propios posts msgid "" "Blocked users can only login and send feedback to the site administrators, " "their url and profile will also be hidden." -msgstr "" +msgstr "Los usuarios bloqueados solo pueden acceder y enviar aportes a los administradores del sitio, su url y perfil también estaran ocultos." #: templates/user_profile/user_network.html:5 #: templates/user_profile/user_tabs.html:18 @@ -7316,7 +7317,7 @@ msgstr "Vista preliminar en tiempo real del editor Markdown" msgid "" "To post on behalf of someone else, enter user name <strong>and</strong> " "email below." -msgstr "" +msgstr "Para publicar en lugar de alguien mas, ingrese su nombre <strong>y</strong> su email abajo." #: templates/widgets/footer.html:33 #, python-format @@ -7365,7 +7366,7 @@ msgstr "moderar preguntas enviadas por email" #: templates/widgets/group_info.html:58 msgid "show only selected answers to enquirers" -msgstr "" +msgstr "mostrar solo las respuestas seleccionadas a buscadores" #: templates/widgets/group_info.html:63 msgid "How users join this group?" @@ -7390,7 +7391,7 @@ msgstr "Lista de direcciones de correo pre-aprobadas" #: templates/widgets/group_info.html:108 msgid "" "Users with these email adderesses will be added to the group automatically." -msgstr "" +msgstr "Los usuarios con esta dirección de correo electrónico va a ser añadida al grupo automaticamente. " #: templates/widgets/group_info.html:109 msgid "edit preapproved emails" @@ -7398,21 +7399,21 @@ msgstr "editar direcciones de correo pre-aprobadas" #: templates/widgets/group_info.html:113 msgid "list of preapproved email address domain names" -msgstr "" +msgstr "lista de dominios de direcciones de correo electrónico pre-aprobadas." #: templates/widgets/group_info.html:118 msgid "List of preapproved email domain names" -msgstr "" +msgstr "Lista de nombres de dominio de correo electronico pre-aprobados" #: templates/widgets/group_info.html:119 msgid "" "Users whose email adderesses belong to these domains will be added to the " "group automatically." -msgstr "" +msgstr "Los usuarios cuyas direcciones de email pertenecen a estos dominios van a ser agregados al grupo automáticamente." #: templates/widgets/group_info.html:120 msgid "edit preapproved email domains" -msgstr "" +msgstr "editar dominios de correo electronico pre-aprobados" #: templates/widgets/logo.html:3 msgid "back to home page" @@ -7550,12 +7551,12 @@ msgstr "Cambiar la frecuencia de correo electrónico" msgid "" "Categorize your question using this tag selector or entering text in tag " "box." -msgstr "" +msgstr "Categorice su pregunta usando el selector de etiquetas o ingresando texto en la caja de etiquetas" #: templates/widgets/three_column_category_selector.html:7 #: templates/widgets/three_column_category_selector.html:10 msgid "(done editing)" -msgstr "" +msgstr "(Terminé de editar)" #: templates/widgets/three_column_category_selector.html:8 #: templates/widgets/three_column_category_selector.html:9 @@ -7581,7 +7582,7 @@ msgstr "cerrar sesión" #: templates/widgets/user_navigation.html:20 msgid "Hi there! Please sign in" -msgstr "" +msgstr "Hola! Ingrese por favor" #: templates/widgets/user_navigation.html:23 msgid "settings" @@ -7598,18 +7599,18 @@ msgstr "Su reputación es %(karma)s" #: templates/widgets/user_perms.html:4 msgid "Karma reflects the value of your contribution to this community." -msgstr "" +msgstr "El Karma refleja el valor de tu contribución a esta comunidad." #: templates/widgets/user_perms.html:13 #, python-format msgid "" "Since you are the site %(role)s, you have access to all functions regardless" " of your karma." -msgstr "" +msgstr "Como eres el %(role)s del sitio, tienes acceso a todas las funciones sin importar tu karma." #: templates/widgets/user_perms.html:15 msgid "The higher is your karma, the more rights you have on this site." -msgstr "" +msgstr "Cuanto mas alto es tu karma, más derechos tienes en este sitio." #: templates/widgets/user_perms.html:19 msgid "Currently, you can:" @@ -7637,7 +7638,7 @@ msgstr "Se ha detectado spam en tu post, perdona si esto es un error" #: utils/decorators.py:243 msgid "This function is limited to moderators and administrators" -msgstr "" +msgstr "Esta funcion es limitada solo a moderadores y administradores" #: utils/forms.py:66 msgid "this field is required" @@ -7822,12 +7823,12 @@ msgstr "EL grupo %(name)s no existe" #: views/commands.py:1408 views/commands.py:1441 msgid "Sorry, looks like sharing request was invalid" -msgstr "" +msgstr "Lo lamentamos, parece que su pedido de compartir es invalido" #: views/commands.py:1464 #, python-format msgid "%(user)s, welcome to group %(group)s!" -msgstr "" +msgstr "%(user)s, bienvenido al grupo %(group)s!" #: views/commands.py:1521 msgid "Sorry, only thread moderators can use this function" @@ -7848,7 +7849,7 @@ msgstr "Sobre %(site)s" #: views/meta.py:91 msgid "Please sign in or register to send your feedback" -msgstr "" +msgstr "Por favor ingrese o registresé para enviarnos sus sugerencias" #: views/meta.py:118 msgid "Q&A forum feedback" @@ -7875,7 +7876,7 @@ msgstr "Etiquetas sugeridas" msgid "" "Please go to <a href=\"%s\">\"settings->URLs, keywords and greetings\"</a> " "and set the base url for your site to function properly" -msgstr "" +msgstr "Por favor vaya a <a href=\"%s\">\"configuraciones->URLs, palabras clave y saludos\"</a> y establezca la url del sitio para que funcione apropiadamente" #: views/readers.py:421 msgid "" @@ -7905,7 +7906,7 @@ msgstr "perfil - actividad reciente" #: views/users.py:682 msgid "group joining requests" -msgstr "" +msgstr "solicitudes de adhesión a grupos" #: views/users.py:683 msgid "profile - moderation" @@ -8024,14 +8025,14 @@ msgstr "lo sentimos, tenemos dificultades técnicas" #: views/writers.py:888 msgid "Error - could not find the destination post" -msgstr "" +msgstr "Error - no se puede encontrar la publicación de destino" #: views/writers.py:912 #, python-format msgid "" "Cannot convert, because text has more characters than %(max_chars)s - " "maximum allowed for comments" -msgstr "" +msgstr "No se puede convertir, porque el texto tiene mas caracteres que %(max_chars)s - el maximo permitido para comentarios" #~ msgid "your email needs to be validated see %(details_url)s" #~ msgstr "" diff --git a/askbot/locale/fr/LC_MESSAGES/django.mo b/askbot/locale/fr/LC_MESSAGES/django.mo Binary files differindex ad9b2875..de12940d 100644 --- a/askbot/locale/fr/LC_MESSAGES/django.mo +++ b/askbot/locale/fr/LC_MESSAGES/django.mo diff --git a/askbot/locale/fr/LC_MESSAGES/django.po b/askbot/locale/fr/LC_MESSAGES/django.po index 2df654dc..76ec2105 100644 --- a/askbot/locale/fr/LC_MESSAGES/django.po +++ b/askbot/locale/fr/LC_MESSAGES/django.po @@ -4,14 +4,15 @@ # # Translators: # Alban Tiberghien <alban.tiberghien@gmail.com>, 2012 +# noirbizarre <noirbizarre@gmail.com>, 2013 # Camille Baldock <mademoisellegeek42@gmail.com>, 2011 # Christophe kryskool <christophe.chauvet@gmail.com>, 2011-2013 # Emmanuel <emmanuel@raviart.com>, 2013 # evgeny <evgeny.fadeev@gmail.com>, 2009 -# fbureau <francois.bureau@cloudwatt.com>, 2013 +# François Bureau <francois.bureau@cloudwatt.com>, 2013 # florent <fpam1108@gmail.com>, 2012 # florent <fpam1108@gmail.com>, 2012 -# fbureau <francois.bureau@cloudwatt.com>, 2013 +# François Bureau <francois.bureau@cloudwatt.com>, 2013 # Camille Baldock <mademoisellegeek42@gmail.com>, 2011 # Camille Baldock <mademoisellegeek42@gmail.com>, 2011 msgid "" @@ -19,8 +20,8 @@ msgstr "" "Project-Id-Version: askbot\n" "Report-Msgid-Bugs-To: http://askbot.org/\n" "POT-Creation-Date: 2013-07-13 14:06-0500\n" -"PO-Revision-Date: 2013-08-10 20:34+0000\n" -"Last-Translator: Emmanuel <emmanuel@raviart.com>\n" +"PO-Revision-Date: 2013-09-27 13:14+0000\n" +"Last-Translator: noirbizarre <noirbizarre@gmail.com>\n" "Language-Team: French (http://www.transifex.com/projects/p/askbot/language/fr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -1109,7 +1110,7 @@ msgstr "Complètement ouvert par défaut" #: conf/forum_data_rules.py:124 msgid "Folded by default" -msgstr "" +msgstr "Replié par défaut" #: conf/forum_data_rules.py:133 msgid "Question details/body editor should be" @@ -1815,7 +1816,7 @@ msgstr "Activer le sélecteur \"Toutes les questions\"" #: conf/question_lists.py:21 conf/question_lists.py:31 #: conf/question_lists.py:41 msgid "At least one of these selectors must be enabled" -msgstr "" +msgstr "Au moins un de ces sélecteurs doit être activé" #: conf/question_lists.py:30 msgid "Enable \"Unanswered Questions\" selector" @@ -1976,7 +1977,7 @@ msgstr "Identification utilisateur" #: conf/sidebar_profile.py:20 msgid "Custom sidebar" -msgstr "" +msgstr "Barre latérale personnalisée" #: conf/sidebar_question.py:11 msgid "Question page banners and sidebar" @@ -3467,7 +3468,7 @@ msgstr "Veuillez vous connecter pour utiliser %s" #: models/__init__.py:569 models/__init__.py:1388 views/writers.py:226 msgid "Sorry, but you have only read access" -msgstr "" +msgstr "Désolé, mais vous n'avez q'un accès en lecture seule" #: models/__init__.py:573 msgid "Sorry, this operation is not allowed" @@ -5173,7 +5174,7 @@ msgstr "Voir les questions marquées par '%(tag)s'." #: templates/macros.html:395 msgid "Comments" -msgstr "" +msgstr "Commentaires" #: templates/macros.html:430 msgid "delete this comment" @@ -5274,7 +5275,7 @@ msgstr "voir plus de commentaires" #: templates/question.html:232 templates/question.html.py:335 msgid "add a comment" -msgstr "" +msgstr "ajouter un commentaire" #: templates/question.html:245 templates/question/content.html:46 msgid "Answer Your Own Question" @@ -5918,15 +5919,15 @@ msgstr "" #: templates/email/delayed_email_alert.html:2 #, python-format msgid "Dear %(name)s," -msgstr "" +msgstr "Cher %(name)s," #: templates/email/delayed_email_alert.html:3 #, python-format msgid "The following question has been updated %(site_name)s:" msgid_plural "" "The following %(num)s questions have been updated on %(site_name)s:" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "La question suivante a été mise à jour %(site_name)s:" +msgstr[1] "Les %(num)s questions suivantes ont été mises à jour sur %(site_name)s:" #: templates/email/feedback_email.txt:2 #, python-format @@ -6041,8 +6042,8 @@ msgid_plural "" "\n" " %(count)s comments:\n" " " -msgstr[0] "" -msgstr[1] "" +msgstr[0] "\n%(count)s commentaire:" +msgstr[1] "\n%(count)s commentaires:" #: templates/email/re_welcome_lamson_on.html:2 #: templates/email/re_welcome_lamson_on.html:3 @@ -6532,7 +6533,7 @@ msgstr "Votre réponse" #: templates/question/new_answer_form.html:22 msgid "Be the first one to answer this question!" -msgstr "Soyez le premier à répondre à cette quesion !" +msgstr "Soyez le premier à répondre à cette question !" #: templates/question/new_answer_form.html:28 msgid "" @@ -7543,11 +7544,11 @@ msgstr "" #: templates/widgets/tag_selector.html:59 msgid "Show only questions from" -msgstr "" +msgstr "Ne montrer que les questions de" #: templates/widgets/tag_selector.html:70 msgid "Send me email alerts for" -msgstr "" +msgstr "Envoyez-moi des alertes par email pour" #: templates/widgets/tag_selector.html:86 msgid "Change frequency of emails" @@ -7684,7 +7685,7 @@ msgstr "veuillez utiliser au moins quelques caractères alphabétiques dans le n #: utils/forms.py:110 msgid "symbol \"@\" is not allowed" -msgstr "" +msgstr "symbole \"@\" non autorisé" #: utils/forms.py:222 msgid "Your email <i>(never shared)</i>" @@ -7704,7 +7705,7 @@ msgstr "Cette adresse email est déjà utilisée par un autre utilisateur; veuil #: utils/forms.py:227 msgid "this email address is not authorized" -msgstr "" +msgstr "cette adresse email n'est pas autorisée" #: utils/forms.py:265 msgid "password is required" @@ -7825,7 +7826,7 @@ msgstr "Veuillez vous inscrire pour supprimer/récupérer une publication" #: views/commands.py:1042 #, python-format msgid "Group %(name)s does not exist" -msgstr "" +msgstr "Le groupe %(name)s n'existe pas" #: views/commands.py:1408 views/commands.py:1441 msgid "Sorry, looks like sharing request was invalid" @@ -7920,7 +7921,7 @@ msgstr "" #: views/users.py:739 msgid "private messages" -msgstr "" +msgstr "messages privés" #: views/users.py:740 msgid "profile - messages" diff --git a/askbot/locale/fr/LC_MESSAGES/djangojs.po b/askbot/locale/fr/LC_MESSAGES/djangojs.po index 22b9918d..8cf842e3 100644 --- a/askbot/locale/fr/LC_MESSAGES/djangojs.po +++ b/askbot/locale/fr/LC_MESSAGES/djangojs.po @@ -6,8 +6,8 @@ # Camille Baldock <mademoisellegeek42@gmail.com>, 2011 # Christophe kryskool <christophe.chauvet@gmail.com>, 2011-2013 # Emmanuel <emmanuel@raviart.com>, 2013 -# fbureau <francois.bureau@cloudwatt.com>, 2013 -# fbureau <francois.bureau@cloudwatt.com>, 2013 +# François Bureau <francois.bureau@cloudwatt.com>, 2013 +# François Bureau <francois.bureau@cloudwatt.com>, 2013 # Camille Baldock <mademoisellegeek42@gmail.com>, 2011 msgid "" msgstr "" diff --git a/askbot/locale/it/LC_MESSAGES/django.mo b/askbot/locale/it/LC_MESSAGES/django.mo Binary files differindex fc17f1a6..01c3c6bc 100644 --- a/askbot/locale/it/LC_MESSAGES/django.mo +++ b/askbot/locale/it/LC_MESSAGES/django.mo diff --git a/askbot/locale/it/LC_MESSAGES/django.po b/askbot/locale/it/LC_MESSAGES/django.po index ee277555..bd5a1054 100644 --- a/askbot/locale/it/LC_MESSAGES/django.po +++ b/askbot/locale/it/LC_MESSAGES/django.po @@ -6,13 +6,14 @@ # evgeny <evgeny.fadeev@gmail.com>, 2009 # giohappy <giohappy@gmail.com>, 2013 # giohappy <giohappy@gmail.com>, 2013 +# noizer, 2013 msgid "" msgstr "" "Project-Id-Version: askbot\n" "Report-Msgid-Bugs-To: http://askbot.org/\n" "POT-Creation-Date: 2013-07-13 14:06-0500\n" -"PO-Revision-Date: 2013-08-02 06:24+0000\n" -"Last-Translator: evgeny <evgeny.fadeev@gmail.com>\n" +"PO-Revision-Date: 2013-08-28 14:51+0000\n" +"Last-Translator: noizer\n" "Language-Team: Italian (http://www.transifex.com/projects/p/askbot/language/it/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -3793,8 +3794,8 @@ msgstr[1] "%(min)d minuti fa" #, python-format msgid "%(days)d day" msgid_plural "%(days)d days" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%(days)d giorno" +msgstr[1] "%(days)d giorni" #: models/__init__.py:2006 #, python-format @@ -3864,12 +3865,12 @@ msgstr[1] "%(count)d medaglie di bronzo" #: models/__init__.py:2533 #, python-format msgid "%(item1)s and %(item2)s" -msgstr "" +msgstr "%(item1)s e %(item2)s" #: models/__init__.py:2535 #, python-format msgid "%(user)s has %(badges)s" -msgstr "" +msgstr "%(user)s ha %(badges)s" #: models/__init__.py:2682 #, python-format diff --git a/askbot/locale/it/LC_MESSAGES/djangojs.mo b/askbot/locale/it/LC_MESSAGES/djangojs.mo Binary files differindex 9fac4301..6aa23a9d 100644 --- a/askbot/locale/it/LC_MESSAGES/djangojs.mo +++ b/askbot/locale/it/LC_MESSAGES/djangojs.mo diff --git a/askbot/locale/it/LC_MESSAGES/djangojs.po b/askbot/locale/it/LC_MESSAGES/djangojs.po index 70791c4b..183802fb 100644 --- a/askbot/locale/it/LC_MESSAGES/djangojs.po +++ b/askbot/locale/it/LC_MESSAGES/djangojs.po @@ -3,14 +3,15 @@ # This file is distributed under the same license as the PACKAGE package. # # Translators: +# noizer, 2013 # Valter Mura <valtermura@gmail.com>, 2012 msgid "" msgstr "" "Project-Id-Version: askbot\n" "Report-Msgid-Bugs-To: http://askbot.org/\n" "POT-Creation-Date: 2013-07-13 14:07-0500\n" -"PO-Revision-Date: 2013-08-02 06:25+0000\n" -"Last-Translator: evgeny <evgeny.fadeev@gmail.com>\n" +"PO-Revision-Date: 2013-08-28 14:50+0000\n" +"Last-Translator: noizer\n" "Language-Team: Italian (http://www.transifex.com/projects/p/askbot/language/it/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -78,11 +79,11 @@ msgstr "" #: media/js/group_messaging.js:139 msgid "Your message:" -msgstr "" +msgstr "Il tuo messaggio:" #: media/js/group_messaging.js:152 msgid "send" -msgstr "" +msgstr "invia" #: media/js/group_messaging.js:164 media/js/post.js:1809 #: media/js/post.js.c:3081 media/js/post.js.c:4598 media/js/user.js:888 @@ -91,11 +92,11 @@ msgstr "annulla" #: media/js/group_messaging.js:227 msgid "Reply" -msgstr "" +msgstr "Rispondi" #: media/js/group_messaging.js:236 media/js/group_messaging.js.c:743 msgid "message sent" -msgstr "" +msgstr "Messaggio inviato" #: media/js/group_messaging.js:271 msgid "user {{str}} does not exist" @@ -105,7 +106,7 @@ msgstr[1] "" #: media/js/group_messaging.js:278 msgid "cannot send message to yourself" -msgstr "" +msgstr "impossibile inviare un messaggio a te stesso" #: media/js/group_messaging.js:323 msgid "Recipient:" @@ -117,7 +118,7 @@ msgstr "" #: media/js/live_search.js:218 msgid "Ask Your Question" -msgstr "" +msgstr "Fai la tua domanda" #: media/js/live_search.js:299 msgid "Sorry, this tag does not exist" @@ -127,7 +128,7 @@ msgstr[1] "" #: media/js/live_search.js:313 msgid "search or ask your question" -msgstr "" +msgstr "cerca o fai la tua domanda" #: media/js/post.js:28 msgid "loading..." @@ -178,11 +179,11 @@ msgstr[1] "" #: media/js/post.js:253 msgid "Back to the question" -msgstr "" +msgstr "Torna alla domanda" #: media/js/post.js:303 msgid "draft saved..." -msgstr "" +msgstr "bozza salvata..." #: media/js/post.js:548 msgid "insufficient privilege" @@ -214,7 +215,7 @@ msgstr "conferma che questo post è offensivo" #: media/js/post.js:559 msgid "please confirm removal of offensive flag" -msgstr "" +msgstr "sei certo che questo post sia offensivo, contenga spam, pubblicità , osservazioni poco idonee, ecc.?" #: media/js/post.js:560 msgid "anonymous users cannot flag offensive posts" @@ -253,11 +254,11 @@ msgstr "<div>Segui</div><div class=\"unfollow\">Non seguire</div>" #: media/js/post.js:901 msgid "remove flag" -msgstr "" +msgstr "rimuovi flag" #: media/js/post.js:935 media/js/post.js.c:964 msgid "flag offensive" -msgstr "" +msgstr "sei certo che questo post sia offensivo, contenga spam, pubblicità , osservazioni poco idonee, ecc.?" #: media/js/post.js:990 media/js/post.js.c:1497 msgid "undelete" diff --git a/askbot/locale/ko/LC_MESSAGES/django.po b/askbot/locale/ko/LC_MESSAGES/django.po index b674aad2..32d7c156 100644 --- a/askbot/locale/ko/LC_MESSAGES/django.po +++ b/askbot/locale/ko/LC_MESSAGES/django.po @@ -10,7 +10,7 @@ # Jihui Choi <jihui.choi@gmail.com>, 2013 # alisol <nocaca@daum.net>, 2012 # seok woojing <ultra066@gmail.com>, 2012 -# Sungjin Gang <potopro@gmail.com>, 2013 +# ujuc Gang <potopro@gmail.com>, 2013 # Whoami Jeong <>, 2012 # Yong Choi <sk8er.choi@gmail.com>, 2012 msgid "" diff --git a/askbot/locale/ko/LC_MESSAGES/djangojs.mo b/askbot/locale/ko/LC_MESSAGES/djangojs.mo Binary files differindex a2c4d34e..9e789b0a 100644 --- a/askbot/locale/ko/LC_MESSAGES/djangojs.mo +++ b/askbot/locale/ko/LC_MESSAGES/djangojs.mo diff --git a/askbot/locale/ko/LC_MESSAGES/djangojs.po b/askbot/locale/ko/LC_MESSAGES/djangojs.po index dd26141d..4e32aa64 100644 --- a/askbot/locale/ko/LC_MESSAGES/djangojs.po +++ b/askbot/locale/ko/LC_MESSAGES/djangojs.po @@ -4,15 +4,15 @@ # # Translators: # EunMiLee <16thetower@gmail.com>, 2012 -# Sungjin Gang <potopro@gmail.com>, 2013 +# ujuc Gang <potopro@gmail.com>, 2013 # Yong Choi <sk8er.choi@gmail.com>, 2012 msgid "" msgstr "" "Project-Id-Version: askbot\n" "Report-Msgid-Bugs-To: http://askbot.org/\n" "POT-Creation-Date: 2013-07-13 14:07-0500\n" -"PO-Revision-Date: 2013-08-20 08:22+0000\n" -"Last-Translator: Sungjin Gang <potopro@gmail.com>\n" +"PO-Revision-Date: 2013-08-20 16:24+0000\n" +"Last-Translator: ujuc Gang <potopro@gmail.com>\n" "Language-Team: Korean (http://www.transifex.com/projects/p/askbot/language/ko/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -144,23 +144,23 @@ msgstr "ì ì–´ë„ í•˜ë‚˜ì˜ íƒœê·¸ë¥¼ ìž…ë ¥í•˜ì‹ì‹œì˜¤." #: media/js/post.js:160 msgid "details are required" -msgstr "" +msgstr "detailsì´ í•„ìš”í•©ë‹ˆë‹¤." #: media/js/post.js:163 #, c-format msgid "details must have > %s character" msgid_plural "details must have > %s characters" -msgstr[0] "" +msgstr[0] "ì ì–´ë„ %s ê¸€ìž ì´ìƒìœ¼ë¡œ ìž…ë ¥ì„ í•´ì£¼ì‹ì‹œì˜¤." #: media/js/post.js:171 msgid "enter your question" -msgstr "" +msgstr "ì§ˆë¬¸ì„ ìž…ë ¥í•´ì£¼ì„¸ìš”." #: media/js/post.js:174 #, c-format msgid "question must have > %s character" msgid_plural "question must have > %s characters" -msgstr[0] "" +msgstr[0] "ì ì–´ë„ %s ê¸€ìž ì´ìƒìœ¼ë¡œ ìž…ë ¥ì„ í•´ì£¼ì‹ì‹œì˜¤." #: media/js/post.js:193 msgid "content cannot be empty" @@ -264,7 +264,7 @@ msgstr "ê¸€ì´ ì‚ì œë˜ì—ˆìŠµë‹ˆë‹¤." #: media/js/post.js:1218 media/js/post.js.c:1445 msgid "sorry, something is not right here" -msgstr "" +msgstr "죄송합니다. ë”ê°€ 올바르지 않습니다." #: media/js/post.js:1665 msgid "add comment" @@ -319,7 +319,7 @@ msgstr "ì§ˆë¬¸ì„ ìž…ë ¥í•´ 주세요 (10ìž ì´ìƒ)" #: media/js/post.js:2612 media/js/post.js.c:4626 msgid "Sorry, you have only read access" -msgstr "" +msgstr "죄송합니다. ì½ê¸°ë§Œ 가능합니다." #: media/js/post.js:3075 media/js/post.js.c:3869 media/js/post.js.c:4058 msgid "save" @@ -366,7 +366,7 @@ msgstr "최소 í•˜ë‚˜ì˜ tag를 ìž…ë ¥í•´ 주ì‹ì‹œì˜¤." #: media/js/post.js:4011 msgid "already exists at the current level!" -msgstr "" +msgstr "ì´ë¯¸ 현재 ë ˆë²¨ì´ ì¡´ìž¬í•©ë‹ˆë‹¤!" #: media/js/post.js:4047 msgid "add category" @@ -430,35 +430,35 @@ msgstr "ê¸€ì´ ë³µì›ë˜ì—ˆìŠµë‹ˆë‹¤." #: media/js/user.js:246 msgid "Accept" -msgstr "" +msgstr "수ë½" #: media/js/user.js:255 msgid "Reject" -msgstr "" +msgstr "ê±°ì ˆ" #: media/js/user.js:270 msgid "add new reject reason" -msgstr "" +msgstr "새로운 ê±°ì ˆ ì´ìœ 추가" #: media/js/user.js:375 msgid "Looks there are some things to fix:" -msgstr "" +msgstr "해결하기 위한 ì–´ë–¤ 것들:" #: media/js/user.js:443 msgid "Please provide description." -msgstr "" +msgstr "ì„¤ëª…ì„ ìž‘ì„±í•˜ì‹ì‹œì˜¤." #: media/js/user.js:446 msgid "Please provide details." -msgstr "" +msgstr "세부 사í•ì„ 작성하ì‹ì‹œì˜¤." #: media/js/user.js:560 msgid "A reason must be selected to delete one." -msgstr "" +msgstr "하나를 ì‚ì œí•˜ë ¤ë©´ ì„ íƒí•˜ì—¬ì•¼ 합니다." #: media/js/user.js:659 msgid "A reason must be selected to reject post." -msgstr "" +msgstr "í¬ìŠ¤íŠ¸ë¥¼ ê±°ì ˆí•˜ê¸° 위해서는 ì„ íƒí•˜ì—¬ì•¼ 합니다." #: media/js/user.js:708 msgid "Please <a href=\"%(signin_url)s\">signin</a> to follow %(username)s" @@ -481,15 +481,15 @@ msgstr "%s 팔로우" #: media/js/user.js:883 msgid "add group" -msgstr "" +msgstr "그룹 추가" #: media/js/user.js:963 msgid "add" -msgstr "" +msgstr "추가" #: media/js/utils.js:99 msgid "and" -msgstr "" +msgstr "ê·¸ë¦¬ê³ " #: media/js/utils.js:117 msgid "click to close" @@ -497,211 +497,211 @@ msgstr "close를 ì„ íƒ" #: media/js/utils.js:880 msgid "click to edit this comment" -msgstr "" +msgstr "í´ë¦í•˜ì—¬ ì´ ëŒ“ê¸€ ìˆ˜ì •" #: media/js/utils.js:905 msgid "convert to answer" -msgstr "" +msgstr "답변 변경" #: media/js/utils.js:958 msgid "Ok" -msgstr "" +msgstr "Ok" #: media/js/utils.js:959 media/js/utils.js.c:1407 msgid "Cancel" -msgstr "" +msgstr "취소" #: media/js/utils.js:1219 #, c-format msgid "Uploaded file: %s" -msgstr "" +msgstr "íŒŒì¼ ì—…ë¡œë“œ: %s" #: media/js/utils.js:1234 msgid "Choose a different image" -msgstr "" +msgstr "다른 ì´ë¯¸ì§€ ì„ íƒ" #: media/js/utils.js:1236 msgid "Choose a different file" -msgstr "" +msgstr "다른 íŒŒì¼ ì„ íƒ" #: media/js/utils.js:1250 msgid "Oops, looks like we had an error. Sorry." -msgstr "" +msgstr "ì´ëŸ°! 오류가 ë°œìƒí–ˆë„¤ìš”. 죄송합니다." #: media/js/utils.js:1311 msgid "Choose an image to insert" -msgstr "" +msgstr "ì‚½ìž…í• ì´ë¯¸ì§€ ì„ íƒ" #: media/js/utils.js:1313 msgid "Choose a file to insert" -msgstr "" +msgstr "ì‚½ìž…í• íŒŒì¼ ì„ íƒ" #: media/js/utils.js:1326 msgid "Allowed file types are:" -msgstr "" +msgstr "íŒŒì¼ í˜•ì‹ í—ˆìš©:" #: media/js/utils.js:1332 #: media/js/tinymce/plugins/askbot_attachment/editor_plugin.js:35 msgid "Or paste file url here" -msgstr "" +msgstr "íŒŒì¼ urlì„ ì—¬ê¸°ì— ë¶™ì—¬ë„£ê¸° 하ì‹ì‹œì˜¤." #: media/js/utils.js:1406 msgid "Save" -msgstr "" +msgstr "ì €ìž¥" #: media/js/utils.js:1478 msgid "saved" -msgstr "" +msgstr "ì €ìž¥" #: media/js/utils.js:1602 msgid "enabled" -msgstr "" +msgstr "활성화" #: media/js/utils.js:1604 msgid "disabled" -msgstr "" +msgstr "비활성화" #: media/js/utils.js:2038 msgid "group name" -msgstr "" +msgstr "그룹 ì´ë¦„" #: media/js/utils.js:2046 msgid "add new group" -msgstr "" +msgstr "새로운 그룹 추가" #: media/js/utils.js:2138 msgid "Group %(name)s already exists. Group names are case-insensitive." -msgstr "" +msgstr "그룹 %(name)sì´ ì¡´ìž¬í•©ë‹ˆë‹¤. 그룹 ì´ë¦„ì€ ëŒ€ì†Œë¬¸ìž êµ¬ë¶„í•©ë‹ˆë‹¤." #: media/js/utils.js:2311 #, c-format msgid "see questions tagged '%s'" -msgstr "" +msgstr "'%s'ë¡œ íƒœê·¸ëœ ì§ˆë¬¸ë“¤ 보기" #: media/js/utils.js:3358 msgid "ago" -msgstr "" +msgstr "ì „" #: media/js/utils.js:3359 msgid "from now" -msgstr "" +msgstr "지금부터" #: media/js/utils.js:3361 msgid "about a minute" -msgstr "" +msgstr "ë¶„ì— ëŒ€í•´ì„œ" #: media/js/utils.js:3362 #, c-format msgid "%d minutes" -msgstr "" +msgstr "%d 분" #: media/js/utils.js:3363 msgid "about an hour" -msgstr "" +msgstr "ì‹œê°„ì— ëŒ€í•´ì„œ" #: media/js/utils.js:3364 #, c-format msgid "%d hours" -msgstr "" +msgstr "%d 시간" #: media/js/utils.js:3365 media/js/utils.js.c:3493 msgid "yesterday" -msgstr "" +msgstr "ì–´ì œ" #: media/js/utils.js:3366 #, c-format msgid "%d days" -msgstr "" +msgstr "%d ì¼" #: media/js/utils.js:3367 msgid "about a month" -msgstr "" +msgstr "ê°œì›”ì— ëŒ€í•´ì„œ" #: media/js/utils.js:3368 #, c-format msgid "%d months" -msgstr "" +msgstr "%d 개월" #: media/js/utils.js:3369 msgid "about a year" -msgstr "" +msgstr "ë…„ë„ì— ëŒ€í•´" #: media/js/utils.js:3370 #, c-format msgid "%d years" -msgstr "" +msgstr "%d ë…„" #: media/js/utils.js:3468 msgid "Jan" -msgstr "" +msgstr "1ì›”" #: media/js/utils.js:3469 msgid "Feb" -msgstr "" +msgstr "2ì›”" #: media/js/utils.js:3470 msgid "Mar" -msgstr "" +msgstr "3ì›”" #: media/js/utils.js:3471 msgid "Apr" -msgstr "" +msgstr "4ì›”" #: media/js/utils.js:3472 msgid "May" -msgstr "" +msgstr "5ì›”" #: media/js/utils.js:3473 msgid "Jun" -msgstr "" +msgstr "6ì›”" #: media/js/utils.js:3474 msgid "Jul" -msgstr "" +msgstr "7ì›”" #: media/js/utils.js:3475 msgid "Aug" -msgstr "" +msgstr "8ì›”" #: media/js/utils.js:3476 msgid "Sep" -msgstr "" +msgstr "9ì›”" #: media/js/utils.js:3477 msgid "Oct" -msgstr "" +msgstr "10ì›”" #: media/js/utils.js:3478 msgid "Nov" -msgstr "" +msgstr "11ì›”" #: media/js/utils.js:3479 msgid "Dec" -msgstr "" +msgstr "12ì›”" #: media/js/utils.js:3491 msgid "2 days ago" -msgstr "" +msgstr "ì´í‹€ ì „" #: media/js/utils.js:3498 #, c-format msgid "%s hour ago" msgid_plural "%s hours ago" -msgstr[0] "" +msgstr[0] "%s 시간 ì „" #: media/js/utils.js:3508 #, c-format msgid "%s min ago" msgid_plural "%s mins ago" -msgstr[0] "" +msgstr[0] "%s 분 ì „" #: media/js/tinymce/plugins/askbot_attachment/editor_plugin.js:71 msgid "Insert a file" -msgstr "" +msgstr "íŒŒì¼ ì‚½ìž…" #: media/js/tinymce/plugins/askbot_imageuploader/editor_plugin.js:70 msgid "Insert image" -msgstr "" +msgstr "ì´ë¯¸ì§€ì— 대한 URL를 ìž…ë ¥í•´ì£¼ì„¸ìš”. 예를들어, http://www.example.com/image.jpg ë˜ëŠ” ì´ë¯¸ì§€ 파ì¼ì„ ì˜¬ë ¤ì£¼ì„¸ìš”." #: media/js/wmd/wmd.js:31 msgid "bold" @@ -769,15 +769,15 @@ msgstr "ì—…ë¡œë“œí• íŒŒì¼ì„ ì„ íƒí•´ì£¼ì„¸ìš”" #: media/js/wmd/wmd.js:1836 msgid "image description" -msgstr "" +msgstr "ì´ë¯¸ì§€ 설명" #: media/js/wmd/wmd.js:1839 msgid "file name" -msgstr "" +msgstr "íŒŒì¼ ì´ë¦„" #: media/js/wmd/wmd.js:1843 msgid "link text" -msgstr "" +msgstr "ë§í¬ í…스트" #~ msgid "post a comment" #~ msgstr "save comment" diff --git a/askbot/locale/nb_NO/LC_MESSAGES/django.mo b/askbot/locale/nb_NO/LC_MESSAGES/django.mo Binary files differindex 7016178e..a2c9f2ee 100644 --- a/askbot/locale/nb_NO/LC_MESSAGES/django.mo +++ b/askbot/locale/nb_NO/LC_MESSAGES/django.mo diff --git a/askbot/locale/nb_NO/LC_MESSAGES/django.po b/askbot/locale/nb_NO/LC_MESSAGES/django.po index f8eacf5c..595720a5 100644 --- a/askbot/locale/nb_NO/LC_MESSAGES/django.po +++ b/askbot/locale/nb_NO/LC_MESSAGES/django.po @@ -9,7 +9,7 @@ msgstr "" "Project-Id-Version: askbot\n" "Report-Msgid-Bugs-To: http://askbot.org/\n" "POT-Creation-Date: 2013-07-13 14:06-0500\n" -"PO-Revision-Date: 2013-08-10 19:57+0000\n" +"PO-Revision-Date: 2013-09-09 22:33+0000\n" "Last-Translator: injectedreality <transifex@ireality.no>\n" "Language-Team: Norwegian BokmÃ¥l (Norway) (http://www.transifex.com/projects/p/askbot/language/nb_NO/)\n" "MIME-Version: 1.0\n" @@ -1367,25 +1367,25 @@ msgid "" "Potentially reduces number of steps in the registration process but can " "expose personal information, e.g. when LDAP login name is the same as email " "address or real name." -msgstr "" +msgstr "Reduserer potensielt antall trinn i registreringsprosessen, men kan avsløre personlig informasjon, for eksempel nÃ¥r LDAP login navn er det samme som e-postadressen eller ekte navn." #: conf/ldap.py:37 msgid "Version 3" -msgstr "" +msgstr "Versjon 3" #: conf/ldap.py:38 msgid "Version 2 (insecure and deprecated)!!!" -msgstr "" +msgstr "Versjon 2 (usikker og utgÃ¥tt)!!!" #: conf/ldap.py:47 msgid "LDAP protocol version" -msgstr "" +msgstr "LDAP protokollversjon" #: conf/ldap.py:49 msgid "" "Note that Version 2 protocol is not secure!!! Do not use it on unprotected " "network." -msgstr "" +msgstr "Vær oppmerksom at Versjon 2 protokollen ikke er sikker!!! Ikke bruk den pÃ¥ et ubeskyttet nettverk." #: conf/ldap.py:59 msgid "LDAP URL" @@ -1393,28 +1393,28 @@ msgstr "LDAP URL" #: conf/ldap.py:68 msgid "LDAP encoding" -msgstr "" +msgstr "LDAP encoding" #: conf/ldap.py:71 msgid "" "This value in almost all cases is \"utf-8\". Change it if yours is " "different. This field is required" -msgstr "" +msgstr "Denne verdien i nesten alle tilfeller er \"UTF-8\". Hvis din er forskjellig sÃ¥ kan du endre den. Dette feltet er pÃ¥krevd." #: conf/ldap.py:82 msgid "Base DN (distinguished name)" -msgstr "" +msgstr "Base DN (entydig navn)" #: conf/ldap.py:85 msgid "" "Usually base DN mirrors domain name of your organization, e.g. " "\"dn=example,dn=com\" when your site url is \"example.com\".This value is " "the \"root\" address of your LDAP directory." -msgstr "" +msgstr "Vanligvis base DN mirror domenenavnet til organisasjonen, for eksempel \"dn=example,dn=com\" nÃ¥r site url er \"example.com\". Denne verdien er \"root\"-adressen til LDAP-katalogen." #: conf/ldap.py:96 msgid "User search filter template" -msgstr "" +msgstr "Brukers søkefiltermal" #: conf/ldap.py:99 msgid "" @@ -1422,55 +1422,55 @@ msgid "" "should be left in the intact format. First placeholder will be used for the " "user id field name, and the second - for the user id value. The template can" " be extended to match schema of your LDAP directory." -msgstr "" +msgstr "Python string-format mal, mÃ¥ ha to string placeholders, som bør overlates i intakt form. Første placeholder vil bli brukt som brukeren id-felt-navn, og den andre - for brukerens id-verdi. Malen kan bli utvidet for bli lik skjema pÃ¥ din LDAP-katalog." #: conf/ldap.py:113 msgid "UserID/login field" -msgstr "" +msgstr "Brukerinnlogging" #: conf/ldap.py:116 msgid "" "This field is required. For Microsoft Active Directory this value usually is" " \"sAMAccountName\"." -msgstr "" +msgstr "Dette feltet er pÃ¥krevet. For Microsoft Active Directory denne verdien er vanligvis \"sAMAccountName\"." #: conf/ldap.py:127 msgid "\"Common Name\" field" -msgstr "" +msgstr "\"Vanlig navn\"-felt" #: conf/ldap.py:129 msgid "" "Common name is a formal or informal name of a person, can be blank. Use it " "only if surname and given names are not available." -msgstr "" +msgstr "Vanlig navn er et formellt eller uformellt navn pÃ¥ en person. Det kan være blankt. Bruk det bare hvis fornavn og etternavn ikke er tilgjengelig." #: conf/ldap.py:139 msgid "First name, Last name" -msgstr "" +msgstr "Fornavn, Etternavn" #: conf/ldap.py:140 msgid "Last name, First name" -msgstr "" +msgstr "Etternavn, Fornavn" #: conf/ldap.py:147 msgid "\"Common Name\" field format" -msgstr "" +msgstr "\"Normalt navn\" felt-format" #: conf/ldap.py:150 msgid "Use this only if \"Common Name\" field is used." -msgstr "" +msgstr "Bruk denne bare hvis \"Normalt navn\" feltet er i bruk." #: conf/ldap.py:158 msgid "Given (First) name" -msgstr "" +msgstr "Fornavn" #: conf/ldap.py:160 conf/ldap.py:170 msgid "This field can be blank" -msgstr "" +msgstr "Dette feltet kan være tomt" #: conf/ldap.py:168 msgid "Surname (last) name" -msgstr "" +msgstr "Etternavn" #: conf/ldap.py:178 msgid "LDAP Server EMAIL field name" @@ -1478,7 +1478,7 @@ msgstr "LDAP Server EPOST feltnavn" #: conf/ldap.py:180 msgid "This field is required" -msgstr "" +msgstr "Dette feltet er pÃ¥krevd" #: conf/leading_sidebar.py:12 msgid "Common left sidebar" @@ -1690,7 +1690,7 @@ msgstr "Aksepter eget svar" #: conf/minimum_reputation.py:58 msgid "Accept any answer" -msgstr "" +msgstr "Aksepter hvilket som helst svar" #: conf/minimum_reputation.py:67 msgid "Flag offensive" @@ -1710,17 +1710,17 @@ msgstr "Last opp filer" #: conf/minimum_reputation.py:115 msgid "Insert clickable links" -msgstr "" +msgstr "Legg til klikkbare lenker" #: conf/minimum_reputation.py:124 msgid "Insert link suggestions as plain text" -msgstr "" +msgstr "Legg til lenkeforslag som klartekst" #: conf/minimum_reputation.py:126 msgid "" "This value should be smaller than that for \"insert clickable links\". This " "setting should stop link-spamming by newly registered users." -msgstr "" +msgstr "Denne verdien bør være mindre enn for \"Sett inn klikkbare linker\". Denne innstillingen burde hindre link-spamming fra nyregistrerte brukere." #: conf/minimum_reputation.py:137 msgid "Close own questions" @@ -1766,7 +1766,7 @@ msgstr "" #: conf/minimum_reputation.py:223 msgid "Trigger email notifications" -msgstr "" +msgstr "Trigger for epostnotifikasoner" #: conf/minimum_reputation.py:224 conf/minimum_reputation.py:234 msgid "Reduces spam" @@ -1778,62 +1778,62 @@ msgstr "" #: conf/moderation.py:19 msgid "Content moderation" -msgstr "" +msgstr "Innholdsmoderasjon" #: conf/moderation.py:28 msgid "Enable content moderation" -msgstr "" +msgstr "Aktiver innholdsmoderasjon" #: conf/moderation.py:38 msgid "Enable tag moderation" -msgstr "" +msgstr "Aktiver merkelappmoderasjon" #: conf/moderation.py:40 msgid "" "If enabled, any new tags will not be applied to the questions, but emailed " "to the moderators. To use this feature, tags must be optional." -msgstr "" +msgstr "Hvis aktivert, sÃ¥ vil eventuellt nye koder ikke brukes pÃ¥ spørsmÃ¥lene, men blir sendt til moderatorene. Hvis du vil bruke denne funksjonen sÃ¥ mÃ¥ kodene være valgfrie." #: conf/question_lists.py:11 msgid "Listings of questions" -msgstr "" +msgstr "Utlisting av spørsmÃ¥l" #: conf/question_lists.py:20 msgid "Enable \"All Questions\" selector" -msgstr "" +msgstr "Aktiver \"Alle spørsmÃ¥l\"-velger" #: conf/question_lists.py:21 conf/question_lists.py:31 #: conf/question_lists.py:41 msgid "At least one of these selectors must be enabled" -msgstr "" +msgstr "Minst en av disse selektorene mÃ¥ være aktivert" #: conf/question_lists.py:30 msgid "Enable \"Unanswered Questions\" selector" -msgstr "" +msgstr "Aktiver \"Ubesvarte spørsmÃ¥l\"-velger" #: conf/question_lists.py:40 msgid "Enable \"Followed Questions\" selector" -msgstr "" +msgstr "Aktiver \"Fulgte spørsmÃ¥ls\"-velger" #: conf/question_lists.py:53 conf/question_lists.py:70 msgid "All Questions" -msgstr "" +msgstr "Alle SpørsmÃ¥l" #: conf/question_lists.py:54 conf/question_lists.py:71 msgid "Unanswered Questions" -msgstr "" +msgstr "Ubesvarte spørsmÃ¥l" #: conf/question_lists.py:55 msgid "Followed Questions" -msgstr "" +msgstr "Fulgte SpørsmÃ¥l" #: conf/question_lists.py:64 msgid "Default questions selector for the authenticated users" -msgstr "" +msgstr "Standard spørsmÃ¥lsvelger for autentiserte brukere" #: conf/question_lists.py:80 msgid "Default questions selector for the anonymous users" -msgstr "" +msgstr "Standard spørsmÃ¥lsvelger for anonyme brukere" #: conf/reputation_changes.py:13 msgid "Karma loss and gain rules" @@ -1970,28 +1970,28 @@ msgstr "" #: conf/sidebar_question.py:11 msgid "Question page banners and sidebar" -msgstr "" +msgstr "SpørsmÃ¥lside banner og sidebox" #: conf/sidebar_question.py:19 msgid "Top banner" -msgstr "" +msgstr "Toppbanner" #: conf/sidebar_question.py:22 msgid "" "When using this option, please use the HTML validation service to make sure " "that your input is valid and works well in all browsers." -msgstr "" +msgstr "NÃ¥r du bruker dette alternativet sÃ¥ kan du bruke HTML valideringstjeneste slik at du sørger for at ditt innlegg er gyldig og fungerer godt i alle nettlesere." #: conf/sidebar_question.py:42 msgid "Answers banner" -msgstr "" +msgstr "Svarbanner" #: conf/sidebar_question.py:45 msgid "" "This banner will show above the second answer. When using this option, " "please use the HTML validation service to make sure that your input is valid" " and works well in all browsers." -msgstr "" +msgstr "Dette banneret vil vises over svar nummer to. NÃ¥r du bruker dette alternativet sÃ¥ kan du bruke HTML valideringstjeneste slik at du sørger for at ditt innspill er gyldig og fungerer godt i alle nettlesere." #: conf/sidebar_question.py:70 msgid "" @@ -1999,7 +1999,7 @@ msgid "" " using this option (as well as the sidebar footer), please use the HTML " "validation service to make sure that your input is valid and works well in " "all browsers." -msgstr "" +msgstr "Bruk dette omrÃ¥de for Ã¥ legge til innhold pÃ¥ toppen av sideboksen i HTML format. NÃ¥r du bruker denne opsjonen (samt for sideboksfooter). bruk HTML valideringstjenesten for Ã¥ være sikker pÃ¥ at det du legger til er gyldig og fungerer godt i alle nettlesere." #: conf/sidebar_question.py:92 msgid "Show tag list in sidebar" @@ -2033,7 +2033,7 @@ msgstr "Bootstrap-modus" #: conf/site_modes.py:73 msgid "Activate a \"Large site\" mode" -msgstr "" +msgstr "Aktiver \"Stor nettside\" modus" #: conf/site_modes.py:75 msgid "" @@ -2041,7 +2041,7 @@ msgid "" "values, more suitable for the larger communities, <strong>WARNING:</strong> " "your current values for Minimum reputation, Badge Settings and Vote Rules " "will be changed after you modify this setting." -msgstr "" +msgstr "\"Stor nettside\"-modus øker omdømme og visse medaljeterskler, til verdier, mer egnet for de større samfunn, <strong>ADVARSEL:</ strong> dine nÃ¥værende verdier for Minimum omdømme, vil medaljeinnstillinger og stemmeregler endres etter at du forandrer denne innstillingen." #: conf/site_settings.py:14 msgid "URLS, keywords & greetings" @@ -2101,7 +2101,7 @@ msgstr "Hvis denne forblir tom, et simpelt tilbakemeldingsforum blir brukt i ste #: conf/skin_general_settings.py:15 msgid "Skin, logos and HTML <head> parts" -msgstr "" +msgstr "Mal, logoer og HTML <head> noder" #: conf/skin_general_settings.py:23 msgid "Q&A site logo" @@ -2113,87 +2113,87 @@ msgstr "For Ã¥ endre logo, velg en ny fil og send inn hele dette skjema igjen." #: conf/skin_general_settings.py:34 msgid "English" -msgstr "" +msgstr "Engelsk" #: conf/skin_general_settings.py:35 msgid "Spanish" -msgstr "" +msgstr "Spansk" #: conf/skin_general_settings.py:36 msgid "Catalan" -msgstr "" +msgstr "Catalan" #: conf/skin_general_settings.py:37 msgid "German" -msgstr "" +msgstr "Tysk" #: conf/skin_general_settings.py:38 msgid "Greek" -msgstr "" +msgstr "Gresk" #: conf/skin_general_settings.py:39 msgid "Finnish" -msgstr "" +msgstr "Finsk" #: conf/skin_general_settings.py:40 msgid "French" -msgstr "" +msgstr "Fransk" #: conf/skin_general_settings.py:41 msgid "Hindi" -msgstr "" +msgstr "Hindi" #: conf/skin_general_settings.py:42 msgid "Hungarian" -msgstr "" +msgstr "Ungarsk" #: conf/skin_general_settings.py:43 msgid "Italian" -msgstr "" +msgstr "Italiensk" #: conf/skin_general_settings.py:44 msgid "Japanese" -msgstr "" +msgstr "Japansk" #: conf/skin_general_settings.py:45 msgid "Korean" -msgstr "" +msgstr "Koreansk" #: conf/skin_general_settings.py:46 msgid "Portuguese" -msgstr "" +msgstr "Portogisisk" #: conf/skin_general_settings.py:47 msgid "Brazilian Portuguese" -msgstr "" +msgstr "Brasiliansk Portogisisk" #: conf/skin_general_settings.py:48 msgid "Romanian" -msgstr "" +msgstr "Rumensk" #: conf/skin_general_settings.py:49 msgid "Russian" -msgstr "" +msgstr "Russisk" #: conf/skin_general_settings.py:50 msgid "Serbian" -msgstr "" +msgstr "Seribisk" #: conf/skin_general_settings.py:51 msgid "Turkish" -msgstr "" +msgstr "Tyrkisk" #: conf/skin_general_settings.py:52 msgid "Vietnamese" -msgstr "" +msgstr "Vietnamesisk" #: conf/skin_general_settings.py:53 msgid "Chinese" -msgstr "" +msgstr "Kinesisk" #: conf/skin_general_settings.py:54 msgid "Chinese (Taiwan)" -msgstr "" +msgstr "Kinesisk (Taiwan)" #: conf/skin_general_settings.py:73 msgid "Show logo" @@ -2362,15 +2362,15 @@ msgstr "Vil bli satt automatisk og er ikke nødvendig Ã¥ modifisere manuelt." #: conf/social_sharing.py:11 msgid "Content sharing" -msgstr "" +msgstr "Innholdsdeling" #: conf/social_sharing.py:20 msgid "Check to enable RSS feeds" -msgstr "" +msgstr "Kryss av for Ã¥ aktivere RSS feeds" #: conf/social_sharing.py:29 msgid "Hashtag or suffix to sharing messages" -msgstr "" +msgstr "Hash-merkelapp og suffix for meldingsdeling" #: conf/social_sharing.py:38 msgid "Check to enable sharing of questions on Twitter" @@ -2442,11 +2442,11 @@ msgstr "Brukerinnstillinger" #: conf/user_settings.py:23 msgid "On-screen greeting shown to the new users" -msgstr "" +msgstr "Velkomstmelding som vises til nye brukere" #: conf/user_settings.py:32 msgid "Allow anonymous users send feedback" -msgstr "" +msgstr "Tillat anonyme bruker Ã¥ sende feedback" #: conf/user_settings.py:41 msgid "Allow editing user screen name" @@ -2454,11 +2454,11 @@ msgstr "Tillat endring av brukers visningsnavn" #: conf/user_settings.py:50 msgid "Auto-fill user name, email, etc on registration" -msgstr "" +msgstr "Autoutfyll brukernavn, epost, etc. under registrering" #: conf/user_settings.py:51 msgid "Implemented only for LDAP logins at this point" -msgstr "" +msgstr "Bare implementert for LDAP innlogging sÃ¥ langt" #: conf/user_settings.py:60 msgid "Allow users change own email addresses" @@ -2466,7 +2466,7 @@ msgstr "Tillat brukere til Ã¥ endre egene epostadresser" #: conf/user_settings.py:69 msgid "Allow email address in user name" -msgstr "" +msgstr "Tillat epostadresse som brukernavn" #: conf/user_settings.py:78 msgid "Allow account recovery by email" @@ -2646,22 +2646,22 @@ msgstr "relevanse" #: const/__init__.py:74 msgid "Never" -msgstr "" +msgstr "Aldri" #: const/__init__.py:75 msgid "When new post is published" -msgstr "" +msgstr "NÃ¥r nye innlegg blir publisert" #: const/__init__.py:76 msgid "When post is published or revised" -msgstr "" +msgstr "NÃ¥r innlegg publiseres eller endres" #: const/__init__.py:108 #, python-format msgid "" "Note: to reply with a comment, please use <a " "href=\"mailto:%(addr)s?subject=%(subject)s\">this link</a>" -msgstr "" +msgstr "Notat: for Ã¥ svare med en kommentar, vennligst bruk <a href=\"mailto:%(addr)s?subject=%(subject)s\">denne lenken</a>" #: const/__init__.py:122 templates/user_inbox/responses_and_flags.html:9 msgid "all" @@ -2673,7 +2673,7 @@ msgstr "ubesvart" #: const/__init__.py:124 msgid "followed" -msgstr "" +msgstr "fulgt" #: const/__init__.py:129 msgid "list" @@ -2765,7 +2765,7 @@ msgstr "epostoppdatering sendt til bruker" #: const/__init__.py:213 msgid "a post was shared" -msgstr "" +msgstr "et innlegg var delt" #: const/__init__.py:216 msgid "reminder about unanswered questions sent" @@ -2781,27 +2781,27 @@ msgstr "nevnt i en artikkel" #: const/__init__.py:225 msgid "created tag description" -msgstr "" +msgstr "laget merkelappbeskrivelse" #: const/__init__.py:229 msgid "updated tag description" -msgstr "" +msgstr "oppdaterte merkelappbeskrivelse" #: const/__init__.py:231 msgid "made a new post" -msgstr "" +msgstr "opprettet et nytt innlegg" #: const/__init__.py:234 msgid "made an edit" -msgstr "" +msgstr "gjorde en endring" #: const/__init__.py:238 msgid "created post reject reason" -msgstr "" +msgstr "opprettet en innleggsavvisningsgrunn" #: const/__init__.py:242 msgid "updated post reject reason" -msgstr "" +msgstr "oppdaterte innlegsavvisningsgrunn" #: const/__init__.py:300 msgid "answered question" @@ -2829,28 +2829,28 @@ msgstr "merkelapper omgjort" #: const/__init__.py:311 msgid "[private]" -msgstr "" +msgstr "[privat]" #: const/__init__.py:320 msgid "show all tags" -msgstr "" +msgstr "vis alle merkelapper" #: const/__init__.py:321 const/__init__.py:330 const/__init__.py:336 #: const/__init__.py:342 msgid "exclude ignored tags" -msgstr "" +msgstr "ekskluder ignorerte merkelapper" #: const/__init__.py:322 const/__init__.py:331 const/__init__.py:343 msgid "only interesting tags" -msgstr "" +msgstr "bare interresante merkelapper" #: const/__init__.py:326 const/__init__.py:337 const/__init__.py:344 msgid "only subscribed tags" -msgstr "" +msgstr "bare abonnerte merkelapper" #: const/__init__.py:329 const/__init__.py:335 const/__init__.py:341 msgid "email for all tags" -msgstr "" +msgstr "epost for alle merkelapper" #: const/__init__.py:348 msgid "instantly" @@ -2914,35 +2914,35 @@ msgstr "Opplastet Avatar" #: const/__init__.py:429 msgid "date descendant" -msgstr "" +msgstr "dato stigende" #: const/__init__.py:430 msgid "date ascendant" -msgstr "" +msgstr "dato fallende" #: const/__init__.py:431 msgid "activity descendant" -msgstr "" +msgstr "aktivitet stigende" #: const/__init__.py:432 msgid "activity ascendant" -msgstr "" +msgstr "aktivitet fallende" #: const/__init__.py:433 msgid "answers descendant" -msgstr "" +msgstr "svar stigende" #: const/__init__.py:434 msgid "answers ascendant" -msgstr "" +msgstr "svar fallende" #: const/__init__.py:435 msgid "votes descendant" -msgstr "" +msgstr "stemmer stigende" #: const/__init__.py:436 msgid "votes ascendant" -msgstr "" +msgstr "stemmer fallende" #: const/message_keys.py:21 msgid "most relevant questions" @@ -3014,7 +3014,7 @@ msgstr "ignorert" #: const/message_keys.py:38 models/tag.py:313 msgid "subscribed" -msgstr "" +msgstr "abonnert" #: const/message_keys.py:39 templates/question_retag.html:58 msgid "tags are required" @@ -3022,7 +3022,7 @@ msgstr "merkelapper mÃ¥ fylles ut" #: const/message_keys.py:41 msgid "please use letters, numbers and characters \"-+.#\"" -msgstr "" +msgstr "vennligst bruk bokstaver, tall eller tegnene \"-+.#\"" #: const/message_keys.py:47 msgid "" @@ -3103,7 +3103,7 @@ msgstr "signin/" #: deps/django_authopenid/urls.py:15 msgid "widget/signin/" -msgstr "" +msgstr "widget/signin/" #: deps/django_authopenid/urls.py:18 msgid "signout/" @@ -3131,7 +3131,7 @@ msgstr "recover/" #: deps/django_authopenid/urls.py:45 msgid "verify-email/" -msgstr "" +msgstr "verify-email/" #: deps/django_authopenid/util.py:379 #, python-format @@ -3157,7 +3157,7 @@ msgstr "AOL brukernavn" #: deps/django_authopenid/util.py:502 msgid "Sign in with LaunchPad" -msgstr "" +msgstr "Logg inn med LaunchPad" #: deps/django_authopenid/util.py:509 msgid "OpenID url" @@ -3312,7 +3312,7 @@ msgstr "Sjekk din epost Ã¥ følg den vedlagte lenken." #: deps/group_messaging/models.py:356 msgid "Re: " -msgstr "" +msgstr "Re:" #: deps/livesettings/models.py:107 deps/livesettings/models.py:153 msgid "Site" @@ -3350,33 +3350,33 @@ msgstr "Gratulerer. Du er nÃ¥ en Administrator" #: mail/__init__.py:183 msgid "<p>To ask by email, please:</p>" -msgstr "" +msgstr "<p>For Ã¥ spørre via epost:</p>" #: mail/__init__.py:185 msgid "<li>Type title in the subject line</li>" -msgstr "" +msgstr "<li>Typetittel i emnelinjen</li>" #: mail/__init__.py:188 msgid "<li>Type details of your question into the email body</li>" -msgstr "" +msgstr "<li>Typedetaljer for spørsmÃ¥l i epostinnhold</li>" #: mail/__init__.py:191 msgid "" "<li>The beginning of the subject line can contain tags,\n" "<em>enclosed in the square brackets</em> like so: [Tag1; Tag2]</li>" -msgstr "" +msgstr "<li>Begynnelsen av emnelinjer kan inneholde merkelpper,\n<em>omkretset av firkantparanteser</em> slik: [Merkelapp1; Merkelapp2]</li>" #: mail/__init__.py:195 msgid "" "<li>In the beginning of the subject add at least one tag\n" "<em>enclosed in the brackets</em> like so: [Tag1; Tag2].</li>" -msgstr "" +msgstr "<li>I begynnelsen av emnet, legg til minst en merkelapp\n<em>omkranset av firkantparantes</em> slik: [Merkelapp1; Merkelapp2].</li>" #: mail/__init__.py:199 msgid "" "<p>Note that a tag may consist of more than one word, to separate\n" "the tags, use a semicolon or a comma, for example, [One tag; Other tag]</p>" -msgstr "" +msgstr "<p>Legg merke til at merkelapp kan bestÃ¥ av mer enn et ord. For Ã¥ separere \nmerkelappene, bruk semikolon eller comma, som for eksempel, [En merkelapp; Annen merkelapp]</p>" #: mail/__init__.py:214 #, python-format diff --git a/askbot/locale/ru/LC_MESSAGES/django.mo b/askbot/locale/ru/LC_MESSAGES/django.mo Binary files differindex ab73ba75..82b2b137 100644 --- a/askbot/locale/ru/LC_MESSAGES/django.mo +++ b/askbot/locale/ru/LC_MESSAGES/django.mo diff --git a/askbot/locale/ru/LC_MESSAGES/django.po b/askbot/locale/ru/LC_MESSAGES/django.po index dc0eff25..97464485 100644 --- a/askbot/locale/ru/LC_MESSAGES/django.po +++ b/askbot/locale/ru/LC_MESSAGES/django.po @@ -3866,7 +3866,7 @@ msgstr "%(reputation)s кармы %(username)s " #, python-format msgid "one gold badge" msgid_plural "%(count)d gold badges" -msgstr[0] "<span class=\"hidden\">%(count)d</span>Ð·Ð¾Ð»Ð¾Ñ‚Ð°Ñ Ð¼ÐµÐ´Ð°Ð»ÑŒ" +msgstr[0] "%(count)d Ð·Ð¾Ð»Ð¾Ñ‚Ð°Ñ Ð¼ÐµÐ´Ð°Ð»ÑŒ" msgstr[1] "%(count)d золотых медалей" msgstr[2] "%(count)d золотых медалей" @@ -3874,7 +3874,7 @@ msgstr[2] "%(count)d золотых медалей" #, python-format msgid "one silver badge" msgid_plural "%(count)d silver badges" -msgstr[0] "<span class=\"hidden\">%(count)d</span>ÑеребрÑÐ½Ð°Ñ Ð¼ÐµÐ´Ð°Ð»ÑŒ" +msgstr[0] "%(count)d ÑеребрÑÐ½Ð°Ñ Ð¼ÐµÐ´Ð°Ð»ÑŒ" msgstr[1] "%(count)d ÑеребрÑных медалей" msgstr[2] "%(count)d ÑеребрÑных медалей" @@ -3882,7 +3882,7 @@ msgstr[2] "%(count)d ÑеребрÑных медалей" #, python-format msgid "one bronze badge" msgid_plural "%(count)d bronze badges" -msgstr[0] "<span class=\"hidden\">%(count)d</span>Ð±Ñ€Ð¾Ð½Ð·Ð¾Ð²Ð°Ñ Ð¼ÐµÐ´Ð°Ð»ÑŒ" +msgstr[0] "%(count)d Ð±Ñ€Ð¾Ð½Ð·Ð¾Ð²Ð°Ñ Ð¼ÐµÐ´Ð°Ð»ÑŒ" msgstr[1] "%(count)d бронзовых медалей" msgstr[2] "%(count)d бронзовых медалей" diff --git a/askbot/locale/vi/LC_MESSAGES/django.mo b/askbot/locale/vi/LC_MESSAGES/django.mo Binary files differindex 7b848f14..dc54b8ef 100644 --- a/askbot/locale/vi/LC_MESSAGES/django.mo +++ b/askbot/locale/vi/LC_MESSAGES/django.mo diff --git a/askbot/locale/vi/LC_MESSAGES/django.po b/askbot/locale/vi/LC_MESSAGES/django.po index a552642d..65462f00 100644 --- a/askbot/locale/vi/LC_MESSAGES/django.po +++ b/askbot/locale/vi/LC_MESSAGES/django.po @@ -5,13 +5,17 @@ # Translators: # ppanhh <ppanhh@gmail.com>, 2013 # Cong It <EMAIL@ADDRESS>, 2010 +# linux <linux87s@gmail.com>, 2013 +# Nguyen Long <gialacmail@gmail.com>, 2013 +# ppanhh <ppanhh@gmail.com>, 2013 +# rgv151 <rgv151@gmail.com>, 2013 msgid "" msgstr "" "Project-Id-Version: askbot\n" "Report-Msgid-Bugs-To: http://askbot.org/\n" "POT-Creation-Date: 2013-07-13 14:06-0500\n" -"PO-Revision-Date: 2013-08-17 04:26+0000\n" -"Last-Translator: ppanhh <ppanhh@gmail.com>\n" +"PO-Revision-Date: 2013-09-19 03:25+0000\n" +"Last-Translator: evgeny <evgeny.fadeev@gmail.com>\n" "Language-Team: Vietnamese (http://www.transifex.com/projects/p/askbot/language/vi/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -47,17 +51,17 @@ msgstr "Khung thông tin vá» quốc gia không được để trống" #, python-format msgid "must be > %d word" msgid_plural "must be > %d words" -msgstr[0] "" +msgstr[0] "cần phải dà i hÆ¡n %d kà tá»±" #: forms.py:199 #, python-format msgid "must be < %d word" msgid_plural "must be < %d words" -msgstr[0] "" +msgstr[0] "cần phải ngắn hÆ¡n %d kà tá»±" #: forms.py:220 msgid "minor edit (don't send alerts)" -msgstr "" +msgstr "chỉnh sữa nhá» (không gá»i thông báo)" #: forms.py:247 templates/widgets/markdown_help.html:20 #: templates/widgets/markdown_help.html:24 @@ -66,23 +70,23 @@ msgstr "tiêu Ä‘á»" #: forms.py:249 templates/embed/ask_by_widget.html:170 msgid "Please enter your question" -msgstr "" +msgstr "Hãy nháºp câu há»i của bạn" #: forms.py:260 #, python-format msgid "must have > %d character" msgid_plural "must have > %d characters" -msgstr[0] "" +msgstr[0] "cần phải dà i hÆ¡n %d kà tá»±" #: forms.py:270 #, python-format msgid "The question is too long, maximum allowed size is %d characters" -msgstr "" +msgstr "Câu há»i nà y quá dà i, tối Ä‘a cho phép là %d kà tá»±" #: forms.py:277 #, python-format msgid "The question is too long, maximum allowed size is %d bytes" -msgstr "" +msgstr "Câu há»i nà y quá dà i, tối Ä‘a cho phép là %d byte" #: forms.py:309 msgid "content" @@ -98,7 +102,7 @@ msgstr[0] "má»—i thẻ đánh dấu phải có Ãt hÆ¡n %(max_chars)d ký tá»±" msgid "" "We ran out of space for recording the tags. Please shorten or delete some of" " them." -msgstr "" +msgstr "Chúng ta đã sá» dụng hết dung lượng thẻ tối Ä‘a, hãy rút ngắn lại hoặc bá» bá»›t để tiếp tục." #: forms.py:410 forms.py:1006 models/widgets.py:27 #: templates/widgets/edit_post.html:32 templates/widgets/meta_nav.html:6 @@ -113,7 +117,7 @@ msgid "" msgid_plural "" "Tags are short keywords, with no spaces within. Up to %(max_tags)d tags can " "be used." -msgstr[0] "" +msgstr[0] "Thẻ là những từ khoá ngắn, không có khoảng trống. Bạn có thể dùng tối Ä‘a %(max_tags)d." #: forms.py:439 #, python-format @@ -160,122 +164,122 @@ msgstr "đã theo dõi" #: forms.py:602 const/__init__.py:377 msgid "suspended" -msgstr "" +msgstr "bị đình chỉ" #: forms.py:603 const/__init__.py:378 msgid "blocked" -msgstr "" +msgstr "bị khóa" #: forms.py:605 msgid "administrator" -msgstr "" +msgstr "quản trị viên" #: forms.py:606 const/__init__.py:374 msgid "moderator" -msgstr "" +msgstr "Ä‘iá»u hà nh viên" #: forms.py:625 msgid "Change status to" -msgstr "" +msgstr "Äổi trạng thái thà nh" #: forms.py:652 msgid "which one?" -msgstr "" +msgstr "-- chá»n -- " #: forms.py:673 msgid "Cannot change own status" -msgstr "" +msgstr "Bạn không thể thay đổi quyá»n của mình" #: forms.py:679 msgid "Cannot turn other user to moderator" -msgstr "" +msgstr "Bạn không thể nâng quyá»n Ä‘iá»u hà nh cho ngÆ°á»i khác" #: forms.py:686 msgid "Cannot change status of another moderator" -msgstr "" +msgstr "Không thể thay đổi quyá»n của ngÆ°á»i Ä‘iá»u hà nh khác" #: forms.py:692 msgid "Cannot change status to admin" -msgstr "" +msgstr "Không thể nâng lên quyá»n quản lý" #: forms.py:698 #, python-format msgid "" "If you wish to change %(username)s's status, please make a meaningful " "selection." -msgstr "" +msgstr "Nếu bạn muốn thay đổi quyá»n của %(username)s, hãy Ä‘Æ°a ra lá»±a chá»n hợp lý." #: forms.py:708 msgid "Subject line" -msgstr "" +msgstr "Tiêu Ä‘á»" #: forms.py:713 msgid "Message text" -msgstr "" +msgstr "Ná»™i dung" #: forms.py:727 msgid "Your name (optional):" -msgstr "" +msgstr "Tên của bạn (Không bắt buá»™c)" #: forms.py:728 msgid "Email:" -msgstr "" +msgstr "Email:" #: forms.py:730 msgid "Your message:" -msgstr "" +msgstr "Thông Ä‘iệp:" #: forms.py:735 msgid "I don't want to give my email or receive a response:" -msgstr "" +msgstr "Tôi không muốn cung cấp địa chỉ email hoặc nháºn thông tin phản hồi:" #: forms.py:758 msgid "Please mark \"I dont want to give my mail\" field." -msgstr "" +msgstr "Hãy đánh dấu mục \"Tôi không muốn cung cấp địa chỉ email\"." #: forms.py:791 msgid "keep private within your groups" -msgstr "" +msgstr "giữ bà máºt trong các nhóm của bạn" #: forms.py:830 msgid "User name:" -msgstr "" +msgstr "Tên đăng nháºp:" #: forms.py:832 msgid "Enter name to post on behalf of someone else. Can create new accounts." -msgstr "" +msgstr "Hãy Ä‘iá»n tên của ngÆ°á»i bạn muốn đăng há»™, hoặc tạo tà i khoản má»›i." #: forms.py:839 msgid "Email address:" -msgstr "" +msgstr "Äịa chỉ email:" #: forms.py:889 msgid "User name is required with the email" -msgstr "" +msgstr "Tên đăng nháºp là bắt buá»™c cùng vá»›i email" #: forms.py:894 msgid "Email is required if user name is added" -msgstr "" +msgstr "Bạn phải cung cấp địa chỉ email nếu dùng tên đăng nháºp" #: forms.py:914 forms.py:957 msgid "ask anonymously" -msgstr "" +msgstr "há»i nặc danh" #: forms.py:916 forms.py:959 msgid "Check if you do not want to reveal your name when asking this question" -msgstr "" +msgstr "chá»n nếu bạn không muốn tiết lá»™ tên của bạn khi há»i câu há»i nà y" #: forms.py:947 msgid "" "Subject line is expected in the format: [tag1, tag2, tag3,...] question " "title" -msgstr "" +msgstr "Tiêu đỠđược hiểu theo định dạng: [thẻ1, thẻ2, thẻ3,...] câu há»i" #: forms.py:1213 msgid "" "You have asked this question anonymously, if you decide to reveal your " "identity, please check this box." -msgstr "" +msgstr "Bạn đã ẩn danh khi há»i câu nà y, nếu bạn quyết định tiết lá»™ danh tÃnh của bạn, xin vui lòng chá»n và o đây ." #: forms.py:1217 msgid "reveal identity" @@ -296,7 +300,7 @@ msgstr "" #: forms.py:1373 msgid "Real name" -msgstr "" +msgstr "Tên tháºt" #: forms.py:1380 msgid "Website" @@ -304,27 +308,27 @@ msgstr "" #: forms.py:1387 msgid "City" -msgstr "" +msgstr "Thà nh phố" #: forms.py:1396 msgid "Show country" -msgstr "" +msgstr "Hiển thị Quốc gia" #: forms.py:1401 msgid "Show tag choices" -msgstr "" +msgstr "Hiển thị lá»±a chá»n từ khóa" #: forms.py:1406 msgid "Date of birth" -msgstr "" +msgstr "Ngà y sinh" #: forms.py:1408 msgid "will not be shown, used to calculate age, format: YYYY-MM-DD" -msgstr "" +msgstr "sẽ không được hiển thị, được dùng để tÃnh tuổi, định dạng : YYYY-MM-DD" #: forms.py:1416 msgid "Profile" -msgstr "" +msgstr "Hồ sÆ¡ cá nhân" #: forms.py:1425 msgid "Screen name" @@ -332,7 +336,7 @@ msgstr "" #: forms.py:1457 forms.py:1461 msgid "this email has already been registered, please use another one" -msgstr "" +msgstr "email nà y đã được sá» dụng hãy thá» lại vá»›i email khác" #: forms.py:1470 msgid "Choose email tag filter" @@ -340,11 +344,11 @@ msgstr "" #: forms.py:1522 msgid "Asked by me" -msgstr "" +msgstr "Câu há»i của tôi" #: forms.py:1525 msgid "Answered by me" -msgstr "" +msgstr "Câu trả lá»i của tôi" #: forms.py:1528 msgid "Individually selected" @@ -352,15 +356,15 @@ msgstr "" #: forms.py:1531 msgid "Entire forum (tag filtered)" -msgstr "" +msgstr "Toà n bá»™ diá»…n Ä‘Ã n (đã lá»c theo từ khóa)" #: forms.py:1535 msgid "Comments and posts mentioning me" -msgstr "" +msgstr "à kiến ​​và bà i ​​viết Ä‘á» cáºp đến tôi" #: forms.py:1619 msgid "please choose one of the options above" -msgstr "" +msgstr "xin vui lòng chá»n má»™t trong các tùy chá»n ở trên" #: forms.py:1622 msgid "okay, let's try!" @@ -373,51 +377,51 @@ msgstr "" #: forms.py:1673 templates/reopen.html:7 msgid "Title" -msgstr "" +msgstr "tiêu Ä‘á»" #: forms.py:1676 templates/groups.html:32 msgid "Description" -msgstr "" +msgstr "Mô tả" #: forms.py:1695 templates/tags.html:3 templates/tags/header.html:9 #: templates/tags/list_bulk_tag_subscription.html:12 #: templates/widgets/edit_post.html:26 templates/widgets/related_tags.html:3 #: templates/widgets/tag_category_selector.html:2 msgid "Tags" -msgstr "" +msgstr "Thẻ đánh dấu" #: tasks.py:98 msgid "An edit for my answer" -msgstr "" +msgstr "chỉnh sá»a câu trả lá»i của tôi" #: tasks.py:101 msgid "To add to your post EDIT ABOVE THIS LINE" -msgstr "" +msgstr "Äể thêm và o bà i viết của bạn SỬA DÃ’NG TRÊN" #: tasks.py:119 #, python-format msgid "Your post at %(site_name)s is now published" -msgstr "" +msgstr "Bà i viết của bạn đã được đăng ở mục %(site_name)s" #: urls.py:44 msgid "questions" -msgstr "" +msgstr "câu há»i" #: urls.py:56 msgid "question/" -msgstr "" +msgstr "câu há»i/" #: urls.py:61 msgid "tags/" -msgstr "" +msgstr "thẻ đánh dấu/" #: urls.py:66 urls.py:71 urls.py:78 urls.py:84 urls.py:93 urls.py:100 msgid "users/" -msgstr "" +msgstr "ngÆ°á»i dùng/" #: urls.py:71 msgid "by-group/" -msgstr "" +msgstr "bởi nhóm/" #: urls.py:78 urls.py:159 urls.py:226 urls.py:520 msgid "edit/" @@ -556,23 +560,23 @@ msgstr "" #: conf/access_control.py:17 msgid "Allow only registered user to access the forum" -msgstr "" +msgstr "Chỉ cho phép ngÆ°á»i dùng đã đăng ký được và o diá»…n Ä‘Ã n" #: conf/access_control.py:22 msgid "nothing - not required" -msgstr "" +msgstr "không có gì - không bắt buá»™c" #: conf/access_control.py:23 msgid "access to content" -msgstr "" +msgstr "truy cáºp ná»™i dung" #: conf/access_control.py:34 msgid "Require valid email for" -msgstr "" +msgstr "yêu cầu email hợp lệ cho" #: conf/access_control.py:44 msgid "Allowed email addresses" -msgstr "" +msgstr "Äịa chỉ email cho phép" #: conf/access_control.py:45 msgid "Please use space to separate the entries" @@ -580,7 +584,7 @@ msgstr "" #: conf/access_control.py:54 msgid "Allowed email domain names" -msgstr "" +msgstr "Äịa chỉ tên miá»n email cho phép" #: conf/access_control.py:55 msgid "Please use space to separate the entries, do not use the @ symbol!" @@ -588,7 +592,7 @@ msgstr "" #: conf/badges.py:13 msgid "Badge settings" -msgstr "" +msgstr "Thiết láºp huy hiệu" #: conf/badges.py:23 msgid "Disciplined: minimum upvotes for deleted post" @@ -628,15 +632,15 @@ msgstr "" #: conf/badges.py:104 msgid "Popular Question: minimum views" -msgstr "" +msgstr "Câu há»i phổ biến: lượt xem tối thiểu" #: conf/badges.py:113 msgid "Notable Question: minimum views" -msgstr "" +msgstr "Câu há»i đáng chú ý:lượt xem tối thiểu" #: conf/badges.py:122 msgid "Famous Question: minimum views" -msgstr "" +msgstr "Câu há»i nổi tiếng: lượt xem tối thiểu" #: conf/badges.py:131 msgid "Self-Learner: minimum answer upvotes" @@ -664,7 +668,7 @@ msgstr "" #: conf/badges.py:185 msgid "Associate Editor: minimum number of edits" -msgstr "" +msgstr "Phó biên táºp: số lượng chỉ sá»a tối thiểu" #: conf/badges.py:194 msgid "Favorite Question: minimum stars" @@ -688,11 +692,11 @@ msgstr "" #: conf/email.py:15 msgid "Email and email alert settings" -msgstr "" +msgstr "Email và thiết láºp email cảnh báo" #: conf/email.py:24 msgid "Prefix for the email subject line" -msgstr "" +msgstr "Tiá»n tố cho dòng chủ Ä‘á» email" #: conf/email.py:26 msgid "" @@ -702,70 +706,70 @@ msgstr "" #: conf/email.py:44 msgid "Site administrator email address" -msgstr "" +msgstr "Äịa chỉ email của ngÆ°á»i quản trị trang web" #: conf/email.py:53 msgid "Enable email alerts" -msgstr "" +msgstr "Báºt thông báo bằng email" #: conf/email.py:62 msgid "Maximum number of news entries in an email alert" -msgstr "" +msgstr "Số lượng tối Ä‘a các mục tin tức trong má»™t thông báo qua email" #: conf/email.py:72 msgid "Default notification frequency all questions" -msgstr "" +msgstr "Mặc định tần số thông báo tất cả các câu há»i" #: conf/email.py:74 msgid "Option to define frequency of emailed updates for: all questions." -msgstr "" +msgstr "Tùy chá»n để xác định tần số cáºp nháºt được gá»i qua email cho: tất cả các câu há»i." #: conf/email.py:86 msgid "Default notification frequency questions asked by the user" -msgstr "" +msgstr "Mặc định tần số thông báo câu há»i của ngÆ°á»i sá» dụng" #: conf/email.py:88 msgid "" "Option to define frequency of emailed updates for: Question asked by the " "user." -msgstr "" +msgstr "Tùy chá»n để xác định tần số cáºp nháºt được gá»i qua email cho: Câu há»i yêu cầu bởi ngÆ°á»i dùng." #: conf/email.py:100 msgid "Default notification frequency questions answered by the user" -msgstr "" +msgstr "Tần số thông báo mặc định cho câu há»i đã trả lá»i bởi ngÆ°á»i dùng" #: conf/email.py:102 msgid "" "Option to define frequency of emailed updates for: Question answered by the " "user." -msgstr "" +msgstr "Tùy chá»n để xác định tần số cáºp nháºt được gá»i qua email cho: Câu há»i đã trả lá»i bởi ngÆ°á»i dùng." #: conf/email.py:114 msgid "" "Default notification frequency questions individually" " selected by the user" -msgstr "" +msgstr "Tần số thông báo mặc định câu há»i lá»±a chá»n cá nhân của ngÆ°á»i dùng" #: conf/email.py:117 msgid "" "Option to define frequency of emailed updates for: Question individually " "selected by the user." -msgstr "" +msgstr "Tùy chá»n để xác định tần số cáºp nháºt được gá»i qua email cho: Câu há»i lá»±a chá»n cá nhân của ngÆ°á»i dùng." #: conf/email.py:129 msgid "" "Default notification frequency for mentions and " "comments" -msgstr "" +msgstr "Tần số thông báo mặc định cho Ä‘á» cáºp và bình luáºn" #: conf/email.py:132 msgid "" "Option to define frequency of emailed updates for: Mentions and comments." -msgstr "" +msgstr "Tùy chá»n để xác định tần số cáºp nháºt được gá»i qua email cho: Äá» cáºp và bình luáºn." #: conf/email.py:143 msgid "Send periodic reminders about unanswered questions" -msgstr "" +msgstr "Gá»i lá»i nhắc nhở định kỳ vá» các câu há»i chÆ°a được trả lá»i" #: conf/email.py:145 msgid "" @@ -776,7 +780,7 @@ msgstr "" #: conf/email.py:158 msgid "Days before starting to send reminders about unanswered questions" -msgstr "" +msgstr "Ngà y trÆ°á»›c khi bắt đầu gá»i lá»i nhắc nhở vá» những câu há»i chÆ°a được trả lá»i" #: conf/email.py:169 msgid "" @@ -786,11 +790,11 @@ msgstr "" #: conf/email.py:181 msgid "Max. number of reminders to send about unanswered questions" -msgstr "" +msgstr "Số lượng tối Ä‘a của lá»i nhắc để gá»i vá» các câu há»i chÆ°a được trả lá»i" #: conf/email.py:192 msgid "Send periodic reminders to accept the best answer" -msgstr "" +msgstr "Gá»i lá»i nhắc nhở định kỳ để chấp nháºn câu trả lá»i tốt nhất" #: conf/email.py:194 msgid "" @@ -801,7 +805,7 @@ msgstr "" #: conf/email.py:207 msgid "Days before starting to send reminders to accept an answer" -msgstr "" +msgstr "Ngà y trÆ°á»›c khi bắt đầu gá»i lá»i nhắc nhở để chấp nháºn má»™t câu trả lá»i" #: conf/email.py:218 msgid "" @@ -811,11 +815,11 @@ msgstr "" #: conf/email.py:230 msgid "Max. number of reminders to send to accept the best answer" -msgstr "" +msgstr "Số lượng tối Ä‘a của lá»i nhắc để gá»i chấp nháºn câu trả lá»i tốt nhất" #: conf/email.py:242 msgid "Require email verification before allowing to post" -msgstr "" +msgstr "Yêu cầu xác minh email trÆ°á»›c khi cho phép gá»i" #: conf/email.py:243 msgid "" @@ -824,7 +828,7 @@ msgstr "" #: conf/email.py:252 msgid "Fake email for anonymous user" -msgstr "" +msgstr "Email giả mạo cho ngÆ°á»i dùng vô danh" #: conf/email.py:253 msgid "Use this setting to control gravatar for email-less user" @@ -832,7 +836,7 @@ msgstr "" #: conf/email.py:262 msgid "Allow posting questions by email" -msgstr "" +msgstr "Cho phép gá»i câu há»i qua email" #: conf/email.py:264 msgid "" @@ -842,21 +846,21 @@ msgstr "" #: conf/email.py:275 msgid "Replace space in emailed tags with dash" -msgstr "" +msgstr "Thay thế khoảng trống trong thẻ email bằng dấu gạch ngang" #: conf/email.py:277 msgid "" "This setting applies to tags written in the subject line of questions asked " "by email" -msgstr "" +msgstr "Thiết láºp nà y áp dụng đối vá»›i thẻ ghi trong dòng chủ Ä‘á» của câu há»i qua email" #: conf/email.py:288 msgid "Enable posting answers and comments by email" -msgstr "" +msgstr "Cho phép gá»i câu trả lá»i và ý kiến ​​qua email" #: conf/email.py:291 msgid "To enable this feature make sure lamson is running" -msgstr "" +msgstr "Äể kÃch hoạt tÃnh năng nà y hãy chắc chắn lamson Ä‘ang chạy" #: conf/email.py:302 msgid "Emailed post: when to notify author about publishing" @@ -874,11 +878,11 @@ msgstr "" #: conf/external_keys.py:11 msgid "Keys for external services" -msgstr "" +msgstr "Các chìa khóa cho các dịch vụ bên ngoà i" #: conf/external_keys.py:19 msgid "Google site verification key" -msgstr "" +msgstr "Chìa khóa xác minh Google site" #: conf/external_keys.py:21 #, python-format @@ -889,7 +893,7 @@ msgstr "" #: conf/external_keys.py:36 msgid "Google Analytics key" -msgstr "" +msgstr "Chìa khóa Google Analytics " #: conf/external_keys.py:38 #, python-format @@ -900,7 +904,7 @@ msgstr "" #: conf/external_keys.py:51 msgid "Enable recaptcha (keys below are required)" -msgstr "" +msgstr "Báºt recaptcha (khóa bên dÆ°á»›i là bắt buá»™c)" #: conf/external_keys.py:62 msgid "Recaptcha public key" @@ -943,7 +947,7 @@ msgstr "" msgid "" "Please register your forum at <a href=\"%(url)s\">twitter applications " "site</a>" -msgstr "" +msgstr "Xin vui lòng đăng ký diá»…n Ä‘Ã n của bạn tại <a href=\"%(url)s\"> ứng dụng trang web twitter</ a>" #: conf/external_keys.py:120 msgid "Twitter consumer secret" @@ -958,7 +962,7 @@ msgstr "" msgid "" "Please register your forum at <a href=\"%(url)s\">LinkedIn developer " "site</a>" -msgstr "" +msgstr "Xin vui lòng đăng ký diá»…n Ä‘Ã n của bạn tại <a href=\"%(url)s\">trang developer LinkedIn </ a>" #: conf/external_keys.py:141 msgid "LinkedIn consumer secret" @@ -973,7 +977,7 @@ msgstr "" msgid "" "Please register your forum at <a href=\"%(url)s\">Identi.ca applications " "site</a>" -msgstr "" +msgstr "Xin vui lòng đăng ký diá»…n Ä‘Ã n của bạn tại <a href=\"%(url)s\">Identi.ca applications site</a>" #: conf/external_keys.py:162 msgid "ident.ca consumer secret" @@ -981,7 +985,7 @@ msgstr "" #: conf/flatpages.py:11 msgid "Messages and pages - about, privacy policy, etc." -msgstr "" +msgstr "Tin nhắn và các trang - vá» chÃnh sách bảo máºt, vv" #: conf/flatpages.py:19 msgid "Text of the Q&A forum About page (html format)" @@ -1005,7 +1009,7 @@ msgstr "" #: conf/flatpages.py:45 msgid "Instructions on how to ask questions" -msgstr "" +msgstr "HÆ°á»›ng dẫn vá» cách đặt câu há»i" #: conf/flatpages.py:48 msgid "" @@ -1025,19 +1029,19 @@ msgstr "" #: conf/flatpages.py:75 msgid "Do not edit this field manually!!!" -msgstr "" +msgstr "Không chỉnh sá»a trÆ°á»ng nà y bằng tay!" #: conf/forum_data_rules.py:12 msgid "Data entry and display rules" -msgstr "" +msgstr "Nháºp dữ liệu và các quy tắc hiển thị" #: conf/forum_data_rules.py:27 msgid "Editor for the posts" -msgstr "" +msgstr "Biên táºp viên cho các bà i viết" #: conf/forum_data_rules.py:42 msgid "Editor for the comments" -msgstr "" +msgstr "Biên táºp viên cho ý kiến" #: conf/forum_data_rules.py:51 msgid "Enable big Ask button" @@ -1047,11 +1051,11 @@ msgstr "" msgid "" "Disabling this button will reduce number of new questions. If this button is" " disabled, the ask button in the search menu will still be available." -msgstr "" +msgstr "Vô hiệu hóa nút nà y sẽ là m giảm số câu há»i má»›i. Nếu nút nà y bị vô hiệu hóa, các nút ask trong menu tìm kiếm sẽ vẫn có sẵn." #: conf/forum_data_rules.py:66 msgid "Enable embedding videos. " -msgstr "" +msgstr "Cho phép nhúng video." #: conf/forum_data_rules.py:68 #, python-format @@ -1060,11 +1064,11 @@ msgstr "" #: conf/forum_data_rules.py:78 msgid "Check to enable community wiki feature" -msgstr "" +msgstr "chá»n để kÃch hoạt tÃnh năng cá»™ng đồng wiki" #: conf/forum_data_rules.py:87 msgid "Allow asking questions anonymously" -msgstr "" +msgstr "Cho phép đặt câu há»i ẩn danh" #: conf/forum_data_rules.py:89 msgid "" @@ -7243,11 +7247,11 @@ msgstr "" #: templates/widgets/ask_form.html:22 templates/widgets/ask_form.html.py:24 msgid "Add details (optional)" -msgstr "" +msgstr "Thêm chi tiết (không bắt buá»™c)" #: templates/widgets/ask_form.html:26 msgid "Add details" -msgstr "" +msgstr "Thêm chi tiết" #: templates/widgets/ask_form.html:59 msgid "Select language" @@ -7390,44 +7394,44 @@ msgstr "" #: templates/widgets/markdown_help.html:6 msgid "*italic*" -msgstr "" +msgstr "*nghiêng*" #: templates/widgets/markdown_help.html:9 msgid "**bold**" -msgstr "" +msgstr "**Ä‘áºm**" #: templates/widgets/markdown_help.html:13 msgid "*italic* or _italic_" -msgstr "" +msgstr "*nghiêng* hoặc _nghiêng_" #: templates/widgets/markdown_help.html:16 msgid "**bold** or __bold__" -msgstr "" +msgstr "**Ä‘áºm** hoặc __Ä‘áºm_" #: templates/widgets/markdown_help.html:20 #: templates/widgets/markdown_help.html:24 msgid "text" -msgstr "" +msgstr "chữ" #: templates/widgets/markdown_help.html:24 msgid "image" -msgstr "" +msgstr "hình" #: templates/widgets/markdown_help.html:28 msgid "numbered list:" -msgstr "" +msgstr "danh sách (số)" #: templates/widgets/markdown_help.html:33 msgid "basic HTML tags are also supported" -msgstr "" +msgstr "các thẻ HTML cÆ¡ bản cÅ©ng được há»— trợ" #: templates/widgets/markdown_help.html:38 msgid "learn more about Markdown" -msgstr "" +msgstr "xem thêm vá» Markdown" #: templates/widgets/meta_nav.html:12 msgid "people & groups" -msgstr "" +msgstr "thà nh viên & nhóm" #: templates/widgets/meta_nav.html:20 msgid "users" @@ -7435,7 +7439,7 @@ msgstr "people" #: templates/widgets/meta_nav.html:27 msgid "badges" -msgstr "" +msgstr "danh hiệu" #: templates/widgets/question_edit_tips.html:5 msgid "ask a question interesting to this community" @@ -7444,41 +7448,41 @@ msgstr "" #: templates/widgets/question_summary.html:12 msgid "view" msgid_plural "views" -msgstr[0] "" +msgstr[0] "xem" #: templates/widgets/question_summary.html:30 msgid "answer" msgid_plural "answers" -msgstr[0] "" +msgstr[0] "trả lá»i" #: templates/widgets/question_summary.html:41 msgid "vote" msgid_plural "votes" -msgstr[0] "" +msgstr[0] "đánh giá" #: templates/widgets/scope_nav.html:17 msgid "ALL" -msgstr "" +msgstr "TẤT CẢ" #: templates/widgets/scope_nav.html:22 msgid "see unanswered questions" -msgstr "" +msgstr "xem câu há»i chÆ°a có trả lá»i" #: templates/widgets/scope_nav.html:22 msgid "UNANSWERED" -msgstr "" +msgstr "CHƯA TRẢ LỜI" #: templates/widgets/scope_nav.html:27 msgid "see your followed questions" -msgstr "" +msgstr "xem câu há»i Ä‘ang theo dõi" #: templates/widgets/scope_nav.html:27 msgid "FOLLOWED" -msgstr "" +msgstr "ÄANG THEO DÕI" #: templates/widgets/scope_nav.html:30 msgid "Please ask your question here" -msgstr "" +msgstr "Hãy đặt câu há»i của bạn tại đây" #: templates/widgets/tag_selector.html:4 msgid "Interesting tags" @@ -7494,15 +7498,15 @@ msgstr "" #: templates/widgets/tag_selector.html:59 msgid "Show only questions from" -msgstr "" +msgstr "Chỉ hiển thị câu há»i từ" #: templates/widgets/tag_selector.html:70 msgid "Send me email alerts for" -msgstr "" +msgstr "Gá»i email thông báo đên tôi khi" #: templates/widgets/tag_selector.html:86 msgid "Change frequency of emails" -msgstr "" +msgstr "Thay đổi tần suất gá»i email" #: templates/widgets/three_column_category_selector.html:4 msgid "" @@ -7527,15 +7531,15 @@ msgstr "" #: templates/widgets/user_long_score_and_badge_summary.html:10 msgid "karma:" -msgstr "" +msgstr "Ä‘iểm:" #: templates/widgets/user_long_score_and_badge_summary.html:15 msgid "badges:" -msgstr "" +msgstr "danh hiệu:" #: templates/widgets/user_navigation.html:17 msgid "sign out" -msgstr "" +msgstr "đăng xuất" #: templates/widgets/user_navigation.html:20 msgid "Hi there! Please sign in" @@ -7543,7 +7547,7 @@ msgstr "" #: templates/widgets/user_navigation.html:23 msgid "settings" -msgstr "" +msgstr "thiết láºp" #: templates/widgets/user_navigation.html:24 msgid "widgets" @@ -7552,7 +7556,7 @@ msgstr "" #: templates/widgets/user_perms.html:1 #, python-format msgid "Your karma is %(karma)s" -msgstr "" +msgstr "Số Ä‘iểm của bạn là %(karma)s" #: templates/widgets/user_perms.html:4 msgid "Karma reflects the value of your contribution to this community." diff --git a/askbot/locale/vi/LC_MESSAGES/djangojs.mo b/askbot/locale/vi/LC_MESSAGES/djangojs.mo Binary files differindex 8fd001ed..c79bd0a2 100644 --- a/askbot/locale/vi/LC_MESSAGES/djangojs.mo +++ b/askbot/locale/vi/LC_MESSAGES/djangojs.mo diff --git a/askbot/locale/vi/LC_MESSAGES/djangojs.po b/askbot/locale/vi/LC_MESSAGES/djangojs.po index d9c34724..2028781f 100644 --- a/askbot/locale/vi/LC_MESSAGES/djangojs.po +++ b/askbot/locale/vi/LC_MESSAGES/djangojs.po @@ -4,13 +4,16 @@ # # Translators: # linux <linux87s@gmail.com>, 2013 +# linux <linux87s@gmail.com>, 2013 +# Nguyen Long <gialacmail@gmail.com>, 2013 +# rgv151 <rgv151@gmail.com>, 2013 msgid "" msgstr "" "Project-Id-Version: askbot\n" "Report-Msgid-Bugs-To: http://askbot.org/\n" "POT-Creation-Date: 2013-07-13 14:07-0500\n" -"PO-Revision-Date: 2013-08-21 02:48+0000\n" -"Last-Translator: linux <linux87s@gmail.com>\n" +"PO-Revision-Date: 2013-09-19 03:25+0000\n" +"Last-Translator: evgeny <evgeny.fadeev@gmail.com>\n" "Language-Team: Vietnamese (http://www.transifex.com/projects/p/askbot/language/vi/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -21,295 +24,295 @@ msgstr "" #: media/jquery-openid/jquery.openid.js:73 #, c-format msgid "Are you sure you want to remove your %s login?" -msgstr "" +msgstr "Bạn muốn loại bá» phÆ°Æ¡ng thức đăng nháºp từ %s?" #: media/jquery-openid/jquery.openid.js:90 msgid "Please add one or more login methods." -msgstr "" +msgstr "Hãy thêm má»™t hoặc và i phÆ°Æ¡ng thức đăng nháºp khác." #: media/jquery-openid/jquery.openid.js:93 msgid "" "You don't have a method to log in right now, please add one or more by " "clicking any of the icons below." -msgstr "" +msgstr "Hiện tại bạn không có phÆ°Æ¡ng thức đăng nháºp nà o, hãy thêm bằng cách nhấn và o biểu tượng bất kì bên dÆ°á»›i." #: media/jquery-openid/jquery.openid.js:135 msgid "passwords do not match" -msgstr "" +msgstr "máºt khẩu không khá»›p" #: media/jquery-openid/jquery.openid.js:162 msgid "Show/change current login methods" -msgstr "" +msgstr "Hiển thị/thay đổi các phÆ°Æ¡ng thức đăng nháºp Ä‘ang sá» dụng" #: media/jquery-openid/jquery.openid.js:227 #, c-format msgid "Please enter your %s, then proceed" -msgstr "" +msgstr "Hãy nhâp %s của bạn và tiếp tục" #: media/jquery-openid/jquery.openid.js:229 msgid "Connect your %(provider_name)s account to %(site)s" -msgstr "" +msgstr "Kết nối vá»›i tải khoản %(provider_name)s của bạn tá»›i %(site)s" #: media/jquery-openid/jquery.openid.js:323 #, c-format msgid "Change your %s password" -msgstr "" +msgstr "Äổi máºt khẩu %s của bạn" #: media/jquery-openid/jquery.openid.js:324 msgid "Change password" -msgstr "" +msgstr "Äổi máºt khẩu" #: media/jquery-openid/jquery.openid.js:327 #, c-format msgid "Create a password for %s" -msgstr "" +msgstr "Tạo máºt khẩu má»›i cho %s" #: media/jquery-openid/jquery.openid.js:328 msgid "Create password" -msgstr "" +msgstr "Tạo máºt khẩu" #: media/jquery-openid/jquery.openid.js:344 msgid "Create a password-protected account" -msgstr "" +msgstr "Tạo tà i khoản má»›i" #: media/js/group_messaging.js:102 media/js/group_messaging.js.c:293 msgid "required" -msgstr "" +msgstr "bắt buá»™c" #: media/js/group_messaging.js:139 msgid "Your message:" -msgstr "" +msgstr "Thông Ä‘iệp của bạn:" #: media/js/group_messaging.js:152 msgid "send" -msgstr "" +msgstr "gá»i" #: media/js/group_messaging.js:164 media/js/post.js:1809 #: media/js/post.js.c:3081 media/js/post.js.c:4598 media/js/user.js:888 msgid "cancel" -msgstr "" +msgstr "hủy" #: media/js/group_messaging.js:227 msgid "Reply" -msgstr "" +msgstr "Trả lá»i" #: media/js/group_messaging.js:236 media/js/group_messaging.js.c:743 msgid "message sent" -msgstr "" +msgstr "đã gá»i" #: media/js/group_messaging.js:271 msgid "user {{str}} does not exist" msgid_plural "users {{str}} do not exist" -msgstr[0] "" +msgstr[0] "thà nh viên {{str}} không tồn tại" #: media/js/group_messaging.js:278 msgid "cannot send message to yourself" -msgstr "" +msgstr "không thể gá»i tin nhắn đến chÃnh bạn" #: media/js/group_messaging.js:323 msgid "Recipient:" -msgstr "" +msgstr "NgÆ°á»i nháºn:" #: media/js/live_search.js:196 msgid "To see search results, 2 or more characters may be required" -msgstr "" +msgstr "Äể có kết quả tìm kiếm, vui lòng sá» dụng từ khóa dà i hÆ¡n" #: media/js/live_search.js:218 msgid "Ask Your Question" -msgstr "" +msgstr "Äặt câu há»i" #: media/js/live_search.js:299 msgid "Sorry, this tag does not exist" msgid_plural "Sorry, these tags do not exist" -msgstr[0] "" +msgstr[0] "Xin lá»—i, những thẻ nà y không tồn tại" #: media/js/live_search.js:313 msgid "search or ask your question" -msgstr "" +msgstr "tìm hoặc đặt câu há»i" #: media/js/post.js:28 msgid "loading..." -msgstr "" +msgstr "Ä‘ang tải..." #: media/js/post.js:100 msgid "must be shorter than %(max_chars)s character" msgid_plural "must be shorter than %(max_chars)s characters" -msgstr[0] "" +msgstr[0] "cần phải ngắn hÆ¡n %(max_chars)s kà tá»±" #: media/js/post.js:154 media/js/post.js.c:1269 msgid "tags cannot be empty" -msgstr "" +msgstr "không thể dùng thẻ rá»—ng" #: media/js/post.js:160 msgid "details are required" -msgstr "" +msgstr "thông tin chi tiết là bắt buá»™c" #: media/js/post.js:163 #, c-format msgid "details must have > %s character" msgid_plural "details must have > %s characters" -msgstr[0] "" +msgstr[0] " chi tiết cần dà i hÆ¡n %s kà tá»±" #: media/js/post.js:171 msgid "enter your question" -msgstr "" +msgstr "nháºp câu há»i của bạn" #: media/js/post.js:174 #, c-format msgid "question must have > %s character" msgid_plural "question must have > %s characters" -msgstr[0] "" +msgstr[0] "câu há»i cần dà i hÆ¡n %s kà tá»±" #: media/js/post.js:193 msgid "content cannot be empty" -msgstr "" +msgstr "ná»™i dung không thể rá»—ng" #: media/js/post.js:196 #, c-format msgid "answer must be > %s character" msgid_plural "answer must be > %s characters" -msgstr[0] "" +msgstr[0] "câu trả lá»i cần phải dà i hÆ¡n %s kà tá»±" #: media/js/post.js:253 msgid "Back to the question" -msgstr "" +msgstr "Trở vá» câu há»i" #: media/js/post.js:303 msgid "draft saved..." -msgstr "" +msgstr "đã lÆ°u bản nháp..." #: media/js/post.js:548 msgid "insufficient privilege" -msgstr "" +msgstr "không đủ quyá»n" #: media/js/post.js:549 msgid "cannot pick own answer as best" -msgstr "" +msgstr "bạn không thể đánh giá cho câu trả lá»i của chÃnh mình" #: media/js/post.js:552 media/js/post.js.c:1416 msgid "please login" -msgstr "" +msgstr "vui lòng đăng nháºp" #: media/js/post.js:554 msgid "anonymous users cannot follow questions" -msgstr "" +msgstr "hãy đăng nháºp để theo dõi câu há»i nà y" #: media/js/post.js:555 msgid "anonymous users cannot subscribe to questions" -msgstr "" +msgstr "hãy đăng nháºp để đăng ký theo dõi câu há»i nà y" #: media/js/post.js:556 media/js/post.js.c:1426 msgid "anonymous users cannot vote" -msgstr "" +msgstr "hãy đăng nháºp để đánh giá" #: media/js/post.js:558 msgid "please confirm offensive" -msgstr "" +msgstr "vui lòng xác nháºn thông báo vi phạm" #: media/js/post.js:559 msgid "please confirm removal of offensive flag" -msgstr "" +msgstr "vui long xác nháºn gỡ bá» thông báo vi phạm" #: media/js/post.js:560 msgid "anonymous users cannot flag offensive posts" -msgstr "" +msgstr "ngÆ°á»i dùng nặc danh không thể thông báo vi phạm" #: media/js/post.js:561 msgid "confirm delete" -msgstr "" +msgstr "xác nháºn xóa" #: media/js/post.js:562 msgid "anonymous users cannot delete/undelete" -msgstr "" +msgstr "ngÆ°á»i sá» dụng ẩn danh không thể xóa/phục hồi" #: media/js/post.js:563 msgid "post recovered" -msgstr "" +msgstr "bà i viết đã được khôi phục" #: media/js/post.js:564 msgid "post deleted" -msgstr "" +msgstr "đã xóa bà i viết" #: media/js/post.js:831 msgid "Follow" -msgstr "" +msgstr "Theo sau" #: media/js/post.js:840 media/js/post.js.c:849 #, c-format msgid "%s follower" msgid_plural "%s followers" -msgstr[0] "" +msgstr[0] "%s ngÆ°á»i theo" #: media/js/post.js:845 msgid "<div>Following</div><div class=\"unfollow\">Unfollow</div>" -msgstr "" +msgstr "<div>Äang theo</div><div class=\"unfollow\">Ngừng theo</div>" #: media/js/post.js:901 msgid "remove flag" -msgstr "" +msgstr "loại bá» cá»" #: media/js/post.js:935 media/js/post.js.c:964 msgid "flag offensive" -msgstr "" +msgstr "thông báo vi phạm" #: media/js/post.js:990 media/js/post.js.c:1497 msgid "undelete" -msgstr "" +msgstr "Khôi phục" #: media/js/post.js:995 media/js/post.js.c:1501 msgid "delete" -msgstr "" +msgstr "xóa" #: media/js/post.js:1218 media/js/post.js.c:1445 msgid "sorry, something is not right here" -msgstr "" +msgstr "xin lá»—i, má»™t cái gì đó không đúng ở đây" #: media/js/post.js:1665 msgid "add comment" -msgstr "" +msgstr "Thêm ý kiến" #: media/js/post.js:1671 msgid "save comment" -msgstr "" +msgstr "lÆ°u ý kiến" #: media/js/post.js:1711 #, c-format msgid "enter at least %s characters" -msgstr "" +msgstr "nháºp Ãt nhất %s ký tá»±" #: media/js/post.js:1713 #, c-format msgid "enter at least %s more characters" -msgstr "" +msgstr "nháºp thêm Ãt nhất %s kà tá»± nữa" #: media/js/post.js:1723 #, c-format msgid "%s characters left" -msgstr "" +msgstr "còn lại %s ký tá»±" #: media/js/post.js:1823 msgid "minor edit (don't send alerts)" -msgstr "" +msgstr "sá»a đổi nhá» (không gá»i thông báo)" #: media/js/post.js:1855 msgid "Are you sure you don't want to post this comment?" -msgstr "" +msgstr "Bạn có chắc là bạn không muốn gá»i bình luáºn nà y?" #: media/js/post.js:1890 media/js/utils.js:3360 media/js/utils.js.c:3515 msgid "just now" -msgstr "" +msgstr "chỉ bây giá»" #: media/js/post.js:1956 msgid "delete this comment" -msgstr "" +msgstr "xóa ý kiến nà y" #: media/js/post.js:2271 msgid "confirm delete comment" -msgstr "" +msgstr "xác nháºn xóa ye kiến nà y" #: media/js/post.js:2409 msgid "please sign in or register to post comments" -msgstr "" +msgstr "vui lòng đăng nháºp hoặc đăng ký để gá»i ý kiến" #: media/js/post.js:2560 msgid "Please enter question title (>10 characters)" @@ -317,82 +320,82 @@ msgstr "Là m Æ¡n nháºp tiêu Ä‘á» của câu há»i (>10 ký tá»±)" #: media/js/post.js:2612 media/js/post.js.c:4626 msgid "Sorry, you have only read access" -msgstr "" +msgstr "Xin lá»—i, bạn chỉ có quyá»n xem bà i" #: media/js/post.js:3075 media/js/post.js.c:3869 media/js/post.js.c:4058 msgid "save" -msgstr "" +msgstr "LÆ°u" #: media/js/post.js:3199 msgid "Enter the logo url or upload an image" -msgstr "" +msgstr "Nháºp địa chỉ logo hoặc tải lên má»™t hình ảnh" #: media/js/post.js:3225 msgid "Do you really want to remove the image?" -msgstr "" +msgstr "Bạn có thá»±c sá»± muốn xóa hình nà y?" #: media/js/post.js:3341 msgid "change logo" -msgstr "" +msgstr "đổi logo" #: media/js/post.js:3342 msgid "add logo" -msgstr "" +msgstr "thêm logo" #: media/js/post.js:3444 #, c-format msgid "tag \"%s\" was already added, no need to repeat (press \"escape\" to delete)" -msgstr "" +msgstr "thẻ \"%s\" đã có, không cần phải thêm và o (nhấn phÃm \"escape\" để xóa)" #: media/js/post.js:3453 #, c-format msgid "a maximum of %s tag is allowed" msgid_plural "a maximum of %s tags are allowed" -msgstr[0] "" +msgstr[0] "tối Ä‘a %s thẻ có thể sá» dụng" #: media/js/post.js:3799 msgid "Delete category?" -msgstr "" +msgstr "Xóa danh mục?" #: media/js/post.js:3888 media/js/utils.js:881 msgid "edit" -msgstr "" +msgstr "sá»a" #: media/js/post.js:3975 msgid "category name cannot be empty" -msgstr "" +msgstr "tên danh mục không thể để trống" #: media/js/post.js:4011 msgid "already exists at the current level!" -msgstr "" +msgstr "đã tồn tại ở cấp Ä‘á»™ hiện tại!" #: media/js/post.js:4047 msgid "add category" -msgstr "" +msgstr "thêm thể loại" #: media/js/post.js:4594 msgid "save tags" -msgstr "" +msgstr "lÆ°u thẻ đánh dấu" #: media/js/post.js:4689 media/js/post.js.c:4723 msgid "User name:" -msgstr "" +msgstr "Tên đăng nháºp:" #: media/js/post.js:4710 msgid "Group name:" -msgstr "" +msgstr "Tên nhóm:" #: media/js/post.js:4736 msgid "Shared with the following users:" -msgstr "" +msgstr "Chia sẻ vá»›i ngÆ°á»i dùng sau đây:" #: media/js/post.js:4742 msgid "Shared with the following groups:" -msgstr "" +msgstr "Chia sẻ vá»›i các nhóm sau:" #: media/js/tag_selector.js:14 msgid "Tag \"<span></span>\" matches:" -msgstr "" +msgstr "Thẻ đánh dấu \"<span></span>\" phù hợp:" #: media/js/tag_selector.js:84 #, c-format @@ -401,381 +404,381 @@ msgstr "và %s nhiá»u hÆ¡n, không được hiển thị..." #: media/js/user.js:15 msgid "Please select at least one item" -msgstr "" +msgstr "Vui lòng chá»n Ãt nhất má»™t mục" #: media/js/user.js:59 msgid "Delete this notification?" msgid_plural "Delete these notifications?" -msgstr[0] "" +msgstr[0] "Xóa các thông báo nà y?" #: media/js/user.js:66 msgid "Close this entry?" msgid_plural "Close these entries?" -msgstr[0] "" +msgstr[0] "Äóng các mục?" #: media/js/user.js:74 msgid "Remove all flags and approve this entry?" msgid_plural "Remove all flags and approve these entries?" -msgstr[0] "" +msgstr[0] "Loại bá» tất cả các cá» và phê duyệt những mục nà y?" #: media/js/user.js:223 msgid "Post deleted" -msgstr "" +msgstr "đã xóa bà i viết" #: media/js/user.js:225 msgid "Post approved" -msgstr "" +msgstr "đã chấp thuáºn" #: media/js/user.js:246 msgid "Accept" -msgstr "" +msgstr "Chấp nháºn" #: media/js/user.js:255 msgid "Reject" -msgstr "" +msgstr "Từ chối" #: media/js/user.js:270 msgid "add new reject reason" -msgstr "" +msgstr "thêm lý do từ chối" #: media/js/user.js:375 msgid "Looks there are some things to fix:" -msgstr "" +msgstr "Có vẻ có má»™t số Ä‘iá»u phải sá»a chữa:" #: media/js/user.js:443 msgid "Please provide description." -msgstr "" +msgstr "Vui lòng cung cấp mô tả." #: media/js/user.js:446 msgid "Please provide details." -msgstr "" +msgstr "Vui lòng cung cấp chi tiết." #: media/js/user.js:560 msgid "A reason must be selected to delete one." -msgstr "" +msgstr "Phải chá»n má»™t lý do để xóa 1." #: media/js/user.js:659 msgid "A reason must be selected to reject post." -msgstr "" +msgstr "Phải chá»n má»™t lý do để từ chối bà i viết" #: media/js/user.js:708 msgid "Please <a href=\"%(signin_url)s\">signin</a> to follow %(username)s" -msgstr "" +msgstr "Hãy <a href=\"%(signin_url)s\">tạo tà i khoản</a> để theo dõi %(username)s" #: media/js/user.js:740 #, c-format msgid "unfollow %s" -msgstr "" +msgstr "ngừng theo dõi %s" #: media/js/user.js:743 #, c-format msgid "following %s" -msgstr "" +msgstr "Ä‘ang theo dõi %s" #: media/js/user.js:749 #, c-format msgid "follow %s" -msgstr "" +msgstr "theo dõi %s" #: media/js/user.js:883 msgid "add group" -msgstr "" +msgstr "thêm nhóm" #: media/js/user.js:963 msgid "add" -msgstr "" +msgstr "thêm" #: media/js/utils.js:99 msgid "and" -msgstr "" +msgstr "và " #: media/js/utils.js:117 msgid "click to close" -msgstr "" +msgstr "đóng" #: media/js/utils.js:880 msgid "click to edit this comment" -msgstr "" +msgstr "sá»a ý kiến nà y" #: media/js/utils.js:905 msgid "convert to answer" -msgstr "" +msgstr "chuyển thà nh câu trả lá»i" #: media/js/utils.js:958 msgid "Ok" -msgstr "" +msgstr "Äồng ý" #: media/js/utils.js:959 media/js/utils.js.c:1407 msgid "Cancel" -msgstr "" +msgstr "hủy" #: media/js/utils.js:1219 #, c-format msgid "Uploaded file: %s" -msgstr "" +msgstr "Äã tải lên táºp tin: %s" #: media/js/utils.js:1234 msgid "Choose a different image" -msgstr "" +msgstr "Chá»n má»™t hình ảnh khác " #: media/js/utils.js:1236 msgid "Choose a different file" -msgstr "" +msgstr "Chá»n má»™t táºp tin khác" #: media/js/utils.js:1250 msgid "Oops, looks like we had an error. Sorry." -msgstr "" +msgstr "Rất tiếc, có vẻ nhÆ° chúng tôi đã có má»™t lá»—i. Xin lôi." #: media/js/utils.js:1311 msgid "Choose an image to insert" -msgstr "" +msgstr "Chá»n hình để chèn và o" #: media/js/utils.js:1313 msgid "Choose a file to insert" -msgstr "" +msgstr "Chá»n táºp tin để chèn và o" #: media/js/utils.js:1326 msgid "Allowed file types are:" -msgstr "" +msgstr "Các loại táºp tin cho phép là :" #: media/js/utils.js:1332 #: media/js/tinymce/plugins/askbot_attachment/editor_plugin.js:35 msgid "Or paste file url here" -msgstr "" +msgstr "Hoặc dán url táºp tin ở đây" #: media/js/utils.js:1406 msgid "Save" -msgstr "" +msgstr "LÆ°u" #: media/js/utils.js:1478 msgid "saved" -msgstr "" +msgstr "Äã lÆ°u" #: media/js/utils.js:1602 msgid "enabled" -msgstr "" +msgstr "đã báºt" #: media/js/utils.js:1604 msgid "disabled" -msgstr "" +msgstr "bị vô hiệu hóa" #: media/js/utils.js:2038 msgid "group name" -msgstr "" +msgstr "tên nhóm" #: media/js/utils.js:2046 msgid "add new group" -msgstr "" +msgstr "thêm nhóm má»›i" #: media/js/utils.js:2138 msgid "Group %(name)s already exists. Group names are case-insensitive." -msgstr "" +msgstr "Nhóm %(name)s đã tồn tại. Tên nhóm có phân biệt dạng chữ" #: media/js/utils.js:2311 #, c-format msgid "see questions tagged '%s'" -msgstr "" +msgstr "xem các câu há»i được gắn thẻ '%s'" #: media/js/utils.js:3358 msgid "ago" -msgstr "" +msgstr "trÆ°á»›c" #: media/js/utils.js:3359 msgid "from now" -msgstr "" +msgstr "từ bây giá»" #: media/js/utils.js:3361 msgid "about a minute" -msgstr "" +msgstr "khoảng má»™t phút" #: media/js/utils.js:3362 #, c-format msgid "%d minutes" -msgstr "" +msgstr "%d phút" #: media/js/utils.js:3363 msgid "about an hour" -msgstr "" +msgstr "Khoảng 1 giá»" #: media/js/utils.js:3364 #, c-format msgid "%d hours" -msgstr "" +msgstr "%d giá»" #: media/js/utils.js:3365 media/js/utils.js.c:3493 msgid "yesterday" -msgstr "" +msgstr "ngà y hôm qua" #: media/js/utils.js:3366 #, c-format msgid "%d days" -msgstr "" +msgstr "%d ngà y" #: media/js/utils.js:3367 msgid "about a month" -msgstr "" +msgstr "khoảng má»™t tháng" #: media/js/utils.js:3368 #, c-format msgid "%d months" -msgstr "" +msgstr "%d tháng" #: media/js/utils.js:3369 msgid "about a year" -msgstr "" +msgstr "khoảng má»™t năm" #: media/js/utils.js:3370 #, c-format msgid "%d years" -msgstr "" +msgstr "%d năm" #: media/js/utils.js:3468 msgid "Jan" -msgstr "" +msgstr "tháng giêng" #: media/js/utils.js:3469 msgid "Feb" -msgstr "" +msgstr "tháng 2" #: media/js/utils.js:3470 msgid "Mar" -msgstr "" +msgstr "tháng 3" #: media/js/utils.js:3471 msgid "Apr" -msgstr "" +msgstr "tháng 4" #: media/js/utils.js:3472 msgid "May" -msgstr "" +msgstr "tháng 5" #: media/js/utils.js:3473 msgid "Jun" -msgstr "" +msgstr "tháng 6" #: media/js/utils.js:3474 msgid "Jul" -msgstr "" +msgstr "tháng 7" #: media/js/utils.js:3475 msgid "Aug" -msgstr "" +msgstr "tháng 8" #: media/js/utils.js:3476 msgid "Sep" -msgstr "" +msgstr "tháng 9" #: media/js/utils.js:3477 msgid "Oct" -msgstr "" +msgstr "tháng 10" #: media/js/utils.js:3478 msgid "Nov" -msgstr "" +msgstr "tháng 11" #: media/js/utils.js:3479 msgid "Dec" -msgstr "" +msgstr "tháng 12" #: media/js/utils.js:3491 msgid "2 days ago" -msgstr "" +msgstr "2 ngà y trÆ°á»›c" #: media/js/utils.js:3498 #, c-format msgid "%s hour ago" msgid_plural "%s hours ago" -msgstr[0] "" +msgstr[0] "%s giá» trÆ°á»›c" #: media/js/utils.js:3508 #, c-format msgid "%s min ago" msgid_plural "%s mins ago" -msgstr[0] "" +msgstr[0] "%s phút trÆ°á»›c" #: media/js/tinymce/plugins/askbot_attachment/editor_plugin.js:71 msgid "Insert a file" -msgstr "" +msgstr "chèn 1 táºp tin" #: media/js/tinymce/plugins/askbot_imageuploader/editor_plugin.js:70 msgid "Insert image" -msgstr "" +msgstr "chèn hình" #: media/js/wmd/wmd.js:31 msgid "bold" -msgstr "" +msgstr "Ä‘áºm" #: media/js/wmd/wmd.js:32 msgid "italic" -msgstr "" +msgstr "nghiêng" #: media/js/wmd/wmd.js:33 msgid "link" -msgstr "" +msgstr "liên hết" #: media/js/wmd/wmd.js:34 msgid "quote" -msgstr "" +msgstr "trÃch dẫn" #: media/js/wmd/wmd.js:35 msgid "preformatted text" -msgstr "" +msgstr "ná»™i dung đã được định dạng" #: media/js/wmd/wmd.js:36 msgid "image" -msgstr "" +msgstr "hình" #: media/js/wmd/wmd.js:37 msgid "attachment" -msgstr "" +msgstr "Ä‘Ãnh kèm" #: media/js/wmd/wmd.js:38 msgid "numbered list" -msgstr "" +msgstr "danh sách số" #: media/js/wmd/wmd.js:39 msgid "bulleted list" -msgstr "" +msgstr "danh sách liệt kê" #: media/js/wmd/wmd.js:40 msgid "heading" -msgstr "" +msgstr "tiêu Ä‘á»" #: media/js/wmd/wmd.js:41 msgid "horizontal bar" -msgstr "" +msgstr "thanh ngang" #: media/js/wmd/wmd.js:42 msgid "undo" -msgstr "" +msgstr "lùi lại" #: media/js/wmd/wmd.js:43 media/js/wmd/wmd.js.c:1169 msgid "redo" -msgstr "" +msgstr "là m lại" #: media/js/wmd/wmd.js:54 msgid "enter image url" -msgstr "" +msgstr "nháºp url hình" #: media/js/wmd/wmd.js:55 msgid "enter url" -msgstr "" +msgstr "nháºp url" #: media/js/wmd/wmd.js:56 msgid "upload file attachment" -msgstr "" +msgstr "tải lên 1 táºp tin Ä‘Ãnh kèm" #: media/js/wmd/wmd.js:1836 msgid "image description" -msgstr "" +msgstr "mô tả hình ảnh" #: media/js/wmd/wmd.js:1839 msgid "file name" -msgstr "" +msgstr "tên táºp tin " #: media/js/wmd/wmd.js:1843 msgid "link text" -msgstr "" +msgstr "liên kết văn bản" #~ msgid "post a comment" #~ msgstr "save comment" diff --git a/askbot/locale/zh_CN/LC_MESSAGES/django.mo b/askbot/locale/zh_CN/LC_MESSAGES/django.mo Binary files differindex 1a4d973b..8d468276 100644 --- a/askbot/locale/zh_CN/LC_MESSAGES/django.mo +++ b/askbot/locale/zh_CN/LC_MESSAGES/django.mo diff --git a/askbot/locale/zh_CN/LC_MESSAGES/django.po b/askbot/locale/zh_CN/LC_MESSAGES/django.po index 2805dce5..8ed703d0 100644 --- a/askbot/locale/zh_CN/LC_MESSAGES/django.po +++ b/askbot/locale/zh_CN/LC_MESSAGES/django.po @@ -16,8 +16,8 @@ msgstr "" "Project-Id-Version: askbot\n" "Report-Msgid-Bugs-To: http://askbot.org/\n" "POT-Creation-Date: 2013-07-13 14:06-0500\n" -"PO-Revision-Date: 2013-08-16 03:20+0000\n" -"Last-Translator: ianwu <ian.wu@163.com>\n" +"PO-Revision-Date: 2013-08-27 23:19+0000\n" +"Last-Translator: daisy.ycguo <daisy.ycguo@gmail.com>\n" "Language-Team: Chinese (China) (http://www.transifex.com/projects/p/askbot/language/zh_CN/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -104,7 +104,7 @@ msgstr[0] "æ ‡ç¾æœ€å¤šåªèƒ½æœ‰%(max_chars)d个å—符" msgid "" "We ran out of space for recording the tags. Please shorten or delete some of" " them." -msgstr "" +msgstr "å·²ç»æ²¡æœ‰ç©ºé—´å˜å‚¨æ ‡è®°ã€‚请缩çŸæˆ–è€…åˆ é™¤éƒ¨åˆ†æ ‡è®°ã€‚" #: forms.py:410 forms.py:1006 models/widgets.py:27 #: templates/widgets/edit_post.html:32 templates/widgets/meta_nav.html:6 @@ -150,7 +150,7 @@ msgstr "更新概è¦ï¼š" msgid "" "enter a brief summary of your revision (e.g. fixed spelling, grammar, " "improved style, this field is optional)" -msgstr "输入本次修改的简å•æ¦‚述(如:修改了别å—,修æ£äº†è¯æ³•ï¼Œæ”¹è¿›äº†æ ·å¼ç‰ã€‚éžå¿…填项。)" +msgstr "输入本次修改的简å•æ¦‚è¿°(如:修改了错别å—,修æ£äº†è¯æ³•ï¼Œæ”¹è¿›äº†æ ·å¼ç‰ã€‚éžå¿…填项。)" #: forms.py:585 msgid "Enter number of points to add or subtract" @@ -241,7 +241,7 @@ msgstr "è¯·æ ‡è®°â€œæˆ‘ä¸æƒ³ç»™å‡ºé‚®ç®±åœ°å€â€å—段。" #: forms.py:791 msgid "keep private within your groups" -msgstr "" +msgstr "åªæœ‰ä½ 的组æˆå‘˜å¯ä»¥è®¿é—®" #: forms.py:830 msgid "User name:" @@ -275,7 +275,7 @@ msgstr "若您ä¸æƒ³åœ¨æé—®æ¤é—®é¢˜æ—¶å…¬å¸ƒè‡ªå·±çš„åå—,请选ä¸æœ¬é¡¹ msgid "" "Subject line is expected in the format: [tag1, tag2, tag3,...] question " "title" -msgstr "" +msgstr "æ ‡é¢˜è¡Œè¦æ»¡è¶³å¦‚ä¸‹æ ¼å¼ï¼š[tag1, tag2, tag2, ...] é—®é¢˜æ ‡é¢˜" #: forms.py:1213 msgid "" @@ -390,7 +390,7 @@ msgstr "æè¿°" #: templates/widgets/edit_post.html:26 templates/widgets/related_tags.html:3 #: templates/widgets/tag_category_selector.html:2 msgid "Tags" -msgstr "ä¸ªæ ‡ç¾" +msgstr "æ ‡ç¾" #: tasks.py:98 msgid "An edit for my answer" @@ -598,55 +598,55 @@ msgstr "设置" #: conf/badges.py:23 msgid "Disciplined: minimum upvotes for deleted post" -msgstr "å—ç½šï¼šè¾¾åˆ°åˆ é™¤å¸–å的最低åŒæ„票数" +msgstr "è‡ªå¾‹ï¼šåˆ é™¤å¸–å的最低赞æˆç¥¨æ•°" #: conf/badges.py:32 msgid "Peer Pressure: minimum downvotes for deleted post" -msgstr "ç”¨æˆ·åŽ‹åŠ›ï¼šè¾¾åˆ°åˆ é™¤å¸–å的最低å¦å†³ç¥¨æ•°" +msgstr "ä»–å¾‹ï¼šåˆ é™¤å¸–å的最低å对票数" #: conf/badges.py:41 msgid "Teacher: minimum upvotes for the answer" -msgstr "è€å¸ˆ:ç”案的最å°æŽ¨è票数" +msgstr "è€å¸ˆ:ç”案的最å°èµžæˆç¥¨æ•°" #: conf/badges.py:50 msgid "Nice Answer: minimum upvotes for the answer" -msgstr "好ç”案:ç”案的最å°æŽ¨è票数" +msgstr "好ç”案:ç”案的最å°èµžæˆç¥¨æ•°" #: conf/badges.py:59 msgid "Good Answer: minimum upvotes for the answer" -msgstr "良好的ç”案:ç”案的最å°æŽ¨è票数" +msgstr "优秀ç”案:ç”案的最å°èµžæˆç¥¨æ•°" #: conf/badges.py:68 msgid "Great Answer: minimum upvotes for the answer" -msgstr "æžå¥½çš„ç”案:ç”案的最å°æŽ¨è票数" +msgstr "完美ç”案:ç”案的最å°èµžæˆç¥¨æ•°" #: conf/badges.py:77 msgid "Nice Question: minimum upvotes for the question" -msgstr "好问题:问题的最å°æŽ¨è票数" +msgstr "好问题:问题的最å°èµžæˆç¥¨æ•°" #: conf/badges.py:86 msgid "Good Question: minimum upvotes for the question" -msgstr "良好的问题:问题的最å°æŽ¨è票数" +msgstr "优秀问题:问题的最å°èµžæˆç¥¨æ•°" #: conf/badges.py:95 msgid "Great Question: minimum upvotes for the question" -msgstr "优秀的问题:问题的最å°æŽ¨è票数" +msgstr "完美问题:问题的最å°èµžæˆç¥¨æ•°" #: conf/badges.py:104 msgid "Popular Question: minimum views" -msgstr "å—欢迎问题:最å°æµè§ˆæ¬¡æ•°" +msgstr "å—欢迎的问题:最å°æµè§ˆæ¬¡æ•°" #: conf/badges.py:113 msgid "Notable Question: minimum views" -msgstr "关注的问题:最å°æµè§ˆæ¬¡æ•°" +msgstr "çƒé—¨çš„问题:最å°æµè§ˆæ¬¡æ•°" #: conf/badges.py:122 msgid "Famous Question: minimum views" -msgstr "æžå¥½çš„问题:最å°æµè§ˆæ¬¡æ•°" +msgstr "è‘—å的问题:最å°æµè§ˆæ¬¡æ•°" #: conf/badges.py:131 msgid "Self-Learner: minimum answer upvotes" -msgstr "自å¦è€…:ç”案最少推è票数" +msgstr "自å¦è€…:ç”案最少赞æˆç¥¨æ•°" #: conf/badges.py:140 msgid "Civic Duty: minimum votes" @@ -654,35 +654,35 @@ msgstr "居民义务:最少投票数" #: conf/badges.py:149 msgid "Enlightened Duty: minimum upvotes" -msgstr "优良义务:最低åŒæ„票数" +msgstr "å¯å‘责任:最低赞æˆç¥¨æ•°" #: conf/badges.py:158 msgid "Guru: minimum upvotes" -msgstr "专家:最少推è票数" +msgstr "专家:最少赞æˆç¥¨æ•°" #: conf/badges.py:167 msgid "Necromancer: minimum upvotes" -msgstr "亡çµï¼šæœ€ä½ŽåŒæ„票数" +msgstr "å¤å…´çš„问题:最低赞æˆç¥¨æ•°" #: conf/badges.py:176 msgid "Necromancer: minimum delay in days" -msgstr "亡çµï¼šæœ€ä½Žå»¶è¿Ÿå¤©æ•°" +msgstr "å¤å…´çš„问题:最低延迟天数" #: conf/badges.py:185 msgid "Associate Editor: minimum number of edits" -msgstr "è”åˆç¼–辑:最å°ç¼–辑数" +msgstr "主编:最å°ç¼–辑数" #: conf/badges.py:194 msgid "Favorite Question: minimum stars" -msgstr "收è—问题:最少星数" +msgstr "收è—问题:最少关注数" #: conf/badges.py:203 msgid "Stellar Question: minimum stars" -msgstr "é‡è¦é—®é¢˜:最少星数" +msgstr "é‡è¦é—®é¢˜:最少关注数" #: conf/badges.py:212 msgid "Commentator: minimum comments" -msgstr "评论家:最低评论数" +msgstr "评论员:最低评论数" #: conf/badges.py:221 msgid "Taxonomist: minimum tag use count" @@ -858,11 +858,11 @@ msgstr "This setting applies to tags written in the subject line of questions as #: conf/email.py:288 msgid "Enable posting answers and comments by email" -msgstr "" +msgstr "å…许通过电å邮件å‘布ç”案和评论" #: conf/email.py:291 msgid "To enable this feature make sure lamson is running" -msgstr "" +msgstr "为了å¯ç”¨è¿™é¡¹åŠŸèƒ½ï¼Œè¯·ç¡®ä¿lamsonæ£åœ¨è¿è¡Œ" #: conf/email.py:302 msgid "Emailed post: when to notify author about publishing" @@ -870,13 +870,13 @@ msgstr "" #: conf/email.py:327 msgid "Reply by email hostname" -msgstr "" +msgstr "通过电å邮件的主机å回å¤ã€‚" #: conf/email.py:338 msgid "" "Email replies having fewer words than this number will be posted as comments" " instead of answers" -msgstr "" +msgstr "如果电å邮件的回å¤å—数少于该数å—,将会被å‘布为注释,而ä¸æ˜¯ç”案。" #: conf/external_keys.py:11 msgid "Keys for external services" @@ -1057,12 +1057,12 @@ msgstr "" #: conf/forum_data_rules.py:66 msgid "Enable embedding videos. " -msgstr "" +msgstr "å¯ç”¨è¿å…¥è§†é¢‘" #: conf/forum_data_rules.py:68 #, python-format msgid "<em>Note: please read <a href=\"%(url)s\">read this</a> first.</em>" -msgstr "" +msgstr "<em>注æ„: 请先阅读 <a href=\"%(url)s\">读这里</a> </em>" #: conf/forum_data_rules.py:78 msgid "Check to enable community wiki feature" @@ -1353,7 +1353,7 @@ msgstr "" #: conf/ldap.py:9 msgid "LDAP login configuration" -msgstr "" +msgstr "LDAP登录é…ç½®" #: conf/ldap.py:17 msgid "Use LDAP authentication for the password login" @@ -1475,7 +1475,7 @@ msgstr "姓" #: conf/ldap.py:178 msgid "LDAP Server EMAIL field name" -msgstr "" +msgstr "LDAPæœåŠ¡å™¨EMAILçš„å—段åå—" #: conf/ldap.py:180 msgid "This field is required" @@ -1502,7 +1502,7 @@ msgstr "" #: conf/license.py:13 msgid "Content License" -msgstr "" +msgstr "内容版æƒ" #: conf/license.py:21 msgid "Show license clause in the site footer" @@ -1695,15 +1695,15 @@ msgstr "接å—ç”案" #: conf/minimum_reputation.py:67 msgid "Flag offensive" -msgstr "垃圾帖" +msgstr "æ ‡è®°åžƒåœ¾å¸–" #: conf/minimum_reputation.py:88 msgid "Delete comments posted by others" -msgstr "åˆ é™¤å…¶ä»–äººçš„ç•™è¨€" +msgstr "åˆ é™¤å…¶ä»–äººçš„è¯„è®º" #: conf/minimum_reputation.py:97 msgid "Delete questions and answers posted by others" -msgstr "åˆ é™¤ä»»ä½•ä¸€ä¸ªé—®é¢˜æˆ–ç”案,åŠå…¶ä»–管ç†åŠŸèƒ½" +msgstr "åˆ é™¤å…¶ä»–äººçš„é—®é¢˜æˆ–ç”案" #: conf/minimum_reputation.py:106 msgid "Upload files" @@ -1729,23 +1729,23 @@ msgstr "å…³é—自己的问题" #: conf/minimum_reputation.py:146 msgid "Retag questions posted by other people" -msgstr "为其他人å‘布的问题é‡æ–°è®¾ç½®æ ‡ç¾" +msgstr "为其他人的问题é‡æ–°è®¾ç½®æ ‡ç¾" #: conf/minimum_reputation.py:155 msgid "Reopen own questions" -msgstr "é‡è®¾é—®é¢˜" +msgstr "é‡æ–°æ‰“开自己的问题" #: conf/minimum_reputation.py:164 msgid "Edit community wiki posts" -msgstr "编辑wiki类问题" +msgstr "ç¼–è¾‘ç¤¾åŒºç»´åŸºæ–‡ç« " #: conf/minimum_reputation.py:173 msgid "Edit posts authored by other people" -msgstr "编辑其他人的å‘布æƒé™" +msgstr "编辑其他人的帖å" #: conf/minimum_reputation.py:182 msgid "View offensive flags" -msgstr "æŸ¥çœ‹æ ‡è®°åžƒåœ¾å¸–" +msgstr "æŸ¥çœ‹åžƒåœ¾å¸–çš„æ ‡è®°" #: conf/minimum_reputation.py:191 msgid "Close questions asked by others" @@ -1818,7 +1818,7 @@ msgstr "" #: conf/question_lists.py:53 conf/question_lists.py:70 msgid "All Questions" -msgstr "" +msgstr "所有问题" #: conf/question_lists.py:54 conf/question_lists.py:71 msgid "Unanswered Questions" @@ -1846,55 +1846,55 @@ msgstr "用户æ¯æ—¥èŽ·å–积分上é™" #: conf/reputation_changes.py:32 msgid "Gain for receiving an upvote" -msgstr "æ ‡è®°æŽ¥æ”¶çš„æŽ¨è票" +msgstr "收到赞æˆç¥¨å¯ä»¥èŽ·å¾—积分" #: conf/reputation_changes.py:41 msgid "Gain for the author of accepted answer" -msgstr "æ ‡è®°æŽ¥å—回ç”的作者" +msgstr "被接å—ç”案的作者å¯ä»¥èŽ·å¾—积分" #: conf/reputation_changes.py:50 msgid "Gain for accepting best answer" -msgstr "æ ‡è®°æœ€ä½³ç”案" +msgstr "接å—最佳ç”案å¯ä»¥èŽ·å¾—积分" #: conf/reputation_changes.py:59 msgid "Gain for post owner on canceled downvote" -msgstr "æ ‡è®°å‘布者å–消å对票" +msgstr "被å–消å对票的帖å作者å¯ä»¥èŽ·å¾—积分" #: conf/reputation_changes.py:68 msgid "Gain for voter on canceling downvote" -msgstr "æ ‡è®°æŠ•ç¥¨è€…å–消å对票" +msgstr "å–消å对票的投票者å¯ä»¥èŽ·å¾—积分" #: conf/reputation_changes.py:78 msgid "Loss for voter for canceling of answer acceptance" -msgstr "å‡å°‘投票者积分当å–消回ç”的接å—æ—¶" +msgstr "投票者å–消了接å—的回ç”积分将å‡å°‘" #: conf/reputation_changes.py:88 msgid "Loss for author whose answer was \"un-accepted\"" -msgstr "å‡å°‘å‘布者积分当回ç”为ä¸å¯æŽ¥å—æ—¶" +msgstr "ä¸è¢«æŽ¥å—ç”案的作者积分å‡å°‘" #: conf/reputation_changes.py:98 msgid "Loss for giving a downvote" -msgstr "å‡å°‘å‘布者积分当获得å对票时" +msgstr "投å对票者积分å‡å°‘" #: conf/reputation_changes.py:108 msgid "Loss for owner of post that was flagged offensive" -msgstr "å‡å°‘å‘å¸ƒè€…ç§¯åˆ†å½“é—®é¢˜è¢«æ ‡è®°ä¸ºåžƒåœ¾è´´æ—¶" +msgstr "è¢«æ ‡è®°ä¸ºåžƒåœ¾è´´çš„ä½œè€…ç§¯åˆ†å‡å°‘" #: conf/reputation_changes.py:118 msgid "Loss for owner of post that was downvoted" -msgstr "å‡å°‘å‘布者积分当问题被投å对票时" +msgstr "被投å对票的作者积分å‡å°‘" #: conf/reputation_changes.py:128 msgid "Loss for owner of post that was flagged 3 times per same revision" -msgstr "å‡å°‘å‘布者积分当问题被3次åŒæ ·çš„ä¿®æ”¹æ ‡è®°æ—¶" +msgstr "åŒä¸€ä¸ªå¸–åè¢«æ ‡è®°3次垃圾贴的作者积分å‡å°‘" #: conf/reputation_changes.py:138 msgid "Loss for owner of post that was flagged 5 times per same revision" -msgstr "å‡å°‘å‘布者积分当问题被5次åŒæ ·çš„ä¿®æ”¹æ ‡è®°æ—¶" +msgstr "åŒä¸€ä¸ªå¸–åè¢«æ ‡è®°5次垃圾贴的作者积分å‡å°‘" #: conf/reputation_changes.py:148 msgid "Loss for post owner when upvote is canceled" -msgstr "å‡å°‘å‘布者积分当推è票å–消时" +msgstr "帖å赞æˆç¥¨è¢«å–消的作者积分å‡å°‘" #: conf/sidebar_main.py:12 msgid "Main page sidebar" @@ -2463,7 +2463,7 @@ msgstr "" #: conf/user_settings.py:60 msgid "Allow users change own email addresses" -msgstr "" +msgstr "å…许用户改å˜è‡ªå·±çš„电å邮件地å€" #: conf/user_settings.py:69 msgid "Allow email address in user name" @@ -2483,16 +2483,16 @@ msgstr "用户昵称å…许的最å°é•¿åº¦" #: conf/user_settings.py:105 msgid "Default avatar for users" -msgstr "" +msgstr "用户的缺çœå¤´åƒ" #: conf/user_settings.py:107 msgid "" "To change the avatar image, select new file, then submit this whole form." -msgstr "" +msgstr "è¦æ”¹å˜å¤´åƒï¼Œè¯·é€‰æ‹©æ–°æ–‡ä»¶ï¼Œç„¶åŽæäº¤æ•´å¼ è¡¨å•ã€‚" #: conf/user_settings.py:120 msgid "Use automatic avatars from gravatar.com" -msgstr "" +msgstr "使用æ¥è‡ªgravatar.com的自动头åƒ" #: conf/user_settings.py:122 msgid "" @@ -2501,7 +2501,7 @@ msgid "" "effective. You will have to enable uploaded avatars as well. For more " "information, please visit <a href=\"http://askbot.org/doc/optional-" "modules.html#uploaded-avatars\">this page</a>." -msgstr "" +msgstr "å¦‚æžœä½ æƒ³è¦å…许使用gravatar.comä¸çš„头åƒï¼Œè¯·é€‰æ‹©è¿™ä¸ªé€‰é¡¹ã€‚请注æ„这个功能å¯èƒ½éœ€è¦å¤§çº¦10分钟æ‰èƒ½å®Œå…¨ç”Ÿæ•ˆã€‚ä½ è¿˜éœ€è¦å¯ç”¨ä¸Šä¼ 头åƒã€‚想è¦å¾—到更多信æ¯ï¼Œè¯·é˜…读<a href=\"http://askbot.org/doc/optional-modules.html#uploaded-avatars\">这一页</a>." #: conf/user_settings.py:134 msgid "Default Gravatar icon type" @@ -2524,11 +2524,11 @@ msgstr "æŠ•ç¥¨ä¸Žæ ‡è®°é™åˆ¶" #: conf/vote_rules.py:24 msgid "Number of votes a user can cast per day" -msgstr "æ¯ç”¨æˆ·æ¯å¤©å…许的投票数" +msgstr "用户æ¯å¤©å…许的投票数" #: conf/vote_rules.py:33 msgid "Maximum number of flags per user per day" -msgstr "æ¯ç”¨æˆ·æ¯å¤©çš„æœ€å¤šæ ‡è®°" +msgstr "用户æ¯å¤©å…è®¸çš„æ ‡è®°æ•°" #: conf/vote_rules.py:42 msgid "Threshold for warning about remaining daily votes" @@ -2544,17 +2544,17 @@ msgstr "回ç”自己的æ问之å‰å…许的天数" #: conf/vote_rules.py:69 msgid "Number of flags required to automatically hide posts" -msgstr "è¦æ±‚自动éšè—æ ‡å¿—æ•°" +msgstr "帖å自动éšè—çš„æ ‡å¿—æ•°" #: conf/vote_rules.py:78 msgid "Number of flags required to automatically delete posts" -msgstr "è¦æ±‚è‡ªåŠ¨åˆ é™¤çš„æ ‡å¿—æ•°" +msgstr "帖åè‡ªåŠ¨åˆ é™¤çš„æ ‡å¿—æ•°" #: conf/vote_rules.py:87 msgid "" "Minimum days to accept an answer, if it has not been accepted by the " "question poster" -msgstr "Minimum days to accept an answer, if it has not been accepted by the question poster" +msgstr "接å—一个ç”案的最少天数,如果它没有被问题å‘起者接å—。" #: const/__init__.py:11 msgid "duplicate question" @@ -2594,19 +2594,19 @@ msgstr "太地域化" #: const/__init__.py:29 msgid "disable sharing" -msgstr "" +msgstr "撤销共享" #: const/__init__.py:30 #: templates/user_profile/twitter_sharing_controls.html:13 #: templates/user_profile/twitter_sharing_controls.html:17 msgid "my posts" -msgstr "" +msgstr "我的帖å" #: const/__init__.py:31 #: templates/user_profile/twitter_sharing_controls.html:14 #: templates/user_profile/twitter_sharing_controls.html:16 msgid "all posts" -msgstr "" +msgstr "所有帖å" #: const/__init__.py:54 templates/question/answer_tab_bar.html:18 msgid "newest" @@ -2722,7 +2722,7 @@ msgstr "获了奖牌" #: const/__init__.py:202 msgid "marked best answer" -msgstr "æ ‡è®°æœ€ä½³ç”案" +msgstr "作最佳回ç”" #: const/__init__.py:203 msgid "upvoted" @@ -2830,7 +2830,7 @@ msgstr "æ›´æ–°äº†æ ‡ç¾" #: const/__init__.py:311 msgid "[private]" -msgstr "" +msgstr "[ç§æœ‰]" #: const/__init__.py:320 msgid "show all tags" @@ -2851,7 +2851,7 @@ msgstr "åªè¦è®¢é˜…æ ‡ç¾" #: const/__init__.py:329 const/__init__.py:335 const/__init__.py:341 msgid "email for all tags" -msgstr "" +msgstr "æ‰€æœ‰æ ‡ç¾çš„邮件" #: const/__init__.py:348 msgid "instantly" @@ -2915,35 +2915,35 @@ msgstr "å·²ä¸Šä¼ å¤´åƒ" #: const/__init__.py:429 msgid "date descendant" -msgstr "" +msgstr "日期å‡å°‘" #: const/__init__.py:430 msgid "date ascendant" -msgstr "" +msgstr "æ—¥æœŸå¢žåŠ " #: const/__init__.py:431 msgid "activity descendant" -msgstr "" +msgstr "活跃人数下é™" #: const/__init__.py:432 msgid "activity ascendant" -msgstr "" +msgstr "活跃人数上å‡" #: const/__init__.py:433 msgid "answers descendant" -msgstr "" +msgstr "回ç”人数下é™" #: const/__init__.py:434 msgid "answers ascendant" -msgstr "" +msgstr "回ç”人数上å‡" #: const/__init__.py:435 msgid "votes descendant" -msgstr "" +msgstr "选票下é™" #: const/__init__.py:436 msgid "votes ascendant" -msgstr "" +msgstr "选票上å‡" #: const/message_keys.py:21 msgid "most relevant questions" @@ -3011,7 +3011,7 @@ msgstr "感兴趣" #: const/message_keys.py:37 models/tag.py:312 msgid "ignored" -msgstr "有趣的" +msgstr "ä¸æ„Ÿå…´è¶£çš„" #: const/message_keys.py:38 models/tag.py:313 msgid "subscribed" @@ -3030,14 +3030,14 @@ msgid "" "Sorry, your account appears to be blocked and you cannot make new posts " "until this issue is resolved. Please contact the forum administrator to " "reach a resolution." -msgstr "" +msgstr "对ä¸èµ·ï¼Œä½ çš„å¸æˆ·è¢«å†»ç»“,该问题解决之å‰ï¼Œä½ ä¸èƒ½å‘布新帖å。请è”系论å›ç®¡ç†å‘˜å¯»æ±‚解决方案。" #: const/message_keys.py:52 models/__init__.py:1136 msgid "" "Sorry, your account appears to be suspended and you cannot make new posts " "until this issue is resolved. You can, however edit your existing posts. " "Please contact the forum administrator to reach a resolution." -msgstr "" +msgstr "对ä¸èµ·ï¼Œä½ çš„å¸æˆ·è¢«ç¦ç”¨ï¼Œè¯¥é—®é¢˜è§£å†³ä¹‹å‰ï¼Œä½ ä¸èƒ½å‘布新帖å。请è”系论å›ç®¡ç†å‘˜å¯»æ±‚解决方案。" #: deps/django_authopenid/backends.py:99 msgid "" @@ -3095,7 +3095,7 @@ msgstr "用户å是必需项" #: deps/django_authopenid/forms.py:455 msgid "sorry, there is no such user name" -msgstr "" +msgstr "对ä¸èµ·ï¼Œæ²¡æœ‰è¿™ä¸ªç”¨æˆ·å" #: deps/django_authopenid/urls.py:14 deps/django_authopenid/urls.py:20 #: deps/django_authopenid/urls.py:23 setup_templates/settings.py:229 @@ -3351,15 +3351,15 @@ msgstr "æ喜您,社区给您é¢å‘了奖牌" #: mail/__init__.py:183 msgid "<p>To ask by email, please:</p>" -msgstr "" +msgstr "<p>请使用邮件å‘问:</p>" #: mail/__init__.py:185 msgid "<li>Type title in the subject line</li>" -msgstr "" +msgstr "<li>åœ¨ä¸»é¢˜è¡Œå†™æ ‡é¢˜</li>" #: mail/__init__.py:188 msgid "<li>Type details of your question into the email body</li>" -msgstr "" +msgstr "<li>问题的详细æ述应该放入邮件æ£æ–‡ä¸åŽ»</li>" #: mail/__init__.py:191 msgid "" @@ -3377,7 +3377,7 @@ msgstr "" msgid "" "<p>Note that a tag may consist of more than one word, to separate\n" "the tags, use a semicolon or a comma, for example, [One tag; Other tag]</p>" -msgstr "" +msgstr "<p>\n注æ„ï¼Œä¸€ä¸ªæ ‡ç¾åŒ…å«ä¸€ä¸ªä»¥ä¸Šçš„å—ï¼Œä½¿ç”¨ç©ºæ ¼æ¥åˆ†éš”æ ‡ç¾ï¼Œä¾‹å¦‚[æ ‡ç¾1 æ ‡ç¾2]\n</p>" #: mail/__init__.py:214 #, python-format @@ -3460,7 +3460,7 @@ msgstr "对ä¸èµ·ï¼Œä½ åªæœ‰è®¿é—®çš„æƒé™" #: models/__init__.py:573 msgid "Sorry, this operation is not allowed" -msgstr "" +msgstr "对ä¸èµ·ï¼Œè¿™ä¸ªæ“作ä¸å…许" #: models/__init__.py:623 msgid "" @@ -3527,15 +3527,15 @@ msgstr "对ä¸èµ·,æš‚åœä½¿ç”¨ç”¨æˆ·ä¸èƒ½ä¸Šä¼ 文件" #: models/__init__.py:740 #, python-format msgid "sorry, file uploading requires karma >%(min_rep)s" -msgstr "" +msgstr "对ä¸èµ·ï¼Œä¸Šä¼ 文件需è¦karma大于%(min_rep)s" #: models/__init__.py:759 msgid "Could not post, because your karma is insufficient to publish links" -msgstr "" +msgstr "æ— æ³•å‘è¡¨ï¼Œå› ä¸ºä½ çš„å£°æœ›ä¸è¶³ä»¥å‘布链接" #: models/__init__.py:785 msgid "Sorry, you already gave an answer, please edit it instead." -msgstr "" +msgstr "对ä¸èµ·ï¼Œä½ 已有一个ç”案,请编辑它。" #: models/__init__.py:809 #, python-format @@ -3620,7 +3620,7 @@ msgstr "对ä¸èµ·ï¼Œä½ åªèƒ½åˆ é™¤ä½ è‡ªå·±å‘布的信æ¯å› ä¸ºä½ çš„è´¦æˆ·è¢« msgid "" "Sorry, to delete other people's posts, a minimum reputation of %(min_rep)s " "is required" -msgstr "" +msgstr "对ä¸èµ·ï¼Œè¦åˆ 除别人的帖å,声望至少为%(min_rep)s " #: models/__init__.py:1040 msgid "Sorry, since your account is blocked you cannot close questions" @@ -3659,20 +3659,20 @@ msgstr "对ä¸èµ·ï¼Œä½ 必须有%(min_rep)s积分æ‰èƒ½é‡å¼€è‡ªå·±å‘布的问é #: models/__init__.py:1095 msgid "Sorry, you cannot reopen questions because your account is blocked" -msgstr "" +msgstr "对ä¸èµ·ï¼Œå› 为您的å¸æˆ·è¢«å°é”ï¼Œæ‰€ä»¥ä½ ä¸èƒ½é‡æ–°æ‰“开问题" #: models/__init__.py:1100 msgid "Sorry, you cannot reopen questions because your account is suspended" -msgstr "" +msgstr "对ä¸èµ·ï¼Œå› ä¸ºä½ çš„å¸æˆ·è¢«æš‚åœï¼Œæ‰€ä»¥ä½ ä¸èƒ½é‡æ–°æ‰“开问题。" #: models/__init__.py:1123 msgid "You have flagged this question before and cannot do it more than once" -msgstr "" +msgstr "ä½ å·²ç»æ ‡è®°è¿‡è¿™ä¸ªé—®é¢˜ï¼Œä¸èƒ½å†æ¬¡æ ‡è®°" #: models/__init__.py:1131 msgid "" "Sorry, since your account is blocked you cannot flag posts as offensive" -msgstr "" +msgstr "对ä¸èµ·ï¼Œä½ çš„å¸æˆ·è¢«å†»ç»“ï¼Œä½ ä¸å…è®¸æ ‡è®°å¸–å为攻击的" #: models/__init__.py:1142 #, python-format @@ -3686,7 +3686,7 @@ msgstr "" msgid "" "Sorry, you have exhausted the maximum number of %(max_flags_per_day)s " "offensive flags per day." -msgstr "" +msgstr "对ä¸èµ·ï¼Œä½ å·²ç»ç”¨å®Œäº†æ¯å¤©çš„æ”»å‡»æ€§æ ‡è®°çš„æœ€å¤§æ•°ç›®%(max_flags_per_day)s " #: models/__init__.py:1175 msgid "cannot remove non-existing flag" @@ -3694,20 +3694,20 @@ msgstr "æ— æ³•ç§»é™¤ä¸å˜åœ¨çš„æ ‡è®°" #: models/__init__.py:1181 msgid "Sorry, since your account is blocked you cannot remove flags" -msgstr "" +msgstr "对ä¸èµ·ï¼Œä½ çš„å¸æˆ·è¢«å†»ç»“ï¼Œä½ ä¸èƒ½åˆ é™¤æ ‡è®°" #: models/__init__.py:1185 msgid "" "Sorry, your account appears to be suspended and you cannot remove flags. " "Please contact the forum administrator to reach a resolution." -msgstr "" +msgstr "对ä¸èµ·ï¼Œä½ çš„å¸æˆ·è¢«æš‚åœä½¿ç”¨ï¼Œä½ ä¸èƒ½åˆ é™¤æ ‡è®°ã€‚è¯·è”系论å›ç®¡ç†å‘˜å¯»æ±‚解决方法。" #: models/__init__.py:1191 #, python-format msgid "Sorry, to flag posts a minimum reputation of %(min_rep)d is required" msgid_plural "" "Sorry, to flag posts a minimum reputation of %(min_rep)d is required" -msgstr[0] "" +msgstr[0] "需è¦å¤§äºŽ%(min_rep)d积分值æ‰èƒ½æ ‡è®°ä¿¡æ¯" #: models/__init__.py:1210 msgid "you don't have the permission to remove all flags" @@ -3754,7 +3754,7 @@ msgstr "对ä¸èµ·ï¼Œåˆ 除留言必须有%(min_rep)s积分值" #: models/__init__.py:1303 msgid "sorry, but older votes cannot be revoked" -msgstr "" +msgstr "这个投票已ç»è¿‡æ—¶ï¼Œä¸èƒ½æ’¤é”€ã€‚" #: models/__init__.py:1995 utils/functions.py:98 #, python-format @@ -3863,41 +3863,41 @@ msgstr "%(user)s 有 %(badges)s" #, python-format msgid "At least %d karma point is required to post links" msgid_plural "At least %d karma points is required to post links" -msgstr[0] "" +msgstr[0] "必须至少有%d声望值æ‰èƒ½å‘表链接" #: models/__init__.py:3159 #, python-format msgid "%(user)s shared a %(post_link)s." -msgstr "" +msgstr "%(user)s 共享了 %(post_link)s." #: models/__init__.py:3162 models/__init__.py:3172 #, python-format msgid "%(user)s edited a %(post_link)s." -msgstr "" +msgstr "%(user)s 修改了 %(post_link)s." #: models/__init__.py:3164 #, python-format msgid "%(user)s posted a %(post_link)s" -msgstr "" +msgstr "%(user)s å‘表了 %(post_link)s" #: models/__init__.py:3167 #, python-format msgid "%(user)s edited an %(post_link)s." -msgstr "" +msgstr "%(user)s 修改了 %(post_link)s." #: models/__init__.py:3169 #, python-format msgid "%(user)s posted an %(post_link)s." -msgstr "" +msgstr "%(user)s å‘表了 %(post_link)s." #: models/__init__.py:3174 #, python-format msgid "%(user)s posted a %(post_link)s." -msgstr "" +msgstr "%(user)s å‘表了 %(post_link)s." #: models/__init__.py:3190 msgid "To reply, PLEASE WRITE ABOVE THIS LINE." -msgstr "" +msgstr "回å¤ï¼Œè¯·å†™åœ¨è¿™æ¡çº¿ã€‚" #: models/__init__.py:3232 #, python-format @@ -3923,25 +3923,25 @@ msgstr "æ‚¨çš„æ ‡ç¾è®¢é˜…å·²ä¿å˜ï¼Œéžå¸¸æ„Ÿè°¢!" #: models/badges.py:129 #, python-format msgid "Deleted own post with %(votes)s or more upvotes" -msgstr "åˆ é™¤è‡ªå·±å‘布的有%(votes)s或更多推è票的问题" +msgstr "åˆ é™¤è‡ªå·±ä¸€ä¸ª%(votes)så¼ èµžæˆç¥¨ä»¥ä¸Šçš„帖å" #: models/badges.py:133 msgid "Disciplined" -msgstr "规则" +msgstr "自律" #: models/badges.py:151 #, python-format msgid "Deleted own post with %(votes)s or more downvotes" -msgstr "åˆ é™¤è‡ªå·±å‘布的%(votes)s或更多å对票的信æ¯" +msgstr "åˆ é™¤è‡ªå·±ä¸€ä¸ª%(votes)så¼ å对票以上的帖å" #: models/badges.py:155 msgid "Peer Pressure" -msgstr "åŒç‰åŽ‹åŠ›" +msgstr "他律" #: models/badges.py:174 #, python-format msgid "Received at least %(votes)s upvote for an answer for the first time" -msgstr "获å–至少有%(votes)s推è票的问题" +msgstr "第一次回ç”且获得至少%(votes)så¼ èµžæˆç¥¨" #: models/badges.py:178 msgid "Teacher" @@ -3957,7 +3957,7 @@ msgstr "第一个赞æˆç¥¨" #: models/badges.py:227 msgid "Critic" -msgstr "评论家" +msgstr "批评家" #: models/badges.py:228 msgid "First downvote" @@ -3975,7 +3975,7 @@ msgstr "已投票%(num)s次" #: models/badges.py:252 #, python-format msgid "Answered own question with at least %(num)s up votes" -msgstr "自己回ç”的至少有%(num)s次推è票的问题" +msgstr "回ç”自己的问题至少有%(num)s次赞æˆç¥¨" #: models/badges.py:256 msgid "Self-Learner" @@ -3988,11 +3988,11 @@ msgstr "好回ç”" #: models/badges.py:309 models/badges.py:321 models/badges.py:333 #, python-format msgid "Answer voted up %(num)s times" -msgstr "该用户投的赞æˆç¥¨å›žç”总数%(num)s" +msgstr "赞æˆæ•°ç¥¨ä¸º%(num)så¼ çš„å›žç”" #: models/badges.py:316 msgid "Good Answer" -msgstr "好回ç”" +msgstr "优秀回ç”" #: models/badges.py:328 msgid "Great Answer" @@ -4005,15 +4005,15 @@ msgstr "好问题" #: models/badges.py:345 models/badges.py:357 models/badges.py:369 #, python-format msgid "Question voted up %(num)s times" -msgstr "该用户投的赞æˆç¥¨é—®é¢˜æ€»æ•°%(num)s" +msgstr "赞æˆæ•°ç¥¨ä¸º%(num)s票的问题" #: models/badges.py:352 msgid "Good Question" -msgstr "好问题" +msgstr "优秀问题" #: models/badges.py:364 msgid "Great Question" -msgstr "完美的问题" +msgstr "完美问题" #: models/badges.py:376 msgid "Student" @@ -4021,7 +4021,7 @@ msgstr "å¦ç”Ÿ" #: models/badges.py:381 msgid "Asked first question with at least one up vote" -msgstr "得到至少一个赞æˆç¥¨çš„问题" +msgstr "第一次æ问且至少有一个赞æˆç¥¨" #: models/badges.py:414 msgid "Popular Question" @@ -4034,7 +4034,7 @@ msgstr "被查看 %(views)s次的问题" #: models/badges.py:425 msgid "Notable Question" -msgstr "关注的问题" +msgstr "çƒé—¨çš„问题" #: models/badges.py:436 msgid "Famous Question" @@ -4042,7 +4042,7 @@ msgstr "è‘—å问题" #: models/badges.py:450 msgid "Asked a question and accepted an answer" -msgstr "æ问的有æ£ç¡®ç”案的问题" +msgstr "问了一个问题且接å—了一个ç”案" #: models/badges.py:453 msgid "Scholar" @@ -4050,12 +4050,12 @@ msgstr "å¦è€…" #: models/badges.py:495 msgid "Enlightened" -msgstr "文明的" +msgstr "å¯å‘" #: models/badges.py:499 #, python-format msgid "First answer was accepted with %(num)s or more votes" -msgstr "第一个æ£ç¡®ä¸”被投了%(num)s或更多票的ç”案" +msgstr "被æ问者接å—且被投了%(num)s或更多票的ç”案" #: models/badges.py:507 msgid "Guru" @@ -4064,42 +4064,42 @@ msgstr "专家" #: models/badges.py:510 #, python-format msgid "Answer accepted with %(num)s or more votes" -msgstr "被接å—的且被投了%(num)s或更多æ¤çš„回ç”" +msgstr "回ç”被接å—,且被投了%(num)s或更多的赞æˆç¥¨" #: models/badges.py:518 #, python-format msgid "" "Answered a question more than %(days)s days later with at least %(votes)s " "votes" -msgstr "问了一个超过%(days)s天且至少有%(votes)s投票的问题" +msgstr "在一个问题出现%(days)s天åŽæ‰è¢«å›žç”且票数至少为%(votes)s票" #: models/badges.py:525 msgid "Necromancer" -msgstr "亡çµ" +msgstr "å¤å…´çš„问题" #: models/badges.py:548 msgid "Citizen Patrol" -msgstr "社区居民" +msgstr "市民侦察兵" #: models/badges.py:551 msgid "First flagged post" -msgstr "ç¬¬ä¸€æ¬¡æ ‡è®°" +msgstr "第一次举报帖å" #: models/badges.py:563 msgid "Cleanup" -msgstr "清除" +msgstr "清扫工作" #: models/badges.py:566 msgid "First rollback" -msgstr "第一次回滚" +msgstr "第一次回滚æ“作" #: models/badges.py:577 msgid "Pundit" -msgstr "å¦è€…" +msgstr "åšå¦è€…" #: models/badges.py:580 msgid "Left 10 comments with score of 10 or more" -msgstr "留言超过10且得分上10的问题" +msgstr "评论超过10æ¡ä¸”得分上10的问题" #: models/badges.py:612 msgid "Editor" @@ -4111,12 +4111,12 @@ msgstr "第一次编辑" #: models/badges.py:623 msgid "Associate Editor" -msgstr "è”åˆç¼–辑" +msgstr "主编" #: models/badges.py:627 #, python-format msgid "Edited %(num)s entries" -msgstr "编辑了%(num)sæ¡ç›®" +msgstr "编辑了%(num)s个帖å" #: models/badges.py:634 msgid "Organizer" @@ -4128,7 +4128,7 @@ msgstr "ç¬¬ä¸€æ¬¡ä¿®æ”¹æ ‡ç¾" #: models/badges.py:644 msgid "Autobiographer" -msgstr "完善个人资料者" +msgstr "è‡ªä¼ ä½œè€…" #: models/badges.py:647 msgid "Completed all user profile fields" @@ -4137,7 +4137,7 @@ msgstr "完善个人所有资料" #: models/badges.py:663 #, python-format msgid "Question favorited by %(num)s users" -msgstr "被%(num)s用户收è—的问题" +msgstr "被%(num)s个用户关注的问题" #: models/badges.py:689 msgid "Stellar Question" @@ -4149,7 +4149,7 @@ msgstr "收è—问题" #: models/badges.py:710 msgid "Enthusiast" -msgstr "çƒå¿ƒäºº" +msgstr "粉ä¸" #: models/badges.py:714 #, python-format @@ -4172,15 +4172,15 @@ msgstr "分类å¦è€…" #: models/badges.py:756 #, python-format msgid "Created a tag used by %(num)s questions" -msgstr "创建一个%(num)sä¸ªé—®é¢˜éƒ½ç”¨åˆ°çš„æ ‡ç¾" +msgstr "åˆ›å»ºä¸€ä¸ªæ ‡ç¾ï¼Œä¸”被%(num)s个问题使用过" #: models/badges.py:774 msgid "Expert" -msgstr "专家" +msgstr "达人" #: models/badges.py:777 msgid "Very active in one tag" -msgstr "éžå¸¸æ´»è·ƒçš„æ ‡ç¾" +msgstr "åœ¨ä¸€ä¸ªæ ‡ç¾é‡Œéžå¸¸æ´»è·ƒçš„人" #: models/message.py:16 msgid "message" @@ -4302,7 +4302,7 @@ msgstr "" #: models/reply_by_email.py:109 msgid "edited by email" -msgstr "" +msgstr "通过电å邮件编辑" #: models/repute.py:207 #, python-format @@ -4607,7 +4607,7 @@ msgstr "铜牌:时常授予之特殊è£èª‰" #: templates/base.html:23 #, python-format msgid "RSS feed from %(site_title)s" -msgstr "" +msgstr "èšåˆå†…容æ¥è‡ª %(site_title)s" #: templates/close.html:3 templates/close.html.py:5 msgid "Close question" @@ -4653,11 +4653,11 @@ msgstr "应该é¿å…ä»€ä¹ˆæ ·çš„é—®é¢˜ï¼Ÿ" msgid "" "Please avoid asking questions that are not relevant to this community, too " "subjective and argumentative." -msgstr "请é¿å…æå‡ºæ— å…³ã€è¿‡äºŽä¸»è§‚æ€§æˆ–æ˜“é€ æˆäº‰åµçš„问题。" +msgstr "请é¿å…å«æœ‰æžç«¯æƒ…绪化ã€æžç«¯ä¸»è§‚的个人判æ–的问题。å«æœ‰æžç«¯æƒ…绪化的æ问往往ä¸æ˜¯ä¸ºäº†å¯»æ‰¾ç”案,而是通过æé—®æ¥è¡¨è¾¾ã€å‘泄个人行情绪。å«æœ‰æžç«¯ä¸»è§‚个人判æ–的问题,问题ä¸çš„判æ–å¯èƒ½ä¸Žäº‹å®žä¸ç›¸ç¬¦ã€‚" #: templates/faq_static.html:13 msgid "What should I avoid in my answers?" -msgstr "ä»€ä¹ˆæ ·çš„å›žç”是ä¸å—欢迎的?" +msgstr "应该é¿å…ä»€ä¹ˆæ ·çš„å›žç”?" #: templates/faq_static.html:14 msgid "" @@ -4665,7 +4665,7 @@ msgid "" "discussion group</strong>. Please avoid holding debates in your answers as " "they tend to dilute the essense of questions and answers. For the brief " "discussions please use commenting facility." -msgstr "是一个<strong>é—®ç”社区</strong>-而ä¸æ˜¯ä¸€ä¸ª<strong>çŒæ°´è®ºå›</strong>。请é¿å…åœ¨ä½ çš„é—®é¢˜å’Œç”案ä¸æŒæœ‰è¾©è®ºçš„观点,他们倾å‘于使事情å¤æ‚åŒ–ã€‚å¦‚æžœä½ æœ‰å»ºè®®ï¼Œè¯·ä½¿ç”¨è¯„è®ºã€‚" +msgstr "是一个<strong>é—®ç”社区</strong>-而ä¸æ˜¯ä¸€ä¸ª<strong>çŒæ°´è®ºå›</strong>。请é¿å…ä¸Žé—®é¢˜æœ¬èº«æ— å…³æˆ–æ²¡æœ‰æ„义的回ç”。" #: templates/faq_static.html:15 msgid "Who moderates this community?" @@ -4729,7 +4729,7 @@ msgstr " 自己的æ问接å—自己的回ç”" #: templates/faq_static.html:49 msgid "open and close own questions" -msgstr "打开关é—任何人的问题" +msgstr "打开和关é—自己的问题" #: templates/faq_static.html:53 msgid "retag other's questions" @@ -4737,7 +4737,7 @@ msgstr "æ•´ç†æ ‡ç¾" #: templates/faq_static.html:58 msgid "edit community wiki questions" -msgstr "编辑wiki类问题" +msgstr "编辑社区维基里的问题" #: templates/faq_static.html:63 msgid "edit any answer" @@ -4796,7 +4796,7 @@ msgid "" "So questions and answers can be edited like wiki pages by experienced users " "of this site and this improves the overall quality of the knowledge base " "content." -msgstr "所以问题和ç”案都是如 Wiki ä¸€æ ·å¯ç¼–辑的,我们希望社区能帮助用户沉淀ã€ç§¯ç´¯æ›´å¤šæœ‰ç”¨çš„知识和ç»éªŒã€‚" +msgstr "所有问题和ç”æ¡ˆéƒ½å¦‚ç»´åŸºç™¾ç§‘ä¸€æ ·å¯å…±åŒç¼–辑的,我们希望社区æˆå‘˜çš„å…±åŒå作å¯ä»¥è®©æ¯ä¸€ä¸ªé—®é¢˜å’Œç”案å˜å¾—更有价值,就åƒä¸€æ¡æµåŠ¨çš„æ²³æµï¼ŒçŸ¥è¯†åœ¨è¿™é‡Œå¯ä»¥éšæ—¶é—´ä¸æ–更新,得到æŒç»ä¼˜åŒ–和改进。" #: templates/faq_static.html:79 msgid "If this approach is not for you, we respect your choice." @@ -4916,19 +4916,19 @@ msgstr "如何æ问,回ç”和评论。" msgid "" "This site is for asking and answering questions, not for open-ended " "discussions." -msgstr "这个网站的目的是为了å‘起和回ç”问题,而ä¸æ˜¯çŒæ°´ã€‚" +msgstr "这个网站的目的是为了æ供高质é‡çš„ç”案,而ä¸æ˜¯çŒæ°´ã€‚" #: templates/help.html:19 msgid "" "We encourage everyone to use “question†space for asking and “answer†for " "answering." -msgstr "我们鼓励大家“å‘èµ·ä½ ä¸çŸ¥é“,别人知é“的问题;回ç”ä½ çŸ¥é“,别人ä¸çŸ¥é“çš„ç”案â€ã€‚" +msgstr "我们鼓励大家“å‘èµ·ä½ ä¸çŸ¥é“,别人知é“的问题;回ç”ä½ çŸ¥é“,别人ä¸çŸ¥é“çš„ç”案â€ã€‚æ问应éµå¾ªâ€œçœŸå®žã€å®¢è§‚ã€ç®€æ´ã€æ˜Žç¡®ã€è§„范â€çš„原则。回ç”应éµå¾ªâ€œå°½å¯èƒ½æ供详细的解释和说明â€çš„原则。" #: templates/help.html:22 msgid "" "Despite that, each question and answer can be commented – \n" " the comments are good for the limited discussions." -msgstr "对问题和ç”案有什么完善的æ„è§ï¼Œè¯·ä½¿ç”¨è¯„论。" +msgstr "å¦‚æžœä½ å¯¹é—®é¢˜æœ¬èº«æˆ–åˆ«äººçš„ç”æ¡ˆæœ‰è‡ªå·±çš„çœ‹æ³•ï¼Œä½ å¯ä»¥é€šè¿‡ã€Œè¯„论ã€æ¥è¿›è¡Œï¼Œä¸è¦æŠŠè¯„论当作ç”案æ¥å‘å¸ƒã€‚é‚£æ ·çš„è¯ï¼Œè¯¥é—®é¢˜ä¼šè¢«å…¶ä»–用户点击「å对票ã€è€Œæ‰£é™¤ä½œè€…的声望值,å而起ä¸åˆ°å®žé™…æ•ˆæžœï¼Œä¹Ÿæ— åŠ©äºŽæ供高质é‡çš„ç”案。" #: templates/help.html:26 msgid "Please search before asking your questions" @@ -4938,7 +4938,7 @@ msgstr "åœ¨ä½ æ问之å‰ï¼Œè¯·å…ˆæœç´¢ä¸€ä¸‹ã€‚" msgid "" "Type your question in the search bar and see whether a similar question has " "been asked before" -msgstr "在æœç´¢æ ä¸è¾“入您的问题,看是å¦æœ‰ç±»ä¼¼çš„问题已ç»é—®è¿‡äº†ã€‚" +msgstr "在æœç´¢æ¡†ä¸è¾“入您的问题,看是å¦æœ‰ç±»ä¼¼çš„问题已ç»é—®è¿‡ã€‚" #: templates/help.html:29 msgid "Search has advanced capabilities:" @@ -5000,7 +5000,7 @@ msgstr "其它æ示" msgid "" "You can @mention users anywhere in the text to point their attention,\n" " follow users and conversations and report inappropriate content by flagging it." -msgstr "ä½ å¯ä»¥ä¿®æ”¹ä»–人的问题和ç”案,åªåœ¨ä½ 相信自己的修改能够帮助改进这个问题时æ‰è¿›è¡Œä¿®æ”¹ã€‚ï¼ˆå½“ç„¶ï¼Œåœ¨ä½ çš„ç§¯åˆ†è¾¾åˆ°æŸä¸ªç¨‹åº¦æ—¶æ‰èƒ½ä¿®æ”¹ï¼‰" +msgstr "虽然å…è®¸ä½ ä¿®æ”¹ä»–äººæå‡ºçš„é—®é¢˜ï¼Œä½†å½“ä½ åœ¨ä¿®æ”¹ä»–äººæ出的问题时,ä»ç„¶åº”该慎é‡ã€‚有些问题有明显的错误或ä¸å¦¥ï¼Œä½ å¯ä»¥å¤§èƒ†åœ°æ”¹è¿›å®ƒä»¬ï¼›ä½†æœ‰äº›é—®é¢˜ç»†å¾®çš„æ–‡å—修改就会带æ¥é—®é¢˜æœ¬èº«çš„差别,这时候更应该慎é‡ã€‚æ— è®ºä½•æ—¶ï¼Œåªåœ¨ä½ 相信自己的修改能够帮助改进这个问题时æ‰è¿›è¡Œä¿®æ”¹ã€‚请ä¸è¦æ¶æ„修改问题。如果出现æ¶æ„ç ´å行为,社区系统会记录æ“作者的身份,我们会酌情予以è¦å‘Šæˆ–åœæ¢å¸å·ç‰å¤„ç†ã€‚" #: templates/help.html:56 msgid "Enjoy." @@ -5128,20 +5128,20 @@ msgstr "" #: templates/macros.html:263 templates/macros.html.py:268 #: templates/macros.html:278 msgid "You are a member" -msgstr "" +msgstr "您是会员" #: templates/macros.html:270 msgid "Cancel application" -msgstr "" +msgstr "å–消应用" #: templates/macros.html:271 templates/macros.html.py:280 msgid "Waiting approval" -msgstr "" +msgstr "ç‰å¾…å®¡æ ¸" #: templates/macros.html:273 templates/macros.html.py:274 #: templates/macros.html:285 msgid "Ask to join" -msgstr "" +msgstr "è¯·åŠ å…¥" #: templates/macros.html:314 #, python-format @@ -5164,7 +5164,7 @@ msgstr "编辑" #: templates/macros.html:452 msgid "convert to answer" -msgstr "" +msgstr "转为ç”案" #: templates/macros.html:579 #, python-format @@ -5306,7 +5306,7 @@ msgstr "最多5ä¸ªæ ‡ç¾ï¼Œæ¯ä¸ªæ ‡ç¾é•¿åº¦å°äºŽ20个å—符。" #: templates/reopen.html:4 templates/reopen.html.py:6 msgid "Reopen question" -msgstr "é‡è®¾é—®é¢˜" +msgstr "é‡æ–°æ‰“开问题" #: templates/reopen.html:12 #, python-format @@ -5544,7 +5544,7 @@ msgid "" "If you believe that this message was sent in mistake - \n" "no further action is needed. Just ignore this email, we apologize\n" "for any inconvenience" -msgstr "" +msgstr "å¦‚æžœä½ è®¤ä¸ºæ¤æ¶ˆæ¯è¢«é”™è¯¯çš„å‘é€,ä¸è¦è¿›è¡Œæ›´è¿›ä¸€æ¥çš„动作.仅仅忽略这å°é‚®ä»¶,为给您带æ¥çš„ä¸ä¾¿é“æ‰." #: templates/authopenid/email_validation.txt:1 msgid "Greetings from the Q&A forum" @@ -5789,7 +5789,7 @@ msgstr "" #: templates/authopenid/widget_signin.html:94 msgid "or enter your <span>user name and password</span>, then sign in" -msgstr "" +msgstr "æˆ–è€…è¾“å…¥ä½ çš„<span>用户å和密ç </span>, 然åŽç™»é™†" #: templates/avatar/add.html:3 msgid "add avatar" @@ -5934,7 +5934,7 @@ msgstr "" #: templates/email/macros.html:19 #, python-format msgid "Question by %(author)s:" -msgstr "" +msgstr "%(author)s å‘起问题:" #: templates/email/macros.html:21 #, python-format @@ -5942,7 +5942,7 @@ msgid "" "\n" " In reply to %(author)s's question:\n" " " -msgstr "" +msgstr "\n在回ç”%(author)s的问题:" #: templates/email/macros.html:26 msgid "Question :" @@ -5984,7 +5984,7 @@ msgid "" "\n" " %(author)s's comment:\n" " " -msgstr "" +msgstr "\n%(author)s的评论:" #: templates/email/macros.html:68 #, python-format @@ -6000,7 +6000,7 @@ msgid "" "\n" " Commented by %(author)s:\n" " " -msgstr "" +msgstr "\n%(author)s的评论:" #: templates/email/notify_author_about_approved_post.html:21 msgid "Below is a copy of your post:" @@ -6066,7 +6066,7 @@ msgstr "" msgid "" "\n" "<p>The system was unable to process your message successfully, the reason being:<p>\n" -msgstr "" +msgstr "\n<p>系统ä¸èƒ½æ£ç¡®å¤„ç†ä½ çš„ä¿¡æ¯ï¼ŒåŽŸå› 如下:<p>\n" #: templates/email/welcome_lamson_off.html:6 #: templates/email/welcome_lamson_off.html:7 @@ -6155,7 +6155,7 @@ msgstr "" #: templates/group_messaging/macros.html:5 #, python-format msgid "You wrote on %(date)s:" -msgstr "" +msgstr "ä½ å†™äºŽ%(date)s:" #: templates/group_messaging/senders_list.html:3 msgid "Messages by sender:" @@ -6398,7 +6398,7 @@ msgstr "检举该帖为垃“水帖â€ï¼ˆå«å¹¿å‘Šã€äººèº«æ”»å‡»ã€æ¶æ„言论 #: templates/question/question_controls.html:18 #: templates/question/question_controls.html:25 msgid "flag offensive" -msgstr "垃圾帖?" +msgstr "垃圾帖" #: templates/question/answer_controls.html:33 #: templates/question/question_controls.html:36 @@ -6520,7 +6520,7 @@ msgid "" "<strong>use comments for discussions</strong> and <strong>please don't " "forget to vote :)</strong> for the answers that you liked (or perhaps did " "not like)!" -msgstr "<span class='big strong'>æ¬¢è¿Žä½ æ¥å›žç”自己的问题</span>,但请务必给一个<strong>ç”案</strong>。记ä½ï¼Œä½ å¯ä»¥éšæ—¶<strong>ä¿®æ”¹ä½ åŽŸæ¥çš„问题</strong>。请使用评论功能æ¥è®¨è®ºé—®é¢˜ï¼Œè¯·ä¸è¦å¿˜è®°ç»™â€œæ‰€æœ‰çš„ç”案â€<strong>投票</strong>(赞或踩)" +msgstr "<span class='big strong'>æ¬¢è¿Žä½ æ¥å›žç”自己的问题</span>,但请务必给一个<strong>ç”案</strong>。记ä½ï¼Œä½ å¯ä»¥éšæ—¶<strong>ä¿®æ”¹ä½ åŽŸæ¥çš„问题</strong>。请使用评论功能æ¥è®¨è®ºé—®é¢˜ï¼Œè¯·ä¸è¦å¿˜è®°ç»™â€œæ‰€æœ‰çš„ç”案â€<strong>投票:)</strong>(赞或踩)!" #: templates/question/new_answer_form.html:34 msgid "" @@ -6724,7 +6724,7 @@ msgstr "" #: templates/user_inbox/base.html:14 msgid "Sections:" -msgstr "段" +msgstr "部分:" #: templates/user_inbox/base.html:19 msgid "messages" @@ -6738,7 +6738,7 @@ msgstr "论å›å›žåº” (%(re_count)s)" #: templates/user_inbox/base.html:31 #, python-format msgid "flagged items (%(flags_count)s)" -msgstr "" +msgstr "å·²æ ‡è®°çš„æ ‡ç¾ (%(flags_count)s)" #: templates/user_inbox/base.html:38 msgid "group join requests" @@ -6770,11 +6770,11 @@ msgstr "选择:" #: templates/user_inbox/responses_and_flags.html:10 msgid "seen" -msgstr "查看" +msgstr "已看" #: templates/user_inbox/responses_and_flags.html:11 msgid "new" -msgstr "æ–°" +msgstr "未看" #: templates/user_inbox/responses_and_flags.html:12 msgid "none" @@ -6782,11 +6782,11 @@ msgstr "æ— " #: templates/user_inbox/responses_and_flags.html:15 msgid "mark as seen" -msgstr "å·²çœ‹æ ‡è®°" +msgstr "æ ‡è®°ä¸ºå·²çœ‹" #: templates/user_inbox/responses_and_flags.html:16 msgid "mark as new" -msgstr "æ–°æ ‡è®°" +msgstr "æ ‡è®°ä¸ºæœªçœ‹" #: templates/user_inbox/responses_and_flags.html:17 msgid "dismiss" @@ -6802,56 +6802,56 @@ msgstr "åˆ é™¤æ–‡ç« " #: templates/user_profile/reject_post_dialog.html:4 msgid "Reject the post(s)?" -msgstr "" +msgstr "æ‹’ç»å¸–å?" #: templates/user_profile/reject_post_dialog.html:11 msgid "1) Enter a brief description of why you are rejecting the post." -msgstr "" +msgstr "1)简è¦è¯´æ˜Žä½ æ‹’ç»çš„ç†ç”±ã€‚" #: templates/user_profile/reject_post_dialog.html:14 msgid "2) Please enter details here. This text will be sent to the user." -msgstr "" +msgstr "2)请在这里输入的细节。本文将被å‘é€åˆ°ç”¨æˆ·ã€‚" #: templates/user_profile/reject_post_dialog.html:20 #: templates/user_profile/reject_post_dialog.html:88 msgid "Use this reason & reject" -msgstr "" +msgstr "使用这个ç†ç”± & æ‹’ç»" #: templates/user_profile/reject_post_dialog.html:27 #: templates/user_profile/reject_post_dialog.html:95 msgid "Use other reason" -msgstr "" +msgstr "使用其它的ç†ç”±" #: templates/user_profile/reject_post_dialog.html:33 msgid "Save reason, but do not reject" -msgstr "" +msgstr "ä¿å˜ä¸€ä¸ªç†ç”±ï¼Œä½†ç”¨ä¸ä½¿ç”¨" #: templates/user_profile/reject_post_dialog.html:43 msgid "Please, choose a reason for the rejection." -msgstr "" +msgstr "请选择一个ç†ç”±ï¼Œæ‹’ç»ã€‚" #: templates/user_profile/reject_post_dialog.html:58 msgid "Select this reason" -msgstr "" +msgstr "选择这个ç†ç”±" #: templates/user_profile/reject_post_dialog.html:65 msgid "Delete this reason" -msgstr "" +msgstr "åˆ é™¤è¿™ä¸ªç†ç”±" #: templates/user_profile/reject_post_dialog.html:71 msgid "Add a new reason" -msgstr "" +msgstr "æ·»åŠ ä¸€ä¸ªæ–°çš„ç†ç”±" #: templates/user_profile/reject_post_dialog.html:81 msgid "" "You have selected reason for the rejection <strong>\"<span class=\"selected-" "reason-title\"></span>\"</strong>. The text below will be sent to the user " "and the post(s) will be deleted:" -msgstr "" +msgstr "ä½ å·²ç»é€‰æ‹©äº†ä¸€ä¸ªç†ç”±æ¥æ‹’ç»<strong>\"<span class=\"selected-reason-title\"></span>\"</strong>. 下é¢çš„æ–‡å—(ç†ç”±)å°†åœ¨åˆ é™¤åŽå‘é€ç»™ç”¨æˆ·ï¼š" #: templates/user_profile/reject_post_dialog.html:101 msgid "Edit this reason" -msgstr "" +msgstr "修改这个ç†ç”±" #: templates/user_profile/twitter_sharing_controls.html:8 #, python-format @@ -6991,7 +6991,7 @@ msgstr "上次活动时间" #: templates/user_profile/user_info.html:88 msgid "website" -msgstr "" +msgstr "个人网站" #: templates/user_profile/user_info.html:101 msgid "location" @@ -7099,7 +7099,7 @@ msgstr "" #: templates/user_profile/user_network.html:5 #: templates/user_profile/user_tabs.html:18 msgid "network" -msgstr "网络" +msgstr "朋å‹åœˆ" #: templates/user_profile/user_network.html:10 #, python-format @@ -7117,7 +7117,7 @@ msgstr[0] "关注 %(count)s å用户" msgid "" "Your network is empty. Would you like to follow someone? - Just visit their " "profiles and click \"follow\"" -msgstr "网络为空。是å¦å¸Œæœ›å…³æ³¨ä¸€äº›ç”¨æˆ·? - åªéœ€è®¿é—®å…¶ä¸ªäººæ¡£æ¡ˆå¹¶ç‚¹å‡»â€œå…³æ³¨â€" +msgstr "朋å‹åœˆä¸ºç©ºã€‚是å¦å¸Œæœ›å…³æ³¨ä¸€äº›ç”¨æˆ·? - åªéœ€è®¿é—®å…¶ä¸ªäººæ¡£æ¡ˆå¹¶ç‚¹å‡»â€œå…³æ³¨â€" #: templates/user_profile/user_network.html:33 #, python-format @@ -7196,7 +7196,7 @@ msgstr "粉ä¸åŠå·²å…³æ³¨ç”¨æˆ·" #: templates/user_profile/user_tabs.html:22 msgid "Graph of user karma" -msgstr "" +msgstr "用户的社区积分历å²" #: templates/user_profile/user_tabs.html:27 msgid "questions that user is following" @@ -7265,7 +7265,7 @@ msgstr "贡献者" #: templates/widgets/edit_post.html:33 msgid ", one of these is required" -msgstr "" +msgstr "这些ä¸çš„一个为必填项" #: templates/widgets/edit_post.html:42 templates/widgets/edit_post.html:47 msgid "tags:" @@ -7492,7 +7492,7 @@ msgstr "æ„Ÿå…´è¶£çš„æ ‡ç¾" #: templates/widgets/tag_selector.html:22 msgid "Ignored tags" -msgstr "å¿½ç•¥æ ‡ç¾" +msgstr "ä¸æ„Ÿå…´è¶£çš„æ ‡ç¾" #: templates/widgets/tag_selector.html:40 msgid "Subscribed tags" @@ -7585,7 +7585,7 @@ msgstr "å‘起问题,ç”案和评论。" #: templatetags/extra_filters_jinja.py:332 msgid "no" -msgstr "" +msgstr "æ— " #: utils/decorators.py:104 views/commands.py:146 msgid "Oops, apologies - there was some error" @@ -7775,7 +7775,7 @@ msgstr "请登录åŽæŠ•ç¥¨" #: views/commands.py:980 msgid "Please sign in to delete/restore posts" -msgstr "" +msgstr "请登录åŽçš„åˆ é™¤/æ¢å¤å¸–å" #: views/commands.py:1042 #, python-format @@ -7891,7 +7891,7 @@ msgstr "用户资料 - 投票" #: views/users.py:883 msgid "user karma" -msgstr "" +msgstr "用户社区积分" #: views/users.py:884 msgid "Profile - User's Karma" diff --git a/askbot/locale/zh_HK/LC_MESSAGES/django.mo b/askbot/locale/zh_HK/LC_MESSAGES/django.mo Binary files differindex 432ba792..37fff89a 100644 --- a/askbot/locale/zh_HK/LC_MESSAGES/django.mo +++ b/askbot/locale/zh_HK/LC_MESSAGES/django.mo diff --git a/askbot/locale/zh_HK/LC_MESSAGES/django.po b/askbot/locale/zh_HK/LC_MESSAGES/django.po index 35944848..96beb4a5 100644 --- a/askbot/locale/zh_HK/LC_MESSAGES/django.po +++ b/askbot/locale/zh_HK/LC_MESSAGES/django.po @@ -9,7 +9,7 @@ msgstr "" "Project-Id-Version: askbot\n" "Report-Msgid-Bugs-To: http://askbot.org/\n" "POT-Creation-Date: 2013-07-13 14:06-0500\n" -"PO-Revision-Date: 2013-07-15 02:23+0000\n" +"PO-Revision-Date: 2013-08-28 05:48+0000\n" "Last-Translator: brucelok\n" "Language-Team: Chinese (Hong Kong) (http://www.transifex.com/projects/p/askbot/language/zh_HK/)\n" "MIME-Version: 1.0\n" @@ -163,7 +163,7 @@ msgstr "已暫åœ" #: forms.py:603 const/__init__.py:378 msgid "blocked" -msgstr "" +msgstr "阻æ¢" #: forms.py:605 msgid "administrator" @@ -171,11 +171,11 @@ msgstr "管ç†å“¡" #: forms.py:606 const/__init__.py:374 msgid "moderator" -msgstr "" +msgstr "å”調人" #: forms.py:625 msgid "Change status to" -msgstr "" +msgstr "將狀態更改為" #: forms.py:652 msgid "which one?" @@ -183,7 +183,7 @@ msgstr "哪一個?" #: forms.py:673 msgid "Cannot change own status" -msgstr "" +msgstr "ä¸èƒ½æ›´æ”¹è‡ªå·±çš„狀態" #: forms.py:679 msgid "Cannot turn other user to moderator" diff --git a/askbot/locale/zh_TW/LC_MESSAGES/django.mo b/askbot/locale/zh_TW/LC_MESSAGES/django.mo Binary files differindex af1956a7..270aa57c 100644 --- a/askbot/locale/zh_TW/LC_MESSAGES/django.mo +++ b/askbot/locale/zh_TW/LC_MESSAGES/django.mo diff --git a/askbot/locale/zh_TW/LC_MESSAGES/django.po b/askbot/locale/zh_TW/LC_MESSAGES/django.po index ed8cb429..a3aee812 100644 --- a/askbot/locale/zh_TW/LC_MESSAGES/django.po +++ b/askbot/locale/zh_TW/LC_MESSAGES/django.po @@ -3,8 +3,11 @@ # This file is distributed under the same license as the CNPROG package. # # Translators: +# carl_tw, 2013 +# carl_tw, 2013 # evgeny <evgeny.fadeev@gmail.com>, 2009 # evgeny <evgeny.fadeev@gmail.com>, 2009 +# floydsoft <floydsoft@gmail.com>, 2013 # whisky <whisky@ystaiwan.org.tw>, 2013 # whisky <whisky@ystaiwan.org.tw>, 2013 msgid "" @@ -12,8 +15,8 @@ msgstr "" "Project-Id-Version: askbot\n" "Report-Msgid-Bugs-To: http://askbot.org/\n" "POT-Creation-Date: 2013-07-13 14:06-0500\n" -"PO-Revision-Date: 2013-08-02 06:30+0000\n" -"Last-Translator: evgeny <evgeny.fadeev@gmail.com>\n" +"PO-Revision-Date: 2013-09-02 17:31+0000\n" +"Last-Translator: carl_tw\n" "Language-Team: Chinese (Taiwan) (http://www.transifex.com/projects/p/askbot/language/zh_TW/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -23,7 +26,7 @@ msgstr "" #: exceptions.py:13 msgid "Sorry, but anonymous visitors cannot access this function" -msgstr "" +msgstr "抱æ‰ï¼ŒåŒ¿å訪å•è€…無法å˜å–æ¤åŠŸèƒ½" #: feed.py:34 feed.py:108 msgid " - " @@ -43,7 +46,7 @@ msgstr "國家" #: forms.py:158 msgid "Country field is required" -msgstr "" +msgstr "國家欄ä½å¿…å¡«" #: forms.py:188 #, python-format @@ -162,11 +165,11 @@ msgstr "" #: forms.py:602 const/__init__.py:377 msgid "suspended" -msgstr "" +msgstr "å·²åœæ¬Š" #: forms.py:603 const/__init__.py:378 msgid "blocked" -msgstr "" +msgstr "å·²å°éŽ–" #: forms.py:605 msgid "administrator" @@ -174,11 +177,11 @@ msgstr "管ç†å“¡" #: forms.py:606 const/__init__.py:374 msgid "moderator" -msgstr "" +msgstr "å”調人" #: forms.py:625 msgid "Change status to" -msgstr "" +msgstr "改變狀態至" #: forms.py:652 msgid "which one?" @@ -198,7 +201,7 @@ msgstr "" #: forms.py:692 msgid "Cannot change status to admin" -msgstr "" +msgstr "無法將狀態改為管ç†å“¡" #: forms.py:698 #, python-format @@ -221,11 +224,11 @@ msgstr "" #: forms.py:728 msgid "Email:" -msgstr "" +msgstr "é›»å信箱:" #: forms.py:730 msgid "Your message:" -msgstr "訊æ¯å…§å®¹ï¼š" +msgstr "您的訊æ¯ï¼š" #: forms.py:735 msgid "I don't want to give my email or receive a response:" @@ -261,7 +264,7 @@ msgstr "" #: forms.py:914 forms.py:957 msgid "ask anonymously" -msgstr "" +msgstr "匿åæå•" #: forms.py:916 forms.py:959 msgid "Check if you do not want to reveal your name when asking this question" @@ -310,7 +313,7 @@ msgstr "城市" #: forms.py:1396 msgid "Show country" -msgstr "" +msgstr "顯示國家" #: forms.py:1401 msgid "Show tag choices" @@ -330,7 +333,7 @@ msgstr "個人簡介" #: forms.py:1425 msgid "Screen name" -msgstr "" +msgstr "顯示å稱" #: forms.py:1457 forms.py:1461 msgid "this email has already been registered, please use another one" @@ -407,150 +410,150 @@ msgstr "å•é¡Œ" #: urls.py:56 msgid "question/" -msgstr "" +msgstr "question/" #: urls.py:61 msgid "tags/" -msgstr "" +msgstr "tags/" #: urls.py:66 urls.py:71 urls.py:78 urls.py:84 urls.py:93 urls.py:100 msgid "users/" -msgstr "" +msgstr "users/" #: urls.py:71 msgid "by-group/" -msgstr "" +msgstr "by-group/" #: urls.py:78 urls.py:159 urls.py:226 urls.py:520 msgid "edit/" -msgstr "編輯/" +msgstr "edit/" #: urls.py:85 msgid "subscriptions/" -msgstr "" +msgstr "subscriptions/" #: urls.py:94 msgid "select_languages/" -msgstr "" +msgstr "select_languages/" #: urls.py:105 msgid "groups/" -msgstr "" +msgstr "groups/" #: urls.py:110 msgid "users/update_has_custom_avatar/" -msgstr "" +msgstr "users/update_has_custom_avatar/" #: urls.py:115 urls.py:120 msgid "badges/" -msgstr "å¾½ç« /" +msgstr "badges/" #: urls.py:133 msgid "feedback/" -msgstr "" +msgstr "feedback/" #: urls.py:154 msgid "about/" -msgstr "關於/" +msgstr "about/" #: urls.py:155 msgid "faq/" -msgstr "" +msgstr "faq/" #: urls.py:156 msgid "privacy/" -msgstr "" +msgstr "privacy/" #: urls.py:157 msgid "help/" -msgstr "" +msgstr "help/" #: urls.py:159 urls.py:164 msgid "answers/" -msgstr "" +msgstr "answers/" #: urls.py:164 urls.py:256 msgid "revisions/" -msgstr "版本/" +msgstr "revisions/" #: urls.py:221 urls.py:226 urls.py:231 urls.py:236 urls.py:241 urls.py:246 #: urls.py:256 msgid "questions/" -msgstr "å•é¡Œ/" +msgstr "questions/" #: urls.py:221 urls.py:495 urls.py:500 urls.py:505 urls.py:510 msgid "ask/" -msgstr "æå•/" +msgstr "ask/" #: urls.py:231 msgid "retag/" -msgstr "" +msgstr "retag/" #: urls.py:236 msgid "close/" -msgstr "" +msgstr "close/" #: urls.py:241 msgid "reopen/" -msgstr "" +msgstr "reopen/" #: urls.py:246 msgid "answer/" -msgstr "" +msgstr "answer/" #: urls.py:314 msgid "tags/subscriptions/" -msgstr "" +msgstr "tags/subscriptions/" #: urls.py:319 msgid "tags/subscriptions/delete/" -msgstr "" +msgstr "tags/subscriptions/delete/" #: urls.py:324 msgid "tags/subscriptions/create/" -msgstr "" +msgstr "tags/subscriptions/create/" #: urls.py:329 msgid "tags/subscriptions/edit/" -msgstr "" +msgstr "tags/subscriptions/edit/" #: urls.py:334 msgid "suggested-tags/" -msgstr "" +msgstr "suggested-tags/" #: urls.py:459 msgid "messages/" -msgstr "" +msgstr "messages/" #: urls.py:459 msgid "markread/" -msgstr "" +msgstr "markread/" #: urls.py:490 urls.py:495 urls.py:500 urls.py:505 urls.py:510 urls.py:515 #: urls.py:520 urls.py:525 urls.py:530 msgid "widgets/" -msgstr "" +msgstr "widgets/" #: urls.py:510 deps/django_authopenid/urls.py:20 msgid "complete/" -msgstr "" +msgstr "complete/" #: urls.py:515 msgid "create/" -msgstr "" +msgstr "create/" #: urls.py:525 msgid "delete/" -msgstr "" +msgstr "delete/" #: urls.py:560 msgid "upload/" -msgstr "" +msgstr "upload/" #: urls.py:585 setup_templates/settings.py:229 #: templates/authopenid/providers_javascript.html:7 msgid "account/" -msgstr "" +msgstr "account/" #: conf/access_control.py:8 msgid "Access control settings" @@ -590,7 +593,7 @@ msgstr "" #: conf/badges.py:13 msgid "Badge settings" -msgstr "" +msgstr "å¾½ç« è¨å®š" #: conf/badges.py:23 msgid "Disciplined: minimum upvotes for deleted post" @@ -690,7 +693,7 @@ msgstr "" #: conf/email.py:15 msgid "Email and email alert settings" -msgstr "" +msgstr "é›»å信箱以åŠä¿¡ç®±é€šçŸ¥è¨å®š" #: conf/email.py:24 msgid "Prefix for the email subject line" @@ -880,7 +883,7 @@ msgstr "" #: conf/external_keys.py:19 msgid "Google site verification key" -msgstr "" +msgstr "Google å”作平å°é©—è‰é‡‘é‘°" #: conf/external_keys.py:21 #, python-format @@ -922,7 +925,7 @@ msgstr "" #: conf/external_keys.py:84 msgid "Facebook public API key" -msgstr "" +msgstr "Facebook 公開 API 金鑰" #: conf/external_keys.py:86 #, python-format @@ -934,7 +937,7 @@ msgstr "" #: conf/external_keys.py:99 msgid "Facebook secret key" -msgstr "" +msgstr "Facebook ç§é‘°" #: conf/external_keys.py:107 msgid "Twitter consumer key" @@ -1345,7 +1348,7 @@ msgstr "" #: conf/karma_and_badges_visibility.py:47 msgid "Badges can be either publicly shown or completely hidden" -msgstr "" +msgstr "å¾½ç« å¯ä»¥å…¬é–‹å±•ç¤ºï¼Œä¹Ÿå¯ä»¥å®Œå…¨éš±è—" #: conf/ldap.py:9 msgid "LDAP login configuration" @@ -1572,7 +1575,7 @@ msgstr "" #: conf/login_providers.py:60 msgid "Upload your icon" -msgstr "" +msgstr "上傳您的圖示" #: conf/login_providers.py:93 msgid "local password" @@ -1894,7 +1897,7 @@ msgstr "" #: conf/sidebar_main.py:12 msgid "Main page sidebar" -msgstr "" +msgstr "首é 資訊看æ¿" #: conf/sidebar_main.py:20 conf/sidebar_question.py:67 msgid "Custom sidebar header" @@ -1959,7 +1962,7 @@ msgstr "" #: conf/sidebar_profile.py:12 msgid "User profile sidebar" -msgstr "" +msgstr "使用者資料資訊看æ¿" #: conf/sidebar_profile.py:20 msgid "Custom sidebar" @@ -2000,11 +2003,11 @@ msgstr "" #: conf/sidebar_question.py:92 msgid "Show tag list in sidebar" -msgstr "" +msgstr "資訊看æ¿é¡¯ç¤ºæ¨™ç±¤æ¸…å–®" #: conf/sidebar_question.py:94 msgid "Uncheck this if you want to hide the tag list from the sidebar " -msgstr "" +msgstr "若您想在資訊看æ¿éš±è—標籤清單,請å–消勾é¸æ¤é …" #: conf/sidebar_question.py:105 msgid "Show meta information in sidebar" @@ -2297,7 +2300,7 @@ msgstr "" #: conf/skin_general_settings.py:234 msgid "Apply custom style sheet (CSS)" -msgstr "" +msgstr "套用自訂樣å¼è¡¨ (CSS)" #: conf/skin_general_settings.py:236 msgid "" @@ -2307,7 +2310,7 @@ msgstr "" #: conf/skin_general_settings.py:248 msgid "Custom style sheet (CSS)" -msgstr "" +msgstr "自訂樣å¼è¡¨ (CSS)" #: conf/skin_general_settings.py:250 msgid "" @@ -2320,7 +2323,7 @@ msgstr "" #: conf/skin_general_settings.py:266 msgid "Add custom javascript" -msgstr "" +msgstr "åŠ å…¥è‡ªè¨‚ JavaScript" #: conf/skin_general_settings.py:269 msgid "Check to enable javascript that you can enter in the next field" @@ -2501,7 +2504,7 @@ msgstr "" #: conf/user_settings.py:134 msgid "Default Gravatar icon type" -msgstr "" +msgstr "é è¨ Gravatar 圖示類型" #: conf/user_settings.py:136 msgid "" @@ -2714,7 +2717,7 @@ msgstr "修改回ç”" #: const/__init__.py:201 msgid "received badge" -msgstr "" +msgstr "æ”¶åˆ°çš„å¾½ç« " #: const/__init__.py:202 msgid "marked best answer" @@ -2903,7 +2906,7 @@ msgstr "" #: const/__init__.py:424 msgid "Gravatar" -msgstr "" +msgstr "Gravatar" #: const/__init__.py:425 msgid "Uploaded Avatar" @@ -3096,39 +3099,39 @@ msgstr "" #: deps/django_authopenid/urls.py:14 deps/django_authopenid/urls.py:20 #: deps/django_authopenid/urls.py:23 setup_templates/settings.py:229 msgid "signin/" -msgstr "" +msgstr "signin/" #: deps/django_authopenid/urls.py:15 msgid "widget/signin/" -msgstr "" +msgstr "widget/signin/" #: deps/django_authopenid/urls.py:18 msgid "signout/" -msgstr "" +msgstr "signout/" #: deps/django_authopenid/urls.py:23 msgid "complete-oauth/" -msgstr "" +msgstr "complete-oauth/" #: deps/django_authopenid/urls.py:32 msgid "register/" -msgstr "" +msgstr "register/" #: deps/django_authopenid/urls.py:34 msgid "signup/" -msgstr "" +msgstr "signup/" #: deps/django_authopenid/urls.py:38 msgid "logout/" -msgstr "" +msgstr "logout/" #: deps/django_authopenid/urls.py:43 msgid "recover/" -msgstr "" +msgstr "recover/" #: deps/django_authopenid/urls.py:45 msgid "verify-email/" -msgstr "" +msgstr "verify-email/" #: deps/django_authopenid/util.py:379 #, python-format @@ -3146,7 +3149,7 @@ msgstr "" #: deps/django_authopenid/util.py:486 msgid "Sign in with Yahoo" -msgstr "" +msgstr "使用 Yahoo 帳號登入" #: deps/django_authopenid/util.py:493 msgid "AOL screen name" @@ -3329,12 +3332,12 @@ msgstr "" #: deps/livesettings/values.py:251 msgid "Default value: " -msgstr "" +msgstr "é è¨å€¼ï¼š" #: deps/livesettings/values.py:254 #, python-format msgid "Default value: %s" -msgstr "" +msgstr "é è¨å€¼ï¼š%s" #: deps/livesettings/values.py:641 #, python-format @@ -3578,7 +3581,7 @@ msgstr "" #: models/__init__.py:921 msgid "" "Sorry, since your account is suspended you can edit only your own posts" -msgstr "" +msgstr "很抱æ‰ï¼Œç”±æ–¼æ‚¨çš„帳號已被åœæ¬Šï¼Œå› æ¤åªèƒ½ç·¨è¼¯è‡ªå·±çš„貼文。" #: models/__init__.py:926 #, python-format @@ -3620,7 +3623,7 @@ msgstr "" #: models/__init__.py:1040 msgid "Sorry, since your account is blocked you cannot close questions" -msgstr "" +msgstr "很抱æ‰ï¼Œç”±æ–¼æ‚¨çš„帳號已éå°éŽ–ï¼Œå› æ¤ç„¡æ³•é—œé–‰å•é¡Œã€‚" #: models/__init__.py:1044 msgid "Sorry, since your account is suspended you cannot close questions" @@ -3741,7 +3744,7 @@ msgstr "" #: models/__init__.py:1274 msgid "" "Sorry, since your account is suspended you can delete only your own comments" -msgstr "" +msgstr "很抱æ‰ï¼Œç”±æ–¼æ‚¨çš„帳號已被åœæ¬Šï¼Œå› æ¤åªèƒ½åˆªé™¤è‡ªå·±çš„留言" #: models/__init__.py:1278 #, python-format @@ -3769,13 +3772,13 @@ msgstr "" #, python-format msgid "in %(hr)d hour" msgid_plural "in %(hr)d hours" -msgstr[0] "" +msgstr[0] "æ–¼ %(hr)d å°æ™‚å‰" #: models/__init__.py:2003 #, python-format msgid "in %(min)d min" msgid_plural "in %(min)d mins" -msgstr[0] "" +msgstr[0] "æ–¼ %(min)d 分é˜å‰" #: models/__init__.py:2004 #, python-format @@ -3804,7 +3807,7 @@ msgstr "" #: models/__init__.py:2302 msgid "Suspended User" -msgstr "" +msgstr "åœæ¬Šçš„使用者" #: models/__init__.py:2304 msgid "Blocked User" @@ -3831,19 +3834,19 @@ msgstr "" #, python-format msgid "one gold badge" msgid_plural "%(count)d gold badges" -msgstr[0] "" +msgstr[0] "%(count)d 個金牌" #: models/__init__.py:2515 #, python-format msgid "one silver badge" msgid_plural "%(count)d silver badges" -msgstr[0] "" +msgstr[0] "%(count)d 個銀牌" #: models/__init__.py:2522 #, python-format msgid "one bronze badge" msgid_plural "%(count)d bronze badges" -msgstr[0] "" +msgstr[0] "%(count)d 個銅牌" #: models/__init__.py:2533 #, python-format @@ -4545,12 +4548,12 @@ msgstr "" #: templates/badge.html:5 msgid "Badge" -msgstr "çŽç‰Œ" +msgstr "å¾½ç« " #: templates/badge.html:7 #, python-format msgid "Badge \"%(name)s\"" -msgstr "" +msgstr "「%(name)sã€å¾½ç« " #: templates/badge.html:9 templates/user_profile/user_recent.html:16 #: templates/user_profile/user_stats.html:71 @@ -4561,11 +4564,11 @@ msgstr "" #: templates/badge.html:14 msgid "user received this badge:" msgid_plural "users received this badge:" -msgstr[0] "" +msgstr[0] "使用者收到æ¤å¾½ç« :" #: templates/badges.html:3 templates/badges.html.py:5 msgid "Badges" -msgstr "çŽå‹µ" +msgstr "å¾½ç« " #: templates/badges.html:7 msgid "Community gives you awards for your questions, answers and votes." @@ -4579,7 +4582,7 @@ msgstr "" #: templates/badges.html:31 msgid "Community badges" -msgstr "社群çŽå‹µ" +msgstr "å¾½ç« ç‰ç´š" #: templates/badges.html:33 msgid "gold badge: the highest honor and is very rare" @@ -5350,7 +5353,7 @@ msgstr "" #: templates/subscribe_for_tags.html:15 msgid "Subscribe" -msgstr "" +msgstr "訂閱" #: templates/tags.html:17 msgid "search for tags" @@ -5552,7 +5555,7 @@ msgstr "登出" #: templates/authopenid/logout.html:5 msgid "You have successfully logged out" -msgstr "" +msgstr "您已æˆåŠŸç™»å‡º" #: templates/authopenid/logout.html:7 msgid "" @@ -5651,12 +5654,12 @@ msgstr "" #: templates/authopenid/signin.html:126 #: templates/authopenid/widget_signin.html:129 msgid "New password" -msgstr "" +msgstr "新的密碼" #: templates/authopenid/signin.html:135 #: templates/authopenid/widget_signin.html:138 msgid "Please, retype" -msgstr "" +msgstr "è«‹é‡æ–°è¼¸å…¥" #: templates/authopenid/signin.html:145 #: templates/authopenid/widget_signin.html:148 @@ -6489,7 +6492,7 @@ msgstr "" #: templates/question/new_answer_form.html:12 msgid "Login/Signup to Answer" -msgstr "" +msgstr "登入或註冊回ç”å•é¡Œ" #: templates/question/new_answer_form.html:20 msgid "Your answer" @@ -7084,7 +7087,7 @@ msgstr "" #: templates/user_profile/user_moderate.html:83 msgid "Suspended users can only edit or delete their own posts." -msgstr "" +msgstr "é到åœæ¬Šçš„使用者åªèƒ½ç·¨è¼¯æˆ–刪除自己的貼文。" #: templates/user_profile/user_moderate.html:86 msgid "" @@ -7437,7 +7440,7 @@ msgstr "用戶" #: templates/widgets/meta_nav.html:27 msgid "badges" -msgstr "çŽå‹µæ¦œ" +msgstr "å¾½ç« " #: templates/widgets/question_edit_tips.html:5 msgid "ask a question interesting to this community" @@ -7533,7 +7536,7 @@ msgstr "" #: templates/widgets/user_long_score_and_badge_summary.html:15 msgid "badges:" -msgstr "" +msgstr "å¾½ç« ï¼š" #: templates/widgets/user_navigation.html:17 msgid "sign out" diff --git a/askbot/locale/zh_TW/LC_MESSAGES/djangojs.mo b/askbot/locale/zh_TW/LC_MESSAGES/djangojs.mo Binary files differindex e66fa4e9..534b2ac4 100644 --- a/askbot/locale/zh_TW/LC_MESSAGES/djangojs.mo +++ b/askbot/locale/zh_TW/LC_MESSAGES/djangojs.mo diff --git a/askbot/locale/zh_TW/LC_MESSAGES/djangojs.po b/askbot/locale/zh_TW/LC_MESSAGES/djangojs.po index aecd2bcf..1132bf48 100644 --- a/askbot/locale/zh_TW/LC_MESSAGES/djangojs.po +++ b/askbot/locale/zh_TW/LC_MESSAGES/djangojs.po @@ -3,13 +3,14 @@ # This file is distributed under the same license as the PACKAGE package. # # Translators: +# carl_tw, 2013 msgid "" msgstr "" "Project-Id-Version: askbot\n" "Report-Msgid-Bugs-To: http://askbot.org/\n" "POT-Creation-Date: 2013-07-13 14:07-0500\n" -"PO-Revision-Date: 2013-08-02 06:31+0000\n" -"Last-Translator: evgeny <evgeny.fadeev@gmail.com>\n" +"PO-Revision-Date: 2013-09-02 17:13+0000\n" +"Last-Translator: carl_tw\n" "Language-Team: Chinese (Taiwan) (http://www.transifex.com/projects/p/askbot/language/zh_TW/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -77,7 +78,7 @@ msgstr "" #: media/js/group_messaging.js:139 msgid "Your message:" -msgstr "" +msgstr "您的訊æ¯ï¼š" #: media/js/group_messaging.js:152 msgid "send" @@ -90,7 +91,7 @@ msgstr "å–消" #: media/js/group_messaging.js:227 msgid "Reply" -msgstr "" +msgstr "回覆" #: media/js/group_messaging.js:236 media/js/group_messaging.js.c:743 msgid "message sent" @@ -316,7 +317,7 @@ msgstr "請輸入å•é¡Œæ¨™é¡Œ (>10 個å—å…ƒ)" #: media/js/post.js:2612 media/js/post.js.c:4626 msgid "Sorry, you have only read access" -msgstr "" +msgstr "很抱æ‰ï¼Œæ‚¨åªæ“有讀å–權é™" #: media/js/post.js:3075 media/js/post.js.c:3869 media/js/post.js.c:4058 msgid "save" @@ -351,7 +352,7 @@ msgstr[0] "" #: media/js/post.js:3799 msgid "Delete category?" -msgstr "" +msgstr "是å¦åˆªé™¤åˆ†é¡žï¼Ÿ" #: media/js/post.js:3888 media/js/utils.js:881 msgid "edit" @@ -379,15 +380,15 @@ msgstr "" #: media/js/post.js:4710 msgid "Group name:" -msgstr "" +msgstr "群組å稱:" #: media/js/post.js:4736 msgid "Shared with the following users:" -msgstr "" +msgstr "與這些使用者共享:" #: media/js/post.js:4742 msgid "Shared with the following groups:" -msgstr "" +msgstr "與這些群組共享:" #: media/js/tag_selector.js:14 msgid "Tag \"<span></span>\" matches:" @@ -410,7 +411,7 @@ msgstr[0] "是å¦è¦åˆªé™¤é€™äº›é€šçŸ¥ï¼Ÿ" #: media/js/user.js:66 msgid "Close this entry?" msgid_plural "Close these entries?" -msgstr[0] "" +msgstr[0] "是å¦é—œé–‰é€™äº›é …目?" #: media/js/user.js:74 msgid "Remove all flags and approve this entry?" @@ -419,23 +420,23 @@ msgstr[0] "" #: media/js/user.js:223 msgid "Post deleted" -msgstr "" +msgstr "您的貼文已經刪除" #: media/js/user.js:225 msgid "Post approved" -msgstr "" +msgstr "您的貼文已經æ¢å¾©äº†ï¼" #: media/js/user.js:246 msgid "Accept" -msgstr "" +msgstr "接å—" #: media/js/user.js:255 msgid "Reject" -msgstr "" +msgstr "拒絕" #: media/js/user.js:270 msgid "add new reject reason" -msgstr "" +msgstr "æ–°å¢žæ‹’çµ•åŽŸå› " #: media/js/user.js:375 msgid "Looks there are some things to fix:" @@ -478,11 +479,11 @@ msgstr "跟隨 %s" #: media/js/user.js:883 msgid "add group" -msgstr "" +msgstr "åŠ å…¥ç¾¤çµ„" #: media/js/user.js:963 msgid "add" -msgstr "" +msgstr "åŠ å…¥" #: media/js/utils.js:99 msgid "and" @@ -502,16 +503,16 @@ msgstr "" #: media/js/utils.js:958 msgid "Ok" -msgstr "" +msgstr "確定" #: media/js/utils.js:959 media/js/utils.js.c:1407 msgid "Cancel" -msgstr "" +msgstr "å–消" #: media/js/utils.js:1219 #, c-format msgid "Uploaded file: %s" -msgstr "" +msgstr "已上傳檔案:%s" #: media/js/utils.js:1234 msgid "Choose a different image" @@ -544,27 +545,27 @@ msgstr "" #: media/js/utils.js:1406 msgid "Save" -msgstr "" +msgstr "儲å˜" #: media/js/utils.js:1478 msgid "saved" -msgstr "" +msgstr "已儲å˜" #: media/js/utils.js:1602 msgid "enabled" -msgstr "" +msgstr "已啟用" #: media/js/utils.js:1604 msgid "disabled" -msgstr "" +msgstr "å·²åœç”¨" #: media/js/utils.js:2038 msgid "group name" -msgstr "" +msgstr "群組å稱" #: media/js/utils.js:2046 msgid "add new group" -msgstr "" +msgstr "åŠ å…¥æ–°çš„ç¾¤çµ„" #: media/js/utils.js:2138 msgid "Group %(name)s already exists. Group names are case-insensitive." @@ -577,7 +578,7 @@ msgstr "查看標有「%sã€çš„å•é¡Œ" #: media/js/utils.js:3358 msgid "ago" -msgstr "" +msgstr "å‰" #: media/js/utils.js:3359 msgid "from now" @@ -585,48 +586,48 @@ msgstr "" #: media/js/utils.js:3361 msgid "about a minute" -msgstr "" +msgstr "約一分é˜" #: media/js/utils.js:3362 #, c-format msgid "%d minutes" -msgstr "" +msgstr "%d 分é˜" #: media/js/utils.js:3363 msgid "about an hour" -msgstr "" +msgstr "約一個å°æ™‚" #: media/js/utils.js:3364 #, c-format msgid "%d hours" -msgstr "" +msgstr "%d å°æ™‚" #: media/js/utils.js:3365 media/js/utils.js.c:3493 msgid "yesterday" -msgstr "" +msgstr "昨天" #: media/js/utils.js:3366 #, c-format msgid "%d days" -msgstr "" +msgstr "%d 天" #: media/js/utils.js:3367 msgid "about a month" -msgstr "" +msgstr "約一個月" #: media/js/utils.js:3368 #, c-format msgid "%d months" -msgstr "" +msgstr "%d 個月" #: media/js/utils.js:3369 msgid "about a year" -msgstr "" +msgstr "約一年" #: media/js/utils.js:3370 #, c-format msgid "%d years" -msgstr "" +msgstr "%d å¹´" #: media/js/utils.js:3468 msgid "Jan" @@ -678,23 +679,23 @@ msgstr "" #: media/js/utils.js:3491 msgid "2 days ago" -msgstr "" +msgstr "2 天å‰" #: media/js/utils.js:3498 #, c-format msgid "%s hour ago" msgid_plural "%s hours ago" -msgstr[0] "" +msgstr[0] "%s å°æ™‚å‰" #: media/js/utils.js:3508 #, c-format msgid "%s min ago" msgid_plural "%s mins ago" -msgstr[0] "" +msgstr[0] "%s 分é˜å‰" #: media/js/tinymce/plugins/askbot_attachment/editor_plugin.js:71 msgid "Insert a file" -msgstr "" +msgstr "æ’入檔案" #: media/js/tinymce/plugins/askbot_imageuploader/editor_plugin.js:70 msgid "Insert image" diff --git a/askbot/mail/__init__.py b/askbot/mail/__init__.py index 6fb88443..cb6f86a0 100644 --- a/askbot/mail/__init__.py +++ b/askbot/mail/__init__.py @@ -109,14 +109,14 @@ def _send_mail(subject_line, body_text, sender_email, recipient_list, headers=No msg.send() def send_mail( - subject_line = None, - body_text = None, - from_email = django_settings.DEFAULT_FROM_EMAIL, - recipient_list = None, - activity_type = None, - related_object = None, - headers = None, - raise_on_failure = False, + subject_line=None, + body_text=None, + from_email=None, + recipient_list=None, + activity_type=None, + related_object=None, + headers=None, + raise_on_failure=False, ): """ todo: remove parameters not relevant to the function @@ -131,6 +131,8 @@ def send_mail( if raise_on_failure is True, exceptions.EmailNotSent is raised """ + from_email = from_email or askbot_settings.ADMIN_EMAIL or \ + django_settings.DEFAULT_FROM_EMAIL body_text = absolutize_urls(body_text) try: assert(subject_line is not None) @@ -178,12 +180,12 @@ def mail_moderators( ) -INSTRUCTIONS_PREAMBLE = ugettext_lazy('<p>To ask by email, please:</p>') +INSTRUCTIONS_PREAMBLE = ugettext_lazy('<p>To post by email, please:</p>') QUESTION_TITLE_INSTRUCTION = ugettext_lazy( '<li>Type title in the subject line</li>' ) QUESTION_DETAILS_INSTRUCTION = ugettext_lazy( - '<li>Type details of your question into the email body</li>' + '<li>Type details into the email body</li>' ) OPTIONAL_TAGS_INSTRUCTION = ugettext_lazy( """<li>The beginning of the subject line can contain tags, @@ -209,7 +211,7 @@ def bounce_email( """ if reason == 'problem_posting': error_message = _( - '<p>Sorry, there was an error posting your question ' + '<p>Sorry, there was an error while processing your message ' 'please contact the %(site)s administrator</p>' ) % {'site': askbot_settings.APP_SHORT_NAME} @@ -236,7 +238,7 @@ def bounce_email( elif reason == 'unknown_user': error_message = _( - '<p>Sorry, in order to post questions on %(site)s ' + '<p>Sorry, in order to make posts to %(site)s ' 'by email, please <a href="%(url)s">register first</a></p>' ) % { 'site': askbot_settings.APP_SHORT_NAME, @@ -244,7 +246,7 @@ def bounce_email( } elif reason == 'permission_denied' and body_text is None: error_message = _( - '<p>Sorry, your question could not be posted ' + '<p>Sorry, your post could not be made by email ' 'due to insufficient privileges of your user account</p>' ) elif body_text: diff --git a/askbot/management/commands/askbot_add_osqa_content.py b/askbot/management/commands/askbot_add_osqa_content.py new file mode 100644 index 00000000..6820a036 --- /dev/null +++ b/askbot/management/commands/askbot_add_osqa_content.py @@ -0,0 +1,481 @@ +from askbot.deps.django_authopenid.models import UserAssociation +from askbot.management.commands.base import BaseImportXMLCommand +from askbot.models import Award +from askbot.models import BadgeData +from askbot.models import Post +from askbot.models import PostRevision +from askbot.models import Thread +from askbot.models import Tag +from askbot.models import User +from askbot.utils.slug import slugify_camelcase +from bs4 import BeautifulSoup +from datetime import datetime +from django.db.models import Q +from django.utils import translation +from django.conf import settings as django_settings +from django.utils.http import urlquote as django_urlquote +from django.template.defaultfilters import slugify +from HTMLParser import HTMLParser + +def decode_datetime(data): + """Decodes formats: + * '2013-10-25 09:46:34' + * '2013-10-25' + """ + if data: + try: + return datetime.strptime(data, '%Y-%m-%d %H:%M:%S') + except ValueError: + return datetime.strptime(data, '%Y-%m-%d') + return None + +class DataObject(object): + def __init__(self, soup): + """Initializes object based on the values passed + via BeautifulSoup instance for that object""" + self.soup = soup + self.data = dict() + + def decode_typed_value(self, field): + field_type = field['type'] + value = field.text.strip() + if field_type == 'BooleanField': + if value == 'False': + return False + else: + return True + elif field_type in ('CharField', 'TextField'): + return value + elif 'Integer' in field_type: + return int(value) + elif field_type in ('DateField', 'DateTimeField'): + return decode_datetime(value) + else: + raise ValueError('unknown field type: %s' % field_type) + + def decode_rel_value(self, field): + rel_type = field['rel'] + if rel_type in ('ManyToOneRel', 'OneToOneRel'): + try: + return int(field.text) + except: + return None + elif rel_type == 'ManyToManyRel': + items = field.find_all('object') + return [item['pk'] for item in items] + else: + raise ValueError('unknown relation type %s' % rel_type) + + def decode_value(self, key): + """ + type="DateField"> + type="DateTimeField"> + """ + if key in ('pk', 'id'): + return int(self.soup['pk']) + field = self.soup.find('field', attrs={'name': key}) + if field is None: + raise ValueError('could not find field %s' % key) + if field.get('type') != None: + return self.decode_typed_value(field) + elif field.get('rel') != None: + return self.decode_rel_value(field) + else: + raise ValueError('unknown field class %s - neither data nor relation') + + + def __getattr__(self, key): + """Returns value of property, if decoded + or decodes the property first from the bs4 soup""" + if key not in self.data: + value = self.decode_value(key) + self.data[key] = value + return self.data[key] + + +class Command(BaseImportXMLCommand): + args = '<xml file>' + help = 'Adds XML OSQA data produced by the "dumpdata" command' + + def handle(self, *args, **options): + translation.activate(django_settings.LANGUAGE_CODE) + + self.setup_run() + self.redirect_format = self.get_redirect_format(options['redirect_format']) + + dump_file_name = args[0] + xml = open(dump_file_name, 'r').read() + self.soup = BeautifulSoup(xml, ['lxml', 'xml']) + + #site settings + #forum.keyvalue + self.import_users() + self.import_user_logins() + #model="forum.tag" + self.import_tags() + + #model="forum.question"/answer/comment - derivatives of the Node model + self.import_threads() + self.import_posts('question', True) + #inside we also mark accepted answer, b/c it's more convenient that way + self.import_posts('answer') + self.import_posts('comment') + #model="forum.noderevision" + self.import_post_revisions() + + self.fix_answer_counts() + self.fix_comment_counts() + + #model="forum.subscriptionsettings" + #this model has no correspondence in Askbot + + #model="forum.actionrepute" + #model="forum.award" + + #model="forum.nodestate" + + #model="forum.question" + #model="forum.questionsubscription" + #model="forum.userproperty" + #model="forum.validationhash" + #model="forum.vote" + + #self.import_marked_tags() + + #self.apply_groups_to_threads() + + #self.apply_question_followers() + self.import_votes() + + self.import_badges() + #self.import_badge_awards() + + def get_objects_for_model(self, model): + objects_soup = self.soup.find_all(attrs={'model': model}) + for item_soup in objects_soup: + yield DataObject(item_soup) + + def import_users(self): + """import OSQA users to Askbot users""" + #in OSQA user profile is split in two models + #auth.user + #forum.user + for from_user in self.get_objects_for_model('auth.user'): + try: + to_user = User.objects.get(email=from_user.email) + except User.DoesNotExist: + username = self.get_safe_username(from_user.username) + to_user = User.objects.create_user(username, from_user.email) + + self.copy_string_parameter(from_user, to_user, 'first_name') + self.copy_string_parameter(from_user, to_user, 'last_name') + self.copy_string_parameter(from_user, to_user, 'password') + self.copy_bool_parameter(from_user, to_user, 'is_staff') + self.copy_bool_parameter(from_user, to_user, 'is_active') + self.copy_bool_parameter(from_user, to_user, 'is_superuser') + self.copy_numeric_parameter(from_user, to_user, 'last_login', operator='max') + self.copy_numeric_parameter(from_user, to_user, 'date_joined', operator='min') + to_user.save() + + self.log_action(from_user, to_user) + + for profile in self.get_objects_for_model('forum.user'): + user = self.get_imported_object_by_old_id(User, profile.id) + self.copy_bool_parameter(profile, user, 'email_isvalid') + user.reputation = max(user.reputation + profile.reputation - 1, 1) + user.gold += profile.gold + user.silver += profile.silver + user.bronze += profile.bronze + self.copy_string_parameter(profile, user, 'real_name') + self.copy_numeric_parameter(profile, user, 'last_seen', operator='max') + self.copy_string_parameter(profile, user, 'website') + self.copy_string_parameter(profile, user, 'location') + self.copy_numeric_parameter(profile, user, 'date_of_birth') + self.copy_string_parameter(profile, user, 'about') + user.save() + + def import_user_logins(self): + """import user's login methods from OSQA to Askbot""" + for user_login in self.get_objects_for_model('forum.authkeyuserassociation'): + assoc = UserAssociation() + assoc.openid_url = user_login.key + assoc.user = self.get_imported_object_by_old_id(User, user_login.user) + assoc.provider_name = user_login.provider + assoc.last_used_timestamp = user_login.added_at + assoc.save() + + def import_tags(self): + """imports OSQA tags to Askbot tags""" + """ + <object model="forum.tag" pk="2"> + <field name="name" type="CharField"> + pro + </field> + <field name="created_by" rel="ManyToOneRel" to="forum.user"> + 1 + </field> + <field name="created_at" type="DateTimeField"> + 2012-06-09 18:34:13 + </field> + <field name="used_count" type="PositiveIntegerField"> + 259 + </field> + </object> + """ + for osqa_tag in self.get_objects_for_model('forum.tag'): + tag = Tag() + tag.name = osqa_tag.name + tag.created_by = self.get_imported_object_by_old_id(User, osqa_tag.created_by) + tag.used_count = osqa_tag.used_count + tag.save() + + def import_badges(self): + """remembers relation of OSQA badges with Askbot badges""" + #model="forum.badge" + for osqa_badge in self.get_objects_for_model('forum.badge'): + badge_slug = slugify_camelcase(osqa_badge.cls) + try: + askbot_badge = BadgeData.objects.get(slug=badge_slug) + except BadgeData.DoesNotExist: + print 'Could not find an equivalent to badge %s in Askbot' % osqa_badge.cls + continue + self.log_action(osqa_badge, askbot_badge) + """ + <object model="forum.badge" pk="1"> + <field name="type" type="SmallIntegerField"> + 3 + </field> + <field name="cls" type="CharField"> + PopularQuestion + </field> + <field name="awarded_count" type="PositiveIntegerField"> + 0 + </field> + </object> + """ + """ + slug = models.SlugField(max_length=50, unique=True) + awarded_count = models.PositiveIntegerField(default=0) + awarded_to = models.ManyToManyField( + User, through='Award', related_name='badges' + ) + """ + + def import_badge_awards(self): + """Makes sure that users are re-awarded all previously + awarded OSQA badges""" + for osqa_award in self.get_objects_for_model('forum.award'): + user = self.get_imported_object_by_old_id(User, osqa_award.user) + badge = self.get_imported_object_by_old_id(BadgeData, osqa_award.badge) + if badge is None: + continue + print 'awarding badge %s' % badge.slug + #if multiple or user does not have this badge, then award + if badge.is_multiple() or (not user.has_badge(badge)): + award = Award() + award.badge = badge + award.user = user + award.notified = True + #todo: here we need to map to the node object + #content_type = self.get_content_type_by_old_id(award.content_type_id) + #obj_class = content_type.model_class() + #award.object_id = self.get_imported_object_id_by_old_id(obj_class, award.object_id) + #award.content_type = content_type + award.save() + """ + <object model="forum.award" pk="1"> + <field name="user" rel="ManyToOneRel" to="forum.user"> + 1 + </field> + <field name="badge" rel="ManyToOneRel" to="forum.badge"> + 32 + </field> + <field name="node" rel="ManyToOneRel" to="forum.node"> + <None/> + </field> + <field name="awarded_at" type="DateTimeField"> + 2012-06-08 17:49:15 + </field> + <field name="trigger" rel="ManyToOneRel" to="forum.action"> + 4 + </field> + <field name="action" rel="OneToOneRel" to="forum.action"> + 6 + </field> + </object> + """ + + def import_threads(self): + """import thread objects""" + count = 0 + for osqa_thread in self.get_objects_for_model('forum.question'): + count += 1 + #todo: there must be code lated to set the commented values + thread = Thread( + title=osqa_thread.title, + tagnames=osqa_thread.tagnames, + view_count=osqa_thread.extra_count, + #favourite_count=thread.favourite_count, + #answer_count=thread.answer_count, + last_activity_at=osqa_thread.last_activity_at, + last_activity_by=self.get_imported_object_by_old_id(User, osqa_thread.last_activity_by), + language_code=django_settings.LANGUAGE_CODE, + #"closed" data is stored differently in OSQA + #closed_by=self.get_imported_object_by_old_id(User, thread.closed_by_id), + #closed=thread.closed, + #closed_at=thread.closed_at, + #close_reason=thread.close_reason, + #deleted=False, + approved=True, #no equivalent in OSQA + #must be done later, after importing answers + #answer_accepted_at=thread.answer_accepted_at, + added_at=osqa_thread.added_at, + ) + + #apply tags to threads + tag_names = thread.get_tag_names() + if tag_names: + + tag_filter = Q(name__iexact=tag_names[0]) + for tag_name in tag_names[1:]: + tag_filter |= Q(name__iexact=tag_name) + tags = Tag.objects.filter(tag_filter) + + thread.tagnames = ' '.join([tag.name for tag in tags]) + + thread.save() + for tag in tags: + thread.tags.add(tag) + tag.used_count += 1 + tag.save() + + else: + thread.save() + + self.log_action(osqa_thread, thread) + + def import_posts(self, post_type, save_redirects=False): + """imports osqa Nodes to askbot Post objects""" + if save_redirects: + redirects_file = self.open_unique_file('question_redirects') + + models_map = { + 'question': 'forum.question', + 'answer': 'forum.answer', + 'comment': 'forum.comment' + } + + model_name = models_map[post_type] + + for osqa_node in self.get_objects_for_model(model_name): + #we iterate through all nodes, but pick only the ones we need + if osqa_node.node_type != post_type: + continue + + #cheat: do not import deleted content + if '(deleted)' in osqa_node.state_string: + continue + + post = Post() + + #this line is a bit risky, but should work if we import things in correct order + if osqa_node.parent: + post.parent = self.get_imported_object_by_old_id(Post, osqa_node.parent) + if post.parent is None: + continue #deleted parent + post.thread = post.parent.thread + else: + post.thread = self.get_imported_object_by_old_id(Thread, osqa_node.id) + if post.thread is None: + continue #deleted thread + + post.post_type = osqa_node.node_type + post.added_at = osqa_node.added_at + + if save_redirects: + slug = django_urlquote(slugify(osqa_node.title)) + #todo: add i18n to the old url + old_url = '/questions/%d/%s/' % (osqa_node.id, slug) + + post.author = self.get_imported_object_by_old_id(User, osqa_node.author) + #html will de added with the revisions + #post.html = HTMLParser().unescape(osqa_node.body) + post.summary = post.get_snippet() + + #these don't have direct equivalent in the OSQA Node object + #post.deleted_by - deleted nodes are not imported + #post.locked_by + #post.last_edited_by + + #these are to be set later with the real values + post.points = 0 + post.vote_up_count = 0 + post.vote_down_count = 0 + post.offensive_flag_count = 0 + + post.save() + + #mark accepted answer + if osqa_node.node_type == 'answer': + if '(accepted)' in osqa_node.state_string: + post.thread.accepted_answer = post + post.thread.save() + + + if save_redirects: + new_url = post.get_absolute_url() + self.write_redirect(old_url, new_url, redirects_file) + + self.log_action_with_old_id(osqa_node.id, post) + + if save_redirects: + redirects_file.close() + + def import_post_revisions(self): + """Imports OSQA revisions to Askbot revisions""" + for osqa_revision in self.get_objects_for_model('forum.noderevision'): + post = self.get_imported_object_by_old_id(Post, osqa_revision.node) + if post is None: + continue #deleted post + user = self.get_imported_object_by_old_id(User, osqa_revision.author) + revision = PostRevision( + post=post, + author=user, + text=osqa_revision.body, + title=osqa_revision.title, + tagnames=osqa_revision.tagnames, + revised_at=osqa_revision.revised_at, + summary=osqa_revision.summary, + revision=osqa_revision.revision + ) + post.text = osqa_revision.body + if osqa_revision == 1: + post.added_at = osqa_revision.revised_at + else: + post.last_edited_at = osqa_revision.revised_at + post.last_edited_by = user + + post.parse_and_save(author=user) + revision.save() + + def import_votes(self): + """Imports OSQA votes to Askbot votes""" + for osqa_vote in self.get_objects_for_model('forum.vote'): + post = self.get_imported_object_by_old_id(Post, osqa_vote.node) + if post is None: + continue #deleted post + user = self.get_imported_object_by_old_id(User, osqa_vote.user) + if osqa_vote.value > 0: + user.upvote(post, timestamp=osqa_vote.voted_at, force=True) + elif osqa_vote.value < 0: + user.downvote(post, timestamp=osqa_vote.voted_at, force=True) + + def fix_answer_counts(self): + for thread in Thread.objects.all(): + thread.answer_count = thread.get_answers().count() + thread.save() + + def fix_comment_counts(self): + for post in Post.objects.filter(post_type__in=('question', 'answer')): + post.comment_count = Post.objects.filter(post_type='comment', parent=post).count() + post.save() diff --git a/askbot/management/commands/askbot_add_xml_content.py b/askbot/management/commands/askbot_add_xml_content.py new file mode 100644 index 00000000..307a0d76 --- /dev/null +++ b/askbot/management/commands/askbot_add_xml_content.py @@ -0,0 +1,558 @@ +from askbot.models import BadgeData +from askbot.models import FavoriteQuestion +from askbot.models import Group +from askbot.models import ImportedObjectInfo +from askbot.models import Post +from askbot.models import Tag +from askbot.models import Thread +from askbot.models import User +from askbot.management.commands.base import BaseImportXMLCommand +from django.conf import settings as django_settings +from django.contrib.auth.models import Group as AuthGroup +from django.contrib.contenttypes.models import ContentType +from django.db import transaction +from django.db.models import Q + +if 'avatar' in django_settings.INSTALLED_APPS: + from avatar.models import Avatar + +def get_status_rank(status): + """returns integer rank of user account status, + the larger is the number the higher is the status""" + if len(status) != 1: + #default status - approved user + status = 'a' + try: + return 'bswamd'.index(status) + except ValueError: + return 0 + +class Command(BaseImportXMLCommand): + help = 'Adds XML askbot data produced by the "dumpdata" command' + + def handle_import(self): + self.read_content_types() + + self.import_groups() + self.import_users() + #we don't import subscriptions + if 'avatar' in django_settings.INSTALLED_APPS: + self.import_avatars() + + #we need this to link old user ids to + #new users' personal groups + #self.record_personal_groups() + + self.import_user_logins() + self.import_tags() + self.import_marked_tags() + + self.import_threads() + self.apply_groups_to_threads() + + #model="askbot.posttogroup"> + self.import_posts('question', save_redirects=True) + self.import_posts('answer') + self.import_posts('comment') + self.import_post_revisions() + self.apply_groups_to_posts() + self.apply_question_followers() + self.import_votes() + + self.import_badges() + self.import_badge_awards() + self.delete_new_messages() + #we'll try to ignore importing this + #model="askbot.activity" + + def log_personal_group(self, group): + info = ImportedObjectInfo() + info.old_id = group.id + info.new_id = int(group.name.split('_')[-1]) + info.model = 'personal_group' + info.run = self.run + info.save() + + def get_group_by_old_id(self, old_id): + normal_group = self.get_imported_object_by_old_id(AuthGroup, old_id) + if normal_group: + return Group.objects.get(group_ptr=normal_group) + + log = ImportedObjectInfo.objects.get( + model='personal_group', + old_id=old_id, + run=self.run + ) + old_user_id = log.new_id + new_user = self.get_imported_object_by_old_id(User, old_user_id) + return new_user.get_personal_group() + + def read_content_types(self): + """reads content types from the data dump and makes + dictionary with keys of old content type ids and + values - active content type objects""" + ctypes_map = dict() + for old_ctype in self.get_objects_for_model('contenttypes.contenttype'): + try: + new_ctype = ContentType.objects.get( + app_label=old_ctype.app_label, + model=old_ctype.model + ) + except ContentType.DoesNotExist: + continue + ctypes_map[old_ctype.id] = new_ctype + + self.content_types_map = ctypes_map + """ + <object pk="38" model="contenttypes.contenttype"> + <field type="CharField" name="name">activity</field> + <field type="CharField" name="app_label">askbot</field> + <field type="CharField" name="model">activity</field> + </object> + """ + + def get_content_type_by_old_id(self, old_ctype_id): + return self.content_types_map[old_ctype_id] + + @transaction.commit_manually + def import_groups(self): + """imports askbot group profiles""" + + #redirects_file = self.open_unique_file('group_redirects') + + #1) we import auth groups + for group in self.get_objects_for_model('auth.group'): + + #old_url = group.get_absolute_url() + if group.name.startswith('_personal'): + #we don't import these groups, but log + #associations between old user ids and old personal + #group ids, because we create the personal groups + #anew and so need to have a connection + #old personal group id --> old user id --> new user id + # --> new pers. group id + self.log_personal_group(group) + continue + old_group_id = group.id + try: + group = AuthGroup.objects.get(name=group.name) + except AuthGroup.DoesNotExist: + group.id = None + group.save() + + transaction.commit() + + #new_url = group.get_absolute_url() + + #if old_url != new_url: + # redirects_file.write('%s %s\n' % (old_url, new_url)) + + #we will later populate memberships only in these groups + self.log_action_with_old_id(old_group_id, group) + + if transaction.is_dirty(): + transaction.commit() + + #redirects_file.close() + + #2) we import askbot group profiles only for groups + for profile in self.get_objects_for_model('askbot.group'): + auth_group = self.get_imported_object_by_old_id(AuthGroup, profile.group_ptr_id) + if auth_group is None or auth_group.name.startswith('_personal'): + continue + + #if profile for this group does not exist, then create new profile and save + try: + existing_profile = Group.objects.get(group_ptr__id=auth_group.id) + self.copy_string_parameter(profile, existing_profile, 'logo_url') + self.merge_words_parameter(profile, existing_profile, 'preapproved_emails') + self.merge_words_parameter(profile, existing_profile, 'preapproved_email_domains') + existing_profile.save() + except Group.DoesNotExist: + new_profile = Group.objects.create( + name=auth_group.name, + logo_url=profile.logo_url, + preapproved_emails=profile.preapproved_emails, + preapproved_email_domains=profile.preapproved_email_domains + ) + new_profile.save() + + transaction.commit() + + if transaction.is_dirty(): + transaction.commit() + + def import_users(self): + redirects_file = self.open_unique_file('user_redirects') + + model_path = str(User._meta) + dupes = 0 + for from_user in self.get_objects_for_model('auth.user'): + log_info = dict() + log_info['notify_user'] = list() + + old_url = from_user.get_absolute_url() + + try: + to_user = User.objects.get(email=from_user.email) + dupes += 1 + except User.DoesNotExist: + username = self.get_safe_username(from_user.username) + if username != from_user.username: + template = 'Your user name was changed from %s to %s' + log_info['notify_user'].append(template % (from_user.username, username)) + to_user = User.objects.create_user(username, from_user.email) + + #copy the data + if from_user.username != to_user.username: + names = (from_user.username, to_user.username) + log_info['notify_user'].append('Your user name has changed from %s to %s' % names) + + self.copy_string_parameter(from_user, to_user, 'first_name') + self.copy_string_parameter(from_user, to_user, 'last_name') + self.copy_string_parameter(from_user, to_user, 'real_name') + self.copy_string_parameter(from_user, to_user, 'website') + self.copy_string_parameter(from_user, to_user, 'location') + + to_user.country = from_user.country + + self.copy_string_parameter(from_user, to_user, 'about') + self.copy_string_parameter(from_user, to_user, 'email_signature') + self.copy_string_parameter(from_user, to_user, 'twitter_access_token') + self.copy_string_parameter(from_user, to_user, 'twitter_handle') + + self.merge_words_parameter(from_user, to_user, 'interesting_tags') + self.merge_words_parameter(from_user, to_user, 'ignored_tags') + self.merge_words_parameter(from_user, to_user, 'subscribed_tags') + self.merge_words_parameter(from_user, to_user, 'languages') + + if to_user.password == '!' and from_user.password != '!': + to_user.password = from_user.password + self.copy_bool_parameter(from_user, to_user, 'is_staff') + self.copy_bool_parameter(from_user, to_user, 'is_active') + self.copy_bool_parameter(from_user, to_user, 'is_superuser') + self.copy_bool_parameter(from_user, to_user, 'is_fake', operator='and') + self.copy_bool_parameter(from_user, to_user, 'email_isvalid', operator='and') + self.copy_bool_parameter(from_user, to_user, 'show_country') + self.copy_bool_parameter(from_user, to_user, 'show_marked_tags') + + self.copy_numeric_parameter(from_user, to_user, 'last_login') + self.copy_numeric_parameter(from_user, to_user, 'last_seen') + self.copy_numeric_parameter(from_user, to_user, 'date_joined', operator='min') + self.copy_numeric_parameter(from_user, to_user, 'email_tag_filter_strategy') + self.copy_numeric_parameter(from_user, to_user, 'display_tag_filter_strategy') + self.copy_numeric_parameter( + from_user, + to_user, + 'consecutive_days_visit_count', + operator='sum' + ) + self.copy_numeric_parameter(from_user, to_user, 'social_sharing_mode') + + #position of character in this string == rank of status + if get_status_rank(from_user.status) > get_status_rank(to_user.status): + to_user.status = from_user.status + + to_user.save() + + new_url = to_user.get_absolute_url() + self.write_redirect(old_url, new_url, redirects_file) + + group_ids = self.get_m2m_ids_for_field(from_user, 'groups') + for group_id in group_ids: + #get group by old id, + #if group is private - skip, + #otherwise join this group + group = self.get_imported_object_by_old_id(Group, int(group_id)) + if group is None or group.name.startswith('_personal'): + continue + #unfortunately, xml dump does not allow us to know of the membership status + #as m2m user -> group does not contain id of the m2m bridge relation, but + #only id of the group itself + to_user.join_group(group, force=True) + + """ + these were not imported: + <field type="CharField" name="email_key"><None></None></field> + <field type="PositiveIntegerField" name="reputation">1</field> + <field type="SmallIntegerField" name="gold">0</field> + <field type="SmallIntegerField" name="silver">0</field> + <field type="SmallIntegerField" name="bronze">0</field> + <field type="IntegerField" name="new_response_count">0</field> + <field type="IntegerField" name="seen_response_count">0</field> + """ + self.log_action(from_user, to_user, extra_info=log_info) + + redirects_file.close() + + def import_avatars(self): + """imports user avatar, chooses later uploaded primary avatar""" + for avatar in self.get_objects_for_model('avatar.avatar'): + user = self.get_imported_object_by_old_id(User, avatar.user_id) + + if avatar.primary: + #get other primary avatar and make the later one as primary + try: + existing_avatar = Avatar.objects.get(user=user, primary=True) + if existing_avatar.date_uploaded > avatar.date_uploaded: + avatar.primary = False + else: + existing_avatar.primary = False + existing_avatar.save() + except Avatar.DoesNotExist: + pass + + avatar.user = user + avatar.id = None + avatar.save() + """ + <object pk="9" model="avatar.avatar"> + <field to="auth.user" name="user" rel="ManyToOneRel">33</field> + <field type="BooleanField" name="primary">True</field> + <field type="FileField" name="avatar">avatars/Valdir Barbosa/ValdirBarbosa.png</field> + <field type="DateTimeField" name="date_uploaded">2013-08-22T16:45:01.517315</field> + </object> + """ + + def import_marked_tags(self): + #model="askbot.markedtag"> + for mark in self.get_objects_for_model('askbot.markedtag'): + tag = self.get_imported_object_by_old_id(Tag, mark.tag_id) + user = self.get_imported_object_by_old_id(User, mark.user_id) + user.mark_tags(tagnames=tag.name, reason=mark.reason, action='add') + """ + <object pk="1" model="askbot.markedtag"> + <field to="askbot.tag" name="tag" rel="ManyToOneRel">13</field> + <field to="auth.user" name="user" rel="ManyToOneRel">205</field> + <field type="CharField" name="reason">good</field> + </object> + """ + + @transaction.commit_manually + def import_user_logins(self): + #logins_soup = self.soup.find_all('object', {'model': 'django_authopenid.userassociation'}) + #for login_info in self.get_objects_for_model('django_authopenid.userassociation'): + #for login_ + for association in self.get_objects_for_model('django_authopenid.userassociation'): + #where possible, we should copy the login, but respecting the + #uniqueness constraints: ('user','provider_name'), ('openid_url', 'provider_name') + #1) get new user by old id + user = self.get_imported_object_by_old_id(User, association.user_id) + try: + association.id = None + association.user = user + association.save() + transaction.commit() + except: + transaction.rollback() + + def import_tags(self): + """imports tag objects""" + for tag in self.get_objects_for_model('askbot.tag'): + old_tag_id = tag.id + try: + #try to get existing tag with this name + tag = Tag.objects.get(name__iexact=tag.name) + except Tag.DoesNotExist: + tag.id = None + tag.tag_wiki = None + tag.created_by = self.get_imported_object_by_old_id(User, tag.created_by_id) + tag.deleted_by = self.get_imported_object_by_old_id(User, tag.deleted_by_id) + tag.save() + self.log_action_with_old_id(old_tag_id, tag) + + def import_threads(self): + """import thread objects""" + count = 0 + for thread in self.get_objects_for_model('askbot.thread'): + count += 1 + new_thread = Thread( + title=thread.title, + tagnames=thread.tagnames, + view_count=thread.view_count, + favourite_count=thread.favourite_count, + answer_count=thread.answer_count, + last_activity_at=thread.last_activity_at, + last_activity_by=self.get_imported_object_by_old_id(User, thread.last_activity_by_id), + language_code=thread.language_code, + closed_by=self.get_imported_object_by_old_id(User, thread.closed_by_id), + closed=thread.closed, + closed_at=thread.closed_at, + close_reason=thread.close_reason, + deleted=thread.deleted, + approved=thread.approved, + answer_accepted_at=thread.answer_accepted_at, + added_at=thread.added_at, + ) + + #apply tags to threads + tag_names = thread.get_tag_names() + if tag_names: + + tag_filter = Q(name__iexact=tag_names[0]) + for tag_name in tag_names[1:]: + tag_filter |= Q(name__iexact=tag_name) + tags = Tag.objects.filter(tag_filter) + + new_thread.tagnames = ' '.join([tag.name for tag in tags]) + + new_thread.save() + for tag in tags: + new_thread.tags.add(tag) + tag.used_count += 1 + tag.save() + + else: + new_thread.save() + + self.log_action(thread, new_thread) + """ + these are not handled here + <object pk="155" model="askbot.thread"> + <field to="askbot.post" name="accepted_answer" rel="ManyToOneRel"><None></None></field> + <field type="IntegerField" name="points">0</field> + <field to="auth.user" name="followed_by" rel="ManyToManyRel"></field> + </object> + """ + + def apply_question_followers(self): + """mark followed questions""" + for fave in self.get_objects_for_model('askbot.favoritequestion'): + #askbot.favoritequestion + user = self.get_imported_object_by_old_id(User, fave.user_id) + thread = self.get_imported_object_by_old_id(Thread, fave.thread_id) + user.toggle_favorite_question(thread._question_post(), timestamp=fave.added_at) + """ + <object pk="1" model="askbot.favoritequestion"> + <field to="askbot.thread" name="thread" rel="ManyToOneRel">8</field> + <field to="auth.user" name="user" rel="ManyToOneRel">32</field> + <field type="DateTimeField" name="added_at">2012-12-28T17:34:17.289056</field> + </object> + """ + + def apply_groups_to_threads(self): + for link in self.get_objects_for_model('askbot.threadtogroup'): + thread = self.get_imported_object_by_old_id(Thread, link.thread_id) + group = self.get_group_by_old_id(link.group_id) + thread.add_to_groups([group,], visibility=link.visibility) + + def import_posts(self, post_type, save_redirects=False): + """imports posts of specific post_type""" + if save_redirects: + redirects_file = self.open_unique_file('question_redirects') + for post in self.get_objects_for_model('askbot.post'): + if post.post_type != post_type: + continue + + #this line is a bit risky, but should work if we import things in correct order + post.parent = self.get_imported_object_by_old_id(Post, post.parent_id) + + post.thread = self.get_imported_object_by_old_id(Thread, post.thread_id) + + if save_redirects: + old_url = post.get_absolute_url(thread=post.thread) + + post.author = self.get_imported_object_by_old_id(User, post.author_id) + post.deleted_by = self.get_imported_object_by_old_id(User, post.deleted_by_id) + post.locked_by = self.get_imported_object_by_old_id(User, post.locked_by_id) + post.last_edited_by = self.get_imported_object_by_old_id(User, post.last_edited_by_id) + post.points = 0 + post.vote_up_count = 0 + post.vote_down_count = 0 + post.offensive_flag_count = 0 + + old_post_id = post.id + post.id = None + post.save() + + if save_redirects: + new_url = post.get_absolute_url() + self.write_redirect(old_url, new_url, redirects_file) + + self.log_action_with_old_id(old_post_id, post) + + if save_redirects: + redirects_file.close() + + """ + these were not imported + votes + <field type="PositiveIntegerField" name="comment_count">0</field> + <field type="SmallIntegerField" name="offensive_flag_count">0</field> + """ + + def apply_groups_to_posts(self): + for link in self.get_objects_for_model('askbot.posttogroup'): + post = self.get_imported_object_by_old_id(Post, link.post_id) + group = self.get_group_by_old_id(link.group_id) + post.add_to_groups([group,]) + + def import_post_revisions(self): + for revision in self.get_objects_for_model('askbot.postrevision'): + revision.post = self.get_imported_object_by_old_id(Post, revision.post_id) + revision.author = self.get_imported_object_by_old_id(User, revision.author_id) + revision.approved_by = self.get_imported_object_by_old_id(User, revision.approved_by_id) + revision.id = None + revision.save() + + def import_badges(self): + """imports badgedata objects""" + for badge in self.get_objects_for_model('askbot.badgedata'): + #here we need to make sure that we don't create duplicate badges + old_badge_id = badge.id + try: + new_badge = BadgeData.objects.get(slug=badge.slug) + except BadgeData.DoesNotExist: + new_badge = badge + new_badge.id = None + new_badge.awarded_count = 0 #we will re-award this, restart count + new_badge.save() + + self.log_action_with_old_id(old_badge_id, new_badge) + """ + <object pk="36" model="askbot.badgedata"> + <field type="SlugField" name="slug">taxonomist</field> + <field type="PositiveIntegerField" name="awarded_count">9</field> + </object> + """ + + def import_badge_awards(self): + for award in self.get_objects_for_model('askbot.award'): + award.user = self.get_imported_object_by_old_id(User, award.user_id) + badge = self.get_imported_object_by_old_id(BadgeData, award.badge_id) + #if multiple or user does not have this badge, then award + if badge.is_multiple() or (not award.user.has_badge(badge)): + award.badge = badge + content_type = self.get_content_type_by_old_id(award.content_type_id) + obj_class = content_type.model_class() + award.object_id = self.get_imported_object_id_by_old_id(obj_class, award.object_id) + award.content_type = content_type + award.id = None + award.save() + """ + <object pk="1" model="askbot.award"> + <field to="auth.user" name="user" rel="ManyToOneRel">2</field> + <field to="askbot.badgedata" name="badge" rel="ManyToOneRel">10</field> + <field to="contenttypes.contenttype" name="content_type" rel="ManyToOneRel">30</field> + <field type="PositiveIntegerField" name="object_id">1</field> + <field type="DateTimeField" name="awarded_at">2012-10-22T18:09:13.527031</field> + <field type="BooleanField" name="notified">False</field> + </object> + """ + + def import_votes(self): + for vote in self.get_objects_for_model('askbot.vote'): + post = self.get_imported_object_by_old_id(Post, vote.voted_post_id) + user = self.get_imported_object_by_old_id(User, vote.user_id) + if vote.vote == 1: + user.upvote(post, timestamp=vote.voted_at) + else: + user.downvote(post, timestamp=vote.voted_at) + """ + <object pk="1" model="askbot.vote"> + <field to="auth.user" name="user" rel="ManyToOneRel">8</field> + <field to="askbot.post" name="voted_post" rel="ManyToOneRel">20</field> + <field type="SmallIntegerField" name="vote">1</field> + <field type="DateTimeField" name="voted_at">2012-12-26T19:10:08.334818</field> + </object> + """ diff --git a/askbot/management/commands/base.py b/askbot/management/commands/base.py new file mode 100644 index 00000000..dce02e20 --- /dev/null +++ b/askbot/management/commands/base.py @@ -0,0 +1,240 @@ +from askbot.models import Message +from askbot.models import User +from askbot.models import ImportedObjectInfo +from askbot.models import ImportRun +from django.core.management.base import BaseCommand, CommandError +from django.conf import settings as django_settings +from bs4 import BeautifulSoup +from collections import defaultdict +from django.core import serializers +from django.utils.encoding import smart_str +from django.utils.translation import activate as activate_language +from optparse import make_option +import os +import sys +from tempfile import mkstemp + +class BaseImportXMLCommand(BaseCommand): + help = 'Base command for adding XML data from other forums to Askbot' + + option_list = BaseCommand.option_list + ( + make_option('--redirect-format', + action = 'store', + dest = 'redirect_format', + default = 'none', + help = 'Format for the redirect files (apache|nginx|none)' + ), + ) + + def handle(self, *args, **kwargs): + + activate_language(django_settings.LANGUAGE_CODE) + + #init the redirects file format table + self.redirect_format = self.get_redirect_format(kwargs['redirect_format']) + + self.setup_run() + self.read_xml_file(args[0]) + + self.remember_message_ids() + self.handle_import() + self.delete_new_messages() + + def handle_import(self): + """this method should contain the actual work of importing data + + If necessary, create redirect files using methods + redirects_file = self.open_unique_file('user_redirects') + self.write_redirect(old_url, new_url, redirects_file) + redirects_file.close() + where old_url and new_url are urls of the corresponding objects + before and after importation + """ + raise NotImplementedError('Implement this method to import data') + + + def get_redirect_format(self, format_setting): + format_table = { + 'nginx': 'rewrite ^%s$ %s break;\n', + 'apache': 'Redirect permanent %s %s\n', + } + format_table = defaultdict(lambda: '%s %s\n', format_table) + return format_table[format_setting] + + def setup_run(self): + """remembers the run information, + for the logging purposes + """ + command = ' '.join(sys.argv) + run = ImportRun.objects.create(command=command) + self.run = run + + def read_xml_file(self, filename): + """reads xml data int BeautifulSoup instance""" + if not os.path.isfile(filename): + raise CommandError('File %s does not exist') % filename + xml = open(filename, 'r').read() + self.soup = BeautifulSoup(xml, ['lxml', 'xml']) + + def remember_message_ids(self): + """remembers messages ids of existing messages - we use these + to delete any messages added automatically during the import""" + self.message_ids = list(Message.objects.values_list('id', flat=True)) + + def log_action_with_old_id(self, from_object_id, to_object, extra_info=None): + info = ImportedObjectInfo() + info.old_id = from_object_id + info.new_id = to_object.id + info.model = str(to_object._meta) + info.run = self.run + info.extra_info = extra_info or dict() + info.save() + + def log_action(self, from_object, to_object, extra_info=None): + self.log_action_with_old_id(from_object.id, to_object, extra_info=extra_info) + + def get_imported_object_id_by_old_id(self, model_class, old_id): + """Returts id of imported object by old id""" + if old_id is None: + return None + try: + log = ImportedObjectInfo.objects.get( + model=str(model_class._meta), + old_id=old_id, + run=self.run + ) + return log.new_id + except ImportedObjectInfo.DoesNotExist: + return None + + def get_imported_object_by_old_id(self, model_class, old_id): + """Returns new imported object by id of corresponding old object""" + new_id = self.get_imported_object_id_by_old_id(model_class, old_id) + if new_id: + return model_class.objects.get(id=new_id) + return None + + def get_objects_for_model(self, model_name): + """returns iterator of objects from the django + xml dump by name""" + object_soup = self.soup.find_all('object', {'model': model_name}) + for datum in object_soup: + yield self.get_deserialized_object(datum) + + def delete_new_messages(self): + """deletes any messages that were added by askbot during the import process""" + Message.objects.exclude(id__in=self.message_ids).delete() + + def open_unique_file(self, name_hint): + """return a file using name_hint as the hint + for the file name, if file with that name exists, + create a unique file name containing hint as part of + the name""" + if os.path.exists(name_hint): + info = mkstemp(dir=os.getcwd(), prefix=name_hint + '_') + name_hint = info[1] + print 'saving file: %s' % name_hint + return open(name_hint, 'w') + + def write_redirect(self, from_url, to_url, redirects_file): + """writes redirect clause to a file in format + chosen earlier in the `handle` function""" + if from_url != to_url: + redirects_file.write(self.redirect_format % (from_url, to_url)) + + def get_safe_username(self, username): + """get unique username similar to `username` + to avoid the uniqueness clash""" + existing_names = User.objects.filter( + username__istartswith=username + ).values_list('username', flat=True) + + if len(existing_names) == 0: + return username + + num = 1 + while True: + new_name = username + str(num) + if new_name in existing_names: + num += 1 + else: + return new_name + + def get_deserialized_object(self, xml_soup): + """returns deserialized django object for xml soup with one item""" + item_xml = smart_str(xml_soup) + #below call assumes a single item within + obj = serializers.deserialize('xml', item_xml).next().object + obj._source_xml = item_xml + return obj + + def get_m2m_ids_for_field(self, obj, field_name): + xml = obj._source_xml + soup = BeautifulSoup(xml) + ids = list() + for field in soup.findAll('field', attrs={'name': field_name}): + objs = field.findAll('object') + for obj in objs: + ids.append(obj.attrs['pk']) + return ids + + def copy_string_parameter(self, from_obj, to_obj, from_param_name, to_param_name=None): + """copy value of string parameter from old to new object""" + + to_param_name = to_param_name or from_param_name + + from_par = getattr(from_obj, from_param_name) + to_par = getattr(to_obj, to_param_name) + if from_par is None and to_par is None: + return + from_par = from_par or '' + to_par = to_par or '' + if from_par.strip() == '' and to_par.strip() != '': + setattr(to_obj, to_param_name, from_par) + + def copy_bool_parameter(self, from_obj, to_obj, from_param_name, to_param_name=None, operator='or'): + """copy value of boolean parameter from old to new object""" + + to_param_name = to_param_name or from_param_name + + from_par = getattr(from_obj, from_param_name) + to_par = getattr(to_obj, to_param_name) + if operator == 'or': + value = from_par or to_par + elif operator == 'and': + value = from_par and to_par + else: + raise ValueError('unsupported operator "%s"' % operator) + setattr(to_obj, to_param_name, value) + + def merge_words_parameter(self, from_obj, to_obj, from_param_name, to_param_name=None): + """merge unique words from the two objects and assign to the new object""" + + to_param_name = to_param_name or from_param_name + + from_words = getattr(from_obj, from_param_name).split() + to_words = getattr(to_obj, to_param_name).split() + value = ' '.join(set(from_words)|set(to_words)) + setattr(to_obj, to_param_name, value) + + def copy_numeric_parameter(self, from_obj, to_obj, from_param_name, to_param_name=None, operator='max'): + + to_param_name = to_param_name or from_param_name + + from_par = getattr(from_obj, from_param_name) + to_par = getattr(to_obj, to_param_name) + + if from_par is None: + return to_par + elif to_par is None: + return from_par + + if operator == 'max': + value = max(from_par, to_par) + elif operator == 'min': + value = min(from_par, to_par) + elif operator == 'sum': + value = from_par + to_par + else: + raise ValueError('unsupported operator "%s"' % operator) + setattr(to_obj, to_param_name, value) diff --git a/askbot/management/commands/dump_forum.py b/askbot/management/commands/dump_forum.py deleted file mode 100644 index 0bead908..00000000 --- a/askbot/management/commands/dump_forum.py +++ /dev/null @@ -1,36 +0,0 @@ -import sys -import optparse -from django.core import management -from django.core.management.base import BaseCommand -from askbot.utils import console - -class Command(BaseCommand): - help = """Dumps askbot forum data into the file for the later use with "load_forum". -The extension ".json" will be added automatically.""" - - option_list = BaseCommand.option_list + ( - optparse.make_option('--dump-name', - type = 'str', - dest = 'dump_file' - ), - ) - def handle(self, *args, **options): - dump_file = console.open_new_file( - 'Please enter file name (no extension): ', - hint = options.get('dump_file', None), - extension = '.json' - ) - print ("Saving file %s ..." % dump_file.name).encode('utf-8') - stdout_orig = sys.stdout - try: - sys.stdout = dump_file - management.call_command( - 'dumpdata', - #exclude = ('contenttypes',), - indent = 4 - ) - sys.stdout = stdout_orig - print "Done." - except KeyboardInterrupt: - sys.stdout = stdout_orig - print "\nCanceled." diff --git a/askbot/management/commands/export_osqa.py b/askbot/management/commands/export_osqa.py new file mode 100644 index 00000000..5dd6eb5d --- /dev/null +++ b/askbot/management/commands/export_osqa.py @@ -0,0 +1,215 @@ +from django.core.exceptions import ImproperlyConfigured +from django.core.management.base import BaseCommand, CommandError +from django.core.serializers.xml_serializer import Serializer +from django.db import connections, router, DEFAULT_DB_ALIAS +from django.utils.datastructures import SortedDict +from StringIO import StringIO + +from optparse import make_option + +class XMLExportSerializer(Serializer): + def serialize(self, queryset, **options): + """ + Serialize a queryset. + Copy-paste from the base serializer with a minor difference + commented below + """ + self.options = options + + self.stream = options.pop("stream", StringIO()) + self.selected_fields = options.pop("fields", None) + self.use_natural_keys = options.pop("use_natural_keys", False) + + self.start_serialization() + for obj in queryset: + self.start_object(obj) + #the line below is the only one that was changed + for field in obj._meta.fields: + if field.serialize: + if field.rel is None: + if self.selected_fields is None or field.attname in self.selected_fields: + self.handle_field(obj, field) + else: + if self.selected_fields is None or field.attname[:-3] in self.selected_fields: + self.handle_fk_field(obj, field) + for field in obj._meta.many_to_many: + if field.serialize: + if self.selected_fields is None or field.attname in self.selected_fields: + self.handle_m2m_field(obj, field) + self.end_object(obj) + self.end_serialization() + return self.getvalue() + + +class Command(BaseCommand): + option_list = BaseCommand.option_list + ( + make_option('--indent', default=4, dest='indent', type='int', + help='Specifies the indent level to use when pretty-printing output'), + make_option('--database', action='store', dest='database', + default=DEFAULT_DB_ALIAS, help='Nominates a specific database to load ' + 'fixtures into. Defaults to the "default" database.'), + make_option('-e', '--exclude', dest='exclude',action='append', default=['sessions', 'contenttypes'], + help='An appname or appname.ModelName to exclude (use multiple --exclude to exclude multiple apps/models).'), + make_option('-n', '--natural', action='store_true', dest='use_natural_keys', default=False, + help='Use natural keys if they are available.'), + make_option('-a', '--all', action='store_true', dest='use_base_manager', default=False, + help="Use Django's base manager to dump all models stored in the database, including those that would otherwise be filtered or modified by a custom manager."), + ) + help = ("Output the contents of the OSQA database as XML fixture of the given " + "format (using each model's default manager unless --all is " + "specified).") + args = '[appname appname.ModelName ...]' + + def handle(self, *app_labels, **options): + from django.db.models import get_app, get_apps, get_models, get_model + + indent = options.get('indent', None) + using = options.get('database', DEFAULT_DB_ALIAS) + connection = connections[using] + excludes = options.get('exclude',[]) + show_traceback = options.get('traceback', False) + use_natural_keys = options.get('use_natural_keys', False) + use_base_manager = options.get('use_base_manager', False) + + excluded_apps = set() + excluded_models = set() + for exclude in excludes: + if '.' in exclude: + app_label, model_name = exclude.split('.', 1) + model_obj = get_model(app_label, model_name) + if not model_obj: + raise CommandError('Unknown model in excludes: %s' % exclude) + excluded_models.add(model_obj) + else: + try: + app_obj = get_app(exclude) + excluded_apps.add(app_obj) + except ImproperlyConfigured: + raise CommandError('Unknown app in excludes: %s' % exclude) + + if len(app_labels) == 0: + app_list = SortedDict((app, None) for app in get_apps() if app not in excluded_apps) + else: + app_list = SortedDict() + for label in app_labels: + try: + app_label, model_label = label.split('.') + try: + app = get_app(app_label) + except ImproperlyConfigured: + raise CommandError("Unknown application: %s" % app_label) + if app in excluded_apps: + continue + model = get_model(app_label, model_label) + if model is None: + raise CommandError("Unknown model: %s.%s" % (app_label, model_label)) + + if app in app_list.keys(): + if app_list[app] and model not in app_list[app]: + app_list[app].append(model) + else: + app_list[app] = [model] + except ValueError: + # This is just an app - no model qualifier + app_label = label + try: + app = get_app(app_label) + except ImproperlyConfigured: + raise CommandError("Unknown application: %s" % app_label) + if app in excluded_apps: + continue + app_list[app] = None + + # Now collate the objects to be serialized. + objects = [] + for model in sort_dependencies(app_list.items()): + if model in excluded_models: + continue + if not model._meta.proxy and router.allow_syncdb(using, model): + if use_base_manager: + objects.extend(model._base_manager.using(using).all()) + else: + objects.extend(model._default_manager.using(using).all()) + + try: + serializer = XMLExportSerializer() + return serializer.serialize(objects, indent=indent, use_natural_keys=use_natural_keys) + except Exception, e: + if show_traceback: + raise + raise CommandError("Unable to serialize database: %s" % e) + +def sort_dependencies(app_list): + """Sort a list of app,modellist pairs into a single list of models. + + The single list of models is sorted so that any model with a natural key + is serialized before a normal model, and any model with a natural key + dependency has it's dependencies serialized first. + """ + from django.db.models import get_model, get_models + # Process the list of models, and get the list of dependencies + model_dependencies = [] + models = set() + for app, model_list in app_list: + if model_list is None: + model_list = get_models(app) + + for model in model_list: + models.add(model) + # Add any explicitly defined dependencies + if hasattr(model, 'natural_key'): + deps = getattr(model.natural_key, 'dependencies', []) + if deps: + deps = [get_model(*d.split('.')) for d in deps] + else: + deps = [] + + # Now add a dependency for any FK or M2M relation with + # a model that defines a natural key + for field in model._meta.fields: + if hasattr(field.rel, 'to'): + rel_model = field.rel.to + if hasattr(rel_model, 'natural_key'): + deps.append(rel_model) + for field in model._meta.many_to_many: + rel_model = field.rel.to + if hasattr(rel_model, 'natural_key'): + deps.append(rel_model) + model_dependencies.append((model, deps)) + + model_dependencies.reverse() + # Now sort the models to ensure that dependencies are met. This + # is done by repeatedly iterating over the input list of models. + # If all the dependencies of a given model are in the final list, + # that model is promoted to the end of the final list. This process + # continues until the input list is empty, or we do a full iteration + # over the input models without promoting a model to the final list. + # If we do a full iteration without a promotion, that means there are + # circular dependencies in the list. + model_list = [] + while model_dependencies: + skipped = [] + changed = False + while model_dependencies: + model, deps = model_dependencies.pop() + + # If all of the models in the dependency list are either already + # on the final model list, or not on the original serialization list, + # then we've found another model with all it's dependencies satisfied. + found = True + for candidate in ((d not in models or d in model_list) for d in deps): + if not candidate: + found = False + if found: + model_list.append(model) + changed = True + else: + skipped.append((model, deps)) + if not changed: + raise CommandError("Can't resolve dependencies for %s in serialized app list." % + ', '.join('%s.%s' % (model._meta.app_label, model._meta.object_name) + for model, deps in sorted(skipped, key=lambda obj: obj[0].__name__)) + ) + model_dependencies = skipped + + return model_list diff --git a/askbot/management/commands/find_bodyless_questions.py b/askbot/management/commands/find_bodyless_questions.py index 75312620..b137ba54 100644 --- a/askbot/management/commands/find_bodyless_questions.py +++ b/askbot/management/commands/find_bodyless_questions.py @@ -2,19 +2,28 @@ that do not have revisions by creating a fake initial revision based on the content stored in the post itself """ -from django.core.management.base import NoArgsCommand +from django.core.management.base import BaseCommand from askbot import models from askbot import const from askbot.utils.console import ProgressBar +from optparse import make_option def print_results(items): template = 'id=%d, title=%s' for thread in items: print template % (thread.id, thread.title.encode('utf8')) -class Command(NoArgsCommand): +class Command(BaseCommand): """Command class for "fix_bodyless_questions" """ + option_list = BaseCommand.option_list + ( + make_option('--delete', + action='store_true', + dest='delete', + default=False, + help='Delete poll instead of closing it', + ), + ) def handle(self, *arguments, **options): """function that handles the command job """ @@ -39,6 +48,12 @@ class Command(NoArgsCommand): if len(bodyless): print '\nQuestions without body text:' print_results(bodyless) + if options['delete']: + for thread in bodyless: + thread.delete() if len(multi_body): print '\nQuestions with >1 instances of body text' print_results(multi_body) + if options['delete']: + for thread in multi_body: + thread.delete() diff --git a/askbot/management/commands/fix_comment_counts.py b/askbot/management/commands/fix_comment_counts.py new file mode 100644 index 00000000..3a7f16f8 --- /dev/null +++ b/askbot/management/commands/fix_comment_counts.py @@ -0,0 +1,34 @@ +"""Management command for fixing comment counts in questions and answers + +Bug in converting answer to comment stored wrong comment count in target +question or answer, and in some cases that makes it imposible for users to view +all the comments. +""" + +from django.core.management.base import NoArgsCommand +from django.db.models import signals, Count, F +from askbot.models import Post +from askbot.utils.console import ProgressBar + +class Command(NoArgsCommand): + + help = "Fixes the wrong comment counts on questions and answers, "\ + "where answers have been converted to comments.\n" + + def remove_save_signals(self): + """Prevent possible unvanted side effects of saving + """ + signals.pre_save.receivers = [] + signals.post_save.receivers = [] + + def handle(self, *arguments, **options): + """Function that handles the command job + """ + self.remove_save_signals() + posts = Post.objects.annotate(real_comment_count=Count('comments') + ).exclude(real_comment_count=F('comment_count')) + count = posts.count() + message = 'Fixing comment counts' + for post in ProgressBar(posts.iterator(), count, message): + post.comment_count = post.comments.count(); + post.save() diff --git a/askbot/management/commands/fix_question_tags.py b/askbot/management/commands/fix_question_tags.py index ed1ee6fb..3cb696b0 100644 --- a/askbot/management/commands/fix_question_tags.py +++ b/askbot/management/commands/fix_question_tags.py @@ -1,11 +1,31 @@ +import re import sys from django.core.management.base import NoArgsCommand +from django.conf import settings as django_settings from django.db import transaction +from django.utils import translation +from askbot import const from askbot import models from askbot import forms from askbot.utils import console +from askbot.utils.slug import slugify_camelcase from askbot.models import signals from askbot.conf import settings as askbot_settings +from askbot.management.commands.rename_tags import get_admin + +def get_valid_tag_name(tag): + """Returns valid version of the tag name. + If necessary, lowercases the tag. + Strips the forbidden first characters in the tag. + """ + name = tag.name + if askbot_settings.FORCE_LOWERCASE_TAGS: + #name = slugify_camelcase(name) + name = name.lower() + #if tag name starts with forbidden character, chop off that character + #until no more forbidden chars are at the beginning + first_char_regex = re.compile('^%s+' % const.TAG_FORBIDDEN_FIRST_CHARS) + return first_char_regex.sub('', name) class Command(NoArgsCommand): def handle_noargs(self, **options): @@ -13,58 +33,115 @@ class Command(NoArgsCommand): self.run_command() signals.set_all_db_signal_receivers(signal_data) + def retag_threads(self, from_tags, to_tag): + """finds threads matching the `from_tags` + removes the `from_tags` from them and applies the + to_tags""" + threads = models.Thread.objects.filter(tags__in=from_tags) + from_tag_names = [tag.name for tag in from_tags] + for thread in threads: + tagnames = set(thread.get_tag_names()) + tagnames.difference_update(from_tag_names) + tagnames.add(to_tag.name) + self.admin.retag_question( + question=thread._question_post(), + tags=' '.join(tagnames) + ) + + @transaction.commit_manually def run_command(self): """method that runs the actual command""" #go through tags and find character case duplicates and eliminate them + translation.activate(django_settings.LANGUAGE_CODE) tagnames = models.Tag.objects.values_list('name', flat = True) + self.admin = get_admin() + + #1) first we go through all tags and + #either fix or delete illegal tags + found_count = 0 + for name in tagnames: - dupes = models.Tag.objects.filter(name__iexact = name) - first_tag = dupes[0] - if dupes.count() > 1: - line = 'Found duplicate tags for %s: ' % first_tag.name - print line, - for idx in xrange(1, dupes.count()): - print dupes[idx].name + ' ', - dupes[idx].delete() - print '' - if askbot_settings.FORCE_LOWERCASE_TAGS: - lowercased_name = first_tag.name.lower() - if first_tag.name != lowercased_name: - print 'Converting tag %s to lower case' % first_tag.name - first_tag.name = lowercased_name - first_tag.save() + try: + tag = models.Tag.objects.get(name=name) + except models.Tag.DoesNotExist: + #tag with this name was already deleted, + #because it was an invalid duplicate version + #of other valid tag + continue + + + fixed_name = get_valid_tag_name(tag) + + #if fixed name is empty after cleaning, delete the tag + if fixed_name == '': + print 'Deleting invalid tag: %s' % name + tag.delete() + found_count += 1 + continue + + if fixed_name != name: + print 'Renaming tag: %s -> %s' % (name, fixed_name) + + #if tag name changed, see if there is a duplicate + #with the same name, in which case we re-assign questions + #with the current tag to that other duplicate + #then delete the current tag as no longer used + if fixed_name != name: + try: + duplicate_tag = models.Tag.objects.get(name=fixed_name) + except models.Tag.DoesNotExist: + pass + self.retag_threads([tag], duplicate_tag) + tag.delete() + found_count += 1 + continue + + + #if there are case variant dupes, we assign questions + #from the case variants to the current tag and + #delete the case variant tags + dupes = models.Tag.objects.filter( + name__iexact=fixed_name + ).exclude(pk=tag.id) + + dupes_count = dupes.count() + if dupes_count: + self.retag_threads(dupes, tag) + dupes.delete() + found_count += dupes_count + + if tag.name != fixed_name: + tag.name = fixed_name + tag.save() + transaction.commit() - #go through questions and fix tag records on each + #2) go through questions and fix tag records on each + # and recalculate all the denormalised tag names on threads threads = models.Thread.objects.all() checked_count = 0 - found_count = 0 total_count = threads.count() - print "Searching for questions with inconsistent tag records:", + print "Searching for questions with inconsistent copies of tag records:", for thread in threads: + #make sure that denormalized tag set is the same as normalized + #we just add both the tags together and try to apply them + #to the question tags = thread.tags.all() denorm_tag_set = set(thread.get_tag_names()) norm_tag_set = set(thread.tags.values_list('name', flat=True)) - if norm_tag_set != denorm_tag_set: - - if thread.last_edited_by: - user = thread.last_edited_by - timestamp = thread.last_edited_at - else: - user = thread.author - timestamp = thread.added_at - - tagnames = forms.TagNamesField().clean(thread.tagnames) - thread.update_tags( - tagnames = tagnames, - user = user, - timestamp = timestamp + if norm_tag_set != denorm_tag_set: + denorm_tag_set.update(norm_tag_set) + cleaned_tag_set = set( + models.Tag.objects.filter( + name__in=denorm_tag_set + ).values_list('name', flat=True) + ) + self.admin.retag_question( + question=thread._question_post(), + tags=' '.join(cleaned_tag_set) ) - thread.tagnames = tagnames - thread.save() - found_count += 1 transaction.commit() checked_count += 1 diff --git a/askbot/management/commands/generate_post_snippets.py b/askbot/management/commands/generate_post_snippets.py new file mode 100644 index 00000000..688450bf --- /dev/null +++ b/askbot/management/commands/generate_post_snippets.py @@ -0,0 +1,18 @@ +from django.core.management.base import NoArgsCommand +from django.db import transaction +from askbot.models import Post +from askbot.utils.console import ProgressBar + +class Command(NoArgsCommand): + help = 'Generates snippets for all posts' + @transaction.commit_manually + def handle_noargs(self, *args, **kwargs): + posts = Post.objects.all() + count = posts.count() + message = 'Building post snippets' + for post in ProgressBar(posts.iterator(), count, message): + if hasattr(post, 'summary'): + post.summary = post.get_snippet() + post.save() + transaction.commit() + transaction.commit() diff --git a/askbot/management/commands/init_postgresql_full_text_search.py b/askbot/management/commands/init_postgresql_full_text_search.py index 3cf4b03c..cc6a7263 100644 --- a/askbot/management/commands/init_postgresql_full_text_search.py +++ b/askbot/management/commands/init_postgresql_full_text_search.py @@ -11,7 +11,7 @@ class Command(NoArgsCommand): askbot.get_install_directory(), 'search', 'postgresql', - 'thread_and_post_models_01162012.plsql' + 'thread_and_post_models_10032013.plsql' ) setup_full_text_search(script_path) @@ -19,6 +19,6 @@ class Command(NoArgsCommand): askbot.get_install_directory(), 'search', 'postgresql', - 'user_profile_search_16102012.plsql' + 'user_profile_search_02262013.plsql' ) setup_full_text_search(script_path) diff --git a/askbot/management/commands/load_forum.py b/askbot/management/commands/load_forum.py deleted file mode 100644 index 65ac410f..00000000 --- a/askbot/management/commands/load_forum.py +++ /dev/null @@ -1,16 +0,0 @@ -from django.core import management -from django.db.models import signals -from django.contrib.contenttypes.models import ContentType -from django.core.management.base import BaseCommand -from askbot import models - -class Command(BaseCommand): - args = '<data file>' - help = 'Loads askbot forum data from the dump file obtained with command "dump_forum"' - def handle(self, *args, **options): - #need to remove badge data b/c they are aslo in the dump - models.BadgeData.objects.all().delete() - ContentType.objects.all().delete() - #turn off the post_save signal so than Activity can be copied - signals.post_save.receivers = [] - management.call_command('loaddata', args[0]) diff --git a/askbot/management/commands/merge_users.py b/askbot/management/commands/merge_users.py index 189b74bb..a5ce25cd 100644 --- a/askbot/management/commands/merge_users.py +++ b/askbot/management/commands/merge_users.py @@ -1,4 +1,5 @@ from django.core.management.base import CommandError, BaseCommand +from django.db import transaction from askbot.models import User # TODO: this command is broken - doesn't take into account UNIQUE constraints @@ -13,32 +14,40 @@ class MergeUsersBaseCommand(BaseCommand): args = '<from_user_id> <to_user_id>' help = 'Merge an account and all information from a <user_id> to a <user_id>, deleting the <from_user>' + @transaction.commit_manually def handle(self, *arguments, **options): - self.parse_arguments(*arguments) - + for rel in User._meta.get_all_related_objects(): + sid = transaction.savepoint() try: self.process_field(rel.model, rel.field.name) + transaction.savepoint_commit(sid) except Exception, error: self.stdout.write((u'Warning: %s\n' % error).encode('utf-8')) + transaction.savepoint_rollback(sid) + transaction.commit() for rel in User._meta.get_all_related_many_to_many_objects(): + sid = transaction.savepoint() try: self.process_m2m_field(rel.model, rel.field.name) + transaction.savepoint_commit(sid) except Exception, error: self.stdout.write((u'Warning: %s\n' % error).encode('utf-8')) + transaction.savepoint_rollback(sid) + transaction.commit() self.process_custom_user_fields() self.cleanup() def cleanup(self): - raise Exception, 'Not implemented' + raise Exception, 'Not implemented' def process_custom_user_fields(self): - """Put app specific logic here.""" - raise Exception, 'Not implemented' + """Put app specific logic here.""" + raise Exception, 'Not implemented' def parse_arguments(self, *arguments): if len(arguments) != 2: @@ -66,19 +75,19 @@ class MergeUsersBaseCommand(BaseCommand): class Command(MergeUsersBaseCommand): - def process_custom_user_fields(self): - self.to_user.reputation += self.from_user.reputation - 1 - self.to_user.gold += self.from_user.gold - self.to_user.silver += self.from_user.silver - self.to_user.bronze += self.from_user.bronze - - if self.from_user.last_seen > self.to_user.last_seen: - self.to_user.last_seen = self.from_user.last_seen + def process_custom_user_fields(self): + self.to_user.reputation += self.from_user.reputation - 1 + self.to_user.gold += self.from_user.gold + self.to_user.silver += self.from_user.silver + self.to_user.bronze += self.from_user.bronze - if self.from_user.date_joined < self.to_user.date_joined: - self.to_user.date_joined = self.from_user.date_joined + if self.from_user.last_seen > self.to_user.last_seen: + self.to_user.last_seen = self.from_user.last_seen + + if self.from_user.date_joined < self.to_user.date_joined: + self.to_user.date_joined = self.from_user.date_joined - def cleanup(self): - self.to_user.save() - self.from_user.delete() + def cleanup(self): + self.to_user.save() + self.from_user.delete() diff --git a/askbot/management/commands/rename_tags.py b/askbot/management/commands/rename_tags.py index bd15d685..b3eaf70d 100644 --- a/askbot/management/commands/rename_tags.py +++ b/askbot/management/commands/rename_tags.py @@ -4,8 +4,10 @@ retagged """ import sys from optparse import make_option +from django.conf import settings as django_settings from django.core import management from django.core.management.base import BaseCommand, CommandError +from django.utils import translation from askbot import api, models from askbot.utils import console @@ -94,6 +96,7 @@ ask you to confirm your action before making changes. The data of tag id's is then delegated to the command "rename_tag_id" """ + translation.activate(django_settings.LANGUAGE_CODE) if options['from'] is None: raise CommandError('the --from argument is required') if options['to'] is None: @@ -124,7 +127,7 @@ Also, you can try command "rename_tag_id" """ % tag_name raise CommandError(error_message) except models.Tag.MultipleObjectsReturned: - raise CommandError(u'found more than one tag named %s' % from_tag_name) + raise CommandError(u'found more than one tag named %s' % tag_name) admin = get_admin(seed_user_id = options['user_id']) diff --git a/askbot/management/commands/rename_tags_id.py b/askbot/management/commands/rename_tags_id.py index 1da22868..45e4a76a 100644 --- a/askbot/management/commands/rename_tags_id.py +++ b/askbot/management/commands/rename_tags_id.py @@ -8,8 +8,10 @@ also, corresponding questions are retagged import re import sys from optparse import make_option +from django.conf import settings as django_settings from django.core.management.base import BaseCommand, CommandError from django.db import transaction +from django.utils import translation from askbot import const, models from askbot.utils import console from askbot.management.commands.rename_tags import get_admin @@ -84,6 +86,7 @@ rename_tags, but using tag id's def handle(self, *args, **options): """command handle function. retrieves tags by id """ + translation.activate(django_settings.LANGUAGE_CODE) try: from_tag_ids = parse_tag_ids(options['from']) to_tag_ids = parse_tag_ids(options['to']) @@ -161,6 +164,7 @@ or repost a bug, if that does not help""" tags = u' '.join(tag_names), #silent = True #do we want to timestamp activity on question ) + question.invalidate_cached_thread_content_fragment() i += 1 sys.stdout.write('%6.2f%%' % (100*float(i)/float(question_count))) sys.stdout.write('\b'*7) diff --git a/askbot/management/commands/send_accept_answer_reminders.py b/askbot/management/commands/send_accept_answer_reminders.py index 22ae311d..70baac62 100644 --- a/askbot/management/commands/send_accept_answer_reminders.py +++ b/askbot/management/commands/send_accept_answer_reminders.py @@ -57,15 +57,7 @@ class Command(NoArgsCommand): if question_count == 0: continue - subject_line = _( - 'Accept the best answer for %(question_count)d of your questions' - ) % {'question_count': question_count} - - #todo - make a template for these - if question_count == 1: - reminder_phrase = _('Please accept the best answer for this question:') - else: - reminder_phrase = _('Please accept the best answer for these questions:') + reminder_phrase = _('Please select the best responses to:') data = { 'site_url': site_url(''),#here we need only the domain name @@ -76,6 +68,7 @@ class Command(NoArgsCommand): template = get_template('email/accept_answer_reminder.html') body_text = template.render(Context(data))#todo: set lang + subject_line = askbot_settings.WORDS_ACCEPT_BEST_ANSWERS_FOR_YOUR_QUESTIONS if DEBUG_THIS_COMMAND: print "User: %s<br>\nSubject:%s<br>\nText: %s<br>\n" % \ (user.email, subject_line, body_text) diff --git a/askbot/management/commands/send_email_alerts.py b/askbot/management/commands/send_email_alerts.py index e1783316..a9162079 100644 --- a/askbot/management/commands/send_email_alerts.py +++ b/askbot/management/commands/send_email_alerts.py @@ -433,8 +433,8 @@ class Command(NoArgsCommand): question_count = len(q_list.keys()) subject_line = ungettext( - '%(question_count)d updated question about %(topics)s', - '%(question_count)d updated questions about %(topics)s', + '%(question_count)d update about %(topics)s', + '%(question_count)d updates about %(topics)s', question_count ) % { 'question_count': question_count, diff --git a/askbot/management/commands/send_unanswered_question_reminders.py b/askbot/management/commands/send_unanswered_question_reminders.py index 42ce5119..c428881d 100644 --- a/askbot/management/commands/send_unanswered_question_reminders.py +++ b/askbot/management/commands/send_unanswered_question_reminders.py @@ -64,11 +64,13 @@ class Command(NoArgsCommand): tag_summary = Thread.objects.get_tag_summary_from_threads(threads) subject_line = ungettext( - '%(question_count)d unanswered question about %(topics)s', - '%(question_count)d unanswered questions about %(topics)s', + '%(question_count)d %(unanswered_question)s about %(topics)s', + '%(question_count)d %(unanswered_questions)s about %(topics)s', question_count ) % { 'question_count': question_count, + 'unanswered_question': askbot_settings.WORDS_UNANSWERED_QUESTION_SINGULAR, + 'unanswered_questions': askbot_settings.WORDS_UNANSWERED_QUESTION_PLURAL, 'topics': tag_summary } diff --git a/askbot/media/jquery-openid/jquery.openid.js b/askbot/media/jquery-openid/jquery.openid.js index c8e925a3..20807065 100644 --- a/askbot/media/jquery-openid/jquery.openid.js +++ b/askbot/media/jquery-openid/jquery.openid.js @@ -310,7 +310,7 @@ $.fn.authenticator = function() { var setup_password_login_or_change = function(provider_name){ var token_name = extra_token_name[provider_name] var password_action_input = $('input[name=password_action]'); - if (userIsAuthenticated === true){ + if (userIsAuthenticated === true && askbot['settings']['useLdapForPasswordLogin'] == false){ var password_button = $('input[name=change_password]'); var submit_action = submit_change_password; if (provider_name === 'local'){ @@ -334,8 +334,7 @@ $.fn.authenticator = function() { password_action_input.val('change_password'); var focus_input = $('#id_new_password'); var submittable_input = $('#id_new_password_retyped'); - } - else{ + } else { $('#password-heading>span').html(token_name); var password_button = $('input[name=login_with_password]'); var submit_action = submit_login_with_password; diff --git a/askbot/media/js/live_search.js b/askbot/media/js/live_search.js index f6eecff1..e833059f 100644 --- a/askbot/media/js/live_search.js +++ b/askbot/media/js/live_search.js @@ -162,6 +162,7 @@ SearchDropMenu.prototype.showWaitIcon = function() { this._footer.hide(); this._element.addClass('empty'); } + this._element.addClass('waiting'); }; SearchDropMenu.prototype.hideWaitIcon = function() { @@ -170,6 +171,7 @@ SearchDropMenu.prototype.hideWaitIcon = function() { this._footer.show(); this._element.removeClass('empty'); } + this._element.removeClass('waiting'); }; SearchDropMenu.prototype.hideHeader = function() { @@ -896,7 +898,7 @@ FullTextSearch.prototype.decorate = function(element) { dropMenu.setAskHandler(this.makeAskHandler()); dropMenu.setAskButtonEnabled(this._askButtonEnabled); this._dropMenu = dropMenu; - element.parent().after(this._dropMenu.getElement()); + element.parent().append(this._dropMenu.getElement()); $(element).click(function(e) { return false }); $(document).click(function() { dropMenu.reset(); }); diff --git a/askbot/media/js/post.js b/askbot/media/js/post.js index 18031482..d077ce9e 100644 --- a/askbot/media/js/post.js +++ b/askbot/media/js/post.js @@ -83,35 +83,6 @@ function setupFormValidation(form, validationRules, validationMessages, onSubmit }); } -/** - * generic tag cleaning function, settings - * are from askbot live settings and askbot.const - */ -var cleanTag = function(tag_name, settings) { - var tag_regex = new RegExp(settings['tag_regex']); - if (tag_regex.test(tag_name) === false) { - throw settings['messages']['wrong_chars'] - } - - var max_length = settings['max_tag_length']; - if (tag_name.length > max_length) { - throw interpolate( - ngettext( - 'must be shorter than %(max_chars)s character', - 'must be shorter than %(max_chars)s characters', - max_length - ), - {'max_chars': max_length }, - true - ); - } - if (settings['force_lowercase_tags']) { - return tag_name.toLowerCase(); - } else { - return tag_name; - } -}; - var validateTagLength = function(value){ var tags = getUniqueWords(value); var are_tags_ok = true; @@ -171,11 +142,15 @@ var CPValidator = function() { required: " " + gettext('enter your question'), minlength: interpolate( ngettext( - 'question must have > %s character', - 'question must have > %s characters', + '%(question)s must have > %(length)s character', + '%(question)s must have > %(length)s characters', askbot['settings']['minTitleLength'] ), - [askbot['settings']['minTitleLength'], ] + { + 'question': askbot['messages']['questionSingular'], + 'length': askbot['settings']['minTitleLength'] + }, + true ) } }; @@ -193,11 +168,15 @@ var CPValidator = function() { required: " " + gettext('content cannot be empty'), minlength: interpolate( ngettext( - 'answer must be > %s character', - 'answer must be > %s characters', + '%(answer)s must be > %(length)s character', + '%(answer)s must be > %(length)s characters', askbot['settings']['minAnswerBodyLength'] ), - [askbot['settings']['minAnswerBodyLength'], ] + { + 'answer': askbot['messages']['answerSingular'], + 'length': askbot['settings']['minAnswerBodyLength'] + }, + true ) }, } @@ -546,12 +525,17 @@ var Vote = function(){ var questionSubscribeSidebar= 'question-subscribe-sidebar'; var acceptAnonymousMessage = gettext('insufficient privilege'); - var acceptOwnAnswerMessage = gettext('cannot pick own answer as best'); var pleaseLogin = " <a href='" + askbot['urls']['user_signin'] + ">" + gettext('please login') + "</a>"; - var favoriteAnonymousMessage = gettext('anonymous users cannot follow questions') + pleaseLogin; + var tmpMsg = interpolate( + gettext('anonymous users cannot %(follow_questions)s'), + {'follow_questions': askbot['messages']['followQuestions']}, + true + ); + var favoriteAnonymousMessage = tmpMsg + pleaseLogin; + //todo: this below is probably not used var subscribeAnonymousMessage = gettext('anonymous users cannot subscribe to questions') + pleaseLogin; var voteAnonymousMessage = gettext('anonymous users cannot vote') + pleaseLogin; //there were a couple of more messages... @@ -617,17 +601,17 @@ var Vote = function(){ }; var getOffensiveQuestionFlag = function(){ - var offensiveQuestionFlag = '.question-card span[id^="'+ offensiveIdPrefixQuestionFlag +'"]'; + var offensiveQuestionFlag = 'div.question span[id^="'+ offensiveIdPrefixQuestionFlag +'"]'; return $(offensiveQuestionFlag); }; var getRemoveOffensiveQuestionFlag = function(){ - var removeOffensiveQuestionFlag = '.question-card span[id^="'+ removeOffensiveIdPrefixQuestionFlag +'"]'; + var removeOffensiveQuestionFlag = 'div.question span[id^="'+ removeOffensiveIdPrefixQuestionFlag +'"]'; return $(removeOffensiveQuestionFlag); }; var getRemoveAllOffensiveQuestionFlag = function(){ - var removeAllOffensiveQuestionFlag = '.question-card span[id^="'+ removeAllOffensiveIdPrefixQuestionFlag +'"]'; + var removeAllOffensiveQuestionFlag = 'div.question span[id^="'+ removeAllOffensiveIdPrefixQuestionFlag +'"]'; return $(removeAllOffensiveQuestionFlag); }; @@ -795,7 +779,12 @@ var Vote = function(){ showMessage(object, acceptAnonymousMessage); } else if(data.allowed == "-1"){ - showMessage(object, acceptOwnAnswerMessage); + var message = interpolate( + gettext('sorry, you cannot %(accept_own_answer)s'), + {'accept_own_answer': askbot['messages']['acceptOwnAnswer']}, + true + ); + showMessage(object, message); } else if(data.status == "1"){ $("#"+answerContainerIdPrefix+postId).removeClass("accepted-answer"); @@ -2403,7 +2392,10 @@ PostCommentsWidget.prototype.getActivateHandler = function(){ } else { //if user can't post, we tell him something and refuse - if (askbot['data']['userIsAuthenticated']) { + if (askbot['settings']['readOnlyModeEnabled'] === true) { + var message = askbot['messages']['readOnlyMessage']; + showMessage(button, message, 'after'); + } else if (askbot['data']['userIsAuthenticated']) { me.startNewComment(); } else { var message = gettext('please sign in or register to post comments'); @@ -2514,7 +2506,7 @@ var socialSharing = function(){ URL = window.location.href; var urlBits = URL.split('/'); URL = urlBits.slice(0, -2).join('/') + '/'; - TEXT = encodeURIComponent($('h1 > a').html()); + TEXT = encodeURIComponent($('h1 > a').text()); var hashtag = encodeURIComponent( askbot['settings']['sharingSuffixText'] ); @@ -3388,9 +3380,55 @@ var TagEditor = function() { WrappedElement.call(this); this._has_hot_backspace = false; this._settings = JSON.parse(askbot['settings']['tag_editor']); + /* + tags: { + required: askbot['settings']['tagsAreRequired'], + maxlength: askbot['settings']['maxTagsPerPost'] * askbot['settings']['maxTagLength'], + limit_tag_count: true, + limit_tag_length: true + }, + tags: { + required: " " + gettext('tags cannot be empty'), + maxlength: askbot['messages']['tagLimits'], + limit_tag_count: askbot['messages']['maxTagsPerPost'], + limit_tag_length: askbot['messages']['maxTagLength'] + }, + */ }; inherits(TagEditor, WrappedElement); +/* retagger function + var doRetag = function(){ + $.ajax({ + type: "POST", + url: retagUrl,//todo add this url to askbot['urls'] + dataType: "json", + data: { tags: getUniqueWords(tagInput.val()).join(' ') }, + success: function(json) { + if (json['success'] === true){ + new_tags = getUniqueWords(json['new_tags']); + oldTagsHtml = ''; + cancelRetag(); + drawNewTags(new_tags.join(' ')); + if (json['message']) { + notify.show(json['message']); + } + } + else { + cancelRetag(); + showMessage(tagsDiv, json['message']); + } + }, + error: function(xhr, textStatus, errorThrown) { + showMessage(tagsDiv, gettext('sorry, something is not right here')); + cancelRetag(); + } + }); + return false; + } +*/ + + TagEditor.prototype.getSelectedTags = function() { return $.trim(this._hidden_tags_input.val()).split(/\s+/); }; diff --git a/askbot/media/js/tag_selector.js b/askbot/media/js/tag_selector.js index dfc8a29a..c905ab86 100644 --- a/askbot/media/js/tag_selector.js +++ b/askbot/media/js/tag_selector.js @@ -274,10 +274,16 @@ function pickedTags(){ }); } + var tagSettings = JSON.parse(askbot['settings']['tag_editor']); var clean_tagnames = []; $.each(tagnames, function(idx, tagname){ if (!(tagname in to_target)){ - clean_tagnames.push(tagname); + try { + cleanTag(tagname, tagSettings); + clean_tagnames.push(tagname); + } catch (e) { + alert(e); + } } }); diff --git a/askbot/media/js/user.js b/askbot/media/js/user.js index de5d0804..90f35f2f 100644 --- a/askbot/media/js/user.js +++ b/askbot/media/js/user.js @@ -1076,6 +1076,7 @@ inherits(UserQuestionsPaginator, Paginator); UserQuestionsPaginator.prototype.renderPage = function(data) { $('.users-questions').html(data['questions']); + $('.timeago').timeago(); }; UserQuestionsPaginator.prototype.getPageDataUrl = function(pageNo) { @@ -1095,6 +1096,7 @@ inherits(UserAnswersPaginator, Paginator); UserAnswersPaginator.prototype.renderPage = function(data) { $('.users-answers').html(data['html']); + $('.timeago').timeago(); }; UserAnswersPaginator.prototype.getPageDataUrl = function() { diff --git a/askbot/media/js/utils.js b/askbot/media/js/utils.js index 7e7b2935..64932ccd 100644 --- a/askbot/media/js/utils.js +++ b/askbot/media/js/utils.js @@ -44,6 +44,41 @@ var getNewUniqueInt = function() { return num; }; +/** + * generic tag cleaning function, settings + * are from askbot live settings and askbot.const + */ +var cleanTag = function(tag_name, settings) { + var tag_regex = new RegExp(settings['tag_regex']); + if (tag_regex.test(tag_name) === false) { + var firstChar = tag_name.substring(0, 1); + if (settings['tag_forbidden_first_chars'].indexOf(firstChar) > -1) { + throw settings['messages']['wrong_first_char']; + } else { + throw settings['messages']['wrong_chars']; + } + } + + var max_length = settings['max_tag_length']; + if (tag_name.length > max_length) { + throw interpolate( + ngettext( + 'must be shorter than %(max_chars)s character', + 'must be shorter than %(max_chars)s characters', + max_length + ), + {'max_chars': max_length }, + true + ); + } + if (settings['force_lowercase_tags']) { + return tag_name.toLowerCase(); + } else { + return tag_name; + } +}; + + var getSingletonController = function(controllerClass, name) { askbot['controllers'] = askbot['controllers'] || {}; var controller = askbot['controllers'][name]; @@ -2750,10 +2785,9 @@ Tag.prototype.createDom = function(){ } this._inner_element.addClass('tag tag-right'); this._inner_element.attr('rel', 'tag'); - if (this._title === null){ - this.setTitle( - interpolate(gettext("see questions tagged '%s'"), [this.getName()]) - ); + if (this._title === null) { + var name = this.getName(); + this.setTitle(interpolate(gettext("see questions tagged '%s'"), [name,])); } this._inner_element.attr('title', this._title); this._inner_element.html(this.getDisplayTagName()); diff --git a/askbot/media/js/wmd/wmd.js b/askbot/media/js/wmd/wmd.js index 6f7505d0..f84cd6e4 100644 --- a/askbot/media/js/wmd/wmd.js +++ b/askbot/media/js/wmd/wmd.js @@ -122,14 +122,15 @@ Attacklab.wmdBase = function(){ // Adds a listener callback to a DOM element which is fired on a specified // event. util.addEvent = function(elem, event, listener){ - if (elem && elem.attachEvent) { - // IE only. The "on" is mandatory. - elem.attachEvent("on" + event, listener); - } - else { - // Other browsers. - elem.addEventListener(event, listener, false); - } + if (elem) { + if (elem.attachEvent) { + // IE only. The "on" is mandatory. + elem.attachEvent("on" + event, listener); + } else { + // Other browsers. + elem.addEventListener(event, listener, false); + } + } }; diff --git a/askbot/media/style/style.css b/askbot/media/style/style.css index fb1cf98b..0f0119f3 100644 --- a/askbot/media/style/style.css +++ b/askbot/media/style/style.css @@ -198,6 +198,9 @@ h1 { /* ----- Extra space above for messages ----- */ body.user-messages { margin-top: 2.4em; + box-sizing: border-box; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; } /* ----- Custom positions ----- */ .left { @@ -460,11 +463,21 @@ body.user-messages { border-top: #fcfcfc 1px solid; margin-bottom: 10px; font-family: 'Open Sans Condensed', Arial, sans-serif; + box-sizing: border-box; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; +} +#secondaryHeader td { + padding: 0; +} +#secondaryHeader td.search-bar { + padding: 0 32px 0 15px; + position: relative; } #homeButton { border-right: #afaf9e 1px solid; background: -6px -36px url(../images/sprites.png) no-repeat; - height: 55px; + height: 54px; width: 43px; display: block; float: left; @@ -473,8 +486,7 @@ body.user-messages { background: -51px -36px url(../images/sprites.png) no-repeat; } .scope-selector { - display: block; - float: left; + display: inline-block; font-size: 20px; color: #7a7a6b; height: 55px; @@ -482,7 +494,7 @@ body.user-messages { margin-left: 16px; } .scope-selector.on { - background: url(../images/scopearrow.png) no-repeat center bottom; + background: url(../images/scopearrow.png) no-repeat center 41px; } .scope-selector.ask-message { font-size: 24px; @@ -505,12 +517,12 @@ body.user-messages { #searchBar { /* Main search form , check widgets/search_bar.html */ - display: block; - background-color: #fff; border: 1px solid #c9c9b5; + background: white; height: 41px; z-index: 1000; position: relative; + width: 100%; /* the guts are absolute-positioned */ } @@ -570,17 +582,20 @@ body.user-messages { } .search-drop-menu { box-sizing: border-box; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; background: whitesmoke; - border: 1px solid #c9c9b5; border-top: none; + top: 42px; margin: 0; - position: relative; + outline: 1px solid #dadad4; + position: absolute; z-index: 10000; } .search-drop-menu ul { list-style: none; overflow: auto; - padding: 0 0 10px 0; + padding: 0; margin: 0; position: relative; width: 100%; @@ -598,12 +613,13 @@ body.user-messages { .search-drop-menu ul li.selected a { color: whitesmoke; } -.search-drop-menu ul.empty { - margin-bottom: 0; -} .search-drop-menu .footer { text-align: center; - padding: 9px 0 10px 0; + margin: 0 0 1px 0; + padding: 4px 0 10px 0; +} +.search-drop-menu.empty .footer { + padding-top: 9px; } .search-drop-menu.empty ul { padding: 1px; @@ -623,7 +639,7 @@ input[type="submit"].searchBtn { border: #FFF 1px solid; line-height: 22px; text-align: center; - margin: 1px 0 0 0; + margin: 0; width: 48px; background: -98px -37px url(../images/sprites.png) no-repeat; border-radius: 0; @@ -652,13 +668,21 @@ input[type="submit"].searchBtn { color: white; height: 0; z-index: 0; + position: absolute; + left: -1000px; + /* hide away */ + +} +.ask-page .search-drop-menu { + top: 37px; } .ask-page .search-drop-menu.empty { border: none; - padding: 0; + outline: none; + padding: 0 !important; } .ask-page .search-drop-menu.empty ul { - padding: 0; + padding: 0 !important; } input[type="submit"].searchBtn:hover { background-image: none; @@ -801,73 +825,23 @@ form.ajax-file-upload img.spinner { font-size: 20px; height: 42px; line-height: 44px; - margin: 6px 0 0 0; + margin: -1px 0 0 0; text-transform: uppercase; width: 200px; /* to match width of sidebar */ } -/* - Put the secondary navigation together: - 1) raise the search bar by 55px - 2) add padding to fit the buttons -*/ -#searchBar { - margin: 0 228px 0 327px; - width: auto; - margin-top: -49px; - padding: 0 49px 0 8px; -} -/* line up drop menu the same way as the search bar */ .search-drop-menu { - margin: 0 228px 0 327px; - width: auto; + width: 100%; } .ask-page .search-drop-menu, body.anon.ask-page .search-drop-menu { - margin: -9px 0 10px; + padding: 5px 10px 6px 0; } #scopeNav { - height: 41px; - float: left; - width: 280px; -} -.scopes-True-True-False #searchBar, -.scopes-True-True-False .search-drop-menu { - margin-left: 228px; -} -.scopes-True-True-False #scopeNav { - width: 180px; -} -.scopes-True-False-True #searchBar, -.scopes-True-False-True .search-drop-menu { - margin-left: 203px; -} -.scopes-True-False-True #scopeNav { - width: 150px; -} -.scopes-False-True-True #searchBar, -.scopes-False-True-True .search-drop-menu { - margin-left: 286px; -} -.scopes-False-True-True #scopeNav { - width: 238px; -} -.scopes-True-False-False #searchBar, -.scopes-False-True-False #searchBar, -.scopes-False-False-True #searchBar, -.scopes-False-False-False #searchBar, -.scopes-True-False-False .search-drop-menu, -.scopes-False-True-False .search-drop-menu, -.scopes-False-False-True .search-drop-menu, -.scopes-False-False-False .search-drop-menu { - margin-left: 52px; -} -.scopes-True-False-False #scopeNav, -.scopes-False-True-False #scopeNav, -.scopes-False-False-True #scopeNav, -.scopes-False-False-False #scopeNav { - width: 0; + height: 54px; + display: inline-block; + white-space: nowrap; } /* ----- Content layout, check two_column_body.html or one_column_body.html ----- */ #ContentLeft { @@ -1078,7 +1052,7 @@ body.anon.ask-page .search-drop-menu { -webkit-box-shadow: 1px 1px 3px #999999; -moz-box-shadow: 1px 1px 3px #999999; box-shadow: 1px 1px 3px #999999; - padding: 7px 10px 1px 10px; + padding: 7px 10px 9px 0; margin-bottom: 10px; width: 100%; } @@ -1199,7 +1173,8 @@ body.anon.ask-page .search-drop-menu { ul#searchTags { margin-left: 10px; float: right; - padding-top: 2px; + padding: 8px 6px 0px 6px; + min-width: 43px; } .search-tips { font-size: 16px; @@ -1381,23 +1356,25 @@ ul#searchTags { .paginator .page a, .paginator .page a:visited, .paginator .curr { - padding: .25em; - margin: 0em .25em; + padding: 0 .25em; + margin: 0em .15em 0 0; } .paginator .curr { - background-color: #8ebcc7; + /*background-color: #8ebcc7;*/ + color: #fff; font-weight: bold; } .paginator .curr a { background: #8ebcc7; color: white; - padding: 0; + /*padding: 0;*/ + } .paginator .curr.page a:hover { background: #8ebcc7; color: white; - padding: 0; + padding: 0 0.25em; } .paginator .page a:hover, .paginator .prev a:hover, @@ -1505,7 +1482,7 @@ ul#related-tags li { background: #f3f6f6; border: #fff 1px solid ; border-top: #fff 2px solid; - outline: #cfdbdb 1px solid; + outline: #cfdbdb 1px solid !important; /* .box-shadow(0px,1px,0px,#88a8a8);*/ display: block; @@ -1667,6 +1644,7 @@ ul#related-tags li { padding: 4px 0 0 0; margin-top: 0px; width: 100%; + position: relative; } #askFormBar p { margin: 0 0 5px 0; @@ -2151,7 +2129,7 @@ ul#related-tags li { float: right; font-size: 9px; font-family: Arial; - line-height: 13px; + line-height: 12px; margin: 0px 0px 5px 5px; padding: 4px; width: 166px; @@ -3586,6 +3564,14 @@ a.offensive { .message p { margin-bottom: 0px; } +.system-messages { + color: red; + background: yellow; + font-size: 21px; + font-weight: bold; + line-height: 25px; + padding: 0 5px; +} p.space-above { margin-top: 10px; } @@ -3920,7 +3906,7 @@ p.signup_p { } .user-card .avatar-box { float: left; - margin: 3px 6px 0 0; + margin: 0px 6px 0 2px; } .user-card .info { height: 32px; @@ -4066,6 +4052,9 @@ a.primary-group-name { color: #990E08; font-weight: bold; } +.post-update-info .user-info { + margin-top: -2px; +} .users-page .wmd-prompt-dialog { background: #ccc; } @@ -4201,30 +4190,34 @@ textarea.tipped-input { } /* tag editor */ .tag-editor { - height: 64px; - border: #ccc 3px solid; - padding-left: 8px; + height: 32px; + border: #cce6ec 3px solid; + padding-left: 6px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); } .tag-editor ul.tags { margin: 0; } .tag-editor ul.tags li { - margin-top: 8px; + margin-top: 6px; height: 13px; } .tag-editor input.new-tags-input, .tag-editor input.new-tags-input:focus { border: none; - font-size: 15px; + box-shadow: none; + font-size: 14px; font-color: #707070; height: 16px; line-height: 16px; - margin-top: 9px; + margin: 9px 0 0 -6px; -webkit-box-shadow: none; /* undo bootstrap glow */ -moz-box-shadow: none; - box-shadow: none; + padding: 0 0 0 6px; } /* fixes for bootstrap */ .caret { @@ -4578,17 +4571,26 @@ td.setting-input textarea { .short-summary:first-child { padding-top: 0; } - #searchBar, - body.anon #searchBar { - margin: -49px 8px 0 52px; - } - .search-drop-menu, - body.anon .search-drop-menu { - margin: 0 8px 0 52px; - } .short-summary { width: 100%; } + #secondaryHeader td.search-bar { + padding: 0 6px; + } +} +@media screen and (max-width: 540px) { + .question-page .post-controls { + float: left; + margin-left: -8px; + padding-left: 0; + text-align: left; + } + .question-page .post-controls .question-close { + display: none; + } + .question-page div.comments.empty { + margin-top: 0; + } } @media screen and (max-width: 480px) { .openid-signin h1, @@ -4609,6 +4611,15 @@ td.setting-input textarea { width: 100%; } } +@media screen and (max-width: 380px) { + .wmd-button-bar .wmd-hr-button, + .wmd-button-bar .wmd-heading-button { + display: none; + } + .editor-status { + margin-right: 0; + } +} @media screen and (max-width: 338px) { #scopeNav { display: none; @@ -4624,6 +4635,9 @@ td.setting-input textarea { width: 100%; margin: 6px 0; } + .question-page .post-controls .offensive-flag { + display: none; + } } /* language-specific fixes */ body.lang-zh .box .inputs #interestingTagInput, @@ -4694,39 +4708,12 @@ body.lang-zh-tw.question-page a.submit, body.lang-zh_TW.question-page a.submit { line-height: 30px !important; } -body.lang-zh .scopes-True-True-False #searchBar, -body.lang-zh_CN .scopes-True-True-False #searchBar, -body.lang-zh-cn .scopes-True-True-False #searchBar, -body.lang-zh-tw .scopes-True-True-False #searchBar, -body.lang-zh_TW .scopes-True-True-False #searchBar, -body.lang-zh .scopes-True-True-False .search-drop-menu, -body.lang-zh_CN .scopes-True-True-False .search-drop-menu, -body.lang-zh-cn .scopes-True-True-False .search-drop-menu, -body.lang-zh-tw .scopes-True-True-False .search-drop-menu, -body.lang-zh_TW .scopes-True-True-False .search-drop-menu { - margin-left: 194px; -} -body.lang-zh .scopes-True-True-True #searchBar, -body.lang-zh_CN .scopes-True-True-True #searchBar, -body.lang-zh-cn .scopes-True-True-True #searchBar, -body.lang-zh-tw .scopes-True-True-True #searchBar, -body.lang-zh_TW .scopes-True-True-True #searchBar, -body.lang-zh .scopes-True-True-True .search-drop-menu, -body.lang-zh_CN .scopes-True-True-True .search-drop-menu, -body.lang-zh-cn .scopes-True-True-True .search-drop-menu, -body.lang-zh-tw .scopes-True-True-True .search-drop-menu, -body.lang-zh_TW .scopes-True-True-True .search-drop-menu { - margin-left: 274px; -} body.lang-hu .scope-selector { font-size: 17px; margin-left: 10px; } -body.lang-hu .scopes-True-True-False #scopeNav { - width: 200px; -} -body.lang-hu .scopes-True-True-False #searchBar, -body.lang-hu .scopes-True-True-False .search-drop-menu { +body.lang-hu #searchBar, +body.lang-hu .search-drop-menu { margin-left: 252px; } body.lang-hu .box .inputs #interestingTagInput, @@ -4755,34 +4742,9 @@ body.lang-es .short-summary .counts .views div, body.lang-es .short-summary .counts .votes div { font-size: 10px; } -body.lang-es .scopes-True-True-False #scopeNav { - width: 187px; -} -body.lang-es .scopes-True-True-False #searchBar, -body.lang-es .scopes-True-True-False .search-drop-menu { - margin-left: 250px; -} -body.lang-es .scopes-True-True-True #searchBar, -body.lang-es .scopes-True-True-True .search-drop-menu { - margin-left: 327px; -} body.lang-de .scope-selector { font-size: 17px; } -body.lang-de .scopes-True-True-False #scopeNav { - width: 218px; -} -body.lang-de .scopes-True-True-False #searchBar, -body.lang-de .scopes-True-True-False .search-drop-menu { - margin-left: 250px; -} -body.lang-de .scopes-True-True-True #scopeNav { - width: 354px; -} -body.lang-de .scopes-True-True-True #searchBar, -body.lang-de .scopes-True-True-True .search-drop-menu { - margin-left: 354px; -} body.lang-de #metaNav a { font-size: 16px; } @@ -4801,24 +4763,12 @@ body.lang-gl .box .inputs #subscribedTagInput, body.lang-gl .box .inputs #ab-tag-search { width: 127px; } -body.lang-gl .scopes-True-True-True #searchBar, -body.lang-gl .scopes-True-True-True .search-drop-menu { - margin-left: 299px; -} body.lang-pt_BR .box .inputs #interestingTagInput, body.lang-pt_BR .box .inputs #ignoredTagInput, body.lang-pt_BR .box .inputs #subscribedTagInput, body.lang-pt_BR .box .inputs #ab-tag-search { width: 116px; } -body.lang-pt_BR .scopes-True-True-False #searchBar, -body.lang-pt_BR .scopes-True-True-False .search-drop-menu { - margin-left: 236px; -} -body.lang-fr .scopes-True-True-True #searchBar, -body.lang-fr .scopes-True-True-True .search-drop-menu { - margin-left: 287px; -} body.lang-fr .box .inputs #interestingTagInput, body.lang-fr .box .inputs #ignoredTagInput, body.lang-fr .box .inputs #subscribedTagInput, @@ -4834,34 +4784,15 @@ body.lang-fi #scopeNav { body.lang-fi .scope-selector { font-size: 17px; } -body.lang-fi .scopes-True-True-True #searchBar, -body.lang-fi .scopes-True-True-True .search-drop-menu { - margin-left: 371px; -} -body.lang-fi .scopes-True-True-False #searchBar, -body.lang-fi .scopes-True-True-False .search-drop-menu { - margin-left: 268px; -} body.lang-fi .box .inputs #interestingTagInput, body.lang-fi .box .inputs #ignoredTagInput, body.lang-fi .box .inputs #subscribedTagInput, body.lang-fi .box .inputs #ab-tag-search { width: 142px; } -body.lang-ru #scopeNav { - width: 315px; -} body.lang-ru .scope-selector { font-size: 17px; } -body.lang-ru .scopes-True-True-True #searchBar, -body.lang-ru .scopes-True-True-True .search-drop-menu { - margin-left: 326px; -} -body.lang-ru .scopes-True-True-False #searchBar, -body.lang-ru .scopes-True-True-False .search-drop-menu { - margin-left: 227px; -} body.lang-ru .box .inputs #interestingTagInput, body.lang-ru .box .inputs #ignoredTagInput, body.lang-ru .box .inputs #subscribedTagInput, @@ -4871,32 +4802,12 @@ body.lang-ru .box .inputs #ab-tag-search { body.lang-ko #scopeNav { width: 315px; } -body.lang-ko .scopes-True-True-True #searchBar, -body.lang-ko .scopes-True-True-True .search-drop-menu { - margin-left: 248px; -} -body.lang-ko .scopes-True-True-False #searchBar, -body.lang-ko .scopes-True-True-False .search-drop-menu { - margin-left: 183px; -} body.lang-ko .box .inputs #interestingTagInput, body.lang-ko .box .inputs #ignoredTagInput, body.lang-ko .box .inputs #subscribedTagInput, body.lang-ko .box .inputs #ab-tag-search { width: 144px; } -body.lang-nb_NO .scopes-True-True-True #searchBar, -body.lang-nb_NO .scopes-True-True-True #searchBar, -body.lang-nb_NO .scopes-True-True-True .search-drop-menu, -body.lang-nb_NO .scopes-True-True-True .search-drop-menu { - margin-left: 289px; -} -body.lang-nb_NO .scopes-True-True-False #searchBar, -body.lang-nb_NO .scopes-True-True-False #searchBar, -body.lang-nb_NO .scopes-True-True-False .search-drop-menu, -body.lang-nb_NO .scopes-True-True-False .search-drop-menu { - margin-left: 220px; -} body.lang-nb_NO .box .inputs #interestingTagInput, body.lang-nb_NO .box .inputs #interestingTagInput, body.lang-nb_NO .box .inputs #ignoredTagInput, diff --git a/askbot/media/style/style.less b/askbot/media/style/style.less index 513fc6b3..e4a5623b 100644 --- a/askbot/media/style/style.less +++ b/askbot/media/style/style.less @@ -205,6 +205,9 @@ h1 { body.user-messages { margin-top: 2.4em; + box-sizing: border-box; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; } /* ----- Custom positions ----- */ @@ -487,37 +490,44 @@ body.user-messages { border-top:#fcfcfc 1px solid; margin-bottom:10px; font-family:@main-font; + box-sizing: border-box; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + td { + padding: 0; + &.search-bar { + padding: 0 32px 0 15px; + position: relative; + } + } } #homeButton{ border-right: #afaf9e 1px solid; .sprites(-6px,-36px); - height:55px; - width:43px; - display:block; - float:left; + height: 54px; + width: 43px; + display: block; + float: left; } -#homeButton:hover{ +#homeButton:hover { .sprites(-51px,-36px); } .scope-selector { - display:block; - float:left; - font-size:20px; - color:#7a7a6b; - height:55px; - line-height:55px; - margin-left:16px -} - -.scope-selector.on { - background:url(../images/scopearrow.png) no-repeat center bottom; -} - -.scope-selector.ask-message { - font-size:24px; + display: inline-block; + font-size: 20px; + color: #7a7a6b; + height: 55px; + line-height: 55px; + margin-left: 16px; + &.on { + background: url(../images/scopearrow.png) no-repeat center 41px; + } + &.ask-message { + font-size: 24px; + } } .validate-email-page { @@ -539,12 +549,12 @@ body.user-messages { } #searchBar { /* Main search form , check widgets/search_bar.html */ - display: block; - background-color: #fff; border: 1px solid #c9c9b5; + background: white; height: 41px; z-index: 1000; position: relative; + width: 100%; /* the guts are absolute-positioned */ input.searchInput, @@ -605,17 +615,20 @@ body.user-messages { .search-drop-menu { box-sizing: border-box; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; background: whitesmoke; - border: 1px solid #c9c9b5; border-top: none; + top: 42px; margin: 0; - position: relative; + outline: 1px solid #dadad4; + position: absolute; z-index: 10000; ul { list-style: none; overflow: auto; - padding: 0 0 10px 0; + padding: 0; margin: 0; position: relative; width: 100%; @@ -634,13 +647,13 @@ body.user-messages { } } - ul.empty { - margin-bottom: 0; - } - .footer { text-align: center; - padding: 9px 0 10px 0; + margin: 0 0 1px 0; + padding: 4px 0 10px 0; + } + &.empty .footer { + padding-top: 9px; } } @@ -666,7 +679,7 @@ input[type="submit"].searchBtn { border:#FFF 1px solid; line-height: 22px; text-align: center; - margin: 1px 0 0 0; + margin: 0; width: 48px; .sprites(-98px,-37px); .rounded-corners(0); @@ -694,12 +707,18 @@ input[type="submit"].searchBtn { color: white; height: 0; z-index: 0; + position: absolute; + left: -1000px;/* hide away */ } - .search-drop-menu.empty { - border: none; - padding: 0; - ul { - padding: 0; + .search-drop-menu { + top: 37px; + &.empty { + border: none; + outline: none; + padding: 0 !important; + ul { + padding: 0 !important; + } } } } @@ -822,74 +841,22 @@ form.ajax-file-upload { font-size: 20px; height: 42px; line-height: 44px; - margin: 6px 0 0 0; + margin: -1px 0 0 0; text-transform: uppercase; width: 200px;/* to match width of sidebar */ } -/* - Put the secondary navigation together: - 1) raise the search bar by 55px - 2) add padding to fit the buttons -*/ -#searchBar { - margin: 0 228px 0 327px; - width: auto; - margin-top: -49px; - padding: 0 49px 0 8px; -} -/* line up drop menu the same way as the search bar */ .search-drop-menu { - margin: 0 228px 0 327px; - width: auto; + width: 100%; } .ask-page .search-drop-menu, body.anon.ask-page .search-drop-menu { - margin: -9px 0 10px; + padding: 5px 10px 6px 0; } #scopeNav { - height: 41px; - float: left; - width: 280px; -} -.scopes-True-True-False { - #searchBar, - .search-drop-menu { - margin-left: 228px; - } - #scopeNav { - width: 180px; - } -} -.scopes-True-False-True { - #searchBar, - .search-drop-menu { - margin-left: 203px; - } - #scopeNav { - width: 150px; - } -} -.scopes-False-True-True { - #searchBar, - .search-drop-menu { - margin-left: 286px; - } - #scopeNav { - width: 238px; - } -} -.scopes-True-False-False, -.scopes-False-True-False, -.scopes-False-False-True, -.scopes-False-False-False { - #searchBar, - .search-drop-menu { - margin-left: 52px; - } - #scopeNav { - width: 0; - } + height: 54px; + display: inline-block; + white-space: nowrap; } /* ----- Content layout, check two_column_body.html or one_column_body.html ----- */ @@ -1121,7 +1088,7 @@ body.anon.ask-page .search-drop-menu { -khtml-border-radius: 5px; -webkit-border-radius: 5px; .box-shadow(1px, 1px, 3px, #999); - padding: 7px 10px 1px 10px; + padding: 7px 10px 9px 0; margin-bottom: 10px; width: 100%; ul { @@ -1255,7 +1222,8 @@ body.anon.ask-page .search-drop-menu { ul#searchTags { margin-left:10px; float:right; - padding-top:2px; + padding: 8px 6px 0px 6px; + min-width: 43px; } .search-tips { @@ -1462,25 +1430,25 @@ ul#searchTags { } .page a, .page a:visited, .curr { - padding: .25em; - margin: 0em .25em; + padding: 0 .25em; + margin: 0em .15em 0 0; } .curr { - background-color: #8ebcc7; + /*background-color: #8ebcc7;*/ color: #fff; font-weight: bold; a { background: #8ebcc7; color: white; - padding: 0; + /*padding: 0;*/ } } .curr.page { a:hover { background: #8ebcc7; color: white; - padding: 0; + padding: 0 0.25em; } } @@ -1606,7 +1574,7 @@ ul#related-tags li { background: #f3f6f6; border:#fff 1px solid ; border-top:#fff 2px solid; - outline:#cfdbdb 1px solid; + outline:#cfdbdb 1px solid !important; /* .box-shadow(0px,1px,0px,#88a8a8);*/ display: block; float: left; @@ -1774,6 +1742,7 @@ ul#related-tags li { padding: 4px 0 0 0; margin-top:0px; width: 100%; + position: relative; p { margin:0 0 5px 0; @@ -2288,7 +2257,7 @@ ul#related-tags li { float: right; font-size: 9px; font-family:@secondary-font; - line-height: 13px; + line-height: 12px; margin:0px 0px 5px 5px; padding:4px; width: 166px; @@ -3805,6 +3774,15 @@ a.offensive { margin-bottom: 0px; } +.system-messages { + color: red; + background: yellow; + font-size: 21px; + font-weight: bold; + line-height: 25px; + padding: 0 5px; +} + p.space-above { margin-top: 10px; } @@ -4196,7 +4174,7 @@ p.signup_p { .avatar-box { float: left; - margin: 3px 6px 0 0; + margin: 0px 6px 0 2px; } .info { height: 32px; @@ -4255,6 +4233,10 @@ a.primary-group-name { font-weight: bold; } +.post-update-info .user-info { + margin-top: -2px; +} + .users-page { .wmd-prompt-dialog { background: #ccc; @@ -4414,27 +4396,31 @@ textarea.tipped-input { /* tag editor */ .tag-editor { - height: 64px; - border: #ccc 3px solid; - padding-left: 8px; + height: 32px; + border: #cce6ec 3px solid; + padding-left: 6px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); ul.tags { margin: 0; li { - margin-top: 8px; + margin-top: 6px; height: 13px; } } input.new-tags-input, input.new-tags-input:focus { border: none; - font-size: 15px; + box-shadow: none; + font-size: 14px; font-color: @info-text; height: 16px; line-height: 16px; - margin-top: 9px; + margin: 9px 0 0 -6px; -webkit-box-shadow: none;/* undo bootstrap glow */ -moz-box-shadow: none; - box-shadow: none; + padding: 0 0 0 6px; } } @@ -4815,17 +4801,29 @@ td.setting-input { .short-summary:first-child { padding-top: 0; } - #searchBar, - body.anon #searchBar { - margin: -49px 8px 0 52px; - } - .search-drop-menu, - body.anon .search-drop-menu { - margin: 0 8px 0 52px; - } .short-summary { width: 100%; } + #secondaryHeader td.search-bar { + padding: 0 6px; + } +} + +@media screen and (max-width: 540px) { + .question-page { + .post-controls { + float: left; + margin-left: -8px; + padding-left: 0; + text-align: left; + .question-close { + display: none; + } + } + div.comments.empty { + margin-top: 0; + } + } } @media screen and (max-width: 480px) { @@ -4848,6 +4846,18 @@ td.setting-input { } } +@media screen and (max-width: 380px) { + .wmd-button-bar { + .wmd-hr-button, + .wmd-heading-button { + display: none; + } + } + .editor-status { + margin-right: 0; + } +} + @media screen and (max-width: 338px) { #scopeNav { display: none; @@ -4862,6 +4872,11 @@ td.setting-input { margin: 6px 0; } } + .question-page .post-controls { + .offensive-flag { + display: none; + } + } } /* language-specific fixes */ @@ -4892,33 +4907,16 @@ body.lang-zh_TW { &.question-page a.submit { line-height: 30px !important; } - .scopes-True-True-False { - #searchBar, - .search-drop-menu { - margin-left: 194px; - } - } - .scopes-True-True-True { - #searchBar, - .search-drop-menu { - margin-left: 274px; - } - } } body.lang-hu { - .scope-selector{ + .scope-selector { font-size: 17px; margin-left: 10px; } - .scopes-True-True-False { - #scopeNav { - width: 200px; - } - #searchBar, - .search-drop-menu { + #searchBar, + .search-drop-menu { margin-left: 252px; - } } .box { .inputs{ @@ -4957,45 +4955,12 @@ body.lang-es { .short-summary .counts .votes div { font-size: 10px; } - .scopes-True-True-False { - #scopeNav { - width: 187px; - } - #searchBar, - .search-drop-menu { - margin-left: 250px; - } - } - .scopes-True-True-True { - #searchBar, - .search-drop-menu { - margin-left: 327px; - } - } } body.lang-de { .scope-selector { font-size: 17px; } - .scopes-True-True-False { - #scopeNav { - width: 218px; - } - #searchBar, - .search-drop-menu { - margin-left: 250px; - } - } - .scopes-True-True-True { - #scopeNav { - width: 354px; - } - #searchBar, - .search-drop-menu { - margin-left: 354px; - } - } #metaNav a { font-size: 16px; } @@ -5025,12 +4990,6 @@ body.lang-gl { } } } - .scopes-True-True-True { - #searchBar, - .search-drop-menu { - margin-left: 299px; - } - } } body.lang-pt_BR { @@ -5044,21 +5003,9 @@ body.lang-pt_BR { } } } - .scopes-True-True-False { - #searchBar, - .search-drop-menu { - margin-left: 236px; - } - } } body.lang-fr { - .scopes-True-True-True { - #searchBar, - .search-drop-menu { - margin-left: 287px; - } - } .box { .inputs { #interestingTagInput, @@ -5081,18 +5028,6 @@ body.lang-fi { .scope-selector { font-size: 17px; } - .scopes-True-True-True { - #searchBar, - .search-drop-menu { - margin-left: 371px; - } - } - .scopes-True-True-False { - #searchBar, - .search-drop-menu { - margin-left: 268px; - } - } .box { .inputs { #interestingTagInput, @@ -5106,24 +5041,9 @@ body.lang-fi { } body.lang-ru { - #scopeNav { - width: 315px; - } .scope-selector { font-size: 17px; } - .scopes-True-True-True { - #searchBar, - .search-drop-menu { - margin-left: 326px; - } - } - .scopes-True-True-False { - #searchBar, - .search-drop-menu { - margin-left: 227px; - } - } .box { .inputs { #interestingTagInput, @@ -5140,18 +5060,6 @@ body.lang-ko { #scopeNav { width: 315px; } - .scopes-True-True-True { - #searchBar, - .search-drop-menu { - margin-left: 248px; - } - } - .scopes-True-True-False { - #searchBar, - .search-drop-menu { - margin-left: 183px; - } - } .box { .inputs { #interestingTagInput, @@ -5166,18 +5074,6 @@ body.lang-ko { body.lang-nb_NO, body.lang-nb_NO, { - .scopes-True-True-True { - #searchBar, - .search-drop-menu { - margin-left: 289px; - } - } - .scopes-True-True-False { - #searchBar, - .search-drop-menu { - margin-left: 220px; - } - } .box { .inputs { #interestingTagInput, diff --git a/askbot/middleware/cancel.py b/askbot/middleware/cancel.py index f13d8d69..ac2f3ded 100644 --- a/askbot/middleware/cancel.py +++ b/askbot/middleware/cancel.py @@ -8,7 +8,7 @@ class CancelActionMiddleware(object): msg = getattr(view_func,'CANCEL_MESSAGE') except AttributeError: msg = 'action canceled' - request.user.message_set.create(message=msg) + request.user.message_set.create(message=unicode(msg)) return HttpResponseRedirect(get_next_url(request)) else: return None diff --git a/askbot/middleware/forum_mode.py b/askbot/middleware/forum_mode.py index 331fe85b..5fd2bda3 100644 --- a/askbot/middleware/forum_mode.py +++ b/askbot/middleware/forum_mode.py @@ -8,13 +8,14 @@ from django.conf import settings from django.core.urlresolvers import resolve from askbot.shims.django_shims import ResolverMatch from askbot.conf import settings as askbot_settings +import urllib PROTECTED_VIEW_MODULES = ( 'askbot.views', 'askbot.feed', ) ALLOWED_VIEWS = ( - 'askbot.views.meta.media', + 'askbot.views.meta.config_variable', ) def is_view_protected(view_func): @@ -63,5 +64,9 @@ class ForumModeMiddleware(object): _('Please log in to use %s') % \ askbot_settings.APP_SHORT_NAME ) - return HttpResponseRedirect(settings.LOGIN_URL) + redirect_url = '%s?next=%s' % ( + settings.LOGIN_URL, + urllib.quote_plus(request.get_full_path()) + ) + return HttpResponseRedirect(redirect_url) return None diff --git a/askbot/migrations/0006_add_subscription_setting_for_comments_and_mentions.py b/askbot/migrations/0006_add_subscription_setting_for_comments_and_mentions.py index 1dbfe24f..711e87e4 100644 --- a/askbot/migrations/0006_add_subscription_setting_for_comments_and_mentions.py +++ b/askbot/migrations/0006_add_subscription_setting_for_comments_and_mentions.py @@ -45,7 +45,7 @@ class Migration(DataMigration): new_feed.save() verbose_frequency = unicode(dict(const.NOTIFICATION_DELIVERY_SCHEDULE_CHOICES)[frequency]) print 'added \'%s\' subscription for %s (%d)' % ( - verbose_frequency, + unicode(verbose_frequency), unidecode(user.username), user.id ) diff --git a/askbot/migrations/0032_auto__del_field_badgedata_multiple__del_field_badgedata_description__d.py b/askbot/migrations/0032_auto__del_field_badgedata_multiple__del_field_badgedata_description__d.py index 2c58d82a..d7c28d3e 100644 --- a/askbot/migrations/0032_auto__del_field_badgedata_multiple__del_field_badgedata_description__d.py +++ b/askbot/migrations/0032_auto__del_field_badgedata_multiple__del_field_badgedata_description__d.py @@ -9,7 +9,7 @@ class Migration(SchemaMigration): def forwards(self, orm): # Removing unique constraint on 'BadgeData', fields ['type', 'name'] - #db.delete_unique('askbot_badgedata', ['type', 'name']) + db.delete_unique('askbot_badgedata', ['type', 'name']) # Deleting field 'BadgeData.multiple' db.delete_column('askbot_badgedata', 'multiple') @@ -17,6 +17,7 @@ class Migration(SchemaMigration): # Deleting field 'BadgeData.description' db.delete_column('askbot_badgedata', 'description') + # Deleting field 'BadgeData.type' db.delete_column('askbot_badgedata', 'type') diff --git a/askbot/migrations/0171_auto__add_importedobjectinfo__add_importrun.py b/askbot/migrations/0171_auto__add_importedobjectinfo__add_importrun.py new file mode 100644 index 00000000..8822dda8 --- /dev/null +++ b/askbot/migrations/0171_auto__add_importedobjectinfo__add_importrun.py @@ -0,0 +1,439 @@ +# -*- coding: utf-8 -*- +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding model 'ImportedObjectInfo' + db.create_table('askbot_importedobjectinfo', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('old_id', self.gf('django.db.models.fields.IntegerField')()), + ('new_id', self.gf('django.db.models.fields.IntegerField')()), + ('model', self.gf('django.db.models.fields.CharField')(default='', max_length=255)), + ('run', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['askbot.ImportRun'])), + ('extra_info', self.gf('picklefield.fields.PickledObjectField')()), + )) + db.send_create_signal('askbot', ['ImportedObjectInfo']) + + # Adding model 'ImportRun' + db.create_table('askbot_importrun', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('command', self.gf('django.db.models.fields.TextField')(default='')), + ('timestamp', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)), + )) + db.send_create_signal('askbot', ['ImportRun']) + + + def backwards(self, orm): + # Deleting model 'ImportedObjectInfo' + db.delete_table('askbot_importedobjectinfo') + + # Deleting model 'ImportRun' + db.delete_table('askbot_importrun') + + + models = { + 'askbot.activity': { + 'Meta': {'object_name': 'Activity', 'db_table': "u'activity'"}, + 'active_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'activity_type': ('django.db.models.fields.SmallIntegerField', [], {}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_auditted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']", 'null': 'True'}), + 'receiving_users': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'received_activity'", 'symmetrical': 'False', 'to': "orm['auth.User']"}), + 'recipients': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'incoming_activity'", 'symmetrical': 'False', 'through': "orm['askbot.ActivityAuditStatus']", 'to': "orm['auth.User']"}), + 'summary': ('django.db.models.fields.TextField', [], {'default': "''"}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}) + }, + 'askbot.activityauditstatus': { + 'Meta': {'unique_together': "(('user', 'activity'),)", 'object_name': 'ActivityAuditStatus'}, + 'activity': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Activity']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}) + }, + 'askbot.anonymousanswer': { + 'Meta': {'object_name': 'AnonymousAnswer'}, + 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}), + 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'anonymous_answers'", 'to': "orm['askbot.Post']"}), + 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}), + 'text': ('django.db.models.fields.TextField', [], {}), + 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'}) + }, + 'askbot.anonymousquestion': { + 'Meta': {'object_name': 'AnonymousQuestion'}, + 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}), + 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}), + 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}), + 'text': ('django.db.models.fields.TextField', [], {}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}), + 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'}) + }, + 'askbot.askwidget': { + 'Meta': {'object_name': 'AskWidget'}, + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Group']", 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'include_text_field': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'inner_style': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'outer_style': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'tag': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Tag']", 'null': 'True', 'blank': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'askbot.award': { + 'Meta': {'object_name': 'Award', 'db_table': "u'award'"}, + 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['askbot.BadgeData']"}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_user'", 'to': "orm['auth.User']"}) + }, + 'askbot.badgedata': { + 'Meta': {'ordering': "('slug',)", 'object_name': 'BadgeData'}, + 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'symmetrical': 'False', 'through': "orm['askbot.Award']", 'to': "orm['auth.User']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50'}) + }, + 'askbot.bulktagsubscription': { + 'Meta': {'ordering': "['-date_added']", 'object_name': 'BulkTagSubscription'}, + 'date_added': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['askbot.Group']", 'symmetrical': 'False'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['askbot.Tag']", 'symmetrical': 'False'}), + 'users': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.User']", 'symmetrical': 'False'}) + }, + 'askbot.draftanswer': { + 'Meta': {'object_name': 'DraftAnswer'}, + 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'draft_answers'", 'to': "orm['auth.User']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}), + 'thread': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'draft_answers'", 'to': "orm['askbot.Thread']"}) + }, + 'askbot.draftquestion': { + 'Meta': {'object_name': 'DraftQuestion'}, + 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125', 'null': 'True'}), + 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True'}) + }, + 'askbot.emailfeedsetting': { + 'Meta': {'unique_together': "(('subscriber', 'feed_type'),)", 'object_name': 'EmailFeedSetting'}, + 'added_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'feed_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}), + 'frequency': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '8'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'reported_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), + 'subscriber': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'notification_subscriptions'", 'to': "orm['auth.User']"}) + }, + 'askbot.favoritequestion': { + 'Meta': {'object_name': 'FavoriteQuestion', 'db_table': "u'favorite_question'"}, + 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'thread': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Thread']"}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['auth.User']"}) + }, + 'askbot.group': { + 'Meta': {'object_name': 'Group', '_ormbases': ['auth.Group']}, + 'description': ('django.db.models.fields.related.OneToOneField', [], {'blank': 'True', 'related_name': "'described_group'", 'unique': 'True', 'null': 'True', 'to': "orm['askbot.Post']"}), + 'group_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.Group']", 'unique': 'True', 'primary_key': 'True'}), + 'is_vip': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'logo_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True'}), + 'moderate_answers_to_enquirers': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'moderate_email': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'openness': ('django.db.models.fields.SmallIntegerField', [], {'default': '2'}), + 'preapproved_email_domains': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'}), + 'preapproved_emails': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'}), + 'read_only': ('django.db.models.fields.BooleanField', [], {'default': 'False'}) + }, + 'askbot.groupmembership': { + 'Meta': {'object_name': 'GroupMembership', '_ormbases': ['auth.AuthUserGroups']}, + 'authusergroups_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.AuthUserGroups']", 'unique': 'True', 'primary_key': 'True'}), + 'level': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}) + }, + 'askbot.importedobjectinfo': { + 'Meta': {'object_name': 'ImportedObjectInfo'}, + 'extra_info': ('picklefield.fields.PickledObjectField', [], {}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), + 'new_id': ('django.db.models.fields.IntegerField', [], {}), + 'old_id': ('django.db.models.fields.IntegerField', [], {}), + 'run': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.ImportRun']"}) + }, + 'askbot.importrun': { + 'Meta': {'object_name': 'ImportRun'}, + 'command': ('django.db.models.fields.TextField', [], {'default': "''"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'timestamp': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}) + }, + 'askbot.markedtag': { + 'Meta': {'object_name': 'MarkedTag'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}), + 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['askbot.Tag']"}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['auth.User']"}) + }, + 'askbot.post': { + 'Meta': {'object_name': 'Post'}, + 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}), + 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'posts'", 'to': "orm['auth.User']"}), + 'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}), + 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_posts'", 'null': 'True', 'to': "orm['auth.User']"}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'group_posts'", 'symmetrical': 'False', 'through': "orm['askbot.PostToGroup']", 'to': "orm['askbot.Group']"}), + 'html': ('django.db.models.fields.TextField', [], {'null': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'language_code': ('django.db.models.fields.CharField', [], {'default': "'en'", 'max_length': '16'}), + 'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_posts'", 'null': 'True', 'to': "orm['auth.User']"}), + 'locked': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'locked_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'locked_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locked_posts'", 'null': 'True', 'to': "orm['auth.User']"}), + 'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}), + 'old_answer_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}), + 'old_comment_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}), + 'old_question_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}), + 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'comments'", 'null': 'True', 'to': "orm['askbot.Post']"}), + 'points': ('django.db.models.fields.IntegerField', [], {'default': '0', 'db_column': "'score'"}), + 'post_type': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'summary': ('django.db.models.fields.TextField', [], {'null': 'True'}), + 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}), + 'thread': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'posts'", 'null': 'True', 'blank': 'True', 'to': "orm['askbot.Thread']"}), + 'vote_down_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'vote_up_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}) + }, + 'askbot.postflagreason': { + 'Meta': {'object_name': 'PostFlagReason'}, + 'added_at': ('django.db.models.fields.DateTimeField', [], {}), + 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), + 'details': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'post_reject_reasons'", 'to': "orm['askbot.Post']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '128'}) + }, + 'askbot.postrevision': { + 'Meta': {'ordering': "('-revision',)", 'unique_together': "(('post', 'revision'),)", 'object_name': 'PostRevision'}, + 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}), + 'approved_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'approved_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}), + 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'postrevisions'", 'to': "orm['auth.User']"}), + 'by_email': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'email_address': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'post': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'revisions'", 'null': 'True', 'to': "orm['askbot.Post']"}), + 'revised_at': ('django.db.models.fields.DateTimeField', [], {}), + 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300', 'blank': 'True'}), + 'tagnames': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '125', 'blank': 'True'}), + 'text': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '300', 'blank': 'True'}) + }, + 'askbot.posttogroup': { + 'Meta': {'unique_together': "(('post', 'group'),)", 'object_name': 'PostToGroup', 'db_table': "'askbot_post_groups'"}, + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Group']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'post': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']"}) + }, + 'askbot.questionview': { + 'Meta': {'object_name': 'QuestionView'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'viewed'", 'to': "orm['askbot.Post']"}), + 'when': ('django.db.models.fields.DateTimeField', [], {}), + 'who': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'question_views'", 'to': "orm['auth.User']"}) + }, + 'askbot.questionwidget': { + 'Meta': {'object_name': 'QuestionWidget'}, + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Group']", 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'order_by': ('django.db.models.fields.CharField', [], {'default': "'-added_at'", 'max_length': '18'}), + 'question_number': ('django.db.models.fields.PositiveIntegerField', [], {'default': '7'}), + 'search_query': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'null': 'True', 'blank': 'True'}), + 'style': ('django.db.models.fields.TextField', [], {'default': '"\\n@import url(\'http://fonts.googleapis.com/css?family=Yanone+Kaffeesatz:300,400,700\');\\nbody {\\n overflow: hidden;\\n}\\n\\n#container {\\n width: 200px;\\n height: 350px;\\n}\\nul {\\n list-style: none;\\n padding: 5px;\\n margin: 5px;\\n}\\nli {\\n border-bottom: #CCC 1px solid;\\n padding-bottom: 5px;\\n padding-top: 5px;\\n}\\nli:last-child {\\n border: none;\\n}\\na {\\n text-decoration: none;\\n color: #464646;\\n font-family: \'Yanone Kaffeesatz\', sans-serif;\\n font-size: 15px;\\n}\\n"', 'blank': 'True'}), + 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '50'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'askbot.replyaddress': { + 'Meta': {'object_name': 'ReplyAddress'}, + 'address': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '25'}), + 'allowed_from_email': ('django.db.models.fields.EmailField', [], {'max_length': '150'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reply_addresses'", 'null': 'True', 'to': "orm['askbot.Post']"}), + 'reply_action': ('django.db.models.fields.CharField', [], {'default': "'auto_answer_or_comment'", 'max_length': '32'}), + 'response_post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'edit_addresses'", 'null': 'True', 'to': "orm['askbot.Post']"}), + 'used_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}) + }, + 'askbot.repute': { + 'Meta': {'object_name': 'Repute', 'db_table': "u'repute'"}, + 'comment': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'negative': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}), + 'positive': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}), + 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']", 'null': 'True', 'blank': 'True'}), + 'reputation': ('django.db.models.fields.IntegerField', [], {'default': '1'}), + 'reputation_type': ('django.db.models.fields.SmallIntegerField', [], {}), + 'reputed_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}) + }, + 'askbot.tag': { + 'Meta': {'ordering': "('-used_count', 'name')", 'object_name': 'Tag', 'db_table': "u'tag'"}, + 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['auth.User']"}), + 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['auth.User']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), + 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}), + 'suggested_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'suggested_tags'", 'symmetrical': 'False', 'to': "orm['auth.User']"}), + 'tag_wiki': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'described_tag'", 'unique': 'True', 'null': 'True', 'to': "orm['askbot.Post']"}), + 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}) + }, + 'askbot.tagsynonym': { + 'Meta': {'object_name': 'TagSynonym'}, + 'auto_rename_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'last_auto_rename_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), + 'owned_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_synonyms'", 'to': "orm['auth.User']"}), + 'source_tag_name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), + 'target_tag_name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}) + }, + 'askbot.thread': { + 'Meta': {'object_name': 'Thread'}, + 'accepted_answer': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'to': "orm['askbot.Post']"}), + 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'answer_accepted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'answer_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}), + 'close_reason': ('django.db.models.fields.SmallIntegerField', [], {'null': 'True', 'blank': 'True'}), + 'closed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'closed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'closed_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}), + 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}), + 'favorited_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'unused_favorite_threads'", 'symmetrical': 'False', 'through': "orm['askbot.FavoriteQuestion']", 'to': "orm['auth.User']"}), + 'favourite_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'followed_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'followed_threads'", 'symmetrical': 'False', 'to': "orm['auth.User']"}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'group_threads'", 'symmetrical': 'False', 'through': "orm['askbot.ThreadToGroup']", 'to': "orm['askbot.Group']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'language_code': ('django.db.models.fields.CharField', [], {'default': "'en'", 'max_length': '16'}), + 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'unused_last_active_in_threads'", 'to': "orm['auth.User']"}), + 'points': ('django.db.models.fields.IntegerField', [], {'default': '0', 'db_column': "'score'"}), + 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}), + 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'threads'", 'symmetrical': 'False', 'to': "orm['askbot.Tag']"}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}), + 'view_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}) + }, + 'askbot.threadtogroup': { + 'Meta': {'unique_together': "(('thread', 'group'),)", 'object_name': 'ThreadToGroup', 'db_table': "'askbot_thread_groups'"}, + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Group']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'thread': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Thread']"}), + 'visibility': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}) + }, + 'askbot.vote': { + 'Meta': {'unique_together': "(('user', 'voted_post'),)", 'object_name': 'Vote', 'db_table': "u'vote'"}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['auth.User']"}), + 'vote': ('django.db.models.fields.SmallIntegerField', [], {}), + 'voted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'voted_post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['askbot.Post']"}) + }, + 'auth.authusergroups': { + 'Meta': {'unique_together': "(('group', 'user'),)", 'object_name': 'AuthUserGroups', 'db_table': "'auth_user_groups'", 'managed': 'False'}, + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.Group']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}) + }, + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'avatar_type': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}), + 'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}), + 'consecutive_days_visit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'blank': 'True'}), + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), + 'display_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}), + 'email_signature': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'email_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}), + 'gravatar': ('django.db.models.fields.CharField', [], {'max_length': '32'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'ignored_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'interesting_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_fake': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'languages': ('django.db.models.fields.CharField', [], {'default': "'en'", 'max_length': '128'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}), + 'new_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}), + 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}), + 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}), + 'seen_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'show_country': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'show_marked_tags': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}), + 'social_sharing_mode': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}), + 'subscribed_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'twitter_access_token': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '256'}), + 'twitter_handle': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '32'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), + 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + } + } + + complete_apps = ['askbot']
\ No newline at end of file diff --git a/askbot/migrations_api/__init__.py b/askbot/migrations_api/__init__.py index a9b20a69..5a65f9cf 100644 --- a/askbot/migrations_api/__init__.py +++ b/askbot/migrations_api/__init__.py @@ -13,7 +13,7 @@ def safe_add_column(table, column, column_data, keep_default = False): so, we need to add these columns here in separate transactions and roll back if they fail, if we want we could also record - which columns clash """ - if db.backend_name == 'mysql': + if db.backend_name in ('mysql', 'postgres'): if len(db.execute('select column_name from information_schema.columns where table_name=%s and column_name=%s', params=[table, column])) == 0: db.add_column(table, column, column_data, keep_default = keep_default) else: diff --git a/askbot/models/__init__.py b/askbot/models/__init__.py index a2f55ab7..42f97185 100644 --- a/askbot/models/__init__.py +++ b/askbot/models/__init__.py @@ -35,7 +35,7 @@ from django.core import exceptions as django_exceptions from django_countries.fields import CountryField from askbot import exceptions as askbot_exceptions from askbot import const -from askbot.const.message_keys import get_i18n_message +from askbot.const import message_keys from askbot.conf import settings as askbot_settings from askbot.models.question import Thread from askbot.skins import utils as skin_utils @@ -54,10 +54,10 @@ from askbot.models.post import PostFlagReason, AnonymousAnswer from askbot.models.post import PostToGroup from askbot.models.post import DraftAnswer from askbot.models.reply_by_email import ReplyAddress -from askbot.models import signals -from askbot.models.badges import award_badges_signal, get_badge, BadgeData -from askbot.models.repute import Award, Repute, Vote +from askbot.models.badges import award_badges_signal, get_badge +from askbot.models.repute import Award, Repute, Vote, BadgeData from askbot.models.widgets import AskWidget, QuestionWidget +from askbot.models.meta import ImportRun, ImportedObjectInfo from askbot import auth from askbot.utils.decorators import auto_now_timestamp from askbot.utils.markup import URL_RE @@ -68,6 +68,7 @@ from askbot.utils.html import site_url from askbot.utils.diff import textDiff as htmldiff from askbot.utils.url_utils import strip_path from askbot import mail +from askbot.models import signals from django import VERSION @@ -76,6 +77,8 @@ DJANGO_VERSION = VERSION[:2] if DJANGO_VERSION > (1, 3): from askbot.models.message import Message +else: + from django.contrib.messages.models import Message def get_model(model_name): """a shortcut for getting model for an askbot app""" @@ -464,6 +467,13 @@ def user_has_interesting_wildcard_tags(self): and self.interesting_tags != '' ) +def user_has_badge(self, badge): + """True, if user was awarded a given badge, + ``badge`` is instance of BadgeData + """ + return Award.objects.filter(user=self, badge=badge).count() > 0 + + def user_can_create_tags(self): """true if user can create tags""" if askbot_settings.ENABLE_TAG_MODERATION: @@ -565,19 +575,16 @@ def user_get_notifications(self, notification_types=None, **kwargs): ) def _assert_user_can( - user = None, - post = None, #related post (may be parent) - admin_or_moderator_required = False, - owner_can = False, - suspended_owner_cannot = False, - owner_min_rep_setting = None, - blocked_error_message = None, - suspended_error_message = None, - min_rep_setting = None, - low_rep_error_message = None, - owner_low_rep_error_message = None, - general_error_message = None, - ): + user=None, + post=None, #related post (may be parent) + admin_or_moderator_required=False, + owner_can=False, + action_display=None, + suspended_owner_cannot=False, + suspended_user_cannot=False, + blocked_user_cannot=False, + min_rep_setting=None + ): """generic helper assert for use in several User.assert_can_XYZ() calls regarding changing content @@ -586,69 +593,81 @@ def _assert_user_can( if assertion fails, method raises exception.PermissionDenied with appropriate text as a payload """ + action_display = action_display or _('perform this action') if askbot_settings.GROUPS_ENABLED: if user.is_read_only(): message = _('Sorry, but you have only read access') raise django_exceptions.PermissionDenied(message) - if general_error_message is None: - general_error_message = _('Sorry, this operation is not allowed') - if blocked_error_message and user.is_blocked(): - error_message = blocked_error_message + if blocked_user_cannot and user.is_blocked(): + error_message = _(message_keys.ACCOUNT_CANNOT_PERFORM_ACTION) % { + 'perform_action': action_display, + 'your_account_is': _('your account is blocked') + } elif post and owner_can and user == post.get_owner(): - if owner_min_rep_setting: - if post.get_owner().reputation < owner_min_rep_setting: - if user.is_moderator() or user.is_administrator(): - return - else: - assert(owner_low_rep_error_message is not None) - raise askbot_exceptions.InsufficientReputation( - owner_low_rep_error_message - ) - if suspended_owner_cannot and user.is_suspended(): - if suspended_error_message: - error_message = suspended_error_message - else: - error_message = general_error_message - assert(error_message is not None) - raise django_exceptions.PermissionDenied(error_message) + if user.is_suspended() and suspended_owner_cannot: + error_message = _(message_keys.ACCOUNT_CANNOT_PERFORM_ACTION) % { + 'perform_action': action_display, + 'your_account_is': _('your account is suspended') + } else: return - return - elif suspended_error_message and user.is_suspended(): - error_message = suspended_error_message + elif suspended_user_cannot and user.is_suspended(): + error_message = _(message_keys.ACCOUNT_CANNOT_PERFORM_ACTION) % { + 'perform_action': action_display, + 'your_account_is': _('your account is suspended') + } elif user.is_administrator() or user.is_moderator(): return elif user.is_post_moderator(post): return - elif low_rep_error_message and user.reputation < min_rep_setting: - raise askbot_exceptions.InsufficientReputation(low_rep_error_message) + elif min_rep_setting and user.reputation < min_rep_setting: + raise askbot_exceptions.InsufficientReputation( + _(message_keys.MIN_REP_REQUIRED_TO_PERFORM_ACTION) % { + 'perform_action': action_display, + 'min_rep': min_rep_setting + } + ) + elif admin_or_moderator_required: + if min_rep_setting is None: + #message about admins only + error_message = _( + 'Sorry, only moderators and site administrators can %(perform_action)s' + ) % { + 'perform_action': action_display + } + else: + #message with minimum reputation + error_message = _( + 'Sorry, only administrators, moderators ' + 'or users with reputation > %(min_rep)s ' + 'can %(perform_action)s' + ) % { + 'min_rep': min_rep_setting, + 'perform_action': action_display + } else: - if admin_or_moderator_required == False: - return + return - #if admin or moderator is required, then substitute the message - if admin_or_moderator_required: - error_message = general_error_message assert(error_message is not None) raise django_exceptions.PermissionDenied(error_message) def user_assert_can_approve_post_revision(self, post_revision = None): _assert_user_can( - user = self, - admin_or_moderator_required = True + user=self, + admin_or_moderator_required=True ) def user_assert_can_unaccept_best_answer(self, answer = None): assert getattr(answer, 'post_type', '') == 'answer' - blocked_error_message = _( - 'Sorry, you cannot accept or unaccept best answers ' - 'because your account is blocked' - ) - suspended_error_message = _( - 'Sorry, you cannot accept or unaccept best answers ' - 'because your account is suspended' - ) + suspended_error_message = _(message_keys.ACCOUNT_CANNOT_PERFORM_ACTION) % { + 'perform_action': askbot_settings.WORDS_ACCEPT_OR_UNACCEPT_THE_BEST_ANSWER, + 'your_account_is': _('your account is suspended') + } + blocked_error_message = _(message_keys.ACCOUNT_CANNOT_PERFORM_ACTION) % { + 'perform_action': askbot_settings.WORDS_ACCEPT_OR_UNACCEPT_THE_BEST_ANSWER, + 'your_account_is': _('your account is blocked') + } if self.is_blocked(): error_message = blocked_error_message @@ -658,18 +677,12 @@ def user_assert_can_unaccept_best_answer(self, answer = None): if self == answer.get_owner(): if not self.is_administrator(): #check rep - min_rep_setting = askbot_settings.MIN_REP_TO_ACCEPT_OWN_ANSWER - low_rep_error_message = _( - ">%(points)s points required to accept or unaccept " - " your own answer to your own question" - ) % {'points': min_rep_setting} - _assert_user_can( - user = self, - blocked_error_message = blocked_error_message, - suspended_error_message = suspended_error_message, - min_rep_setting = min_rep_setting, - low_rep_error_message = low_rep_error_message + user=self, + action_display=askbot_settings.WORDS_ACCEPT_OR_UNACCEPT_OWN_ANSWER, + blocked_user_cannot=True, + suspended_owner_cannot=True, + min_rep_setting = askbot_settings.MIN_REP_TO_ACCEPT_OWN_ANSWER ) return # success @@ -683,19 +696,19 @@ def user_assert_can_unaccept_best_answer(self, answer = None): ) if datetime.datetime.now() < will_be_able_at: - error_message = _( - 'Sorry, you will be able to accept this answer ' - 'only after %(will_be_able_at)s' - ) % {'will_be_able_at': will_be_able_at.strftime('%d/%m/%Y')} + error_message = _(message_keys.CANNOT_PERFORM_ACTION_UNTIL) % { + 'perform_action': askbot_settings.WORDS_ACCEPT_OR_UNACCEPT_OWN_ANSWER, + 'until': will_be_able_at.strftime('%d/%m/%Y') + } else: return else: question_owner = answer.thread._question_post().get_owner() - error_message = _( - 'Sorry, only moderators or original author of the question ' - ' - %(username)s - can accept or unaccept the best answer' - ) % {'username': question_owner.username} + error_message = _(message_keys.MODERATORS_OR_AUTHOR_CAN_PEFROM_ACTION) % { + 'post_author': askbot_settings.WORDS_AUTHOR_OF_THE_QUESTION, + 'perform_action': askbot_settings.WORDS_ACCEPT_OR_UNACCEPT_THE_BEST_ANSWER, + } raise django_exceptions.PermissionDenied(error_message) @@ -719,54 +732,32 @@ def user_assert_can_vote_for_post( _('Sorry, you cannot vote for your own posts') ) - blocked_error_message = _( - 'Sorry your account appears to be blocked ' + - 'and you cannot vote - please contact the ' + - 'site administrator to resolve the issue' - ), - suspended_error_message = _( - 'Sorry your account appears to be suspended ' + - 'and you cannot vote - please contact the ' + - 'site administrator to resolve the issue' - ) - assert(direction in ('up', 'down')) if direction == 'up': min_rep_setting = askbot_settings.MIN_REP_TO_VOTE_UP - low_rep_error_message = _( - ">%(points)s points required to upvote" - ) % \ - {'points': askbot_settings.MIN_REP_TO_VOTE_UP} + action_display = _('upvote') else: min_rep_setting = askbot_settings.MIN_REP_TO_VOTE_DOWN - low_rep_error_message = _( - ">%(points)s points required to downvote" - ) % \ - {'points': askbot_settings.MIN_REP_TO_VOTE_DOWN} + action_display = _('downvote') _assert_user_can( - user = self, - blocked_error_message = blocked_error_message, - suspended_error_message = suspended_error_message, + user=self, + action_display=action_display, + blocked_user_cannot=True, + suspended_user_cannot=True, min_rep_setting = min_rep_setting, - low_rep_error_message = low_rep_error_message ) def user_assert_can_upload_file(request_user): - blocked_error_message = _('Sorry, blocked users cannot upload files') - suspended_error_message = _('Sorry, suspended users cannot upload files') - low_rep_error_message = _( - 'sorry, file uploading requires karma >%(min_rep)s', - ) % {'min_rep': askbot_settings.MIN_REP_TO_UPLOAD_FILES } - _assert_user_can( - user = request_user, - suspended_error_message = suspended_error_message, - min_rep_setting = askbot_settings.MIN_REP_TO_UPLOAD_FILES, - low_rep_error_message = low_rep_error_message + user=request_user, + action_display=_('upload files'), + blocked_user_cannot=True, + suspended_user_cannot=True, + min_rep_setting=askbot_settings.MIN_REP_TO_UPLOAD_FILES ) @@ -787,14 +778,11 @@ def user_assert_can_post_question(self): """raises exceptions.PermissionDenied with text that has the reason for the denial """ - - blocked_message = get_i18n_message('BLOCKED_USERS_CANNOT_POST') - suspended_message = get_i18n_message('SUSPENDED_USERS_CANNOT_POST') - _assert_user_can( - user = self, - blocked_error_message = blocked_message, - suspended_error_message = suspended_message + user=self, + action_display=askbot_settings.WORDS_ASK_QUESTIONS, + blocked_user_cannot=True, + suspended_user_cannot=True, ) @@ -804,8 +792,10 @@ def user_assert_can_post_answer(self, thread = None): limit_answers = askbot_settings.LIMIT_ONE_ANSWER_PER_USER if limit_answers and thread.has_answer_by_user(self): message = _( - 'Sorry, you already gave an answer, please edit it instead.' - ) + 'Sorry, %(you_already_gave_an_answer)s, please edit it instead.' + ) % { + 'you_already_gave_an_answer': askbot_settings.WORDS_YOU_ALREADY_GAVE_AN_ANSWER + } raise askbot_exceptions.AnswerAlreadyGiven(message) self.assert_can_post_question() @@ -848,18 +838,17 @@ def user_assert_can_edit_comment(self, comment = None): def user_can_post_comment(self, parent_post = None): """a simplified method to test ability to comment """ - return True - """ - #commented out to disable the min rep - if self.reputation >= askbot_settings.MIN_REP_TO_LEAVE_COMMENTS: - return True - if parent_post and self == parent_post.author: - return True if self.is_administrator_or_moderator(): return True - return False - """ + elif self.is_suspended(): + if parent_post and self == parent_post.author: + return True + else: + return False + elif self.is_blocked(): + return False + return True def user_assert_can_post_comment(self, parent_post = None): """raises exceptions.PermissionDenied if @@ -867,52 +856,35 @@ def user_assert_can_post_comment(self, parent_post = None): the reason will be in text of exception """ + _assert_user_can( + user=self, + post=parent_post, + action_display=_('post comments'), + owner_can=True, + blocked_user_cannot=True, + suspended_user_cannot=True, + ) - suspended_error_message = _( - 'Sorry, since your account is suspended ' - 'you can comment only your own posts' - ) - low_rep_error_message = _( - 'Sorry, to comment any post a minimum reputation of ' - '%(min_rep)s points is required. You can still comment ' - 'your own posts and answers to your questions' - ) % {'min_rep': 0}#askbot_settings.MIN_REP_TO_LEAVE_COMMENTS} - - blocked_message = get_i18n_message('BLOCKED_USERS_CANNOT_POST') +def user_assert_can_see_deleted_post(self, post=None): + """attn: this assertion is independently coded in + Question.get_answers call + """ try: _assert_user_can( - user = self, - post = parent_post, - owner_can = True, - blocked_error_message = blocked_message, - suspended_error_message = suspended_error_message, - min_rep_setting = 0,#askbot_settings.MIN_REP_TO_LEAVE_COMMENTS, - low_rep_error_message = low_rep_error_message, + user=self, + post=post, + admin_or_moderator_required=True, + owner_can=True ) - except askbot_exceptions.InsufficientReputation, e: - if parent_post.post_type == 'answer': - if self == parent_post.thread._question_post().author: - return - raise e - -def user_assert_can_see_deleted_post(self, post = None): + except django_exceptions.PermissionDenied, e: + #re-raise the same exception with a different message + error_message = _( + 'This post has been deleted and can be seen only ' + 'by post owners, site administrators and moderators' + ) + raise django_exceptions.PermissionDenied(error_message) - """attn: this assertion is independently coded in - Question.get_answers call - """ - - error_message = _( - 'This post has been deleted and can be seen only ' - 'by post owners, site administrators and moderators' - ) - _assert_user_can( - user = self, - post = post, - admin_or_moderator_required = True, - owner_can = True, - general_error_message = error_message - ) def user_assert_can_edit_deleted_post(self, post = None): assert(post.deleted == True) @@ -920,9 +892,9 @@ def user_assert_can_edit_deleted_post(self, post = None): self.assert_can_see_deleted_post(post) except django_exceptions.PermissionDenied, e: error_message = _( - 'Sorry, only moderators, site administrators ' - 'and post owners can edit deleted posts' - ) + 'Sorry, only moderators, site administrators ' + 'and post owners can edit deleted posts' + ) raise django_exceptions.PermissionDenied(error_message) def user_assert_can_edit_post(self, post = None): @@ -935,37 +907,21 @@ def user_assert_can_edit_post(self, post = None): return - blocked_error_message = _( - 'Sorry, since your account is blocked ' - 'you cannot edit posts' - ) - suspended_error_message = _( - 'Sorry, since your account is suspended ' - 'you can edit only your own posts' - ) if post.wiki == True: - low_rep_error_message = _( - 'Sorry, to edit wiki posts, a minimum ' - 'reputation of %(min_rep)s is required' - ) % \ - {'min_rep': askbot_settings.MIN_REP_TO_EDIT_WIKI} + action_display=_('edit wiki posts') min_rep_setting = askbot_settings.MIN_REP_TO_EDIT_WIKI else: - low_rep_error_message = _( - 'Sorry, to edit other people\'s posts, a minimum ' - 'reputation of %(min_rep)s is required' - ) % \ - {'min_rep': askbot_settings.MIN_REP_TO_EDIT_OTHERS_POSTS} + action_display=_('edit posts') min_rep_setting = askbot_settings.MIN_REP_TO_EDIT_OTHERS_POSTS _assert_user_can( - user = self, - post = post, - owner_can = True, - blocked_error_message = blocked_error_message, - suspended_error_message = suspended_error_message, - low_rep_error_message = low_rep_error_message, - min_rep_setting = min_rep_setting, + user=self, + post=post, + action_display=action_display, + owner_can=True, + blocked_user_cannot=True, + suspended_user_cannot=True, + min_rep_setting = min_rep_setting ) @@ -1015,12 +971,16 @@ def user_assert_can_delete_question(self, question = None): return else: msg = ungettext( - 'Sorry, cannot delete your question since it ' - 'has an upvoted answer posted by someone else', - 'Sorry, cannot delete your question since it ' - 'has some upvoted answers posted by other users', + 'Sorry, cannot %(delete_your_question)s since it ' + 'has an %(upvoted_answer)s posted by someone else', + 'Sorry, cannot %(delete_your_question)s since it ' + 'has some %(upvoted_answers)s posted by other users', answer_count - ) + ) % { + 'delete_your_question': askbot_settings.WORDS_DELETE_YOUR_QUESTION, + 'upvoted_answer': askbot_settings.WORDS_UPVOTED_ANSWER, + 'upvoted_answers': askbot_settings.WORDS_UPVOTED_ANSWERS + } raise django_exceptions.PermissionDenied(msg) @@ -1029,111 +989,44 @@ def user_assert_can_delete_answer(self, answer = None): instead of "answer", because this logic also applies to assert on deleting question (in addition to some special rules) """ - blocked_error_message = _( - 'Sorry, since your account is blocked ' - 'you cannot delete posts' - ) - suspended_error_message = _( - 'Sorry, since your account is suspended ' - 'you can delete only your own posts' - ) - low_rep_error_message = _( - 'Sorry, to delete other people\'s posts, a minimum ' - 'reputation of %(min_rep)s is required' - ) % \ - {'min_rep': askbot_settings.MIN_REP_TO_DELETE_OTHERS_POSTS} min_rep_setting = askbot_settings.MIN_REP_TO_DELETE_OTHERS_POSTS - - _assert_user_can( - user = self, - post = answer, - owner_can = True, - blocked_error_message = blocked_error_message, - suspended_error_message = suspended_error_message, - low_rep_error_message = low_rep_error_message, - min_rep_setting = min_rep_setting, + user=self, + post=answer, + action_display=_('delete posts'), + owner_can=True, + blocked_user_cannot=True, + suspended_user_cannot=True, + min_rep_setting=min_rep_setting, ) def user_assert_can_close_question(self, question = None): assert(getattr(question, 'post_type', '') == 'question') - blocked_error_message = _( - 'Sorry, since your account is blocked ' - 'you cannot close questions' - ) - suspended_error_message = _( - 'Sorry, since your account is suspended ' - 'you cannot close questions' - ) - low_rep_error_message = _( - 'Sorry, to close other people\' posts, a minimum ' - 'reputation of %(min_rep)s is required' - ) % \ - {'min_rep': askbot_settings.MIN_REP_TO_CLOSE_OTHERS_QUESTIONS} min_rep_setting = askbot_settings.MIN_REP_TO_CLOSE_OTHERS_QUESTIONS - - owner_min_rep_setting = askbot_settings.MIN_REP_TO_CLOSE_OWN_QUESTIONS - - owner_low_rep_error_message = _( - 'Sorry, to close own question ' - 'a minimum reputation of %(min_rep)s is required' - ) % {'min_rep': owner_min_rep_setting} - - _assert_user_can( user = self, post = question, + action_display=askbot_settings.WORDS_CLOSE_QUESTIONS, owner_can = True, suspended_owner_cannot = True, - owner_min_rep_setting = owner_min_rep_setting, - blocked_error_message = blocked_error_message, - suspended_error_message = suspended_error_message, - low_rep_error_message = low_rep_error_message, - owner_low_rep_error_message = owner_low_rep_error_message, + blocked_user_cannot=True, + suspended_user_cannot=True, min_rep_setting = min_rep_setting, ) def user_assert_can_reopen_question(self, question = None): assert(question.post_type == 'question') - - #for some reason rep to reopen own questions != rep to close own q's - owner_min_rep_setting = askbot_settings.MIN_REP_TO_REOPEN_OWN_QUESTIONS - min_rep_setting = askbot_settings.MIN_REP_TO_CLOSE_OTHERS_QUESTIONS - - general_error_message = _( - 'Sorry, only administrators, moderators ' - 'or post owners with reputation > %(min_rep)s ' - 'can reopen questions.' - ) % {'min_rep': owner_min_rep_setting } - - owner_low_rep_error_message = _( - 'Sorry, to reopen own question ' - 'a minimum reputation of %(min_rep)s is required' - ) % {'min_rep': owner_min_rep_setting} - - blocked_error_message = _( - 'Sorry, you cannot reopen questions ' - 'because your account is blocked' - ) - - suspended_error_message = _( - 'Sorry, you cannot reopen questions ' - 'because your account is suspended' - ) - _assert_user_can( - user = self, - post = question, - owner_can = True, - suspended_owner_cannot = True, - owner_min_rep_setting = owner_min_rep_setting, - min_rep_setting = min_rep_setting, - owner_low_rep_error_message = owner_low_rep_error_message, - general_error_message = general_error_message, - blocked_error_message = blocked_error_message, - suspended_error_message = suspended_error_message + user=self, + post=question, + action_display=_('reopen questions'), + suspended_owner_cannot=True, + #for some reason rep to reopen own questions != rep to close own q's + min_rep_setting=askbot_settings.MIN_REP_TO_CLOSE_OTHERS_QUESTIONS, + blocked_user_cannot=True, + suspended_user_cannot=True, ) @@ -1142,37 +1035,21 @@ def user_assert_can_flag_offensive(self, post = None): assert(post is not None) double_flagging_error_message = _( - 'You have flagged this question before and ' + 'You have flagged this post before and ' 'cannot do it more than once' ) if self.get_flags_for_post(post).count() > 0: raise askbot_exceptions.DuplicateCommand(double_flagging_error_message) - blocked_error_message = _( - 'Sorry, since your account is blocked ' - 'you cannot flag posts as offensive' - ) - - suspended_error_message = _( - 'Sorry, your account appears to be suspended and you cannot make new posts ' - 'until this issue is resolved. You can, however edit your existing posts. ' - 'Please contact the forum administrator to reach a resolution.' - ) - - low_rep_error_message = _( - 'Sorry, to flag posts as offensive a minimum reputation ' - 'of %(min_rep)s is required' - ) % \ - {'min_rep': askbot_settings.MIN_REP_TO_FLAG_OFFENSIVE} min_rep_setting = askbot_settings.MIN_REP_TO_FLAG_OFFENSIVE _assert_user_can( user = self, post = post, - blocked_error_message = blocked_error_message, - suspended_error_message = suspended_error_message, - low_rep_error_message = low_rep_error_message, + action_display=_('flag posts as offensive'), + blocked_user_cannot=True, + suspended_user_cannot=True, min_rep_setting = min_rep_setting ) #one extra assertion @@ -1199,28 +1076,13 @@ def user_assert_can_remove_flag_offensive(self, post = None): if self.get_flags_for_post(post).count() < 1: raise django_exceptions.PermissionDenied(non_existing_flagging_error_message) - blocked_error_message = _( - 'Sorry, since your account is blocked you cannot remove flags' - ) - - suspended_error_message = _( - 'Sorry, your account appears to be suspended and you cannot remove flags. ' - 'Please contact the forum administrator to reach a resolution.' - ) - min_rep_setting = askbot_settings.MIN_REP_TO_FLAG_OFFENSIVE - low_rep_error_message = ungettext( - 'Sorry, to flag posts a minimum reputation of %(min_rep)d is required', - 'Sorry, to flag posts a minimum reputation of %(min_rep)d is required', - min_rep_setting - ) % {'min_rep': min_rep_setting} - _assert_user_can( user = self, post = post, - blocked_error_message = blocked_error_message, - suspended_error_message = suspended_error_message, - low_rep_error_message = low_rep_error_message, + action_display=_('remove flags'), + blocked_user_cannot=True, + suspended_user_cannot=True, min_rep_setting = min_rep_setting ) #one extra assertion @@ -1250,67 +1112,30 @@ def user_assert_can_remove_all_flags_offensive(self, post = None): def user_assert_can_retag_question(self, question = None): if question.deleted == True: - try: - self.assert_can_edit_deleted_post(question) - except django_exceptions.PermissionDenied: - error_message = _( - 'Sorry, only question owners, ' - 'site administrators and moderators ' - 'can retag deleted questions' - ) - raise django_exceptions.PermissionDenied(error_message) - - - blocked_error_message = _( - 'Sorry, since your account is blocked ' - 'you cannot retag questions' - ) - suspended_error_message = _( - 'Sorry, since your account is suspended ' - 'you can retag only your own questions' - ) - low_rep_error_message = _( - 'Sorry, to retag questions a minimum ' - 'reputation of %(min_rep)s is required' - ) % \ - {'min_rep': askbot_settings.MIN_REP_TO_RETAG_OTHERS_QUESTIONS} - min_rep_setting = askbot_settings.MIN_REP_TO_RETAG_OTHERS_QUESTIONS + self.assert_can_edit_deleted_post(question) _assert_user_can( - user = self, - post = question, - owner_can = True, - blocked_error_message = blocked_error_message, - suspended_error_message = suspended_error_message, - low_rep_error_message = low_rep_error_message, - min_rep_setting = min_rep_setting, + user=self, + post=question, + action_display=askbot_settings.WORDS_RETAG_QUESTIONS, + owner_can=True, + blocked_user_cannot=True, + suspended_user_cannot=True, + min_rep_setting=askbot_settings.MIN_REP_TO_RETAG_OTHERS_QUESTIONS ) def user_assert_can_delete_comment(self, comment = None): - blocked_error_message = _( - 'Sorry, since your account is blocked ' - 'you cannot delete comment' - ) - suspended_error_message = _( - 'Sorry, since your account is suspended ' - 'you can delete only your own comments' - ) - low_rep_error_message = _( - 'Sorry, to delete comments ' - 'reputation of %(min_rep)s is required' - ) % \ - {'min_rep': askbot_settings.MIN_REP_TO_DELETE_OTHERS_COMMENTS} min_rep_setting = askbot_settings.MIN_REP_TO_DELETE_OTHERS_COMMENTS _assert_user_can( user = self, post = comment, + action_display=_('delete comments'), owner_can = True, - blocked_error_message = blocked_error_message, - suspended_error_message = suspended_error_message, - low_rep_error_message = low_rep_error_message, + blocked_user_cannot=True, + suspended_user_cannot=True, min_rep_setting = min_rep_setting, ) @@ -1418,12 +1243,15 @@ def user_post_anonymous_askbot_content(user, session_key): aa.save() #maybe add pending posts message? else: - if user.is_blocked(): - msg = get_i18n_message('BLOCKED_USERS_CANNOT_POST') - user.message_set.create(message = msg) - elif user.is_suspended(): - msg = get_i18n_message('SUSPENDED_USERS_CANNOT_POST') - user.message_set.create(message = msg) + if user.is_blocked() or user.is_suspended(): + if user.is_blocked(): + account_status = _('your account is blocked') + elif user.is_suspended(): + account_status = _('your account is suspended') + user.message_set.create(message = _(message_keys.ACCOUNT_CANNOT_PERFORM_ACTION) % { + 'perform_action': _('make posts'), + 'your_account_is': account_status + }) else: for aq in aq_list: aq.publish(user) @@ -2053,9 +1881,13 @@ def user_post_answer( left = ungettext('in %(min)d min','in %(min)d mins',minutes) % {'min':minutes} day = ungettext('%(days)d day','%(days)d days',askbot_settings.MIN_DAYS_TO_ANSWER_OWN_QUESTION) % {'days':askbot_settings.MIN_DAYS_TO_ANSWER_OWN_QUESTION} error_message = _( - 'New users must wait %(days)s before answering their own question. ' + 'New users must wait %(days)s to %(answer_own_questions)s. ' ' You can post an answer %(left)s' - ) % {'days': day,'left': left} + ) % { + 'days': day, + 'left': left, + 'answer_own_questions': askbot_settings.WORDS_ANSWER_OWN_QUESTIONS + } assert(error_message is not None) raise django_exceptions.PermissionDenied(error_message) @@ -2498,11 +2330,12 @@ def user_get_primary_group(self): first non-personal non-everyone group works only for one real private group per-person """ - groups = self.get_groups(private=True) - for group in groups: - if group.is_personal(): - continue - return group + if askbot_settings.GROUPS_ENABLED: + groups = self.get_groups(private=True) + for group in groups: + if group.is_personal(): + continue + return group return None def user_can_make_group_private_posts(self): @@ -2754,7 +2587,7 @@ def user_is_following_question(user, question): return question.thread.followed_by.filter(id=user.id).exists() -def upvote(self, post, timestamp=None, cancel=False, force = False): +def upvote(self, post, timestamp=None, cancel=False, force=False): #force parameter not used yet return _process_vote( self, @@ -2764,7 +2597,7 @@ def upvote(self, post, timestamp=None, cancel=False, force = False): vote_type=Vote.VOTE_UP ) -def downvote(self, post, timestamp=None, cancel=False, force = False): +def downvote(self, post, timestamp=None, cancel=False, force=False): #force not used yet return _process_vote( self, @@ -3097,6 +2930,7 @@ User.add_to_class('has_interesting_wildcard_tags', user_has_interesting_wildcard User.add_to_class('has_ignored_wildcard_tags', user_has_ignored_wildcard_tags) User.add_to_class('can_moderate_user', user_can_moderate_user) User.add_to_class('has_affinity_to_question', user_has_affinity_to_question) +User.add_to_class('has_badge', user_has_badge) User.add_to_class('moderate_user_reputation', user_moderate_user_reputation) User.add_to_class('set_status', user_set_status) User.add_to_class('get_badge_summary', user_get_badge_summary) @@ -3209,13 +3043,13 @@ def format_instant_notification_email( ) #todo: remove hardcoded style else: - content_preview = post.format_for_email(is_leaf_post = True) + content_preview = post.format_for_email(is_leaf_post=True, recipient=to_user) #add indented summaries for the parent posts - content_preview += post.format_for_email_as_parent_thread_summary() + content_preview += post.format_for_email_as_parent_thread_summary(recipient=to_user) #content_preview += '<p>======= Full thread summary =======</p>' - #content_preview += post.thread.format_for_email(user=to_user) + #content_preview += post.thread.format_for_email(recipient=to_user) if update_type == 'post_shared': user_action = _('%(user)s shared a %(post_link)s.') @@ -3239,10 +3073,22 @@ def format_instant_notification_email( post_url = site_url(post.get_absolute_url()) user_url = site_url(from_user.get_absolute_url()) + + if to_user.is_administrator_or_moderator() and askbot_settings.SHOW_ADMINS_PRIVATE_USER_DATA: + user_link_fmt = '<a href="%(profile_url)s">%(username)s</a> (<a href="mailto:%(email)s">%(email)s</a>)' + user_link = user_link_fmt % { + 'profile_url': user_url, + 'username': from_user.username, + 'email': from_user.email + } + elif post.is_anonymous: + user_link = from_user.get_name_of_anonymous_user() + else: + user_link = '<a href="%s">%s</a>' % (user_url, from_user.username) + user_action = user_action % { - 'user': '<a href="%s">%s</a>' % (user_url, from_user.username), + 'user': user_link, 'post_link': '<a href="%s">%s</a>' % (post_url, _(post.post_type)) - #'post_link': '%s <a href="%s">>>></a>' % (_(post.post_type), post_url) } can_reply = to_user.can_post_by_email() @@ -3709,6 +3555,10 @@ def greet_new_user(user, **kwargs): if askbot_settings.NEW_USER_GREETING: user.message_set.create(message = askbot_settings.NEW_USER_GREETING) + import sys + if 'test' in sys.argv: + return + if askbot_settings.REPLY_BY_EMAIL:#with this on we also collect signature template_name = 'email/welcome_lamson_on.html' else: @@ -3786,22 +3636,17 @@ def set_user_avatar_type_flag(instance, created, **kwargs): def update_user_avatar_type_flag(instance, **kwargs): instance.user.update_avatar_type() -def make_admin_if_first_user(instance, **kwargs): +def make_admin_if_first_user(user, **kwargs): """first user automatically becomes an administrator the function is run only once in the interpreter session + + function is run when user registers """ import sys - #have to check sys.argv to satisfy the test runner - #which fails with the cache-based skipping - #for real the setUp() code in the base test case must - #clear the cache!!! - if 'test' not in sys.argv and cache.cache.get('admin-created'): - #no need to hit the database every time! - return user_count = User.objects.all().count() - if user_count == 0: - instance.set_admin_status() - cache.cache.set('admin-created', True) + if user_count == 1: + user.set_admin_status() + user.save() def moderate_group_joining(sender, instance=None, created=False, **kwargs): if created and instance.level == GroupMembership.PENDING: @@ -3819,8 +3664,14 @@ def tweet_new_post(sender, user=None, question=None, answer=None, form_data=None post = question or answer tweet_new_post_task.delay(post.id) +def init_badge_data(sender, created_models=None, **kwargs): + if BadgeData in created_models: + from askbot.models import badges + badges.init_badges() + +django_signals.post_syncdb.connect(init_badge_data) + #signal for User model save changes -django_signals.pre_save.connect(make_admin_if_first_user, sender=User) django_signals.pre_save.connect(calculate_gravatar_hash, sender=User) django_signals.post_save.connect(add_missing_subscriptions, sender=User) django_signals.post_save.connect(add_user_to_global_group, sender=User) @@ -3846,6 +3697,7 @@ signals.flag_offensive.connect(record_flag_offensive, sender=Post) signals.remove_flag_offensive.connect(remove_flag_offensive, sender=Post) signals.tags_updated.connect(record_update_tags) signals.user_registered.connect(greet_new_user) +signals.user_registered.connect(make_admin_if_first_user) signals.user_updated.connect(record_user_full_updated, sender=User) signals.user_logged_in.connect(complete_pending_tag_subscriptions)#todo: add this to fake onlogin middleware signals.user_logged_in.connect(post_anonymous_askbot_content) @@ -3894,6 +3746,9 @@ __all__ = [ 'User', 'ReplyAddress', + + 'ImportRun', + 'ImportedObjectInfo', 'get_model', ] diff --git a/askbot/models/badges.py b/askbot/models/badges.py index 244c8e2f..44eda0c3 100644 --- a/askbot/models/badges.py +++ b/askbot/models/badges.py @@ -21,10 +21,8 @@ import datetime from django.template.defaultfilters import slugify from django.contrib.contenttypes.models import ContentType from django.utils.translation import ugettext as _ +from django.utils.translation import ungettext from django.dispatch import Signal -from askbot.models.repute import BadgeData, Award -from askbot.models.user import Activity -from askbot.models.question import FavoriteQuestion as Fave#name collision from askbot.models.post import Post from askbot import const from askbot.conf import settings as askbot_settings @@ -57,6 +55,7 @@ class Badge(object): self.css_class = const.BADGE_CSS_CLASSES[self.level] def get_stored_data(self): + from askbot.models.repute import BadgeData data, created = BadgeData.objects.get_or_create(slug = self.key) return data @@ -86,7 +85,7 @@ class Badge(object): def award(self, recipient = None, context_object = None, timestamp = None): """do award, the recipient was proven to deserve""" - + from askbot.models.repute import Award if self.multiple == False: if recipient.badges.filter(slug = self.key).count() != 0: return False @@ -171,8 +170,11 @@ class PeerPressure(Badge): class Teacher(Badge): def __init__(self): description = _( - 'Received at least %(votes)s upvote for an answer for the first time' - ) % {'votes': askbot_settings.TEACHER_BADGE_MIN_UPVOTES} + 'Gave an %(answer_voted_up)s at least %(votes)s times for the first time' + ) % { + 'votes': askbot_settings.TEACHER_BADGE_MIN_UPVOTES, + 'answer_voted_up': askbot_settings.WORDS_ANSWER_VOTED_UP + } super(Teacher, self).__init__( key = 'teacher', name = _('Teacher'), @@ -186,7 +188,7 @@ class Teacher(Badge): if context_object.post_type != 'answer': return False - if context_object.points>= askbot_settings.TEACHER_BADGE_MIN_UPVOTES: + if context_object.points >= askbot_settings.TEACHER_BADGE_MIN_UPVOTES: return self.award(context_object.author, context_object, timestamp) return False @@ -249,14 +251,16 @@ class CivicDuty(Badge): class SelfLearner(Badge): def __init__(self): - description = _('Answered own question with at least %(num)s up votes') - min_votes = askbot_settings.SELF_LEARNER_BADGE_MIN_UPVOTES + description = _('%(answered_own_question)s with at least %(num)s up votes') % { + 'num': askbot_settings.SELF_LEARNER_BADGE_MIN_UPVOTES, + 'answered_own_question': askbot_settings.WORDS_ANSWERED_OWN_QUESTION + } super(SelfLearner, self).__init__( - key = 'self-learner', - name = _('Self-Learner'), - description = description % {'num': min_votes}, - level = const.BRONZE_BADGE, - multiple = True + key='self-learner', + name=_('Self-Learner'), + description=description, + level=const.BRONZE_BADGE, + multiple=True ) def consider_award(self, actor = None, @@ -301,72 +305,90 @@ class QualityPost(Badge): class NiceAnswer(QualityPost): def __new__(cls): self = super(NiceAnswer, cls).__new__(cls) - self.name = _('Nice Answer') + self.name = askbot_settings.WORDS_NICE_ANSWER self.key = 'nice-answer' self.level = const.BRONZE_BADGE self.multiple = True self.min_votes = askbot_settings.NICE_ANSWER_BADGE_MIN_UPVOTES - self.description = _('Answer voted up %(num)s times') % {'num': self.min_votes} + self.description = _('%(answer_voted_up)s %(num)s times') % { + 'num': self.min_votes, + 'answer_voted_up': askbot_settings.WORDS_ANSWER_VOTED_UP + } self.post_type = 'answer' return self class GoodAnswer(QualityPost): def __new__(cls): self = super(GoodAnswer, cls).__new__(cls) - self.name = _('Good Answer') + self.name = askbot_settings.WORDS_GOOD_ANSWER self.key = 'good-answer' self.level = const.SILVER_BADGE self.multiple = True self.min_votes = askbot_settings.GOOD_ANSWER_BADGE_MIN_UPVOTES - self.description = _('Answer voted up %(num)s times') % {'num': self.min_votes} + self.description = _('%(answer_voted_up)s %(num)s times') % { + 'num': self.min_votes, + 'answer_voted_up': askbot_settings.WORDS_ANSWER_VOTED_UP + } self.post_type = 'answer' return self class GreatAnswer(QualityPost): def __new__(cls): self = super(GreatAnswer, cls).__new__(cls) - self.name = _('Great Answer') + self.name = askbot_settings.WORDS_GREAT_ANSWER self.key = 'great-answer' self.level = const.GOLD_BADGE self.multiple = True self.min_votes = askbot_settings.GREAT_ANSWER_BADGE_MIN_UPVOTES - self.description = _('Answer voted up %(num)s times') % {'num': self.min_votes} + self.description = _('%(answer_voted_up)s %(num)s times') % { + 'num': self.min_votes, + 'answer_voted_up': askbot_settings.WORDS_ANSWER_VOTED_UP + } self.post_type = 'answer' return self class NiceQuestion(QualityPost): def __new__(cls): self = super(NiceQuestion, cls).__new__(cls) - self.name = _('Nice Question') + self.name = askbot_settings.WORDS_NICE_QUESTION self.key = 'nice-question' self.level = const.BRONZE_BADGE self.multiple = True self.min_votes = askbot_settings.NICE_QUESTION_BADGE_MIN_UPVOTES - self.description = _('Question voted up %(num)s times') % {'num': self.min_votes} + self.description = _('%(question_voted_up)s up %(num)s times') % { + 'num': self.min_votes, + 'question_voted_up': askbot_settings.WORDS_QUESTION_VOTED_UP + } self.post_type = 'question' return self class GoodQuestion(QualityPost): def __new__(cls): self = super(GoodQuestion, cls).__new__(cls) - self.name = _('Good Question') + self.name = askbot_settings.WORDS_GOOD_QUESTION self.key = 'good-question' self.level = const.SILVER_BADGE self.multiple = True self.min_votes = askbot_settings.GOOD_QUESTION_BADGE_MIN_UPVOTES - self.description = _('Question voted up %(num)s times') % {'num': self.min_votes} + self.description = _('%(question_voted_up)s up %(num)s times') % { + 'num': self.min_votes, + 'question_voted_up': askbot_settings.WORDS_QUESTION_VOTED_UP + } self.post_type = 'question' return self class GreatQuestion(QualityPost): def __new__(cls): self = super(GreatQuestion, cls).__new__(cls) - self.name = _('Great Question') + self.name = askbot_settings.WORDS_GREAT_QUESTION self.key = 'great-question' self.level = const.GOLD_BADGE self.multiple = True self.min_votes = askbot_settings.GREAT_QUESTION_BADGE_MIN_UPVOTES - self.description = _('Question voted up %(num)s times') % {'num': self.min_votes} + self.description = _('%(question_voted_up)s %(num)s times') % { + 'num': self.min_votes, + 'question_voted_up': askbot_settings.WORDS_QUESTION_VOTED_UP + } self.post_type = 'question' return self @@ -378,7 +400,9 @@ class Student(QualityPost): self.level = const.BRONZE_BADGE self.multiple = False self.min_votes = 1 - self.description = _('Asked first question with at least one up vote') + self.description = _('%(asked_first_question)s with at least one up vote') % { + 'asked_first_question': askbot_settings.WORDS_ASKED_FIRST_QUESTION + } self.post_type = 'question' return self @@ -411,35 +435,41 @@ class FrequentedQuestion(Badge): class PopularQuestion(FrequentedQuestion): def __new__(cls): self = super(PopularQuestion, cls).__new__(cls) - self.name = _('Popular Question') + self.name = askbot_settings.WORDS_POPULAR_QUESTION self.key = 'popular-question' self.level = const.BRONZE_BADGE self.min_views = askbot_settings.POPULAR_QUESTION_BADGE_MIN_VIEWS - self.description = _('Asked a question with %(views)s views') \ - % {'views' : self.min_views} + self.description = _('%(asked_a_question)s with %(views)s views') % { + 'views' : self.min_views, + 'asked_a_question': askbot_settings.WORDS_ASKED_A_QUESTION + } return self class NotableQuestion(FrequentedQuestion): def __new__(cls): self = super(NotableQuestion, cls).__new__(cls) - self.name = _('Notable Question') + self.name = askbot_settings.WORDS_NOTABLE_QUESTION self.key = 'notable-question' self.level = const.SILVER_BADGE self.min_views = askbot_settings.NOTABLE_QUESTION_BADGE_MIN_VIEWS - self.description = _('Asked a question with %(views)s views') \ - % {'views' : self.min_views} + self.description = _('%(asked_a_question)s with %(views)s views') % { + 'views' : self.min_views, + 'asked_a_question': askbot_settings.WORDS_ASKED_A_QUESTION + } return self class FamousQuestion(FrequentedQuestion): def __new__(cls): self = super(FamousQuestion, cls).__new__(cls) - self.name = _('Famous Question') + self.name = askbot_settings.WORDS_FAMOUS_QUESTION self.key = 'famous-question' self.level = const.GOLD_BADGE self.multiple = True self.min_views = askbot_settings.FAMOUS_QUESTION_BADGE_MIN_VIEWS - self.description = _('Asked a question with %(views)s views') \ - % {'views' : self.min_views} + self.description = _('%(asked_a_question)s with %(views)s views') % { + 'views' : self.min_views, + 'asked_a_question': askbot_settings.WORDS_ASKED_A_QUESTION + } return self class Scholar(Badge): @@ -447,7 +477,10 @@ class Scholar(Badge): he/she accepts an answer for the first time """ def __init__(self): - description = _('Asked a question and accepted an answer') + description = _('%(asked_a_question)s and %(accepted_an_answer)s') % { + 'asked_a_question': askbot_settings.WORDS_ASKED_A_QUESTION, + 'accepted_an_answer': askbot_settings.WORDS_ACCEPTED_AN_ANSWER + } super(Scholar, self).__init__( key = 'scholar', name = _('Scholar'), @@ -496,8 +529,11 @@ class Enlightened(VotedAcceptedAnswer): self.level = const.SILVER_BADGE self.multiple = False self.min_votes = askbot_settings.ENLIGHTENED_BADGE_MIN_UPVOTES - descr = _('First answer was accepted with %(num)s or more votes') - self.description = descr % {'num': self.min_votes} + descr = _('%(gave_accepted_answer)s upvoted %(num)s or more times') + self.description = descr % { + 'num': self.min_votes, + 'gave_accepted_answer': askbot_settings.WORDS_GAVE_ACCEPTED_ANSWER + } return self class Guru(VotedAcceptedAnswer): @@ -507,24 +543,31 @@ class Guru(VotedAcceptedAnswer): self.name = _('Guru') self.level = const.GOLD_BADGE self.multiple = True - descr = _('Answer accepted with %(num)s or more votes') self.min_votes = askbot_settings.GURU_BADGE_MIN_UPVOTES - self.description = descr % {'num': self.min_votes} + descr = _('%(gave_accepted_answer)s upvoted %(num)s or more times') + self.description = descr % { + 'num': self.min_votes, + 'gave_accepted_answer': askbot_settings.WORDS_GAVE_ACCEPTED_ANSWER + } return self class Necromancer(Badge): def __init__(self): - description = _( - 'Answered a question more than %(days)s days ' - 'later with at least %(votes)s votes' - ) days = askbot_settings.NECROMANCER_BADGE_MIN_DELAY votes = askbot_settings.NECROMANCER_BADGE_MIN_UPVOTES + description = _( + '%(answered_a_question)s more than %(days)s days ' + 'later with at least %(votes)s votes' + ) % { + 'days':days, + 'votes':votes, + 'answered_a_question': askbot_settings.WORDS_ANSWERED_A_QUESTION + } super(Necromancer, self).__init__( key = 'necromancer', name = _('Necromancer'), level = const.SILVER_BADGE, - description = description % {'days':days, 'votes':votes}, + description = description, multiple = True ) @@ -602,6 +645,7 @@ class EditorTypeBadge(Badge): const.TYPE_ACTIVITY_UPDATE_ANSWER ) filters = {'user': actor, 'activity_type__in': atypes} + from askbot.models.user import Activity if Activity.objects.filter(**filters).count() == self.min_edits: return self.award(actor, context_object, timestamp) @@ -660,19 +704,25 @@ class FavoriteTypeBadge(Badge): must provide min_stars property for the badge """ def __init__(self): - descr = _('Question favorited by %(num)s users') + description = _( + '%(asked_a_question)s with %(num)s followers' + ) % { + 'num': self.min_stars, + 'asked_a_question': askbot_settings.WORDS_ASKED_A_QUESTION + } super(FavoriteTypeBadge, self).__init__( - key = self.key, - name = self.name, - level = self.level, - multiple = True, - description = descr % {'num': self.min_stars} + key=self.key, + name=self.name, + level=self.level, + multiple=True, + description=description ) def consider_award(self, actor = None, context_object = None, timestamp = None): question = context_object #model FavoriteQuestion imported under alias of Fave + from askbot.models.question import FavoriteQuestion as Fave#name collision count = Fave.objects.filter( thread = question.thread ).exclude( @@ -686,7 +736,7 @@ class StellarQuestion(FavoriteTypeBadge): def __new__(cls): self = super(StellarQuestion, cls).__new__(cls) self.key = 'stellar-question' - self.name = _('Stellar Question') + self.name = askbot_settings.WORDS_STELLAR_QUESTION self.level = const.GOLD_BADGE self.min_stars = askbot_settings.STELLAR_QUESTION_BADGE_MIN_STARS return self @@ -695,7 +745,7 @@ class FavoriteQuestion(FavoriteTypeBadge): def __new__(cls): self = super(FavoriteQuestion, cls).__new__(cls) self.key = 'favorite-question' - self.name = _('Favorite Question') + self.name = askbot_settings.WORDS_FAVORITE_QUESTION self.level = const.SILVER_BADGE self.min_stars = askbot_settings.FAVORITE_QUESTION_BADGE_MIN_STARS return self @@ -752,8 +802,10 @@ class Taxonomist(Badge): name = _('Taxonomist'), level = const.SILVER_BADGE, multiple = False, - description = _( - 'Created a tag used by %(num)s questions' + description = ungettext( + 'Created a tag used %(num)s time', + 'Created a tag used %(num)s times', + askbot_settings.TAXONOMIST_BADGE_MIN_USE_COUNT ) % {'num': askbot_settings.TAXONOMIST_BADGE_MIN_USE_COUNT} ) @@ -880,6 +932,7 @@ def init_badges(): get_badge(key).get_stored_data() #remove any badges from the database #that are no longer in the BADGES dictionary + from askbot.models.repute import BadgeData BadgeData.objects.exclude( slug__in = map(slugify, BADGES.keys()) ).delete() diff --git a/askbot/models/meta.py b/askbot/models/meta.py new file mode 100644 index 00000000..013e918a --- /dev/null +++ b/askbot/models/meta.py @@ -0,0 +1,32 @@ +"""Models that are not essential to operation of +an askbot instance, but may be used in some cases. +Data in these models can be erased without loss of function. +""" +from django.db import models +from picklefield.fields import PickledObjectField + +class ImportRun(models.Model): + """records information about the data import run""" + command = models.TextField(default='') + timestamp = models.DateTimeField(auto_now_add=True) + + class Meta: + app_label = 'askbot' + +class ImportedObjectInfo(models.Model): + """records data about objects imported into askbot + from other sources. + This is useful to create redirect urls when object id's change + """ + old_id = models.IntegerField(help_text='Old object id in the source database') + new_id = models.IntegerField(help_text='New object id in the current database') + model = models.CharField( + default='', + help_text='dotted python path to model', + max_length=255 + ) + run = models.ForeignKey(ImportRun) + extra_info = PickledObjectField(help_text='to hold dictionary for various data') + + class Meta: + app_label = 'askbot' diff --git a/askbot/models/post.py b/askbot/models/post.py index 906cba1e..7ab0b524 100644 --- a/askbot/models/post.py +++ b/askbot/models/post.py @@ -25,10 +25,6 @@ import askbot from askbot.utils.slug import slugify from askbot import const -from askbot.models.user import Activity -from askbot.models.user import EmailFeedSetting -from askbot.models.user import Group -from askbot.models.user import GroupMembership from askbot.models.tag import Tag, MarkedTag from askbot.models.tag import tags_match_some_wildcard from askbot.conf import settings as askbot_settings @@ -46,7 +42,7 @@ from askbot.search import mysql class PostToGroup(models.Model): post = models.ForeignKey('Post') - group = models.ForeignKey(Group) + group = models.ForeignKey('Group') class Meta: unique_together = ('post', 'group') @@ -62,6 +58,7 @@ class PostQuerySet(models.query.QuerySet): #as all methods on this class seem to want to #belong to Thread manager or Query set. def get_for_user(self, user): + from askbot.models.user import Group if askbot_settings.GROUPS_ENABLED: if user is None or user.is_anonymous(): groups = [Group.objects.get_global_group()] @@ -347,7 +344,7 @@ class Post(models.Model): parent = models.ForeignKey('Post', blank=True, null=True, related_name='comments') # Answer or Question for Comment thread = models.ForeignKey('Thread', blank=True, null=True, default = None, related_name='posts') - groups = models.ManyToManyField(Group, through='PostToGroup', related_name = 'group_posts')#used for group-private posts + groups = models.ManyToManyField('Group', through='PostToGroup', related_name = 'group_posts')#used for group-private posts author = models.ForeignKey(User, related_name='posts') added_at = models.DateTimeField(default=datetime.datetime.now) @@ -415,9 +412,9 @@ class Post(models.Model): """ url = site_url(self.get_absolute_url(no_slug=True)) if self.post_type == 'question': - tweet = _('Question: ') + tweet = askbot_settings.WORDS_QUESTION_SINGULAR + ': ' elif self.post_type == 'answer': - tweet = _('Answer: ') + tweet = askbot_settings.WORDS_ANSWER_SINGULAR + ': ' chars_left = 140 - (len(url) + len(tweet) + 1) title_str = self.thread.title[:chars_left] @@ -449,10 +446,14 @@ class Post(models.Model): removed_mentions = list() if '@' in text: op = self.get_origin_post() - anticipated_authors = op.get_author_list( - include_comments = True, - recursive = True - ) + + if op.id: + anticipated_authors = op.get_author_list( + include_comments = True, + recursive = True + ) + else: + anticipated_authors = list() extra_name_seeds = markup.extract_mentioned_name_seeds(text) @@ -504,7 +505,6 @@ class Post(models.Model): """generic method to use with posts to be used prior to saving post edit or addition """ - assert(author is not None) last_revision = self.html @@ -643,6 +643,7 @@ class Post(models.Model): #vip groups to the list behind the scenes. groups = list(groups) #add moderator groups to the post implicitly + from askbot.models.user import Group vips = Group.objects.filter(is_vip=True) groups.extend(vips) #todo: use bulk-creation @@ -688,6 +689,7 @@ class Post(models.Model): else: summary = self.get_snippet() + from askbot.models import Activity update_activity = Activity( user = updated_by, active_at = timestamp, @@ -701,6 +703,7 @@ class Post(models.Model): update_activity.add_recipients(notify_sets['for_inbox']) #create new mentions (barring the double-adds) + from askbot.models import Activity for u in notify_sets['for_mentions'] - notify_sets['for_inbox']: Activity.objects.create_new_mention( mentioned_whom = u, @@ -740,6 +743,7 @@ class Post(models.Model): """makes post private within user's groups todo: this is a copy-paste in thread and post """ + from askbot.models.user import Group if group_id: group = Group.objects.get(id=group_id) groups = [group] @@ -767,12 +771,14 @@ class Post(models.Model): def make_public(self): """removes the privacy mark from users groups""" + from askbot.models.user import Group groups = (Group.objects.get_global_group(),) self.add_to_groups(groups) def is_private(self): """true, if post belongs to the global group""" if askbot_settings.GROUPS_ENABLED: + from askbot.models.user import Group group = Group.objects.get_global_group() return not self.groups.filter(id=group.id).exists() return False @@ -895,9 +901,9 @@ class Post(models.Model): """ if max_length is None: if self.post_type == 'comment': - max_words = 30 + max_words = 150 else: - max_words = 100 + max_words = 500 else: max_words = int(max_length/5) @@ -936,6 +942,7 @@ class Post(models.Model): return list() #load group memberships for the candidates + from askbot.models.user import GroupMembership memberships = GroupMembership.objects.filter( user__in=candidates, group__in=groups @@ -951,7 +958,8 @@ class Post(models.Model): return filtered_candidates def format_for_email( - self, quote_level=0, is_leaf_post=False, format=None + self, quote_level=0, is_leaf_post=False, format=None, + recipient=None ): """format post for the output in email, if quote_level > 0, the post will be indented that number of times @@ -962,13 +970,14 @@ class Post(models.Model): template = get_template('email/quoted_post.html') data = { 'post': self, + 'recipient': recipient, 'quote_level': quote_level, 'is_leaf_post': is_leaf_post, 'format': format } return template.render(Context(data))#todo: set lang - def format_for_email_as_parent_thread_summary(self): + def format_for_email_as_parent_thread_summary(self, recipient=None): """format for email as summary of parent posts all the way to the original question""" quote_level = 0 @@ -980,20 +989,25 @@ class Post(models.Model): break quote_level += 1 output += parent_post.format_for_email( - quote_level = quote_level, - format = 'parent_subthread' + quote_level=quote_level, + format='parent_subthread', + recipient=recipient ) current_post = parent_post return output - def format_for_email_as_subthread(self): + def format_for_email_as_subthread(self, recipient=None): """outputs question or answer and all it's comments returns empty string for all other post types """ from django.template import Context from django.template.loader import get_template template = get_template('email/post_as_subthread.html') - return template.render(Context({'post': self}))#todo: set lang + data = { + 'post': self, + 'recipient': recipient + } + return template.render(Context(data))#todo: set lang def set_cached_comments(self, comments): """caches comments in the lifetime of the object @@ -1138,6 +1152,7 @@ class Post(models.Model): """ subscriber_set = set() + from askbot.models.user import EmailFeedSetting global_subscriptions = EmailFeedSetting.objects.filter( feed_type = 'q_all', frequency = 'i' @@ -1215,6 +1230,7 @@ class Post(models.Model): #print 'potential subscribers: ', potential_subscribers #1) mention subscribers - common to questions and answers + from askbot.models.user import EmailFeedSetting if mentioned_users: mention_subscribers = EmailFeedSetting.objects.filter_subscribers( potential_subscribers = mentioned_users, @@ -1308,6 +1324,7 @@ class Post(models.Model): if mentioned_users: potential_subscribers.update(mentioned_users) + from askbot.models.user import EmailFeedSetting if potential_subscribers: comment_subscribers = EmailFeedSetting.objects.filter_subscribers( potential_subscribers = potential_subscribers, @@ -1459,6 +1476,8 @@ class Post(models.Model): ) elif user.email_tag_filter_strategy == const.INCLUDE_ALL: return True + elif user.email_tag_filter_strategy == const.INCLUDE_SUBSCRIBED: + return user.has_affinity_to_question(question, affinity_type='like') else: raise ValueError( 'unexpected User.email_tag_filter_strategy %s'\ @@ -1598,10 +1617,7 @@ class Post(models.Model): if self.is_approved() is False: raise exceptions.QuestionHidden() if self.deleted: - message = _( - 'Sorry, this question has been ' - 'deleted and is no longer accessible' - ) + message = _('Sorry, this content is no longer available') if user.is_anonymous(): raise exceptions.QuestionHidden(message) try: @@ -1614,17 +1630,10 @@ class Post(models.Model): try: self.thread._question_post().assert_is_visible_to(user) except exceptions.QuestionHidden: - message = _( - 'Sorry, the answer you are looking for is ' - 'no longer available, because the parent ' - 'question has been removed' - ) + message = _('Sorry, this content is no longer available') raise exceptions.QuestionHidden(message) if self.deleted: - message = _( - 'Sorry, this answer has been ' - 'removed and is no longer accessible' - ) + message = _('Sorry, this content is no longer available') if user.is_anonymous(): raise exceptions.AnswerHidden(message) try: @@ -1637,18 +1646,10 @@ class Post(models.Model): try: self.parent.assert_is_visible_to(user) except exceptions.QuestionHidden: - message = _( - 'Sorry, the comment you are looking for is no ' - 'longer accessible, because the parent question ' - 'has been removed' - ) + message = _('Sorry, this comment is no longer available') raise exceptions.QuestionHidden(message) except exceptions.AnswerHidden: - message = _( - 'Sorry, the comment you are looking for is no ' - 'longer accessible, because the parent answer ' - 'has been removed' - ) + message = _('Sorry, this comment is no longer available') raise exceptions.AnswerHidden(message) def assert_is_visible_to_user_groups(self, user): @@ -2135,6 +2136,7 @@ class PostRevision(models.Model): #if sent by email to group and group does not want moderation if self.by_email and self.email_address: group_name = self.email_address.split('@')[0] + from askbot.models.user import Group try: group = Group.objects.get(name = group_name, deleted = False) return group.group.profile.moderate_email diff --git a/askbot/models/question.py b/askbot/models/question.py index fe68870a..5455b927 100644 --- a/askbot/models/question.py +++ b/askbot/models/question.py @@ -14,6 +14,7 @@ from django.utils.translation import ugettext as _ from django.utils.translation import ungettext from django.utils.translation import string_concat from django.utils.translation import get_language +from django.utils.translation import activate as activate_language import askbot from askbot.conf import settings as askbot_settings @@ -24,8 +25,6 @@ from askbot.models.tag import get_tags_by_names from askbot.models.tag import filter_accepted_tags, filter_suggested_tags from askbot.models.tag import separate_unused_tags from askbot.models.base import DraftContent, BaseQuerySetManager -from askbot.models.post import Post, PostRevision -from askbot.models.post import PostToGroup from askbot.models.user import Group, PERSONAL_GROUP_NAME_PREFIX from askbot.models import signals from askbot import const @@ -34,6 +33,27 @@ from askbot.search import mysql from askbot.utils.slug import slugify from askbot.search.state_manager import DummySearchState + +def clean_tagnames(tagnames): + """Cleans tagnames string so that the field fits the constraint of the + database. + TODO: remove this when the Thread.tagnames field is converted into + text_field + """ + original = tagnames + tagnames = tagnames.strip().split() + #see if the tagnames field fits into 125 bytes + while True: + encoded_tagnames = ' '.join(tagnames).encode('utf-8') + length = len(encoded_tagnames) + if length == 0: + return '' + elif length <= 125: + return ' '.join(tagnames) + else: + tagnames.pop() + + class ThreadQuerySet(models.query.QuerySet): def get_visible(self, user): """filters out threads not belonging to the user groups""" @@ -52,7 +72,7 @@ class ThreadQuerySet(models.query.QuerySet): if getattr(django_settings, 'ENABLE_HAYSTACK_SEARCH', False): from askbot.search.haystack.searchquery import AskbotSearchQuerySet hs_qs = AskbotSearchQuerySet().filter(content=search_query).models(self.model) - return hs_qs.get_django_queryset() + return self & hs_qs.get_django_queryset() else: db_engine_name = askbot.get_database_engine_name() filter_parameters = {'deleted': False} @@ -134,6 +154,7 @@ class ThreadManager(BaseQuerySetManager): # TODO: Some of this code will go to Post.objects.create_new language = language or get_language() + tagnames = clean_tagnames(tagnames) thread = super( ThreadManager, @@ -147,6 +168,7 @@ class ThreadManager(BaseQuerySetManager): ) #todo: code below looks like ``Post.objects.create_new()`` + from askbot.models.post import Post question = Post( post_type='question', thread=thread, @@ -369,7 +391,7 @@ class ThreadManager(BaseQuerySetManager): except User.DoesNotExist: meta_data['author_name'] = None else: - qs = qs.filter(posts__post_type__in=('question', 'answer'), posts__author=u, posts__deleted=False) + qs = qs.filter(posts__post_type='question', posts__author=u, posts__deleted=False) meta_data['author_name'] = u.username #get users tag filters @@ -466,6 +488,7 @@ class ThreadManager(BaseQuerySetManager): #threads = [thread for thread in threads if not thread.summary_html_cached()] thread_ids = [obj.id for obj in threads] + from askbot.models.post import Post page_questions = Post.objects.filter( post_type='question', thread__id__in = thread_ids ).only(# pick only the used fields @@ -491,6 +514,7 @@ class ThreadManager(BaseQuerySetManager): def get_thread_contributors(self, thread_list): """Returns query set of Thread contributors""" # INFO: Evaluate this query to avoid subquery in the subsequent query below (At least MySQL can be awfully slow on subqueries) + from askbot.models.post import Post u_id = list(Post.objects.filter(post_type__in=('question', 'answer'), thread__in=thread_list).values_list('author', flat=True)) #todo: this does not belong gere - here we select users with real faces @@ -505,6 +529,8 @@ class ThreadManager(BaseQuerySetManager): def get_for_user(self, user): """returns threads where a given user had participated""" + from askbot.models.post import PostRevision + from askbot.models.post import Post post_ids = PostRevision.objects.filter( author = user ).values_list( @@ -543,7 +569,7 @@ class ThreadToGroup(models.Model): class Thread(models.Model): - SUMMARY_CACHE_KEY_TPL = 'thread-question-summary-%d' + SUMMARY_CACHE_KEY_TPL = 'thread-question-summary-%d-%s' ANSWER_LIST_KEY_TPL = 'thread-answer-list-%d' title = models.CharField(max_length=300) @@ -560,6 +586,8 @@ class Thread(models.Model): last_activity_by = models.ForeignKey(User, related_name='unused_last_active_in_threads') language_code = models.CharField(max_length=16, default=django_settings.LANGUAGE_CODE) + #todo: these two are redundant (we used to have a "star" and "subscribe" + #now merged into "followed") followed_by = models.ManyToManyField(User, related_name='followed_threads') favorited_by = models.ManyToManyField(User, through='FavoriteQuestion', related_name='unused_favorite_threads') @@ -578,7 +606,7 @@ class Thread(models.Model): #approvals - by whom and when approved = models.BooleanField(default=True, db_index=True) - accepted_answer = models.ForeignKey(Post, null=True, blank=True, related_name='+') + accepted_answer = models.ForeignKey('Post', null=True, blank=True, related_name='+') answer_accepted_at = models.DateTimeField(null=True, blank=True) added_at = models.DateTimeField(default = datetime.datetime.now) @@ -605,6 +633,7 @@ class Thread(models.Model): post = getattr(self, '_question_cache', None) if post: return post + from askbot.models.post import Post self._question_cache = Post.objects.get(post_type='question', thread=self) return self._question_cache @@ -828,14 +857,15 @@ class Thread(models.Model): else: return self.title - def format_for_email(self, user=None): + def format_for_email(self, recipient=None): """experimental function: output entire thread for email""" question, answers, junk, published_ans_ids = \ - self.get_cached_post_data(user=user) + self.get_cached_post_data(user=recipient) - output = question.format_for_email_as_subthread() + output = question.format_for_email_as_subthread(recipient=recipient) if answers: + #todo: words answer_heading = ungettext( '%(count)d answer:', '%(count)d answers:', @@ -843,7 +873,7 @@ class Thread(models.Model): ) % {'count': len(answers)} output += '<p>%s</p>' % answer_heading for answer in answers: - output += answer.format_for_email_as_subthread() + output += answer.format_for_email_as_subthread(recipient=recipient) return output def get_answers_by_user(self, user): @@ -911,7 +941,7 @@ class Thread(models.Model): # ) def invalidate_cached_thread_content_fragment(self): - cache.cache.delete(self.SUMMARY_CACHE_KEY_TPL % self.id) + cache.cache.delete(self.SUMMARY_CACHE_KEY_TPL % (self.id, get_language())) def get_post_data_cache_key(self, sort_method = None): return 'thread-data-%s-%s' % (self.id, sort_method) @@ -1106,6 +1136,7 @@ class Thread(models.Model): # Denormalize questions to speed up template rendering # todo: just denormalize question_post_id on the thread! thread_map = dict([(thread.id, thread) for thread in similar_threads]) + from askbot.models.post import Post questions = Post.objects.get_questions() questions = questions.select_related('thread').filter(thread__in=similar_threads) for q in questions: @@ -1150,6 +1181,7 @@ class Thread(models.Model): #it is important that update method is called - not save, #because we do not want the signals to fire here thread_question = self._question_post() + from askbot.models.post import Post Post.objects.filter(id=thread_question.id).update(is_anonymous=False) thread_question.revisions.all().update(is_anonymous=False) @@ -1183,6 +1215,7 @@ class Thread(models.Model): """removes child posts from given groups""" post_ids = self.posts.all().values_list('id', flat=True) group_ids = [group.id for group in groups] + from askbot.models.post import PostToGroup PostToGroup.objects.filter( post__id__in=post_ids, tag__id__in=group_ids @@ -1400,19 +1433,18 @@ class Thread(models.Model): silent=silent ) + def retag(self, retagged_by=None, retagged_at=None, tagnames=None, silent=False): """changes thread tags""" if None in (retagged_by, retagged_at, tagnames): raise Exception('arguments retagged_at, retagged_by and tagnames are required') - if len(tagnames) > 125:#todo: remove magic number!!! - raise django_exceptions.ValidationError('tagnames value too long') + tagnames = clean_tagnames(tagnames) + self.tagnames = tagnames + self.save() thread_question = self._question_post() - self.tagnames = tagnames.strip() - self.save() - # Update the Question itself if silent == False: thread_question.last_edited_at = retagged_at @@ -1426,6 +1458,8 @@ class Thread(models.Model): # Create a new revision latest_revision = thread_question.get_latest_revision() + + from askbot.models.post import PostRevision PostRevision.objects.create( post=thread_question, title=latest_revision.title, @@ -1490,7 +1524,7 @@ class Thread(models.Model): #parameter visitor is there to get summary out by the user groups if askbot_settings.GROUPS_ENABLED: return None - return cache.cache.get(self.SUMMARY_CACHE_KEY_TPL % self.id) + return cache.cache.get(self.SUMMARY_CACHE_KEY_TPL % (self.id, get_language())) def update_summary_html(self, visitor = None): #todo: it is quite wrong that visitor is an argument here @@ -1508,6 +1542,7 @@ class Thread(models.Model): } from askbot.views.context import get_extra as get_extra_context context.update(get_extra_context('ASKBOT_QUESTION_SUMMARY_EXTRA_CONTEXT', None, context)) + activate_language(self.language_code) html = get_template('widgets/question_summary.html').render(context) # INFO: Timeout is set to 30 days: # * timeout=0/None is not a reliable cross-backend way to set infinite timeout @@ -1515,17 +1550,17 @@ class Thread(models.Model): # * Additionally, Memcached treats timeouts > 30day as dates (https://code.djangoproject.com/browser/django/tags/releases/1.3/django/core/cache/backends/memcached.py#L36), # which probably doesn't break anything but if we can stick to 30 days then let's stick to it cache.cache.set( - self.SUMMARY_CACHE_KEY_TPL % self.id, + self.SUMMARY_CACHE_KEY_TPL % (self.id, get_language()), html, timeout=const.LONG_TIME ) return html def summary_html_cached(self): - return cache.cache.has_key(self.SUMMARY_CACHE_KEY_TPL % self.id) + return cache.cache.has_key(self.SUMMARY_CACHE_KEY_TPL % (self.id, get_language())) class QuestionView(models.Model): - question = models.ForeignKey(Post, related_name='viewed') + question = models.ForeignKey('Post', related_name='viewed') who = models.ForeignKey(User, related_name='question_views') when = models.DateTimeField() @@ -1598,9 +1633,3 @@ class AnonymousQuestion(DraftContent): text=self.text, tagnames=self.tagnames ) - #add message with a link to the ask page - extra_message = _( - 'Please, <a href="%s">review your question</a>.' - ) % reverse('ask') - message = string_concat(unicode(error), u' ', extra_message) - user.message_set.create(message=unicode(message)) diff --git a/askbot/models/reply_by_email.py b/askbot/models/reply_by_email.py index 983edc8f..0b164d24 100644 --- a/askbot/models/reply_by_email.py +++ b/askbot/models/reply_by_email.py @@ -5,7 +5,6 @@ import logging from django.db import models from django.contrib.auth.models import User from django.utils.translation import ugettext as _ -from django.utils.translation import ugettext_lazy from askbot.models.post import Post from askbot.models.base import BaseQuerySetManager from askbot.conf import settings as askbot_settings @@ -35,12 +34,12 @@ class ReplyAddressManager(BaseQuerySetManager): REPLY_ACTION_CHOICES = ( - ('post_answer', ugettext_lazy('Post an answer')), - ('post_comment', ugettext_lazy('Post a comment')), - ('replace_content', ugettext_lazy('Edit post')), - ('append_content', ugettext_lazy('Append to post')), - ('auto_answer_or_comment', ugettext_lazy('Answer or comment, depending on the size of post')), - ('validate_email', ugettext_lazy('Validate email and record signature')), + ('post_answer', 'Post an answer'), + ('post_comment', 'Post a comment'), + ('replace_content', 'Edit post'), + ('append_content', 'Append to post'), + ('auto_answer_or_comment', 'Answer or comment, depending on the size of post'), + ('validate_email', 'Validate email and record signature'), ) class ReplyAddress(models.Model): """Stores a reply address for the post diff --git a/askbot/models/repute.py b/askbot/models/repute.py index 5e9c295f..515356f0 100644 --- a/askbot/models/repute.py +++ b/askbot/models/repute.py @@ -101,6 +101,9 @@ class BadgeData(models.Model): from askbot.models import badges return badges.get_badge(self.slug) + def is_multiple(self): + return self._get_meta_data().multiple + def get_name(self): return self._get_meta_data().name @@ -213,21 +216,10 @@ class Repute(models.Model): 'username': self.user.username, 'question_title': self.question.thread.title } - if delta > 0: - link_title = _( - '%(points)s points were added for %(username)s\'s ' - 'contribution to question %(question_title)s' - ) % link_title_data - else: - link_title = _( - '%(points)s points were subtracted for %(username)s\'s ' - 'contribution to question %(question_title)s' - ) % link_title_data - return '<a href="%(url)s" title="%(link_title)s">%(question_title)s</a>' \ + return '<a href="%(url)s">%(question_title)s</a>' \ % { 'url': self.question.get_absolute_url(), 'question_title': escape(self.question.thread.title), - 'link_title': escape(link_title) } diff --git a/askbot/models/user.py b/askbot/models/user.py index ad49222b..a3e2d4f0 100644 --- a/askbot/models/user.py +++ b/askbot/models/user.py @@ -16,11 +16,6 @@ from askbot import const from askbot.conf import settings as askbot_settings from askbot.utils import functions from askbot.models.base import BaseQuerySetManager -from askbot.models.tag import Tag -from askbot.models.tag import clean_group_name#todo - delete this -from askbot.models.tag import get_tags_by_names -from askbot.forms import DomainNameField -from askbot.utils.forms import email_is_allowed from collections import defaultdict PERSONAL_GROUP_NAME_PREFIX = '_personal_' @@ -312,6 +307,7 @@ class EmailFeedSetting(models.Model): 'q_sel': 'i', 'm_and_c': 'i' } + #todo: words FEED_TYPE_CHOICES = ( ('q_all', ugettext_lazy('Entire forum')), ('q_ask', ugettext_lazy('Questions that I asked')), @@ -455,6 +451,7 @@ class GroupQuerySet(models.query.QuerySet): return self.filter(user = user) def get_by_name(self, group_name = None): + from askbot.models.tag import clean_group_name#todo - delete this return self.get(name = clean_group_name(group_name)) @@ -589,6 +586,7 @@ class Group(AuthGroup): return 'open' #relying on a specific method of storage + from askbot.utils.forms import email_is_allowed if email_is_allowed( user.email, allowed_emails=self.preapproved_emails, @@ -619,6 +617,7 @@ class Group(AuthGroup): self.preapproved_emails = ' ' + '\n'.join(emails) + ' ' domains = functions.split_list(self.preapproved_email_domains) + from askbot.forms import DomainNameField domain_field = DomainNameField() try: map(lambda v: domain_field.clean(v), domains) @@ -648,6 +647,7 @@ class BulkTagSubscriptionManager(BaseQuerySetManager): tag_name_list = [] if tag_names: + from askbot.models.tag import get_tags_by_names tags, new_tag_names = get_tags_by_names(tag_names) if new_tag_names: assert(tag_author) @@ -655,6 +655,7 @@ class BulkTagSubscriptionManager(BaseQuerySetManager): tags_id_list= [tag.id for tag in tags] tag_name_list = [tag.name for tag in tags] + from askbot.models.tag import Tag new_tags = Tag.objects.create_in_bulk( tag_names=new_tag_names, user=tag_author @@ -687,7 +688,7 @@ class BulkTagSubscriptionManager(BaseQuerySetManager): class BulkTagSubscription(models.Model): date_added = models.DateField(auto_now_add=True) - tags = models.ManyToManyField(Tag) + tags = models.ManyToManyField('Tag') users = models.ManyToManyField(User) groups = models.ManyToManyField(Group) diff --git a/askbot/search/haystack/__init__.py b/askbot/search/haystack/__init__.py index 05580bc4..77308180 100644 --- a/askbot/search/haystack/__init__.py +++ b/askbot/search/haystack/__init__.py @@ -32,7 +32,7 @@ class PostIndex(indexes.SearchIndex, indexes.Indexable): text = indexes.CharField(document=True, use_template=True) post_text = indexes.CharField(model_attr='text') author = indexes.CharField() - thread_id = indexes.IntegerField(model_attr='thread__pk') + thread_id = indexes.IntegerField(model_attr='thread__pk', null=True) def get_model(self): diff --git a/askbot/search/state_manager.py b/askbot/search/state_manager.py index 356c15bb..5fede602 100644 --- a/askbot/search/state_manager.py +++ b/askbot/search/state_manager.py @@ -93,7 +93,6 @@ class SearchState(object): author=None, page=None, page_size=None, user_logged_in=False ): # INFO: zip(*[('a', 1), ('b', 2)])[0] == ('a', 'b') - if (scope not in zip(*const.POST_SCOPE_LIST)[0]) or (scope == 'followed' and not user_logged_in): if user_logged_in: self.scope = askbot_settings.DEFAULT_SCOPE_AUTHENTICATED diff --git a/askbot/skins/loaders.py b/askbot/skins/loaders.py index afdf758e..1a9e8edb 100644 --- a/askbot/skins/loaders.py +++ b/askbot/skins/loaders.py @@ -86,7 +86,8 @@ def load_skins(language_code): skin_code = skin_name + '-' + language_code skins[skin_code] = SkinEnvironment( skin = skin_name, - extensions=['jinja2.ext.i18n',] + extensions=['jinja2.ext.i18n',], + globals={'settings': askbot_settings} ) skins[skin_code].set_language(language_code) #from askbot.templatetags import extra_filters_jinja as filters diff --git a/askbot/startup_procedures.py b/askbot/startup_procedures.py index e3888e53..3adbd781 100644 --- a/askbot/startup_procedures.py +++ b/askbot/startup_procedures.py @@ -1054,20 +1054,11 @@ def run_startup_tests(): if 'manage.py test' in ' '.join(sys.argv): test_settings_for_test_runner() -@transaction.commit_manually +#@transaction.commit_manually def run(): - """runs all the startup procedures""" try: if getattr(django_settings, 'ASKBOT_SELF_TEST', True): run_startup_tests() except AskbotConfigError, error: - transaction.rollback() print error sys.exit(1) - try: - from askbot.models import badges - badges.init_badges() - transaction.commit() - except Exception, error: - print error - transaction.rollback() diff --git a/askbot/tasks.py b/askbot/tasks.py index 3d3c57a7..ec3e405b 100644 --- a/askbot/tasks.py +++ b/askbot/tasks.py @@ -26,6 +26,7 @@ from django.contrib.contenttypes.models import ContentType from django.template import Context from django.template.loader import get_template from django.utils.translation import ugettext as _ +from django.utils.translation import activate as activate_language from django.utils import simplejson from celery.decorators import task from askbot.conf import settings as askbot_settings @@ -95,7 +96,7 @@ def notify_author_of_published_revision_celery_task(revision): if revision.post.post_type == 'question': mailto_link_subject = revision.post.thread.title else: - mailto_link_subject = _('An edit for my answer') + mailto_link_subject = _('make an edit by email') #todo: possibly add more mailto thread headers to organize messages prompt = _('To add to your post EDIT ABOVE THIS LINE') @@ -111,6 +112,7 @@ def notify_author_of_published_revision_celery_task(revision): } #load the template + activate_language(revision.post.language_code) template = get_template('email/notify_author_about_approved_post.html') #todo: possibly add headers to organize messages in threads headers = {'Reply-To': append_content_address} @@ -248,6 +250,7 @@ def send_instant_notifications_about_activity_in_post( reply_address, alt_reply_address = get_reply_to_addresses(user, post) + activate_language(post.language_code) subject_line, body_text = format_instant_notification_email( to_user = user, from_user = update_activity.user, diff --git a/askbot/templates/404.html b/askbot/templates/404.html index 565ff164..8388a42f 100644 --- a/askbot/templates/404.html +++ b/askbot/templates/404.html @@ -14,7 +14,7 @@ <div style="margin-top:5px"> {% trans %}This might have happened for the following reasons:{% endtrans %}<br/> <ul> - <li>{% trans %}this question or answer has been deleted;{% endtrans %}</li> + <li>{% trans %}This page has been deleted{% endtrans %}</li> <li>{% trans %}url has error - please check it;{% endtrans %}</li> <li>{% trans %}the page you tried to visit is protected or you don't have sufficient points, see{% endtrans %} <a href="{% url faq %}">{% trans %}faq{% endtrans %}</a>;</li> <li>{% trans %}if you believe this error 404 should not have occured, please{% endtrans %} @@ -26,11 +26,6 @@ var GOOG_FIXURL_SITE = '{{ site_url }}'; </script> <script type="text/javascript" src="http://linkhelp.clients.google.com/tbproxy/lh/wm/fixurl.js"></script> - <ul> - <li><a href="#" id="linkPrevious">{% trans %}back to previous page{% endtrans %} »</li> - <li><a href="{% url questions %}">{% trans %}see all questions{% endtrans %} »</a></li> - <li><a href="{% url tags %}">{% trans %}see all tags{% endtrans %} »</a></li> - </u> </div> </div> {% endblock %} diff --git a/askbot/templates/500.html b/askbot/templates/500.html index 297ae736..3cf6778b 100644 --- a/askbot/templates/500.html +++ b/askbot/templates/500.html @@ -6,20 +6,8 @@ <div id="main-body"> <div style="padding:5px 0px 10px 0;line-height:25px"> {% trans %}system error log is recorded, error will be fixed as soon as possible{% endtrans %}<br/> - {% trans %}please report the error to the site administrators if you wish{% endtrans %} - <ul> - <li><a href="#" id="linkPrevious">{% trans %}back to previous page{% endtrans %}</li> - <li><a href="{% url questions %}">{% trans %}see latest questions{% endtrans %}</a></li> - <li><a href="{% url tags %}">{% trans %}see tags{% endtrans %}</a></li> - </u> + {% trans %}please report the error to the site administrators{% endtrans %} </div> </div> {% endblock %} -{% block endjs %} - <script type="text/javascript"> - $().ready(function(){ - $("#linkPrevious").bind("click", back=function(){history.go(-1);}) - }); - </script> -{% endblock %} <!-- end template 500.html --> diff --git a/askbot/templates/answer_edit.html b/askbot/templates/answer_edit.html index 3c6b7a4c..c9d8a147 100644 --- a/askbot/templates/answer_edit.html +++ b/askbot/templates/answer_edit.html @@ -1,13 +1,14 @@ {% extends "two_column_body.html" %} {% import "macros.html" as macros %} <!-- template answer_edit.html --> -{% block title %}{% spaceless %}{% trans %}Edit answer{% endtrans %}{% endspaceless %}{% endblock %} +{% block title %}{% spaceless %}{{ settings.WORDS_EDIT_ANSWER|escape }}{% endspaceless %}{% endblock %} {% block forestyle %} <link rel="stylesheet" type="text/css" href="{{"/js/wmd/wmd.css"|media}}" /> {% endblock %} {% block content %} <div class="section-title"> - {% trans %}Edit answer{% endtrans %} [<a href="{{ answer.thread._question_post().get_absolute_url() }}#{{ answer.id }}">{% trans %}back{% endtrans %}</a>] +{{ settings.WORDS_EDIT_ANSWER|escape }} +[<a href="{{ answer.get_absolute_url() }}">{% trans %}back{% endtrans %}</a>] </div> <div id="main-body" class="ask-body"> <form id="fmedit" action="{% url edit_answer answer.id %}" method="post" >{% csrf_token %} diff --git a/askbot/templates/ask.html b/askbot/templates/ask.html index 64a8a260..bf713a70 100644 --- a/askbot/templates/ask.html +++ b/askbot/templates/ask.html @@ -13,29 +13,7 @@ {% endblock %} {% block content %} <div class="question-instructions"> - {% if settings.QUESTION_INSTRUCTIONS %} - {{ settings.QUESTION_INSTRUCTIONS|safe }} - {% else %} - <ul> - {% if not request.user.is_authenticated() %} - <li class="warning">{% trans %}since you are not logged in right now, you will be asked to sign in or register after posting your question{% endtrans %}</li> - {% else %} - {% if settings.EMAIL_VALIDATION %} - {% if not request.user.email_isvalid %} - <li class="warning">{% trans email=request.user.email %}Your email, {{ email }} has not yet been validated. To post messages you must verify your email, please see <a href='{{ email_validation_faq_url }}'>more details here</a>. You can submit your question now and validate email after that. Meanwhile, your question will saved as pending.{% endtrans %}</li> - {% endif %} - {% endif %} - {% endif %} - <li>{% trans %}please, try to make your question interesting to this community{% endtrans %}</li> - <li>{% trans %}provide enough details{% endtrans %}</li> - <li>{% trans %}be clear and concise{% endtrans %}</li> - </ul> - {% endif %} - <p class='info-box-follow-up-links'> - <!-- will be change to a popup windows - <a href="{% url faq %}" target="_blank" title="{% trans %}see frequently asked questions{% endtrans %}">{% trans %}FAQ{% endtrans %} »</a> - --> - </p> + {% include "widgets/question_edit_tips.html" %} </div> {% include "widgets/ask_form.html" %} {% endblock %} diff --git a/askbot/templates/authopenid/changeemail.html b/askbot/templates/authopenid/changeemail.html deleted file mode 100644 index 37de8369..00000000 --- a/askbot/templates/authopenid/changeemail.html +++ /dev/null @@ -1,29 +0,0 @@ -{% extends "one_column_body.html" %} -{% block title %}{% spaceless %}{% trans %}Change Email{% endtrans %}{% endspaceless %}{% endblock %} -{% block content %} -{% if action_type=="validate" %} - <div id="main-bar" class="headNormal"> - {% trans %}Validate email{% endtrans %} - </div> - <p class="message"> - {% trans %}<span class=\"strong big\">An email with a validation link has been sent to -{{ email }}.</span> Please <strong>follow the emailed link</strong> with your -web browser. Email validation is necessary to help insure the proper use of -email on <span class=\"orange\">Q&A</span>. If you would like to use -<strong>another email</strong>, please <a -href='{{ change_email_url }}'><strong>change it again</strong></a>.{% endtrans %} - </p> -{% elif action_type=="validation_complete" %} - <div id="main-bar" class="headNormal"> - {% trans %}Email verified{% endtrans %} - </div> - <p class="message"> - {% trans %}<span class=\"big strong\">Thank you for verifying your email!</span> Now -you can <strong>ask</strong> and <strong>answer</strong> questions. Also if -you find a very interesting question you can <strong>subscribe for the -updates</strong> - then will be notified about changes <strong>once a day</strong> -or less frequently.{% endtrans %} - </p> -{% endif %} -{% endblock %} -<!-- end changeemail.html --> diff --git a/askbot/templates/authopenid/providers_javascript.html b/askbot/templates/authopenid/providers_javascript.html index 9d8c34a8..86f1004f 100644 --- a/askbot/templates/authopenid/providers_javascript.html +++ b/askbot/templates/authopenid/providers_javascript.html @@ -1,5 +1,5 @@ -<script type='text/javascript' src='{{"/js/jquery.validate.min.js"|media}}'></script> -<script type="text/javascript" src="{{"/jquery-openid/jquery.openid.js"|media}}"></script> +<script type='text/javascript' src='{{ "/js/jquery.validate.min.js"|media }}'></script> +<script type="text/javascript" src="{{ "/jquery-openid/jquery.openid.js"|media }}"></script> <script type="text/javascript"> askbot['urls']['changePassword'] = '{% url change_password %}'; var extra_token_name = {}; @@ -11,22 +11,22 @@ {% for login_provider in major_login_providers %} {%if settings['SIGNIN_' + login_provider.name.upper() + '_ENABLED'] == True %} {% if login_provider.extra_token_name %} - extra_token_name['{{login_provider.name}}'] = '{{login_provider.extra_token_name}}'; + extra_token_name['{{login_provider.name}}'] = '{{ login_provider.extra_token_name|escapejs }}'; {% endif %} {% if login_provider.type == 'password' %} - create_pw_text['{{login_provider.name}}'] = '{{login_provider.create_password_prompt}}'; - change_pw_text['{{login_provider.name}}'] = '{{login_provider.change_password_prompt}}'; + create_pw_text['{{login_provider.name}}'] = '{{ login_provider.create_password_prompt|escapejs }}'; + change_pw_text['{{login_provider.name}}'] = '{{ login_provider.change_password_prompt|escapejs }}'; {% endif %} {% endif %} {% endfor %} {% for login_provider in minor_login_providers %} {% if settings['SIGNIN_' + login_provider.name.upper() + '_ENABLED'] == True %} - {% if login_provider.extra_token_name %} - extra_token_name['{{login_provider.name}}'] = '{{login_provider.extra_token_name}}'; +{% if login_provider.extra_token_name %} + extra_token_name['{{login_provider.name}}'] = '{{ login_provider.extra_token_name|escapejs }}'; {% endif %} {% if login_provider.type == 'password' %} - create_pw_text['{{login_provider.name}}'] = '{{login_provider.create_password_prompt}}'; - change_pw_text['{{login_provider.name}}'] = '{{login_provider.change_password_prompt}}'; + create_pw_text['{{login_provider.name}}'] = '{{ login_provider.create_password_prompt|escapejs }}'; + change_pw_text['{{login_provider.name}}'] = '{{ login_provider.change_password_prompt|escapejs }}'; {% endif %} {% endif %} {% endfor %} @@ -36,6 +36,7 @@ var userIsAuthenticated = false; {% endif %} askbot['settings']['signin_always_show_local_login'] = {% if settings.SIGNIN_ALWAYS_SHOW_LOCAL_LOGIN %}true{% else %}false{% endif %}; + askbot['settings']['useLdapForPasswordLogin'] = {{ settings.USE_LDAP_FOR_PASSWORD_LOGIN|as_js_bool}}; $("body").authenticator(); (function() { var form = new ChangePasswordForm(); diff --git a/askbot/templates/authopenid/signin.html b/askbot/templates/authopenid/signin.html index ad003b69..daf5a45a 100644 --- a/askbot/templates/authopenid/signin.html +++ b/askbot/templates/authopenid/signin.html @@ -10,20 +10,6 @@ {% if have_buttons or view_subtype == 'email_sent' %}
<h1 class="section-title">{{page_title}}</h1>
{% endif %}
- {% if answer %}
- <div class="message">
- {% trans title=answer.question.title|escape %}
- Your answer to {{title}} will be posted once you log in
- {% endtrans %}
- </div>
- {% endif %}
- {% if question %}
- <div class="message">
- {% trans title=question.title|escape %}Your question
- {{title}} will be posted once you log in
- {% endtrans %}
- </div>
- {% endif %}
{% if not (view_subtype == 'default' and have_buttons) %}
<p id='login-intro'>
{% if view_subtype == 'add_openid' and have_buttons %}
@@ -87,7 +73,7 @@ {% endif %}
>
{{login_form.password_action}}
- {% if user.is_anonymous() %}
+ {% if user.is_anonymous() or settings.USE_LDAP_FOR_PASSWORD_LOGIN %}
{% if have_buttons %}
<h2 id="password-heading">
{% trans %}or enter your <span>user name and password</span>{% endtrans %}
@@ -106,7 +92,13 @@ </tr>
{% endif %}
<tr>
- <td><label for="id_username">{% trans %}Login or email{% endtrans %}</label></td>
+ <td><label for="id_username">
+ {% if settings.USE_LDAP_FOR_PASSWORD_LOGIN %}
+ {% trans %}Login{% endtrans %}
+ {% else %}
+ {% trans %}Login or email{% endtrans %}
+ {% endif %}
+ </label></td>
<td>{{login_form.username}}</td>
</tr>
<tr>
@@ -120,7 +112,7 @@ <a class="create-password-account" style="vertical-align:middle" href="{% url user_signup_with_password %}?login_provider=local">{% trans %}Create a password-protected account{% endtrans %}</a>
{% endif %}
</p>
- {% elif settings.USE_LDAP_FOR_PASSWORD_LOGIN == False %}
+ {% else %}{# change password form #}
<h2 id="password-heading">
{% trans %}To change your password - please enter the new one twice, then submit{% endtrans %}
</h2>
diff --git a/askbot/templates/authopenid/widget_signin.html b/askbot/templates/authopenid/widget_signin.html index 717aec63..4cedd014 100644 --- a/askbot/templates/authopenid/widget_signin.html +++ b/askbot/templates/authopenid/widget_signin.html @@ -14,20 +14,6 @@ {% if have_buttons or view_subtype == 'email_sent' %}
<h1 class="section-title">{{page_title}}</h1>
{% endif %}
- {% if answer %}
- <div class="message">
- {% trans title=answer.question.title|escape %}
- Your answer to {{title}} will be posted once you log in
- {% endtrans %}
- </div>
- {% endif %}
- {% if question %}
- <div class="message">
- {% trans title=question.title|escape %}Your question
- {{title}} will be posted once you log in
- {% endtrans %}
- </div>
- {% endif %}
<p id='login-intro'>
{% if view_subtype == 'default' and have_buttons %}
{% trans %}Choose your favorite service below to sign in using secure OpenID or similar technology. Your external service password always stays confidential and you don't have to rememeber or create another one.{% endtrans %}
diff --git a/askbot/templates/badges.html b/askbot/templates/badges.html index 112adc61..4f4d0973 100644 --- a/askbot/templates/badges.html +++ b/askbot/templates/badges.html @@ -4,7 +4,8 @@ {% block content %} <h1 class="section-title">{% trans %}Badges{% endtrans %}</h1> <p> -{% trans %}Community gives you awards for your questions, answers and votes.{% endtrans %}<br/> +{{ settings.WORDS_COMMUNITY_GIVES_YOU_AWARDS|escape }} +<br/> {% trans %}Below is the list of available badges and number of times each type of badge has been awarded.{% endtrans %} </p> <div id="medalList"> diff --git a/askbot/templates/close.html b/askbot/templates/close.html index bac2b3ee..70d7cc8b 100644 --- a/askbot/templates/close.html +++ b/askbot/templates/close.html @@ -1,9 +1,9 @@ {% extends "one_column_body.html" %} <!-- template close.html --> -{% block title %}{% spaceless %}{% trans %}Close question{% endtrans %}{% endspaceless %}{% endblock %} +{% block title %}{% spaceless %}{{ settings.WORDS_CLOSE_QUESTION|escape }}{% endspaceless %}{% endblock %} {% block content %} -<h1>{% trans %}Close question{% endtrans %}</h1> - <p>{% trans %}Close the question{% endtrans %}: <a href="{{ question.get_absolute_url() }}"> +<h1>{{ settings.WORDS_CLOSE_QUESTION|escape }}</h1> + <p>{{ settings.WORDS_CLOSE_QUESTION|escape }}: <a href="{{ question.get_absolute_url() }}"> <strong>{{ question.get_question_title()|escape }}</strong></a> </p> <form id="fmclose" action="{% url close question.id %}" method="post" >{% csrf_token %} diff --git a/askbot/templates/email/delayed_email_alert.html b/askbot/templates/email/delayed_email_alert.html index 3ccacea4..252a2337 100644 --- a/askbot/templates/email/delayed_email_alert.html +++ b/askbot/templates/email/delayed_email_alert.html @@ -1,6 +1,6 @@ {% block content %} <p>{% trans %}Dear {{ name }},{% endtrans %}</p> -<p>{% trans num=questions|length %}The following question has been updated {{ site_name }}:{% pluralize num %}The following {{ num }} questions have been updated on {{ site_name }}:{% endtrans %}</p> +<p>{% trans %}{{ site_name }} has these updates, please have a look:{% endtrans %}</p> <ul> {% for q in questions %} <li> diff --git a/askbot/templates/email/insufficient_rep_to_post_by_email.html b/askbot/templates/email/insufficient_rep_to_post_by_email.html index df7f797a..deabfbbd 100644 --- a/askbot/templates/email/insufficient_rep_to_post_by_email.html +++ b/askbot/templates/email/insufficient_rep_to_post_by_email.html @@ -7,12 +7,12 @@ * site_link - html for the link #} {% block headline %} - {% trans user=username|escape %}{{ username }}, your question could not be posted by email just yet.{% endtrans %} + {% trans user=username|escape %}{{ username }}, your content could not be posted by email just yet.{% endtrans %} {%endblock%} {% block content %} <p> {% trans %}To make posts by email, you need to receive about {{min_upvotes}} upvotes.{% endtrans %}<br/> - {% trans link=site_link|safe %}At this time, please post your question at {{link}}{% endtrans %} + {% trans link=site_link|safe %}At this time, please post your content at {{link}}{% endtrans %} </p> {% endblock %} {% block footer %} diff --git a/askbot/templates/email/macros.html b/askbot/templates/email/macros.html index 77345a45..c5b7cfcc 100644 --- a/askbot/templates/email/macros.html +++ b/askbot/templates/email/macros.html @@ -1,60 +1,73 @@ +{%- macro mailto_link(user) -%} + <a href="mailto:{{ user.email }}">{{ user.email }}</a> +{%- endmacro -%} + {% macro quoted_post( - post = None, - quote_level = 0, - format = None, - is_leaf_post = False + post=None, + recipient=None, + quote_level=0, + format=None, + is_leaf_post=False ) %} {% spaceless %} {{ start_quote(quote_level) }} - {% set author = post.author.username|escape %} - {% if post.post_type == 'question' %} - {% if quote_level > 0 %} - <p style="font-size:10px; font-weight: bold;"> + + {% if recipient|can_see_private_user_data(post.author) %} + {% set author = post.author.username|escape ~ '/(' ~ mailto_link(post.author) ~ ')' %} + {% elif post.is_anonymous %} + {% set author = post.author.get_name_of_anonymous_user()|escape %} {% else %} - <p style="font-size:20px; font-weight: bold; margin: 10px 0"> + {% set author = post.author.username|escape %} {% endif %} - {% if format == 'parent_subthread' %} - {% if is_leaf_post %} - {% trans %}Question by {{ author }}:{% endtrans %} + + {% if post.post_type == 'question' %} + {% if quote_level > 0 %} + <p style="font-size:10px; font-weight: bold;"> + {% else %} + <p style="font-size:20px; font-weight: bold; margin: 10px 0"> + {% endif %} + {% if format == 'parent_subthread' %} + {% if is_leaf_post %} + {% trans %}Started by {{ author }}:{% endtrans %} + {% else %} + {% trans -%} + In reply to {{ author }}: + {%- endtrans %} + {% endif %} {% else %} - {% trans -%} - In reply to {{ author }}'s question: - {%- endtrans %} + {{ settings.WORDS_QUESTION_SINGULAR|title|escape }} : {% endif %} - {% else %} - {% trans %}Question :{% endtrans %} - {% endif %} - {{ post.thread.title }} - </p> - {% if quote_level > 0 %} - <p style="font-size:10px; font-weight: bold;"> - {% if format != 'parent_subthread' %} - {% trans %}Asked by {{ author }}:{% endtrans %} - {% endif %} - </p> - {% endif %} - {% set tag_names = post.get_tag_names() %} - {% if tag_names %} - <p style="font-size:10px; font-style:italic;"> - {% trans %}Tags:{% endtrans %} - {{ tag_names|join(', ') }}. - </p> - {% endif %} + {{ post.thread.title }} + </p> + {% if quote_level > 0 %} + <p style="font-size:10px; font-weight: bold;"> + {% if format != 'parent_subthread' %} + {% trans %}Started by {{ author }}:{% endtrans %} + {% endif %} + </p> + {% endif %} + {% set tag_names = post.get_tag_names() %} + {% if tag_names %} + <p style="font-size:10px; font-style:italic;"> + {% trans %}Tags:{% endtrans %} + {{ tag_names|join(', ') }}. + </p> + {% endif %} {% elif post.post_type == 'answer' %} <p style="font-size:10px; font-weight: bold;"> {% if format == 'parent_subthread' %} {% if is_leaf_post %} {% trans -%} - {{ author }}'s answer: + {{ author }}'s response: {%- endtrans %} {% else %} {% trans -%} - In reply to {{ author }}'s answer: + In reply to {{ author }}: {%- endtrans %} {% endif %} {% else %} - {% trans %}Answered by {{ author }}:{% endtrans %} + {% trans %}Replied by {{ author }}:{% endtrans %} {% endif %} </p> {% else %} diff --git a/askbot/templates/email/post_as_subthread.html b/askbot/templates/email/post_as_subthread.html index 08b35ac5..5c08247f 100644 --- a/askbot/templates/email/post_as_subthread.html +++ b/askbot/templates/email/post_as_subthread.html @@ -1,7 +1,7 @@ {% from "email/macros.html" import quoted_post %} {% if post.post_type in ('question', 'answer') %} - {{ quoted_post(post) }} + {{ quoted_post(post, recipient=recipient) }} {% set comments = post.get_cached_comments() %} {% if comments %} <p> @@ -12,7 +12,7 @@ {%- endtrans -%} </p> {% for comment in comments %} - {{ quoted_post(comment, quote_level = 1) }} + {{ quoted_post(comment, quote_level=1, recipient=recipient) }} {% endfor %} {% endif %} {% endif %} diff --git a/askbot/templates/email/quoted_post.html b/askbot/templates/email/quoted_post.html index ecc20ad9..2c3b6046 100644 --- a/askbot/templates/email/quoted_post.html +++ b/askbot/templates/email/quoted_post.html @@ -1,5 +1,9 @@ {% from "email/macros.html" import quoted_post %} {{ quoted_post( - post, quote_level, is_leaf_post = is_leaf_post, format = format + post=post, + quote_level=quote_level, + recipient=recipient, + is_leaf_post=is_leaf_post, + format=format ) }} diff --git a/askbot/templates/email/re_welcome_lamson_on.html b/askbot/templates/email/re_welcome_lamson_on.html index f30345d1..af050960 100644 --- a/askbot/templates/email/re_welcome_lamson_on.html +++ b/askbot/templates/email/re_welcome_lamson_on.html @@ -4,7 +4,7 @@ {% block content %} {% if can_post_by_email %} - <p>{% trans %}You can post questions by emailing them at {{ ask_address }}.{% endtrans %}</p> + <p>{{ settings.WORDS_YOU_CAN_POST_QUESTIONS_BY_EMAILING_THEM_AT|escape }} {{ ask_address }}</p> <p>{% trans %}When you receive update notifications, you will be able to respond to them, also by email.{% endtrans %}</p> <p>{% trans %}Of course, you can always visit the {{ site_name }} at <a href="{{ site_url }}">{{ site_url }}</a>.{% endtrans %}</p> {% else %} diff --git a/askbot/templates/email/welcome_lamson_on.html b/askbot/templates/email/welcome_lamson_on.html index 3e47f44f..898e4b3d 100644 --- a/askbot/templates/email/welcome_lamson_on.html +++ b/askbot/templates/email/welcome_lamson_on.html @@ -11,7 +11,7 @@ of the email code to detect the response signature that will appear under #} {% trans %}Important: <em>Please reply</em> to this message, without editing it. We need this to determine your email signature and that the email address is valid and was typed correctly.{% endtrans %} </p> <p> - {% trans %}Until we receive the response from you, you will not be able ask or answer questions on {{ site_name }} by email.{% endtrans %} + {% trans %}Until we receive the response from you, you will not be able to post content on {{ site_name }} by email.{% endtrans %} </p> {% endblock %} {%block footer %} diff --git a/askbot/templates/embed/ask_by_widget.html b/askbot/templates/embed/ask_by_widget.html index fb38ad64..949284e1 100644 --- a/askbot/templates/embed/ask_by_widget.html +++ b/askbot/templates/embed/ask_by_widget.html @@ -167,7 +167,7 @@ <div class="title">{{widget.title}}</div> <form action="." method="POST" accept-charset="utf-8"> {% csrf_token %} - <label>{%trans%}Please enter your question{%endtrans%}</label> + <label>{{ settings.WORDS_PLEASE_ENTER_YOUR_QUESTION|escape }}</label> <div class="input-title"> {{form.title}} </div> @@ -195,7 +195,7 @@ {% if form.ask_anonymously %} <p>{{form.ask_anonymously.label_tag()}}: {{form.ask_anonymously}}</p> {%endif%} - <input type="submit" value="Ask your question" id="submit" /> + <input type="submit" value="{{ settings.WORDS_ASK_YOUR_QUESTION|escape }}" id="submit" /> </form> {%endblock%} {% block endjs %} diff --git a/askbot/templates/embed/widgets.html b/askbot/templates/embed/widgets.html index 767ebc2c..7fcfa94b 100644 --- a/askbot/templates/embed/widgets.html +++ b/askbot/templates/embed/widgets.html @@ -13,7 +13,7 @@ </thead> <tbody> <tr> - <td>{% trans %}Ask a question{% endtrans %}</td> + <td>"{{ settings.WORDS_ASK_YOUR_QUESTION|escape }}"</td> <td><a href="{% url create_widget 'ask' %}">{% trans %}create{% endtrans %}</a></td> <td> {% if ask_widgets > 0 %} @@ -22,7 +22,7 @@ </td> </tr> <tr> - <td>{% trans %}List of questions{% endtrans %}</td> + <td>{{ settings.WORDS_LIST_OF_QUESTIONS|escape }}</td> <td><a href="{% url create_widget 'question' %}">{% trans %}create{% endtrans %}</a></td> <td> {% if question_widgets > 0 %} diff --git a/askbot/templates/faq_static.html b/askbot/templates/faq_static.html index 3a2638be..20a090d2 100644 --- a/askbot/templates/faq_static.html +++ b/askbot/templates/faq_static.html @@ -18,7 +18,7 @@ {% trans %}Karma system allows users to earn rights to perform a variety of moderation tasks{% endtrans %} </p> <h2>{% trans %}How does karma system work?{% endtrans %}</h2> -<p>{% trans %}When a question or answer is upvoted, the user who posted them will gain some points, which are called \"karma points\". These points serve as a rough measure of the community trust to him/her. Various moderation tasks are gradually assigned to the users based on those points.{% endtrans %}</p> +<p>{% trans %}When a question or answer is upvoted, the user who posted them will gain some points, which are called "karma points". These points serve as a rough measure of the community trust to him/her. Various moderation tasks are gradually assigned to the users based on those points.{% endtrans %}</p> <p>{% trans MAX_REP_GAIN_PER_USER_PER_DAY=settings.MAX_REP_GAIN_PER_USER_PER_DAY, REP_GAIN_FOR_RECEIVING_UPVOTE=settings.REP_GAIN_FOR_RECEIVING_UPVOTE, REP_LOSS_FOR_RECEIVING_DOWNVOTE=settings.REP_LOSS_FOR_RECEIVING_DOWNVOTE|absolute_value %}For example, if you ask an interesting question or give a helpful answer, your input will be upvoted. On the other hand if the answer is misleading - it will be downvoted. Each vote in favor will generate <strong>{{REP_GAIN_FOR_RECEIVING_UPVOTE}}</strong> points, each vote against will subtract <strong>{{REP_LOSS_FOR_RECEIVING_DOWNVOTE}}</strong> points. There is a limit of <strong>{{MAX_REP_GAIN_PER_USER_PER_DAY}}</strong> points that can be accumulated for a question or answer per day. The table below explains reputation point requirements for each type of moderation task.{% endtrans %} </p> @@ -40,14 +40,11 @@ <tr> <td class="faq-rep-item"><strong>{{settings.MIN_REP_TO_VOTE_DOWN}}</strong></td> <td>{% trans %}downvote{% endtrans %}</td> - </tr><tr> + </tr> + <tr> <td class="faq-rep-item"><strong>{{settings.MIN_REP_TO_ACCEPT_OWN_ANSWER}}</strong></td> <td>{% trans %} accept own answer to own questions{% endtrans %}</td> </tr> - </tr><tr> - <td class="faq-rep-item"><strong>{{settings.MIN_REP_TO_CLOSE_OWN_QUESTIONS}}</strong></td> - <td>{% trans %}open and close own questions{% endtrans %}</td> - </tr> <tr> <td class="faq-rep-item"><strong>{{settings.MIN_REP_TO_RETAG_OTHERS_QUESTIONS}}</strong></td> <td>{% trans %}retag other's questions{% endtrans %}</td> diff --git a/askbot/templates/list_suggested_tags.html b/askbot/templates/list_suggested_tags.html index 1c9a947d..7c69ddc3 100644 --- a/askbot/templates/list_suggested_tags.html +++ b/askbot/templates/list_suggested_tags.html @@ -11,7 +11,7 @@ <th class="tags-col">{% trans %}Tag{% endtrans %}</th> <th class="users-col">{% trans %}Suggested by{% endtrans %}</th> <th class="decision-col">{% trans %}Your decision{% endtrans %}</th> - <th>{% trans %}Suggested tag was used for questions{% endtrans %}</th> + <th>{% trans %}Where the tag was used{% endtrans %}</th> </tr> </thead> <tbody> @@ -35,7 +35,7 @@ <button class="reject">{% trans %}Reject{% endtrans %}</button> </td> <td class="thread-links-col"> - <span>{% trans %}There are no questions with this tag yet{% endtrans %}</span> + <span>{% trans %}This tag has not yet been used{% endtrans %}</span> </td> </tr> {% else %} @@ -58,7 +58,7 @@ <tr class="per-tag-controls" data-tag-id="{{ tag.id }}"> <td colspan="4"> {% if tag.threads.count() > 1 %} - <button class="accept">{% trans name=tag.name %}Apply tag "{{ name }}" to all above questions{% endtrans %}</button> + <button class="accept">{% trans name=tag.name %}Apply tag "{{ name }}" to the above{% endtrans %}</button> <button class="reject">{% trans %}Reject tag{% endtrans %}</button> {% endif %} </td> diff --git a/askbot/templates/livesettings/group_settings.html b/askbot/templates/livesettings/group_settings.html index a8baa47f..3c28d320 100644 --- a/askbot/templates/livesettings/group_settings.html +++ b/askbot/templates/livesettings/group_settings.html @@ -1,7 +1,7 @@ {% extends "one_column_body.html" %} {% block content %} <h1 class="section-title"> - {% trans %}Settings{% endtrans %} → {{ group.super_group.name }} → {{ group.name }} + {% trans %}Settings{% endtrans %} → {{ settings_group.super_group.name }} → {{ settings_group.name }} </h1> <div class="settings-main"> {% if form.errors %} @@ -13,7 +13,7 @@ <form method="post" enctype="multipart/form-data">{% csrf_token %} <table class="settings" - summary="{% trans name = group.name %}Settings included in {{ name }}.{% endtrans %}" + summary="{% trans name = settings_group.name %}Settings included in {{ name }}.{% endtrans %}" > {% for field in form %} {% if field.is_hidden %} @@ -57,7 +57,7 @@ <ul> {% for g in super_group.groups %} {% if g.keys %} - {% if g.key == group.key %} + {% if g.key == settings_group.key %} <li class="on">{{g.name}}</li> {% else %} <li><a href="{% url "group_settings" g.key %}">{{g.name}}</a></li> diff --git a/askbot/templates/macros.html b/askbot/templates/macros.html index c6f40a51..a17c808e 100644 --- a/askbot/templates/macros.html +++ b/askbot/templates/macros.html @@ -2,7 +2,7 @@ {%- macro share(site = None, site_label = None, icon = False) -%} <a class="{{ site }}-share{% if icon == True %} icon{% endif %}" - title="{% trans %}Share this question on {{site}}{% endtrans %}" + title="{% trans %}Share this content on {{site}}{% endtrans %}" >{% if icon == False %}{% if site_label %}{{ site_label }}{% else %}{{ site }}{% endif %}{% endif %}</a> {%- endmacro -%} @@ -59,7 +59,9 @@ {% else %} {{ user_card(user, karma_mode=karma_mode, badges_mode=badges_mode) }} {% endif %} - {{ user_primary_group(user) }} + {% if settings.GROUPS_ENABLED %} + {{ user_primary_group(user) }} + {% endif %} {%- endmacro -%} {%- macro post_last_updater_and_creator_info( @@ -88,11 +90,11 @@ poor design of the data or methods on data objects #} {% if is_wiki %} <p> {%- if post.post_type == 'question' -%} - {%- trans %}asked{% endtrans %} + {{ settings.WORDS_ASKED|escape }} {% elif post.post_type == 'answer' %} - {%- trans %}answered{% endtrans %} + {{ settings.WORDS_ANSWERED|escape }} {% else %} - {%- trans %}posted{% endtrans %} + {%- trans %}posted{% endtrans %} {% endif %} <strong>{{ timeago(post.added_at) }}</strong> </p> @@ -107,9 +109,9 @@ poor design of the data or methods on data objects #} <p style="line-height:12px;"> {# todo: access to class names needs to be removed here #} {% if post.post_type == 'question' %} - {% trans %}asked{% endtrans %} + {{ settings.WORDS_ASKED|escape }} {% elif post.post_type == 'answer' %} - {% trans %}answered{% endtrans %} + {{ settings.WORDS_ANSWERED|escape }} {% else %} {% trans %}posted{% endtrans %} {% endif %} @@ -311,7 +313,6 @@ poor design of the data or methods on data objects #} class="tag tag-right{% if css_class %} {{ css_class }}{% endif %}" {% if is_link %} href="{{ search_state.add_tag(tag).full_url() }}" - title="{% trans tag=tag|escape %}see questions tagged '{{ tag }}'{% endtrans %}" {% endif %} rel="tag" data-tag-name="{{ tag|replace('*', '✽')|escape }}" @@ -768,7 +769,7 @@ for the purposes of the AJAX comment editor #} {% for num in p.page_numbers %} {% if num == p.page and p.pages != 1%} - <span class="curr" title="{% trans %}current page{% endtrans %}">{{ num }}</span> + <span class="curr page" title="{% trans %}current page{% endtrans %}"><a>{{ num }}</a></span> {% else %} <span class="page"><a href="{{ search_state.change_page(num).full_url() }}" title="{% trans %}page {{num}}{% endtrans %}">{{ num }}</a></span> {% endif %} diff --git a/askbot/templates/main_page.html b/askbot/templates/main_page.html index 207e064d..19c447a2 100644 --- a/askbot/templates/main_page.html +++ b/askbot/templates/main_page.html @@ -29,6 +29,10 @@ <script type="text/javascript"> {# cant cache this #} askbot['settings']['showSortByRelevance'] = {{ show_sort_by_relevance|as_js_bool }}; + askbot['messages']['questionSingular'] = '{{ settings.WORDS_QUESTION_SINGULAR|escapejs }}'; + askbot['messages']['answerSingular'] = '{{ settings.WORDS_ANSWER_SINGULAR|escapejs }}'; + askbot['messages']['acceptOwnAnswer'] = '{{ settings.WORDS_ACCEPT_OR_UNACCEPT_OWN_ANSWER|escapejs }}'; + askbot['messages']['followQuestions'] = '{{ settings.WORDS_FOLLOW_QUESTIONS|escapejs }}'; </script> {% include "main_page/javascript.html" %} {% include "main_page/custom_javascript.html" ignore missing %} diff --git a/askbot/templates/main_page/headline.html b/askbot/templates/main_page/headline.html index 11f638e1..f597a114 100644 --- a/askbot/templates/main_page/headline.html +++ b/askbot/templates/main_page/headline.html @@ -1,7 +1,7 @@ {% import "macros.html" as macros %} {% if questions_count > 0 %} <h1 id="questionCount" class="search-result-summary"> - {% trans cnt=questions_count, q_num=questions_count|intcomma %}{{q_num}} question{% pluralize %}{{q_num}} questions{% endtrans %} + {{ questions_count|intcomma }} {{ settings.WORDS_QUESTIONS_COUNTABLE_FORMS|py_pluralize(questions_count) }} {% if author_name %} {% trans %}with {{author_name}}'s contributions{% endtrans %} {% endif %} diff --git a/askbot/templates/main_page/javascript.html b/askbot/templates/main_page/javascript.html index 24182708..72d63ed3 100644 --- a/askbot/templates/main_page/javascript.html +++ b/askbot/templates/main_page/javascript.html @@ -17,6 +17,7 @@ askbot['urls']['mark_subscribed_tag'] = '{% url mark_subscribed_tag %}'; askbot['urls']['unmark_tag'] = '{% url unmark_tag %}'; askbot['urls']['set_tag_filter_strategy'] = '{% url "set_tag_filter_strategy" %}'; + askbot['settings']['tag_editor'] = '{{ tag_editor_settings|escapejs }}'; if (Modernizr.history) { // history management works! diff --git a/askbot/templates/main_page/nothing_found.html b/askbot/templates/main_page/nothing_found.html index 98629476..73497df0 100644 --- a/askbot/templates/main_page/nothing_found.html +++ b/askbot/templates/main_page/nothing_found.html @@ -1,11 +1,11 @@ {# todo: add tips to widen selection #} <p class="evenMore" style="padding-top:30px;text-align:center;"> {% if search_state.scope == "unanswered" %} - {% trans %}There are no unanswered questions here{% endtrans %} + {{ settings.WORDS_THERE_ARE_NO_UNANSWERED_QUESTIONS_HERE|escape }} {% endif %} {% if search_state.scope == "followed" %} - {% trans %}No questions here. {% endtrans %} - {% trans %}Please follow some questions or follow some users.{% endtrans %} + {{ settings.WORDS_NO_QUESTIONS_HERE|escape }} + {{ settings.WORDS_PLEASE_FOLLOW_QUESTIONS|escape }} {% endif %} </p> {% if search_state.query or search_state.tags or search_state.author %} @@ -27,5 +27,5 @@ </p> {% endif %} <p class="evenMore" style="text-align:center"> -<a href="{% url ask %}">{% trans %}Please always feel free to ask your question!{% endtrans %}</a> +<a href="{% url ask %}">{{ settings.WORDS_PLEASE_FEEL_FREE_TO_ASK_YOUR_QUESTION|escape }}</a> </p> diff --git a/askbot/templates/main_page/questions_loop.html b/askbot/templates/main_page/questions_loop.html index 80598b67..020649ee 100644 --- a/askbot/templates/main_page/questions_loop.html +++ b/askbot/templates/main_page/questions_loop.html @@ -7,7 +7,7 @@ {% endfor %} {#<div class="evenMore"> {% trans %}Did not find what you were looking for?{% endtrans %} - <a href="{% url ask %}">{% trans %}Ask your question!{% endtrans %}</a> + <a href="{% url ask %}">{{ settings.WORDS_ASK_YOUR_QUESTION }}</a> </div>#} {% endif %} diff --git a/askbot/templates/main_page/tab_bar.html b/askbot/templates/main_page/tab_bar.html index c0b37955..ef66aebe 100644 --- a/askbot/templates/main_page/tab_bar.html +++ b/askbot/templates/main_page/tab_bar.html @@ -8,7 +8,7 @@ {% else %} href="/feeds/rss/" {% endif %} - title="{% trans %}subscribe to the questions feed{% endtrans %}" + title="{% trans %}subscribe to the feed{% endtrans %}" >{% trans %}RSS{% endtrans %} </a> {% endif %} diff --git a/askbot/templates/meta/bottom_scripts.html b/askbot/templates/meta/bottom_scripts.html index 5a307b19..3f1a6e57 100644 --- a/askbot/templates/meta/bottom_scripts.html +++ b/askbot/templates/meta/bottom_scripts.html @@ -33,6 +33,7 @@ askbot['data']['maxCommentLength'] = {{ settings.MAX_COMMENT_LENGTH }}; askbot['settings']['editorType'] = '{{ settings.EDITOR_TYPE }}'; askbot['settings']['commentsEditorType'] = '{{ settings.COMMENTS_EDITOR_TYPE }}'; + askbot['messages']['askYourQuestion'] = '{{ settings.WORDS_ASK_YOUR_QUESTION }}'; {% if settings.ALLOWED_UPLOAD_FILE_TYPES %} askbot['settings']['allowedUploadFileTypes'] = [ "{{ settings.ALLOWED_UPLOAD_FILE_TYPES|join('", "')|replace('.','') }}" diff --git a/askbot/templates/question.html b/askbot/templates/question.html index 8e834304..e1310e3c 100644 --- a/askbot/templates/question.html +++ b/askbot/templates/question.html @@ -15,6 +15,9 @@ //below is pure cross-browser javascript, no jQuery askbot['data']['userIsThreadModerator'] = {% if user_is_thread_moderator %}true{% else %}false{% endif %}; askbot['data']['oldestAnswerId'] = {% if oldest_answer_id %}{{ oldest_answer_id }}{% else %}-1{% endif %}; + {% if settings.READ_ONLY_MODE_ENABLED %} + askbot['settings']['readOnlyModeEnabled'] = true; + {% endif %} (function(){ var hasClass = function(node, selector) { @@ -174,7 +177,37 @@ } } + function remove_all_controls(post_id) { + var deleteBtn = document.getElementById('post-' + post_id + '-delete'); + var controls = deleteBtn.parentNode; + if (controls.className == 'comment-content') { + removeNode(deleteBtn); + var convertLinks = findChildrenByClassName(controls, 'convert-comment'); + if (convertLinks.length) { + removeNode(convertLinks[0]); + } + var editLinks = findChildrenByClassName(controls, 'edit'); + if (editLinks.length) { + removeNode(editLinks[0]); + } + } else { + var buttons = controls.childNodes; + var numButtons = buttons.length; + for (var i = numButtons - 1; i >= 0; i--) { + removeNode(buttons[i]); + } + } + }; + + function render_post_controls(post_id){ + + //in this case remove all post controls + if (askbot['settings']['readOnlyModeEnabled'] === true) { + remove_all_controls(post_id); + return; + } + if (data['userIsAdminOrMod']){ return;//all remaining functions stay on } @@ -191,8 +224,10 @@ ) { removeNode(deleteBtn); } + + var canFlagPosts = data['userReputation'] >= {{ settings.MIN_REP_TO_FLAG_OFFENSIVE }}; var flags = findChildrenByClassName(controls, 'question-flag'); - if (flags.length > 0) { + if (flags.length > 0 && !canFlagPosts) { removeNode(flags[0]); } var closeBtn = findChildrenByClassName(controls, 'question-close'); @@ -242,12 +277,12 @@ add_answer_btn.className += ' answer-own-question'; add_answer_btn.setAttribute( 'value', - '{% trans %}Answer Your Own Question{% endtrans %}' + '{{ settings.WORDS_ANSWER_YOUR_OWN_QUESTION|escapejs }}' ) } else { add_answer_btn.setAttribute( 'value', - '{% trans %}Post Your Answer{% endtrans %}' + '{{ settings.WORDS_POST_YOUR_ANSWER|escapejs }}' ) } } else { @@ -335,6 +370,9 @@ askbot['messages']['addComment'] = '{% trans %}add a comment{% endtrans %}'; askbot['messages']['userNamePrompt'] = '{% trans %}User name:{% endtrans %}'; askbot['messages']['userEmailPrompt'] = '{% trans %}Email address:{% endtrans %}'; + {% if settings.READ_ONLY_MODE_ENABLED %} + askbot['messages']['readOnlyMessage'] = '{{ settings.READ_ONLY_MESSAGE }}'; + {% endif %} askbot['settings']['saveCommentOnEnter'] = {{ settings.SAVE_COMMENT_ON_ENTER|as_js_bool }}; askbot['settings']['tagSource'] = '{{ settings.TAG_SOURCE }}'; askbot['settings']['enableSharingGoogle'] = {{ settings.ENABLE_SHARING_GOOGLE|as_js_bool }}; diff --git a/askbot/templates/question/answer_controls.html b/askbot/templates/question/answer_controls.html index 21aafe47..1c66f147 100644 --- a/askbot/templates/question/answer_controls.html +++ b/askbot/templates/question/answer_controls.html @@ -1,5 +1,5 @@ {#<span class="action-link swap-qa"> - <a id="swap-question-with-answer-{{answer.id}}">{% trans %}swap with question{% endtrans %}</a> + <a id="swap-question-with-answer-{{answer.id}}">{{ settings.WORDS_SWAP_WITH_QUESTION|escape }}</a> </span>uncomment if needed#} <span id='post-{{answer.id}}-edit' class="action-link"> <a class="question-edit" href="{% url edit_answer answer.id %}">{% trans %}edit{% endtrans %}</a> @@ -68,7 +68,7 @@ <input type="submit" class="link" - value="{% trans %}repost as a question comment{% endtrans %}" + value="{{ settings.WORDS_REPOST_AS_A_QUESTION_COMMENT|escape }}" /> </form> </li> @@ -82,7 +82,7 @@ <input type="submit" class="link" - value="{% trans %}repost as a comment under the older answer{% endtrans %}" + value="{{ settings.WORDS_REPOST_AS_A_COMMENT_UNDER_THE_OLDER_ANSWER|escape }}" /> </form> </li> diff --git a/askbot/templates/question/answer_tab_bar.html b/askbot/templates/question/answer_tab_bar.html index bebf68b8..917ce6d9 100644 --- a/askbot/templates/question/answer_tab_bar.html +++ b/askbot/templates/question/answer_tab_bar.html @@ -1,23 +1,16 @@ <div class="tabBar tabBar-answer"> <h2 id="questionCount"> - {% trans counter=answer_count %} - {{counter}} Answer - {% pluralize %} - {{counter}} Answers - {% endtrans %} + {{ answer_count }} {{ settings.WORDS_ANSWERS_COUNTABLE_FORMS|py_pluralize(answer_count) }} </h2> <div class="tabsA"> <span class="label"> {% trans %}Sort by »{% endtrans %} </span> <a id="oldest" href="{{ question.get_absolute_url() }}?sort=oldest#sort-top" - title="{% trans %}oldest answers will be shown first{% endtrans %}" - ><span>{% trans %}oldest{% endtrans %}</span></a> + ><span>{% trans %}oldest{% endtrans %}</span></a> <a id="latest" href="{{ question.get_absolute_url() }}?sort=latest#sort-top" - title="{% trans %}newest answers will be shown first{% endtrans %}" - ><span>{% trans %}newest{% endtrans %}</span></a> + ><span>{% trans %}newest{% endtrans %}</span></a> <a id="votes" href="{{ question.get_absolute_url() }}?sort=votes#sort-top" - title="{% trans %}most voted answers will be shown first{% endtrans %}" - ><span>{% trans %}most voted{% endtrans %}</span></a> + ><span>{% trans %}most voted{% endtrans %}</span></a> </div> </div> diff --git a/askbot/templates/question/answer_vote_buttons.html b/askbot/templates/question/answer_vote_buttons.html index 68503310..84c901e0 100644 --- a/askbot/templates/question/answer_vote_buttons.html +++ b/askbot/templates/question/answer_vote_buttons.html @@ -4,10 +4,10 @@ <div id="answer-img-accept-{{ answer.id }}" class="answer-img-accept" - {% if answer.accepted() %} - title="{% trans %}this answer has been selected as correct{% endtrans %}" - {% else %} - title="{% trans %}mark this answer as correct (click again to undo){% endtrans %}" - {% endif %} + {% if answer.accepted() %} + title="{{ settings.WORDS_THIS_ANSWER_HAS_BEEN_SELECTED_AS_CORRECT|escape }}" + {% else %} + title="{{ settings.WORDS_MARK_THIS_ANSWER_AS_CORRECT|escape }} {% trans %}(click again to undo){% endtrans %}" + {% endif %} ></div> {% endif %} diff --git a/askbot/templates/question/closed_question_info.html b/askbot/templates/question/closed_question_info.html index f6f3f557..33fc9482 100644 --- a/askbot/templates/question/closed_question_info.html +++ b/askbot/templates/question/closed_question_info.html @@ -1,5 +1,7 @@ <div class="question-status"> - <h3>{% trans close_reason=thread.get_close_reason_display() %}The question has been closed for the following reason <b>"{{ close_reason }}"</b> <i>by{% endtrans %} - <a href="{{ thread.closed_by.get_profile_url() }}">{{ thread.closed_by.username|escape }}</a> </i><br> - {% trans closed_at=thread.closed_at %}close date {{closed_at}}{% endtrans %}</h3> + <h3>{% trans %}Closed for the following reason{% endtrans %} + <b>{{ thread.get_close_reason_display() }}</b> {% trans %}by{% endtrans %} + {% trans close_reason=thread.get_close_reason_display() %}Closed for the following reason <b>"{{ close_reason }}"</b> <i>by{% endtrans %} + <a href="{{ thread.closed_by.get_profile_url() }}">{{ thread.closed_by.username|escape }}</a> </i><br> + {% trans closed_at=thread.closed_at %}close date {{closed_at}}{% endtrans %}</h3> </div> diff --git a/askbot/templates/question/content.html b/askbot/templates/question/content.html index 6a73ebef..50bfee55 100644 --- a/askbot/templates/question/content.html +++ b/askbot/templates/question/content.html @@ -35,8 +35,8 @@ <a class="button submit" href="{% url "edit_answer" previous_answer.id %}" - >{% trans %}Edit Your Previous Answer{% endtrans %}</a> - <span>{% trans %}(only one answer per user is allowed){% endtrans %}</span> + >{{ settings.WORDS_EDIT_YOUR_PREVIOUS_ANSWER|escape }}</a> + <span>{{ settings.WORDS_ONLY_ONE_ANSWER_PER_USER_IS_ALLOWED|escape }}</span> <div class="invisible"> {# hidden because we still need js from the tinymce widget #} {% include "question/new_answer_form.html" %} @@ -48,6 +48,6 @@ type="button" class="submit after-editor answer-own-question" id="fmanswer_button" - value="{% trans %}Answer Your Own Question{% endtrans %}" + value="{{ settings.WORDS_ANSWER_YOUR_OWN_QUESTION|escape }}" /> {% endif %} diff --git a/askbot/templates/question/new_answer_form.html b/askbot/templates/question/new_answer_form.html index 473a4bc2..f8b4cd46 100644 --- a/askbot/templates/question/new_answer_form.html +++ b/askbot/templates/question/new_answer_form.html @@ -9,34 +9,31 @@ <a class="button submit" href="{{settings.LOGIN_URL}}?next={% url question question.id %}" - >{% trans %}Login/Signup to Answer{% endtrans %}</a> + >{{ settings.WORDS_LOGIN_SIGNUP_TO_ANSWER|escape }}</a> {% endif %} {% else %} - {% if not thread.closed %} + {% if not thread.closed and settings.READ_ONLY_MODE_ENABLED == False %} <div> {% spaceless %} <h2> {% if answers %} - {% trans %}Your answer{% endtrans %} + {{ settings.WORDS_YOUR_ANSWER|escape }} {% else %} - {% trans %}Be the first one to answer this question!{% endtrans %} + {{ settings.WORDS_BE_THE_FIRST_TO_ANSWER_THIS_QUESTION|escape }} {% endif %} </h2> {% endspaceless %} </div> + <p class="message"> {% if request.user.is_anonymous() %} - <div class="message">{% trans %}<span class='strong big'>Please start posting your answer anonymously</span> - your answer will be saved within the current session and published after you log in or create a new account. Please try to give a <strong>substantial answer</strong>, for discussions, <strong>please use comments</strong> and <strong>please do remember to vote</strong> (after you log in)!{% endtrans %}</div> - {% else %} - <p class="message"> - {% if request.user==question.author %} - {% trans %}<span class='big strong'>You are welcome to answer your own question</span>, but please make sure to give an <strong>answer</strong>. Remember that you can always <strong>revise your original question</strong>. Please <strong>use comments for discussions</strong> and <strong>please don't forget to vote :)</strong> for the answers that you liked (or perhaps did not like)!{% endtrans %} - {% else %} - {% trans %}<span class='big strong'>Please try to give a substantial answer</span>. If you wanted to comment on the question or answer, just <strong>use the commenting tool</strong>. Please remember that you can always <strong>revise your answers</strong> - no need to answer the same question twice. Also, please <strong>don't forget to vote</strong> - it really helps to select the best questions and answers!{% endtrans %} - {% endif %} - </p> + {{ settings.WORDS_INSTRUCTION_TO_POST_ANONYMOUSLY }} + {% elif request.user==question.author %} + {{ settings.WORDS_INSTRUCTION_TO_ANSWER_OWN_QUESTION }} {% endif %} + {{ settings.WORDS_INSTRUCTION_TO_GIVE_ANSWER }} + </p> <div class="folded-editor{% if editor_is_unfolded %}unfolded{% endif %}" tabindex="6"> - <p class="prompt"><a>{% trans %}Add answer{% endtrans %}</a></p> + <p class="prompt"><a>{{ settings.WORDS_ADD_ANSWER|escape }}</a></p> <div class="editor-proper"> {{ macros.edit_post( answer, diff --git a/askbot/templates/question/sidebar.html b/askbot/templates/question/sidebar.html index c4301b6c..0894b935 100644 --- a/askbot/templates/question/sidebar.html +++ b/askbot/templates/question/sidebar.html @@ -5,16 +5,16 @@ </div> {% endif %} <div class="box vote-buttons"> - <h2 >{% trans %}Question tools{% endtrans %}</h2> + <h2>{{ settings.WORDS_QUESTION_TOOLS|escape }}</h2> {% if favorited %} <a class="button followed" - alt="{% trans %}click to unfollow this question{% endtrans %}"> + alt="{% trans %}click to unfollow {% endtrans %}"> <div>{% trans %}Following{% endtrans %}</div> <div class='unfollow'>{% trans %}Unfollow{% endtrans %}</div> </a> {% else %} <a class="button followed" - alt="{% trans %}click to follow this question{% endtrans %}"> + alt="{% trans %}click to follow {% endtrans %}"> {%trans %}Follow{%endtrans%} </a> {% endif %} @@ -30,7 +30,7 @@ <p class="rss"> <a href="{{ base_url }}/feeds/question/{{ question.id }}" - title="{% trans %}subscribe to this question rss feed{% endtrans %}" + title="{% trans %}subscribe to the rss feed{% endtrans %}" >{% trans %}subscribe to rss feed{% endtrans %}</a> </p> {% endif %} @@ -42,8 +42,7 @@ <div class="box sharing-widget"> {% if thread.is_private() %} <h2>{% trans %}Invite{% endtrans %}</h2> - <p style="margin: 16px 0" - >Invite others to help answer this question</p> + <p style="margin: 16px 0">{{ settings.WORDS_INVITE_OTHERS_TO_HELP_ANSWER_THIS_QUESTION|escape }}</p> <form action="{% url share_question_with_user %}" method="post">{% csrf_token %} <input id="share_user_name" type="text" class="groups-input" name="recipient_name" /> <input type="hidden" name="thread_id" value="{{ thread.id }}"/> @@ -78,7 +77,7 @@ {% if shared_users_count or shared_groups_count %} <p style="margin:16px 0 4px 0" - >{% trans %}This question is currently shared only with:{% endtrans %}</p> + >{{ settings.WORDS_THIS_QUESTION_IS_CURRENTLY_SHARED_ONLY_WITH|escape }}</p> {% endif %} <h3>{% trans %}Individual users{% endtrans %}</h3> {% set comma = joiner(',') %} @@ -148,7 +147,7 @@ {% if similar_threads.data() and settings.SIDEBAR_QUESTION_SHOW_RELATED %} {#% cache 1800 "related_questions" related_questions question.id language_code %#} <div class="box"> - <h2>{% trans %}Related questions{% endtrans %}</h2> + <h2>{{ settings.WORDS_RELATED_QUESTIONS|escape }}</h2> <div class="questions-related"> {% for thread_dict in similar_threads.data() %} <p> diff --git a/askbot/templates/question_edit.html b/askbot/templates/question_edit.html index 1b119f93..e31050ec 100644 --- a/askbot/templates/question_edit.html +++ b/askbot/templates/question_edit.html @@ -1,19 +1,19 @@ {% extends "two_column_body.html" %} {% import "macros.html" as macros %} <!-- question_edit.html --> -{% block title %}{% spaceless %}{% trans %}Edit question{% endtrans %}{% endspaceless %}{% endblock %} +{% block title %}{% spaceless %}{{ settings.WORDS_EDIT_QUESTION|escape }}{% endspaceless %}{% endblock %} {% block forestyle %} <link rel="stylesheet" type="text/css" href="{{"/js/wmd/wmd.css"|media}}" /> {% endblock %} {% block content %} -<div class="section-title">{% trans %}Edit question{% endtrans %} [<a href="{{ question.get_absolute_url() }}">{% trans %}back{% endtrans %}</a>]</div> +<div class="section-title">{{ settings.WORDS_EDIT_QUESTION|escape }} [<a href="{{ question.get_absolute_url() }}">{% trans %}back{% endtrans %}</a>]</div> <form id="fmedit" action="{% url edit_question question.id %}" method="post" >{% csrf_token %} {% if revision_form.revision.errors %}{{ revision_form.revision.errors.as_ul() }}{% endif %} {{ revision_form.revision }} <input type="hidden" id="select_revision" name="select_revision" value="false"/> <div class="form-item"> <label for="id_title" > - {% trans %}Question - in one sentence{% endtrans %} + {{ settings.WORDS_QUESTION_IN_ONE_SENTENCE|escape }} {% if form.title.errors %} {{ form.title.errors }} {% endif %} @@ -66,7 +66,13 @@ {% endblock %} {% block sidebar %} -{% include "widgets/question_edit_tips.html" %} +<div id ="tips" class="box"> + <h2>{% trans %}Tips{% endtrans %}</h2> + {% include "widgets/question_edit_tips.html" %} +</div> +{% if settings.EDITOR_TYPE == 'markdown' %} + {% include "/widgets/markdown_help.html" %} +{% endif %} {% endblock %} {% block endjs %} diff --git a/askbot/templates/question_retag.html b/askbot/templates/question_retag.html index c42b42f8..e1341f7a 100644 --- a/askbot/templates/question_retag.html +++ b/askbot/templates/question_retag.html @@ -1,8 +1,8 @@ {% extends "two_column_body.html" %} <!-- question_retag.html --> -{% block title %}{% spaceless %}{% trans %}Retag question{% endtrans %}{% endspaceless %}{% endblock %} +{% block title %}{% spaceless %}{{ settings.WORDS_RETAG_QUESTION|escape }}{% endspaceless %}{% endblock %} {% block content %} -<h1>{% trans %}Retag question{% endtrans %} [<a href="{{ question.get_absolute_url() }}">{% trans %}back{% endtrans %}</a>]</h1> +<h1>{{ settings.WORDS_RETAG_QUESTION|escape }} [<a href="{{ question.get_absolute_url() }}">{% trans %}back{% endtrans %}</a>]</h1> <form id="fmretag" action="{% url retag_question question.id %}" method="post" >{% csrf_token %} <h2> {{ question.thread.get_title()|escape }} diff --git a/askbot/templates/reopen.html b/askbot/templates/reopen.html index 4ddd6f31..9c617403 100644 --- a/askbot/templates/reopen.html +++ b/askbot/templates/reopen.html @@ -1,15 +1,15 @@ {% extends "two_column_body.html" %} {% from "macros.html" import timeago %} <!-- reopen.html --> -{% block title %}{% spaceless %}{% trans %}Reopen question{% endtrans %}{% endspaceless %}{% endblock %} +{% block title %}{{ settings.WORDS_REOPEN_QUESTION|escape }}{% endblock %} {% block content %} -<h1>{% trans %}Reopen question{% endtrans %}</h1> +<h1>{{ settings.WORDS_REOPEN_QUESTION|escape }}</h1> <p>{% trans %}Title{% endtrans %}: <a href="{{ question.get_absolute_url() }}"> <span class="big">{{ question.get_question_title()|escape }}</span> </a> </p> -<p>{% trans username = closed_by_username|escape %}This question has been closed by +<p>{% trans username = closed_by_username|escape %}Closed by: <a href="{{closed_by_profile_url}}">{{username}}</a> {% endtrans %} </p> @@ -19,12 +19,10 @@ <p> {% trans %}When:{% endtrans %} {{ timeago(question.thread.closed_at) }} </p> -<p> - {% trans %}Reopen this question?{% endtrans %} -</p> +<p>{{ settings.WORDS_REOPEN_QUESTION|escape }}?</p> <form id="fmclose" action="{% url reopen question.id %}" method="post" >{% csrf_token %} <div id="" style="padding:20px 0 20px 0"> - <input type="submit" value="{% trans %}Reopen this question{% endtrans %}" class="submit" /> + <input type="submit" value="{{ settings.WORDS_REOPEN_QUESTION|escape }}" class="submit" /> <input id="btBack" type="button" value="{% trans %}Cancel{% endtrans %}" class="submit" /> </div> </form> diff --git a/askbot/templates/revisions.html b/askbot/templates/revisions.html index 1765b728..1617ff25 100644 --- a/askbot/templates/revisions.html +++ b/askbot/templates/revisions.html @@ -53,7 +53,7 @@ revision, contributor_type, False, - 0 + 0, ) }} </div> diff --git a/askbot/templates/search/indexes/auth/user_text.txt b/askbot/templates/search/indexes/auth/user_text.txt index b0baa3a6..e2b4ecd8 100644 --- a/askbot/templates/search/indexes/auth/user_text.txt +++ b/askbot/templates/search/indexes/auth/user_text.txt @@ -3,3 +3,5 @@ {{ object.last_name }} {{ object.email }} {{ object.full_name }} +{{ object.about }} +{{ object.location }} diff --git a/askbot/templates/user_profile/user_answers_list.html b/askbot/templates/user_profile/user_answers_list.html index 4f0c2ff2..0215ee54 100644 --- a/askbot/templates/user_profile/user_answers_list.html +++ b/askbot/templates/user_profile/user_answers_list.html @@ -1,8 +1,7 @@ {% for top_answer in top_answers %} <div class="answer-summary"> <a href="{{ top_answer.get_absolute_url() }}"> - <span class="answer-votes {% if top_answer.accepted() %}answered-accepted{% endif %}" - title="{% trans answer_score=top_answer.score %}the answer has been voted for {{ answer_score }} times{% endtrans %} {% if top_answer.accepted() %}{% trans %}this answer has been selected as correct{% endtrans %}{%endif%}"> + <span class="answer-votes {% if top_answer.accepted() %}answered-accepted{% endif %}"> {{ top_answer.score }} </span> </a> @@ -10,11 +9,6 @@ {% spaceless %} <a href="{% url question top_answer.thread._question_post().id %}{{ top_answer.thread.title|slugify }}#{{top_answer.id}}">{{ top_answer.thread.title|escape }}</a> {% endspaceless %} - {% if top_answer.comment_count > 0 %} - <span> - {% trans comment_count=top_answer.comment_count %}({{ comment_count }} comment){% pluralize %}the answer has been commented {{ comment_count }} times{% endtrans %} - </span> - {% endif %} </div> </div> {% endfor %} diff --git a/askbot/templates/user_profile/user_email_subscriptions.html b/askbot/templates/user_profile/user_email_subscriptions.html index 4692456b..fdda03b7 100644 --- a/askbot/templates/user_profile/user_email_subscriptions.html +++ b/askbot/templates/user_profile/user_email_subscriptions.html @@ -7,7 +7,7 @@ {% block usercontent %} <h2>{% trans %}Email subscription settings{% endtrans %}</h2> <p class="message"> -{% trans %}<span class='big strong'>Adjust frequency of email updates.</span> Receive updates on interesting questions by email, <strong><br/>help the community</strong> by answering questions of your colleagues. If you do not wish to receive emails - select 'no email' on all items below.<br/>Updates are only sent when there is any new activity on selected items.{% endtrans %}</p> +{% trans %}<span class='big strong'>Adjust frequency of email updates.</span> Receive updates on interesting content by email. If you do not wish to receive emails - select 'no email' on all items below.<br/>Updates are only sent when there is any new activity on selected items.{% endtrans %}</p> <div> {% if action_status %} <p class="action-status"><span>{{action_status}}</span></p> diff --git a/askbot/templates/user_profile/user_favorites.html b/askbot/templates/user_profile/user_favorites.html index ffdcbd0d..e94015de 100644 --- a/askbot/templates/user_profile/user_favorites.html +++ b/askbot/templates/user_profile/user_favorites.html @@ -1,8 +1,6 @@ {% extends "user_profile/user.html" %} <!-- user_favorites.html --> -{% block profilesection %} - {% trans %}followed questions{% endtrans %} -{% endblock %} +{% block profilesection %}{{ settings.WORDS_FOLLOWED_QUESTIONS|escape }}{% endblock %} {% block usercontent %} {% include "user_profile/users_questions.html" %} {% endblock %} diff --git a/askbot/templates/user_profile/user_info.html b/askbot/templates/user_profile/user_info.html index 9786d4ec..93f1660f 100644 --- a/askbot/templates/user_profile/user_info.html +++ b/askbot/templates/user_profile/user_info.html @@ -52,7 +52,13 @@ {% if view_user.real_name %} <tr> <td>{% trans %}real name{% endtrans %}</td> - <td><b>{{view_user.real_name}}</b></td> + <td><b>{{view_user.real_name|escape}}</b></td> + </tr> + {% endif %} + {% if request.user|can_see_private_user_data(view_user) %} + <tr> + <td>{% trans %}email{% endtrans %}</td> + <td>{{view_user.email}}</td> </tr> {% endif %} {% if settings.GROUPS_ENABLED %} diff --git a/askbot/templates/user_profile/user_stats.html b/askbot/templates/user_profile/user_stats.html index f62a57e7..7bb97d88 100644 --- a/askbot/templates/user_profile/user_stats.html +++ b/askbot/templates/user_profile/user_stats.html @@ -9,12 +9,18 @@ {% include "user_profile/user_info.html" %} <a name="questions"></a> {% spaceless %} - <h2>{% trans counter=question_count %}<span class="count">{{counter}}</span> Question{% pluralize %}<span class="count">{{counter}}</span> Questions{% endtrans %}</h2> + <h2> + <span class="count">{{ question_count }}</span> + {{ settings.WORDS_QUESTIONS_COUNTABLE_FORMS|py_pluralize(question_count)|capitalize }} + </h2> {% endspaceless %} {% include "user_profile/users_questions.html" %} <a name="answers"></a> {% spaceless %} - <h2 style="clear:both;"><span class="count">{{ top_answer_count }}</span> {% trans counter=top_answer_count %}Answer{% pluralize %}Answers{% endtrans %}</h2> + <h2 style="clear:both;"> + <span class="count">{{ top_answer_count }}</span> + {{ settings.WORDS_ANSWERS_COUNTABLE_FORMS|py_pluralize(top_answer_count)|capitalize }} + </h2> {% endspaceless %} {% include "user_profile/users_answers.html" %} <a name="votes"></a> @@ -79,7 +85,6 @@ {% if award.content_object and award.content_object_is_post %} <li> <a - title="{{ award.content_object.get_snippet()|collapse }}" href="{{ award.content_object.get_absolute_url() }}" >{% if award.content_type.post_type == 'answer' %}{% trans %}Answer to:{% endtrans %}{% endif %} {{ award.content_object.thread.title|escape }}</a> </li> diff --git a/askbot/templates/user_profile/user_tabs.html b/askbot/templates/user_profile/user_tabs.html index c7df4187..0abb89f7 100644 --- a/askbot/templates/user_profile/user_tabs.html +++ b/askbot/templates/user_profile/user_tabs.html @@ -2,50 +2,41 @@ <div class="tabBar tabBar-profile"> <div class="tabsC"> <a id="stats" {% if tab_name=="stats" %}class="on first"{%else%}class="first"{% endif %} - title="{% trans %}User profile{% endtrans %}" href="{% url user_profile view_user.id, view_user.username|slugify %}?sort=stats" ><span>{% trans %}overview{% endtrans %}</span></a> {% if request.user == view_user or request.user|can_moderate_user(view_user) %} <a id="inbox" {% if tab_name=="inbox" %}class="on"{% endif %} - title="{% trans %}comments and answers to others questions{% endtrans %}" href="{% url user_profile view_user.id, view_user.username|slugify %}?sort=inbox" ><span>{% trans %}inbox{% endtrans %}</span></a> {% endif %} {% if user_follow_feature_on %} <a id="network" {% if tab_name=="network" %}class="on"{% endif %} - title="{% trans %}followers and followed users{% endtrans %}" href="{% url user_profile view_user.id, view_user.username|slugify %}?sort=network" ><span>{% trans %}network{% endtrans %}</span></a> {% endif %} {% if can_show_karma %} <a id="reputation" {% if tab_name=="reputation" %}class="on"{% endif %} - title="{% trans %}Graph of user karma{% endtrans %}" href="{% url user_profile view_user.id, view_user.username|slugify %}?sort=reputation" ><span>{% trans %}karma{% endtrans %}</span></a> {% endif %} <a id="favorites" {% if tab_name=="favorites" %}class="on"{% endif %} - title="{% trans %}questions that user is following{% endtrans %}" href="{% url user_profile view_user.id, view_user.username|slugify %}?sort=favorites" - ><span>{% trans %}followed questions{% endtrans %}</span></a> + ><span>{{ settings.WORDS_FOLLOWED_QUESTIONS|escape }}</span></a> <a id="recent" {% if tab_name=="recent" %}class="on"{% endif %} - title="{% trans %}activity{% endtrans %}" href="{% url user_profile view_user.id, view_user.username|slugify %}?sort=recent" ><span>{% trans %}activity{% endtrans %}</span></a> {% if request.user == view_user or request.user|can_moderate_user(view_user) %} <a id="votes" {% if tab_name=="votes" %}class="on"{% endif %} - title="{% trans %}user vote record{% endtrans %}" href="{% url user_profile view_user.id, view_user.username|slugify %}?sort=votes" ><span>{% trans %}votes{% endtrans %}</span></a> {% endif %} {% if request.user == view_user or request.user|can_moderate_user(view_user) %} <a id="email_subscriptions" {% if tab_name=="email_subscriptions" %}class="on"{% endif %} - title="{% trans %}email subscription settings{% endtrans %}" href="{% url user_profile view_user.id, view_user.username|slugify %}?sort=email_subscriptions" ><span>{% trans %}subscriptions{% endtrans %}</span></a> {% endif %} {% if request.user|can_moderate_user(view_user) %} <a id="moderation" {% if tab_name=="moderation" %}class="on"{% endif %} - title="{% trans %}moderate this user{% endtrans %}" href="{% url user_profile view_user.id, view_user.username|slugify %}?sort=moderation" ><span>{% trans %}moderation{% endtrans %}</span></a> {% endif %} diff --git a/askbot/templates/widgets/answer_edit_tips.html b/askbot/templates/widgets/answer_edit_tips.html index 2bb5b256..fdcd27b4 100644 --- a/askbot/templates/widgets/answer_edit_tips.html +++ b/askbot/templates/widgets/answer_edit_tips.html @@ -3,23 +3,11 @@ <h2>{% trans %}Tips{% endtrans %}</h2> <div id="tips"> <ul > - <li> <b>{% trans %}give an answer interesting to this community{% endtrans %}</b> - </li> - <li> - {% trans %}try to give an answer, rather than engage into a discussion{% endtrans %} - </li> - <li> - {% trans %}provide enough details{% endtrans %} - </li> - <li> - {% trans %}be clear and concise{% endtrans %} - </li> + <li>{{ settings.WORDS_GIVE_AN_ANSWER_INTERESTING_TO_THIS_COMMUNITY|escape }}</li> + <li>{{ settings.WORDS_TRY_TO_GIVE_AN_ANSWER|escape }}</li> + <li>{% trans %}provide enough details{% endtrans %}</li> + <li>{% trans %}be clear and concise{% endtrans %}</li> </ul> - <p class='info-box-follow-up-links'> -<!-- will be change to a popup windows - <a href="{% url faq %}" target="_blank" title="{% trans %}see frequently asked questions{% endtrans %}">{% trans %}FAQ{% endtrans %} »</a> ---> - </p> </div> </div> {% if settings.EDITOR_TYPE == 'markdown' %} diff --git a/askbot/templates/widgets/ask_button.html b/askbot/templates/widgets/ask_button.html index f8ea82bd..5d969a00 100644 --- a/askbot/templates/widgets/ask_button.html +++ b/askbot/templates/widgets/ask_button.html @@ -5,6 +5,10 @@ <a id="askButton" class="button" - href="{{ search_state.full_ask_url() }}{% if group %}{% if '?' in search_state.full_ask_url() %}&{% else %}?{% endif %}group_id={{ group.id }}{% endif %}" - >{% if group %}{% trans %}Ask the Group{% endtrans %}{% else %}{% trans %}Ask Your Question{% endtrans %}{% endif %}</a> + href="{{ search_state.full_ask_url() }}{% if group %}{% if '?' in search_state.full_ask_url() %}&{% else %}?{% endif %}group_id={{ group.id }}{% endif %}" + >{% if group %} + {{ settings.WORDS_ASK_THE_GROUP|escape }} + {% else %} + {{ settings.WORDS_ASK_YOUR_QUESTION|escape }} + {% endif %}</a> {% endif %} diff --git a/askbot/templates/widgets/ask_form.html b/askbot/templates/widgets/ask_form.html index 1d2642c7..df37ba3c 100644 --- a/askbot/templates/widgets/ask_form.html +++ b/askbot/templates/widgets/ask_form.html @@ -64,7 +64,7 @@ {% if not request.user.is_authenticated() %} <input type="submit" name="post_anon" value="{% trans %}Login/Signup to Post{% endtrans %}" class="submit" /> {% else %} - <input type="submit" name="post" value="{% trans %}Ask Your Question{% endtrans %}" class="submit" /> + <input type="submit" name="post" value="{{ settings.WORDS_ASK_YOUR_QUESTION|escape }}" class="submit" /> {% endif %} <div class="clean"></div> </form> diff --git a/askbot/templates/widgets/group_info.html b/askbot/templates/widgets/group_info.html index 6a6b788d..05fcff9b 100644 --- a/askbot/templates/widgets/group_info.html +++ b/askbot/templates/widgets/group_info.html @@ -43,7 +43,7 @@ data-toggle-url="{% url toggle_group_profile_property %}" /> <label for="moderate-email"> - {% trans %}moderate emailed questions{% endtrans %} + {% trans %}moderate emailed content{% endtrans %} </label> <br/> {% endif %} @@ -55,7 +55,7 @@ data-toggle-url="{% url toggle_group_profile_property %}" /> <label for="moderate-answers-to-enquirers"> - {% trans %}show only selected answers to enquirers{% endtrans %} + {{ settings.WORDS_SHOW_ONLY_SELECTED_ANSWERS_TO_ENQUIRERS|escape }} </label> <br/> @@ -99,7 +99,6 @@ <br/> <a id="preapproved-emails" - title="{% trans %}list of email addresses of pre-approved users{% endtrans %}" data-object-id="{{group.group_ptr_id}}" data-model-name="Group" data-property-name="preapproved_emails" @@ -110,7 +109,6 @@ <br/> <a id="preapproved-email-domains" - title="{% trans %}list of preapproved email address domain names{% endtrans %}" data-object-id="{{group.group_ptr_id}}" data-model-name="Group" data-property-name="preapproved_email_domains" diff --git a/askbot/templates/widgets/header.html b/askbot/templates/widgets/header.html index 52e528bc..50a25564 100644 --- a/askbot/templates/widgets/header.html +++ b/askbot/templates/widgets/header.html @@ -16,5 +16,10 @@ </div> <div class="clean"></div> </div> + {% if settings.READ_ONLY_MODE_ENABLED %} + <div class="content-wrapper system-messages"> + {{ settings.READ_ONLY_MESSAGE }} + </div> + {% endif %} </div> <!-- end template header.html --> diff --git a/askbot/templates/widgets/question_edit_tips.html b/askbot/templates/widgets/question_edit_tips.html index f60304c1..636bd38d 100644 --- a/askbot/templates/widgets/question_edit_tips.html +++ b/askbot/templates/widgets/question_edit_tips.html @@ -1,22 +1,19 @@ <!-- question_edit_tips.html --> -<div id ="tips" class="box"> - <h2>{% trans %}Tips{% endtrans %}</h2> +{% if settings.QUESTION_INSTRUCTIONS %} + {{ settings.QUESTION_INSTRUCTIONS|safe }} +{% else %} <ul> - <li> <b>{% trans %}ask a question interesting to this community{% endtrans %}</b> - </li> - <li> - {% trans %}provide enough details{% endtrans %} - </li> - <li> - {% trans %}be clear and concise{% endtrans %} - </li> + {% if not request.user.is_authenticated() %} + <li class="warning">{% trans %}since you are not logged in right now, you will be asked to sign in or register after making your post{% endtrans %}</li> + {% else %} + {% if settings.EMAIL_VALIDATION %} + {% if not request.user.email_isvalid %} + <li class="warning">{% trans email=request.user.email %}Your email, {{ email }} has not yet been validated. To post messages you must verify your email, please see <a href='{{ email_validation_faq_url }}'>more details here</a>. You can submit your post now and validate email after that.{% endtrans %}</li> + {% endif %} + {% endif %} + {% endif %} + <li>{{ settings.WORDS_ASK_A_QUESTION_INTERESTING_TO_THIS_COMMUNITY|escape }}</li> + <li>{% trans %}provide enough details{% endtrans %}</li> + <li>{% trans %}be clear and concise{% endtrans %}</li> </ul> - <p class='info-box-follow-up-links'> -<!-- will be change to a popup windows - <a href="{% url faq %}" target="_blank" title="{% trans %}see frequently asked questions{% endtrans %}">{% trans %}FAQ{% endtrans %} »</a> ---> - </p> -</div> -{% if settings.EDITOR_TYPE == 'markdown' %} - {% include "/widgets/markdown_help.html" %} {% endif %} diff --git a/askbot/templates/widgets/question_summary.html b/askbot/templates/widgets/question_summary.html index 306bd672..9b1168b9 100644 --- a/askbot/templates/widgets/question_summary.html +++ b/askbot/templates/widgets/question_summary.html @@ -27,7 +27,7 @@ class="item-count" >{{ answer_count|humanize_counter }}{% if thread.accepted_answer_id %}{% endif %}</span> <div> - {% trans cnt = answer_count %}answer{% pluralize %}answers{% endtrans %} + {{ settings.WORDS_ANSWERS_COUNTABLE_FORMS|py_pluralize(answer_count) }} </div> </div> <div class="votes @@ -44,13 +44,14 @@ <div style="clear:both"></div> <div class="userinfo"> {{ timeago(thread.last_activity_at) }} - {% if question.is_anonymous %} + {% if question.is_anonymous %}{# todo: here we need to look at the anonymity of the last edit instead #} <span class="anonymous">{{ thread.last_activity_by.get_anonymous_name() }}</span> {% else %} <a href="{% url user_profile thread.last_activity_by.id, thread.last_activity_by.username|slugify %}">{{thread.last_activity_by.username|escape}}</a> {{ user_country_flag(thread.last_activity_by) }} + {% if thread.last_activity_by.get_primary_group() %} + - {{ user_primary_group(thread.last_activity_by) }} + {% endif %} {% endif %} - {% if thread.last_activity_by.get_primary_group() %}-{% endif %} - {{ user_primary_group(thread.last_activity_by) }} </div> </div> <h2><a href="{{ question.get_absolute_url(thread=thread) }}">{{thread.get_title(question)|escape}}</a></h2> diff --git a/askbot/templates/widgets/scope_nav.html b/askbot/templates/widgets/scope_nav.html index 254c3b48..155667ac 100644 --- a/askbot/templates/widgets/scope_nav.html +++ b/askbot/templates/widgets/scope_nav.html @@ -14,20 +14,20 @@ {% if settings.ALL_SCOPE_ENABLED %} <a class="scope-selector {% if scope == 'all' %}on{% endif %}" href="{{ search_state.change_scope('all').full_url() }}" - title="{% trans %}see all questions{% endtrans %}">{% trans %}ALL{% endtrans %}</a> + >{% trans %}ALL{% endtrans %}</a> {% endif %} {% if settings.UNANSWERED_SCOPE_ENABLED %} <a class="scope-selector {% if scope == 'unanswered' %}on{% endif %}" href="{{ search_state.change_scope('unanswered').change_sort('answers-asc').full_url() }}" - title="{% trans %}see unanswered questions{% endtrans %}">{% trans %}UNANSWERED{% endtrans %}</a> + >{{ settings.WORDS_UNANSWERED|escape }}</a> {% endif %} {% if request.user.is_authenticated() and settings.FOLLOWED_SCOPE_ENABLED %} <a class="scope-selector {% if scope == 'followed' %}on{% endif %}" href="{{ search_state.change_scope('followed').full_url() }}" - title="{% trans %}see your followed questions{% endtrans %}">{% trans %}FOLLOWED{% endtrans %}</a> + >{% trans %}FOLLOWED{% endtrans %}</a> {% endif %} {% else %} - <div class="scope-selector ask-message">{% trans %}Please ask your question here{% endtrans %}</div> + <div class="scope-selector ask-message">{{ settings.WORDS_PLEASE_ASK_YOUR_QUESTION_HERE|escape }}</div> {% endif %} {% endif %} </div> diff --git a/askbot/templates/widgets/secondary_header.html b/askbot/templates/widgets/secondary_header.html index 69e5742c..92f34cff 100644 --- a/askbot/templates/widgets/secondary_header.html +++ b/askbot/templates/widgets/secondary_header.html @@ -19,28 +19,27 @@ {% endif %} class="{{ enabled_scopes_class }}" method="get"> - <div> - {# - Some or all contents of this div may be dropped - over the search bar via negative margins, - to make sure that the search bar can occupy 100% - of the content width. - Search bar may have padding on the left and right - to accomodate the buttons. - #} - <a id="homeButton" href="{% url questions %}"></a> - {% include "widgets/scope_nav.html" %} - {# - three buttons below are in the opposite order because - they are floated at the right - #} - {% if settings.ASK_BUTTON_ENABLED %} - {% include "widgets/ask_button.html" %} - {% endif %} - {# clears button floats #} - <div class="clearfix"></div> - </div> - {% include "widgets/search_bar.html" %} {# include search form widget #} + {# + A single row table to help the semi-fixed width layout where: + * all cells have "tight width" without linebreaks + * except that the search bar cell takes the remaining width + We had hard time making this layout work without tables. + Please suggest if there is a better way. + #} + <table width="100%"> + <tr> + {# width 1 means that cell will expand just enough to fit the contents #} + <td width="1"><a id="homeButton" href="{% url questions %}"></a></td> + <td width="1">{% include "widgets/scope_nav.html" %}</td> + {# width * means that the cell takes the remaining table width #} + <td width="*" class="search-bar">{% include "widgets/search_bar.html" %}</td> + {% if settings.ASK_BUTTON_ENABLED %} + <td width="1"> + {% include "widgets/ask_button.html" %} + </td> + {% endif %} + </tr> + </table> </form> </div> </div> diff --git a/askbot/templates/widgets/system_messages.html b/askbot/templates/widgets/system_messages.html index 10ba4a84..69f6672f 100644 --- a/askbot/templates/widgets/system_messages.html +++ b/askbot/templates/widgets/system_messages.html @@ -1,8 +1,10 @@ <div class="notify" style="display:none"> - {% if user_messages %} - {% for message in user_messages %} - <p class="notification">{{ message }}</p> - {% endfor %} - {% endif %} - <a id="closeNotify" onclick="notify.close(true)"></a> + <div class="content-wrapper"> + {% if user_messages %} + {% for message in user_messages %} + <p class="notification">{{ message }}</p> + {% endfor %} + {% endif %} + <a id="closeNotify" onclick="notify.close(true)"></a> + </div> </div> diff --git a/askbot/templates/widgets/tag_selector.html b/askbot/templates/widgets/tag_selector.html index ba304d2c..720de4a1 100644 --- a/askbot/templates/widgets/tag_selector.html +++ b/askbot/templates/widgets/tag_selector.html @@ -56,7 +56,7 @@ <input id="subscribedTagAdd" type="submit" value="{% trans %}add{% endtrans%}"/> </div> {% endif %} - <h3>{% trans %}Show only questions from{% endtrans%}</h3> + <h3>{{ settings.WORDS_SHOW_ONLY_QUESTIONS_FROM|escape }}</h3> <div id="displayTagFilterControl"> {{ macros.radio_select( diff --git a/askbot/templates/widgets/three_column_category_selector.html b/askbot/templates/widgets/three_column_category_selector.html index ab0886c6..c6e10460 100644 --- a/askbot/templates/widgets/three_column_category_selector.html +++ b/askbot/templates/widgets/three_column_category_selector.html @@ -1,7 +1,7 @@ {# just a skeleton for the category selector - filled by js #} <table class="category-selector"> <thead> - <th colspan="3">{% trans %}Categorize your question using this tag selector or entering text in tag box.{% endtrans %} + <th colspan="3">{{ settings.WORDS_INSTRUCTION_FOR_THE_CATEGORY_SELECTOR|escape }} <a style="display:none;" class='category-editor-toggle' data-on-state-text='{% trans %}(done editing){% endtrans %}' diff --git a/askbot/templates/widgets/user_perms.html b/askbot/templates/widgets/user_perms.html index 887a712f..33109140 100644 --- a/askbot/templates/widgets/user_perms.html +++ b/askbot/templates/widgets/user_perms.html @@ -18,7 +18,7 @@ {% if not user.is_administrator_or_moderator() %} <p> {% trans %}Currently, you can:{% endtrans %}</p> <ul> - <li>{% trans %}Post questions, answers and comments{% endtrans %}</li> + <li>{% trans %}Make new posts{% endtrans %}</li> {% for perm in perms_data %} {% if user.reputation >= perm[1] %} <li>{{ perm[0] }}</li> diff --git a/askbot/templatetags/extra_filters_jinja.py b/askbot/templatetags/extra_filters_jinja.py index 8a1c4b8e..0d7ab0c8 100644 --- a/askbot/templatetags/extra_filters_jinja.py +++ b/askbot/templatetags/extra_filters_jinja.py @@ -23,6 +23,7 @@ from askbot.utils.html import site_url as site_url_func from askbot.utils import functions from askbot.utils import url_utils from askbot.utils.slug import slugify +from askbot.utils.pluralization import py_pluralize as _py_pluralize from askbot.shims.django_shims import ResolverMatch from django_countries import countries @@ -94,6 +95,13 @@ def strip_path(url): return url_utils.strip_path(url) @register.filter +def can_see_private_user_data(viewer, target): + if viewer.is_authenticated() and viewer.is_administrator_or_moderator(): + #todo: take into account intersection of viewer and target user groups + return askbot_settings.SHOW_ADMINS_PRIVATE_USER_DATA + return False + +@register.filter def clean_login_url(url): """pass through, unless user was originally on the logout page""" try: @@ -350,6 +358,10 @@ def humanize_counter(number): else: return str(number) +@register.filter +def py_pluralize(source, count): + plural_forms = source.strip().split('\n') + return _py_pluralize(plural_forms, count) @register.filter def absolute_value(number): diff --git a/askbot/tests/db_api_tests.py b/askbot/tests/db_api_tests.py index 6b08fb65..3e19a1c2 100644 --- a/askbot/tests/db_api_tests.py +++ b/askbot/tests/db_api_tests.py @@ -199,10 +199,10 @@ class DBApiTests(AskbotTestCase): def test_retag_tags_too_long_raises(self): tags = "aoaoesuouooeueooeuoaeuoeou aostoeuoaethoeastn oasoeoa nuhoasut oaeeots aoshootuheotuoehao asaoetoeatuoasu o aoeuethut aoaoe uou uoetu uouuou ao aouosutoeh" question = self.post_question(user=self.user) - self.assertRaises( - exceptions.ValidationError, - self.user.retag_question, - question=question, tags=tags + self.user.retag_question(question=question, tags=tags) + self.assertEqual( + set(question.thread.tagnames.split()), + set('aoaoesuouooeueooeuoaeuoeou aostoeuoaethoeastn oasoeoa nuhoasut oaeeots aoshootuheotuoehao asaoetoeatuoasu o aoeuethut aoaoe'.split()) ) def test_search_with_apostrophe_works(self): diff --git a/askbot/tests/email_alert_tests.py b/askbot/tests/email_alert_tests.py index e2f328fc..902b810d 100644 --- a/askbot/tests/email_alert_tests.py +++ b/askbot/tests/email_alert_tests.py @@ -10,6 +10,7 @@ import django.core.mail from django.core.urlresolvers import reverse from django.test import TestCase from django.test.client import Client +from django.utils import translation from askbot.tests import utils from askbot.tests.utils import with_settings from askbot import models @@ -155,6 +156,7 @@ class EmailAlertTests(TestCase): between the default version (defined in the decorator) and the desired version in the "real" test """ + translation.activate('en') pass def setUpUsers(self): diff --git a/askbot/tests/form_tests.py b/askbot/tests/form_tests.py index fed38f87..c21ac5bf 100644 --- a/askbot/tests/form_tests.py +++ b/askbot/tests/form_tests.py @@ -311,8 +311,7 @@ class UserNameFieldTest(AskbotTestCase): #invalid username and username in reserved words self.assertRaises(django_forms.ValidationError, self.username_field.clean, ' ') self.assertRaises(django_forms.ValidationError, self.username_field.clean, 'fuck') - self.assertRaises(django_forms.ValidationError, self.username_field.clean, '......') - + self.assertEqual(self.username_field.clean('......'), '......') #TODO: test more things class AnswerEditorFieldTests(AskbotTestCase): diff --git a/askbot/tests/page_load_tests.py b/askbot/tests/page_load_tests.py index be54a1dc..1143d056 100644 --- a/askbot/tests/page_load_tests.py +++ b/askbot/tests/page_load_tests.py @@ -12,6 +12,7 @@ import coffin import coffin.template from bs4 import BeautifulSoup +import askbot from askbot import models from askbot.utils.slug import slugify from askbot.deployment import package_utils @@ -53,6 +54,7 @@ class PageLoadTestCase(AskbotTestCase): # @classmethod def setUpClass(cls): + super(PageLoadTestCase, cls).setUpClass() management.call_command('flush', verbosity=0, interactive=False) activate_language(settings.LANGUAGE_CODE) management.call_command('askbot_add_test_content', verbosity=0, interactive=False) @@ -74,6 +76,12 @@ class PageLoadTestCase(AskbotTestCase): #Disable caching (to not interfere with production cache, #not sure if that's possible but let's not risk it) cache.cache = DummyCache('', {}) + if 'postgresql' in askbot.get_database_engine_name(): + management.call_command( + 'init_postgresql_full_text_search', + verbosity=0, + interactive=False + ) def tearDown(self): cache.cache = self.old_cache # Restore caching @@ -196,7 +204,6 @@ class PageLoadTestCase(AskbotTestCase): """test all reader views thoroughly on non-crashiness (no correcteness tests here) """ - self.try_url('sitemap') self.try_url( 'get_groups_list', diff --git a/askbot/tests/permission_assertion_tests.py b/askbot/tests/permission_assertion_tests.py index 9d549450..16a5afde 100644 --- a/askbot/tests/permission_assertion_tests.py +++ b/askbot/tests/permission_assertion_tests.py @@ -322,7 +322,6 @@ class CloseQuestionPermissionAssertionTests(utils.AskbotTestCase): self.create_user(username = 'other_user') self.question = self.post_question() self.min_rep = askbot_settings.MIN_REP_TO_CLOSE_OTHERS_QUESTIONS - self.min_rep_own = askbot_settings.MIN_REP_TO_CLOSE_OWN_QUESTIONS def assert_can_close(self, user = None): user.assert_can_close_question(self.question) @@ -359,11 +358,10 @@ class CloseQuestionPermissionAssertionTests(utils.AskbotTestCase): def test_low_rep_owner_cannot_close(self): assert(self.user.reputation < self.min_rep) - assert(self.user.reputation < self.min_rep_own) - self.assert_cannot_close(user = self.user) + self.assert_can_close(user=self.user) def test_high_rep_owner_can_close(self): - self.user.reputation = self.min_rep_own + self.user.reputation = self.min_rep self.assert_can_close(user = self.user) def test_high_rep_other_can_close(self): @@ -380,14 +378,9 @@ class CloseQuestionPermissionAssertionTests(utils.AskbotTestCase): self.other_user.reputation = self.min_rep self.assert_cannot_close(user = self.other_user) - def test_medium_rep_blocked_owner_cannot_close(self): - self.user.set_status('b') - self.user.reputation = self.min_rep_own - self.assert_cannot_close(user = self.user) - def test_high_rep_blocked_owner_cannot_close(self): self.user.set_status('b') - self.user.reputation = self.min_rep + self.user.reputation = 2*self.min_rep self.assert_cannot_close(user = self.user) def test_low_rep_suspended_cannot_close(self): @@ -402,12 +395,12 @@ class CloseQuestionPermissionAssertionTests(utils.AskbotTestCase): def test_medium_rep_suspended_owner_cannot_close(self): self.user.set_status('s') - self.user.reputation = self.min_rep_own + self.user.reputation = self.min_rep self.assert_cannot_close(user = self.user) def test_high_rep_suspended_owner_cannot_close(self): self.user.set_status('s') - self.user.reputation = self.min_rep + self.user.reputation = 2*self.min_rep self.assert_cannot_close(user = self.user) @@ -423,7 +416,7 @@ class ReopenQuestionPermissionAssertionTests(utils.AskbotTestCase): """ def setUp(self): - self.min_rep = askbot_settings.MIN_REP_TO_REOPEN_OWN_QUESTIONS + self.min_rep = askbot_settings.MIN_REP_TO_CLOSE_OTHERS_QUESTIONS self.create_user() self.create_user(username = 'other_user') self.question = self.post_question() @@ -1152,11 +1145,14 @@ class CommentPermissionAssertionTests(PermissionAssertionTestCase): ) def test_suspended_user_can_comment_own_question(self): + #post question question = self.post_question() + #suspend the poster self.user.set_status('s') + #attempt to post a comment under the same question comment = self.user.post_comment( - parent_post = question, - body_text = 'test comment' + parent_post=question, + body_text='test comment' ) self.assertTrue(isinstance(comment, models.Post) and comment.is_comment()) self.assertTrue( diff --git a/askbot/tests/post_model_tests.py b/askbot/tests/post_model_tests.py index 2e785802..6d9233a2 100644 --- a/askbot/tests/post_model_tests.py +++ b/askbot/tests/post_model_tests.py @@ -365,7 +365,7 @@ class ThreadRenderLowLevelCachingTests(AskbotTestCase): cache.cache = LocMemCache('', {}) # Enable local caching thread = self.q.thread - key = Thread.SUMMARY_CACHE_KEY_TPL % thread.id + key = Thread.SUMMARY_CACHE_KEY_TPL % (thread.id, 'en') self.assertTrue(thread.summary_html_cached()) self.assertIsNotNone(thread.get_cached_summary_html()) diff --git a/askbot/tests/utils.py b/askbot/tests/utils.py index 141f229a..0a207464 100644 --- a/askbot/tests/utils.py +++ b/askbot/tests/utils.py @@ -1,8 +1,10 @@ """utility functions used by Askbot test cases """ +from django.core.cache import cache from django.test import TestCase from functools import wraps from askbot import models +from askbot.models import signals def with_settings(**settings_dict): """a decorator that will run function with settings @@ -71,7 +73,6 @@ def create_user( if date_joined is not None: user.date_joined = date_joined user.save() - user.set_status(status) if notification_schedule == None: notification_schedule = models.EmailFeedSetting.NO_EMAIL_SCHEDULE @@ -86,6 +87,10 @@ def create_user( subscriber = user ) feed.save() + + signals.user_registered.send(None, user=user) + user.set_status(status) + return user @@ -94,6 +99,10 @@ class AskbotTestCase(TestCase): to django TestCase class """ + @classmethod + def setUpClass(cls): + cache.clear() + def create_user( self, username='user', diff --git a/askbot/tests/widget_tests.py b/askbot/tests/widget_tests.py index 98c5a8aa..73a5f06e 100644 --- a/askbot/tests/widget_tests.py +++ b/askbot/tests/widget_tests.py @@ -4,12 +4,15 @@ from askbot import models from askbot.tests.utils import AskbotTestCase from django.test.client import Client +from django.conf import settings as django_settings from django.core.urlresolvers import reverse +from django.utils import translation class WidgetViewsTests(AskbotTestCase): def setUp(self): + translation.activate(django_settings.LANGUAGE_CODE) self.client = Client() self.widget = models.AskWidget.objects.create(title='foo widget') self.user = self.create_user('user1') @@ -74,6 +77,7 @@ class WidgetLoginViewTest(AskbotTestCase): class WidgetCreatorViewsTests(AskbotTestCase): def setUp(self): + translation.activate(django_settings.LANGUAGE_CODE) self.client = Client() self.user = self.create_user('user1') self.user.set_password('testpass') @@ -136,6 +140,7 @@ class WidgetCreatorViewsTests(AskbotTestCase): class QuestionWidgetViewsTests(AskbotTestCase): def setUp(self): + translation.activate(django_settings.LANGUAGE_CODE) self.user = self.create_user('testuser') self.client = Client() self.widget = models.QuestionWidget.objects.create(title="foo", diff --git a/askbot/urls.py b/askbot/urls.py index bb902508..618562e7 100644 --- a/askbot/urls.py +++ b/askbot/urls.py @@ -35,13 +35,24 @@ sitemaps = { #except those that are namespaced PREFIX = getattr(settings, 'ASKBOT_SERVICE_URL_PREFIX', '') +MAIN_PAGE_BASE_URL = getattr( + settings, + 'ASKBOT_MAIN_PAGE_BASE_URL', + _('questions') + ).strip('/') + '/' +QUESTION_PAGE_BASE_URL = getattr( + settings, + 'ASKBOT_QUESTION_PAGE_BASE_URL', + _('question') + ).strip('/') + '/' + APP_PATH = os.path.dirname(__file__) urlpatterns = patterns('', url(r'^$', views.readers.index, name='index'), # BEGIN Questions (main page) urls. All this urls work both normally and through ajax url( # Note that all parameters, even if optional, are provided to the view. Non-present ones have None value. - (r'^%s' % _('questions') + + (r'^%s' % MAIN_PAGE_BASE_URL.strip('/') + r'(%s)?' % r'/scope:(?P<scope>\w+)' + r'(%s)?' % r'/sort:(?P<sort>[\w\-]+)' + r'(%s)?' % r'/tags:(?P<tags>[\w+.#,-]+)' + # Should match: const.TAG_CHARS + ','; TODO: Is `#` char decoded by the time URLs are processed ?? @@ -54,7 +65,7 @@ urlpatterns = patterns('', name='questions' ), url( - r'^%s(?P<id>\d+)/' % _('question/'), + r'^%s(?P<id>\d+)/' % QUESTION_PAGE_BASE_URL, views.readers.question, name='question' ), @@ -229,32 +240,32 @@ urlpatterns = patterns('', name='get_post_html' ), service_url( - r'^%s%s$' % (_('questions/'), _('ask/')), + r'^%s%s$' % (MAIN_PAGE_BASE_URL, _('ask/')), views.writers.ask, name='ask' ), service_url( - r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('edit/')), + r'^%s(?P<id>\d+)/%s$' % (MAIN_PAGE_BASE_URL, _('edit/')), views.writers.edit_question, name='edit_question' ), service_url(#this url is both regular and ajax - r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('retag/')), + r'^%s(?P<id>\d+)/%s$' % (MAIN_PAGE_BASE_URL, _('retag/')), views.writers.retag_question, name='retag_question' ), service_url( - r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('close/')), + r'^%s(?P<id>\d+)/%s$' % (MAIN_PAGE_BASE_URL, _('close/')), views.commands.close, name='close' ), service_url( - r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('reopen/')), + r'^%s(?P<id>\d+)/%s$' % (MAIN_PAGE_BASE_URL, _('reopen/')), views.commands.reopen, name='reopen' ), service_url( - r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('answer/')), + r'^%s(?P<id>\d+)/%s$' % (MAIN_PAGE_BASE_URL, _('answer/')), views.writers.answer, name='answer' ), @@ -264,7 +275,7 @@ urlpatterns = patterns('', name='vote' ), service_url( - r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('revisions/')), + r'^%s(?P<id>\d+)/%s$' % (MAIN_PAGE_BASE_URL, _('revisions/')), views.readers.revisions, kwargs = {'post_type': 'question'}, name='question_revisions' @@ -543,7 +554,7 @@ urlpatterns = patterns('', name = 'list_widgets' ), service_url( - r'^widgets/questions/(?P<widget_id>\d+)/$', + r'^widgets/%s(?P<widget_id>\d+)/$' % MAIN_PAGE_BASE_URL, views.widgets.question_widget, name='question_widget' ), diff --git a/askbot/user_messages/context_processors.py b/askbot/user_messages/context_processors.py index 230e967c..59f348ff 100644 --- a/askbot/user_messages/context_processors.py +++ b/askbot/user_messages/context_processors.py @@ -9,7 +9,7 @@ from django.utils.encoding import StrAndUnicode from askbot.user_messages import get_and_delete_messages -def user_messages (request): +def user_messages(request): """ Returns session messages for the current session. @@ -18,16 +18,19 @@ def user_messages (request): #todo: a hack, for real we need to remove this middleware #and switch to the new-style session messages return {} - messages = request.user.get_and_delete_messages() - #if request.user.is_authenticated(): - #else: - # messages = LazyMessages(request) - #import inspect - #print inspect.stack()[1] - #print messages - return { 'user_messages': messages } - -class LazyMessages (StrAndUnicode): + + #the get_and_delete_messages is added to anonymous user by the + #ConnectToSessionMessages middleware by the process_request, + #however - if the user is logging out via /admin/logout/ + #the AnonymousUser is installed in the response and thus + #the Askbot's session messages hack will fail, so we have + #an extra if statement here. + if hasattr(request.user, 'get_and_delete_messages'): + messages = request.user.get_and_delete_messages() + return { 'user_messages': messages } + return {} + +class LazyMessages(StrAndUnicode): """ Lazy message container, so messages aren't actually retrieved from session and deleted until the template asks for them. diff --git a/askbot/utils/get_plurals.py b/askbot/utils/get_plurals.py new file mode 100644 index 00000000..1e30de24 --- /dev/null +++ b/askbot/utils/get_plurals.py @@ -0,0 +1,22 @@ +"""reads pluralization formulae from the .po files +and prints out list of languages for each formula""" +import sys +import os.path +import collections + +def find_formula(item): + return item.startswith('"Plural-Forms:') + +lang_codes = collections.defaultdict(set) + +for filename in sys.argv: + if not filename.endswith('.po'): + continue + lines = open(filename).readlines() + formula = filter(find_formula, lines)[0] + lang = os.path.dirname(os.path.dirname(filename)) + lang_codes[formula].add(lang.split('/')[-1]) + +for formula in lang_codes: + print lang_codes[formula] + print formula diff --git a/askbot/utils/html.py b/askbot/utils/html.py index 18a730a8..a9b489f4 100644 --- a/askbot/utils/html.py +++ b/askbot/utils/html.py @@ -89,7 +89,7 @@ def urlize_html(html): #bs4 is weird, so we work around to replace nodes #maybe there is a better way though - urlized_text = urlize(node) + urlized_text = urlize(node, trim_url_limit=40) if unicode(node) == urlized_text: continue diff --git a/askbot/utils/markup.py b/askbot/utils/markup.py index 61821bba..ffa1fdde 100644 --- a/askbot/utils/markup.py +++ b/askbot/utils/markup.py @@ -202,8 +202,8 @@ def plain_text_input_converter(text): def markdown_input_converter(text): """markdown to html converter""" text = get_parser().convert(text) - text = urlize_html(text) - return sanitize_html(text) + text = sanitize_html(text) + return urlize_html(text) def tinymce_input_converter(text): """tinymce input to production html converter""" diff --git a/askbot/utils/pluralization.py b/askbot/utils/pluralization.py new file mode 100644 index 00000000..74549f10 --- /dev/null +++ b/askbot/utils/pluralization.py @@ -0,0 +1,144 @@ +"""pluralization formulae for the supported languages""" +import logging + +def arabic(count): + """six forms for arabic: + n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n""" + if count == 0: + return 0 + elif count == 1: + return 1 + elif count == 2: + return 2 + else: + rem = count % 100 + if rem >= 3 and rem <= 10: + return 3 + if rem >= 11 and rem <= 99: + return 4 + return 5 + +def germannic(count): + """two forms for germannic languages""" + return int(count != 1) + +def francoid(count): + """french, portuguese""" + return int(count > 1) + +def singular(count): + return 0 + +def slavic(count): + """'ru', 'sr', 'hr'""" + rem10 = count % 10 + rem100 = count % 100 + if rem10 == 1 and rem100 != 11: + return 0 + elif rem10 >=2 and rem10 <= 4 and (rem100 < 10 or rem100 >= 20): + return 1 + return 2 + +def romanian(count): + if count == 1: + return 0 + else: + rem100 = count % 100 + if rem100 > 19 or (count and rem100 == 0): + return 2 + return 1 + +def polish(count): + if count == 1: + return 0 + else: + rem10 = count % 10 + rem100 = count % 100 + if rem10 >=2 and rem10 <= 4 and (rem100 < 10 and rem100 >= 20): + return 1 + return 2 + +def slovenian(count): + rem100 = count % 100 + if rem100 == 1: + return 0 + elif rem100 == 2: + return 1 + elif rem100 in (3, 4): + return 2 + return 3 + +def chech(count): + if count == 1: + return 0 + elif count >=2 and count <=4: + return 1 + return 2 + +"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" + +FORMULAE = { + 'arabic': arabic, + 'germannic': germannic, + 'slavic': slavic, + 'singular': singular, + 'romanian': romanian, + 'slovenian': slovenian, + 'chech': chech, + 'francoid': francoid +} + +GERMANNIC_FAMILY = ( + 'en', 'bg', 'bg_BG', 'el', 'nb_NO', 'pt', 'ast', 'ca', 'de', + 'it', 'hu', 'hi', 'sv_SE', 'fi', 'he_IL', 'gl', 'es', 'bn_IN' +) + +FRANCOID_FAMILY = ('fr', 'pt', 'pt_BR') + +SLAVIC_FAMILY = ( + 'ru', 'sr', 'hr' +) + +ROMANIAN_FAMILY = ('ro',) +POLISH_FAMILY = ('pl',) +SLOVENIAN_FAMILY = ('sl',) +CHECH_FAMILY = ('cs', 'cs_CZ') + +SINGULAR_FAMILY = ( + 'zh_HK', 'fa_IR', 'zh_CN', 'id_ID', 'zh_TW', 'ko', 'ms_MY', 'tr', 'tr_TR', 'vi', 'ja' +) + +def get_formula(lang): + """returns pluralization formula, default to germannic""" + if lang == 'ar': + return arabic + elif lang in GERMANNIC_FAMILY: + return germannic + elif lang in SINGULAR_FAMILY: + return singular + elif lang in SLAVIC_FAMILY: + return slavic + elif lang in FRANCOID_FAMILY: + return francoid + elif lang in ROMANIAN_FAMILY: + return romanian + elif lang in POLISH_FAMILY: + return polish + elif lang in SLOVENIAN_FAMILY: + return slovenian + elif lang in SINGULAR_FAMILY: + return singular + logging.critical('language %s not supported by askbot.utils.pluralization' % lang) + return germannic + +def py_pluralize(plural_forms, count): + from django.utils.translation import get_language + lang = get_language() + formula = get_formula(lang) + num_forms = len(plural_forms) + form_number = formula(count) + if form_number >= num_forms: + template = 'not enough plural forms for %s in language %s' + logging.critical(template % (str(plural_forms), lang)) + form_number = num_forms - 1 + return plural_forms[form_number] diff --git a/askbot/utils/slug.py b/askbot/utils/slug.py index 1c95e1d4..c27c8b79 100644 --- a/askbot/utils/slug.py +++ b/askbot/utils/slug.py @@ -17,6 +17,12 @@ from django.utils.encoding import smart_unicode # Extra characters outside of alphanumerics that we'll allow. SLUG_OK = '-_~' +def slugify_camelcase(camel): + """Converts CamelCase to camel-case""" + def subf(match): + return '-' + match.groups(1)[0].lower() + return re.sub('([A-Z])', subf, camel).strip('-') + def unicode_slugify(s, ok=SLUG_OK, lower=True, spaces=False): """Function copied from https://github.com/mozilla/unicode-slugify @@ -67,4 +73,4 @@ def slugify(input_text, max_length=150): #apply the cut-off directly slug = slug[:max_length] break - return slug + return slug or '_' diff --git a/askbot/views/commands.py b/askbot/views/commands.py index 8e08c3c4..2ade1b36 100644 --- a/askbot/views/commands.py +++ b/askbot/views/commands.py @@ -283,9 +283,10 @@ def vote(request): else: raise exceptions.PermissionDenied( - _('Sorry, but anonymous users cannot accept answers') - ) - + _('Sorry, but anonymous users cannot %(perform_action)s') % { + 'perform_action': askbot_settings.WORDS_ACCEPT_OR_UNACCEPT_THE_BEST_ANSWER + } + ) elif vote_type in ('1', '2', '5', '6'):#Q&A up/down votes ############################### @@ -376,14 +377,17 @@ def vote(request): question = get_object_or_404(models.Post, post_type='question', id=id) vote_type = request.POST.get('type') - #accept answer if vote_type == '4': + #follow question fave = request.user.toggle_favorite_question(question) response_data['count'] = models.FavoriteQuestion.objects.filter(thread = question.thread).count() if fave == False: response_data['status'] = 1 elif vote_type == '11':#subscribe q updates + #todo: this branch is not used anymore + #now we just follow question, we don't have the + #separate "subscribe" function user = request.user if user.is_authenticated(): if user not in question.thread.followed_by.all(): @@ -998,7 +1002,7 @@ def delete_post(request): @csrf.csrf_exempt def read_message(request):#marks message a read if request.method == "POST": - if request.POST['formdata'] == 'required': + if request.POST.get('formdata') == 'required': request.session['message_silent'] = 1 if request.user.is_authenticated(): request.user.delete_messages() diff --git a/askbot/views/context.py b/askbot/views/context.py index 2b9ef5ea..eda8f6a7 100644 --- a/askbot/views/context.py +++ b/askbot/views/context.py @@ -13,13 +13,15 @@ def get_for_tag_editor(): #data for the tag editor data = { 'tag_regex': const.TAG_REGEX, + 'tag_forbidden_first_chars': const.TAG_FORBIDDEN_FIRST_CHARS, 'tags_are_required': askbot_settings.TAGS_ARE_REQUIRED, 'max_tags_per_post': askbot_settings.MAX_TAGS_PER_POST, 'max_tag_length': askbot_settings.MAX_TAG_LENGTH, 'force_lowercase_tags': askbot_settings.FORCE_LOWERCASE_TAGS, 'messages': { 'required': _(msg.TAGS_ARE_REQUIRED_MESSAGE), - 'wrong_chars': _(msg.TAG_WRONG_CHARS_MESSAGE) + 'wrong_chars': _(msg.TAG_WRONG_CHARS_MESSAGE), + 'wrong_first_char': _(msg.TAG_WRONG_FIRST_CHAR_MESSAGE), } } return {'tag_editor_settings': simplejson.dumps(data)} diff --git a/askbot/views/meta.py b/askbot/views/meta.py index 692216da..6e80957c 100644 --- a/askbot/views/meta.py +++ b/askbot/views/meta.py @@ -9,7 +9,10 @@ from django.core.paginator import Paginator, EmptyPage, InvalidPage from django.shortcuts import render from django.template import RequestContext, Template from django.template.loader import get_template -from django.http import HttpResponseRedirect, HttpResponse, Http404 +from django.http import Http404 +from django.http import HttpResponse +from django.http import HttpResponseForbidden +from django.http import HttpResponseRedirect from django.core.urlresolvers import reverse from django.utils.translation import ugettext as _ from django.utils.translation import ugettext_lazy @@ -21,13 +24,16 @@ from askbot.conf import settings as askbot_settings from askbot.forms import FeedbackForm from askbot.utils.url_utils import get_login_url from askbot.utils.forms import get_next_url -from askbot.mail import mail_moderators +from askbot.mail import mail_moderators, send_mail from askbot.models import BadgeData, Award, User, Tag from askbot.models import badges as badge_data from askbot.skins.loaders import render_text_into_skin from askbot.utils.decorators import admins_only from askbot.utils.forms import get_next_url from askbot.utils import functions +from recaptcha_works.decorators import fix_recaptcha_remote_ip + +import re def generic_view(request, template = None, page_class = None): """this may be not necessary, since it is just a rewrite of render""" @@ -35,13 +41,18 @@ def generic_view(request, template = None, page_class = None): return render_to_response('django_error.html') return render(request, template, {'page_class': page_class}) +PUBLIC_VARIABLES = ('CUSTOM_CSS', 'CUSTOM_JS') + def config_variable(request, variable_name = None, mimetype = None): """Print value from the configuration settings as response content. All parameters are required. """ - #todo add http header-based caching here!!! - output = getattr(askbot_settings, variable_name, '') - return HttpResponse(output, mimetype = mimetype) + if variable_name in PUBLIC_VARIABLES: + #todo add http header-based caching here!!! + output = getattr(askbot_settings, variable_name, '') + return HttpResponse(output, mimetype = mimetype) + else: + return HttpResponseForbidden() def about(request, template='about.html'): title = _('About %(site)s') % {'site': askbot_settings.APP_SHORT_NAME} @@ -82,6 +93,7 @@ def faq(request): return render(request, 'faq_static.html', data) @csrf.csrf_protect +@fix_recaptcha_remote_ip def feedback(request): data = {'page_class': 'meta'} form = None @@ -113,12 +125,21 @@ def feedback(request): headers = {} if data['email']: headers = {'Reply-To': data['email']} - - mail_moderators( - _('Q&A forum feedback'), - message, - headers=headers - ) + subject = _('Q&A forum feedback') + if askbot_settings.FEEDBACK_EMAILS: + recipients = re.split('\s*,\s*', askbot_settings.FEEDBACK_EMAILS) + send_mail( + subject_line=subject, + body_text=message, + headers=headers, + recipient_list=recipients, + ) + else: + mail_moderators( + subject_line=subject, + body_text=message, + headers=headers + ) msg = _('Thanks for the feedback!') request.user.message_set.create(message=msg) return HttpResponseRedirect(get_next_url(request)) diff --git a/askbot/views/readers.py b/askbot/views/readers.py index 8bf2cea9..155be946 100644 --- a/askbot/views/readers.py +++ b/askbot/views/readers.py @@ -154,6 +154,7 @@ def questions(request, **kwargs): if request.is_ajax(): q_count = paginator.count + #todo: words question_counter = ungettext('%(q_num)s question', '%(q_num)s questions', q_count) question_counter = question_counter % {'q_num': humanize.intcomma(q_count),} @@ -262,7 +263,9 @@ def questions(request, **kwargs): request, template_data ) + template_data.update(extra_context) + template_data.update(context.get_for_tag_editor()) #and one more thing:) give admin user heads up about #setting the domain name if they have not done that yet @@ -738,8 +741,6 @@ def get_perms_data(request): 'MIN_REP_TO_UPLOAD_FILES', 'MIN_REP_TO_INSERT_LINK', 'MIN_REP_TO_SUGGEST_LINK', - 'MIN_REP_TO_CLOSE_OWN_QUESTIONS', - 'MIN_REP_TO_REOPEN_OWN_QUESTIONS', 'MIN_REP_TO_CLOSE_OTHERS_QUESTIONS', 'MIN_REP_TO_RETAG_OTHERS_QUESTIONS', 'MIN_REP_TO_EDIT_WIKI', diff --git a/askbot/views/users.py b/askbot/views/users.py index 14aad336..57397457 100644 --- a/askbot/views/users.py +++ b/askbot/views/users.py @@ -283,7 +283,6 @@ def user_moderate(request, subject, context): 'active_tab': 'users', 'page_class': 'user-profile-page', 'tab_name': 'moderation', - 'tab_description': _('moderate this user'), 'page_title': _('moderate user'), 'change_user_status_form': user_status_form, 'change_user_reputation_form': user_rep_form, @@ -529,7 +528,6 @@ def user_stats(request, user, context): 'page_class': 'user-profile-page', 'support_custom_avatars': ('avatar' in django_settings.INSTALLED_APPS), 'tab_name' : 'stats', - 'tab_description' : _('user profile'), 'page_title' : _('user profile overview'), 'user_status_for_display': user.get_status_display(soft = True), 'questions' : questions, @@ -653,7 +651,6 @@ def user_recent(request, user, context): 'active_tab': 'users', 'page_class': 'user-profile-page', 'tab_name' : 'recent', - 'tab_description' : _('recent user activity'), 'page_title' : _('profile - recent activity'), 'activities' : activities } @@ -685,7 +682,6 @@ def show_group_join_requests(request, user, context): 'inbox_section': 'group-join-requests', 'page_class': 'user-profile-page', 'tab_name' : 'join_requests', - 'tab_description' : _('group joining requests'), 'page_title' : _('profile - moderation'), 'groups_dict': groups_dict, 'join_requests': join_requests @@ -742,7 +738,6 @@ def user_responses(request, user, context): 'page_class': 'user-profile-page', 'tab_name' : 'inbox', 'inbox_section': section, - 'tab_description' : _('private messages'), 'page_title' : _('profile - messages') } context.update(data) @@ -822,7 +817,6 @@ def user_responses(request, user, context): 'page_class': 'user-profile-page', 'tab_name' : 'inbox', 'inbox_section': section, - 'tab_description' : _('comments and answers to others questions'), 'page_title' : _('profile - responses'), 'post_reject_reasons': reject_reasons, 'responses' : filtered_response_list, @@ -864,7 +858,6 @@ def user_votes(request, user, context): 'active_tab':'users', 'page_class': 'user-profile-page', 'tab_name' : 'votes', - 'tab_description' : _('user vote record'), 'page_title' : _('profile - votes'), 'votes' : votes[:const.USER_VIEW_DATA_SIZE] } @@ -886,7 +879,6 @@ def user_reputation(request, user, context): 'active_tab':'users', 'page_class': 'user-profile-page', 'tab_name': 'reputation', - 'tab_description': _('user karma'), 'page_title': _("Profile - User's Karma"), 'reputation': reputes, 'reps': reps @@ -922,8 +914,7 @@ def user_favorites(request, user, context): 'active_tab':'users', 'page_class': 'user-profile-page', 'tab_name' : 'favorites', - 'tab_description' : _('users favorite questions'), - 'page_title' : _('profile - favorite questions'), + 'page_title' : _('profile - favorites'), 'questions' : questions, 'q_paginator_context': q_paginator_context, 'question_count': question_count, @@ -996,7 +987,6 @@ def user_email_subscriptions(request, user, context): 'subscribed_tag_names': user.get_marked_tag_names('subscribed'), 'page_class': 'user-profile-page', 'tab_name': 'email_subscriptions', - 'tab_description': _('email subscription settings'), 'page_title': _('profile - email subscriptions'), 'email_feeds_form': email_feeds_form, 'tag_filter_selection_form': tag_filter_form, diff --git a/askbot/views/widgets.py b/askbot/views/widgets.py index 5c4042fa..c049f91d 100644 --- a/askbot/views/widgets.py +++ b/askbot/views/widgets.py @@ -60,6 +60,10 @@ def ask_widget(request, widget_id): widget = get_object_or_404(models.AskWidget, id=widget_id) if request.method == "POST": + + if askbot_settings.READ_ONLY_MODE_ENABLED: + return redirect('ask_by_widget') + form = forms.AskWidgetForm( include_text=widget.include_text_field, data=request.POST, diff --git a/askbot/views/writers.py b/askbot/views/writers.py index 7df425ee..9234c37f 100644 --- a/askbot/views/writers.py +++ b/askbot/views/writers.py @@ -205,13 +205,7 @@ def import_data(request): #@login_required #actually you can post anonymously, but then must register @csrf.csrf_protect -@decorators.check_authorization_to_post(ugettext_lazy( - "<span class=\"strong big\">You are welcome to start submitting your question " - "anonymously</span>. When you submit the post, you will be redirected to the " - "login/signup page. Your question will be saved in the current session and " - "will be published after you log in. Login/signup process is very simple. " - "Login takes about 30 seconds, initial signup takes a minute or less." -)) +@decorators.check_authorization_to_post(ugettext_lazy('Please log in to make posts')) @decorators.check_spam('text') def ask(request):#view used to ask a new question """a view to ask a new question @@ -226,6 +220,9 @@ def ask(request):#view used to ask a new question request.user.message_set.create(message=_('Sorry, but you have only read access')) return HttpResponseRedirect(referer) + if askbot_settings.READ_ONLY_MODE_ENABLED: + return HttpResponseRedirect(reverse('index')) + form = forms.AskForm(request.REQUEST, user=request.user) if request.method == 'POST': if form.is_valid(): @@ -390,8 +387,13 @@ def edit_question(request, id): """edit question view """ question = get_object_or_404(models.Post, id=id) + + if askbot_settings.READ_ONLY_MODE_ENABLED: + return HttpResponseRedirect(question.get_absolute_url()) + revision = question.get_latest_revision() revision_form = None + try: request.user.assert_can_edit_question(question) if request.method == 'POST': @@ -492,6 +494,10 @@ def edit_question(request, id): @decorators.check_spam('text') def edit_answer(request, id): answer = get_object_or_404(models.Post, id=id) + + if askbot_settings.READ_ONLY_MODE_ENABLED: + return HttpResponseRedirect(answer.get_absolute_url()) + revision = answer.get_latest_revision() class_path = getattr(settings, 'ASKBOT_EDIT_ANSWER_FORM', None) @@ -579,7 +585,7 @@ def edit_answer(request, id): return HttpResponseRedirect(answer.get_absolute_url()) #todo: rename this function to post_new_answer -@decorators.check_authorization_to_post(ugettext_lazy('Please log in to answer questions')) +@decorators.check_authorization_to_post(ugettext_lazy('Please log in to make posts')) @decorators.check_spam('text') def answer(request, id, form_class=forms.AnswerForm):#process a new answer """view that posts new answer @@ -590,6 +596,10 @@ def answer(request, id, form_class=forms.AnswerForm):#process a new answer authenticated users post directly """ question = get_object_or_404(models.Post, post_type='question', id=id) + + if askbot_settings.READ_ONLY_MODE_ENABLED: + return HttpResponseRedirect(question.get_absolute_url()) + if request.method == "POST": #this check prevents backward compatilibility @@ -727,6 +737,10 @@ def post_comments(request):#generic ajax handler to load comments to an object '<a href="%(sign_in_url)s">sign in</a>.') % \ {'sign_in_url': url_utils.get_login_url()} raise exceptions.PermissionDenied(msg) + + if askbot_settings.READ_ONLY_MODE_ENABLED: + raise exceptions.PermissionDenied(askbot_settings.READ_ONLY_MESSAGE) + comment = user.post_comment( parent_post=post, body_text=form.cleaned_data['comment'] ) @@ -741,13 +755,16 @@ def post_comments(request):#generic ajax handler to load comments to an object return response -#@csrf.csrf_exempt +@csrf.csrf_exempt @decorators.ajax_only #@decorators.check_spam('comment') def edit_comment(request): if request.user.is_anonymous(): raise exceptions.PermissionDenied(_('Sorry, anonymous users cannot edit comments')) + if askbot_settings.READ_ONLY_MODE_ENABLED: + raise exceptions.PermissionDenied(askbot_settings.READ_ONLY_MESSAGE) + form = forms.EditCommentForm(request.POST) if form.is_valid() == False: raise exceptions.PermissionDenied('This content is forbidden') @@ -811,6 +828,9 @@ def delete_comment(request): comment = get_object_or_404(models.Post, post_type='comment', id=comment_id) request.user.assert_can_delete_comment(comment) + if askbot_settings.READ_ONLY_MODE_ENABLED: + raise exceptions.PermissionDenied(askbot_settings.READ_ONLY_MESSAGE) + parent = comment.parent comment.delete() #attn: recalc denormalized field @@ -831,17 +851,24 @@ def delete_comment(request): @decorators.post_only def comment_to_answer(request): - comment_id = request.POST.get('comment_id') - if comment_id: - comment_id = int(comment_id) - comment = get_object_or_404(models.Post, - post_type='comment', id=comment_id) - request.user.repost_comment_as_answer(comment) - return HttpResponseRedirect(comment.get_absolute_url()) - else: + try: + comment_id = int(request.POST.get('comment_id')) + except (ValueError, TypeError): + #type or value error is raised is int() fails raise Http404 + comment = get_object_or_404( + models.Post, + post_type='comment', + id=comment_id + ) + + if askbot_settings.READ_ONLY_MODE_ENABLED is False: + request.user.repost_comment_as_answer(comment) + + return HttpResponseRedirect(comment.get_absolute_url()) + @decorators.post_only @csrf.csrf_protect #todo: change the urls config for this @@ -858,6 +885,9 @@ def repost_answer_as_comment(request, destination=None): answer = get_object_or_404(models.Post, post_type = 'answer', id=answer_id) + if askbot_settings.READ_ONLY_MODE_ENABLED: + return HttpResponseRedirect(answer.get_absolute_url()) + if destination == 'comment_under_question': destination_post = answer.thread._question_post() else: @@ -873,8 +903,8 @@ def repost_answer_as_comment(request, destination=None): if len(answer.text) <= askbot_settings.MAX_COMMENT_LENGTH: answer.post_type = 'comment' answer.parent = destination_post - #can we trust this? - old_comment_count = answer.comment_count + + new_comment_count = answer.comments.count() + 1 answer.comment_count = 0 answer_comments = models.Post.objects.get_comments().filter(parent=answer) @@ -884,7 +914,7 @@ def repost_answer_as_comment(request, destination=None): answer.parse_and_save(author=answer.author) answer.thread.update_answer_count() - answer.parent.comment_count = 1 + old_comment_count + answer.parent.comment_count += new_comment_count answer.parent.save() answer.thread.invalidate_cached_data() |