diff options
-rw-r--r-- | .gitignore | 3 | ||||
-rw-r--r-- | forum/management/commands/once_award_badges.py | 50 | ||||
-rw-r--r-- | forum/views.py | 3916 | ||||
-rw-r--r-- | locale/zh-cn/LC_MESSAGES/django.mo | bin | 39094 -> 0 bytes | |||
-rw-r--r-- | locale/zh-cn/LC_MESSAGES/django.po | 1430 | ||||
-rw-r--r-- | locale/zh_CN/LC_MESSAGES/django.po | 2300 | ||||
-rw-r--r-- | templates/answer_edit_tips.html | 1 | ||||
-rw-r--r-- | templates/pagesize.html | 2 | ||||
-rw-r--r-- | templates/paginator.html | 1 | ||||
-rw-r--r-- | templates/questions.html | 5 |
10 files changed, 4031 insertions, 3677 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..4f83efab --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.pyc +*.swp +nbproject diff --git a/forum/management/commands/once_award_badges.py b/forum/management/commands/once_award_badges.py index c26251d7..7074e3db 100644 --- a/forum/management/commands/once_award_badges.py +++ b/forum/management/commands/once_award_badges.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python
+#!/usr/bin/env python
#encoding:utf-8
#-------------------------------------------------------------------------------
# Name: Award badges command
@@ -12,7 +12,6 @@ # Licence: GPL V2
#-------------------------------------------------------------------------------
-from datetime import datetime, date
from django.db import connection
from django.shortcuts import get_object_or_404
from django.contrib.contenttypes.models import ContentType
@@ -157,8 +156,7 @@ class Command(BaseCommand): """
activity_types = ','.join('%s' % item for item in BADGE_AWARD_TYPE_FIRST.keys())
# ORDER BY user_id, activity_type
- query = "SELECT id, user_id, activity_type, content_type_id, object_id "+
- "FROM activity WHERE is_auditted = 0 AND activity_type IN (%s) ORDER BY user_id, activity_type" % activity_types
+ query = "SELECT id, user_id, activity_type, content_type_id, object_id FROM activity WHERE is_auditted = 0 AND activity_type IN (%s) ORDER BY user_id, activity_type" % activity_types
cursor = connection.cursor()
try:
@@ -206,9 +204,9 @@ class Command(BaseCommand): (13, '学生', 3, '学生', '第一次提问并且有一次以上赞成票', 0, 0),
"""
- query = "SELECT act.user_id, q.vote_up_count, act.object_id FROM "+
- "activity act, question q WHERE act.activity_type = %s AND "+
- "act.object_id = q.id AND "+
+ query = "SELECT act.user_id, q.vote_up_count, act.object_id FROM " \
+ "activity act, question q WHERE act.activity_type = %s AND " \
+ "act.object_id = q.id AND " \
"act.user_id NOT IN (SELECT distinct user_id FROM award WHERE badge_id = %s)" % (TYPE_ACTIVITY_ASK_QUESTION, 13)
cursor = connection.cursor()
try:
@@ -236,9 +234,9 @@ class Command(BaseCommand): (15, '教师', 3, '教师', '第一次回答问题并且得到一个以上赞成票', 0, 0),
"""
- query = "SELECT act.user_id, a.vote_up_count, act.object_id FROM "+
- "activity act, answer a WHERE act.activity_type = %s AND "+
- "act.object_id = a.id AND "+
+ query = "SELECT act.user_id, a.vote_up_count, act.object_id FROM " \
+ "activity act, answer a WHERE act.activity_type = %s AND " \
+ "act.object_id = a.id AND " \
"act.user_id NOT IN (SELECT distinct user_id FROM award WHERE badge_id = %s)" % (TYPE_ACTIVITY_ANSWER, 15)
cursor = connection.cursor()
try:
@@ -264,10 +262,10 @@ class Command(BaseCommand): """
(32, '学问家', 2, '学问家', '第一次回答被投赞成票10次以上', 0, 0)
"""
- query = "SELECT act.user_id, act.object_id FROM "+
- "activity act, answer a WHERE act.object_id = a.id AND "+
- "act.activity_type = %s AND "+
- "a.vote_up_count >= 10 AND "+
+ query = "SELECT act.user_id, act.object_id FROM " \
+ "activity act, answer a WHERE act.object_id = a.id AND " \
+ "act.activity_type = %s AND " \
+ "a.vote_up_count >= 10 AND " \
"act.user_id NOT IN (SELECT user_id FROM award WHERE badge_id = %s)" % (TYPE_ACTIVITY_ANSWER, 32)
cursor = connection.cursor()
try:
@@ -292,10 +290,10 @@ class Command(BaseCommand): """
(26, '优秀市民', 2, '优秀市民', '投票300次以上', 0, 0)
"""
- query = "SELECT count(*) vote_count, user_id FROM activity WHERE "+
- "activity_type = %s OR "+
- "activity_type = %s AND "+
- "user_id NOT IN (SELECT user_id FROM award WHERE badge_id = %s) "+
+ query = "SELECT count(*) vote_count, user_id FROM activity WHERE " \
+ "activity_type = %s OR " \
+ "activity_type = %s AND " \
+ "user_id NOT IN (SELECT user_id FROM award WHERE badge_id = %s) " \
"GROUP BY user_id HAVING vote_count >= 300" % (TYPE_ACTIVITY_VOTE_UP, TYPE_ACTIVITY_VOTE_DOWN, 26)
self.__award_for_count_num(query, 26)
@@ -304,10 +302,10 @@ class Command(BaseCommand): """
(27, '编辑主任', 2, '编辑主任', '编辑了100个帖子', 0, 0)
"""
- query = "SELECT count(*) vote_count, user_id FROM activity WHERE "+
- "activity_type = %s OR "+
- "activity_type = %s AND "+
- "user_id NOT IN (SELECT user_id FROM award WHERE badge_id = %s) "+
+ query = "SELECT count(*) vote_count, user_id FROM activity WHERE " \
+ "activity_type = %s OR " \
+ "activity_type = %s AND " \
+ "user_id NOT IN (SELECT user_id FROM award WHERE badge_id = %s) " \
"GROUP BY user_id HAVING vote_count >= 100" % (TYPE_ACTIVITY_UPDATE_QUESTION, TYPE_ACTIVITY_UPDATE_ANSWER, 27)
self.__award_for_count_num(query, 27)
@@ -316,10 +314,10 @@ class Command(BaseCommand): """
(5, '评论家', 3, '评论家', '评论10次以上', 0, 0),
"""
- query = "SELECT count(*) vote_count, user_id FROM activity WHERE "+
- "activity_type = %s OR "+
- "activity_type = %s AND "+
- "user_id NOT IN (SELECT user_id FROM award WHERE badge_id = %s) "+
+ query = "SELECT count(*) vote_count, user_id FROM activity WHERE " \
+ "activity_type = %s OR " \
+ "activity_type = %s AND " \
+ "user_id NOT IN (SELECT user_id FROM award WHERE badge_id = %s) " \
"GROUP BY user_id HAVING vote_count >= 10" % (TYPE_ACTIVITY_COMMENT_QUESTION, TYPE_ACTIVITY_COMMENT_ANSWER, 5)
self.__award_for_count_num(query, 5)
diff --git a/forum/views.py b/forum/views.py index 08a0e958..6ac172df 100644 --- a/forum/views.py +++ b/forum/views.py @@ -1,1958 +1,1958 @@ -# encoding:utf-8
-import os.path
-import time, datetime, calendar, random
-import logging
-from urllib import quote, unquote
-from django.conf import settings
-from django.core.files.storage import default_storage
-from django.shortcuts import render_to_response, get_object_or_404
-from django.contrib.auth.decorators import login_required
-from django.http import HttpResponseRedirect, HttpResponse,Http404
-from django.core.paginator import Paginator, EmptyPage, InvalidPage
-from django.template import RequestContext
-from django.utils.html import *
-from django.utils import simplejson
-from django.core import serializers
-from django.db import transaction
-from django.contrib.contenttypes.models import ContentType
-from django.utils.translation import ugettext as _
-
-from utils.html import sanitize_html
-from markdown2 import Markdown
-#from lxml.html.diff import htmldiff
-from forum.diff import textDiff as htmldiff
-from forum.forms import *
-from forum.models import *
-from forum.auth import *
-from forum.const import *
-from forum.user import *
-from forum import auth
-
-# used in index page
-INDEX_PAGE_SIZE = 20
-INDEX_AWARD_SIZE = 15
-INDEX_TAGS_SIZE = 100
-# used in tags list
-DEFAULT_PAGE_SIZE = 60
-# used in questions
-QUESTIONS_PAGE_SIZE = 10
-# used in users
-USERS_PAGE_SIZE = 35
-# used in answers
-ANSWERS_PAGE_SIZE = 10
-markdowner = Markdown(html4tags=True)
-question_type = ContentType.objects.get_for_model(Question)
-answer_type = ContentType.objects.get_for_model(Answer)
-comment_type = ContentType.objects.get_for_model(Comment)
-question_revision_type = ContentType.objects.get_for_model(QuestionRevision)
-answer_revision_type = ContentType.objects.get_for_model(AnswerRevision)
-repute_type =ContentType.objects.get_for_model(Repute)
-question_type_id = question_type.id
-answer_type_id = answer_type.id
-comment_type_id = comment_type.id
-question_revision_type_id = question_revision_type.id
-answer_revision_type_id = answer_revision_type.id
-repute_type_id = repute_type.id
-def _get_tags_cache_json():
- tags = Tag.objects.filter(deleted=False).all()
- tags_list = []
- for tag in tags:
- dic = {'n': tag.name, 'c': tag.used_count }
- tags_list.append(dic)
- tags = simplejson.dumps(tags_list)
- return tags
-
-def index(request):
- view_id = request.GET.get('sort', None)
- view_dic = {
- "latest":"-last_activity_at",
- "hottest":"-answer_count",
- "mostvoted":"-score",
- "trans": "-last_activity_at"
- }
- try:
- orderby = view_dic[view_id]
- except KeyError:
- view_id = "latest"
- orderby = "-last_activity_at"
- # group questions by author_id of 28,29
- if view_id == 'trans':
- questions = Question.objects.get_translation_questions(orderby, INDEX_PAGE_SIZE)
- else:
- questions = Question.objects.get_questions_by_pagesize(orderby, INDEX_PAGE_SIZE)
- # RISK - inner join queries
- questions = questions.select_related()
- tags = Tag.objects.get_valid_tags(INDEX_TAGS_SIZE)
-
- awards = Award.objects.get_recent_awards()
-
- return render_to_response('index.html', {
- "questions" : questions,
- "tab_id" : view_id,
- "tags" : tags,
- "awards" : awards[:INDEX_AWARD_SIZE],
- }, context_instance=RequestContext(request))
-
-def about(request):
- return render_to_response('about.html', context_instance=RequestContext(request))
-
-def faq(request):
- return render_to_response('faq.html', context_instance=RequestContext(request))
-
-def privacy(request):
- return render_to_response('privacy.html', context_instance=RequestContext(request))
-
-def unanswered(request):
- return questions(request, unanswered=True)
-
-def questions(request, tagname=None, unanswered=False):
- """
- List of Questions, Tagged questions, and Unanswered questions.
- """
- # template file
- # "questions.html" or "unanswered.html"
- template_file = "questions.html"
- # Set flag to False by default. If it is equal to True, then need to be saved.
- pagesize_changed = False
- # get pagesize from session, if failed then get default value
- pagesize = request.session.get("pagesize")
- try:
- page = int(request.GET.get('page', '1'))
- except ValueError:
- page = 1
-
- view_id = request.GET.get('sort', None)
- view_dic = {"latest":"-added_at", "active":"-last_activity_at", "hottest":"-answer_count", "mostvoted":"-score" }
- try:
- orderby = view_dic[view_id]
- except KeyError:
- view_id = "latest"
- orderby = "-added_at"
-
- # check if request is from tagged questions
- if tagname is not None:
- objects = Question.objects.get_questions_by_tag(tagname, orderby)
- elif unanswered:
- #check if request is from unanswered questions
- template_file = "unanswered.html"
- objects = Question.objects.get_unanswered_questions(orderby)
- else:
- objects = Question.objects.get_questions(orderby)
-
- # RISK - inner join queries
- objects = objects.select_related(depth=1);
- objects_list = Paginator(objects, pagesize)
- questions = objects_list.page(page)
-
- # Get related tags from this page objects
- if questions.object_list.count() > 0:
- related_tags = Tag.objects.get_tags_by_questions(questions.object_list)
- else:
- related_tags = None
- return render_to_response(template_file, {
- "questions" : questions,
- "tab_id" : view_id,
- "questions_count" : objects_list.count,
- "tags" : related_tags,
- "searchtag" : tagname,
- "is_unanswered" : unanswered,
- "context" : {
- 'is_paginated' : True,
- 'pages': objects_list.num_pages,
- 'page': page,
- 'has_previous': questions.has_previous(),
- 'has_next': questions.has_next(),
- 'previous': questions.previous_page_number(),
- 'next': questions.next_page_number(),
- 'base_url' : request.path + '?sort=%s&' % view_id,
- 'pagesize' : pagesize
- }}, context_instance=RequestContext(request))
-
-#TODO: allow anynomus user to ask question by providing email and username.
-@login_required
-def ask(request):
- if request.method == "POST":
- form = AskForm(request.POST)
- if form.is_valid():
- added_at = datetime.datetime.now()
- html = sanitize_html(markdowner.convert(form.cleaned_data['text']))
- question = Question(
- title = strip_tags(form.cleaned_data['title']),
- author = request.user,
- added_at = added_at,
- last_activity_at = added_at,
- last_activity_by = request.user,
- wiki = form.cleaned_data['wiki'],
- tagnames = form.cleaned_data['tags'].strip(),
- html = html,
- summary = strip_tags(html)[:120]
- )
- if question.wiki:
- question.last_edited_by = question.author
- question.last_edited_at = added_at
- question.wikified_at = added_at
-
- question.save()
-
- # create the first revision
- QuestionRevision.objects.create(
- question = question,
- revision = 1,
- title = question.title,
- author = request.user,
- revised_at = added_at,
- tagnames = question.tagnames,
- summary = CONST['default_version'],
- text = form.cleaned_data['text']
- )
-
- return HttpResponseRedirect(question.get_absolute_url())
-
- else:
- form = AskForm()
-
- tags = _get_tags_cache_json()
- return render_to_response('ask.html', {
- 'form' : form,
- 'tags' : tags,
- }, context_instance=RequestContext(request))
-
-def question(request, id):
- try:
- page = int(request.GET.get('page', '1'))
- except ValueError:
- page = 1
- view_id = request.GET.get('sort', 'votes')
- view_dic = {"latest":"-added_at", "oldest":"added_at", "votes":"-score" }
- try:
- orderby = view_dic[view_id]
- except KeyError:
- view_id = "votes"
- orderby = "-score"
-
- question = get_object_or_404(Question, id=id)
- if question.deleted and not can_view_deleted_post(request.user, question):
- raise Http404
- answer_form = AnswerForm(question)
- answers = Answer.objects.get_answers_from_question(question, request.user)
- answers = answers.select_related(depth=1)
-
- favorited = question.has_favorite_by_user(request.user)
- question_vote = question.votes.select_related().filter(user=request.user)
- if question_vote is not None and question_vote.count() > 0:
- question_vote = question_vote[0]
-
- user_answer_votes = {}
- for answer in answers:
- vote = answer.get_user_vote(request.user)
- if vote is not None and not user_answer_votes.has_key(answer.id):
- vote_value = -1
- if vote.is_upvote():
- vote_value = 1
- user_answer_votes[answer.id] = vote_value
-
-
- if answers is not None:
- answers = answers.order_by("-accepted", orderby)
- objects_list = Paginator(answers, ANSWERS_PAGE_SIZE)
- page_objects = objects_list.page(page)
- # update view count
- Question.objects.update_view_count(question)
- return render_to_response('question.html', {
- "question" : question,
- "question_vote" : question_vote,
- "question_comment_count":question.comments.count(),
- "answer" : answer_form,
- "answers" : page_objects.object_list,
- "user_answer_votes": user_answer_votes,
- "tags" : question.tags.all(),
- "tab_id" : view_id,
- "favorited" : favorited,
- "similar_questions" : Question.objects.get_similar_questions(question),
- "context" : {
- 'is_paginated' : True,
- 'pages': objects_list.num_pages,
- 'page': page,
- 'has_previous': page_objects.has_previous(),
- 'has_next': page_objects.has_next(),
- 'previous': page_objects.previous_page_number(),
- 'next': page_objects.next_page_number(),
- 'base_url' : request.path + '?sort=%s&' % view_id,
- 'extend_url' : "#sort-top"
- }
- }, context_instance=RequestContext(request))
-
-@login_required
-def close(request, id):
- question = get_object_or_404(Question, id=id)
- if not can_close_question(request.user, question):
- return HttpResponse('Permission denied.')
- if request.method == 'POST':
- form = CloseForm(request.POST)
- if form.is_valid():
- reason = form.cleaned_data['reason']
- question.closed = True
- question.closed_by = request.user
- question.closed_at = datetime.datetime.now()
- question.close_reason = reason
- question.save()
- return HttpResponseRedirect(question.get_absolute_url())
- else:
- form = CloseForm()
- return render_to_response('close.html', {
- 'form' : form,
- 'question' : question,
- }, context_instance=RequestContext(request))
-
-@login_required
-def reopen(request, id):
- question = get_object_or_404(Question, id=id)
- # open question
- if not can_reopen_question(request.user, question):
- return HttpResponse('Permission denied.')
- if request.method == 'POST' :
- Question.objects.filter(id=question.id).update(closed=False,
- closed_by=None, closed_at=None, close_reason=None)
- return HttpResponseRedirect(question.get_absolute_url())
- else:
- return render_to_response('reopen.html', {
- 'question' : question,
- }, context_instance=RequestContext(request))
-
-@login_required
-def edit_question(request, id):
- question = get_object_or_404(Question, id=id)
- if question.deleted and not can_view_deleted_post(request.user, question):
- raise Http404
- if can_edit_post(request.user, question):
- return _edit_question(request, question)
- elif can_retag_questions(request.user):
- return _retag_question(request, question)
- else:
- raise Http404
-
-def _retag_question(request, question):
- if request.method == 'POST':
- form = RetagQuestionForm(question, request.POST)
- if form.is_valid():
- if form.has_changed():
- latest_revision = question.get_latest_revision()
- retagged_at = datetime.datetime.now()
- # Update the Question itself
- Question.objects.filter(id=question.id).update(
- tagnames = form.cleaned_data['tags'],
- last_edited_at = retagged_at,
- last_edited_by = request.user,
- last_activity_at = retagged_at,
- last_activity_by = request.user
- )
- # Update the Question's tag associations
- tags_updated = Question.objects.update_tags(question,
- form.cleaned_data['tags'], request.user)
- # Create a new revision
- QuestionRevision.objects.create(
- question = question,
- title = latest_revision.title,
- author = request.user,
- revised_at = retagged_at,
- tagnames = form.cleaned_data['tags'],
- summary = CONST['retagged'],
- text = latest_revision.text
- )
- # send tags updated singal
- tags_updated.send(sender=question.__class__, question=question)
-
- return HttpResponseRedirect(question.get_absolute_url())
- else:
- form = RetagQuestionForm(question)
- return render_to_response('question_retag.html', {
- 'question': question,
- 'form' : form,
- 'tags' : _get_tags_cache_json(),
- }, context_instance=RequestContext(request))
-
-
-def _edit_question(request, question):
- latest_revision = question.get_latest_revision()
- revision_form = None
- if request.method == 'POST':
- if 'select_revision' in request.POST:
- # user has changed revistion number
- revision_form = RevisionForm(question, latest_revision, request.POST)
- if revision_form.is_valid():
- # Replace with those from the selected revision
- form = EditQuestionForm(question,
- QuestionRevision.objects.get(question=question,
- revision=revision_form.cleaned_data['revision']))
- else:
- form = EditQuestionForm(question, latest_revision, request.POST)
- else:
- # Always check modifications against the latest revision
- form = EditQuestionForm(question, latest_revision, request.POST)
- if form.is_valid():
- html = sanitize_html(markdowner.convert(form.cleaned_data['text']))
- if form.has_changed():
- edited_at = datetime.datetime.now()
- tags_changed = (latest_revision.tagnames !=
- form.cleaned_data['tags'])
- tags_updated = False
- # Update the Question itself
- updated_fields = {
- 'title': form.cleaned_data['title'],
- 'last_edited_at': edited_at,
- 'last_edited_by': request.user,
- 'last_activity_at': edited_at,
- 'last_activity_by': request.user,
- 'tagnames': form.cleaned_data['tags'],
- 'summary': strip_tags(html)[:120],
- 'html': html,
- }
-
- # only save when it's checked
- # because wiki doesn't allow to be edited if last version has been enabled already
- # and we make sure this in forms.
- if ('wiki' in form.cleaned_data and
- form.cleaned_data['wiki']):
- updated_fields['wiki'] = True
- updated_fields['wikified_at'] = edited_at
-
- Question.objects.filter(
- id=question.id).update(**updated_fields)
- # Update the Question's tag associations
- if tags_changed:
- tags_updated = Question.objects.update_tags(
- question, form.cleaned_data['tags'], request.user)
- # Create a new revision
- revision = QuestionRevision(
- question = question,
- title = form.cleaned_data['title'],
- author = request.user,
- revised_at = edited_at,
- tagnames = form.cleaned_data['tags'],
- text = form.cleaned_data['text'],
- )
- if form.cleaned_data['summary']:
- revision.summary = form.cleaned_data['summary']
- else:
- revision.summary = 'No.%s Revision' % latest_revision.revision
- revision.save()
-
- return HttpResponseRedirect(question.get_absolute_url())
- else:
-
- revision_form = RevisionForm(question, latest_revision)
- form = EditQuestionForm(question, latest_revision)
- return render_to_response('question_edit.html', {
- 'question': question,
- 'revision_form': revision_form,
- 'form' : form,
- 'tags' : _get_tags_cache_json()
- }, context_instance=RequestContext(request))
-
-
-@login_required
-def edit_answer(request, id):
- answer = get_object_or_404(Answer, id=id)
- if answer.deleted and not can_view_deleted_post(request.user, answer):
- raise Http404
- elif not can_edit_post(request.user, answer):
- raise Http404
- else:
- latest_revision = answer.get_latest_revision()
- if request.method == "POST":
- if 'select_revision' in request.POST:
- # user has changed revistion number
- revision_form = RevisionForm(answer, latest_revision, request.POST)
- if revision_form.is_valid():
- # Replace with those from the selected revision
- form = EditAnswerForm(answer,
- AnswerRevision.objects.get(answer=answer,
- revision=revision_form.cleaned_data['revision']))
- else:
- form = EditAnswerForm(answer, latest_revision, request.POST)
- else:
- form = EditAnswerForm(answer, latest_revision, request.POST)
- if form.is_valid():
- html = sanitize_html(markdowner.convert(form.cleaned_data['text']))
- if form.has_changed():
- edited_at = datetime.datetime.now()
- updated_fields = {
- 'last_edited_at': edited_at,
- 'last_edited_by': request.user,
- 'html': html,
- }
- Answer.objects.filter(id=answer.id).update(**updated_fields)
-
- revision = AnswerRevision(
- answer = answer,
- author = request.user,
- revised_at = edited_at,
- text = form.cleaned_data['text']
- )
-
- if form.cleaned_data['summary']:
- revision.summary = form.cleaned_data['summary']
- else:
- revision.summary = 'No.%s Revision' % latest_revision.revision
- revision.save()
-
- answer.question.last_activity_at = edited_at
- answer.question.last_activity_by = request.user
- answer.question.save()
-
- return HttpResponseRedirect(answer.get_absolute_url())
- else:
- revision_form = RevisionForm(answer, latest_revision)
- form = EditAnswerForm(answer, latest_revision)
- return render_to_response('answer_edit.html', {
- 'answer': answer,
- 'revision_form': revision_form,
- 'form' : form,
- }, context_instance=RequestContext(request))
-
-QUESTION_REVISION_TEMPLATE = ('<h1>%(title)s</h1>\n'
- '<div class="text">%(html)s</div>\n'
- '<div class="tags">%(tags)s</div>')
-def question_revisions(request, id):
- post = get_object_or_404(Question, id=id)
- revisions = list(post.revisions.all())
- for i, revision in enumerate(revisions):
- revision.html = QUESTION_REVISION_TEMPLATE % {
- 'title': revision.title,
- 'html': sanitize_html(markdowner.convert(revision.text)),
- 'tags': ' '.join(['<a class="post-tag">%s</a>' % tag
- for tag in revision.tagnames.split(' ')]),
- }
- if i > 0:
- revisions[i - 1].diff = htmldiff(revision.html,
- revisions[i - 1].html)
- else:
- revisions[i - 1].diff = QUESTION_REVISION_TEMPLATE % {
- 'title': revisions[0].title,
- 'html': sanitize_html(markdowner.convert(revisions[0].text)),
- 'tags': ' '.join(['<a class="post-tag">%s</a>' % tag
- for tag in revisions[0].tagnames.split(' ')]),
- }
- revisions[i - 1].summary = None
- return render_to_response('revisions_question.html', {
- 'post': post,
- 'revisions': revisions,
- }, context_instance=RequestContext(request))
-
-ANSWER_REVISION_TEMPLATE = ('<div class="text">%(html)s</div>')
-def answer_revisions(request, id):
- post = get_object_or_404(Answer, id=id)
- revisions = list(post.revisions.all())
- for i, revision in enumerate(revisions):
- revision.html = ANSWER_REVISION_TEMPLATE % {
- 'html': sanitize_html(markdowner.convert(revision.text))
- }
- if i > 0:
- revisions[i - 1].diff = htmldiff(revision.html,
- revisions[i - 1].html)
- else:
- revisions[i - 1].diff = revisions[i-1].text
- revisions[i - 1].summary = None
- return render_to_response('revisions_answer.html', {
- 'post': post,
- 'revisions': revisions,
- }, context_instance=RequestContext(request))
-
-#TODO: allow anynomus
-@login_required
-def answer(request, id):
- question = get_object_or_404(Question, id=id)
- if request.method == "POST":
- form = AnswerForm(question, request.POST)
- if form.is_valid():
- update_time = datetime.datetime.now()
- answer = Answer(
- question = question,
- author = request.user,
- added_at = update_time,
- wiki = form.cleaned_data['wiki'],
- html = sanitize_html(markdowner.convert(form.cleaned_data['text'])),
- )
- if answer.wiki:
- answer.last_edited_by = answer.author
- answer.last_edited_at = update_time
- answer.wikified_at = update_time
-
- answer.save()
- Question.objects.update_answer_count(question)
-
- question = get_object_or_404(Question, id=id)
- question.last_activity_at = update_time
- question.last_activity_by = request.user
- question.save()
-
- AnswerRevision.objects.create(
- answer = answer,
- revision = 1,
- author = request.user,
- revised_at = update_time,
- summary = CONST['default_version'],
- text = form.cleaned_data['text']
- )
-
- return HttpResponseRedirect(question.get_absolute_url())
-
-def tags(request):
- stag = ""
- is_paginated = True
- sortby = request.GET.get('sort', 'used')
- try:
- page = int(request.GET.get('page', '1'))
- except ValueError:
- page = 1
-
- if request.method == "GET":
- stag = request.GET.get("q", "").strip()
- if stag is not None:
- objects_list = Paginator(Tag.objects.filter(deleted=False).exclude(used_count=0).extra(where=['name like %s'], params=['%' + stag + '%']), DEFAULT_PAGE_SIZE)
- else:
- if sortby == "name":
- objects_list = Paginator(Tag.objects.all().filter(deleted=False).exclude(used_count=0).order_by("name"), DEFAULT_PAGE_SIZE)
- else:
- objects_list = Paginator(Tag.objects.all().filter(deleted=False).exclude(used_count=0).order_by("-used_count"), DEFAULT_PAGE_SIZE)
-
- try:
- tags = objects_list.page(page)
- except (EmptyPage, InvalidPage):
- tags = objects_list.page(objects_list.num_pages)
-
- return render_to_response('tags.html', {
- "tags" : tags,
- "stag" : stag,
- "tab_id" : sortby,
- "keywords" : stag,
- "context" : {
- 'is_paginated' : is_paginated,
- 'pages': objects_list.num_pages,
- 'page': page,
- 'has_previous': tags.has_previous(),
- 'has_next': tags.has_next(),
- 'previous': tags.previous_page_number(),
- 'next': tags.next_page_number(),
- 'base_url' : '/tags/?sort=%s&' % sortby
- }
-
- }, context_instance=RequestContext(request))
-
-def tag(request, tag):
- return questions(request, tagname=tag)
-
-def vote(request, id):
- """
- vote_type:
- acceptAnswer : 0,
- questionUpVote : 1,
- questionDownVote : 2,
- favorite : 4,
- answerUpVote: 5,
- answerDownVote:6,
- offensiveQuestion : 7,
- offensiveAnswer:8,
- removeQuestion: 9,
- removeAnswer:10
-
- accept answer code:
- response_data['allowed'] = -1, Accept his own answer 0, no allowed - Anonymous 1, Allowed - by default
- response_data['success'] = 0, failed 1, Success - by default
- response_data['status'] = 0, By default 1, Answer has been accepted already(Cancel)
-
- vote code:
- allowed = -3, Don't have enough votes left
- -2, Don't have enough reputation score
- -1, Vote his own post
- 0, no allowed - Anonymous
- 1, Allowed - by default
- status = 0, By default
- 1, Cancel
- 2, Vote is too old to be canceled
-
- offensive code:
- allowed = -3, Don't have enough flags left
- -2, Don't have enough reputation score to do this
- 0, not allowed
- 1, allowed
- status = 0, by default
- 1, can't do it again
- """
- response_data = {
- "allowed": 1,
- "success": 1,
- "status" : 0,
- "count" : 0,
- "message" : ''
- }
-
- def can_vote(vote_score, user):
- if vote_score == 1:
- return can_vote_up(request.user)
- else:
- return can_vote_down(request.user)
-
- try:
- if not request.user.is_authenticated():
- response_data['allowed'] = 0
- response_data['success'] = 0
-
- elif request.is_ajax():
- question = get_object_or_404(Question, id=id)
- vote_type = request.POST.get('type')
-
- #accept answer
- if vote_type == '0':
- answer_id = request.POST.get('postId')
- answer = get_object_or_404(Answer, id=answer_id)
- # make sure question author is current user
- if question.author == request.user:
- # answer user who is also question author is not allow to accept answer
- if answer.author == question.author:
- response_data['success'] = 0
- response_data['allowed'] = -1
- # check if answer has been accepted already
- elif answer.accepted:
- onAnswerAcceptCanceled(answer, request.user)
- response_data['status'] = 1
- else:
- # set other answers in this question not accepted first
- for answer_of_question in Answer.objects.get_answers_from_question(question, request.user):
- if answer_of_question != answer and answer_of_question.accepted:
- onAnswerAcceptCanceled(answer_of_question, request.user)
-
- #make sure retrieve data again after above author changes, they may have related data
- answer = get_object_or_404(Answer, id=answer_id)
- onAnswerAccept(answer, request.user)
- else:
- response_data['allowed'] = 0
- response_data['success'] = 0
- # favorite
- elif vote_type == '4':
- has_favorited = False
- fav_questions = FavoriteQuestion.objects.filter(question=question)
- # if the same question has been favorited before, then delete it
- if fav_questions is not None:
- for item in fav_questions:
- if item.user == request.user:
- item.delete()
- response_data['status'] = 1
- response_data['count'] = len(fav_questions) - 1
- if response_data['count'] < 0:
- response_data['count'] = 0
- has_favorited = True
- # if above deletion has not been executed, just insert a new favorite question
- if not has_favorited:
- new_item = FavoriteQuestion(question=question, user=request.user)
- new_item.save()
- response_data['count'] = FavoriteQuestion.objects.filter(question=question).count()
- Question.objects.update_favorite_count(question)
-
- elif vote_type in ['1', '2', '5', '6']:
- post_id = id
- post = question
- vote_score = 1
- if vote_type in ['5', '6']:
- answer_id = request.POST.get('postId')
- answer = get_object_or_404(Answer, id=answer_id)
- post_id = answer_id
- post = answer
- if vote_type in ['2', '6']:
- vote_score = -1
-
- if post.author == request.user:
- response_data['allowed'] = -1
- elif not can_vote(vote_score, request.user):
- response_data['allowed'] = -2
- elif post.votes.filter(user=request.user).count() > 0:
- vote = post.votes.filter(user=request.user)[0]
- # unvote should be less than certain time
- if (datetime.datetime.now().day - vote.voted_at.day) >= VOTE_RULES['scope_deny_unvote_days']:
- response_data['status'] = 2
- else:
- voted = vote.vote
- if voted > 0:
- # cancel upvote
- onUpVotedCanceled(vote, post, request.user)
-
- else:
- # cancel downvote
- onDownVotedCanceled(vote, post, request.user)
-
- response_data['status'] = 1
- response_data['count'] = post.score
- elif Vote.objects.get_votes_count_today_from_user(request.user) >= VOTE_RULES['scope_votes_per_user_per_day']:
- response_data['allowed'] = -3
- else:
- vote = Vote(user=request.user, content_object=post, vote=vote_score, voted_at=datetime.datetime.now())
- if vote_score > 0:
- # upvote
- onUpVoted(vote, post, request.user)
- else:
- # downvote
- onDownVoted(vote, post, request.user)
-
- votes_left = VOTE_RULES['scope_votes_per_user_per_day'] - Vote.objects.get_votes_count_today_from_user(request.user)
- if votes_left <= VOTE_RULES['scope_warn_votes_left']:
- response_data['message'] = u'%s votes left' % votes_left
- response_data['count'] = post.score
- elif vote_type in ['7', '8']:
- post = question
- post_id = id
- if vote_type == '8':
- post_id = request.POST.get('postId')
- post = get_object_or_404(Answer, id=post_id)
-
- if FlaggedItem.objects.get_flagged_items_count_today(request.user) >= VOTE_RULES['scope_flags_per_user_per_day']:
- response_data['allowed'] = -3
- elif not can_flag_offensive(request.user):
- response_data['allowed'] = -2
- elif post.flagged_items.filter(user=request.user).count() > 0:
- response_data['status'] = 1
- else:
- item = FlaggedItem(user=request.user, content_object=post, flagged_at=datetime.datetime.now())
- onFlaggedItem(item, post, request.user)
- response_data['count'] = post.offensive_flag_count
- # send signal when question or answer be marked offensive
- mark_offensive.send(sender=post.__class__, instance=post, mark_by=request.user)
- elif vote_type in ['9', '10']:
- post = question
- post_id = id
- if vote_type == '10':
- post_id = request.POST.get('postId')
- post = get_object_or_404(Answer, id=post_id)
-
- if not can_delete_post(request.user, post):
- response_data['allowed'] = -2
- elif post.deleted:
- onDeleteCanceled(post, request.user)
- response_data['status'] = 1
- else:
- onDeleted(post, request.user)
- delete_post_or_answer.send(sender=post.__class__, instance=post, delete_by=request.user)
- else:
- response_data['success'] = 0
- response_data['message'] = u'Request mode is not supported. Please try again.'
-
- data = simplejson.dumps(response_data)
-
- except Exception, e:
- response_data['message'] = str(e)
- data = simplejson.dumps(response_data)
- return HttpResponse(data, mimetype="application/json")
-
-def users(request):
- is_paginated = True
- sortby = request.GET.get('sort', 'reputation')
- suser = request.REQUEST.get('q', "")
- try:
- page = int(request.GET.get('page', '1'))
- except ValueError:
- page = 1
-
- if suser == "":
- if sortby == "newest":
- objects_list = Paginator(User.objects.all().order_by('-date_joined'), USERS_PAGE_SIZE)
- elif sortby == "last":
- objects_list = Paginator(User.objects.all().order_by('date_joined'), USERS_PAGE_SIZE)
- elif sortby == "user":
- objects_list = Paginator(User.objects.all().order_by('username'), USERS_PAGE_SIZE)
- # default
- else:
- objects_list = Paginator(User.objects.all().order_by('-reputation'), USERS_PAGE_SIZE)
- base_url = '/users/?sort=%s&' % sortby
- else:
- sortby = "reputation"
- objects_list = Paginator(User.objects.extra(where=['username like %s'], params=['%' + suser + '%']).order_by('-reputation'), USERS_PAGE_SIZE)
- base_url = '/users/?name=%s&sort=%s&' % (suser, sortby)
-
- try:
- users = objects_list.page(page)
- except (EmptyPage, InvalidPage):
- users = objects_list.page(objects_list.num_pages)
-
- return render_to_response('users.html', {
- "users" : users,
- "suser" : suser,
- "keywords" : suser,
- "tab_id" : sortby,
- "context" : {
- 'is_paginated' : is_paginated,
- 'pages': objects_list.num_pages,
- 'page': page,
- 'has_previous': users.has_previous(),
- 'has_next': users.has_next(),
- 'previous': users.previous_page_number(),
- 'next': users.next_page_number(),
- 'base_url' : base_url
- }
-
- }, context_instance=RequestContext(request))
-
-def user(request, id):
- sort = request.GET.get('sort', 'stats')
- user_view = dict((v.id, v) for v in USER_TEMPLATE_VIEWS).get(sort, USER_TEMPLATE_VIEWS[0])
- from forum import views
- func = getattr(views, user_view.view_name)
- return func(request, id, user_view)
-
-@login_required
-def edit_user(request, id):
- user = get_object_or_404(User, id=id)
- if request.user != user:
- raise Http404
- if request.method == "POST":
- form = EditUserForm(user, request.POST)
- if form.is_valid():
- user.email = sanitize_html(form.cleaned_data['email'])
- user.real_name = sanitize_html(form.cleaned_data['realname'])
- user.website = sanitize_html(form.cleaned_data['website'])
- user.location = sanitize_html(form.cleaned_data['city'])
- user.date_of_birth = sanitize_html(form.cleaned_data['birthday'])
- if len(user.date_of_birth) == 0:
- user.date_of_birth = '1900-01-01'
- user.about = sanitize_html(form.cleaned_data['about'])
-
- user.save()
- # send user updated singal if full fields have been updated
- if user.email and user.real_name and user.website and user.location and \
- user.date_of_birth and user.about:
- user_updated.send(sender=user.__class__, instance=user, updated_by=user)
- return HttpResponseRedirect(user.get_profile_url())
- else:
- form = EditUserForm(user)
- return render_to_response('user_edit.html', {
- 'form' : form,
- }, context_instance=RequestContext(request))
-
-def user_stats(request, user_id, user_view):
- user = get_object_or_404(User, id=user_id)
- questions = Question.objects.extra(
- select={
- 'vote_count' : 'question.score',
- 'favorited_myself' : 'SELECT count(*) FROM favorite_question f WHERE f.user_id = %s AND f.question_id = question.id',
- 'la_user_id' : 'auth_user.id',
- 'la_username' : 'auth_user.username',
- 'la_user_gold' : 'auth_user.gold',
- 'la_user_silver' : 'auth_user.silver',
- 'la_user_bronze' : 'auth_user.bronze',
- 'la_user_reputation' : 'auth_user.reputation'
- },
- select_params=[user_id],
- tables=['question', 'auth_user'],
- where=['question.deleted = 0 AND question.author_id=%s AND question.last_activity_by_id = auth_user.id'],
- params=[user_id],
- order_by=['-vote_count', '-last_activity_at']
- ).values('vote_count',
- 'favorited_myself',
- 'id',
- 'title',
- 'author_id',
- 'added_at',
- 'answer_accepted',
- 'answer_count',
- 'comment_count',
- 'view_count',
- 'favourite_count',
- 'summary',
- 'tagnames',
- 'vote_up_count',
- 'vote_down_count',
- 'last_activity_at',
- 'la_user_id',
- 'la_username',
- 'la_user_gold',
- 'la_user_silver',
- 'la_user_bronze',
- 'la_user_reputation')[:100]
-
- answered_questions = Question.objects.extra(
- select={
- 'vote_up_count' : 'answer.vote_up_count',
- 'vote_down_count' : 'answer.vote_down_count',
- 'answer_id' : 'answer.id',
- 'accepted' : 'answer.accepted',
- 'vote_count' : 'answer.score',
- 'comment_count' : 'answer.comment_count'
- },
- tables=['question', 'answer'],
- where=['answer.deleted=0 AND answer.author_id=%s AND answer.question_id=question.id'],
- params=[user_id],
- order_by=['-vote_count', '-answer_id'],
- select_params=[user_id]
- ).distinct().values('comment_count',
- 'id',
- 'answer_id',
- 'title',
- 'author_id',
- 'accepted',
- 'vote_count',
- 'answer_count',
- 'vote_up_count',
- 'vote_down_count')[:100]
- up_votes = Vote.objects.get_up_vote_count_from_user(user)
- down_votes = Vote.objects.get_down_vote_count_from_user(user)
- votes_today = Vote.objects.get_votes_count_today_from_user(user)
- votes_total = VOTE_RULES['scope_votes_per_user_per_day']
- tags = user.created_tags.all().order_by('-used_count')[:50]
- awards = Award.objects.extra(
- select={'id': 'badge.id', 'count': 'count(badge_id)', 'name':'badge.name', 'description': 'badge.description', 'type': 'badge.type'},
- tables=['award', 'badge'],
- order_by=['-awarded_at'],
- where=['user_id=%s AND badge_id=badge.id'],
- params=[user.id]
- ).values('id', 'count', 'name', 'description', 'type')
- total_awards = awards.count()
- awards.query.group_by = ['badge_id']
-
- return render_to_response(user_view.template_file,{
- "tab_name" : user_view.id,
- "tab_description" : user_view.tab_description,
- "page_title" : user_view.page_title,
- "view_user" : user,
- "questions" : questions,
- "answered_questions" : answered_questions,
- "up_votes" : up_votes,
- "down_votes" : down_votes,
- "total_votes": up_votes + down_votes,
- "votes_today_left": votes_total-votes_today,
- "votes_total_per_day": votes_total,
- "tags" : tags,
- "awards": awards,
- "total_awards" : total_awards,
- }, context_instance=RequestContext(request))
-
-def user_recent(request, user_id, user_view):
- user = get_object_or_404(User, id=user_id)
- def get_type_name(type_id):
- for item in TYPE_ACTIVITY:
- if type_id in item:
- return item[1]
-
- class Event:
- def __init__(self, time, type, title, summary, answer_id, question_id):
- self.time = time
- self.type = get_type_name(type)
- self.type_id = type
- self.title = title
- self.summary = summary
- self.title_link = u'/questions/%s/%s#%s' %(question_id, title, answer_id)\
- if int(answer_id) > 0 else u'/questions/%s/%s' %(question_id, title)
- class AwardEvent:
- def __init__(self, time, type, id):
- self.time = time
- self.type = get_type_name(type)
- self.type_id = type
- self.badge = get_object_or_404(Badge, id=id)
-
- activities = []
- # ask questions
- questions = Activity.objects.extra(
- select={
- 'title' : 'question.title',
- 'question_id' : 'question.id',
- 'active_at' : 'activity.active_at',
- 'activity_type' : 'activity.activity_type'
- },
- tables=['activity', 'question'],
- where=['activity.content_type_id = %s AND activity.object_id = ' +
- 'question.id AND activity.user_id = %s AND activity.activity_type = %s'],
- params=[question_type_id, user_id, TYPE_ACTIVITY_ASK_QUESTION],
- order_by=['-activity.active_at']
- ).values(
- 'title',
- 'question_id',
- 'active_at',
- 'activity_type'
- )
- if len(questions) > 0:
- questions = [(Event(q['active_at'], q['activity_type'], q['title'], '', '0', \
- q['question_id'])) for q in questions]
- activities.extend(questions)
-
- # answers
- answers = Activity.objects.extra(
- select={
- 'title' : 'question.title',
- 'question_id' : 'question.id',
- 'answer_id' : 'answer.id',
- 'active_at' : 'activity.active_at',
- 'activity_type' : 'activity.activity_type'
- },
- tables=['activity', 'answer', 'question'],
- where=['activity.content_type_id = %s AND activity.object_id = answer.id AND ' +
- 'answer.question_id=question.id AND activity.user_id=%s AND activity.activity_type=%s'],
- params=[answer_type_id, user_id, TYPE_ACTIVITY_ANSWER],
- order_by=['-activity.active_at']
- ).values(
- 'title',
- 'question_id',
- 'answer_id',
- 'active_at',
- 'activity_type'
- )
- if len(answers) > 0:
- answers = [(Event(q['active_at'], q['activity_type'], q['title'], '', q['answer_id'], \
- q['question_id'])) for q in answers]
- activities.extend(answers)
-
- # question comments
- comments = Activity.objects.extra(
- select={
- 'title' : 'question.title',
- 'question_id' : 'comment.object_id',
- 'added_at' : 'comment.added_at',
- 'activity_type' : 'activity.activity_type'
- },
- tables=['activity', 'question', 'comment'],
-
- where=['activity.content_type_id = %s AND activity.object_id = comment.id AND '+
- 'activity.user_id = comment.user_id AND comment.object_id=question.id AND '+
- 'comment.content_type_id=%s AND activity.user_id = %s AND activity.activity_type=%s'],
- params=[comment_type_id, question_type_id, user_id, TYPE_ACTIVITY_COMMENT_QUESTION],
- order_by=['-comment.added_at']
- ).values(
- 'title',
- 'question_id',
- 'added_at',
- 'activity_type'
- )
-
- if len(comments) > 0:
- comments = [(Event(q['added_at'], q['activity_type'], q['title'], '', '0', \
- q['question_id'])) for q in comments]
- activities.extend(comments)
-
- # answer comments
- comments = Activity.objects.extra(
- select={
- 'title' : 'question.title',
- 'question_id' : 'question.id',
- 'answer_id' : 'answer.id',
- 'added_at' : 'comment.added_at',
- 'activity_type' : 'activity.activity_type'
- },
- tables=['activity', 'question', 'answer', 'comment'],
-
- where=['activity.content_type_id = %s AND activity.object_id = comment.id AND '+
- 'activity.user_id = comment.user_id AND comment.object_id=answer.id AND '+
- 'comment.content_type_id=%s AND question.id = answer.question_id AND '+
- 'activity.user_id = %s AND activity.activity_type=%s'],
- params=[comment_type_id, answer_type_id, user_id, TYPE_ACTIVITY_COMMENT_ANSWER],
- order_by=['-comment.added_at']
- ).values(
- 'title',
- 'question_id',
- 'answer_id',
- 'added_at',
- 'activity_type'
- )
-
- if len(comments) > 0:
- comments = [(Event(q['added_at'], q['activity_type'], q['title'], '', q['answer_id'], \
- q['question_id'])) for q in comments]
- activities.extend(comments)
-
- # question revisions
- revisions = Activity.objects.extra(
- select={
- 'title' : 'question_revision.title',
- 'question_id' : 'question_revision.question_id',
- 'added_at' : 'activity.active_at',
- 'activity_type' : 'activity.activity_type',
- 'summary' : 'question_revision.summary'
- },
- tables=['activity', 'question_revision'],
- where=['activity.content_type_id = %s AND activity.object_id = question_revision.id AND '+
- 'activity.user_id = question_revision.author_id AND activity.user_id = %s AND '+
- 'activity.activity_type=%s'],
- params=[question_revision_type_id, user_id, TYPE_ACTIVITY_UPDATE_QUESTION],
- order_by=['-activity.active_at']
- ).values(
- 'title',
- 'question_id',
- 'added_at',
- 'activity_type',
- 'summary'
- )
-
- if len(revisions) > 0:
- revisions = [(Event(q['added_at'], q['activity_type'], q['title'], q['summary'], '0', \
- q['question_id'])) for q in revisions]
- activities.extend(revisions)
-
- # answer revisions
- revisions = Activity.objects.extra(
- select={
- 'title' : 'question.title',
- 'question_id' : 'question.id',
- 'answer_id' : 'answer.id',
- 'added_at' : 'activity.active_at',
- 'activity_type' : 'activity.activity_type',
- 'summary' : 'answer_revision.summary'
- },
- tables=['activity', 'answer_revision', 'question', 'answer'],
-
- where=['activity.content_type_id = %s AND activity.object_id = answer_revision.id AND '+
- 'activity.user_id = answer_revision.author_id AND activity.user_id = %s AND '+
- 'answer_revision.answer_id=answer.id AND answer.question_id = question.id AND '+
- 'activity.activity_type=%s'],
- params=[answer_revision_type_id, user_id, TYPE_ACTIVITY_UPDATE_ANSWER],
- order_by=['-activity.active_at']
- ).values(
- 'title',
- 'question_id',
- 'added_at',
- 'answer_id',
- 'activity_type',
- 'summary'
- )
-
- if len(revisions) > 0:
- revisions = [(Event(q['added_at'], q['activity_type'], q['title'], q['summary'], \
- q['answer_id'], q['question_id'])) for q in revisions]
- activities.extend(revisions)
-
- # accepted answers
- accept_answers = Activity.objects.extra(
- select={
- 'title' : 'question.title',
- 'question_id' : 'question.id',
- 'added_at' : 'activity.active_at',
- 'activity_type' : 'activity.activity_type',
- },
- tables=['activity', 'answer', 'question'],
- where=['activity.content_type_id = %s AND activity.object_id = answer.id AND '+
- 'activity.user_id = question.author_id AND activity.user_id = %s AND '+
- 'answer.question_id=question.id AND activity.activity_type=%s'],
- params=[answer_type_id, user_id, TYPE_ACTIVITY_MARK_ANSWER],
- order_by=['-activity.active_at']
- ).values(
- 'title',
- 'question_id',
- 'added_at',
- 'activity_type',
- )
- if len(accept_answers) > 0:
- accept_answers = [(Event(q['added_at'], q['activity_type'], q['title'], '', '0', \
- q['question_id'])) for q in accept_answers]
- activities.extend(accept_answers)
- #award history
- awards = Activity.objects.extra(
- select={
- 'badge_id' : 'badge.id',
- 'awarded_at': 'award.awarded_at',
- 'activity_type' : 'activity.activity_type'
- },
- tables=['activity', 'award', 'badge'],
- where=['activity.user_id = award.user_id AND activity.user_id = %s AND '+
- 'award.badge_id=badge.id AND activity.object_id=award.id AND activity.activity_type=%s'],
- params=[user_id, TYPE_ACTIVITY_PRIZE],
- order_by=['-activity.active_at']
- ).values(
- 'badge_id',
- 'awarded_at',
- 'activity_type'
- )
- if len(awards) > 0:
- awards = [(AwardEvent(q['awarded_at'], q['activity_type'], q['badge_id'])) for q in awards]
- activities.extend(awards)
-
- activities.sort(lambda x,y: cmp(y.time, x.time))
-
- return render_to_response(user_view.template_file,{
- "tab_name" : user_view.id,
- "tab_description" : user_view.tab_description,
- "page_title" : user_view.page_title,
- "view_user" : user,
- "activities" : activities[:user_view.data_size]
- }, context_instance=RequestContext(request))
-
-def user_responses(request, user_id, user_view):
- """
- We list answers for question, comments, and answer accepted by others for this user.
- """
- class Response:
- def __init__(self, type, title, question_id, answer_id, time, username, user_id, content):
- self.type = type
- self.title = title
- self.titlelink = u'/questions/%s/%s#%s' % (question_id, title, answer_id)
- self.time = time
- self.userlink = u'/users/%s/%s/' % (user_id, username)
- self.username = username
- self.content = u'%s ...' % strip_tags(content)[:300]
-
- def __unicode__(self):
- return u'%s %s' % (self.type, self.titlelink)
-
- user = get_object_or_404(User, id=user_id)
- responses = []
- answers = Answer.objects.extra(
- select={
- 'title' : 'question.title',
- 'question_id' : 'question.id',
- 'answer_id' : 'answer.id',
- 'added_at' : 'answer.added_at',
- 'html' : 'answer.html',
- 'username' : 'auth_user.username',
- 'user_id' : 'auth_user.id'
- },
- select_params=[user_id],
- tables=['answer', 'question', 'auth_user'],
- where=['answer.question_id = question.id AND answer.deleted=0 AND question.deleted = 0 AND '+
- 'question.author_id = %s AND answer.author_id <> %s AND answer.author_id=auth_user.id'],
- params=[user_id, user_id],
- order_by=['-answer.id']
- ).values(
- 'title',
- 'question_id',
- 'answer_id',
- 'added_at',
- 'html',
- 'username',
- 'user_id'
- )
- if len(answers) > 0:
- answers = [(Response(TYPE_RESPONSE['QUESTION_ANSWERED'], a['title'], a['question_id'],
- a['answer_id'], a['added_at'], a['username'], a['user_id'], a['html'])) for a in answers]
- responses.extend(answers)
-
-
- # question comments
- comments = Comment.objects.extra(
- select={
- 'title' : 'question.title',
- 'question_id' : 'comment.object_id',
- 'added_at' : 'comment.added_at',
- 'comment' : 'comment.comment',
- 'username' : 'auth_user.username',
- 'user_id' : 'auth_user.id'
- },
- tables=['question', 'auth_user', 'comment'],
- where=['question.deleted = 0 AND question.author_id = %s AND comment.object_id=question.id AND '+
- 'comment.content_type_id=%s AND comment.user_id <> %s AND comment.user_id = auth_user.id'],
- params=[user_id, question_type_id, user_id],
- order_by=['-comment.added_at']
- ).values(
- 'title',
- 'question_id',
- 'added_at',
- 'comment',
- 'username',
- 'user_id'
- )
-
- if len(comments) > 0:
- comments = [(Response(TYPE_RESPONSE['QUESTION_COMMENTED'], c['title'], c['question_id'],
- '', c['added_at'], c['username'], c['user_id'], c['comment'])) for c in comments]
- responses.extend(comments)
-
- # answer comments
- comments = Comment.objects.extra(
- select={
- 'title' : 'question.title',
- 'question_id' : 'question.id',
- 'answer_id' : 'answer.id',
- 'added_at' : 'comment.added_at',
- 'comment' : 'comment.comment',
- 'username' : 'auth_user.username',
- 'user_id' : 'auth_user.id'
- },
- tables=['answer', 'auth_user', 'comment', 'question'],
- where=['answer.deleted = 0 AND answer.author_id = %s AND comment.object_id=answer.id AND '+
- 'comment.content_type_id=%s AND comment.user_id <> %s AND comment.user_id = auth_user.id '+
- 'AND question.id = answer.question_id'],
- params=[user_id, answer_type_id, user_id],
- order_by=['-comment.added_at']
- ).values(
- 'title',
- 'question_id',
- 'answer_id',
- 'added_at',
- 'comment',
- 'username',
- 'user_id'
- )
-
- if len(comments) > 0:
- comments = [(Response(TYPE_RESPONSE['ANSWER_COMMENTED'], c['title'], c['question_id'],
- c['answer_id'], c['added_at'], c['username'], c['user_id'], c['comment'])) for c in comments]
- responses.extend(comments)
-
- # answer has been accepted
- answers = Answer.objects.extra(
- select={
- 'title' : 'question.title',
- 'question_id' : 'question.id',
- 'answer_id' : 'answer.id',
- 'added_at' : 'answer.accepted_at',
- 'html' : 'answer.html',
- 'username' : 'auth_user.username',
- 'user_id' : 'auth_user.id'
- },
- select_params=[user_id],
- tables=['answer', 'question', 'auth_user'],
- where=['answer.question_id = question.id AND answer.deleted=0 AND question.deleted = 0 AND '+
- 'answer.author_id = %s AND answer.accepted=1 AND question.author_id=auth_user.id'],
- params=[user_id],
- order_by=['-answer.id']
- ).values(
- 'title',
- 'question_id',
- 'answer_id',
- 'added_at',
- 'html',
- 'username',
- 'user_id'
- )
- if len(answers) > 0:
- answers = [(Response(TYPE_RESPONSE['ANSWER_ACCEPTED'], a['title'], a['question_id'],
- a['answer_id'], a['added_at'], a['username'], a['user_id'], a['html'])) for a in answers]
- responses.extend(answers)
-
- # sort posts by time
- responses.sort(lambda x,y: cmp(y.time, x.time))
-
- return render_to_response(user_view.template_file,{
- "tab_name" : user_view.id,
- "tab_description" : user_view.tab_description,
- "page_title" : user_view.page_title,
- "view_user" : user,
- "responses" : responses[:user_view.data_size],
-
- }, context_instance=RequestContext(request))
-
-def user_votes(request, user_id, user_view):
- user = get_object_or_404(User, id=user_id)
- if not can_view_user_votes(request.user, user):
- raise Http404
- votes = []
- question_votes = Vote.objects.extra(
- select={
- 'title' : 'question.title',
- 'question_id' : 'question.id',
- 'answer_id' : 0,
- 'voted_at' : 'vote.voted_at',
- 'vote' : 'vote',
- },
- select_params=[user_id],
- tables=['vote', 'question', 'auth_user'],
- where=['vote.content_type_id = %s AND vote.user_id = %s AND vote.object_id = question.id '+
- 'AND vote.user_id=auth_user.id'],
- params=[question_type_id, user_id],
- order_by=['-vote.id']
- ).values(
- 'title',
- 'question_id',
- 'answer_id',
- 'voted_at',
- 'vote',
- )
- if(len(question_votes) > 0):
- votes.extend(question_votes)
-
- answer_votes = Vote.objects.extra(
- select={
- 'title' : 'question.title',
- 'question_id' : 'question.id',
- 'answer_id' : 'answer.id',
- 'voted_at' : 'vote.voted_at',
- 'vote' : 'vote',
- },
- select_params=[user_id],
- tables=['vote', 'answer', 'question', 'auth_user'],
- where=['vote.content_type_id = %s AND vote.user_id = %s AND vote.object_id = answer.id '+
- 'AND answer.question_id = question.id AND vote.user_id=auth_user.id'],
- params=[answer_type_id, user_id],
- order_by=['-vote.id']
- ).values(
- 'title',
- 'question_id',
- 'answer_id',
- 'voted_at',
- 'vote',
- )
- if(len(answer_votes) > 0):
- votes.extend(answer_votes)
- votes.sort(lambda x,y: cmp(y['voted_at'], x['voted_at']))
- return render_to_response(user_view.template_file,{
- "tab_name" : user_view.id,
- "tab_description" : user_view.tab_description,
- "page_title" : user_view.page_title,
- "view_user" : user,
- "votes" : votes[:user_view.data_size]
-
- }, context_instance=RequestContext(request))
-
-def user_reputation(request, user_id, user_view):
- user = get_object_or_404(User, id=user_id)
- reputation = Repute.objects.extra(
- select={'positive': 'sum(positive)', 'negative': 'sum(negative)', 'question_id':'question_id',
- 'title': 'question.title'},
- tables=['repute', 'question'],
- order_by=['-reputed_at'],
- where=['user_id=%s AND question_id=question.id'],
- params=[user.id]
- ).values('positive', 'negative', 'question_id', 'title', 'reputed_at', 'reputation')
-
- reputation.query.group_by = ['question_id']
-
-
- rep_list = []
- for rep in Repute.objects.filter(user=user).order_by('reputed_at'):
- dic = '[%s,%s]' % (calendar.timegm(rep.reputed_at.timetuple()) * 1000, rep.reputation)
- rep_list.append(dic)
- reps = ','.join(rep_list)
- reps = '[%s]' % reps
-
- return render_to_response(user_view.template_file,{
- "tab_name" : user_view.id,
- "tab_description" : user_view.tab_description,
- "page_title" : user_view.page_title,
- "view_user" : user,
- "reputation" : reputation,
- "reps" : reps
- }, context_instance=RequestContext(request))
-
-def user_favorites(request, user_id, user_view):
- user = get_object_or_404(User, id=user_id)
- questions = Question.objects.extra(
- select={
- 'vote_count' : 'question.vote_up_count + question.vote_down_count',
- 'favorited_myself' : 'SELECT count(*) FROM favorite_question f WHERE f.user_id = %s '+
- 'AND f.question_id = question.id',
- 'la_user_id' : 'auth_user.id',
- 'la_username' : 'auth_user.username',
- 'la_user_gold' : 'auth_user.gold',
- 'la_user_silver' : 'auth_user.silver',
- 'la_user_bronze' : 'auth_user.bronze',
- 'la_user_reputation' : 'auth_user.reputation'
- },
- select_params=[user_id],
- tables=['question', 'auth_user', 'favorite_question'],
- where=['question.deleted = 0 AND question.last_activity_by_id = auth_user.id '+
- 'AND favorite_question.question_id = question.id AND favorite_question.user_id = %s'],
- params=[user_id],
- order_by=['-vote_count', '-question.id']
- ).values('vote_count',
- 'favorited_myself',
- 'id',
- 'title',
- 'author_id',
- 'added_at',
- 'answer_accepted',
- 'answer_count',
- 'comment_count',
- 'view_count',
- 'favourite_count',
- 'summary',
- 'tagnames',
- 'vote_up_count',
- 'vote_down_count',
- 'last_activity_at',
- 'la_user_id',
- 'la_username',
- 'la_user_gold',
- 'la_user_silver',
- 'la_user_bronze',
- 'la_user_reputation')
- return render_to_response(user_view.template_file,{
- "tab_name" : user_view.id,
- "tab_description" : user_view.tab_description,
- "page_title" : user_view.page_title,
- "questions" : questions[:user_view.data_size],
- "view_user" : user
- }, context_instance=RequestContext(request))
-
-
-def user_preferences(request, user_id, user_view):
- user = get_object_or_404(User, id=user_id)
- return render_to_response(user_view.template_file,{
- "tab_name" : user_view.id,
- "tab_description" : user_view.tab_description,
- "page_title" : user_view.page_title,
- "view_user" : user,
- }, context_instance=RequestContext(request))
-
-def question_comments(request, id):
- question = get_object_or_404(Question, id=id)
- user = request.user
- return __comments(request, question, 'question', user)
-
-def answer_comments(request, id):
- answer = get_object_or_404(Answer, id=id)
- user = request.user
- return __comments(request, answer, 'answer', user)
-
-def __comments(request, obj, type, user):
- # only support get comments by ajax now
- if request.is_ajax():
- if request.method == "GET":
- return __generate_comments_json(obj, type, user)
- elif request.method == "POST":
- comment_data = request.POST.get('comment')
- comment = Comment(content_object=obj, comment=comment_data, user=request.user)
- comment.save()
- obj.comment_count = obj.comment_count + 1
- obj.save()
- return __generate_comments_json(obj, type, user)
-
-def __generate_comments_json(obj, type, user):
- comments = obj.comments.all().order_by('-id')
- # {"Id":6,"PostId":38589,"CreationDate":"an hour ago","Text":"hello there!","UserDisplayName":"Jarrod Dixon","UserUrl":"/users/3/jarrod-dixon","DeleteUrl":null}
- json_comments = []
- for comment in comments:
- comment_user = comment.user
- delete_url = ""
- if user != None and auth.can_delete_comment(user, comment):
- #/posts/392845/comments/219852/delete
- delete_url = "/" + type + "s/%s/comments/%s/delete/" % (obj.id, comment.id)
- json_comments.append({"id" : comment.id,
- "object_id" : obj.id,
- "add_date" : comment.added_at.strftime('%Y-%m-%d'),
- "text" : comment.comment,
- "user_display_name" : comment_user.username,
- "user_url" : "/users/%s/%s" % (comment_user.id, comment_user.username),
- "delete_url" : delete_url
- })
-
- data = simplejson.dumps(json_comments)
- return HttpResponse(data, mimetype="application/json")
-
-def delete_question_comment(request, question_id, comment_id):
- if request.is_ajax():
- question = get_object_or_404(Question, id=question_id)
- comment = get_object_or_404(Comment, id=comment_id)
-
- question.comments.remove(comment)
- question.comment_count = question.comment_count - 1
- question.save()
- user = request.user
- return __generate_comments_json(question, 'question', user)
-
-def delete_answer_comment(request, answer_id, comment_id):
- if request.is_ajax():
- answer = get_object_or_404(Answer, id=answer_id)
- comment = get_object_or_404(Comment, id=comment_id)
-
- answer.comments.remove(comment)
- answer.comment_count = answer.comment_count - 1
- answer.save()
- user = request.user
- return __generate_comments_json(answer, 'answer', user)
-
-def logout(request):
- url = request.GET.get('next')
- return render_to_response('logout.html', {
- 'next' : url,
- }, context_instance=RequestContext(request))
-
-def badges(request):
- badges = Badge.objects.all().order_by('type')
- my_badges = []
- if request.user.is_authenticated():
- my_badges = Award.objects.filter(user=request.user)
- my_badges.query.group_by = ['badge_id']
-
- return render_to_response('badges.html', {
- 'badges' : badges,
- 'mybadges' : my_badges,
- }, context_instance=RequestContext(request))
-
-def badge(request, id):
- badge = get_object_or_404(Badge, id=id)
- awards = Award.objects.extra(
- select={'id': 'auth_user.id',
- 'name': 'auth_user.username',
- 'rep':'auth_user.reputation',
- 'gold': 'auth_user.gold',
- 'silver': 'auth_user.silver',
- 'bronze': 'auth_user.bronze'},
- tables=['award', 'auth_user'],
- where=['badge_id=%s AND user_id=auth_user.id'],
- params=[id]
- ).values('id').distinct()
-
- return render_to_response('badge.html', {
- 'awards' : awards,
- 'badge' : badge,
- }, context_instance=RequestContext(request))
-
-def read_message(request):
- if request.method == "POST":
- if request.POST['formdata'] == 'required':
- request.session['message_silent'] = 1
-
- if request.user.is_authenticated():
- request.user.delete_messages()
- return HttpResponse('')
-
-def upload(request):
- class FileTypeNotAllow(Exception):
- pass
- class FileSizeNotAllow(Exception):
- pass
- class UploadPermissionNotAuthorized(Exception):
- pass
-
- #<result><msg><![CDATA[%s]]></msg><error><![CDATA[%s]]></error><file_url>%s</file_url></result>
- xml_template = "<result><msg><![CDATA[%s]]></msg><error><![CDATA[%s]]></error><file_url>%s</file_url></result>"
-
- try:
- f = request.FILES['file-upload']
- # check upload permission
- if not can_upload_files(request.user):
- raise UploadPermissionNotAuthorized
-
- # check file type
- file_name_suffix = os.path.splitext(f.name)[1].lower()
- if not file_name_suffix in settings.ALLOW_FILE_TYPES:
- raise FileTypeNotAllow
-
- # genetate new file name
- new_file_name = str(time.time()).replace('.', str(random.randint(0,100000))) + file_name_suffix
- # use default storage to store file
- default_storage.save(new_file_name, f)
- # check file size
- # byte
- size = default_storage.size(new_file_name)
- if size > settings.ALLOW_MAX_FILE_SIZE:
- default_storage.delete(new_file_name)
- raise FileSizeNotAllow
-
- result = xml_template % ('Good', '', default_storage.url(new_file_name))
- except UploadPermissionNotAuthorized:
- result = xml_template % ('', _('uploading images is limited to users with >60 reputation points'), '')
- except FileTypeNotAllow:
- result = xml_template % ('', _("allowed file types are 'jpg', 'jpeg', 'gif', 'bmp', 'png', 'tiff'"), '')
- except FileSizeNotAllow:
- result = xml_template % ('', _("maximum upload file size is %sK") % settings.ALLOW_MAX_FILE_SIZE / 1024, '')
- except Exception as e:
- result = xml_template % ('', _('Error uploading file. Please contact the site administrator. Thank you. %s' % e), '')
-
- return HttpResponse(result, mimetype="application/xml")
-
-def books(request):
- return HttpResponseRedirect("/books/mysql-zhaoyang")
-
-def book(request, short_name, unanswered=False):
- """
- 1. questions list
- 2. book info
- 3. author info and blog rss items
- """
- """
- List of Questions, Tagged questions, and Unanswered questions.
- """
- books = Book.objects.extra(where=['short_name = %s'], params=[short_name])
- match_count = len(books)
- if match_count == 0 :
- raise Http404
- else:
- # the book info
- book = books[0]
- # get author info
- author_info = BookAuthorInfo.objects.get(book=book)
- # get author rss info
- author_rss = BookAuthorRss.objects.filter(book=book)
-
- # get pagesize from session, if failed then get default value
- user_page_size = request.session.get("pagesize", QUESTIONS_PAGE_SIZE)
- # set pagesize equal to logon user specified value in database
- if request.user.is_authenticated() and request.user.questions_per_page > 0:
- user_page_size = request.user.questions_per_page
-
- try:
- page = int(request.GET.get('page', '1'))
- except ValueError:
- page = 1
-
- view_id = request.GET.get('sort', None)
- view_dic = {"latest":"-added_at", "active":"-last_activity_at", "hottest":"-answer_count", "mostvoted":"-score" }
- try:
- orderby = view_dic[view_id]
- except KeyError:
- view_id = "latest"
- orderby = "-added_at"
-
- # check if request is from tagged questions
- if unanswered:
- # check if request is from unanswered questions
- # Article.objects.filter(publications__id__exact=1)
- objects = Question.objects.filter(book__id__exact=book.id, deleted=False, answer_count=0).order_by(orderby)
- else:
- objects = Question.objects.filter(book__id__exact=book.id, deleted=False).order_by(orderby)
-
- # RISK - inner join queries
- objects = objects.select_related();
- objects_list = Paginator(objects, user_page_size)
- questions = objects_list.page(page)
-
- return render_to_response('book.html', {
- "book" : book,
- "author_info" : author_info,
- "author_rss" : author_rss,
- "questions" : questions,
- "context" : {
- 'is_paginated' : True,
- 'pages': objects_list.num_pages,
- 'page': page,
- 'has_previous': questions.has_previous(),
- 'has_next': questions.has_next(),
- 'previous': questions.previous_page_number(),
- 'next': questions.next_page_number(),
- 'base_url' : request.path + '?sort=%s&' % view_id,
- 'pagesize' : user_page_size
- }
- }, context_instance=RequestContext(request))
-
-@login_required
-def ask_book(request, short_name):
- if request.method == "POST":
- form = AskForm(request.POST)
- if form.is_valid():
- added_at = datetime.datetime.now()
- html = sanitize_html(markdowner.convert(form.cleaned_data['text']))
- question = Question(
- title = strip_tags(form.cleaned_data['title']),
- author = request.user,
- added_at = added_at,
- last_activity_at = added_at,
- last_activity_by = request.user,
- wiki = form.cleaned_data['wiki'],
- tagnames = form.cleaned_data['tags'].strip(),
- html = html,
- summary = strip_tags(html)[:120]
- )
- if question.wiki:
- question.last_edited_by = question.author
- question.last_edited_at = added_at
- question.wikified_at = added_at
-
- question.save()
-
- # create the first revision
- QuestionRevision.objects.create(
- question = question,
- revision = 1,
- title = question.title,
- author = request.user,
- revised_at = added_at,
- tagnames = question.tagnames,
- summary = CONST['default_version'],
- text = form.cleaned_data['text']
- )
-
- books = Book.objects.extra(where=['short_name = %s'], params=[short_name])
- match_count = len(books)
- if match_count == 1:
- # the book info
- book = books[0]
- book.questions.add(question)
-
- return HttpResponseRedirect(question.get_absolute_url())
- else:
- form = AskForm()
-
- tags = _get_tags_cache_json()
- return render_to_response('ask.html', {
- 'form' : form,
- 'tags' : tags,
- }, context_instance=RequestContext(request))
-
-def search(request):
- """
- Search by question, user and tag keywords.
- For questions now we only search keywords in question title.
- """
- if request.method == "GET":
- keywords = request.GET.get("q")
- search_type = request.GET.get("t")
- try:
- page = int(request.GET.get('page', '1'))
- except ValueError:
- page = 1
- if keywords is None:
- return HttpResponseRedirect('/')
- if search_type == 'tag':
- return HttpResponseRedirect('/tags/?q=%s&page=%s' % (keywords.strip(), page))
- elif search_type == "user":
- return HttpResponseRedirect('/users/?q=%s&page=%s' % (keywords.strip(), page))
- elif search_type == "question":
-
- template_file = "questions.html"
- # Set flag to False by default. If it is equal to True, then need to be saved.
- pagesize_changed = False
- # get pagesize from session, if failed then get default value
- user_page_size = request.session.get("pagesize", QUESTIONS_PAGE_SIZE)
- # set pagesize equal to logon user specified value in database
- if request.user.is_authenticated() and request.user.questions_per_page > 0:
- user_page_size = request.user.questions_per_page
-
- try:
- page = int(request.GET.get('page', '1'))
- # get new pagesize from UI selection
- pagesize = int(request.GET.get('pagesize', user_page_size))
- if pagesize <> user_page_size:
- pagesize_changed = True
-
- except ValueError:
- page = 1
- pagesize = user_page_size
-
- # save this pagesize to user database
- if pagesize_changed:
- request.session["pagesize"] = pagesize
- if request.user.is_authenticated():
- user = request.user
- user.questions_per_page = pagesize
- user.save()
-
- view_id = request.GET.get('sort', None)
- view_dic = {"latest":"-added_at", "active":"-last_activity_at", "hottest":"-answer_count", "mostvoted":"-score" }
- try:
- orderby = view_dic[view_id]
- except KeyError:
- view_id = "latest"
- orderby = "-added_at"
-
- objects = Question.objects.filter(deleted=False).extra(where=['title like %s'], params=['%' + keywords + '%']).order_by(orderby)
-
- # RISK - inner join queries
- objects = objects.select_related();
- objects_list = Paginator(objects, pagesize)
- questions = objects_list.page(page)
-
- # Get related tags from this page objects
- related_tags = []
- for question in questions.object_list:
- tags = list(question.tags.all())
- for tag in tags:
- if tag not in related_tags:
- related_tags.append(tag)
-
- return render_to_response(template_file, {
- "questions" : questions,
- "tab_id" : view_id,
- "questions_count" : objects_list.count,
- "tags" : related_tags,
- "searchtag" : None,
- "searchtitle" : keywords,
- "keywords" : keywords,
- "is_unanswered" : False,
- "context" : {
- 'is_paginated' : True,
- 'pages': objects_list.num_pages,
- 'page': page,
- 'has_previous': questions.has_previous(),
- 'has_next': questions.has_next(),
- 'previous': questions.previous_page_number(),
- 'next': questions.next_page_number(),
- 'base_url' : request.path + '?t=question&q=%s&sort=%s&' % (keywords, view_id),
- 'pagesize' : pagesize
- }}, context_instance=RequestContext(request))
-
- else:
- raise Http404
-
+# encoding:utf-8 +import os.path +import time, datetime, calendar, random +import logging +from urllib import quote, unquote +from django.conf import settings +from django.core.files.storage import default_storage +from django.shortcuts import render_to_response, get_object_or_404 +from django.contrib.auth.decorators import login_required +from django.http import HttpResponseRedirect, HttpResponse,Http404 +from django.core.paginator import Paginator, EmptyPage, InvalidPage +from django.template import RequestContext +from django.utils.html import * +from django.utils import simplejson +from django.core import serializers +from django.db import transaction +from django.contrib.contenttypes.models import ContentType +from django.utils.translation import ugettext as _ + +from utils.html import sanitize_html +from markdown2 import Markdown +#from lxml.html.diff import htmldiff +from forum.diff import textDiff as htmldiff +from forum.forms import * +from forum.models import * +from forum.auth import * +from forum.const import * +from forum.user import * +from forum import auth + +# used in index page +INDEX_PAGE_SIZE = 20 +INDEX_AWARD_SIZE = 15 +INDEX_TAGS_SIZE = 100 +# used in tags list +DEFAULT_PAGE_SIZE = 60 +# used in questions +QUESTIONS_PAGE_SIZE = 10 +# used in users +USERS_PAGE_SIZE = 35 +# used in answers +ANSWERS_PAGE_SIZE = 10 +markdowner = Markdown(html4tags=True) +question_type = ContentType.objects.get_for_model(Question) +answer_type = ContentType.objects.get_for_model(Answer) +comment_type = ContentType.objects.get_for_model(Comment) +question_revision_type = ContentType.objects.get_for_model(QuestionRevision) +answer_revision_type = ContentType.objects.get_for_model(AnswerRevision) +repute_type =ContentType.objects.get_for_model(Repute) +question_type_id = question_type.id +answer_type_id = answer_type.id +comment_type_id = comment_type.id +question_revision_type_id = question_revision_type.id +answer_revision_type_id = answer_revision_type.id +repute_type_id = repute_type.id +def _get_tags_cache_json(): + tags = Tag.objects.filter(deleted=False).all() + tags_list = [] + for tag in tags: + dic = {'n': tag.name, 'c': tag.used_count } + tags_list.append(dic) + tags = simplejson.dumps(tags_list) + return tags + +def index(request): + view_id = request.GET.get('sort', None) + view_dic = { + "latest":"-last_activity_at", + "hottest":"-answer_count", + "mostvoted":"-score", + "trans": "-last_activity_at" + } + try: + orderby = view_dic[view_id] + except KeyError: + view_id = "latest" + orderby = "-last_activity_at" + # group questions by author_id of 28,29 + if view_id == 'trans': + questions = Question.objects.get_translation_questions(orderby, INDEX_PAGE_SIZE) + else: + questions = Question.objects.get_questions_by_pagesize(orderby, INDEX_PAGE_SIZE) + # RISK - inner join queries + questions = questions.select_related() + tags = Tag.objects.get_valid_tags(INDEX_TAGS_SIZE) + + awards = Award.objects.get_recent_awards() + + return render_to_response('index.html', { + "questions" : questions, + "tab_id" : view_id, + "tags" : tags, + "awards" : awards[:INDEX_AWARD_SIZE], + }, context_instance=RequestContext(request)) + +def about(request): + return render_to_response('about.html', context_instance=RequestContext(request)) + +def faq(request): + return render_to_response('faq.html', context_instance=RequestContext(request)) + +def privacy(request): + return render_to_response('privacy.html', context_instance=RequestContext(request)) + +def unanswered(request): + return questions(request, unanswered=True) + +def questions(request, tagname=None, unanswered=False): + """ + List of Questions, Tagged questions, and Unanswered questions. + """ + # template file + # "questions.html" or "unanswered.html" + template_file = "questions.html" + # Set flag to False by default. If it is equal to True, then need to be saved. + pagesize_changed = False + # get pagesize from session, if failed then get default value + pagesize = request.session.get("pagesize") + try: + page = int(request.GET.get('page', '1')) + except ValueError: + page = 1 + + view_id = request.GET.get('sort', None) + view_dic = {"latest":"-added_at", "active":"-last_activity_at", "hottest":"-answer_count", "mostvoted":"-score" } + try: + orderby = view_dic[view_id] + except KeyError: + view_id = "latest" + orderby = "-added_at" + + # check if request is from tagged questions + if tagname is not None: + objects = Question.objects.get_questions_by_tag(tagname, orderby) + elif unanswered: + #check if request is from unanswered questions + template_file = "unanswered.html" + objects = Question.objects.get_unanswered_questions(orderby) + else: + objects = Question.objects.get_questions(orderby) + + # RISK - inner join queries + objects = objects.select_related(depth=1); + objects_list = Paginator(objects, pagesize) + questions = objects_list.page(page) + + # Get related tags from this page objects + if questions.object_list.count() > 0: + related_tags = Tag.objects.get_tags_by_questions(questions.object_list) + else: + related_tags = None + return render_to_response(template_file, { + "questions" : questions, + "tab_id" : view_id, + "questions_count" : objects_list.count, + "tags" : related_tags, + "searchtag" : tagname, + "is_unanswered" : unanswered, + "context" : { + 'is_paginated' : True, + 'pages': objects_list.num_pages, + 'page': page, + 'has_previous': questions.has_previous(), + 'has_next': questions.has_next(), + 'previous': questions.previous_page_number(), + 'next': questions.next_page_number(), + 'base_url' : request.path + '?sort=%s&' % view_id, + 'pagesize' : pagesize + }}, context_instance=RequestContext(request)) + +#TODO: allow anynomus user to ask question by providing email and username. +@login_required +def ask(request): + if request.method == "POST": + form = AskForm(request.POST) + if form.is_valid(): + added_at = datetime.datetime.now() + html = sanitize_html(markdowner.convert(form.cleaned_data['text'])) + question = Question( + title = strip_tags(form.cleaned_data['title']), + author = request.user, + added_at = added_at, + last_activity_at = added_at, + last_activity_by = request.user, + wiki = form.cleaned_data['wiki'], + tagnames = form.cleaned_data['tags'].strip(), + html = html, + summary = strip_tags(html)[:120] + ) + if question.wiki: + question.last_edited_by = question.author + question.last_edited_at = added_at + question.wikified_at = added_at + + question.save() + + # create the first revision + QuestionRevision.objects.create( + question = question, + revision = 1, + title = question.title, + author = request.user, + revised_at = added_at, + tagnames = question.tagnames, + summary = CONST['default_version'], + text = form.cleaned_data['text'] + ) + + return HttpResponseRedirect(question.get_absolute_url()) + + else: + form = AskForm() + + tags = _get_tags_cache_json() + return render_to_response('ask.html', { + 'form' : form, + 'tags' : tags, + }, context_instance=RequestContext(request)) + +def question(request, id): + try: + page = int(request.GET.get('page', '1')) + except ValueError: + page = 1 + view_id = request.GET.get('sort', 'votes') + view_dic = {"latest":"-added_at", "oldest":"added_at", "votes":"-score" } + try: + orderby = view_dic[view_id] + except KeyError: + view_id = "votes" + orderby = "-score" + + question = get_object_or_404(Question, id=id) + if question.deleted and not can_view_deleted_post(request.user, question): + raise Http404 + answer_form = AnswerForm(question) + answers = Answer.objects.get_answers_from_question(question, request.user) + answers = answers.select_related(depth=1) + + favorited = question.has_favorite_by_user(request.user) + question_vote = question.votes.select_related().filter(user=request.user) + if question_vote is not None and question_vote.count() > 0: + question_vote = question_vote[0] + + user_answer_votes = {} + for answer in answers: + vote = answer.get_user_vote(request.user) + if vote is not None and not user_answer_votes.has_key(answer.id): + vote_value = -1 + if vote.is_upvote(): + vote_value = 1 + user_answer_votes[answer.id] = vote_value + + + if answers is not None: + answers = answers.order_by("-accepted", orderby) + objects_list = Paginator(answers, ANSWERS_PAGE_SIZE) + page_objects = objects_list.page(page) + # update view count + Question.objects.update_view_count(question) + return render_to_response('question.html', { + "question" : question, + "question_vote" : question_vote, + "question_comment_count":question.comments.count(), + "answer" : answer_form, + "answers" : page_objects.object_list, + "user_answer_votes": user_answer_votes, + "tags" : question.tags.all(), + "tab_id" : view_id, + "favorited" : favorited, + "similar_questions" : Question.objects.get_similar_questions(question), + "context" : { + 'is_paginated' : True, + 'pages': objects_list.num_pages, + 'page': page, + 'has_previous': page_objects.has_previous(), + 'has_next': page_objects.has_next(), + 'previous': page_objects.previous_page_number(), + 'next': page_objects.next_page_number(), + 'base_url' : request.path + '?sort=%s&' % view_id, + 'extend_url' : "#sort-top" + } + }, context_instance=RequestContext(request)) + +@login_required +def close(request, id): + question = get_object_or_404(Question, id=id) + if not can_close_question(request.user, question): + return HttpResponse('Permission denied.') + if request.method == 'POST': + form = CloseForm(request.POST) + if form.is_valid(): + reason = form.cleaned_data['reason'] + question.closed = True + question.closed_by = request.user + question.closed_at = datetime.datetime.now() + question.close_reason = reason + question.save() + return HttpResponseRedirect(question.get_absolute_url()) + else: + form = CloseForm() + return render_to_response('close.html', { + 'form' : form, + 'question' : question, + }, context_instance=RequestContext(request)) + +@login_required +def reopen(request, id): + question = get_object_or_404(Question, id=id) + # open question + if not can_reopen_question(request.user, question): + return HttpResponse('Permission denied.') + if request.method == 'POST' : + Question.objects.filter(id=question.id).update(closed=False, + closed_by=None, closed_at=None, close_reason=None) + return HttpResponseRedirect(question.get_absolute_url()) + else: + return render_to_response('reopen.html', { + 'question' : question, + }, context_instance=RequestContext(request)) + +@login_required +def edit_question(request, id): + question = get_object_or_404(Question, id=id) + if question.deleted and not can_view_deleted_post(request.user, question): + raise Http404 + if can_edit_post(request.user, question): + return _edit_question(request, question) + elif can_retag_questions(request.user): + return _retag_question(request, question) + else: + raise Http404 + +def _retag_question(request, question): + if request.method == 'POST': + form = RetagQuestionForm(question, request.POST) + if form.is_valid(): + if form.has_changed(): + latest_revision = question.get_latest_revision() + retagged_at = datetime.datetime.now() + # Update the Question itself + Question.objects.filter(id=question.id).update( + tagnames = form.cleaned_data['tags'], + last_edited_at = retagged_at, + last_edited_by = request.user, + last_activity_at = retagged_at, + last_activity_by = request.user + ) + # Update the Question's tag associations + tags_updated = Question.objects.update_tags(question, + form.cleaned_data['tags'], request.user) + # Create a new revision + QuestionRevision.objects.create( + question = question, + title = latest_revision.title, + author = request.user, + revised_at = retagged_at, + tagnames = form.cleaned_data['tags'], + summary = CONST['retagged'], + text = latest_revision.text + ) + # send tags updated singal + tags_updated.send(sender=question.__class__, question=question) + + return HttpResponseRedirect(question.get_absolute_url()) + else: + form = RetagQuestionForm(question) + return render_to_response('question_retag.html', { + 'question': question, + 'form' : form, + 'tags' : _get_tags_cache_json(), + }, context_instance=RequestContext(request)) + + +def _edit_question(request, question): + latest_revision = question.get_latest_revision() + revision_form = None + if request.method == 'POST': + if 'select_revision' in request.POST: + # user has changed revistion number + revision_form = RevisionForm(question, latest_revision, request.POST) + if revision_form.is_valid(): + # Replace with those from the selected revision + form = EditQuestionForm(question, + QuestionRevision.objects.get(question=question, + revision=revision_form.cleaned_data['revision'])) + else: + form = EditQuestionForm(question, latest_revision, request.POST) + else: + # Always check modifications against the latest revision + form = EditQuestionForm(question, latest_revision, request.POST) + if form.is_valid(): + html = sanitize_html(markdowner.convert(form.cleaned_data['text'])) + if form.has_changed(): + edited_at = datetime.datetime.now() + tags_changed = (latest_revision.tagnames != + form.cleaned_data['tags']) + tags_updated = False + # Update the Question itself + updated_fields = { + 'title': form.cleaned_data['title'], + 'last_edited_at': edited_at, + 'last_edited_by': request.user, + 'last_activity_at': edited_at, + 'last_activity_by': request.user, + 'tagnames': form.cleaned_data['tags'], + 'summary': strip_tags(html)[:120], + 'html': html, + } + + # only save when it's checked + # because wiki doesn't allow to be edited if last version has been enabled already + # and we make sure this in forms. + if ('wiki' in form.cleaned_data and + form.cleaned_data['wiki']): + updated_fields['wiki'] = True + updated_fields['wikified_at'] = edited_at + + Question.objects.filter( + id=question.id).update(**updated_fields) + # Update the Question's tag associations + if tags_changed: + tags_updated = Question.objects.update_tags( + question, form.cleaned_data['tags'], request.user) + # Create a new revision + revision = QuestionRevision( + question = question, + title = form.cleaned_data['title'], + author = request.user, + revised_at = edited_at, + tagnames = form.cleaned_data['tags'], + text = form.cleaned_data['text'], + ) + if form.cleaned_data['summary']: + revision.summary = form.cleaned_data['summary'] + else: + revision.summary = 'No.%s Revision' % latest_revision.revision + revision.save() + + return HttpResponseRedirect(question.get_absolute_url()) + else: + + revision_form = RevisionForm(question, latest_revision) + form = EditQuestionForm(question, latest_revision) + return render_to_response('question_edit.html', { + 'question': question, + 'revision_form': revision_form, + 'form' : form, + 'tags' : _get_tags_cache_json() + }, context_instance=RequestContext(request)) + + +@login_required +def edit_answer(request, id): + answer = get_object_or_404(Answer, id=id) + if answer.deleted and not can_view_deleted_post(request.user, answer): + raise Http404 + elif not can_edit_post(request.user, answer): + raise Http404 + else: + latest_revision = answer.get_latest_revision() + if request.method == "POST": + if 'select_revision' in request.POST: + # user has changed revistion number + revision_form = RevisionForm(answer, latest_revision, request.POST) + if revision_form.is_valid(): + # Replace with those from the selected revision + form = EditAnswerForm(answer, + AnswerRevision.objects.get(answer=answer, + revision=revision_form.cleaned_data['revision'])) + else: + form = EditAnswerForm(answer, latest_revision, request.POST) + else: + form = EditAnswerForm(answer, latest_revision, request.POST) + if form.is_valid(): + html = sanitize_html(markdowner.convert(form.cleaned_data['text'])) + if form.has_changed(): + edited_at = datetime.datetime.now() + updated_fields = { + 'last_edited_at': edited_at, + 'last_edited_by': request.user, + 'html': html, + } + Answer.objects.filter(id=answer.id).update(**updated_fields) + + revision = AnswerRevision( + answer = answer, + author = request.user, + revised_at = edited_at, + text = form.cleaned_data['text'] + ) + + if form.cleaned_data['summary']: + revision.summary = form.cleaned_data['summary'] + else: + revision.summary = 'No.%s Revision' % latest_revision.revision + revision.save() + + answer.question.last_activity_at = edited_at + answer.question.last_activity_by = request.user + answer.question.save() + + return HttpResponseRedirect(answer.get_absolute_url()) + else: + revision_form = RevisionForm(answer, latest_revision) + form = EditAnswerForm(answer, latest_revision) + return render_to_response('answer_edit.html', { + 'answer': answer, + 'revision_form': revision_form, + 'form' : form, + }, context_instance=RequestContext(request)) + +QUESTION_REVISION_TEMPLATE = ('<h1>%(title)s</h1>\n' + '<div class="text">%(html)s</div>\n' + '<div class="tags">%(tags)s</div>') +def question_revisions(request, id): + post = get_object_or_404(Question, id=id) + revisions = list(post.revisions.all()) + for i, revision in enumerate(revisions): + revision.html = QUESTION_REVISION_TEMPLATE % { + 'title': revision.title, + 'html': sanitize_html(markdowner.convert(revision.text)), + 'tags': ' '.join(['<a class="post-tag">%s</a>' % tag + for tag in revision.tagnames.split(' ')]), + } + if i > 0: + revisions[i - 1].diff = htmldiff(revision.html, + revisions[i - 1].html) + else: + revisions[i - 1].diff = QUESTION_REVISION_TEMPLATE % { + 'title': revisions[0].title, + 'html': sanitize_html(markdowner.convert(revisions[0].text)), + 'tags': ' '.join(['<a class="post-tag">%s</a>' % tag + for tag in revisions[0].tagnames.split(' ')]), + } + revisions[i - 1].summary = None + return render_to_response('revisions_question.html', { + 'post': post, + 'revisions': revisions, + }, context_instance=RequestContext(request)) + +ANSWER_REVISION_TEMPLATE = ('<div class="text">%(html)s</div>') +def answer_revisions(request, id): + post = get_object_or_404(Answer, id=id) + revisions = list(post.revisions.all()) + for i, revision in enumerate(revisions): + revision.html = ANSWER_REVISION_TEMPLATE % { + 'html': sanitize_html(markdowner.convert(revision.text)) + } + if i > 0: + revisions[i - 1].diff = htmldiff(revision.html, + revisions[i - 1].html) + else: + revisions[i - 1].diff = revisions[i-1].text + revisions[i - 1].summary = None + return render_to_response('revisions_answer.html', { + 'post': post, + 'revisions': revisions, + }, context_instance=RequestContext(request)) + +#TODO: allow anynomus +@login_required +def answer(request, id): + question = get_object_or_404(Question, id=id) + if request.method == "POST": + form = AnswerForm(question, request.POST) + if form.is_valid(): + update_time = datetime.datetime.now() + answer = Answer( + question = question, + author = request.user, + added_at = update_time, + wiki = form.cleaned_data['wiki'], + html = sanitize_html(markdowner.convert(form.cleaned_data['text'])), + ) + if answer.wiki: + answer.last_edited_by = answer.author + answer.last_edited_at = update_time + answer.wikified_at = update_time + + answer.save() + Question.objects.update_answer_count(question) + + question = get_object_or_404(Question, id=id) + question.last_activity_at = update_time + question.last_activity_by = request.user + question.save() + + AnswerRevision.objects.create( + answer = answer, + revision = 1, + author = request.user, + revised_at = update_time, + summary = CONST['default_version'], + text = form.cleaned_data['text'] + ) + + return HttpResponseRedirect(question.get_absolute_url()) + +def tags(request): + stag = "" + is_paginated = True + sortby = request.GET.get('sort', 'used') + try: + page = int(request.GET.get('page', '1')) + except ValueError: + page = 1 + + if request.method == "GET": + stag = request.GET.get("q", "").strip() + if stag is not None: + objects_list = Paginator(Tag.objects.filter(deleted=False).exclude(used_count=0).extra(where=['name like %s'], params=['%' + stag + '%']), DEFAULT_PAGE_SIZE) + else: + if sortby == "name": + objects_list = Paginator(Tag.objects.all().filter(deleted=False).exclude(used_count=0).order_by("name"), DEFAULT_PAGE_SIZE) + else: + objects_list = Paginator(Tag.objects.all().filter(deleted=False).exclude(used_count=0).order_by("-used_count"), DEFAULT_PAGE_SIZE) + + try: + tags = objects_list.page(page) + except (EmptyPage, InvalidPage): + tags = objects_list.page(objects_list.num_pages) + + return render_to_response('tags.html', { + "tags" : tags, + "stag" : stag, + "tab_id" : sortby, + "keywords" : stag, + "context" : { + 'is_paginated' : is_paginated, + 'pages': objects_list.num_pages, + 'page': page, + 'has_previous': tags.has_previous(), + 'has_next': tags.has_next(), + 'previous': tags.previous_page_number(), + 'next': tags.next_page_number(), + 'base_url' : '/tags/?sort=%s&' % sortby + } + + }, context_instance=RequestContext(request)) + +def tag(request, tag): + return questions(request, tagname=tag) + +def vote(request, id): + """ + vote_type: + acceptAnswer : 0, + questionUpVote : 1, + questionDownVote : 2, + favorite : 4, + answerUpVote: 5, + answerDownVote:6, + offensiveQuestion : 7, + offensiveAnswer:8, + removeQuestion: 9, + removeAnswer:10 + + accept answer code: + response_data['allowed'] = -1, Accept his own answer 0, no allowed - Anonymous 1, Allowed - by default + response_data['success'] = 0, failed 1, Success - by default + response_data['status'] = 0, By default 1, Answer has been accepted already(Cancel) + + vote code: + allowed = -3, Don't have enough votes left + -2, Don't have enough reputation score + -1, Vote his own post + 0, no allowed - Anonymous + 1, Allowed - by default + status = 0, By default + 1, Cancel + 2, Vote is too old to be canceled + + offensive code: + allowed = -3, Don't have enough flags left + -2, Don't have enough reputation score to do this + 0, not allowed + 1, allowed + status = 0, by default + 1, can't do it again + """ + response_data = { + "allowed": 1, + "success": 1, + "status" : 0, + "count" : 0, + "message" : '' + } + + def can_vote(vote_score, user): + if vote_score == 1: + return can_vote_up(request.user) + else: + return can_vote_down(request.user) + + try: + if not request.user.is_authenticated(): + response_data['allowed'] = 0 + response_data['success'] = 0 + + elif request.is_ajax(): + question = get_object_or_404(Question, id=id) + vote_type = request.POST.get('type') + + #accept answer + if vote_type == '0': + answer_id = request.POST.get('postId') + answer = get_object_or_404(Answer, id=answer_id) + # make sure question author is current user + if question.author == request.user: + # answer user who is also question author is not allow to accept answer + if answer.author == question.author: + response_data['success'] = 0 + response_data['allowed'] = -1 + # check if answer has been accepted already + elif answer.accepted: + onAnswerAcceptCanceled(answer, request.user) + response_data['status'] = 1 + else: + # set other answers in this question not accepted first + for answer_of_question in Answer.objects.get_answers_from_question(question, request.user): + if answer_of_question != answer and answer_of_question.accepted: + onAnswerAcceptCanceled(answer_of_question, request.user) + + #make sure retrieve data again after above author changes, they may have related data + answer = get_object_or_404(Answer, id=answer_id) + onAnswerAccept(answer, request.user) + else: + response_data['allowed'] = 0 + response_data['success'] = 0 + # favorite + elif vote_type == '4': + has_favorited = False + fav_questions = FavoriteQuestion.objects.filter(question=question) + # if the same question has been favorited before, then delete it + if fav_questions is not None: + for item in fav_questions: + if item.user == request.user: + item.delete() + response_data['status'] = 1 + response_data['count'] = len(fav_questions) - 1 + if response_data['count'] < 0: + response_data['count'] = 0 + has_favorited = True + # if above deletion has not been executed, just insert a new favorite question + if not has_favorited: + new_item = FavoriteQuestion(question=question, user=request.user) + new_item.save() + response_data['count'] = FavoriteQuestion.objects.filter(question=question).count() + Question.objects.update_favorite_count(question) + + elif vote_type in ['1', '2', '5', '6']: + post_id = id + post = question + vote_score = 1 + if vote_type in ['5', '6']: + answer_id = request.POST.get('postId') + answer = get_object_or_404(Answer, id=answer_id) + post_id = answer_id + post = answer + if vote_type in ['2', '6']: + vote_score = -1 + + if post.author == request.user: + response_data['allowed'] = -1 + elif not can_vote(vote_score, request.user): + response_data['allowed'] = -2 + elif post.votes.filter(user=request.user).count() > 0: + vote = post.votes.filter(user=request.user)[0] + # unvote should be less than certain time + if (datetime.datetime.now().day - vote.voted_at.day) >= VOTE_RULES['scope_deny_unvote_days']: + response_data['status'] = 2 + else: + voted = vote.vote + if voted > 0: + # cancel upvote + onUpVotedCanceled(vote, post, request.user) + + else: + # cancel downvote + onDownVotedCanceled(vote, post, request.user) + + response_data['status'] = 1 + response_data['count'] = post.score + elif Vote.objects.get_votes_count_today_from_user(request.user) >= VOTE_RULES['scope_votes_per_user_per_day']: + response_data['allowed'] = -3 + else: + vote = Vote(user=request.user, content_object=post, vote=vote_score, voted_at=datetime.datetime.now()) + if vote_score > 0: + # upvote + onUpVoted(vote, post, request.user) + else: + # downvote + onDownVoted(vote, post, request.user) + + votes_left = VOTE_RULES['scope_votes_per_user_per_day'] - Vote.objects.get_votes_count_today_from_user(request.user) + if votes_left <= VOTE_RULES['scope_warn_votes_left']: + response_data['message'] = u'%s votes left' % votes_left + response_data['count'] = post.score + elif vote_type in ['7', '8']: + post = question + post_id = id + if vote_type == '8': + post_id = request.POST.get('postId') + post = get_object_or_404(Answer, id=post_id) + + if FlaggedItem.objects.get_flagged_items_count_today(request.user) >= VOTE_RULES['scope_flags_per_user_per_day']: + response_data['allowed'] = -3 + elif not can_flag_offensive(request.user): + response_data['allowed'] = -2 + elif post.flagged_items.filter(user=request.user).count() > 0: + response_data['status'] = 1 + else: + item = FlaggedItem(user=request.user, content_object=post, flagged_at=datetime.datetime.now()) + onFlaggedItem(item, post, request.user) + response_data['count'] = post.offensive_flag_count + # send signal when question or answer be marked offensive + mark_offensive.send(sender=post.__class__, instance=post, mark_by=request.user) + elif vote_type in ['9', '10']: + post = question + post_id = id + if vote_type == '10': + post_id = request.POST.get('postId') + post = get_object_or_404(Answer, id=post_id) + + if not can_delete_post(request.user, post): + response_data['allowed'] = -2 + elif post.deleted: + onDeleteCanceled(post, request.user) + response_data['status'] = 1 + else: + onDeleted(post, request.user) + delete_post_or_answer.send(sender=post.__class__, instance=post, delete_by=request.user) + else: + response_data['success'] = 0 + response_data['message'] = u'Request mode is not supported. Please try again.' + + data = simplejson.dumps(response_data) + + except Exception, e: + response_data['message'] = str(e) + data = simplejson.dumps(response_data) + return HttpResponse(data, mimetype="application/json") + +def users(request): + is_paginated = True + sortby = request.GET.get('sort', 'reputation') + suser = request.REQUEST.get('q', "") + try: + page = int(request.GET.get('page', '1')) + except ValueError: + page = 1 + + if suser == "": + if sortby == "newest": + objects_list = Paginator(User.objects.all().order_by('-date_joined'), USERS_PAGE_SIZE) + elif sortby == "last": + objects_list = Paginator(User.objects.all().order_by('date_joined'), USERS_PAGE_SIZE) + elif sortby == "user": + objects_list = Paginator(User.objects.all().order_by('username'), USERS_PAGE_SIZE) + # default + else: + objects_list = Paginator(User.objects.all().order_by('-reputation'), USERS_PAGE_SIZE) + base_url = '/users/?sort=%s&' % sortby + else: + sortby = "reputation" + objects_list = Paginator(User.objects.extra(where=['username like %s'], params=['%' + suser + '%']).order_by('-reputation'), USERS_PAGE_SIZE) + base_url = '/users/?name=%s&sort=%s&' % (suser, sortby) + + try: + users = objects_list.page(page) + except (EmptyPage, InvalidPage): + users = objects_list.page(objects_list.num_pages) + + return render_to_response('users.html', { + "users" : users, + "suser" : suser, + "keywords" : suser, + "tab_id" : sortby, + "context" : { + 'is_paginated' : is_paginated, + 'pages': objects_list.num_pages, + 'page': page, + 'has_previous': users.has_previous(), + 'has_next': users.has_next(), + 'previous': users.previous_page_number(), + 'next': users.next_page_number(), + 'base_url' : base_url + } + + }, context_instance=RequestContext(request)) + +def user(request, id): + sort = request.GET.get('sort', 'stats') + user_view = dict((v.id, v) for v in USER_TEMPLATE_VIEWS).get(sort, USER_TEMPLATE_VIEWS[0]) + from forum import views + func = getattr(views, user_view.view_name) + return func(request, id, user_view) + +@login_required +def edit_user(request, id): + user = get_object_or_404(User, id=id) + if request.user != user: + raise Http404 + if request.method == "POST": + form = EditUserForm(user, request.POST) + if form.is_valid(): + user.email = sanitize_html(form.cleaned_data['email']) + user.real_name = sanitize_html(form.cleaned_data['realname']) + user.website = sanitize_html(form.cleaned_data['website']) + user.location = sanitize_html(form.cleaned_data['city']) + user.date_of_birth = sanitize_html(form.cleaned_data['birthday']) + if len(user.date_of_birth) == 0: + user.date_of_birth = '1900-01-01' + user.about = sanitize_html(form.cleaned_data['about']) + + user.save() + # send user updated singal if full fields have been updated + if user.email and user.real_name and user.website and user.location and \ + user.date_of_birth and user.about: + user_updated.send(sender=user.__class__, instance=user, updated_by=user) + return HttpResponseRedirect(user.get_profile_url()) + else: + form = EditUserForm(user) + return render_to_response('user_edit.html', { + 'form' : form, + }, context_instance=RequestContext(request)) + +def user_stats(request, user_id, user_view): + user = get_object_or_404(User, id=user_id) + questions = Question.objects.extra( + select={ + 'vote_count' : 'question.score', + 'favorited_myself' : 'SELECT count(*) FROM favorite_question f WHERE f.user_id = %s AND f.question_id = question.id', + 'la_user_id' : 'auth_user.id', + 'la_username' : 'auth_user.username', + 'la_user_gold' : 'auth_user.gold', + 'la_user_silver' : 'auth_user.silver', + 'la_user_bronze' : 'auth_user.bronze', + 'la_user_reputation' : 'auth_user.reputation' + }, + select_params=[user_id], + tables=['question', 'auth_user'], + where=['question.deleted = 0 AND question.author_id=%s AND question.last_activity_by_id = auth_user.id'], + params=[user_id], + order_by=['-vote_count', '-last_activity_at'] + ).values('vote_count', + 'favorited_myself', + 'id', + 'title', + 'author_id', + 'added_at', + 'answer_accepted', + 'answer_count', + 'comment_count', + 'view_count', + 'favourite_count', + 'summary', + 'tagnames', + 'vote_up_count', + 'vote_down_count', + 'last_activity_at', + 'la_user_id', + 'la_username', + 'la_user_gold', + 'la_user_silver', + 'la_user_bronze', + 'la_user_reputation')[:100] + + answered_questions = Question.objects.extra( + select={ + 'vote_up_count' : 'answer.vote_up_count', + 'vote_down_count' : 'answer.vote_down_count', + 'answer_id' : 'answer.id', + 'accepted' : 'answer.accepted', + 'vote_count' : 'answer.score', + 'comment_count' : 'answer.comment_count' + }, + tables=['question', 'answer'], + where=['answer.deleted=0 AND answer.author_id=%s AND answer.question_id=question.id'], + params=[user_id], + order_by=['-vote_count', '-answer_id'], + select_params=[user_id] + ).distinct().values('comment_count', + 'id', + 'answer_id', + 'title', + 'author_id', + 'accepted', + 'vote_count', + 'answer_count', + 'vote_up_count', + 'vote_down_count')[:100] + up_votes = Vote.objects.get_up_vote_count_from_user(user) + down_votes = Vote.objects.get_down_vote_count_from_user(user) + votes_today = Vote.objects.get_votes_count_today_from_user(user) + votes_total = VOTE_RULES['scope_votes_per_user_per_day'] + tags = user.created_tags.all().order_by('-used_count')[:50] + awards = Award.objects.extra( + select={'id': 'badge.id', 'count': 'count(badge_id)', 'name':'badge.name', 'description': 'badge.description', 'type': 'badge.type'}, + tables=['award', 'badge'], + order_by=['-awarded_at'], + where=['user_id=%s AND badge_id=badge.id'], + params=[user.id] + ).values('id', 'count', 'name', 'description', 'type') + total_awards = awards.count() + awards.query.group_by = ['badge_id'] + + return render_to_response(user_view.template_file,{ + "tab_name" : user_view.id, + "tab_description" : user_view.tab_description, + "page_title" : user_view.page_title, + "view_user" : user, + "questions" : questions, + "answered_questions" : answered_questions, + "up_votes" : up_votes, + "down_votes" : down_votes, + "total_votes": up_votes + down_votes, + "votes_today_left": votes_total-votes_today, + "votes_total_per_day": votes_total, + "tags" : tags, + "awards": awards, + "total_awards" : total_awards, + }, context_instance=RequestContext(request)) + +def user_recent(request, user_id, user_view): + user = get_object_or_404(User, id=user_id) + def get_type_name(type_id): + for item in TYPE_ACTIVITY: + if type_id in item: + return item[1] + + class Event: + def __init__(self, time, type, title, summary, answer_id, question_id): + self.time = time + self.type = get_type_name(type) + self.type_id = type + self.title = title + self.summary = summary + self.title_link = u'/questions/%s/%s#%s' %(question_id, title, answer_id)\ + if int(answer_id) > 0 else u'/questions/%s/%s' %(question_id, title) + class AwardEvent: + def __init__(self, time, type, id): + self.time = time + self.type = get_type_name(type) + self.type_id = type + self.badge = get_object_or_404(Badge, id=id) + + activities = [] + # ask questions + questions = Activity.objects.extra( + select={ + 'title' : 'question.title', + 'question_id' : 'question.id', + 'active_at' : 'activity.active_at', + 'activity_type' : 'activity.activity_type' + }, + tables=['activity', 'question'], + where=['activity.content_type_id = %s AND activity.object_id = ' + + 'question.id AND activity.user_id = %s AND activity.activity_type = %s'], + params=[question_type_id, user_id, TYPE_ACTIVITY_ASK_QUESTION], + order_by=['-activity.active_at'] + ).values( + 'title', + 'question_id', + 'active_at', + 'activity_type' + ) + if len(questions) > 0: + questions = [(Event(q['active_at'], q['activity_type'], q['title'], '', '0', \ + q['question_id'])) for q in questions] + activities.extend(questions) + + # answers + answers = Activity.objects.extra( + select={ + 'title' : 'question.title', + 'question_id' : 'question.id', + 'answer_id' : 'answer.id', + 'active_at' : 'activity.active_at', + 'activity_type' : 'activity.activity_type' + }, + tables=['activity', 'answer', 'question'], + where=['activity.content_type_id = %s AND activity.object_id = answer.id AND ' + + 'answer.question_id=question.id AND activity.user_id=%s AND activity.activity_type=%s'], + params=[answer_type_id, user_id, TYPE_ACTIVITY_ANSWER], + order_by=['-activity.active_at'] + ).values( + 'title', + 'question_id', + 'answer_id', + 'active_at', + 'activity_type' + ) + if len(answers) > 0: + answers = [(Event(q['active_at'], q['activity_type'], q['title'], '', q['answer_id'], \ + q['question_id'])) for q in answers] + activities.extend(answers) + + # question comments + comments = Activity.objects.extra( + select={ + 'title' : 'question.title', + 'question_id' : 'comment.object_id', + 'added_at' : 'comment.added_at', + 'activity_type' : 'activity.activity_type' + }, + tables=['activity', 'question', 'comment'], + + where=['activity.content_type_id = %s AND activity.object_id = comment.id AND '+ + 'activity.user_id = comment.user_id AND comment.object_id=question.id AND '+ + 'comment.content_type_id=%s AND activity.user_id = %s AND activity.activity_type=%s'], + params=[comment_type_id, question_type_id, user_id, TYPE_ACTIVITY_COMMENT_QUESTION], + order_by=['-comment.added_at'] + ).values( + 'title', + 'question_id', + 'added_at', + 'activity_type' + ) + + if len(comments) > 0: + comments = [(Event(q['added_at'], q['activity_type'], q['title'], '', '0', \ + q['question_id'])) for q in comments] + activities.extend(comments) + + # answer comments + comments = Activity.objects.extra( + select={ + 'title' : 'question.title', + 'question_id' : 'question.id', + 'answer_id' : 'answer.id', + 'added_at' : 'comment.added_at', + 'activity_type' : 'activity.activity_type' + }, + tables=['activity', 'question', 'answer', 'comment'], + + where=['activity.content_type_id = %s AND activity.object_id = comment.id AND '+ + 'activity.user_id = comment.user_id AND comment.object_id=answer.id AND '+ + 'comment.content_type_id=%s AND question.id = answer.question_id AND '+ + 'activity.user_id = %s AND activity.activity_type=%s'], + params=[comment_type_id, answer_type_id, user_id, TYPE_ACTIVITY_COMMENT_ANSWER], + order_by=['-comment.added_at'] + ).values( + 'title', + 'question_id', + 'answer_id', + 'added_at', + 'activity_type' + ) + + if len(comments) > 0: + comments = [(Event(q['added_at'], q['activity_type'], q['title'], '', q['answer_id'], \ + q['question_id'])) for q in comments] + activities.extend(comments) + + # question revisions + revisions = Activity.objects.extra( + select={ + 'title' : 'question_revision.title', + 'question_id' : 'question_revision.question_id', + 'added_at' : 'activity.active_at', + 'activity_type' : 'activity.activity_type', + 'summary' : 'question_revision.summary' + }, + tables=['activity', 'question_revision'], + where=['activity.content_type_id = %s AND activity.object_id = question_revision.id AND '+ + 'activity.user_id = question_revision.author_id AND activity.user_id = %s AND '+ + 'activity.activity_type=%s'], + params=[question_revision_type_id, user_id, TYPE_ACTIVITY_UPDATE_QUESTION], + order_by=['-activity.active_at'] + ).values( + 'title', + 'question_id', + 'added_at', + 'activity_type', + 'summary' + ) + + if len(revisions) > 0: + revisions = [(Event(q['added_at'], q['activity_type'], q['title'], q['summary'], '0', \ + q['question_id'])) for q in revisions] + activities.extend(revisions) + + # answer revisions + revisions = Activity.objects.extra( + select={ + 'title' : 'question.title', + 'question_id' : 'question.id', + 'answer_id' : 'answer.id', + 'added_at' : 'activity.active_at', + 'activity_type' : 'activity.activity_type', + 'summary' : 'answer_revision.summary' + }, + tables=['activity', 'answer_revision', 'question', 'answer'], + + where=['activity.content_type_id = %s AND activity.object_id = answer_revision.id AND '+ + 'activity.user_id = answer_revision.author_id AND activity.user_id = %s AND '+ + 'answer_revision.answer_id=answer.id AND answer.question_id = question.id AND '+ + 'activity.activity_type=%s'], + params=[answer_revision_type_id, user_id, TYPE_ACTIVITY_UPDATE_ANSWER], + order_by=['-activity.active_at'] + ).values( + 'title', + 'question_id', + 'added_at', + 'answer_id', + 'activity_type', + 'summary' + ) + + if len(revisions) > 0: + revisions = [(Event(q['added_at'], q['activity_type'], q['title'], q['summary'], \ + q['answer_id'], q['question_id'])) for q in revisions] + activities.extend(revisions) + + # accepted answers + accept_answers = Activity.objects.extra( + select={ + 'title' : 'question.title', + 'question_id' : 'question.id', + 'added_at' : 'activity.active_at', + 'activity_type' : 'activity.activity_type', + }, + tables=['activity', 'answer', 'question'], + where=['activity.content_type_id = %s AND activity.object_id = answer.id AND '+ + 'activity.user_id = question.author_id AND activity.user_id = %s AND '+ + 'answer.question_id=question.id AND activity.activity_type=%s'], + params=[answer_type_id, user_id, TYPE_ACTIVITY_MARK_ANSWER], + order_by=['-activity.active_at'] + ).values( + 'title', + 'question_id', + 'added_at', + 'activity_type', + ) + if len(accept_answers) > 0: + accept_answers = [(Event(q['added_at'], q['activity_type'], q['title'], '', '0', \ + q['question_id'])) for q in accept_answers] + activities.extend(accept_answers) + #award history + awards = Activity.objects.extra( + select={ + 'badge_id' : 'badge.id', + 'awarded_at': 'award.awarded_at', + 'activity_type' : 'activity.activity_type' + }, + tables=['activity', 'award', 'badge'], + where=['activity.user_id = award.user_id AND activity.user_id = %s AND '+ + 'award.badge_id=badge.id AND activity.object_id=award.id AND activity.activity_type=%s'], + params=[user_id, TYPE_ACTIVITY_PRIZE], + order_by=['-activity.active_at'] + ).values( + 'badge_id', + 'awarded_at', + 'activity_type' + ) + if len(awards) > 0: + awards = [(AwardEvent(q['awarded_at'], q['activity_type'], q['badge_id'])) for q in awards] + activities.extend(awards) + + activities.sort(lambda x,y: cmp(y.time, x.time)) + + return render_to_response(user_view.template_file,{ + "tab_name" : user_view.id, + "tab_description" : user_view.tab_description, + "page_title" : user_view.page_title, + "view_user" : user, + "activities" : activities[:user_view.data_size] + }, context_instance=RequestContext(request)) + +def user_responses(request, user_id, user_view): + """ + We list answers for question, comments, and answer accepted by others for this user. + """ + class Response: + def __init__(self, type, title, question_id, answer_id, time, username, user_id, content): + self.type = type + self.title = title + self.titlelink = u'/questions/%s/%s#%s' % (question_id, title, answer_id) + self.time = time + self.userlink = u'/users/%s/%s/' % (user_id, username) + self.username = username + self.content = u'%s ...' % strip_tags(content)[:300] + + def __unicode__(self): + return u'%s %s' % (self.type, self.titlelink) + + user = get_object_or_404(User, id=user_id) + responses = [] + answers = Answer.objects.extra( + select={ + 'title' : 'question.title', + 'question_id' : 'question.id', + 'answer_id' : 'answer.id', + 'added_at' : 'answer.added_at', + 'html' : 'answer.html', + 'username' : 'auth_user.username', + 'user_id' : 'auth_user.id' + }, + select_params=[user_id], + tables=['answer', 'question', 'auth_user'], + where=['answer.question_id = question.id AND answer.deleted=0 AND question.deleted = 0 AND '+ + 'question.author_id = %s AND answer.author_id <> %s AND answer.author_id=auth_user.id'], + params=[user_id, user_id], + order_by=['-answer.id'] + ).values( + 'title', + 'question_id', + 'answer_id', + 'added_at', + 'html', + 'username', + 'user_id' + ) + if len(answers) > 0: + answers = [(Response(TYPE_RESPONSE['QUESTION_ANSWERED'], a['title'], a['question_id'], + a['answer_id'], a['added_at'], a['username'], a['user_id'], a['html'])) for a in answers] + responses.extend(answers) + + + # question comments + comments = Comment.objects.extra( + select={ + 'title' : 'question.title', + 'question_id' : 'comment.object_id', + 'added_at' : 'comment.added_at', + 'comment' : 'comment.comment', + 'username' : 'auth_user.username', + 'user_id' : 'auth_user.id' + }, + tables=['question', 'auth_user', 'comment'], + where=['question.deleted = 0 AND question.author_id = %s AND comment.object_id=question.id AND '+ + 'comment.content_type_id=%s AND comment.user_id <> %s AND comment.user_id = auth_user.id'], + params=[user_id, question_type_id, user_id], + order_by=['-comment.added_at'] + ).values( + 'title', + 'question_id', + 'added_at', + 'comment', + 'username', + 'user_id' + ) + + if len(comments) > 0: + comments = [(Response(TYPE_RESPONSE['QUESTION_COMMENTED'], c['title'], c['question_id'], + '', c['added_at'], c['username'], c['user_id'], c['comment'])) for c in comments] + responses.extend(comments) + + # answer comments + comments = Comment.objects.extra( + select={ + 'title' : 'question.title', + 'question_id' : 'question.id', + 'answer_id' : 'answer.id', + 'added_at' : 'comment.added_at', + 'comment' : 'comment.comment', + 'username' : 'auth_user.username', + 'user_id' : 'auth_user.id' + }, + tables=['answer', 'auth_user', 'comment', 'question'], + where=['answer.deleted = 0 AND answer.author_id = %s AND comment.object_id=answer.id AND '+ + 'comment.content_type_id=%s AND comment.user_id <> %s AND comment.user_id = auth_user.id '+ + 'AND question.id = answer.question_id'], + params=[user_id, answer_type_id, user_id], + order_by=['-comment.added_at'] + ).values( + 'title', + 'question_id', + 'answer_id', + 'added_at', + 'comment', + 'username', + 'user_id' + ) + + if len(comments) > 0: + comments = [(Response(TYPE_RESPONSE['ANSWER_COMMENTED'], c['title'], c['question_id'], + c['answer_id'], c['added_at'], c['username'], c['user_id'], c['comment'])) for c in comments] + responses.extend(comments) + + # answer has been accepted + answers = Answer.objects.extra( + select={ + 'title' : 'question.title', + 'question_id' : 'question.id', + 'answer_id' : 'answer.id', + 'added_at' : 'answer.accepted_at', + 'html' : 'answer.html', + 'username' : 'auth_user.username', + 'user_id' : 'auth_user.id' + }, + select_params=[user_id], + tables=['answer', 'question', 'auth_user'], + where=['answer.question_id = question.id AND answer.deleted=0 AND question.deleted = 0 AND '+ + 'answer.author_id = %s AND answer.accepted=1 AND question.author_id=auth_user.id'], + params=[user_id], + order_by=['-answer.id'] + ).values( + 'title', + 'question_id', + 'answer_id', + 'added_at', + 'html', + 'username', + 'user_id' + ) + if len(answers) > 0: + answers = [(Response(TYPE_RESPONSE['ANSWER_ACCEPTED'], a['title'], a['question_id'], + a['answer_id'], a['added_at'], a['username'], a['user_id'], a['html'])) for a in answers] + responses.extend(answers) + + # sort posts by time + responses.sort(lambda x,y: cmp(y.time, x.time)) + + return render_to_response(user_view.template_file,{ + "tab_name" : user_view.id, + "tab_description" : user_view.tab_description, + "page_title" : user_view.page_title, + "view_user" : user, + "responses" : responses[:user_view.data_size], + + }, context_instance=RequestContext(request)) + +def user_votes(request, user_id, user_view): + user = get_object_or_404(User, id=user_id) + if not can_view_user_votes(request.user, user): + raise Http404 + votes = [] + question_votes = Vote.objects.extra( + select={ + 'title' : 'question.title', + 'question_id' : 'question.id', + 'answer_id' : 0, + 'voted_at' : 'vote.voted_at', + 'vote' : 'vote', + }, + select_params=[user_id], + tables=['vote', 'question', 'auth_user'], + where=['vote.content_type_id = %s AND vote.user_id = %s AND vote.object_id = question.id '+ + 'AND vote.user_id=auth_user.id'], + params=[question_type_id, user_id], + order_by=['-vote.id'] + ).values( + 'title', + 'question_id', + 'answer_id', + 'voted_at', + 'vote', + ) + if(len(question_votes) > 0): + votes.extend(question_votes) + + answer_votes = Vote.objects.extra( + select={ + 'title' : 'question.title', + 'question_id' : 'question.id', + 'answer_id' : 'answer.id', + 'voted_at' : 'vote.voted_at', + 'vote' : 'vote', + }, + select_params=[user_id], + tables=['vote', 'answer', 'question', 'auth_user'], + where=['vote.content_type_id = %s AND vote.user_id = %s AND vote.object_id = answer.id '+ + 'AND answer.question_id = question.id AND vote.user_id=auth_user.id'], + params=[answer_type_id, user_id], + order_by=['-vote.id'] + ).values( + 'title', + 'question_id', + 'answer_id', + 'voted_at', + 'vote', + ) + if(len(answer_votes) > 0): + votes.extend(answer_votes) + votes.sort(lambda x,y: cmp(y['voted_at'], x['voted_at'])) + return render_to_response(user_view.template_file,{ + "tab_name" : user_view.id, + "tab_description" : user_view.tab_description, + "page_title" : user_view.page_title, + "view_user" : user, + "votes" : votes[:user_view.data_size] + + }, context_instance=RequestContext(request)) + +def user_reputation(request, user_id, user_view): + user = get_object_or_404(User, id=user_id) + reputation = Repute.objects.extra( + select={'positive': 'sum(positive)', 'negative': 'sum(negative)', 'question_id':'question_id', + 'title': 'question.title'}, + tables=['repute', 'question'], + order_by=['-reputed_at'], + where=['user_id=%s AND question_id=question.id'], + params=[user.id] + ).values('positive', 'negative', 'question_id', 'title', 'reputed_at', 'reputation') + + reputation.query.group_by = ['question_id'] + + + rep_list = [] + for rep in Repute.objects.filter(user=user).order_by('reputed_at'): + dic = '[%s,%s]' % (calendar.timegm(rep.reputed_at.timetuple()) * 1000, rep.reputation) + rep_list.append(dic) + reps = ','.join(rep_list) + reps = '[%s]' % reps + + return render_to_response(user_view.template_file,{ + "tab_name" : user_view.id, + "tab_description" : user_view.tab_description, + "page_title" : user_view.page_title, + "view_user" : user, + "reputation" : reputation, + "reps" : reps + }, context_instance=RequestContext(request)) + +def user_favorites(request, user_id, user_view): + user = get_object_or_404(User, id=user_id) + questions = Question.objects.extra( + select={ + 'vote_count' : 'question.vote_up_count + question.vote_down_count', + 'favorited_myself' : 'SELECT count(*) FROM favorite_question f WHERE f.user_id = %s '+ + 'AND f.question_id = question.id', + 'la_user_id' : 'auth_user.id', + 'la_username' : 'auth_user.username', + 'la_user_gold' : 'auth_user.gold', + 'la_user_silver' : 'auth_user.silver', + 'la_user_bronze' : 'auth_user.bronze', + 'la_user_reputation' : 'auth_user.reputation' + }, + select_params=[user_id], + tables=['question', 'auth_user', 'favorite_question'], + where=['question.deleted = 0 AND question.last_activity_by_id = auth_user.id '+ + 'AND favorite_question.question_id = question.id AND favorite_question.user_id = %s'], + params=[user_id], + order_by=['-vote_count', '-question.id'] + ).values('vote_count', + 'favorited_myself', + 'id', + 'title', + 'author_id', + 'added_at', + 'answer_accepted', + 'answer_count', + 'comment_count', + 'view_count', + 'favourite_count', + 'summary', + 'tagnames', + 'vote_up_count', + 'vote_down_count', + 'last_activity_at', + 'la_user_id', + 'la_username', + 'la_user_gold', + 'la_user_silver', + 'la_user_bronze', + 'la_user_reputation') + return render_to_response(user_view.template_file,{ + "tab_name" : user_view.id, + "tab_description" : user_view.tab_description, + "page_title" : user_view.page_title, + "questions" : questions[:user_view.data_size], + "view_user" : user + }, context_instance=RequestContext(request)) + + +def user_preferences(request, user_id, user_view): + user = get_object_or_404(User, id=user_id) + return render_to_response(user_view.template_file,{ + "tab_name" : user_view.id, + "tab_description" : user_view.tab_description, + "page_title" : user_view.page_title, + "view_user" : user, + }, context_instance=RequestContext(request)) + +def question_comments(request, id): + question = get_object_or_404(Question, id=id) + user = request.user + return __comments(request, question, 'question', user) + +def answer_comments(request, id): + answer = get_object_or_404(Answer, id=id) + user = request.user + return __comments(request, answer, 'answer', user) + +def __comments(request, obj, type, user): + # only support get comments by ajax now + if request.is_ajax(): + if request.method == "GET": + return __generate_comments_json(obj, type, user) + elif request.method == "POST": + comment_data = request.POST.get('comment') + comment = Comment(content_object=obj, comment=comment_data, user=request.user) + comment.save() + obj.comment_count = obj.comment_count + 1 + obj.save() + return __generate_comments_json(obj, type, user) + +def __generate_comments_json(obj, type, user): + comments = obj.comments.all().order_by('-id') + # {"Id":6,"PostId":38589,"CreationDate":"an hour ago","Text":"hello there!","UserDisplayName":"Jarrod Dixon","UserUrl":"/users/3/jarrod-dixon","DeleteUrl":null} + json_comments = [] + for comment in comments: + comment_user = comment.user + delete_url = "" + if user != None and auth.can_delete_comment(user, comment): + #/posts/392845/comments/219852/delete + delete_url = "/" + type + "s/%s/comments/%s/delete/" % (obj.id, comment.id) + json_comments.append({"id" : comment.id, + "object_id" : obj.id, + "add_date" : comment.added_at.strftime('%Y-%m-%d'), + "text" : comment.comment, + "user_display_name" : comment_user.username, + "user_url" : "/users/%s/%s" % (comment_user.id, comment_user.username), + "delete_url" : delete_url + }) + + data = simplejson.dumps(json_comments) + return HttpResponse(data, mimetype="application/json") + +def delete_question_comment(request, question_id, comment_id): + if request.is_ajax(): + question = get_object_or_404(Question, id=question_id) + comment = get_object_or_404(Comment, id=comment_id) + + question.comments.remove(comment) + question.comment_count = question.comment_count - 1 + question.save() + user = request.user + return __generate_comments_json(question, 'question', user) + +def delete_answer_comment(request, answer_id, comment_id): + if request.is_ajax(): + answer = get_object_or_404(Answer, id=answer_id) + comment = get_object_or_404(Comment, id=comment_id) + + answer.comments.remove(comment) + answer.comment_count = answer.comment_count - 1 + answer.save() + user = request.user + return __generate_comments_json(answer, 'answer', user) + +def logout(request): + url = request.GET.get('next') + return render_to_response('logout.html', { + 'next' : url, + }, context_instance=RequestContext(request)) + +def badges(request): + badges = Badge.objects.all().order_by('type') + my_badges = [] + if request.user.is_authenticated(): + my_badges = Award.objects.filter(user=request.user) + my_badges.query.group_by = ['badge_id'] + + return render_to_response('badges.html', { + 'badges' : badges, + 'mybadges' : my_badges, + }, context_instance=RequestContext(request)) + +def badge(request, id): + badge = get_object_or_404(Badge, id=id) + awards = Award.objects.extra( + select={'id': 'auth_user.id', + 'name': 'auth_user.username', + 'rep':'auth_user.reputation', + 'gold': 'auth_user.gold', + 'silver': 'auth_user.silver', + 'bronze': 'auth_user.bronze'}, + tables=['award', 'auth_user'], + where=['badge_id=%s AND user_id=auth_user.id'], + params=[id] + ).values('id').distinct() + + return render_to_response('badge.html', { + 'awards' : awards, + 'badge' : badge, + }, context_instance=RequestContext(request)) + +def read_message(request): + if request.method == "POST": + if request.POST['formdata'] == 'required': + request.session['message_silent'] = 1 + + if request.user.is_authenticated(): + request.user.delete_messages() + return HttpResponse('') + +def upload(request): + class FileTypeNotAllow(Exception): + pass + class FileSizeNotAllow(Exception): + pass + class UploadPermissionNotAuthorized(Exception): + pass + + #<result><msg><![CDATA[%s]]></msg><error><![CDATA[%s]]></error><file_url>%s</file_url></result> + xml_template = "<result><msg><![CDATA[%s]]></msg><error><![CDATA[%s]]></error><file_url>%s</file_url></result>" + + try: + f = request.FILES['file-upload'] + # check upload permission + if not can_upload_files(request.user): + raise UploadPermissionNotAuthorized + + # check file type + file_name_suffix = os.path.splitext(f.name)[1].lower() + if not file_name_suffix in settings.ALLOW_FILE_TYPES: + raise FileTypeNotAllow + + # genetate new file name + new_file_name = str(time.time()).replace('.', str(random.randint(0,100000))) + file_name_suffix + # use default storage to store file + default_storage.save(new_file_name, f) + # check file size + # byte + size = default_storage.size(new_file_name) + if size > settings.ALLOW_MAX_FILE_SIZE: + default_storage.delete(new_file_name) + raise FileSizeNotAllow + + result = xml_template % ('Good', '', default_storage.url(new_file_name)) + except UploadPermissionNotAuthorized: + result = xml_template % ('', _('uploading images is limited to users with >60 reputation points'), '') + except FileTypeNotAllow: + result = xml_template % ('', _("allowed file types are 'jpg', 'jpeg', 'gif', 'bmp', 'png', 'tiff'"), '') + except FileSizeNotAllow: + result = xml_template % ('', _("maximum upload file size is %sK") % settings.ALLOW_MAX_FILE_SIZE / 1024, '') + except Exception: + result = xml_template % ('', _('Error uploading file. Please contact the site administrator. Thank you. %s' % Exception), '') + + return HttpResponse(result, mimetype="application/xml") + +def books(request): + return HttpResponseRedirect("/books/mysql-zhaoyang") + +def book(request, short_name, unanswered=False): + """ + 1. questions list + 2. book info + 3. author info and blog rss items + """ + """ + List of Questions, Tagged questions, and Unanswered questions. + """ + books = Book.objects.extra(where=['short_name = %s'], params=[short_name]) + match_count = len(books) + if match_count == 0 : + raise Http404 + else: + # the book info + book = books[0] + # get author info + author_info = BookAuthorInfo.objects.get(book=book) + # get author rss info + author_rss = BookAuthorRss.objects.filter(book=book) + + # get pagesize from session, if failed then get default value + user_page_size = request.session.get("pagesize", QUESTIONS_PAGE_SIZE) + # set pagesize equal to logon user specified value in database + if request.user.is_authenticated() and request.user.questions_per_page > 0: + user_page_size = request.user.questions_per_page + + try: + page = int(request.GET.get('page', '1')) + except ValueError: + page = 1 + + view_id = request.GET.get('sort', None) + view_dic = {"latest":"-added_at", "active":"-last_activity_at", "hottest":"-answer_count", "mostvoted":"-score" } + try: + orderby = view_dic[view_id] + except KeyError: + view_id = "latest" + orderby = "-added_at" + + # check if request is from tagged questions + if unanswered: + # check if request is from unanswered questions + # Article.objects.filter(publications__id__exact=1) + objects = Question.objects.filter(book__id__exact=book.id, deleted=False, answer_count=0).order_by(orderby) + else: + objects = Question.objects.filter(book__id__exact=book.id, deleted=False).order_by(orderby) + + # RISK - inner join queries + objects = objects.select_related(); + objects_list = Paginator(objects, user_page_size) + questions = objects_list.page(page) + + return render_to_response('book.html', { + "book" : book, + "author_info" : author_info, + "author_rss" : author_rss, + "questions" : questions, + "context" : { + 'is_paginated' : True, + 'pages': objects_list.num_pages, + 'page': page, + 'has_previous': questions.has_previous(), + 'has_next': questions.has_next(), + 'previous': questions.previous_page_number(), + 'next': questions.next_page_number(), + 'base_url' : request.path + '?sort=%s&' % view_id, + 'pagesize' : user_page_size + } + }, context_instance=RequestContext(request)) + +@login_required +def ask_book(request, short_name): + if request.method == "POST": + form = AskForm(request.POST) + if form.is_valid(): + added_at = datetime.datetime.now() + html = sanitize_html(markdowner.convert(form.cleaned_data['text'])) + question = Question( + title = strip_tags(form.cleaned_data['title']), + author = request.user, + added_at = added_at, + last_activity_at = added_at, + last_activity_by = request.user, + wiki = form.cleaned_data['wiki'], + tagnames = form.cleaned_data['tags'].strip(), + html = html, + summary = strip_tags(html)[:120] + ) + if question.wiki: + question.last_edited_by = question.author + question.last_edited_at = added_at + question.wikified_at = added_at + + question.save() + + # create the first revision + QuestionRevision.objects.create( + question = question, + revision = 1, + title = question.title, + author = request.user, + revised_at = added_at, + tagnames = question.tagnames, + summary = CONST['default_version'], + text = form.cleaned_data['text'] + ) + + books = Book.objects.extra(where=['short_name = %s'], params=[short_name]) + match_count = len(books) + if match_count == 1: + # the book info + book = books[0] + book.questions.add(question) + + return HttpResponseRedirect(question.get_absolute_url()) + else: + form = AskForm() + + tags = _get_tags_cache_json() + return render_to_response('ask.html', { + 'form' : form, + 'tags' : tags, + }, context_instance=RequestContext(request)) + +def search(request): + """ + Search by question, user and tag keywords. + For questions now we only search keywords in question title. + """ + if request.method == "GET": + keywords = request.GET.get("q") + search_type = request.GET.get("t") + try: + page = int(request.GET.get('page', '1')) + except ValueError: + page = 1 + if keywords is None: + return HttpResponseRedirect('/') + if search_type == 'tag': + return HttpResponseRedirect('/tags/?q=%s&page=%s' % (keywords.strip(), page)) + elif search_type == "user": + return HttpResponseRedirect('/users/?q=%s&page=%s' % (keywords.strip(), page)) + elif search_type == "question": + + template_file = "questions.html" + # Set flag to False by default. If it is equal to True, then need to be saved. + pagesize_changed = False + # get pagesize from session, if failed then get default value + user_page_size = request.session.get("pagesize", QUESTIONS_PAGE_SIZE) + # set pagesize equal to logon user specified value in database + if request.user.is_authenticated() and request.user.questions_per_page > 0: + user_page_size = request.user.questions_per_page + + try: + page = int(request.GET.get('page', '1')) + # get new pagesize from UI selection + pagesize = int(request.GET.get('pagesize', user_page_size)) + if pagesize <> user_page_size: + pagesize_changed = True + + except ValueError: + page = 1 + pagesize = user_page_size + + # save this pagesize to user database + if pagesize_changed: + request.session["pagesize"] = pagesize + if request.user.is_authenticated(): + user = request.user + user.questions_per_page = pagesize + user.save() + + view_id = request.GET.get('sort', None) + view_dic = {"latest":"-added_at", "active":"-last_activity_at", "hottest":"-answer_count", "mostvoted":"-score" } + try: + orderby = view_dic[view_id] + except KeyError: + view_id = "latest" + orderby = "-added_at" + + objects = Question.objects.filter(deleted=False).extra(where=['title like %s'], params=['%' + keywords + '%']).order_by(orderby) + + # RISK - inner join queries + objects = objects.select_related(); + objects_list = Paginator(objects, pagesize) + questions = objects_list.page(page) + + # Get related tags from this page objects + related_tags = [] + for question in questions.object_list: + tags = list(question.tags.all()) + for tag in tags: + if tag not in related_tags: + related_tags.append(tag) + + return render_to_response(template_file, { + "questions" : questions, + "tab_id" : view_id, + "questions_count" : objects_list.count, + "tags" : related_tags, + "searchtag" : None, + "searchtitle" : keywords, + "keywords" : keywords, + "is_unanswered" : False, + "context" : { + 'is_paginated' : True, + 'pages': objects_list.num_pages, + 'page': page, + 'has_previous': questions.has_previous(), + 'has_next': questions.has_next(), + 'previous': questions.previous_page_number(), + 'next': questions.next_page_number(), + 'base_url' : request.path + '?t=question&q=%s&sort=%s&' % (keywords, view_id), + 'pagesize' : pagesize + }}, context_instance=RequestContext(request)) + + else: + raise Http404 + diff --git a/locale/zh-cn/LC_MESSAGES/django.mo b/locale/zh-cn/LC_MESSAGES/django.mo Binary files differdeleted file mode 100644 index 8b8f5bb9..00000000 --- a/locale/zh-cn/LC_MESSAGES/django.mo +++ /dev/null diff --git a/locale/zh-cn/LC_MESSAGES/django.po b/locale/zh-cn/LC_MESSAGES/django.po deleted file mode 100644 index 5cad5b51..00000000 --- a/locale/zh-cn/LC_MESSAGES/django.po +++ /dev/null @@ -1,1430 +0,0 @@ -#author Evgeny Fadeev (evgeny.fadeev@gmail.com) -#site-specific messages -msgid "site title" -msgstr "CNProg.com" - -msgid "site slogan" -msgstr "程序员问答社区" - -msgid "meta site keywords, comma separated" -msgstr "技术问答社区,中国程序员,编程技术社区,程序员社区,程序员论坛,程序员wiki,程序员博客" - -msgid "meta site content" -msgstr "中国程序员的编程技术问答社区。我们做专业的、可协作编辑的技术问答社区。" - -msgid "copyright message" -msgstr "Copyright(c)2009.CNPROG.COM" - -msgid "Connect your OpenID with this site" -msgstr "绑定OpenID" - -msgid "Connect your OpenID with your account on this site" -msgstr "绑定OpenID帐号" - -msgid "Your OpenID is accepted. Please complete this to finish the registration. " -msgstr "您的OpenID帐号已经验证通过! 请完成最后一步 - 绑定OpenID到您的帐号。" - -#minimal length of user name may be language specific -msgid "username too short" -msgstr "用户名太短,请使用三个或三个以上字符" - -#translation and user name validation are language-specific -msgid "invalid user name" -msgstr "用户名只能包含英文字母、数字和下划线" - -#chinese translation is domain specific -msgid "question if off-topic or not relevant" -msgstr "不是编程技术问题" - -msgid "Login name" -msgstr "用户名" - -msgid "welcome to website!" -msgstr "CNProg欢迎您!" - -msgid "what is this website" -msgstr "CNProg是一个<strong>面向程序员</strong>的可协作编辑的<strong>开放源代码问答社区</strong>。" - -msgid "what can one do on this website" -msgstr "您可以在这里提问各类<strong>程序技术问题</strong> - 问题不分语言和平台。 同时也希望您对力所能及的问题,给予您的宝贵答案。" - -msgid "Goal of this site is..." -msgstr "CNProg 是为了帮助程序员解决更多问题,更加方便的解决问题。" - -msgid "how privacy policy can be changed" -msgstr "我们可能在事先通知或不通知的情况下随时更改此'隐私政策',我们建议用户时常查看CNProg隐私政策的改动,在任何改动生效后您的继续访问和使用本站,我们假设您已同意了CNProg以上的所有条款。" - -msgid "general message about privacy" -msgstr "CNProg承认用户隐私的重要性。本文件概述在您浏览CNProg过程中所接收和收集的个人信息的种类,以及CNProg所采取的保护信息的一些措施。CNProg希望这将有助于您在知情的情况下,就和我们 共享个人信息的问题作出决定。" - -msgid "cookie policy details" - -msgstr "访问CNProg时,我们会向您的计算机发送一个或多个专门用于识别您的浏览器的Cookie(包含一个字符串的小文件)。 " -"使用 Cookie 的目的是通过储存用户偏好、跟踪用户倾向(例如搜索" -"方法)来提高我们的服务质量。大多数浏览器的初始设置均为接受 Cookie,但也可以将其重置为拒绝所有 Cookie 或在收到 Cookie 时提示。不过,如果禁用 Cookie,某些功能和服务可能无法正常运行。" - -msgid "details on sharing data with third parties" -msgstr "CNProg可能会收集和统计用户访问本站的概况数据。例如,CNProg可能会检测网站最流行的部分功能。CNProg可能会公开显示或者提供给第三方使用该数据。但是,CNProg不会公开您的身份信息。" - -msgid "details on personal information policies" -msgstr "在登录使用CNProg的提问和回答功能时,我们要求使用者提供用户名、密码、电子邮件等信息。CNProg收集这类关于个人身份的信息只是为了登录系统获得使用功能的目的。我们不会向任何其他社区用 户、个人或第三方透露您的密码或者电子邮件信息。用户可以选择性地填写用户资料、个人网站、年龄、城市等信息,我们收集这些内容为了使用户能够更容易和更满意地使用CNProg提供的网页和服务。" - -msgid "Community gives you awards for your questions, answers and votes." -msgstr "提出问题,给予回答,投出你的票 - CNProg 会针对你在社区的表现,授予你各类奖牌。" - -msgid "what technical information is collected about visitors" -msgstr "当您访问本网站或使用我们的某些在线服务时,服务器会自动记录信息,包括但不限于URL、IP地址、浏览器的类型、屏幕分辨率、系统类型和使用的语言以及访问日期和时间。我们的目的是为了向您>提供更好的用户服务,包括可能为您提供定制的在线服务。" - -msgid "please make your answer relevant to this community" -msgstr "您的问题与编程相关吗?" - - -#templates/book.html 78 -msgid "reading channel" -msgstr "读书频道" - -msgid "[author]" -msgstr "【作者】" - -msgid "[publisher]" -msgstr "【出版社】" - -msgid "[publication date]" -msgstr "【出版日期】" - -msgid "[price]" -msgstr "【价格】" - -msgid "[pages]" -msgstr "【页数】" - -msgid "[tags]" -msgstr "【标签】" - -msgid "author blog" -msgstr "作者博客" - -msgid "book directory" -msgstr "书籍目录" - -msgid "buy online" -msgstr "网上购买" - -msgid "book technical Q&A" -msgstr "图书相关的技术答疑" - -msgid "reader questions" -msgstr "答读者问" - -msgid "ask the author" -msgstr "向作者提问" - -msgid "this question was selected as favorite" -msgstr "这个问题被" - -msgid "number of times" -msgstr "位用户收藏" - -msgid "votes" -msgstr "票" - -msgid "the answer has been accepted to be correct" -msgstr "有答案已被接受为正确答案" - -msgid "views" -msgstr "浏览" - -#must have extra space after in english -msgid "see questions tagged" -msgstr "查看有关" - -#book.html line 123 must be empty in english -msgid "using tags" -msgstr "的问题" - -#this is how above two are supposed to be -msgid "see questions tagged '%s'" -msgstr "查看有关'%s'的问题" - -msgid "subscribe to book RSS feed" -msgstr "RSS订阅该图书最新问题" - -msgid "subscribe to the questions feed" -msgstr "订阅最>新问题" - -#base_content.html -msgid "congratulations, community gave you a badge" -msgstr "恭喜您,社区给您颁发了奖牌" - -msgid "see" -msgstr "查看" - -msgid "profile" -msgstr "个人资料" - -#close.html -msgid "Close question" -msgstr "关闭问题" - -msgid "Close the question" -msgstr "由于以下原因,你要关闭这个问题" - -msgid "Reasons" -msgstr "原因" - -msgid "OK to close" -msgstr "确定关闭" - -msgid "Cancel" -msgstr "取消" - -#footer.html -msgid "about" -msgstr "关于本站" - -msgid "faq" -msgstr "常见问题" - -msgid "blog" -msgstr "Blog" - -msgid "contact us" -msgstr "联系我们" - -msgid "privacy policy" -msgstr "隐私政策" - -msgid "give feedback" -msgstr "问题反馈" - -msgid "current revision" -msgstr "当前版本" - -#index.html -msgid "community wiki" -msgstr "社区Wiki" - -msgid "Home" -msgstr "首页" - -msgid "Questions" -msgstr "问题列表" - -msgid "User questions" -msgstr "个问题" - -msgid "newest" -msgstr "最新问题" - -msgid "latest questions" -msgstr "最新问题" - -msgid " - " -msgstr "-" - -msgid "last updated questions" -msgstr "最新更新的问题" - -msgid "hottest" -msgstr "热门问题" - -msgid "hottest questions" -msgstr "被回复最多的问题" - -msgid "most voted" -msgstr "最有价值的问题" - -msgid "most voted questions" -msgstr "投票次数最多的问题" - -msgid "all questions" -msgstr "全部问题" - -msgid "answers" -msgstr "回答" - -msgid "Answers" -msgstr "个回答" - -msgid "number of votes" -msgstr "票数" - -msgid "Recent tags" -msgstr "最新标签" - -msgid "popular tags" -msgstr "受欢迎的标签" - -msgid "Recent awards" -msgstr "最新奖牌" - -msgid "given to" -msgstr "授予" - -msgid "all awards" -msgstr "所有奖牌" - -msgid "subscribe to last 30 questions by RSS" -msgstr "RSS订阅最新30个问题" - -msgid "Still looking for more? See" -msgstr "在寻找更多问题吗?请查阅" - -msgid "complete list of questions" -msgstr "全部问题列表" - -msgid "or" -msgstr "或者" - -msgid "." -msgstr "。" - -msgid "Please help us answer" -msgstr "请帮助我们回答" - -msgid "unanswered questions" -msgstr "没有回答的问题" - -msgid "Unanswered questions" -msgstr "没有回答的问题" - -#revisions_answer.html -msgid "Revision history" -msgstr "版本历史" - -msgid "back" -msgstr "返回" - -msgid "revision" -msgstr "版本" - -msgid "edit" -msgstr "编辑" - -msgid "asked" -msgstr "提问于" - -msgid "updated" -msgstr "更新于" - -msgid "Tag list" -msgstr "标签列表" - -msgid "by name" -msgstr "按名称排序" - -msgid "sorted alphabetically" -msgstr "按名称的字母先后顺序排序" - -msgid "by polularity" -msgstr "按流行程度排序" - -msgid "sorted by frequency of tag use" -msgstr "按标签被使用的次数排序" - -msgid "All tags matching query" -msgstr "匹配查询" - -msgid "all tags - make this empty in english" -msgstr "的所有标签" - -msgid "Nothing found." -msgstr "没有找到相关数据。" - -#paginator.html -msgid "previous" -msgstr "上一页" - -msgid "current page" -msgstr "当前页" - -msgid "next page" -msgstr "下一页" - -msgid "page number " -msgstr "第" - -msgid "number - make blank in english" -msgstr "页" - -msgid "Change tags" -msgstr "修改问题标签" - -msgid "tags are required" -msgstr "标签不能为空。" - -msgid "please use 5 tags or less" -msgstr "最多只能有5个标签" - -#todo: remove magic numbers from this file -msgid "up to 5 tags, less than 20 characters each" -msgstr "最多5个标签,每个标签长度小于20个字符。" - -msgid "Change now" -msgstr "现在修改" - -#synonym of above in Edit question -msgid "Save edit" -msgstr "现在修改" - -msgid "uses tags for the classification of questions" -msgstr "用标签来分类系统的信息" - -msgid "tag editors receive special awards from the community" -msgstr "修改标签的用户将授予特殊的社区奖牌" - -msgid "Why use and modify tags?" -msgstr "为什么我只能修改问题标签?" - -msgid "Found by tag" -msgstr "标签问题" - -msgid "Found by title" -msgstr "查询结果" - -msgid "All questions" -msgstr "所有问题" - -msgid "active" -msgstr "活跃问题" - -msgid "most recently asked questions" -msgstr "最新加入系统的问题" - -msgid "most recently updated questions" -msgstr "最近被更新的问题" - -msgid "latest questions info" -msgstr "" -"问题按<strong>提问时间</strong>显示排序。" -"新加入的问题将显示在最前面。" - -#: templates/questions.html:109 -#, python-format -msgid "" -"\n" -"\t\t\thave total %(q_num)s questions tagged %(tagname)s\n" -"\t\t\t" -msgid_plural "" -"\n" -"\t\t\thave total %(q_num)s questions tagged %(tagname)s\n" -"\t\t\t" -msgstr[0] "" -"\n" -"您正在浏览所有" -"<div class=\"questions-count\">%(q_num)s</div>" -"个标记为<span class=\"tag\">%(tagname)s</span></p>" -msgstr[1] "" -"\n" -"您正在浏览所有" -"<div class=\"questions-count\">%(q_num)s</div>" -"个标记为<span class=\"tag\">%(tagname)s</span></p>" - -#: templates/questions.html:109 -#, python-format -msgid "" -"\n" -"\t\t\thave total %(q_num)s questions containing %(searchtitle)s\n" -"\t\t\t" -msgid_plural "" -"\n" -"\t\t\thave total %(q_num)s questions containing %(searchtitle)s\n" -"\t\t\t" -msgstr[0] "" -"\n" -"您正在浏览所有" -"<div class=\"questions-count\">%(q_num)s</div>" -"个标题含有<span class=\"tag\">%(searchtitle)s</span></p>" -msgstr[1] "" -"\n" -"您正在浏览所有" -"<div class=\"questions-count\">%(q_num)s</div>" -"个标题含有<span class=\"tag\">%(searchtitle)s</span></p>" - -#in unanswered.html and somewhere else -msgid "Have a total of" -msgstr "您正在浏览所有" - -msgid "number of questions" -msgstr "个" - -msgid "number of <strong>unanswered</strong> questions" -msgstr "个 <span class=\"darkred\"><strong>没有回答的</strong></span> 问题。" - -msgid "tagged with" -msgstr "标记为" - -msgid "whose title contains" -msgstr "标题含有" - -msgid "number of questions end of sentence" -msgstr "的问题。" - -msgid "Questions are sorted by the <strong>time of last update</strong>." -msgstr "问题按<strong>最后更新时间</strong>显示排序。" - -msgid "Most recently answered ones are shown first." -msgstr "最后被回答或者>更新的问题将显示在最前面。" - -msgid "Questions sorted by <strong>number of responses</strong>." -msgstr "问题按<strong>回复数量</strong>显示排序。" - -msgid "Most answered questions are shown first" -msgstr "回复最多的问题将显示在最前面。" - -msgid "Questions are sorted by the <strong>number of votes</strong>." -msgstr "问题按<strong>投票数量</strong>显示排序。" - -msgid "Most voted questions are shown first" -msgstr "投票最多的问题将显示在最前面。" - -msgid "Related tags" -msgstr "相关标签" - -msgid "Reopen question" -msgstr "重设问题" - -msgid "Open the previously closed question" -msgstr "你将打开这个已经被关闭的问题" - -msgid "The question was closed for the following reason" -msgstr "问题曾以" - -msgid "reason - leave blank in english" -msgstr "的原因被" - -msgid "on" -msgstr "于" - -msgid "date closed" -msgstr "关闭" - -msgid "reopen this question" -msgstr "确定打开这个问题" - -msgid "Edit user profile" -msgstr "修改个人资料" - -msgid "edit profile" -msgstr "修改资料" - -msgid "image associated with your email address" -msgstr "和您的邮件地址是绑定的" - -msgid "avatar" -msgstr "修改头像" - -msgid "Registered user" -msgstr "注册用户" - -msgid "Update" -msgstr "更新" - -msgid "User profile" -msgstr "用户概览" - -msgid "overview" -msgstr "概览" - -msgid "recent activity" -msgstr "最近活动" - -msgid "comments and answers to others questions" -msgstr "其他用户的回复和评论" - -msgid "responses" -msgstr "回应" - -msgid "reputation history" -msgstr "积分" - -msgid "reputation" -msgstr "积分" - -msgid "graph of user reputation" -msgstr "用户的社区积分历史" - -msgid "user vote record" -msgstr "用户所有投票" - -msgid "casted votes" -msgstr "投票" - -msgid "questions that user selected as his/her favorite" -msgstr "用户收藏的问题" - -msgid "users favorite questions" -msgstr "用户收藏的问题" - -msgid "favorites" -msgstr "收藏" - -msgid "favorite-questions" -msgstr "收藏" - -msgid "user preference settings" -msgstr "用户参数的设置" - -msgid "settings" -msgstr "设置" - -msgid "preferences" -msgstr "设置" - -msgid "About" -msgstr "关于本站" - -msgid "logout" -msgstr "退出登录" - -msgid "Logout" -msgstr "退出登录" - -msgid "As a registered user you can login with your OpenID, log out of the site or permanently remove your account." -msgstr "您是系统的<strong class=\"darkred\">注册</strong>用户,可以随时使用OpenID帐号登录系统或者注销登录。" - -msgid "Logout now" -msgstr "点击退出登录" - -msgid "Frequently Asked Questions " -msgstr "常见问题" - -msgid "What kinds of questions can I ask here?" -msgstr "我可以在这里提问什么样的问题?" - -msgid "What questions should I avoid asking?" -msgstr "什么样的问题我不该在这里提问?" - -msgid "Most importanly - questions should be <strong>relevant</strong> to this community." -msgstr "毫无疑问,首先必须是<span class=\"yellowbg\">技术编程问题!</span>" - -msgid "Before asking the question - please make sure to use search to see whether your question has alredy been answered." -msgstr "提问之前,充分利用系统的自动查找、标签和搜索,看看是否已经有一样的问题并有了答案。" - -msgid "What should I avoid in my answers?" -msgstr "什么样的回答是不受欢迎的?" - -msgid "Who moderates this community?" -msgstr "谁是社区的管理员?" - -msgid "Please avoid asking questions that are not relevant to this community, too subjective and argumentative." -msgstr "<span class=\"yellowbg\">与程序员或技术无关的,引起争吵或太过于主观性等违背社区宗旨的内容。</span>本站建立是为了帮助大众程序员解决实际技术问题,我们需要实际的问题!" - -msgid "is a Q&A site, not a discussion group. Therefore - please avoid having discussions in your answers, comment facility allows some space for brief discussions." -msgstr "希望用户提供针对提问的技术回答,可以是进一步了解问题实质,给予参考方案,或完全解决问题的回答。我们希望通过问答的形式解决用户的实际问题。因此,<span class=\"yellowbg\">我们不>欢迎在回答中出现不是回答问题的内容,包括针对他人回答的讨论,和其他无意义的浪费网络资源行为</span>。CNProg建议您使用<span class=\"yellowbg\">评论</span>功能来讨论你的意见和想法。" - -msgid "The short answer is: <strong>you</strong>." -msgstr "答案是:<span class=\"yellowbg\">每个用户。</span>" - -msgid "The reputation system allows users earn the authorization to perform a variety of moderation tasks." -msgstr "通过积分运作,<span class=\"yellowbg\">每个用户都有权限创建标签,进行对所有问题、回答的投票、编辑、关闭等操作。</span>" - -msgid "This website is moderated by the users." -msgstr "社区没有严格意义上的管理员身份" - -msgid "How does reputation system work?" -msgstr "什么是社区积分?" - -msgid "Anyone can ask questions and give answers, points are not necessary for that." -msgstr "对于正常使用社区进行提问、回答而言,积分不是必须的。" - -msgid "As we've said before, users help running this site. Point system helps select users who can administer this community." -msgstr "我们一再声明,CNProg由你来运行和维护。如果你想帮助我们来运作CNProg,你需要一定的积分等级。" - -msgid "Reputation points roughly measure how community trusts you. These points are given to you directly by other members of the community." -msgstr "<span class=\"yellowbg\">积分是一种用来粗略衡量社区对你有多信任的数据。</span>积分不是有谁来支付或直接给予你的,而是你通过获得其他用户的支持和信任“赚得”的。" - -msgid "For example, if you ask an interesting question or give a helpful answer, your input will be upvoted and you will gain more trust in the community." -msgstr "举例来说,如果你提了一个非常有帮助的问题或者做了很有用的回答,你将会被其他用户投赞成票。" - -msgid "If on the other hand someone gives a misleading answer, the answer will be voted down and he/she loses some points." -msgstr "相反,你提了不受欢迎的问题,或者误导用户的回答,你将可能被其他用户投反对票。每个赞成" - -msgid "Each vote in favor will generate <strong>10</strong> points, each vote against will subtract <strong>2</strong> points." -msgstr "票会帮你产生<strong>10</strong>个社区积分,每个反对票会相应扣除你<strong>2</strong>个积分。" - -msgid "Through the votes of other people you can accumulate a maximum of <strong>200</strong> points." -msgstr "每天通过别人投赞成票,你最多只能产生<strong>200</strong>个积分,这是上限。" - -msgid "After accumulating certain number of points, you can do more:" -msgstr "当你累计到一定>积分,你可以在社区做更多的事情:" - -msgid "upvote" -msgstr "投赞成票" - -msgid "use tags" -msgstr "标记垃圾帖" - -msgid "add comment" -msgstr "添加评论" - -#todo - check if it's indeed plural -msgid "add comments" -msgstr "添加评论" - -msgid "comments" -msgstr "评论" - -msgid "downvote" -msgstr "投反对票" - -msgid "retag questions" -msgstr "给任何问题整理标签" - -msgid "edit community wiki questions" -msgstr "编辑wiki类问题" - -msgid "edit any answer" -msgstr "编辑任何问题或答案" - -msgid "reopen any closed questions" -msgstr "打开关闭任何人的问题" - -msgid "delete any comment" -msgstr "删除任何一个评论" - -msgid "delete any questions and answers and perform other moderation tasks" -msgstr "删除任何一个问题或答案,及其他管理功能" - -msgid "To register, do I need to create new password?" -msgstr "我需要注册一个新用户吗?" - -msgid "Why other people can edit my questions/answers?" -msgstr "为什么其他人可以修改我的问题/回答?" - -msgid "Still have questions?" -msgstr "还有其他问题?" - -msgid "Please ask your question, help make our community better!" -msgstr "如果您对社区还有其他疑问,请一起来完善我们的" - -msgid "No, you don't have to. You can login through any service that supports OpenID, e.g. Google, Yahoo, AOL, etc." -msgstr "不需要。社区提供了OpenID的登录支持,你要用Google、Yahoo等任何支持OpenID登录的帐号就可以使用系统。" - -msgid "Login now!" -msgstr "马上登录" - -msgid "Login" -msgstr "登录" - -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一样可编辑的,我们希望社区能帮助用户沉淀、积累更多有用的知识和经验。" - -msgid "If this approach is not for you, we respect your choice." -msgstr "如果您不喜欢这种方式,我们尊重你的选择。" - -msgid "Privacy policy" -msgstr "隐私政策" - -msgid "Site Visitors" -msgstr "网站访问者" - -msgid "Personal Information" -msgstr "个人身份信息" - -msgid "Other Services" -msgstr "其他服务" - -msgid "Policy Changes" -msgstr "政策更改" - -msgid "Sorry, could not find the page you requested." -msgstr "对不起,没有找到您请求的页面!" - -msgid "This might have happened for the following reasons:" -msgstr "有可能是以下原因导致:" - -msgid "this question or answer has been deleted;" -msgstr "你正在查看的问题或者回答已经被删除;" - -msgid "url has error - please check it;" -msgstr "请求的地址有误 - 请核实原始URL地址;" - -msgid "the page you tried to visit is protected or you don't have sufficient points, see" -msgstr "访问的页面被保护或你的积分不够,参见" - -msgid "if you believe this error 404 should not have occured, please" -msgstr "如果你确信不该出现404错误,请" - -msgid "report this problem" -msgstr "报告这个问题" - -msgid "back to previous page" -msgstr "返回前页" - -msgid "see all questions" -msgstr "查看最新问题" - -msgid "see all tags" -msgstr "查看标签列表" - -msgid "Edit answer" -msgstr "修改回答" - -msgid "hide preview" -msgstr "禁用预览" - -msgid "show preview" -msgstr "启用预览" - -msgid "select revision" -msgstr "选择版本" - -msgid "Toggle the real time Markdown editor preview" -msgstr "打开或者关闭Markdown编辑器的实时预览" - -msgid "toggle preview" -msgstr "预览开关" - -msgid "question tips" -msgstr "受欢迎的提问" - -msgid "answer tips" -msgstr "受欢迎的提问" - -msgid "try to give an answer, rather than engage into a discussion" -msgstr "建议您提的问题是可以被答复的,而不仅仅是可以讨论。" - -msgid "please try to provide details" -msgstr "请详细描述您的问题。" - -msgid "be clear and concise" -msgstr "我们推荐您使用中文描述问题,这样可以得到更多的答复机会。" - -msgid "see frequently asked questions" -msgstr "查看常见问题" - -msgid "learn more about Markdown" -msgstr "有关Markdown详细说明" - -msgid "basic HTML tags are also supported" -msgstr "基本的HTML标签也是支持的" - -msgid "numbered list:" -msgstr "列表:" - -msgid "image" -msgstr "图片" - -msgid "text" -msgstr "文本" - -msgid "title" -msgstr "标题" - -msgid "Markdown tips" -msgstr "Markdown快速参考" - -msgid "*italic* or _italic_" -msgstr "*斜体* 或者 _斜体_" - -msgid "**bold** or __bold__" -msgstr "**加粗** 或者 __加粗__ " - -msgid "link" -msgstr "链接" - -msgid "Badge" -msgstr "奖牌" - -msgid "The users have been awarded with badges:" -msgstr "用户已被授予该奖牌:" - -msgid "posts per page" -msgstr "每页显示" - -msgid "i like this post (click again to cancel)" -msgstr "这篇帖子有价值(再次点击取消操作)" - -msgid "i like this answer (click again to cancel)" -msgstr "这篇帖子有价值(再次点击取消操作)" - -msgid "current number of votes" -msgstr "当前总票数" - -msgid "i dont like this post (click again to cancel)" -msgstr "这篇帖子没有价值(再次点击取消操作)" - -msgid "i dont like this answer (click again to cancel)" -msgstr "这篇帖子没有价值(再次点击取消操作)" - -msgid "mark this question as favorite (click again to cancel)" -msgstr "我要收藏这个问题(再次点击取消操作)" - -msgid "remove favorite mark from this question (click again to restore mark)" -msgstr "我要收藏这个问题(再次点击取消操作)" - -msgid "delete" -msgstr "删除" - -#todo please check this in chinese -msgid "undelete" -msgstr "取消" - -#: templates/unanswered.html:98 -#, python-format -msgid "have %(num_q)s unanswered questions" -msgstr "" -"您正在浏览所有<br>" -"<div class=\"questions-count\">%(num_q)s</div>" -"个<p>问题按 <strong>问题创建时间</strong> 排序。最新加入的问题将显示在最前面。</p>" - -msgid "Change password" -msgstr "修改密码" - -msgid "Change email" -msgstr "更换电子邮件" - -msgid "Change OpenID" -msgstr "更换OpenID地址" - -msgid "Delete account" -msgstr "删除帐号" - -msgid "User login" -msgstr "用户登录" - -msgid "we support two login modes" -msgstr "CNProg支持<b>两种</b>登录模式。您可以使用帐号、密码登录,或者使用OpenID登录。" - -msgid "Login with your OpenID" -msgstr "使用OpenID登录" - -msgid "select openid provider" -msgstr "1)请选择您的帐号类:" - -msgid "verify openid link and login" -msgstr "2)型并完成正确的OpenID地址(如:替换“{username}”为您的对应帐号):" - -msgid "reopen" -msgstr "打开" - -msgid "close" -msgstr "关闭" - -msgid "report as offensive (i.e containing spam, advertising, malicious text, etc.)" -msgstr "检举该帖为垃“水帖”(含广告、人身攻击、恶意言论等)" - -msgid "flag offensive" -msgstr "垃圾帖?" - -msgid "login" -msgstr "登录" - -msgid "back to home page" -msgstr "回到首页" - -msgid "questions" -msgstr "问题" - -msgid "tags" -msgstr "标签" - -msgid "users" -msgstr "用户" - -msgid "books" -msgstr "读书" - -msgid "badges" -msgstr "奖牌榜" - -msgid "my profile" -msgstr "我的资料" - -msgid "ask a question" -msgstr "我要提问" - -msgid "Ask a question" -msgstr "我要提问" - -msgid "search" -msgstr "搜索" - -msgid "update profile" -msgstr "更新我的资料" - -msgid "real name" -msgstr "姓名" - -msgid "member for" -msgstr "已加入" - -msgid "ago" -msgstr "前" - -msgid "last seen" -msgstr "上次活动时间" - -msgid "user website" -msgstr "个人网站" - -msgid "location" -msgstr "城市" - -#user_info.html -msgid "age" -msgstr "年龄" - -msgid "age unit" -msgstr "岁" - -msgid "todays unused votes" -msgstr "今日剩余投票数" - -msgid "votes left" -msgstr "票" - -msgid "this answer has been selected as correct" -msgstr "该回答已被设为最佳答案" - -msgid "the answer has been voted for %d times" -msgstr "该回答总共有%d个投票" - -msgid "the answer has been commented %d times" -msgstr "该回答有%d条评论" - -msgid "votes total" -msgstr "个投票" - -msgid "user has voted up this many times" -msgstr "该用户投的赞成票总数" - -msgid "user has voted down this many times" -msgstr "用户投的反对票总数" - -msgid "Tags" -msgstr "个标签" - -msgid "see other questions tagged '%s'" -msgstr "查看有关'%s'的问题" - -msgid "Badges" -msgstr "枚奖牌" - -msgid "Badge summary" -msgstr "奖牌列表" - -msgid "Users" -msgstr "用户列表" - -msgid "recent" -msgstr "最新加入" - -msgid "oldest" -msgstr "最先加入" - -msgid "by username" -msgstr "用户名" - -msgid "user name" -msgstr "用户名" - -msgid "users matching query %s:" -msgstr "匹配查询 '<span class=\"darkred\"><strong>%s</strong></span>' 的所有用户名:" - -msgid "Below is the list of available badges and number of times each type of badge has been awarded." -msgstr "这里列出社区所有的奖牌,以及到目前为此,每个奖牌被授予的用户人数。" - -msgid "Community badges" -msgstr "社区奖牌" - -msgid "gold badge: the highest honor and is very rare" -msgstr "金牌:十分罕见之最高荣耀" - -msgid "silver badge: occasionally awarded for the very high quality contributions" -msgstr "银牌:偶尔颁发之优质奖章" - -msgid "gold" -msgstr "金牌" - -msgid "Gold badge is very rare." -msgstr "金牌是十分罕见的。" - -msgid "To obtain it you have to show profound knowledge and ability in addition to actively participating in the community." -msgstr "你不仅要参与社区的提问、回答、投票等活动,而且需要有高深的知识和能力才能获得。" - -msgid "Gold badge is the highest award in this community." -msgstr "获得金牌意味着你在某个层次上已经达到了顶峰。" - -msgid "silver" -msgstr "银牌" - -msgid "Obtaining silver badge requires significant patience." -msgstr "银牌需要经过长时间的奋斗才能获得。" - -msgid "If you got one, you have very significantly contributed to this community" -msgstr "它是不同寻常的荣誉,只要你付出足够的努力就会得到。" - -msgid "bronze badge: often given as a special honor" -msgstr "铜牌:时常授予之特殊荣誉" - -msgid "If you are active in this community, you will will get this medal - still it is a special honor." -msgstr "铜牌会在你活跃于社区时产生,它相对容易获得,但也是一种特殊的荣誉。" - -msgid "Use" -msgstr "使用" - -msgid "learn more about OpenID" -msgstr "了解更多有关OpenID的信息" - -msgid "Get your own" -msgstr "获取您自己的" - -msgid "User name" -msgstr "您的大名" - -msgid "Email: (won't be shown to anyone)" -msgstr "电子邮件:(不会公开显示)" - -msgid "Ask your question" -msgstr "现在提问" - -#page title -msgid "Edit question" -msgstr "修改问题" - -msgid "The question has been closed for the following reason \"%s\" by" -msgstr "问题以“%s”的原因已被" - -msgid "%s ago" -msgstr "于%s<font class=\"darkred\">关闭</font>" - -msgid "oldest answers" -msgstr "最先回答" - -msgid "newest answers" -msgstr "最近回答" - -msgid "popular answers" -msgstr "投票最多" - -msgid "oldest answers will be shown first" -msgstr "最先回答显示在最前面" - -msgid "newest answers will be shown first" -msgstr "最晚回答显示在最前面" - -msgid "most voted answers will be shown first" -msgstr "投票次数最多的显示在最前面" - -msgid "mark this answer as favorite (click again to undo)" -msgstr "最佳答案(再次点击取消操作)" - -msgid "the author of the question has selected this answer as correct" -msgstr "这个答案已经被提问作者标记为最佳答案" - -msgid "answer permanent link" -msgstr "该回答的链接地址" - -msgid "permanent link" -msgstr "永久链接" - -msgid "Your answer" -msgstr "您的回答" - -msgid "Answer the question" -msgstr "回答该问题" - -msgid "Login to answer" -msgstr "登录并回答该问题" - -msgid "Question tags" -msgstr "您正在浏览的问题含有以下标签" - -msgid "Question asked" -msgstr "提问时间" - -msgid "question was seen" -msgstr "目前浏览数量" - -msgid "times" -msgstr "次" - -msgid "last updated" -msgstr "最后更新时间" - -msgid "related questions" -msgstr "相似的问题" - -msgid "profile - responses" -msgstr "回应 - 用户资料" - -msgid "user reputation in the community" -msgstr "用户社区积分" - -msgid "profile - user reputation" -msgstr "积分 - 用户资料" - -msgid "profile - favorite questions" -msgstr "收藏 - 用户资料" - -msgid "profile - votes" -msgstr "投票 - 用户资料" - -msgid "profile - user preferences" -msgstr "设置 - 用户资料" - -msgid "uploading images is limited to users with >60 reputation points" -msgstr "上传图片只限于积分+60以上注册用户!" - -#todo take these out of settings -msgid "allowed file types are 'jpg', 'jpeg', 'gif', 'bmp', 'png', 'tiff'" -msgstr "只允许上传'jpg', 'jpeg', 'gif', 'bmp', 'png', 'tiff'类型的文件!" - -msgid "maximum upload file size is %sK" -msgstr "只允许上传%sK大小的文件!" - -msgid "Error uploading file. Please contact the site administrator. Thank you." -msgstr "在文件上传过程中产生了错误,请联系管理员,谢谢^_^" - -msgid "please enter a descriptive title for your question" -msgstr "请输入对问题具有描述性质的标题 - “帮忙!紧急求助!”不是建议的提问方式。" - -msgid "title must be > 10 characters" -msgstr "标题的长度必须大于10" - -msgid "content" -msgstr "内容" - -msgid "question content must be > 10 characters" -msgstr "内容至少要10个字符" - -msgid "please use space to separate tags (this enables autocomplete feature)" -msgstr "多个标签请用空格间隔-最多5个标签。(优先使用自动匹配的英文标签。)" - -msgid "tags must be shorter than 20 characters" -msgstr "每个标签的长度不超过20" - -msgid "please use following characters in tags: letters 'a-z', numbers, and characters '.-_#'" -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 "选择社区wiki模式,问答不计算积分,签名也不显示作者信息" - -msgid "update summary:" -msgstr "更新概要:" - -msgid "enter a brief summary of your revision (e.g. fixed spelling, grammar, improved style, this field is optional)" -msgstr "输入本次修改的简单概述(如:修改了别字,修正了语法,改进了样式等。非必填项。)" - -msgid "this email does not have to be linked to gravatar" -msgstr "不会公开,用于头像显示服务" - -msgid "Real name" -msgstr "真实姓名" - -msgid "Website" -msgstr "个人网站" - -msgid "Location" -msgstr "城市" - -msgid "Date of birth" -msgstr "生日" - -msgid "will not be shown, used to calculate age, format: YYYY-MM-DD" -msgstr "不会公开,只会显示您的年龄,格式为:YYYY-MM-DD" - -msgid "Profile" -msgstr "个人简介" - -msgid "this email has already been registered, please use another one" -msgstr "该电子邮件已被注册,请选择另一个再试。" - -msgid "duplicate question" -msgstr "完全重复的问题" - -msgid "too subjective and argumentative" -msgstr "太主观性、引起争吵的问题" - -msgid "is not an answer to the question" -msgstr "不是一个可以回答的“问题”" - -msgid "the question is answered, right answer was accepted" -msgstr "问题已经解决,已得到正确答案" - -msgid "problem is not reproducible or outdated" -msgstr "已经过时、不可重现的问题" - -msgid "question contains offensive inappropriate, or malicious remarks" -msgstr "恶意言论" - -msgid "spam or advertising" -msgstr "垃圾广告" - -msgid "question" -msgstr "提问" - -msgid "answer" -msgstr "回答" - -msgid "commented question" -msgstr "评论问题" - -msgid "edited question" -msgstr "修改问题" - -msgid "edited answer" -msgstr "修改回答" - -msgid "received award" -msgstr "获奖" - -msgid "marked best answer" -msgstr "标记最佳答案" - -msgid "upvoted" -msgstr "投赞成票" - -msgid "downvoted" -msgstr "投反对票" - -msgid "canceled vote" -msgstr "撤销投票" - -msgid "deleted question" -msgstr "删除问题" - -msgid "deleted answer" -msgstr "删除回答" - -msgid "marked offensive" -msgstr "标记垃圾帖" - -msgid "updated tags" -msgstr "更新标签" - -msgid "selected favorite" -msgstr "收藏" - -msgid "completed user profile" -msgstr "完成个人所有资料" - -msgid "[closed]" -msgstr "[已关闭]" - -msgid "[deleted]" -msgstr "[已删除]" - -msgid "initial version" -msgstr "初始版本" - -msgid "retagged" -msgstr "更新了标签" - -#todo: review this message may be confusing user -msgid "This account already exists, please use another." -msgstr "输入您的新帐号或者指定已经存在的帐号。" - -msgid "Sorry, looks like we have some errors:" -msgstr "请注意以下错误:" - -msgid "New account" -msgstr "新帐号" - -msgid "Use login name and password" -msgstr "使用帐号密码登录" - -msgid "User name (<i>will be shown to others, cannot be modified</i>)" -msgstr "用户名(<i>在社区显示友好名称,不可更改</i>)" - -msgid "Email (<i>not shared with anyone</i>)" -msgstr "电子邮件(<i>用于头像显示服务</i>)" - -msgid "create account" -msgstr "创建帐号" - -msgid "Existing account" -msgstr "已经存在的用户" - -msgid "password" -msgstr "密码" - -msgid "Password" -msgstr "密码" - -msgid "Register" -msgstr "确认" - -msgid "Forgot your password?" -msgstr "忘记密码?" - -msgid "Create new account" -msgstr "注册新帐号" - -msgid "Send new password" -msgstr "发送新密码" - -msgid "Lost your password? No problem - here you can reset it." -msgstr "丢失了您的密码? 你可以在这里重设密码。" - -msgid "Please enter your username below and new password will be sent to your registered e-mail" -msgstr "请输入用户名,新的密码会发送到你注册时候填写的电子邮件。" - -msgid "Reset password" -msgstr "重设密码" - -msgid "return to login" -msgstr "返回登录" - -msgid "back to login" -msgstr "返回登录" - -#todo - check translation or see if it's indeed true -msgid "Note: your new password will be activated only after you click the activation link in the email message" -msgstr "注意: 新的密码只有您在激活邮件中的链接后才会被激活。" - -msgid "Signup" -msgstr "注册帐号" - -msgid "We support two types of user registration: conventional username/password, and" -msgstr "我们支持两种注册方式,你可以使用常规的用户名、密码方式注册,或者" - -msgid "the OpenID method" -msgstr "使用OpenID帐号注册" - -msgid "Conventional registration" -msgstr "请注意以下错误:" - -msgid "choose a user name" -msgstr "选择一个用户名" - -msgid "your email address" -msgstr "您的电子邮件地址" - -msgid "choose password" -msgstr "密码" - -msgid "retype password" -msgstr "确认密码" - -msgid "Register with your OpenID" -msgstr "使用OpenID注册" - -msgid "sorry, this name can not be used, please try another" -msgstr "对不起,您不能注册该用户名,请换一个试试" - -msgid "this name is already in use - please try anoter" -msgstr "该用户名已被注册,请换一个试试" - -msgid "Why use OpenID?" -msgstr "为什么需要OpenID登录?" - -msgid "with openid it is easier" -msgstr "构建在OpenID网络认证上的本系统,不需要你注册新的帐号,即可使用我们系统的所有功能" - -msgid "openid is supported open standard" -msgstr "OpenID是有开放标准,并且有相关的基金组织提供支持" - -msgid "Find out more" -msgstr "查看更多" - -msgid "Get OpenID" -msgstr "获取OpenID" - -msgid "openid is widely adopted" -msgstr "全世界有1.6亿OpenID帐号,和10,000个支持OpenID的站点" - -msgid "reuse openid" -msgstr "用同一个帐号可登录互联网所有激活OpenID的网站" diff --git a/locale/zh_CN/LC_MESSAGES/django.po b/locale/zh_CN/LC_MESSAGES/django.po index 176e41dc..206f4b6f 100644 --- a/locale/zh_CN/LC_MESSAGES/django.po +++ b/locale/zh_CN/LC_MESSAGES/django.po @@ -1,79 +1,108 @@ -# Chinese translations for CNProg.com -# Copyright (C) 2009 -# This file is distributed under the same license as the CNPROG package. -# Mike Chen <chagel@gmail.com>, 2009. -# -#, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-07-15 13:53+0000\n" +"POT-Creation-Date: 2009-07-28 15:57+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" #: settings.py:12 +#, fuzzy msgid "account/" -msgstr "" +msgstr "新帐号" #: settings.py:12 django_authopenid/urls.py:9 django_authopenid/urls.py:11 msgid "signin/" msgstr "" #: django_authopenid/forms.py:67 django_authopenid/views.py:93 +#, fuzzy msgid "i-names are not supported" -msgstr "i-names不支持。" +msgstr "基本的HTML标签也是支持的" #: django_authopenid/forms.py:102 django_authopenid/forms.py:207 msgid "" "Usernames can only contain letters, numbers and " "underscores" -msgstr "用户名格式有误。只有字母,数字和下划线是允许的。" +msgstr "" #: django_authopenid/forms.py:109 msgid "" "This username does not exist in our database. Please " "choose another." -msgstr "用户名不存在。请重新输入。" +msgstr "" #: django_authopenid/forms.py:126 django_authopenid/forms.py:231 msgid "" "Please enter a valid username and password. Note that " "both fields are case-sensitive." -msgstr "请输入用户名和密码。注意区分大小写。" +msgstr "" #: django_authopenid/forms.py:130 django_authopenid/forms.py:235 msgid "This account is inactive." -msgstr "用户已冻结。" +msgstr "" + +# translation and user name validation are language-specific +#: django_authopenid/forms.py:158 +msgid "invalid user name" +msgstr "用户名只能包含英文字母、数字和下划线" + +#: django_authopenid/forms.py:160 +msgid "sorry, this name can not be used, please try another" +msgstr "对不起,您不能注册该用户名,请换一个试试" + +# minimal length of user name may be language specific +#: django_authopenid/forms.py:162 +msgid "username too short" +msgstr "用户名太短,请使用三个或三个以上字符" + +#: django_authopenid/forms.py:170 django_authopenid/forms.py:171 +msgid "this name is already in use - please try anoter" +msgstr "该用户名已被注册,请换一个试试" #: django_authopenid/forms.py:184 msgid "" "This email is already registered in our database. Please " "choose another." -msgstr "电子邮件已被注册。请使用一个新的邮件地址。" +msgstr "该电子邮件已被注册,请选择另一个再试。" #: django_authopenid/forms.py:214 msgid "" "This username don't exist. Please choose another." -msgstr "用户名不存在" +msgstr "" + +#: django_authopenid/forms.py:253 +msgid "choose a username" +msgstr "选择一个用户名" + +#: django_authopenid/forms.py:255 templates/authopenid/signup.html:36 +msgid "your email address" +msgstr "您的电子邮件地址" + +#: django_authopenid/forms.py:257 templates/authopenid/signup.html:37 +msgid "choose password" +msgstr "密码" + +#: django_authopenid/forms.py:259 templates/authopenid/signup.html:38 +msgid "retype password" +msgstr "确认密码" #: django_authopenid/forms.py:330 msgid "" "Old password is incorrect. Please enter the correct " "password." -msgstr "旧密码错误。" +msgstr "" #: django_authopenid/forms.py:342 msgid "new passwords do not match" -msgstr "新密码不匹配" +msgstr "" #: django_authopenid/forms.py:434 msgid "Incorrect username." -msgstr "用户名不正确" +msgstr "选择一个用户名" #: django_authopenid/urls.py:10 msgid "signout/" @@ -84,12 +113,14 @@ msgid "complete/" msgstr "" #: django_authopenid/urls.py:13 +#, fuzzy msgid "register/" -msgstr "" +msgstr "确认" #: django_authopenid/urls.py:14 +#, fuzzy msgid "signup/" -msgstr "" +msgstr "注册帐号" #: django_authopenid/urls.py:16 msgid "sendpw/" @@ -97,360 +128,977 @@ msgstr "" #: django_authopenid/urls.py:26 msgid "delete/" -msgstr "" +msgstr "删除" #: django_authopenid/views.py:99 #, python-format msgid "非法OpenID地址: %s" msgstr "" -#: django_authopenid/views.py:366 templates/index.html:78 +#: django_authopenid/views.py:366 msgid "Welcome" -msgstr "欢迎" +msgstr "" #: django_authopenid/views.py:456 +#, fuzzy msgid "Password changed." -msgstr "密码已更新。" +msgstr "密码" #: django_authopenid/views.py:488 msgid "Email changed." -msgstr "邮件地址已更新。" +msgstr "" #: django_authopenid/views.py:519 django_authopenid/views.py:671 #, python-format msgid "No OpenID %s found associated in our database" -msgstr "该OpenID %s 不在系统中。" +msgstr "" #: django_authopenid/views.py:523 django_authopenid/views.py:678 #, python-format msgid "The OpenID %s isn't associated to current user logged in" -msgstr "OpenID %s 没有和当前登录用户绑定。" +msgstr "" #: django_authopenid/views.py:531 msgid "Email Changed." -msgstr "邮件地址已更新。" +msgstr "" #: django_authopenid/views.py:606 msgid "This OpenID is already associated with another account." -msgstr "这个OpenID已经绑定到另外一个帐号。" +msgstr "" #: django_authopenid/views.py:611 #, python-format msgid "OpenID %s is now associated with your account." -msgstr "OpenID %s 已经绑定到您的帐号。" +msgstr "" +# todo please check this in chinese #: django_authopenid/views.py:681 +#, fuzzy msgid "Account deleted." -msgstr "帐号已删除。" +msgstr "取消" #: django_authopenid/views.py:721 +#, fuzzy msgid "Request for new password" -msgstr "找回密码" +msgstr "重设密码" #: django_authopenid/views.py:734 +#, fuzzy msgid "A new password has been sent to your email address." -msgstr "新的密码已经发送到您的邮件帐号。" +msgstr "和您的邮件地址是绑定的" #: django_authopenid/views.py:764 #, python-format msgid "" "Could not change password. Confirmation key '%s' is not " "registered." -msgstr "不能修改密码。确认信息 '%s' 有误。" +msgstr "" #: django_authopenid/views.py:773 msgid "" "Can not change password. User don't exist anymore in our " "database." -msgstr "不能修改密码。用户帐号不存在。" +msgstr "" #: django_authopenid/views.py:782 #, python-format msgid "Password changed for %s. You may now sign in." -msgstr "帐号 %s 的密码已经修改。您现在可以用它来登录。" +msgstr "" + +#: forum/const.py:8 +msgid "duplicate question" +msgstr "完全重复的问题" + +# chinese translation is domain specific +#: forum/const.py:9 +msgid "question if off-topic or not relevant" +msgstr "不是编程技术问题" + +#: forum/const.py:10 +msgid "too subjective and argumentative" +msgstr "太主观性、引起争吵的问题" + +#: forum/const.py:11 +msgid "is not an answer to the question" +msgstr "不是一个可以回答的“问题”" + +#: forum/const.py:12 +msgid "the question is answered, right answer was accepted" +msgstr "问题已经解决,已得到正确答案" + +#: forum/const.py:13 +msgid "problem is not reproducible or outdated" +msgstr "已经过时、不可重现的问题" + +#: forum/const.py:15 +msgid "question contains offensive inappropriate, or malicious remarks" +msgstr "恶意言论" + +#: forum/const.py:16 +msgid "spam or advertising" +msgstr "垃圾广告" + +#: forum/const.py:56 +msgid "question" +msgstr "提问" + +#: forum/const.py:57 templates/book.html:110 +msgid "answer" +msgstr "回答" + +#: forum/const.py:58 +msgid "commented question" +msgstr "评论问题" + +#: forum/const.py:59 +#, fuzzy +msgid "commented answer" +msgstr "修改回答" + +#: forum/const.py:60 +msgid "edited question" +msgstr "修改问题" + +#: forum/const.py:61 +msgid "edited answer" +msgstr "修改回答" + +#: forum/const.py:62 +msgid "received award" +msgstr "获奖" + +#: forum/const.py:63 +msgid "marked best answer" +msgstr "标记最佳答案" + +#: forum/const.py:64 +msgid "upvoted" +msgstr "投赞成票" + +#: forum/const.py:65 +msgid "downvoted" +msgstr "投反对票" + +#: forum/const.py:66 +msgid "canceled vote" +msgstr "撤销投票" + +#: forum/const.py:67 +msgid "deleted question" +msgstr "删除问题" + +#: forum/const.py:68 +msgid "deleted answer" +msgstr "删除回答" + +#: forum/const.py:69 +msgid "marked offensive" +msgstr "标记垃圾帖" + +#: forum/const.py:70 +msgid "updated tags" +msgstr "更新标签" + +#: forum/const.py:71 +msgid "selected favorite" +msgstr "收藏" + +#: forum/const.py:72 +msgid "completed user profile" +msgstr "完成个人所有资料" + +#: forum/const.py:83 +msgid "[closed]" +msgstr "[已关闭]" + +#: forum/const.py:84 +msgid "[deleted]" +msgstr "[已删除]" + +#: forum/const.py:85 +msgid "initial version" +msgstr "初始版本" + +#: forum/const.py:86 +msgid "retagged" +msgstr "更新了标签" + +#: forum/feed.py:17 +msgid "site title" +msgstr "CNProg.com" + +#: forum/feed.py:17 +msgid " - " +msgstr "-" + +#: forum/feed.py:17 +msgid "site slogan" +msgstr "程序员问答社区" + +#: forum/feed.py:17 +msgid "latest questions" +msgstr "最新问题" -#: forum/user.py:17 -msgid "Overview" +#: forum/feed.py:20 +msgid "meta site content" +msgstr "中国程序员的编程技术问答社区。我们做专业的、可协作编辑的技术问答社区。" + +#: forum/feed.py:22 +msgid "copyright message" +msgstr "Copyright(c)2009.CNPROG.COM" + +#: forum/forms.py:14 templates/question_edit_tips.html:31 +#: templates/question_edit_tips.html:36 +msgid "title" +msgstr "标题" + +#: forum/forms.py:15 +msgid "please enter a descriptive title for your question" +msgstr "" +"请输入对问题具有描述性质的标题 - “帮忙!紧急求助!”不是建议的提问方式。" + +#: forum/forms.py:20 +msgid "title must be > 10 characters" +msgstr "标题的长度必须大于10" + +#: forum/forms.py:29 +msgid "content" +msgstr "内容" + +#: forum/forms.py:35 +msgid "question content must be > 10 characters" +msgstr "内容至少要10个字符" + +#: forum/forms.py:45 templates/header.html:30 templates/header.html.py:61 +msgid "tags" +msgstr "标签" + +#: forum/forms.py:46 +msgid "please use space to separate tags (this enables autocomplete feature)" +msgstr "多个标签请用空格间隔-最多5个标签。(优先使用自动匹配的英文标签。)" + +#: forum/forms.py:53 +msgid "tags are required" +msgstr "标签不能为空。" + +#: forum/forms.py:57 +msgid "please use 5 tags or less" +msgstr "最多只能有5个标签" + +#: forum/forms.py:60 +msgid "tags must be shorter than 20 characters" +msgstr "每个标签的长度不超过20" + +#: forum/forms.py:64 +msgid "" +"please use following characters in tags: letters 'a-z', numbers, and " +"characters '.-_#'" +msgstr "标签请使用英文字母,中文或者数字字符串(. - _ # 也可以)" + +# index.html +#: forum/forms.py:74 templates/index.html:56 templates/question.html:196 +#: templates/question.html.py:377 templates/unanswered.html:48 +#: templates/unanswered.html.py:60 +msgid "community wiki" +msgstr "社区Wiki" + +#: forum/forms.py:75 +msgid "" +"if you choose community wiki option, the question and answer do not generate " +"points and name of author will not be shown" +msgstr "选择社区wiki模式,问答不计算积分,签名也不显示作者信息" + +#: forum/forms.py:84 +msgid "update summary:" +msgstr "更新概要:" + +#: forum/forms.py:85 +msgid "" +"enter a brief summary of your revision (e.g. fixed spelling, grammar, " +"improved style, this field is optional)" +msgstr "" +"输入本次修改的简单概述(如:修改了别字,修正了语法,改进了样式等。非必填" +"项。)" + +#: forum/forms.py:160 +msgid "this email does not have to be linked to gravatar" +msgstr "不会公开,用于头像显示服务" + +#: forum/forms.py:161 +msgid "Real name" +msgstr "真实姓名" + +#: forum/forms.py:162 +msgid "Website" +msgstr "个人网站" + +#: forum/forms.py:163 +msgid "Location" +msgstr "城市" + +#: forum/forms.py:164 +msgid "Date of birth" +msgstr "生日" + +#: forum/forms.py:164 +msgid "will not be shown, used to calculate age, format: YYYY-MM-DD" +msgstr "不会公开,只会显示您的年龄,格式为:YYYY-MM-DD" + +#: forum/forms.py:165 templates/authopenid/settings.html:20 +msgid "Profile" +msgstr "个人简介" + +#: forum/forms.py:190 forum/forms.py:191 +msgid "this email has already been registered, please use another one" +msgstr "该电子邮件已被注册,请选择另一个再试。" + +#: forum/models.py:316 templates/badges.html:50 +msgid "gold" +msgstr "金牌" + +#: forum/models.py:317 templates/badges.html:58 +msgid "silver" +msgstr "银牌" + +#: forum/models.py:318 templates/badges.html:65 +msgid "bronze" +msgstr "" + +#: forum/user.py:17 templates/user_tabs.html:7 +msgid "overview" msgstr "概览" #: forum/user.py:18 -msgid "User overview" +#, fuzzy +msgid "user profile" msgstr "用户概览" #: forum/user.py:19 -msgid "Overview - User Profile" -msgstr "概览-用户资料" +#, fuzzy +msgid "user profile overview" +msgstr "用户概览" -#: forum/user.py:25 -msgid "Recent" +#: forum/user.py:25 templates/user_tabs.html:9 +msgid "recent activity" msgstr "最近活动" #: forum/user.py:26 -msgid "Recent activities" -msgstr "用户最近活动情况" +#, fuzzy +msgid "recent user activity" +msgstr "最近活动" #: forum/user.py:27 -msgid "Recent - User Profile" -msgstr "最近活动-用户资料" +#, fuzzy +msgid "profile - recent activity" +msgstr "最近活动" -#: forum/user.py:34 -msgid "Response" +#: forum/user.py:34 templates/user_tabs.html:13 +msgid "responses" msgstr "回应" -#: forum/user.py:35 -msgid "Responses from others" -msgstr "其他用户的回答和评论" +#: forum/user.py:35 templates/user_tabs.html:12 +msgid "comments and answers to others questions" +msgstr "其他用户的回复和评论" #: forum/user.py:36 -msgid "Response - User Profile" -msgstr "回应-用户资料" +msgid "profile - responses" +msgstr "回应 - 用户资料" -#: forum/user.py:43 -msgid "Reputation" +#: forum/user.py:43 templates/user_info.html:23 templates/users.html:25 +msgid "reputation" msgstr "积分" #: forum/user.py:44 -msgid "Community reputation" -msgstr "社区积分" +msgid "user reputation in the community" +msgstr "用户社区积分" #: forum/user.py:45 -msgid "Reputation - User Profile" -msgstr "积分-用户资料" +msgid "profile - user reputation" +msgstr "积分 - 用户资料" #: forum/user.py:51 -msgid "Favorites" +#, fuzzy +msgid "favorite questions" msgstr "收藏" #: forum/user.py:52 -msgid "User's favorite questions" +msgid "users favorite questions" msgstr "用户收藏的问题" #: forum/user.py:53 -msgid "Favorites - User Profile" -msgstr "收藏-用户资料" +msgid "profile - favorite questions" +msgstr "收藏 - 用户资料" -#: forum/user.py:60 templates/index.html:46 templates/questions.html:45 -msgid "Votes" +#: forum/user.py:60 templates/user_tabs.html:20 +msgid "casted votes" msgstr "投票" -#: forum/user.py:61 -msgid "Votes history" -msgstr "用户投票历史" +#: forum/user.py:61 templates/user_tabs.html:20 +msgid "user vote record" +msgstr "用户所有投票" #: forum/user.py:62 -msgid "Votes - User Profile" -msgstr "投票-用户资料" +msgid "profile - votes" +msgstr "投票 - 用户资料" #: forum/user.py:69 -msgid "Preferences" +msgid "preferences" msgstr "设置" -#: forum/user.py:70 -msgid "User preferences" -msgstr "用户参数设置" +#: forum/user.py:70 templates/user_tabs.html:28 +msgid "user preference settings" +msgstr "用户参数的设置" #: forum/user.py:71 -msgid "Preferences - User Profile" -msgstr "设置-用户资料" +msgid "profile - user preferences" +msgstr "设置 - 用户资料" -#: templates/badges.html:5 templates/badges.html.py:16 -#: templates/header.html:31 -msgid "Badges" +#: forum/views.py:1726 +msgid "uploading images is limited to users with >60 reputation points" +msgstr "上传图片只限于积分+60以上注册用户!" + +# todo take these out of settings +#: forum/views.py:1728 +msgid "allowed file types are 'jpg', 'jpeg', 'gif', 'bmp', 'png', 'tiff'" +msgstr "只允许上传'jpg', 'jpeg', 'gif', 'bmp', 'png', 'tiff'类型的文件!" + +#: forum/views.py:1730 +#, python-format +msgid "maximum upload file size is %sK" +msgstr "只允许上传%sK大小的文件!" + +#: forum/views.py:1732 +#, fuzzy, python-format +msgid "" +"Error uploading file. Please contact the site administrator. Thank you. %s" +msgstr "在文件上传过程中产生了错误,请联系管理员,谢谢^_^" + +#: forum/templatetags/extra_tags.py:139 forum/templatetags/extra_tags.py:168 +#: templates/header.html:33 +msgid "badges" msgstr "奖牌榜" -#: templates/base.html:53 templates/base_content.html:52 -msgid "Congratulations! You have new badges: " -msgstr "恭喜您被授予奖牌:" +#: forum/templatetags/extra_tags.py:140 forum/templatetags/extra_tags.py:167 +#, fuzzy +msgid "reputation points" +msgstr "积分" + +#: forum/templatetags/extra_tags.py:221 +#, fuzzy +msgid " ago" +msgstr "前" + +#: templates/404.html:24 +msgid "Sorry, could not find the page you requested." +msgstr "对不起,没有找到您请求的页面!" + +#: templates/404.html:26 +msgid "This might have happened for the following reasons:" +msgstr "有可能是以下原因导致:" + +#: templates/404.html:28 +msgid "this question or answer has been deleted;" +msgstr "你正在查看的问题或者回答已经被删除;" + +#: templates/404.html:29 +msgid "url has error - please check it;" +msgstr "请求的地址有误 - 请核实原始URL地址;" + +#: templates/404.html:30 +msgid "" +"the page you tried to visit is protected or you don't have sufficient " +"points, see" +msgstr "访问的页面被保护或你的积分不够,参见" + +#: templates/404.html:31 +msgid "if you believe this error 404 should not have occured, please" +msgstr "如果你确信不该出现404错误,请" + +#: templates/404.html:32 +msgid "report this problem" +msgstr "报告这个问题" + +#: templates/404.html:41 templates/500.html:27 +msgid "back to previous page" +msgstr "返回前页" + +#: templates/404.html:42 +msgid "see all questions" +msgstr "查看最新问题" + +#: templates/404.html:43 +msgid "see all tags" +msgstr "查看标签列表" + +#: templates/500.html:24 +msgid "system error log is recorded, error will be fixed as soon as possible" +msgstr "" + +#: templates/500.html:25 +msgid "please report the error to the site administrators if you wish" +msgstr "" + +#: templates/500.html:28 +#, fuzzy +msgid "see latest questions" +msgstr "最新问题" + +#: templates/500.html:29 +#, fuzzy +msgid "see tags" +msgstr "标记垃圾帖" + +#: templates/answer_edit.html:4 templates/answer_edit.html.py:47 +msgid "Edit answer" +msgstr "修改回答" + +#: templates/answer_edit.html:24 templates/answer_edit.html.py:27 +#: templates/ask.html:25 templates/ask.html.py:28 templates/question.html:37 +#: templates/question.html.py:40 templates/question_edit.html:27 +msgid "hide preview" +msgstr "禁用预览" + +#: templates/answer_edit.html:27 templates/ask.html:28 +#: templates/question.html:40 templates/question_edit.html:27 +msgid "show preview" +msgstr "启用预览" + +#: templates/answer_edit.html:47 templates/question_edit.html:65 +#: templates/revisions_answer.html:36 templates/revisions_question.html:36 +msgid "back" +msgstr "返回" + +#: templates/answer_edit.html:52 templates/question_edit.html:70 +#: templates/revisions_answer.html:47 templates/revisions_question.html:47 +msgid "revision" +msgstr "版本" + +#: templates/answer_edit.html:55 templates/question_edit.html:74 +msgid "select revision" +msgstr "选择版本" + +#: templates/answer_edit.html:62 templates/ask.html:81 +#: templates/question.html:447 templates/question_edit.html:91 +msgid "Toggle the real time Markdown editor preview" +msgstr "打开或者关闭Markdown编辑器的实时预览" + +#: templates/answer_edit.html:62 templates/ask.html:81 +#: templates/question.html:447 templates/question_edit.html:91 +msgid "toggle preview" +msgstr "预览开关" + +# synonym of above in Edit question +#: templates/answer_edit.html:73 templates/question_edit.html:119 +msgid "Save edit" +msgstr "现在修改" + +#: templates/answer_edit.html:74 templates/close.html:29 +#: templates/question_edit.html:120 templates/reopen.html:30 +#: templates/user_edit.html:83 +msgid "Cancel" +msgstr "取消" + +#: templates/ask.html:4 templates/ask.html.py:60 +msgid "Ask a question" +msgstr "我要提问" + +#: templates/ask.html:106 +msgid "Use" +msgstr "使用" + +#: templates/ask.html:106 +msgid "learn more about OpenID" +msgstr "了解更多有关OpenID的信息" -#: templates/base.html:54 templates/base_content.html:53 -msgid "go to see" +#: templates/ask.html:106 templates/authopenid/signin.html:35 +#: templates/authopenid/signin.html:61 +msgid "Login" +msgstr "登录" + +#: templates/ask.html:109 +#, fuzzy +msgid "Get your own " +msgstr "获取您自己的" + +#: templates/ask.html:117 templates/authopenid/sendpw.html:27 +msgid "User name" +msgstr "您的大名" + +#: templates/ask.html:120 +msgid "Email: (won't be shown to anyone)" +msgstr "电子邮件:(不会公开显示)" + +#: templates/ask.html:127 +msgid "Ask your question" +msgstr "现在提问" + +#: templates/badge.html:6 templates/badge.html.py:17 +msgid "Badge" +msgstr "奖牌" + +#: templates/badge.html:26 +msgid "The users have been awarded with badges:" +msgstr "用户已被授予该奖牌:" + +#: templates/badges.html:5 +#, fuzzy +msgid "Badges summary" +msgstr "奖牌列表" + +#: templates/badges.html:16 templates/user_stats.html:113 +msgid "Badges" +msgstr "枚奖牌" + +#: templates/badges.html:20 +#, fuzzy +msgid "" +"Community gives you awards for your questions, answers and votes. Below is " +"the list of available badges and number of times each type of badge has been " +"awarded." +msgstr "这里列出社区所有的奖牌,以及到目前为此,每个奖牌被授予的用户人数。" + +#: templates/badges.html:47 +msgid "Community badges" +msgstr "社区奖牌" + +#: templates/badges.html:53 +#, fuzzy +msgid "" +"Gold badge is very rare. To obtain it you have to show profound knowledge " +"and ability in addition to actively participating in the community. Gold " +"badge is the highest award in this community." +msgstr "" +"你不仅要参与社区的提问、回答、投票等活动,而且需要有高深的知识和能力才能获" +"得。" + +#: templates/badges.html:61 +#, fuzzy +msgid "" +"Obtaining silver badge requires significant patience. If you got one, you've " +"very significantly contributed to this community" +msgstr "它是不同寻常的荣誉,只要你付出足够的努力就会得到。" + +#: templates/badges.html:64 +msgid "bronze badge: often given as a special honor" +msgstr "铜牌:时常授予之特殊荣誉" + +#: templates/badges.html:68 +#, fuzzy +msgid "" +"If you are active in this community, you will get this medal - still it is a " +"special honor." +msgstr "铜牌会在你活跃于社区时产生,它相对容易获得,但也是一种特殊的荣誉。" + +# base_content.html +#: templates/base.html:61 templates/base_content.html:60 +msgid "congratulations, community gave you a badge" +msgstr "恭喜您,社区给您颁发了奖牌" + +#: templates/base.html:63 templates/base_content.html:62 +msgid "profile" +msgstr "个人资料" + +#: templates/base_content.html:61 +msgid "see" msgstr "查看" -#: templates/base.html:55 templates/base_content.html:54 -#: templates/header.html:35 -msgid "Profile" -msgstr "我的资料" +# templates/book.html 78 +#: templates/book.html:7 +msgid "reading channel" +msgstr "读书频道" + +#: templates/book.html:26 +msgid "[author]" +msgstr "【作者】" + +#: templates/book.html:30 +msgid "[publisher]" +msgstr "【出版社】" + +#: templates/book.html:34 +msgid "[publication date]" +msgstr "【出版日期】" + +#: templates/book.html:38 +msgid "[price]" +msgstr "【价格】" + +#: templates/book.html:39 +msgid "currency unit" +msgstr "" -#: templates/footer.html:5 templates/header.html:10 templates/index.html:81 +#: templates/book.html:42 +msgid "[pages]" +msgstr "【页数】" + +#: templates/book.html:43 +msgid "pages abbreviation" +msgstr "" + +#: templates/book.html:46 +msgid "[tags]" +msgstr "【标签】" + +#: templates/book.html:56 +msgid "author blog" +msgstr "作者博客" + +#: templates/book.html:62 +msgid "book directory" +msgstr "书籍目录" + +#: templates/book.html:66 +msgid "buy online" +msgstr "网上购买" + +#: templates/book.html:79 +msgid "reader questions" +msgstr "答读者问" + +#: templates/book.html:82 +msgid "ask the author" +msgstr "向作者提问" + +#: templates/book.html:88 templates/book.html.py:93 +#: templates/users_questions.html:17 +msgid "this question was selected as favorite" +msgstr "这个问题被" + +#: templates/book.html:88 templates/book.html.py:93 +#: templates/users_questions.html:11 templates/users_questions.html.py:17 +msgid "number of times" +msgstr "位用户收藏" + +#: templates/book.html:105 templates/index.html:47 +#: templates/unanswered.html:37 templates/users_questions.html:30 +msgid "votes" +msgstr "票" + +#: templates/book.html:108 +msgid "the answer has been accepted to be correct" +msgstr "有答案已被接受为正确答案" + +#: templates/book.html:115 templates/index.html:48 +#: templates/unanswered.html:38 templates/users_questions.html:40 +msgid "views" +msgstr "浏览" + +# book.html line 123 must be empty in english +#: templates/book.html:125 templates/index.html:68 templates/question.html:112 +#: templates/question.html.py:479 templates/tags.html:46 +#: templates/unanswered.html:75 templates/unanswered.html.py:109 +#: templates/users_questions.html:52 +msgid "using tags" +msgstr "的问题" + +#: templates/book.html:147 +msgid "subscribe to book RSS feed" +msgstr "RSS订阅该图书最新问题" + +#: templates/book.html:147 templates/index.html:115 +msgid "subscribe to the questions feed" +msgstr "订阅最>新问题" + +# close.html +#: templates/close.html:6 templates/close.html.py:16 +msgid "Close question" +msgstr "关闭问题" + +#: templates/close.html:19 +msgid "Close the question" +msgstr "由于以下原因,你要关闭这个问题" + +#: templates/close.html:25 +msgid "Reasons" +msgstr "原因" + +#: templates/close.html:28 +msgid "OK to close" +msgstr "确定关闭" + +#: templates/footer.html:5 +#, fuzzy msgid "About us" -msgstr "关于我们" +msgstr "关于本站" -#: templates/footer.html:6 templates/header.html:11 +#: templates/footer.html:6 templates/header.html:13 templates/index.html:83 msgid "faq" msgstr "常见问题" #: templates/footer.html:8 +#, fuzzy msgid "Contact" msgstr "联系我们" #: templates/footer.html:9 +#, fuzzy msgid "Privacy" msgstr "隐私政策" #: templates/footer.html:10 +#, fuzzy msgid "Feedback" -msgstr "用户反馈" +msgstr "问题反馈" -#: templates/header.html:6 templates/logout.html:5 templates/logout.html.py:16 -msgid "Logout" +#: templates/header.html:8 +msgid "logout" msgstr "退出登录" -#: templates/header.html:8 -msgid "Login" +#: templates/header.html:10 templates/authopenid/signup.html:39 +msgid "login" msgstr "登录" -#: templates/header.html:21 -msgid "link to homepage" -msgstr "返回首页" +# footer.html +#: templates/header.html:12 templates/index.html:82 +msgid "about" +msgstr "关于本站" -#: templates/header.html:27 templates/header.html.py:56 -#: templates/index.html:21 -msgid "Questions" -msgstr "问题" +#: templates/header.html:23 +msgid "back to home page" +msgstr "回到首页" -#: templates/header.html:28 templates/header.html.py:57 -msgid "Tags" -msgstr "标签" +#: templates/header.html:29 templates/header.html.py:60 +msgid "questions" +msgstr "问题" -#: templates/header.html:29 templates/header.html.py:58 -msgid "Users" +#: templates/header.html:31 templates/header.html.py:62 +msgid "users" msgstr "用户" -#: templates/header.html:30 -msgid "Books" +#: templates/header.html:32 +msgid "books" msgstr "读书" -#: templates/header.html:32 -msgid "Unanswered" +#: templates/header.html:34 templates/index.html:120 +msgid "unanswered questions" msgstr "没有回答的问题" #: templates/header.html:38 -msgid "Ask a question" +msgid "my profile" +msgstr "我的资料" + +#: templates/header.html:42 +msgid "ask a question" msgstr "我要提问" -#: templates/header.html:53 -msgid "Search" +#: templates/header.html:57 +msgid "search" msgstr "搜索" #: templates/index.html:6 msgid "Home" msgstr "首页" -#: templates/index.html:23 templates/questions.html:25 -msgid "Newest updated questions" +#: templates/index.html:21 +msgid "Questions" +msgstr "问题列表" + +#: templates/index.html:23 +msgid "last updated questions" msgstr "最新更新的问题" -#: templates/index.html:23 templates/questions.html:24 -msgid "Newest" +#: templates/index.html:23 templates/unanswered.html:20 +msgid "newest" msgstr "最新问题" -#: templates/index.html:24 templates/questions.html:26 -msgid "Questions with most answers" +#: templates/index.html:24 +msgid "hottest questions" msgstr "被回复最多的问题" -#: templates/index.html:24 templates/questions.html:26 -msgid "Hottest" -msgstr "最热问题" +#: templates/index.html:24 +msgid "hottest" +msgstr "热门问题" -#: templates/index.html:25 templates/questions.html:27 -msgid "Questions with most votes" -msgstr "被投票最多的问题" +#: templates/index.html:25 +msgid "most voted questions" +msgstr "投票次数最多的问题" -#: templates/index.html:25 templates/questions.html:27 -msgid "Best" -msgstr "最有价值问题" - -#: templates/index.html:26 templates/index.html.py:118 -#: templates/questions.html:22 -msgid "All questions" -msgstr "所有问题" +#: templates/index.html:25 +#"最有价值问题" +#"最新问题" +msgid "most voted" +msgstr "最有价值的问题" #: templates/index.html:26 -msgid "All" -msgstr "所有问题" +msgid "all questions" +msgstr "全部问题" -#: templates/index.html:45 templates/questions.html:44 -msgid "Answers" +#: templates/index.html:46 templates/unanswered.html:36 +#: templates/users_questions.html:35 +msgid "answers" msgstr "回答" -#: templates/index.html:47 templates/questions.html:46 -msgid "Visits" -msgstr "访问" - -#: templates/index.html:55 templates/questions.html:57 -#: templates/questions.html.py:69 -msgid "Community wiki" -msgstr "社区wiki" +# must have extra space after in english +#: templates/index.html:68 templates/question.html:112 +#: templates/question.html.py:479 templates/tags.html:46 +#: templates/unanswered.html:75 templates/unanswered.html.py:109 +#: templates/users_questions.html:52 +msgid "see questions tagged" +msgstr "查看有关" -#: templates/index.html:67 templates/index.html.py:91 -#: templates/questions.html:83 -msgid "Browse questions with tag of " -msgstr "查看所有以下主题问题:" +#: templates/index.html:79 +msgid "welcome to website" +msgstr "CNProg欢迎您!" -#: templates/index.html:87 +#: templates/index.html:88 msgid "Recent tags" msgstr "最新标签" -#: templates/index.html:94 templates/index.html.py:118 -msgid "Popular tags" +# this is how above two are supposed to be +#: templates/index.html:93 +#, fuzzy, python-format +msgid "see questions tagged '%(tagname)s'" +msgstr "查看有关'%(tagname)s'的问题" + +#: templates/index.html:96 templates/index.html.py:120 +msgid "popular tags" msgstr "受欢迎的标签" -#: templates/index.html:98 -msgid "Recent badges" +#: templates/index.html:100 +msgid "Recent awards" msgstr "最新奖牌" -#: templates/index.html:109 -msgid "All badges" +#: templates/index.html:106 +msgid "given to" +msgstr "授予" + +#: templates/index.html:111 +msgid "all awards" msgstr "所有奖牌" -#: templates/index.html:113 -msgid "RSS feed of recent 30 questions" +#: templates/index.html:115 +msgid "subscribe to last 30 questions by RSS" msgstr "RSS订阅最新30个问题" -#: templates/index.html:113 -msgid "Subscribe" -msgstr "订阅最新问题" - -#: templates/index.html:118 -msgid "Are you looking for more questions? Try to browse" +#: templates/index.html:120 +msgid "Still looking for more? See" msgstr "在寻找更多问题吗?请查阅" -#: templates/index.html:118 -msgid " or " -msgstr " 或者 " +#: templates/index.html:120 +#, fuzzy +msgid "complete list of quesionts" +msgstr "全部问题列表" -#: templates/index.html:118 -msgid ". Please help us answer " -msgstr "。请帮助我们回答" +#: templates/index.html:120 +msgid "or" +msgstr "或者" -#: templates/index.html:118 -msgid "Unanswered questions" -msgstr "没有回答的问题" +#: templates/index.html:120 +msgid "." +msgstr "。" #: templates/pagesize.html:5 -msgid "Size per page:" +msgid "posts per page" msgstr "每页显示:" #: templates/paginator.html:5 -msgid "Previous" +msgid "previous" msgstr "上一页" -#: templates/questions.html:6 -msgid "Question list" -msgstr "问题列表" - #: templates/questions.html:22 -msgid "Tagged questions" +msgid "Found by tags" msgstr "标签问题" -#: templates/questions.html:22 -msgid "Query result" -msgstr "查询结果" - -#: templates/questions.html:24 -msgid "New questions" -msgstr "最新问题" - #: templates/questions.html:25 msgid "Active" msgstr "活跃问题" @@ -463,76 +1111,773 @@ msgstr "相关标签" msgid "Account: change email" msgstr "修改电子邮件" -#: templates/authopenid/changeemail.html:13 +#: templates/index.html:120 +msgid "Please help us answer" +msgstr "请帮助我们回答" + +#: templates/logout.html:6 templates/logout.html.py:17 +msgid "Logout" +msgstr "退出登录" + +#: templates/logout.html:20 +msgid "" +"As a registered user you can login with your OpenID, log out of the site or " +"permanently remove your account." +msgstr "" +"您是系统的<strong class=\"darkred\">注册</strong>用户,可以随时使用OpenID帐号" +"登录系统或者注销登录。" + +#: templates/logout.html:21 +msgid "Logout now" +msgstr "点击退出登录" + +#: templates/pagesize.html:5 +#, fuzzy +msgid "Size per page:" +msgstr "每页显示" + +#: templates/privacy.html:6 templates/privacy.html.py:11 +msgid "Privacy policy" +msgstr "隐私政策" + +#: templates/privacy.html:15 +msgid "general message about privacy" +msgstr "" +"CNProg承认用户隐私的重要性。本文件概述在您浏览CNProg过程中所接收和收集的个人" +"信息的种类,以及CNProg所采取的保护信息的一些措施。CNProg希望这将有助于您在知" +"情的情况下,就和我们 共享个人信息的问题作出决定。" + +#: templates/privacy.html:18 +msgid "Site Visitors" +msgstr "网站访问者" + +#: templates/privacy.html:20 +msgid "what technical information is collected about visitors" +msgstr "" +"当您访问本网站或使用我们的某些在线服务时,服务器会自动记录信息,包括但不限于" +"URL、IP地址、浏览器的类型、屏幕分辨率、系统类型和使用的语言以及访问日期和时" +"间。我们的目的是为了向您>提供更好的用户服务,包括可能为您提供定制的在线服务。" + +#: templates/privacy.html:23 +msgid "Personal Information" +msgstr "个人身份信息" + +#: templates/privacy.html:25 +msgid "details on personal information policies" +msgstr "" +"在登录使用CNProg的提问和回答功能时,我们要求使用者提供用户名、密码、电子邮件" +"等信息。CNProg收集这类关于个人身份的信息只是为了登录系统获得使用功能的目的。" +"我们不会向任何其他社区用 户、个人或第三方透露您的密码或者电子邮件信息。用户可" +"以选择性地填写用户资料、个人网站、年龄、城市等信息,我们收集这些内容为了使用" +"户能够更容易和更满意地使用CNProg提供的网页和服务。" + +#: templates/privacy.html:28 +msgid "Other Services" +msgstr "其他服务" + +#: templates/privacy.html:30 +msgid "details on sharing data with third parties" +msgstr "" +"CNProg可能会收集和统计用户访问本站的概况数据。例如,CNProg可能会检测网站最流" +"行的部分功能。CNProg可能会公开显示或者提供给第三方使用该数据。但是,CNProg不" +"会公开您的身份信息。" + +#: templates/privacy.html:35 +msgid "cookie policy details" +msgstr "" +"访问CNProg时,我们会向您的计算机发送一个或多个专门用于识别您的浏览器的Cookie" +"(包含一个字符串的小文件)。 使用 Cookie 的目的是通过储存用户偏好、跟踪用户倾" +"向(例如搜索方法)来提高我们的服务质量。大多数浏览器的初始设置均为接受 " +"Cookie,但也可以将其重置为拒绝所有 Cookie 或在收到 Cookie 时提示。不过,如果" +"禁用 Cookie,某些功能和服务可能无法正常运行。" + +#: templates/privacy.html:37 +msgid "Policy Changes" +msgstr "政策更改" + +#: templates/privacy.html:38 +#, fuzzy +msgid "how privacy policies can be changed" +msgstr "" +"我们可能在事先通知或不通知的情况下随时更改此'隐私政策',我们建议用户时常查看" +"CNProg隐私政策的改动,在任何改动生效后您的继续访问和使用本站,我们假设您已同" +"意了CNProg以上的所有条款。" + +#: templates/question.html:66 templates/question.html.py:78 +msgid "i like this post (click again to cancel)" +msgstr "这篇帖子有价值(再次点击取消操作)" + +#: templates/question.html:68 templates/question.html.py:80 +#: templates/question.html:273 +msgid "current number of votes" +msgstr "当前总票数" + +#: templates/question.html:73 templates/question.html.py:84 +msgid "i dont like this post (click again to cancel)" +msgstr "这篇帖子没有价值(再次点击取消操作)" + +#: templates/question.html:90 +msgid "mark this question as favorite (click again to cancel)" +msgstr "我要收藏这个问题(再次点击取消操作)" + +#: templates/question.html:96 +msgid "remove favorite mark from this question (click again to restore mark)" +msgstr "我要收藏这个问题(再次点击取消操作)" + +#: templates/question.html:121 templates/question.html.py:304 +#: templates/revisions_answer.html:53 templates/revisions_question.html:53 +msgid "edit" +msgstr "编辑" + +#: templates/question.html:125 templates/question.html.py:314 +msgid "delete" +msgstr "删除" + +#: templates/question.html:130 +msgid "reopen" +msgstr "打开" + +#: templates/question.html:135 +msgid "close" +msgstr "关闭" + +#: templates/question.html:141 templates/question.html.py:327 +msgid "" +"report as offensive (i.e containing spam, advertising, malicious text, etc.)" +msgstr "检举该帖为垃“水帖”(含广告、人身攻击、恶意言论等)" + +#: templates/question.html:142 templates/question.html.py:328 +msgid "flag offensive" +msgstr "垃圾帖?" + +#: templates/question.html:154 templates/question.html.py:337 +#: templates/revisions_answer.html:65 templates/revisions_question.html:65 +msgid "updated" +msgstr "更新于" + +#: templates/question.html:203 templates/question.html.py:384 +#: templates/revisions_answer.html:63 templates/revisions_question.html:63 +msgid "asked" +msgstr "提问于" + +#: templates/question.html:233 templates/question.html.py:411 +msgid "comments" +msgstr "评论" + +#: templates/question.html:234 templates/question.html.py:412 +msgid "add comment" +msgstr "添加评论" + +#: templates/question.html:247 +#, fuzzy, python-format +msgid "" +"The question has been closed for the following reason \"%(question." +"get_close_reason_display)s\" by" +msgstr "问题以“%s”的原因已被" + +#: templates/question.html:249 +#, fuzzy, python-format +msgid "close date %(question.closed_at)s" +msgstr "由于以下原因,你要关闭这个问题" + +#: templates/question.html:256 templates/questions.html:44 +#: templates/user_stats.html:28 +msgid "Answers" +msgstr "个回答" + +#: templates/question.html:258 +msgid "oldest answers will be shown first" +msgstr "最先回答显示在最前面" + +#: templates/question.html:258 +msgid "oldest answers" +msgstr "最先回答" + +#: templates/question.html:259 +msgid "newest answers will be shown first" +msgstr "最晚回答显示在最前面" + +#: templates/question.html:259 +msgid "newest answers" +msgstr "最近回答" + +#: templates/question.html:260 +msgid "most voted answers will be shown first" +msgstr "投票次数最多的显示在最前面" + +#: templates/question.html:260 +msgid "popular answers" +msgstr "投票最多" + +#: templates/question.html:272 +msgid "i like this answer (click again to cancel)" +msgstr "这篇帖子有价值(再次点击取消操作)" + +#: templates/question.html:278 +msgid "i dont like this answer (click again to cancel)" +msgstr "这篇帖子没有价值(再次点击取消操作)" + +#: templates/question.html:284 +msgid "mark this answer as favorite (click again to undo)" +msgstr "最佳答案(再次点击取消操作)" + +#: templates/question.html:289 +msgid "the author of the question has selected this answer as correct" +msgstr "这个答案已经被提问作者标记为最佳答案" + +# todo please check this in chinese +#: templates/question.html:311 +msgid "undelete" +msgstr "取消" + +#: templates/question.html:321 +msgid "answer permanent link" +msgstr "该回答的链接地址" + +#: templates/question.html:322 +msgid "permanent link" +msgstr "永久链接" + +#: templates/question.html:436 +msgid "Your answer" +msgstr "您的回答" + +#: templates/question.html:460 +msgid "Answer the question" +msgstr "回答该问题" + +#: templates/question.html:462 +msgid "Login to answer" +msgstr "登录并回答该问题" + +#: templates/question.html:474 +msgid "Question tags" +msgstr "您正在浏览的问题含有以下标签" + +#: templates/question.html:484 +#, fuzzy +msgid "question asked" +msgstr "提问时间" + +#: templates/question.html:484 templates/question.html.py:490 +#: templates/user_info.html:51 +msgid "ago" +msgstr "前" + +#: templates/question.html:487 +msgid "question was seen" +msgstr "目前浏览数量" + +#: templates/question.html:487 +msgid "times" +msgstr "次" + +#: templates/question.html:490 +msgid "last updated" +msgstr "最后更新时间" + +#: templates/question.html:495 +#, fuzzy +msgid "Related questions" +msgstr "相似的问题" + +# page title +#: templates/question_edit.html:4 templates/question_edit.html.py:65 +msgid "Edit question" +msgstr "修改问题" + +#: templates/question_edit_tips.html:4 +msgid "question tips" +msgstr "受欢迎的提问" + +#: templates/question_edit_tips.html:7 +#, fuzzy +msgid "please ask a relevant question" +msgstr "我要提问" + +#: templates/question_edit_tips.html:10 +#, fuzzy +msgid "please try provide enough details" +msgstr "请详细描述您的问题。" + +#: templates/question_edit_tips.html:13 +msgid "be clear and concise" +msgstr "我们推荐您使用中文描述问题,这样可以得到更多的答复机会。" + +#: templates/question_edit_tips.html:16 +msgid "see frequently asked questions" +msgstr "查看常见问题" + +#: templates/question_edit_tips.html:22 +msgid "Markdown tips" +msgstr "Markdown快速参考" + +#: templates/question_edit_tips.html:25 +#, fuzzy +msgid "*italic* or __italic__" +msgstr "*斜体* 或者 _斜体_" + +#: templates/question_edit_tips.html:28 +msgid "**bold** or __bold__" +msgstr "**加粗** 或者 __加粗__ " + +#: templates/question_edit_tips.html:31 +msgid "link" +msgstr "链接" + +#: templates/question_edit_tips.html:31 templates/question_edit_tips.html:36 +msgid "text" +msgstr "文本" + +#: templates/question_edit_tips.html:36 +msgid "image" +msgstr "图片" + +#: templates/question_edit_tips.html:40 +msgid "numbered list:" +msgstr "列表:" + +#: templates/question_edit_tips.html:45 +msgid "basic HTML tags are also supported" +msgstr "基本的HTML标签也是支持的" + +#: templates/question_edit_tips.html:48 +msgid "learn more about Markdown" +msgstr "有关Markdown详细说明" + +#: templates/questions.html:22 +msgid "All questions" +msgstr "所有问题" + +#: templates/questions.html:25 +#, fuzzy +msgid "Active" +msgstr "活跃问题" + +#: templates/questions.html:26 +#, fuzzy +msgid "Questions with most answers" +msgstr "您正在浏览的问题含有以下标签" + +#: templates/questions.html:27 +msgid "Questions with most votes" +msgstr "" + +# index.html +#: templates/questions.html:57 templates/questions.html.py:69 +#, fuzzy +msgid "Community wiki" +msgstr "社区Wiki" + +# must have extra space after in english +#: templates/questions.html:83 +#, fuzzy +msgid "Browse questions with tag of " +msgstr "查看有关" + +#: templates/questions.html:125 templates/unanswered.html:105 +msgid "Related tags" +msgstr "相关标签" + +#: templates/reopen.html:6 templates/reopen.html.py:16 +msgid "Reopen question" +msgstr "重设问题" + +#: templates/reopen.html:19 +msgid "Open the previously closed question" +msgstr "你将打开这个已经被关闭的问题" + +#: templates/reopen.html:22 +#, fuzzy +msgid "The question was closed for the following reason " +msgstr "问题曾以" + +#: templates/reopen.html:22 +msgid "reason - leave blank in english" +msgstr "的原因被" + +#: templates/reopen.html:22 +#, fuzzy +msgid "on " +msgstr "于" + +#: templates/reopen.html:22 +msgid "date closed" +msgstr "关闭" + +#: templates/reopen.html:29 +#, fuzzy +msgid "Reopen this question" +msgstr "确定打开这个问题" + +# revisions_answer.html +#: templates/revisions_answer.html:7 templates/revisions_answer.html.py:36 +#: templates/revisions_question.html:8 templates/revisions_question.html:36 +msgid "Revision history" +msgstr "版本历史" + +#: templates/tags.html:5 templates/tags.html.py:28 +msgid "Tag list" +msgstr "标签列表" + +#: templates/tags.html:30 +msgid "sorted alphabetically" +msgstr "按名称的字母先后顺序排序" + +#: templates/tags.html:30 +msgid "by name" +msgstr "按名称排序" + +#: templates/tags.html:31 +msgid "sorted by frequency of tag use" +msgstr "按标签被使用的次数排序" + +#: templates/tags.html:31 +#, fuzzy +msgid "by popularity" +msgstr "按流行程度排序" + +#: templates/tags.html:37 +msgid "All tags matching query" +msgstr "匹配查询" + +#: templates/tags.html:37 +msgid "all tags - make this empty in english" +msgstr "的所有标签" + +#: templates/tags.html:40 +#, fuzzy +msgid "Nothing found" +msgstr "没有找到相关数据。" + +#: templates/unanswered.html:7 templates/unanswered.html.py:18 +msgid "Unanswered questions" +msgstr "没有回答的问题" + +#: templates/unanswered.html:20 +msgid "most recently asked questions" +msgstr "最新加入系统的问题" + +#: templates/unanswered.html:97 +#, python-format +msgid "have %(num_q)s unanswered questions" +msgstr "" +"您正在浏览所有<br><div class=\"questions-count\">%(num_q)s</div>个<p>问题按 " +"<strong>问题创建时间</strong> 排序。最新加入的问题将显示在最前面。</p>" + +# in unanswered.html and somewhere else +#: templates/unanswered.html:99 +msgid "Have a total of" +msgstr "您正在浏览所有" + +#: templates/user_edit.html:6 +msgid "Edit user profile" +msgstr "修改个人资料" + +#: templates/user_edit.html:19 +msgid "edit profile" +msgstr "修改资料" + +#: templates/user_edit.html:31 +msgid "image associated with your email address" +msgstr "和您的邮件地址是绑定的" + +#: templates/user_edit.html:31 +msgid "avatar" +msgstr "修改头像" + +#: templates/user_edit.html:36 templates/user_info.html:31 +msgid "Registered user" +msgstr "注册用户" + +#: templates/user_edit.html:82 +msgid "Update" +msgstr "更新" + +#: templates/user_info.html:34 +msgid "update profile" +msgstr "更新我的资料" + +#: templates/user_info.html:40 +msgid "real name" +msgstr "姓名" + +#: templates/user_info.html:45 +msgid "member for" +msgstr "已加入" + +#: templates/user_info.html:50 +msgid "last seen" +msgstr "上次活动时间" + +#: templates/user_info.html:56 +msgid "user website" +msgstr "个人网站" + +#: templates/user_info.html:62 +msgid "location" +msgstr "城市" + +# user_info.html +#: templates/user_info.html:69 +msgid "age" +msgstr "年龄" + +#: templates/user_info.html:70 +msgid "age unit" +msgstr "岁" + +#: templates/user_info.html:75 +msgid "todays unused votes" +msgstr "今日剩余投票数" + +#: templates/user_info.html:76 +msgid "votes left" +msgstr "票" + +#: templates/user_stats.html:15 +msgid "User questions" +msgstr "个问题" + +#: templates/user_stats.html:37 +#, fuzzy, python-format +msgid "the answer has been voted for %(vote_count)s times" +msgstr "该回答总共有%d个投票" + +#: templates/user_stats.html:37 +msgid "this answer has been selected as correct" +msgstr "该回答已被设为最佳答案" + +#: templates/user_stats.html:43 +#, fuzzy, python-format +msgid "the answer has been commented %(answered_question.comment_count)s times" +msgstr "该回答有%d条评论" + +#: templates/user_stats.html:56 +msgid "votes total" +msgstr "个投票" + +#: templates/user_stats.html:65 +msgid "user has voted up this many times" +msgstr "该用户投的赞成票总数" + +#: templates/user_stats.html:70 +#, fuzzy +msgid "user voted down this many times" +msgstr "用户投的反对票总数" + +#: templates/user_stats.html:84 +msgid "Tags" +msgstr "个标签" + +#: templates/user_stats.html:94 +#, fuzzy, python-format +msgid "see other questions tagged '%(tag)s' " +msgstr "查看有关'%s'的问题" + +#: templates/user_tabs.html:7 +msgid "User profile" +msgstr "用户概览" + +#: templates/user_tabs.html:16 +msgid "graph of user reputation" +msgstr "用户的社区积分历史" + +#: templates/user_tabs.html:17 +msgid "reputation history" +msgstr "积分" + +#: templates/user_tabs.html:24 +msgid "favorites" +msgstr "收藏" + +#: templates/user_tabs.html:29 +msgid "settings" +msgstr "设置" + +#: templates/user_votes.html:14 +msgid "upvote" +msgstr "投赞成票" + +#: templates/user_votes.html:16 +msgid "downvote" +msgstr "投反对票" + +#: templates/users.html:5 templates/users.html.py:23 +msgid "Users" +msgstr "用户列表" + +#: templates/users.html:26 +msgid "recent" +msgstr "最新加入" + +#: templates/users.html:27 +msgid "oldest" +msgstr "最先加入" + +#: templates/users.html:28 +msgid "by username" +msgstr "用户名" + +#: templates/users.html:34 +#, fuzzy, python-format +msgid "users matching query %(suser)s:" +msgstr "" +"匹配查询 '<span class=\"darkred\"><strong>%s</strong></span>' 的所有用户名:" + +#: templates/users.html:38 +msgid "Nothing found." +msgstr "没有找到相关数据。" + +#: templates/users_questions.html:11 +#, fuzzy +msgid "this questions was selected as favorite" +msgstr "这个问题被" + +#: templates/users_questions.html:33 +#, fuzzy +msgid "this answer has been accepted to be correct" +msgstr "有答案已被接受为正确答案" + +#: templates/authopenid/changeemail.html:6 +#, fuzzy +msgid "Account: change email" +msgstr "更换电子邮件" + +#: templates/authopenid/changeemail.html:9 msgid "" "This is where you can change the email address associated with your account. " "Please keep this email address up to date so we can send you a password-" "reset email if you request one." msgstr "" -"您可以在这里修改您的电子邮件,请确保这个邮件地址有效-找回密码将发送新密码到您" -"的邮件地址。" -#: templates/authopenid/changeemail.html:15 +#: templates/authopenid/changeemail.html:11 #: templates/authopenid/changeopenid.html:13 #: templates/authopenid/changepw.html:18 templates/authopenid/delete.html:14 #: templates/authopenid/delete.html:24 msgid "Please correct errors below:" -msgstr "请改正以下错误:" +msgstr "" -#: templates/authopenid/changeemail.html:32 +#: templates/authopenid/changeemail.html:28 msgid "Email" -msgstr "电子邮件" +msgstr "" -#: templates/authopenid/changeemail.html:33 +#: templates/authopenid/changeemail.html:29 +#: templates/authopenid/signin.html:60 msgid "Password" msgstr "密码" -#: templates/authopenid/changeemail.html:35 +#: templates/authopenid/changeemail.html:31 msgid "Change email" -msgstr "修改电子邮件" +msgstr "更换电子邮件" #: templates/authopenid/changeopenid.html:7 +#, fuzzy msgid "Account: change OpenID URL" -msgstr "修改OpenID地址" +msgstr "更换OpenID地址" #: templates/authopenid/changeopenid.html:11 msgid "" "This is where you can change your OpenID URL. Make sure you remember it!" -msgstr "请修改您的OpenID地址,请不要忘记这个地址!" +msgstr "" #: templates/authopenid/changeopenid.html:28 msgid "OpenID URL:" -msgstr "OpenID地址:" +msgstr "" #: templates/authopenid/changeopenid.html:29 msgid "Change OpenID" -msgstr "修改OpenID" +msgstr "更换OpenID地址" #: templates/authopenid/changepw.html:13 +#, fuzzy msgid "Account: change password" msgstr "修改密码" #: templates/authopenid/changepw.html:16 msgid "This is where you can change your password. Make sure you remember it!" -msgstr "请修改您的密码,切记不要忘记!" +msgstr "" #: templates/authopenid/changepw.html:26 +#, fuzzy msgid "Current password" -msgstr "旧密码" +msgstr "确认密码" #: templates/authopenid/changepw.html:27 +#, fuzzy msgid "New password" -msgstr "新密码" +msgstr "密码" #: templates/authopenid/changepw.html:28 +#, fuzzy msgid "New password again" -msgstr "重复密码" +msgstr "发送新密码" -#: templates/authopenid/changepw.html:29 +#: templates/authopenid/changepw.html:29 templates/authopenid/settings.html:28 msgid "Change password" msgstr "修改密码" +#: templates/authopenid/complete.html:4 +msgid "Connect your OpenID with this site" +msgstr "绑定OpenID" + +#: templates/authopenid/complete.html:7 +msgid "Connect your OpenID with your account on this site" +msgstr "绑定OpenID帐号" + +#: templates/authopenid/complete.html:10 +#, fuzzy +msgid "Your OpenID is accepted. Please complete this to finish registration." +msgstr "您的OpenID帐号已经验证通过! 请完成最后一步 - 绑定OpenID到您的帐号。" + +# todo: review this message may be confusing user +#: templates/authopenid/complete.html:11 +msgid "This account already exists, please use another." +msgstr "输入您的新帐号或者指定已经存在的帐号。" + +#: templates/authopenid/complete.html:16 templates/authopenid/complete.html:29 +#: templates/authopenid/signin.html:43 +msgid "Sorry, looks like we have some errors:" +msgstr "请注意以下错误:" + +#: templates/authopenid/complete.html:45 +msgid "New account" +msgstr "新帐号" + +#: templates/authopenid/complete.html:46 +msgid "User name (<i>will be shown to others, cannot be modified</i>)" +msgstr "用户名(<i>在社区显示友好名称,不可更改</i>)" + +#: templates/authopenid/complete.html:47 +msgid "Email (<i>not shared with anyone</i>)" +msgstr "电子邮件(<i>用于头像显示服务</i>)" + +#: templates/authopenid/complete.html:48 +msgid "create account" +msgstr "创建帐号" + +#: templates/authopenid/complete.html:56 +msgid "Existing account" +msgstr "已经存在的用户" + +#: templates/authopenid/complete.html:57 +msgid "user name" +msgstr "用户名" + +#: templates/authopenid/complete.html:58 +msgid "password" +msgstr "密码" + +#: templates/authopenid/complete.html:61 +msgid "Register" +msgstr "确认" + +#: templates/authopenid/complete.html:62 templates/authopenid/signin.html:62 +msgid "Forgot your password?" +msgstr "忘记密码?" + #: templates/authopenid/delete.html:8 +#, fuzzy msgid "Account: delete account" msgstr "删除帐号" @@ -540,90 +1885,531 @@ msgstr "删除帐号" msgid "" "Note: After deleting your account, anyone will be able to register this " "username." -msgstr "注意:删除您的帐号后,任何其他人可以再注册这个帐号。" +msgstr "" #: templates/authopenid/delete.html:16 msgid "Check confirm box, if you want delete your account." -msgstr "如果确定删除,请选中多选框。" +msgstr "" #: templates/authopenid/delete.html:19 +#, fuzzy msgid "Password:" -msgstr "密码:" +msgstr "密码" #: templates/authopenid/delete.html:31 msgid "I am sure I want to delete my account." -msgstr "我确认要删除这个帐号。" +msgstr "" #: templates/authopenid/delete.html:32 msgid "Password/OpenID URL" -msgstr "密码/OpenID地址" +msgstr "" #: templates/authopenid/delete.html:32 msgid "(required for your security)" -msgstr "(必需)" +msgstr "" #: templates/authopenid/delete.html:34 +#, fuzzy msgid "Delete account permanently" -msgstr "永久删除帐号" +msgstr "删除帐号" + +#: templates/authopenid/sendpw.html:3 templates/authopenid/sendpw.html.py:7 +msgid "Send new password" +msgstr "发送新密码" + +#: templates/authopenid/sendpw.html:11 +msgid "Lost your password? No problem - here you can reset it." +msgstr "丢失了您的密码? 你可以在这里重设密码。" + +#: templates/authopenid/sendpw.html:12 +msgid "" +"Please enter your username below and new password will be sent to your " +"registered e-mail" +msgstr "请输入用户名,新的密码会发送到你注册时候填写的电子邮件。" + +#: templates/authopenid/sendpw.html:29 +msgid "Reset password" +msgstr "重设密码" + +#: templates/authopenid/sendpw.html:29 +msgid "return to login" +msgstr "返回登录" + +# todo - check translation or see if it's indeed true +#: templates/authopenid/sendpw.html:32 +msgid "" +"Note: your new password will be activated only after you click the " +"activation link in the email message" +msgstr "注意: 新的密码只有您在激活邮件中的链接后才会被激活。" #: templates/authopenid/settings.html:29 msgid "Give your account a new password." -msgstr "修改密码" +msgstr "" + +#: templates/authopenid/settings.html:30 +#, fuzzy +msgid "Change email " +msgstr "更换电子邮件" #: templates/authopenid/settings.html:31 msgid "Add or update the email address associated with your account." -msgstr "添加或者更新您的邮件地址。" +msgstr "" #: templates/authopenid/settings.html:34 msgid "Change openid associated to your account" -msgstr "修改和你帐号绑定的OpenID地址" +msgstr "" + +#: templates/authopenid/settings.html:37 +msgid "Delete account" +msgstr "删除帐号" #: templates/authopenid/settings.html:38 msgid "Erase your username and all your data from website" -msgstr "删除您的帐号和所有内容" +msgstr "" + +#: templates/authopenid/signin.html:3 templates/authopenid/signin.html:16 +msgid "User login" +msgstr "用户登录" + +#: templates/authopenid/signin.html:21 +msgid "we support two login modes" +msgstr "" +"CNProg支持<b>两种</b>登录模式。您可以使用帐号、密码登录,或者使用OpenID登录。" + +#: templates/authopenid/signin.html:26 templates/authopenid/signup.html:49 +msgid "Login with your OpenID" +msgstr "使用OpenID登录" +#: templates/authopenid/signin.html:28 +msgid "select openid provider" +msgstr "1)请选择您的帐号类:" + +#: templates/authopenid/signin.html:32 +msgid "verify openid link and login" +msgstr "2)型并完成正确的OpenID地址(如:替换“{username}”为您的对应帐号):" + +#: templates/authopenid/signin.html:58 +msgid "Use login name and password" +msgstr "使用帐号密码登录" + +#: templates/authopenid/signin.html:59 +msgid "Login name" +msgstr "用户名" + +#: templates/authopenid/signin.html:63 #, fuzzy -#~ msgid "Badges " -#~ msgstr "奖牌列表" +msgid "Create new acccount" +msgstr "注册新帐号" + +#: templates/authopenid/signin.html:72 +msgid "Why use OpenID?" +msgstr "为什么需要OpenID登录?" + +#: templates/authopenid/signin.html:76 +msgid "with openid it is easier" +msgstr "" +"构建在OpenID网络认证上的本系统,不需要你注册新的帐号,即可使用我们系统的所有" +"功能" + +#: templates/authopenid/signin.html:79 +msgid "reuse openid" +msgstr "用同一个帐号可登录互联网所有激活OpenID的网站" + +#: templates/authopenid/signin.html:82 +msgid "openid is widely adopted" +msgstr "全世界有1.6亿OpenID帐号,和10,000个支持OpenID的站点" + +#: templates/authopenid/signin.html:85 +msgid "openid is supported open standard" +msgstr "OpenID是有开放标准,并且有相关的基金组织提供支持" + +#: templates/authopenid/signin.html:89 +msgid "Find out more" +msgstr "查看更多" + +#: templates/authopenid/signin.html:90 +msgid "Get OpenID" +msgstr "获取OpenID" + +#: templates/authopenid/signup.html:2 templates/authopenid/signup.html.py:6 +msgid "Signup" +msgstr "注册帐号" + +#: templates/authopenid/signup.html:10 +msgid "" +"We support two types of user registration: conventional username/password, " +"and" +msgstr "我们支持两种注册方式,你可以使用常规的用户名、密码方式注册,或者" + +#: templates/authopenid/signup.html:10 +msgid "the OpenID method" +msgstr "使用OpenID帐号注册" + +#: templates/authopenid/signup.html:15 +#, fuzzy +msgid "Sorry, looks like we have some errors" +msgstr "请注意以下错误:" + +#: templates/authopenid/signup.html:33 +msgid "Conventional registration" +msgstr "请注意以下错误:" + +#: templates/authopenid/signup.html:34 +msgid "choose a user name" +msgstr "选择一个用户名" + +#: templates/authopenid/signup.html:40 +msgid "back to login" +msgstr "返回登录" + +#: templates/authopenid/signup.html:46 +msgid "Register with your OpenID" +msgstr "使用OpenID注册" + +msgid "meta site keywords, comma separated" +msgstr "" +"技术问答社区,中国程序员,编程技术社区,程序员社区,程序员论坛,程序员" +"wiki,程序员博客" + +msgid "what is this website" +msgstr "" +"CNProg是一个<strong>面向程序员</strong>的可协作编辑的<strong>开放源代码问" +"答社区</strong>。" + +msgid "what can one do on this website" +msgstr "" +"您可以在这里提问各类<strong>程序技术问题</strong> - 问题不分语言和平台。 " +"同时也希望您对力所能及的问题,给予您的宝贵答案。" + +msgid "Goal of this site is..." +msgstr "CNProg 是为了帮助程序员解决更多问题,更加方便的解决问题。" + +msgid "Community gives you awards for your questions, answers and votes." +msgstr "" +"提出问题,给予回答,投出你的票 - CNProg 会针对你在社区的表现,授予你各类奖" +"牌。" + +msgid "please make your answer relevant to this community" +msgstr "您的问题与编程相关吗?" + +msgid "book technical Q&A" +msgstr "图书相关的技术答疑" + +msgid "blog" +msgstr "Blog" + +msgid "privacy policy" +msgstr "隐私政策" + +msgid "current revision" +msgstr "当前版本" + +msgid "number of votes" +msgstr "票数" + +msgid "current page" +msgstr "当前页" + +msgid "next page" +msgstr "下一页" + +msgid "page number " +msgstr "第" + +msgid "number - make blank in english" +msgstr "页" + +msgid "Change tags" +msgstr "修改问题标签" + +# todo: remove magic numbers from this file +msgid "up to 5 tags, less than 20 characters each" +msgstr "最多5个标签,每个标签长度小于20个字符。" + +msgid "Change now" +msgstr "现在修改" + +msgid "uses tags for the classification of questions" +msgstr "用标签来分类系统的信息" + +msgid "tag editors receive special awards from the community" +msgstr "修改标签的用户将授予特殊的社区奖牌" + +msgid "Why use and modify tags?" +msgstr "为什么我只能修改问题标签?" + +msgid "Found by tag" +msgstr "标签问题" + +msgid "Found by title" +msgstr "查询结果" + +msgid "most recently updated questions" +msgstr "最近被更新的问题" + +msgid "latest questions info" +msgstr "" +"问题按<strong>提问时间</strong>显示排序。新加入的问题将显示在最前面。" + +msgid "" +"\n" +"\t\t\thave total %(q_num)s questions tagged %(tagname)s\n" +"\t\t\t" +msgid_plural "" +"\n" +"\t\t\thave total %(q_num)s questions tagged %(tagname)s\n" +"\t\t\t" +msgstr[0] "" +"\n" +"您正在浏览所有<div class=\"questions-count\">%(q_num)s</div>个标记为<span " +"class=\"tag\">%(tagname)s</span></p>" +msgstr[1] "" +"\n" +"您正在浏览所有<div class=\"questions-count\">%(q_num)s</div>个标记为<span " +"class=\"tag\">%(tagname)s</span></p>" -#~ msgid "" -#~ "This username is already taken. Please choose another." -#~ msgstr "用户名已经被注册,请选用一个新的帐号。" +msgid "" +"\n" +"\t\t\thave total %(q_num)s questions containing %(searchtitle)s\n" +"\t\t\t" +msgid_plural "" +"\n" +"\t\t\thave total %(q_num)s questions containing %(searchtitle)s\n" +"\t\t\t" +msgstr[0] "" +"\n" +"您正在浏览所有<div class=\"questions-count\">%(q_num)s</div>个标题含有" +"<span class=\"tag\">%(searchtitle)s</span></p>" +msgstr[1] "" +"\n" +"您正在浏览所有<div class=\"questions-count\">%(q_num)s</div>个标题含有" +"<span class=\"tag\">%(searchtitle)s</span></p>" + +msgid "number of questions" +msgstr "个" + +msgid "number of <strong>unanswered</strong> questions" +msgstr "" +"个 <span class=\"darkred\"><strong>没有回答的</strong></span> 问题。" + +msgid "tagged with" +msgstr "标记为" + +msgid "whose title contains" +msgstr "标题含有" + +msgid "number of questions end of sentence" +msgstr "的问题。" + +msgid "Questions are sorted by the <strong>time of last update</strong>." +msgstr "问题按<strong>最后更新时间</strong>显示排序。" + +msgid "Most recently answered ones are shown first." +msgstr "最后被回答或者>更新的问题将显示在最前面。" + +msgid "Questions sorted by <strong>number of responses</strong>." +msgstr "问题按<strong>回复数量</strong>显示排序。" + +msgid "Most answered questions are shown first" +msgstr "回复最多的问题将显示在最前面。" + +msgid "Questions are sorted by the <strong>number of votes</strong>." +msgstr "问题按<strong>投票数量</strong>显示排序。" -#~ msgid "Your OpenID is verified! " -#~ msgstr "您的OpenID帐号已经验证通过" +msgid "Most voted questions are shown first" +msgstr "投票最多的问题将显示在最前面。" -#~ msgid "Associate your OpenID" -#~ msgstr "绑定您的OpenID" +msgid "questions that user selected as his/her favorite" +msgstr "用户收藏的问题" + +msgid "Frequently Asked Questions " +msgstr "常见问题" + +msgid "What kinds of questions can I ask here?" +msgstr "我可以在这里提问什么样的问题?" + +msgid "What questions should I avoid asking?" +msgstr "什么样的问题我不该在这里提问?" + +msgid "" +"Most importanly - questions should be <strong>relevant</strong> to this " +"community." +msgstr "毫无疑问,首先必须是<span class=\"yellowbg\">技术编程问题!</span>" + +msgid "" +"Before asking the question - please make sure to use search to see " +"whether your question has alredy been answered." +msgstr "" +"提问之前,充分利用系统的自动查找、标签和搜索,看看是否已经有一样的问题并有" +"了答案。" -#~ msgid "" -#~ "\n" -#~ "\t<p>If you're joining <strong>Sitename</strong>, associate your OpenID " -#~ "with a new account. If you're already a member, associate with your " -#~ "existing account.</p>\n" -#~ "\t" -#~ msgstr "" -#~ "\n" -#~ "\t<p>输入您的新帐号或者指定已经存在的帐号。</p>\n" -#~ "\t" +msgid "What should I avoid in my answers?" +msgstr "什么样的回答是不受欢迎的?" -#~ msgid "A new account" -#~ msgstr "新帐号" +msgid "Who moderates this community?" +msgstr "谁是社区的管理员?" + +msgid "" +"Please avoid asking questions that are not relevant to this community, " +"too subjective and argumentative." +msgstr "" +"<span class=\"yellowbg\">与程序员或技术无关的,引起争吵或太过于主观性等违" +"背社区宗旨的内容。</span>本站建立是为了帮助大众程序员解决实际技术问题,我" +"们需要实际的问题!" + +msgid "" +"is a Q&A site, not a discussion group. Therefore - please avoid having " +"discussions in your answers, comment facility allows some space for brief " +"discussions." +msgstr "" +"希望用户提供针对提问的技术回答,可以是进一步了解问题实质,给予参考方案,或" +"完全解决问题的回答。我们希望通过问答的形式解决用户的实际问题。因此,<span " +"class=\"yellowbg\">我们不>欢迎在回答中出现不是回答问题的内容,包括针对他人" +"回答的讨论,和其他无意义的浪费网络资源行为</span>。CNProg建议您使用<span " +"class=\"yellowbg\">评论</span>功能来讨论你的意见和想法。" + +msgid "The short answer is: <strong>you</strong>." +msgstr "答案是:<span class=\"yellowbg\">每个用户。</span>" + +msgid "" +"The reputation system allows users earn the authorization to perform a " +"variety of moderation tasks." +msgstr "" +"通过积分运作,<span class=\"yellowbg\">每个用户都有权限创建标签,进行对所" +"有问题、回答的投票、编辑、关闭等操作。</span>" + +msgid "This website is moderated by the users." +msgstr "社区没有严格意义上的管理员身份" + +msgid "How does reputation system work?" +msgstr "什么是社区积分?" + +msgid "" +"Anyone can ask questions and give answers, points are not necessary for " +"that." +msgstr "对于正常使用社区进行提问、回答而言,积分不是必须的。" + +msgid "" +"As we've said before, users help running this site. Point system helps " +"select users who can administer this community." +msgstr "" +"我们一再声明,CNProg由你来运行和维护。如果你想帮助我们来运作CNProg,你需要" +"一定的积分等级。" + +msgid "" +"Reputation points roughly measure how community trusts you. These points " +"are given to you directly by other members of the community." +msgstr "" +"<span class=\"yellowbg\">积分是一种用来粗略衡量社区对你有多信任的数据。</" +"span>积分不是有谁来支付或直接给予你的,而是你通过获得其他用户的支持和信" +"任“赚得”的。" + +msgid "" +"For example, if you ask an interesting question or give a helpful answer, " +"your input will be upvoted and you will gain more trust in the community." +msgstr "" +"举例来说,如果你提了一个非常有帮助的问题或者做了很有用的回答,你将会被其他" +"用户投赞成票。" + +msgid "" +"If on the other hand someone gives a misleading answer, the answer will " +"be voted down and he/she loses some points." +msgstr "" +"相反,你提了不受欢迎的问题,或者误导用户的回答,你将可能被其他用户投反对" +"票。每个赞成" + +msgid "" +"Each vote in favor will generate <strong>10</strong> points, each vote " +"against will subtract <strong>2</strong> points." +msgstr "" +"票会帮你产生<strong>10</strong>个社区积分,每个反对票会相应扣除你" +"<strong>2</strong>个积分。" + +msgid "" +"Through the votes of other people you can accumulate a maximum of " +"<strong>200</strong> points." +msgstr "" +"每天通过别人投赞成票,你最多只能产生<strong>200</strong>个积分,这是上限。" + +msgid "After accumulating certain number of points, you can do more:" +msgstr "当你累计到一定>积分,你可以在社区做更多的事情:" + +# todo - check if it's indeed plural +msgid "add comments" +msgstr "添加评论" + +msgid "retag questions" +msgstr "给任何问题整理标签" + +msgid "edit community wiki questions" +msgstr "编辑wiki类问题" + +msgid "edit any answer" +msgstr "编辑任何问题或答案" + +msgid "reopen any closed questions" +msgstr "打开关闭任何人的问题" + +msgid "delete any comment" +msgstr "删除任何一个评论" + +msgid "delete any questions and answers and perform other moderation tasks" +msgstr "删除任何一个问题或答案,及其他管理功能" + +msgid "To register, do I need to create new password?" +msgstr "我需要注册一个新用户吗?" + +msgid "Why other people can edit my questions/answers?" +msgstr "为什么其他人可以修改我的问题/回答?" + +msgid "Still have questions?" +msgstr "还有其他问题?" + +msgid "Please ask your question, help make our community better!" +msgstr "如果您对社区还有其他疑问,请一起来完善我们的" + +msgid "" +"No, you don't have to. You can login through any service that supports " +"OpenID, e.g. Google, Yahoo, AOL, etc." +msgstr "" +"不需要。社区提供了OpenID的登录支持,你要用Google、Yahoo等任何支持OpenID登" +"录的帐号就可以使用系统。" + +msgid "Login now!" +msgstr "马上登录" + +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一样可编辑的,我们希望社区能帮助用户沉淀、积累更多" +"有用的知识和经验。" + +msgid "If this approach is not for you, we respect your choice." +msgstr "如果您不喜欢这种方式,我们尊重你的选择。" + +msgid "answer tips" +msgstr "受欢迎的提问" + +msgid "try to give an answer, rather than engage into a discussion" +msgstr "建议您提的问题是可以被答复的,而不仅仅是可以讨论。" + +msgid "gold badge: the highest honor and is very rare" +msgstr "金牌:十分罕见之最高荣耀" + +msgid "" +"silver badge: occasionally awarded for the very high quality contributions" +msgstr "银牌:偶尔颁发之优质奖章" -#~ msgid "An exisiting account" -#~ msgstr "已经存在的帐号" +msgid "Gold badge is very rare." +msgstr "金牌是十分罕见的。" -#~ msgid "Account: Send a new password" -#~ msgstr "发送一个新的密码" +msgid "Gold badge is the highest award in this community." +msgstr "获得金牌意味着你在某个层次上已经达到了顶峰。" -#~ msgid "" -#~ "Lost your password ? Here you can ask to reset your password. Enter the " -#~ "username you use and you will get a confirmation email with your new " -#~ "password. This new password will be activated only after you have clicked " -#~ "on the link in the email." -#~ msgstr "" -#~ "丢失了您的密码?你可以在这里重设密码。输入用户名你会收到新的密码的邮件。密" -#~ "码只有您在激活邮件中的链接才会被激活。" +msgid "Obtaining silver badge requires significant patience." +msgstr "银牌需要经过长时间的奋斗才能获得。" -#~ msgid "Send new password" -#~ msgstr "发送新密码" +msgid "%s ago" +msgstr "于%s<font class=\"darkred\">关闭</font>" diff --git a/templates/answer_edit_tips.html b/templates/answer_edit_tips.html index 08d33bc9..565c5298 100644 --- a/templates/answer_edit_tips.html +++ b/templates/answer_edit_tips.html @@ -34,7 +34,6 @@ <b>{% trans "link" %}</b>:[{% trans "text" %}](http://url.com/ "{% trans "title" %}") </li> - <li> <b>{% trans "image" %}</b>:![alt {% trans "text" %}](/path/img.jpg "{% trans "title" %}") diff --git a/templates/pagesize.html b/templates/pagesize.html index e5e17a24..90003749 100644 --- a/templates/pagesize.html +++ b/templates/pagesize.html @@ -2,7 +2,7 @@ {% load i18n %} {% if is_paginated %} <div class="paginator"> - <span class="text">{% trans "Size per page:" %}</span> + <span class="text">{% trans "posts per page" %}</span> {% ifequal pagesize 10 %} <span class="curr">10</span> {% else %} diff --git a/templates/paginator.html b/templates/paginator.html index c5e51a81..2fba5425 100644 --- a/templates/paginator.html +++ b/templates/paginator.html @@ -5,7 +5,6 @@ <div class="paginator"> {% if has_previous %}<span class="prev"><a href="{{base_url}}page={{ previous }}{{ extend_url }}" title="{% trans "previous" %}"> « {% trans "previous" %}</a></span>{% endif %} - {% if not in_leading_range %} {% for num in pages_outside_trailing_range %} <span class="page"><a href="{{base_url}}page={{ num }}{{ extend_url }}" >{{ num }}</a></span> diff --git a/templates/questions.html b/templates/questions.html index 21ac18ce..a531d954 100644 --- a/templates/questions.html +++ b/templates/questions.html @@ -1,5 +1,6 @@ <!-- questions.html --> {% extends "base.html" %} +{% load i18n %} {% load extra_tags %} {% load i18n %} {% load humanize %} @@ -138,15 +139,13 @@ <p>{% trans "Questions are sorted by the <strong>number of votes</strong>." %} {% trans "Most voted questions are shown first." %}</p> {% endifequal %} - - </p> </div> <div class="boxC"> <h3 class="subtitle">{% trans "Related tags" %}</h3> <div class="tags"> {% for tag in tags %} - <a rel="tag" title="{% trans "see questions tagged" %}'{{ tag.name }}'{% trans "using tags" %}" href="{% url forum.views.tag tag.name|urlencode %}">{{ tag.name }}</a> + <a rel="tag" title="{% blocktrans with tag.name as tagname %}see questions tagged '{{ tagname }}'{% endblocktrans %}" href="{% url forum.views.tag tag.name|urlencode %}">{{ tag.name }}</a> <span class="tag-number">× {{ tag.used_count|intcomma }}</span> <br> {% endfor %} |