Change comment style (#70)

This commit is contained in:
Dung T.Bui 2023-05-22 20:52:18 +07:00 committed by GitHub
parent d80ec962a5
commit 1056a470b0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 680 additions and 306 deletions

View file

@ -468,6 +468,8 @@ urlpatterns = [
url(r"^comments/upvote/$", comment.upvote_comment, name="comment_upvote"), url(r"^comments/upvote/$", comment.upvote_comment, name="comment_upvote"),
url(r"^comments/downvote/$", comment.downvote_comment, name="comment_downvote"), url(r"^comments/downvote/$", comment.downvote_comment, name="comment_downvote"),
url(r"^comments/hide/$", comment.comment_hide, name="comment_hide"), url(r"^comments/hide/$", comment.comment_hide, name="comment_hide"),
url(r"^comments/get_replies/$", comment.get_replies, name="comment_get_replies"),
url(r"^comments/show_more/$", comment.get_show_more, name="comment_show_more"),
url( url(
r"^comments/(?P<id>\d+)/", r"^comments/(?P<id>\d+)/",
include( include(

View file

@ -11,6 +11,7 @@ from django.http import (
HttpResponseForbidden, HttpResponseForbidden,
HttpResponseNotFound, HttpResponseNotFound,
HttpResponseRedirect, HttpResponseRedirect,
Http404,
) )
from django.urls import reverse_lazy from django.urls import reverse_lazy
from django.utils.decorators import method_decorator from django.utils.decorators import method_decorator
@ -151,40 +152,92 @@ class CommentedDetailView(TemplateResponseMixin, SingleObjectMixin, View):
return self.render_to_response(context) return self.render_to_response(context)
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
pre_query = None
if "comment-id" in request.GET:
comment_id = int(request.GET["comment-id"])
try:
comment_obj = Comment.objects.get(pk=comment_id)
except Comment.DoesNotExist:
raise Http404
pre_query = comment_obj
while comment_obj is not None:
pre_query = comment_obj
comment_obj = comment_obj.parent
self.object = self.get_object() self.object = self.get_object()
return self.render_to_response( return self.render_to_response(
self.get_context_data( self.get_context_data(
object=self.object, object=self.object,
pre_query=pre_query,
comment_form=CommentForm(request, initial={"parent": None}), comment_form=CommentForm(request, initial={"parent": None}),
) )
) )
def get_context_data(self, **kwargs): def get_context_data(self, pre_query=None, **kwargs):
context = super(CommentedDetailView, self).get_context_data(**kwargs) context = super(CommentedDetailView, self).get_context_data(**kwargs)
queryset = self.object.comments queryset = self.object.comments
context["has_comments"] = queryset.exists() queryset = queryset.filter(parent=None, hidden=False)
context["comment_lock"] = self.is_comment_locked() queryset_all = None
queryset = ( comment_count = len(queryset)
queryset.select_related("author__user") context["comment_remove"] = -1
if (pre_query != None):
comment_remove = pre_query.id
queryset_all = pre_query.get_descendants(include_self=True)
queryset_all = (
queryset_all.select_related("author__user")
.filter(hidden=False) .filter(hidden=False)
.defer("author__about") .defer("author__about")
.annotate(revisions=Count("versions")) .annotate(revisions=Count("versions", distinct=True))
)
context["comment_remove"] = comment_remove
else:
queryset = (
queryset.select_related("author__user")
.defer("author__about")
.filter(hidden=False)
.annotate(
count_replies=Count("replies", distinct=True),
revisions=Count("versions", distinct=True),
)[:10]
) )
if self.request.user.is_authenticated: if self.request.user.is_authenticated:
profile = self.request.profile profile = self.request.profile
if (pre_query != None):
queryset_all = queryset_all.annotate(
my_vote=FilteredRelation(
"votes", condition=Q(votes__voter_id=profile.id)
),
).annotate(vote_score=Coalesce(F("my_vote__score"), Value(0)))
else:
queryset = queryset.annotate( queryset = queryset.annotate(
my_vote=FilteredRelation( my_vote=FilteredRelation(
"votes", condition=Q(votes__voter_id=profile.id) "votes", condition=Q(votes__voter_id=profile.id)
), ),
).annotate(vote_score=Coalesce(F("my_vote__score"), Value(0))) ).annotate(vote_score=Coalesce(F("my_vote__score"), Value(0)))
context["is_new_user"] = ( context["is_new_user"] = (
not self.request.user.is_staff not self.request.user.is_staff
and not profile.submission_set.filter( and not profile.submission_set.filter(
points=F("problem__points") points=F("problem__points")
).exists() ).exists()
) )
context["has_comments"] = queryset.exists()
context["comment_lock"] = self.is_comment_locked()
context["comment_list"] = queryset context["comment_list"] = queryset
context["comment_count"] = len(queryset) context["comment_all_list"] = queryset_all
context["vote_hide_threshold"] = settings.DMOJ_COMMENT_VOTE_HIDE_THRESHOLD context["vote_hide_threshold"] = settings.DMOJ_COMMENT_VOTE_HIDE_THRESHOLD
if queryset.exists():
context["comment_root_id"] = queryset[0].id
else:
context["comment_root_id"] = 0
context["comment_parrent_none"] = 1
if (pre_query != None):
context["offset"] = 1
else:
context["offset"] = 10
context["limit"] = 10
context["comment_count"] = comment_count
return context return context

View file

@ -56,6 +56,7 @@ class Comment(MPTTModel):
related_name="replies", related_name="replies",
on_delete=CASCADE, on_delete=CASCADE,
) )
versions = VersionRelation() versions = VersionRelation()
class Meta: class Meta:
@ -112,6 +113,15 @@ class Comment(MPTTModel):
return output return output
return output return output
@cached_property
def get_replies(self):
query = Comment.filter(parent=self)
return len(query)
@cached_property
def get_revisions(self):
return self.versions.count()
@cached_property @cached_property
def page_title(self): def page_title(self):
if isinstance(self.linked_object, Problem): if isinstance(self.linked_object, Problem):
@ -141,7 +151,7 @@ class Comment(MPTTModel):
) )
def get_absolute_url(self): def get_absolute_url(self):
return "%s#comment-%d" % (self.link, self.id) return "%s?comment-id=%d#comment-%d" % (self.link, self.id, self.id)
class CommentVote(models.Model): class CommentVote(models.Model):

View file

@ -1,8 +1,13 @@
from django.conf import settings
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
from django.contrib.auth.context_processors import PermWrapper
from django.core.exceptions import PermissionDenied from django.core.exceptions import PermissionDenied
from django.db import IntegrityError, transaction from django.db import IntegrityError, transaction
from django.db.models import F from django.db.models import Q, F, Count, FilteredRelation
from django.db.models.functions import Coalesce
from django.db.models.expressions import F, Value
from django.forms.models import ModelForm from django.forms.models import ModelForm
from django.http import ( from django.http import (
Http404, Http404,
@ -15,11 +20,12 @@ from django.utils.translation import gettext as _
from django.views.decorators.http import require_POST from django.views.decorators.http import require_POST
from django.views.generic import DetailView, UpdateView from django.views.generic import DetailView, UpdateView
from django.urls import reverse_lazy from django.urls import reverse_lazy
from django.template import loader
from reversion import revisions from reversion import revisions
from reversion.models import Version from reversion.models import Version
from judge.dblock import LockModel from judge.dblock import LockModel
from judge.models import Comment, CommentVote, Notification from judge.models import Comment, CommentVote, Notification, BlogPost
from judge.utils.views import TitleMixin from judge.utils.views import TitleMixin
from judge.widgets import MathJaxPagedownWidget, HeavyPreviewPageDownWidget from judge.widgets import MathJaxPagedownWidget, HeavyPreviewPageDownWidget
from judge.comments import add_mention_notifications, del_mention_notifications from judge.comments import add_mention_notifications, del_mention_notifications
@ -36,6 +42,11 @@ __all__ = [
@login_required @login_required
# def get_more_reply(request, id):
# queryset = Comment.get_pk(id)
def vote_comment(request, delta): def vote_comment(request, delta):
if abs(delta) != 1: if abs(delta) != 1:
return HttpResponseBadRequest( return HttpResponseBadRequest(
@ -99,10 +110,77 @@ def vote_comment(request, delta):
def upvote_comment(request): def upvote_comment(request):
return vote_comment(request, 1) return vote_comment(request, 1)
def downvote_comment(request): def downvote_comment(request):
return vote_comment(request, -1) return vote_comment(request, -1)
def get_comments(request, limit=10):
try:
comment_id = int(request.GET["id"])
parrent_none = int(request.GET["parrent_none"])
except ValueError:
return HttpResponseBadRequest()
else:
if comment_id and not Comment.objects.filter(id=comment_id).exists():
raise Http404()
offset = 0
if "offset" in request.GET:
offset = int(request.GET["offset"])
comment_remove = -1
if "comment_remove" in request.GET:
comment_remove = int(request.GET["comment_remove"])
comment_root_id = 0
if (comment_id):
comment_obj = Comment.objects.get(pk=comment_id)
comment_root_id = comment_obj.id
else:
comment_obj = None
queryset = comment_obj.linked_object.comments
if parrent_none:
queryset = queryset.filter(parent=None, hidden=False)
if (comment_remove != -1):
queryset.get(pk=comment_remove).delete()
else:
queryset = queryset.filter(parent=comment_obj, hidden=False)
comment_count = len(queryset)
queryset = (
queryset.select_related("author__user")
.defer("author__about")
.annotate(
count_replies=Count("replies", distinct=True),
revisions=Count("versions", distinct=True),
)[offset:offset+limit]
)
if request.user.is_authenticated:
profile = request.profile
queryset = queryset.annotate(
my_vote=FilteredRelation(
"votes", condition=Q(votes__voter_id=profile.id)
),
).annotate(vote_score=Coalesce(F("my_vote__score"), Value(0)))
comment_html = loader.render_to_string(
"comments/content-list.html",
{
"request": request,
"comment_root_id": comment_root_id,
"comment_list": queryset,
"vote_hide_threshold" : settings.DMOJ_COMMENT_VOTE_HIDE_THRESHOLD,
"perms": PermWrapper(request.user),
"offset": offset + min(len(queryset), limit),
"limit": limit,
"comment_count": comment_count,
"comment_parrent_none": parrent_none,
"comment_remove": comment_remove,
}
)
return HttpResponse(comment_html)
def get_show_more(request):
return get_comments(request)
def get_replies(request):
return get_comments(request)
class CommentMixin(object): class CommentMixin(object):
model = Comment model = Comment

View file

@ -2,7 +2,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: lqdoj2\n" "Project-Id-Version: lqdoj2\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-04-26 15:39+0700\n" "POT-Creation-Date: 2023-05-16 16:17+0700\n"
"PO-Revision-Date: 2021-07-20 03:44\n" "PO-Revision-Date: 2021-07-20 03:44\n"
"Last-Translator: Icyene\n" "Last-Translator: Icyene\n"
"Language-Team: Vietnamese\n" "Language-Team: Vietnamese\n"
@ -25,7 +25,7 @@ msgstr ""
msgid "user" msgid "user"
msgstr "người dùng" msgstr "người dùng"
#: chat_box/models.py:32 judge/models/comment.py:44 judge/models/comment.py:179 #: chat_box/models.py:32 judge/models/comment.py:44 judge/models/comment.py:189
msgid "posted time" msgid "posted time"
msgstr "thời gian đăng" msgstr "thời gian đăng"
@ -41,19 +41,19 @@ msgstr "xem lần cuối"
msgid "LQDOJ Chat" msgid "LQDOJ Chat"
msgstr "" msgstr ""
#: dmoj/settings.py:363 #: dmoj/settings.py:365
msgid "Vietnamese" msgid "Vietnamese"
msgstr "Tiếng Việt" msgstr "Tiếng Việt"
#: dmoj/settings.py:364 #: dmoj/settings.py:366
msgid "English" msgid "English"
msgstr "" msgstr ""
#: dmoj/urls.py:135 #: dmoj/urls.py:136
msgid "Login" msgid "Login"
msgstr "Đăng nhập" msgstr "Đăng nhập"
#: dmoj/urls.py:212 templates/base.html:209 #: dmoj/urls.py:214 templates/base.html:209
#: templates/organization/org-left-sidebar.html:2 #: templates/organization/org-left-sidebar.html:2
msgid "Home" msgid "Home"
msgstr "Trang chủ" msgstr "Trang chủ"
@ -140,7 +140,7 @@ msgstr[0] "%d kỳ thi đã được đánh dấu ẩn."
msgid "Mark contests as hidden" msgid "Mark contests as hidden"
msgstr "Ẩn các kỳ thi" msgstr "Ẩn các kỳ thi"
#: judge/admin/contest.py:377 judge/admin/submission.py:243 #: judge/admin/contest.py:377 judge/admin/submission.py:248
#, python-format #, python-format
msgid "%d submission was successfully scheduled for rejudging." msgid "%d submission was successfully scheduled for rejudging."
msgid_plural "%d submissions were successfully scheduled for rejudging." msgid_plural "%d submissions were successfully scheduled for rejudging."
@ -221,7 +221,7 @@ msgstr "Điểm"
msgid "Limits" msgid "Limits"
msgstr "Giới hạn" msgstr "Giới hạn"
#: judge/admin/problem.py:217 judge/admin/submission.py:353 #: judge/admin/problem.py:217 judge/admin/submission.py:358
#: templates/base.html:245 templates/stats/tab.html:4 #: templates/base.html:245 templates/stats/tab.html:4
#: templates/submission/list.html:347 #: templates/submission/list.html:347
msgid "Language" msgid "Language"
@ -255,12 +255,12 @@ msgstr[0] "%d bài tập đã được đánh dấu riêng tư."
msgid "Mark problems as private" msgid "Mark problems as private"
msgstr "Đánh dấu các bài tập là riêng tư" msgstr "Đánh dấu các bài tập là riêng tư"
#: judge/admin/problem.py:432 judge/admin/submission.py:316 #: judge/admin/problem.py:432 judge/admin/submission.py:321
#: templates/problem/list.html:18 templates/problem/list.html:37 #: templates/problem/list.html:18 templates/problem/list.html:37
msgid "Problem code" msgid "Problem code"
msgstr "Mã bài" msgstr "Mã bài"
#: judge/admin/problem.py:444 judge/admin/submission.py:322 #: judge/admin/problem.py:444 judge/admin/submission.py:327
msgid "Problem name" msgid "Problem name"
msgstr "Tên bài" msgstr "Tên bài"
@ -284,7 +284,7 @@ msgstr ""
msgid "timezone" msgid "timezone"
msgstr "múi giờ" msgstr "múi giờ"
#: judge/admin/profile.py:125 judge/admin/submission.py:329 #: judge/admin/profile.py:125 judge/admin/submission.py:334
#: templates/notification/list.html:12 #: templates/notification/list.html:12
#: templates/organization/requests/log.html:9 #: templates/organization/requests/log.html:9
#: templates/organization/requests/pending.html:19 #: templates/organization/requests/pending.html:19
@ -338,7 +338,7 @@ msgid "Capabilities"
msgstr "Khả năng" msgstr "Khả năng"
#: judge/admin/submission.py:31 judge/admin/submission.py:53 #: judge/admin/submission.py:31 judge/admin/submission.py:53
#: judge/admin/submission.py:340 #: judge/admin/submission.py:345
msgid "None" msgid "None"
msgstr "None" msgstr "None"
@ -360,29 +360,29 @@ msgctxt "contest problem"
msgid "%(problem)s in %(contest)s" msgid "%(problem)s in %(contest)s"
msgstr "%(problem)s trong %(contest)s" msgstr "%(problem)s trong %(contest)s"
#: judge/admin/submission.py:215 judge/admin/submission.py:256 #: judge/admin/submission.py:220 judge/admin/submission.py:261
msgid "You do not have the permission to rejudge submissions." msgid "You do not have the permission to rejudge submissions."
msgstr "Bạn không có quyền chấm lại bài." msgstr "Bạn không có quyền chấm lại bài."
#: judge/admin/submission.py:227 #: judge/admin/submission.py:232
msgid "You do not have the permission to rejudge THAT many submissions." msgid "You do not have the permission to rejudge THAT many submissions."
msgstr "Bạn không có quyền chấm lại nhiều bài nộp như vậy." msgstr "Bạn không có quyền chấm lại nhiều bài nộp như vậy."
#: judge/admin/submission.py:250 #: judge/admin/submission.py:255
msgid "Rejudge the selected submissions" msgid "Rejudge the selected submissions"
msgstr "Chấm lại các bài nộp đã chọn" msgstr "Chấm lại các bài nộp đã chọn"
#: judge/admin/submission.py:304 judge/views/problem_manage.py:226 #: judge/admin/submission.py:309 judge/views/problem_manage.py:226
#, python-format #, python-format
msgid "%d submission were successfully rescored." msgid "%d submission were successfully rescored."
msgid_plural "%d submissions were successfully rescored." msgid_plural "%d submissions were successfully rescored."
msgstr[0] "%d bài nộp đã được tính điểm lại." msgstr[0] "%d bài nộp đã được tính điểm lại."
#: judge/admin/submission.py:311 #: judge/admin/submission.py:316
msgid "Rescore the selected submissions" msgid "Rescore the selected submissions"
msgstr "Tính điểm lại cái bài nộp" msgstr "Tính điểm lại cái bài nộp"
#: judge/admin/submission.py:334 templates/notification/list.html:15 #: judge/admin/submission.py:339 templates/notification/list.html:15
#: templates/organization/requests/log.html:10 #: templates/organization/requests/log.html:10
#: templates/organization/requests/pending.html:20 #: templates/organization/requests/pending.html:20
#: templates/problem/list.html:154 #: templates/problem/list.html:154
@ -391,17 +391,17 @@ msgstr "Tính điểm lại cái bài nộp"
msgid "Time" msgid "Time"
msgstr "Thời gian" msgstr "Thời gian"
#: judge/admin/submission.py:342 #: judge/admin/submission.py:347
#, python-format #, python-format
msgid "%d KB" msgid "%d KB"
msgstr "%d KB" msgstr "%d KB"
#: judge/admin/submission.py:344 #: judge/admin/submission.py:349
#, python-format #, python-format
msgid "%.2f MB" msgid "%.2f MB"
msgstr "" msgstr ""
#: judge/admin/submission.py:347 templates/submission/status-testcases.html:151 #: judge/admin/submission.py:352 templates/submission/status-testcases.html:151
msgid "Memory" msgid "Memory"
msgstr "Bộ nhớ" msgstr "Bộ nhớ"
@ -426,20 +426,20 @@ msgstr "Dạng"
msgid "Online Judge" msgid "Online Judge"
msgstr "" msgstr ""
#: judge/comments.py:60 #: judge/comments.py:61
msgid "Comment body" msgid "Comment body"
msgstr "Nội dung bình luận" msgstr "Nội dung bình luận"
#: judge/comments.py:66 judge/views/ticket.py:78 #: judge/comments.py:67 judge/views/ticket.py:78
msgid "Your part is silent, little toad." msgid "Your part is silent, little toad."
msgstr "Bạn không được phép bình luận." msgstr "Bạn không được phép bình luận."
#: judge/comments.py:75 templates/comments/list.html:17 #: judge/comments.py:76 templates/comments/list.html:17
msgid "" msgid ""
"You need to have solved at least one problem before your voice can be heard." "You need to have solved at least one problem before your voice can be heard."
msgstr "Bạn phải giải ít nhất một bài trước khi được phép bình luận." msgstr "Bạn phải giải ít nhất một bài trước khi được phép bình luận."
#: judge/comments.py:124 #: judge/comments.py:125
msgid "Posted comment" msgid "Posted comment"
msgstr "Bình luận đã đăng" msgstr "Bình luận đã đăng"
@ -467,7 +467,7 @@ msgstr ""
msgid "New IOI" msgid "New IOI"
msgstr "IOI mới" msgstr "IOI mới"
#: judge/forms.py:107 judge/views/organization.py:514 #: judge/forms.py:107 judge/views/organization.py:520
#: judge/views/register.py:62 #: judge/views/register.py:62
#, python-brace-format #, python-brace-format
msgid "You may not be part of more than {count} public groups." msgid "You may not be part of more than {count} public groups."
@ -533,7 +533,7 @@ msgid "N j, Y, g:i a"
msgstr "g:i a j b, Y" msgstr "g:i a j b, Y"
#: judge/jinja2/datetime.py:26 templates/chat/message.html:13 #: judge/jinja2/datetime.py:26 templates/chat/message.html:13
#: templates/comments/list.html:76 #: templates/comments/content-list.html:35 templates/comments/list.html:77
#, python-brace-format #, python-brace-format
msgid "{time}" msgid "{time}"
msgstr "{time}" msgstr "{time}"
@ -543,19 +543,19 @@ msgstr "{time}"
msgid "on {time}" msgid "on {time}"
msgstr "vào {time}" msgstr "vào {time}"
#: judge/middleware.py:131 #: judge/middleware.py:135
msgid "No permission" msgid "No permission"
msgstr "Không có quyền truy cập" msgstr "Không có quyền truy cập"
#: judge/middleware.py:132 #: judge/middleware.py:136
msgid "You need to join this group first" msgid "You need to join this group first"
msgstr "Bạn phải là thành viên của nhóm." msgstr "Bạn phải là thành viên của nhóm."
#: judge/middleware.py:142 judge/middleware.py:143 #: judge/middleware.py:146 judge/middleware.py:147
msgid "No such group" msgid "No such group"
msgstr "Nhóm không tồn tại" msgstr "Nhóm không tồn tại"
#: judge/models/bookmark.py:14 judge/models/comment.py:161 #: judge/models/bookmark.py:14 judge/models/comment.py:171
#: judge/models/pagevote.py:13 #: judge/models/pagevote.py:13
msgid "associated page" msgid "associated page"
msgstr "trang tương ứng" msgstr "trang tương ứng"
@ -621,56 +621,49 @@ msgstr "ẩn bình luận"
msgid "parent" msgid "parent"
msgstr "" msgstr ""
#: judge/models/comment.py:62 judge/models/comment.py:181 #: judge/models/comment.py:63 judge/models/comment.py:191
msgid "comment" msgid "comment"
msgstr "bình luận" msgstr "bình luận"
#: judge/models/comment.py:63 #: judge/models/comment.py:64
msgid "comments" msgid "comments"
msgstr "" msgstr ""
#: judge/models/comment.py:122 #: judge/models/comment.py:132
#, fuzzy #, fuzzy
#| msgid "Editorial for {0}" #| msgid "Editorial for {0}"
msgid "Editorial for " msgid "Editorial for "
msgstr "Hướng dẫn cho {0}" msgstr "Hướng dẫn cho {0}"
#: judge/models/comment.py:154 #: judge/models/comment.py:164
msgid "comment vote" msgid "comment vote"
msgstr "" msgstr ""
#: judge/models/comment.py:155 #: judge/models/comment.py:165
msgid "comment votes" msgid "comment votes"
msgstr "" msgstr ""
#: judge/models/comment.py:166 #: judge/models/comment.py:176
msgid "Override comment lock" msgid "Override comment lock"
msgstr "" msgstr ""
#: judge/models/comment.py:175 #: judge/models/comment.py:185
#: src/dmoj-wpadmin/test_project/apps/books/admin.py:24
#: src/dmoj-wpadmin/test_project/apps/books/models.py:30
#: src/dmoj-wpadmin/test_project/apps/cds/models.py:30
#: src/dmoj-wpadmin/test_project/apps/dvds/models.py:30
msgid "owner" msgid "owner"
msgstr "" msgstr ""
#: judge/models/comment.py:183 judge/models/message.py:28 #: judge/models/comment.py:193 judge/models/message.py:28
msgid "read" msgid "read"
msgstr "" msgstr ""
#: judge/models/comment.py:184 #: judge/models/comment.py:194
#: src/dmoj-wpadmin/test_project/apps/books/models.py:28
#: src/dmoj-wpadmin/test_project/apps/cds/models.py:28
#: src/dmoj-wpadmin/test_project/apps/dvds/models.py:28
msgid "category" msgid "category"
msgstr "" msgstr ""
#: judge/models/comment.py:187 #: judge/models/comment.py:197
msgid "html link to comments, used for non-comments" msgid "html link to comments, used for non-comments"
msgstr "" msgstr ""
#: judge/models/comment.py:193 #: judge/models/comment.py:203
msgid "who trigger, used for non-comment" msgid "who trigger, used for non-comment"
msgstr "" msgstr ""
@ -739,13 +732,6 @@ msgstr ""
#: judge/models/contest.py:118 judge/models/course.py:158 #: judge/models/contest.py:118 judge/models/course.py:158
#: judge/models/runtime.py:211 #: judge/models/runtime.py:211
#: src/dmoj-wpadmin/test_project/apps/books/admin.py:20
#: src/dmoj-wpadmin/test_project/apps/books/models.py:13
#: src/dmoj-wpadmin/test_project/apps/books/models.py:27
#: src/dmoj-wpadmin/test_project/apps/cds/models.py:13
#: src/dmoj-wpadmin/test_project/apps/cds/models.py:27
#: src/dmoj-wpadmin/test_project/apps/dvds/models.py:13
#: src/dmoj-wpadmin/test_project/apps/dvds/models.py:27
msgid "description" msgid "description"
msgstr "mô tả" msgstr "mô tả"
@ -2660,24 +2646,24 @@ msgstr "Báo cáo"
msgid "Comment feed" msgid "Comment feed"
msgstr "Bình luận" msgstr "Bình luận"
#: judge/views/comment.py:42 judge/views/pagevote.py:31 #: judge/views/comment.py:53 judge/views/pagevote.py:31
msgid "Messing around, are we?" msgid "Messing around, are we?"
msgstr "Messing around, are we?" msgstr "Messing around, are we?"
#: judge/views/comment.py:58 judge/views/pagevote.py:47 #: judge/views/comment.py:69 judge/views/pagevote.py:47
msgid "You must solve at least one problem before you can vote." msgid "You must solve at least one problem before you can vote."
msgstr "Bạn phải giải ít nhất 1 bài trước khi được vote." msgstr "Bạn phải giải ít nhất 1 bài trước khi được vote."
#: judge/views/comment.py:89 #: judge/views/comment.py:100
msgid "You already voted." msgid "You already voted."
msgstr "Bạn đã vote." msgstr "Bạn đã vote."
#: judge/views/comment.py:165 judge/views/organization.py:811 #: judge/views/comment.py:243 judge/views/organization.py:817
#: judge/views/organization.py:957 judge/views/organization.py:1122 #: judge/views/organization.py:963 judge/views/organization.py:1128
msgid "Edited from site" msgid "Edited from site"
msgstr "Chỉnh sửa từ web" msgstr "Chỉnh sửa từ web"
#: judge/views/comment.py:186 #: judge/views/comment.py:264
msgid "Editing comment" msgid "Editing comment"
msgstr "Chỉnh sửa bình luận" msgstr "Chỉnh sửa bình luận"
@ -2879,13 +2865,13 @@ msgstr "Không thể chỉnh sửa tổ chức"
msgid "You are not allowed to edit this organization." msgid "You are not allowed to edit this organization."
msgstr "Bạn không được phép chỉnh sửa tổ chức này." msgstr "Bạn không được phép chỉnh sửa tổ chức này."
#: judge/views/organization.py:193 judge/views/organization.py:337 #: judge/views/organization.py:193 judge/views/organization.py:340
#, fuzzy #, fuzzy
#| msgid "Can't edit organization" #| msgid "Can't edit organization"
msgid "Can't access organization" msgid "Can't access organization"
msgstr "Không thể chỉnh sửa tổ chức" msgstr "Không thể chỉnh sửa tổ chức"
#: judge/views/organization.py:194 judge/views/organization.py:338 #: judge/views/organization.py:194 judge/views/organization.py:341
msgid "You are not allowed to access this organization." msgid "You are not allowed to access this organization."
msgstr "Bạn không được phép chỉnh sửa tổ chức này." msgstr "Bạn không được phép chỉnh sửa tổ chức này."
@ -2896,57 +2882,57 @@ msgstr "Bạn không được phép chỉnh sửa tổ chức này."
msgid "Groups" msgid "Groups"
msgstr "Nhóm" msgstr "Nhóm"
#: judge/views/organization.py:344 #: judge/views/organization.py:347
#, python-format #, python-format
msgid "%s Members" msgid "%s Members"
msgstr "%s Thành viên" msgstr "%s Thành viên"
#: judge/views/organization.py:470 #: judge/views/organization.py:476
#, python-brace-format #, python-brace-format
msgid "All submissions in <a href=\"{1}\">{0}</a>" msgid "All submissions in <a href=\"{1}\">{0}</a>"
msgstr "Bài nộp trong <a href=\"{1}\">{0}</a>" msgstr "Bài nộp trong <a href=\"{1}\">{0}</a>"
#: judge/views/organization.py:500 judge/views/organization.py:506 #: judge/views/organization.py:506 judge/views/organization.py:512
#: judge/views/organization.py:513 #: judge/views/organization.py:519
msgid "Joining group" msgid "Joining group"
msgstr "Tham gia nhóm" msgstr "Tham gia nhóm"
#: judge/views/organization.py:501 #: judge/views/organization.py:507
msgid "You are already in the group." msgid "You are already in the group."
msgstr "Bạn đã ở trong nhóm." msgstr "Bạn đã ở trong nhóm."
#: judge/views/organization.py:506 #: judge/views/organization.py:512
msgid "This group is not open." msgid "This group is not open."
msgstr "Nhóm này là nhóm kín." msgstr "Nhóm này là nhóm kín."
#: judge/views/organization.py:529 #: judge/views/organization.py:535
msgid "Leaving group" msgid "Leaving group"
msgstr "Rời nhóm" msgstr "Rời nhóm"
#: judge/views/organization.py:530 #: judge/views/organization.py:536
#, python-format #, python-format
msgid "You are not in \"%s\"." msgid "You are not in \"%s\"."
msgstr "Bạn không ở trong \"%s\"." msgstr "Bạn không ở trong \"%s\"."
#: judge/views/organization.py:555 #: judge/views/organization.py:561
#, python-format #, python-format
msgid "Request to join %s" msgid "Request to join %s"
msgstr "Đăng ký tham gia %s" msgstr "Đăng ký tham gia %s"
#: judge/views/organization.py:585 #: judge/views/organization.py:591
msgid "Join request detail" msgid "Join request detail"
msgstr "Chi tiết đơn đăng ký" msgstr "Chi tiết đơn đăng ký"
#: judge/views/organization.py:627 #: judge/views/organization.py:633
msgid "Manage join requests" msgid "Manage join requests"
msgstr "Quản lý đơn đăng ký" msgstr "Quản lý đơn đăng ký"
#: judge/views/organization.py:631 #: judge/views/organization.py:637
#, python-format #, python-format
msgid "Managing join requests for %s" msgid "Managing join requests for %s"
msgstr "Quản lý đơn đăng ký cho %s" msgstr "Quản lý đơn đăng ký cho %s"
#: judge/views/organization.py:671 #: judge/views/organization.py:677
#, python-format #, python-format
msgid "" msgid ""
"Your organization can only receive %d more members. You cannot approve %d " "Your organization can only receive %d more members. You cannot approve %d "
@ -2955,96 +2941,96 @@ msgstr ""
"Tổ chức chỉ có thể chứa %d thành viên. Bạn không thể chấp thuận nhiều hơn %d " "Tổ chức chỉ có thể chứa %d thành viên. Bạn không thể chấp thuận nhiều hơn %d "
"người." "người."
#: judge/views/organization.py:689 #: judge/views/organization.py:695
#, python-format #, python-format
msgid "Approved %d user." msgid "Approved %d user."
msgid_plural "Approved %d users." msgid_plural "Approved %d users."
msgstr[0] "Đã chấp thuận %d người." msgstr[0] "Đã chấp thuận %d người."
#: judge/views/organization.py:692 #: judge/views/organization.py:698
#, python-format #, python-format
msgid "Rejected %d user." msgid "Rejected %d user."
msgid_plural "Rejected %d users." msgid_plural "Rejected %d users."
msgstr[0] "Đã từ chối %d người." msgstr[0] "Đã từ chối %d người."
#: judge/views/organization.py:732 #: judge/views/organization.py:738
#, python-format #, python-format
msgid "Add member for %s" msgid "Add member for %s"
msgstr "Thêm thành viên cho %s" msgstr "Thêm thành viên cho %s"
#: judge/views/organization.py:744 #: judge/views/organization.py:750
#, fuzzy #, fuzzy
#| msgid "Edited from site" #| msgid "Edited from site"
msgid "Added members from site" msgid "Added members from site"
msgstr "Chỉnh sửa từ web" msgstr "Chỉnh sửa từ web"
#: judge/views/organization.py:764 judge/views/organization.py:772 #: judge/views/organization.py:770 judge/views/organization.py:778
msgid "Can't kick user" msgid "Can't kick user"
msgstr "Không thể đuổi" msgstr "Không thể đuổi"
#: judge/views/organization.py:765 #: judge/views/organization.py:771
msgid "The user you are trying to kick does not exist!" msgid "The user you are trying to kick does not exist!"
msgstr "" msgstr ""
#: judge/views/organization.py:773 #: judge/views/organization.py:779
#, python-format #, python-format
msgid "The user you are trying to kick is not in organization: %s." msgid "The user you are trying to kick is not in organization: %s."
msgstr "" msgstr ""
#: judge/views/organization.py:794 judge/views/organization.py:946 #: judge/views/organization.py:800 judge/views/organization.py:952
#, fuzzy, python-format #, fuzzy, python-format
#| msgid "Editing %s" #| msgid "Editing %s"
msgid "Edit %s" msgid "Edit %s"
msgstr "Đang chỉnh sửa %s" msgstr "Đang chỉnh sửa %s"
#: judge/views/organization.py:822 templates/organization/list.html:45 #: judge/views/organization.py:828 templates/organization/list.html:45
msgid "Create group" msgid "Create group"
msgstr "Tạo nhóm" msgstr "Tạo nhóm"
#: judge/views/organization.py:837 #: judge/views/organization.py:843
msgid "Exceeded limit" msgid "Exceeded limit"
msgstr "" msgstr ""
#: judge/views/organization.py:838 #: judge/views/organization.py:844
#, python-format #, python-format
msgid "You created too many groups. You can only create at most %d groups" msgid "You created too many groups. You can only create at most %d groups"
msgstr "" msgstr ""
#: judge/views/organization.py:843 judge/views/organization.py:868 #: judge/views/organization.py:849 judge/views/organization.py:874
#: judge/views/organization.py:1012 #: judge/views/organization.py:1018
msgid "Added from site" msgid "Added from site"
msgstr "Thêm từ web" msgstr "Thêm từ web"
#: judge/views/organization.py:859 #: judge/views/organization.py:865
#: templates/organization/org-right-sidebar.html:55 #: templates/organization/org-right-sidebar.html:55
msgid "Add contest" msgid "Add contest"
msgstr "Thêm kỳ thi" msgstr "Thêm kỳ thi"
#: judge/views/organization.py:902 judge/views/organization.py:1064 #: judge/views/organization.py:908 judge/views/organization.py:1070
msgid "Permission denied" msgid "Permission denied"
msgstr "Truy cập bị từ chối" msgstr "Truy cập bị từ chối"
#: judge/views/organization.py:903 #: judge/views/organization.py:909
#, fuzzy #, fuzzy
#| msgid "You are not allowed to edit this organization." #| msgid "You are not allowed to edit this organization."
msgid "You are not allowed to edit this contest" msgid "You are not allowed to edit this contest"
msgstr "Bạn không được phép chỉnh sửa tổ chức này." msgstr "Bạn không được phép chỉnh sửa tổ chức này."
#: judge/views/organization.py:1001 #: judge/views/organization.py:1007
#, python-format #, python-format
msgid "Add blog for %s" msgid "Add blog for %s"
msgstr "Thêm bài đăng cho %s" msgstr "Thêm bài đăng cho %s"
#: judge/views/organization.py:1065 #: judge/views/organization.py:1071
msgid "Not allowed to edit this blog" msgid "Not allowed to edit this blog"
msgstr "Bạn không được phép chỉnh sửa bài đăng này." msgstr "Bạn không được phép chỉnh sửa bài đăng này."
#: judge/views/organization.py:1097 #: judge/views/organization.py:1103
#, python-format #, python-format
msgid "Edit blog %s" msgid "Edit blog %s"
msgstr "Chỉnh sửa %s" msgstr "Chỉnh sửa %s"
#: judge/views/organization.py:1148 #: judge/views/organization.py:1154
#, python-format #, python-format
msgid "Pending blogs in %s" msgid "Pending blogs in %s"
msgstr "Bài đang đợi duyệt trong %s" msgstr "Bài đang đợi duyệt trong %s"
@ -3097,12 +3083,12 @@ msgstr "Quá nhiều lần nộp"
msgid "You have exceeded the submission limit for this problem." msgid "You have exceeded the submission limit for this problem."
msgstr "Bạn đã vượt quá số lần nộp cho bài này." msgstr "Bạn đã vượt quá số lần nộp cho bài này."
#: judge/views/problem.py:1177 judge/views/problem.py:1182 #: judge/views/problem.py:1176 judge/views/problem.py:1181
#, python-format #, python-format
msgid "Submit to %(problem)s" msgid "Submit to %(problem)s"
msgstr "Nộp bài cho %(problem)s" msgstr "Nộp bài cho %(problem)s"
#: judge/views/problem.py:1208 #: judge/views/problem.py:1207
msgid "Clone Problem" msgid "Clone Problem"
msgstr "Nhân bản bài tập" msgstr "Nhân bản bài tập"
@ -3302,8 +3288,8 @@ msgstr "Phải qua một kỳ thi"
#: judge/views/submission.py:903 #: judge/views/submission.py:903
#, python-brace-format #, python-brace-format
msgid "" msgid ""
"<a href=\"{1}\">{0}</a>'s submissions for <a href=\"{3}\">{2}</a> in <a href=" "<a href=\"{1}\">{0}</a>'s submissions for <a href=\"{3}\">{2}</a> in <a "
"\"{5}\">{4}</a>" "href=\"{5}\">{4}</a>"
msgstr "" msgstr ""
"Các bài nộp của <a href=\"{1}\">{0}</a> cho <a href=\"{3}\">{2}</a> trong <a " "Các bài nộp của <a href=\"{1}\">{0}</a> cho <a href=\"{3}\">{2}</a> trong <a "
"href=\"{5}\">{4}</a>" "href=\"{5}\">{4}</a>"
@ -3431,147 +3417,6 @@ msgstr "Dữ liệu không hợp lệ: %s"
msgid "Bad latitude or longitude" msgid "Bad latitude or longitude"
msgstr "Kinh độ / Vĩ độ không hợp lệ" msgstr "Kinh độ / Vĩ độ không hợp lệ"
#: src/dmoj-wpadmin/test_project/apps/authors/models.py:9
#, fuzzy
#| msgid "short name"
msgid "first name"
msgstr "tên ngắn"
#: src/dmoj-wpadmin/test_project/apps/authors/models.py:10
#, fuzzy
#| msgid "short name"
msgid "last name"
msgstr "tên ngắn"
#: src/dmoj-wpadmin/test_project/apps/authors/models.py:11
msgid "biography"
msgstr "tiểu sử"
#: src/dmoj-wpadmin/test_project/apps/books/models.py:12
#: src/dmoj-wpadmin/test_project/apps/cds/models.py:12
#: src/dmoj-wpadmin/test_project/apps/dvds/models.py:12
msgid "name"
msgstr "tên"
#: src/dmoj-wpadmin/test_project/apps/books/models.py:19
msgid "Category of Books"
msgstr "Thể loại sách"
#: src/dmoj-wpadmin/test_project/apps/books/models.py:20
msgid "Categories of Books"
msgstr "Thể loại sách"
#: src/dmoj-wpadmin/test_project/apps/books/models.py:26
#: src/dmoj-wpadmin/test_project/apps/cds/models.py:26
#: src/dmoj-wpadmin/test_project/apps/dvds/models.py:26
msgid "title"
msgstr "tiêu đề"
#: src/dmoj-wpadmin/test_project/apps/books/models.py:29
#: src/dmoj-wpadmin/test_project/apps/cds/models.py:29
#: src/dmoj-wpadmin/test_project/apps/dvds/models.py:29
msgid "author"
msgstr "tác giả"
#: src/dmoj-wpadmin/test_project/apps/books/models.py:31
msgid "publication date"
msgstr "ngày xuất bản"
#: src/dmoj-wpadmin/test_project/apps/books/models.py:37
msgid "Book"
msgstr "Sách"
#: src/dmoj-wpadmin/test_project/apps/books/models.py:38
#: src/dmoj-wpadmin/test_project/test_project/wp.py:136
msgid "Books"
msgstr "Sách"
#: src/dmoj-wpadmin/test_project/apps/cds/models.py:19
msgid "Category of CDs"
msgstr "Thể loại CDs"
#: src/dmoj-wpadmin/test_project/apps/cds/models.py:20
msgid "Categories of CDs"
msgstr "Thể loại CDs"
#: src/dmoj-wpadmin/test_project/apps/cds/models.py:36
msgid "CD"
msgstr ""
#: src/dmoj-wpadmin/test_project/apps/cds/models.py:37
#: src/dmoj-wpadmin/test_project/test_project/wp.py:141
msgid "CDs"
msgstr ""
#: src/dmoj-wpadmin/test_project/apps/dvds/models.py:19
msgid "Category of DVDs"
msgstr "Thể loại DVDs"
#: src/dmoj-wpadmin/test_project/apps/dvds/models.py:20
msgid "Categories of DVDs"
msgstr "Thể loại DVDs"
#: src/dmoj-wpadmin/test_project/apps/dvds/models.py:36
msgid "DVD"
msgstr ""
#: src/dmoj-wpadmin/test_project/apps/dvds/models.py:37
#: src/dmoj-wpadmin/test_project/test_project/wp.py:146
msgid "DVDs"
msgstr ""
#: src/dmoj-wpadmin/test_project/templates/admin/base_site.html:7
msgid "Django administration"
msgstr "Quản trị viên Django"
#: src/dmoj-wpadmin/test_project/test_project/forms.py:12
#, python-format
msgid ""
"Please enter the correct %(username)s and password for an admin account. "
"Note that both fields may be case-sensitive."
msgstr ""
"Hãy nhập %(username)s và mật khẩu hợp lệ cho tài khoản quản trị. Chú ý cả "
"hai trường có phân biệt chữ Hoa-thường."
#: src/dmoj-wpadmin/test_project/test_project/forms.py:32
#, python-format
msgid ""
"Please enter the correct %(username)s and password for an user account. Note "
"that both fields may be case-sensitive."
msgstr ""
"Hãy nhập %(username)s và mật khẩu hợp lệ cho tài khoản thành viên. Chú ý cả "
"hai trường có phân biệt chữ Hoa-thường."
#: src/dmoj-wpadmin/test_project/test_project/wp.py:27
#: templates/stats/tab.html:5
msgid "Site"
msgstr "Trang"
#: src/dmoj-wpadmin/test_project/test_project/wp.py:38
#: src/dmoj-wpadmin/test_project/test_project/wp.py:41
#: src/dmoj-wpadmin/test_project/test_project/wp.py:130
#: src/dmoj-wpadmin/test_project/test_project/wp.py:133
msgid "Dashboard"
msgstr "Bảng điều khiển"
#: src/dmoj-wpadmin/test_project/test_project/wp.py:48
msgid "Applications"
msgstr "Ứng dụng"
#: src/dmoj-wpadmin/test_project/test_project/wp.py:53
#, fuzzy
#| msgid "administrators"
msgid "Administration"
msgstr "người quản lý"
#: src/dmoj-wpadmin/test_project/test_project/wp.py:64
msgid "Color theme"
msgstr "Chủ đề màu sắc"
#: src/dmoj-wpadmin/test_project/test_project/wp.py:66
msgid "Change color theme"
msgstr "Đổi chủ đề màu sắc"
#: templates/actionbar/list.html:15 #: templates/actionbar/list.html:15
msgid "Like" msgid "Like"
msgstr "Thích" msgstr "Thích"
@ -3657,7 +3502,8 @@ msgid "Profile"
msgstr "Trang cá nhân" msgstr "Trang cá nhân"
#: templates/base.html:276 templates/chat/chat.html:21 #: templates/base.html:276 templates/chat/chat.html:21
#: templates/comments/list.html:125 templates/contest/contest-list-tabs.html:4 #: templates/comments/content-list.html:80 templates/comments/list.html:126
#: templates/contest/contest-list-tabs.html:4
#: templates/contest/ranking-table.html:47 templates/internal/problem.html:57 #: templates/contest/ranking-table.html:47 templates/internal/problem.html:57
#: templates/organization/org-left-sidebar.html:12 #: templates/organization/org-left-sidebar.html:12
#: templates/problem/left-sidebar.html:6 #: templates/problem/left-sidebar.html:6
@ -3713,8 +3559,9 @@ msgstr ""
msgid " posted on %(time)s" msgid " posted on %(time)s"
msgstr "đã đăng vào %(time)s" msgstr "đã đăng vào %(time)s"
#: templates/blog/blog.html:31 templates/comments/list.html:104 #: templates/blog/blog.html:31 templates/comments/content-list.html:61
#: templates/comments/list.html:119 templates/contest/contest-tabs.html:35 #: templates/comments/content-list.html:75 templates/comments/list.html:105
#: templates/comments/list.html:120 templates/contest/contest-tabs.html:35
#: templates/contest/list.html:124 templates/contest/tag-title.html:9 #: templates/contest/list.html:124 templates/contest/tag-title.html:9
#: templates/flatpages/admin_link.html:3 templates/license.html:10 #: templates/flatpages/admin_link.html:3 templates/license.html:10
#: templates/problem/editorial.html:15 templates/problem/feed/problems.html:50 #: templates/problem/editorial.html:15 templates/problem/feed/problems.html:50
@ -3852,6 +3699,68 @@ msgstr "Tắt thông báo"
msgid "users are online" msgid "users are online"
msgstr "người đang trực tuyến" msgstr "người đang trực tuyến"
#: templates/comments/content-list.html:13
#: templates/comments/content-list.html:14
#: templates/comments/content-list.html:22
#: templates/comments/content-list.html:23 templates/comments/list.html:55
#: templates/comments/list.html:64
msgid "Please login to vote"
msgstr "Đăng nhập để vote"
#: templates/comments/content-list.html:43 templates/comments/list.html:86
#, python-format
msgid "edit %(edits)s"
msgstr "chỉnh sửa %(edits)s"
#: templates/comments/content-list.html:45 templates/comments/list.html:88
#: templates/comments/media-js.html:96
msgid "edited"
msgstr "đã chỉnh sửa"
#: templates/comments/content-list.html:54 templates/comments/list.html:97
#: templates/notification/list.html:14
msgid "Link"
msgstr "Link"
#: templates/comments/content-list.html:65
#: templates/comments/content-list.html:71 templates/comments/list.html:110
#: templates/comments/list.html:117
msgid "Reply"
msgstr "Phản hồi"
#: templates/comments/content-list.html:78 templates/comments/list.html:123
msgid "Hide"
msgstr "Ẩn"
#: templates/comments/content-list.html:92
#, fuzzy, python-format
#| msgid ""
#| "This comment is hidden due to too much negative feedback. Click <a "
#| "href=\"javascript:comment_show_content(%(id)s)\">here</a> to view it."
msgid ""
"This comment is hidden due to too much negative feedback. Click <a\n"
" href=\"javascript:"
"comment_show_content(%(id)s)\">here</a> to view it."
msgstr ""
"Bình luận bị ẩn vì nhiều phản hồi tiêu cực. Nhấp vào <a href=\"javascript:"
"comment_show_content(%(id)s)\">đây</a> để mở."
#: templates/comments/content-list.html:107
msgid "replies"
msgstr "phản hồi"
#: templates/comments/content-list.html:114
msgid "reply"
msgstr "phản hồi"
#: templates/comments/content-list.html:130 templates/comments/list.html:160
msgid "comment more"
msgstr "bình luận nữa"
#: templates/comments/content-list.html:137 templates/comments/list.html:168
msgid "comments more"
msgstr "bình luận nữa"
#: templates/comments/list.html:6 #: templates/comments/list.html:6
msgid "Write comment" msgid "Write comment"
msgstr "Thêm bình luận" msgstr "Thêm bình luận"
@ -3868,45 +3777,20 @@ msgstr "Nội dung không hợp lệ."
msgid "Post!" msgid "Post!"
msgstr "Đăng!" msgstr "Đăng!"
#: templates/comments/list.html:54 templates/comments/list.html:63 #: templates/comments/list.html:138
msgid "Please login to vote"
msgstr "Đăng nhập để vote"
#: templates/comments/list.html:85
#, python-format
msgid "edit %(edits)s"
msgstr "chỉnh sửa %(edits)s"
#: templates/comments/list.html:87 templates/comments/media-js.html:96
msgid "edited"
msgstr "đã chỉnh sửa"
#: templates/comments/list.html:96 templates/notification/list.html:14
msgid "Link"
msgstr "Link"
#: templates/comments/list.html:109 templates/comments/list.html:116
msgid "Reply"
msgstr "Trả lời"
#: templates/comments/list.html:122
msgid "Hide"
msgstr "Ẩn"
#: templates/comments/list.html:137
#, python-format #, python-format
msgid "" msgid ""
"This comment is hidden due to too much negative feedback. Click <a href=" "This comment is hidden due to too much negative feedback. Click <a "
"\"javascript:comment_show_content(%(id)s)\">here</a> to view it." "href=\"javascript:comment_show_content(%(id)s)\">here</a> to view it."
msgstr "" msgstr ""
"Bình luận bị ẩn vì nhiều phản hồi tiêu cực. Nhấp vào <a href=\"javascript:" "Bình luận bị ẩn vì nhiều phản hồi tiêu cực. Nhấp vào <a href=\"javascript:"
"comment_show_content(%(id)s)\">đây</a> để mở." "comment_show_content(%(id)s)\">đây</a> để mở."
#: templates/comments/list.html:154 #: templates/comments/list.html:177
msgid "There are no comments at the moment." msgid "There are no comments at the moment."
msgstr "Không có bình luận nào." msgstr "Không có bình luận nào."
#: templates/comments/list.html:159 #: templates/comments/list.html:182
msgid "Comments are disabled on this page." msgid "Comments are disabled on this page."
msgstr "Bình luận bị tắt trong trang này." msgstr "Bình luận bị tắt trong trang này."
@ -4034,8 +3918,8 @@ msgstr "G:i T, j F, Y"
#: templates/contest/contest-datetime.html:39 #: templates/contest/contest-datetime.html:39
#, python-format #, python-format
msgid "" msgid ""
"<b>%(time_limit)s</b> window between <b>%(start_time)s</b> and <b>" "<b>%(time_limit)s</b> window between <b>%(start_time)s</b> and "
"%(end_time)s</b>" "<b>%(end_time)s</b>"
msgstr "" msgstr ""
"Kéo dài <b>%(time_limit)s</b> từ <b>%(start_time)s</b> đến <b>%(end_time)s</" "Kéo dài <b>%(time_limit)s</b> từ <b>%(start_time)s</b> đến <b>%(end_time)s</"
"b>" "b>"
@ -5257,6 +5141,10 @@ msgstr "Thống kê"
msgid "AC Submissions by Language" msgid "AC Submissions by Language"
msgstr "Thống kê AC theo ngôn ngữ" msgstr "Thống kê AC theo ngôn ngữ"
#: templates/stats/tab.html:5
msgid "Site"
msgstr "Trang"
#: templates/status/judge-status-table.html:4 #: templates/status/judge-status-table.html:4
msgid "Online" msgid "Online"
msgstr "Trực tuyến" msgstr "Trực tuyến"
@ -5864,6 +5752,91 @@ msgstr "Thông tin"
msgid "Check all" msgid "Check all"
msgstr "Chọn tất cả" msgstr "Chọn tất cả"
#, fuzzy
#~| msgid "short name"
#~ msgid "first name"
#~ msgstr "tên ngắn"
#, fuzzy
#~| msgid "short name"
#~ msgid "last name"
#~ msgstr "tên ngắn"
#~ msgid "biography"
#~ msgstr "tiểu sử"
#~ msgid "name"
#~ msgstr "tên"
#~ msgid "Category of Books"
#~ msgstr "Thể loại sách"
#~ msgid "Categories of Books"
#~ msgstr "Thể loại sách"
#~ msgid "title"
#~ msgstr "tiêu đề"
#~ msgid "author"
#~ msgstr "tác giả"
#~ msgid "publication date"
#~ msgstr "ngày xuất bản"
#~ msgid "Book"
#~ msgstr "Sách"
#~ msgid "Books"
#~ msgstr "Sách"
#~ msgid "Category of CDs"
#~ msgstr "Thể loại CDs"
#~ msgid "Categories of CDs"
#~ msgstr "Thể loại CDs"
#~ msgid "Category of DVDs"
#~ msgstr "Thể loại DVDs"
#~ msgid "Categories of DVDs"
#~ msgstr "Thể loại DVDs"
#~ msgid "Django administration"
#~ msgstr "Quản trị viên Django"
#, python-format
#~ msgid ""
#~ "Please enter the correct %(username)s and password for an admin account. "
#~ "Note that both fields may be case-sensitive."
#~ msgstr ""
#~ "Hãy nhập %(username)s và mật khẩu hợp lệ cho tài khoản quản trị. Chú ý cả "
#~ "hai trường có phân biệt chữ Hoa-thường."
#, python-format
#~ msgid ""
#~ "Please enter the correct %(username)s and password for an user account. "
#~ "Note that both fields may be case-sensitive."
#~ msgstr ""
#~ "Hãy nhập %(username)s và mật khẩu hợp lệ cho tài khoản thành viên. Chú ý "
#~ "cả hai trường có phân biệt chữ Hoa-thường."
#~ msgid "Dashboard"
#~ msgstr "Bảng điều khiển"
#~ msgid "Applications"
#~ msgstr "Ứng dụng"
#, fuzzy
#~| msgid "administrators"
#~ msgid "Administration"
#~ msgstr "người quản lý"
#~ msgid "Color theme"
#~ msgstr "Chủ đề màu sắc"
#~ msgid "Change color theme"
#~ msgstr "Đổi chủ đề màu sắc"
#~ msgid "commented on {time}" #~ msgid "commented on {time}"
#~ msgstr "bình luận vào {time}" #~ msgstr "bình luận vào {time}"

View file

@ -33,9 +33,6 @@ msgstr "Đề xuất bài tập"
msgid "TanKhoa" msgid "TanKhoa"
msgstr "Tân Khoa" msgstr "Tân Khoa"
msgid "Name"
msgstr "Đăng ký tên"
msgid "Report" msgid "Report"
msgstr "Báo cáo" msgstr "Báo cáo"
@ -345,6 +342,9 @@ msgstr ""
msgid "ltt" msgid "ltt"
msgstr "" msgstr ""
msgid "Luyện tập"
msgstr ""
msgid "manacher" msgid "manacher"
msgstr "" msgstr ""
@ -593,3 +593,6 @@ msgstr ""
msgid "z-function" msgid "z-function"
msgstr "" msgstr ""
#~ msgid "Name"
#~ msgstr "Đăng ký tên"

0
make_style.sh Executable file → Normal file
View file

0
manage.py Executable file → Normal file
View file

0
resources/bootstrap/bootstrap.min.css vendored Executable file → Normal file
View file

View file

@ -126,6 +126,28 @@ a {
margin: -50px 23px 10px -40px; margin: -50px 23px 10px -40px;
padding-top: 50px; padding-top: 50px;
} }
.show_more_reply {
font-weight: bold;
display: flex;
margin: 16px 40px;
align-items: center;
svg {
margin-right: 4px;
}
}
.show_more_comment {
font-weight: bold;
display: flex;
margin: 16px -40px;
align-items: center;
svg {
margin-right: 4px;
}
}
} }
.no-comments-message { .no-comments-message {

View file

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

View file

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

0
resources/fontawesome/fontawesome.css vendored Executable file → Normal file
View file

0
resources/icons/android-chrome-512x512.png Executable file → Normal file
View file

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

0
resources/icons/logo.png Executable file → Normal file
View file

Before

Width:  |  Height:  |  Size: 278 KiB

After

Width:  |  Height:  |  Size: 278 KiB

View file

@ -0,0 +1,139 @@
{% set logged_in = request.user.is_authenticated %}
{% set profile = request.profile if logged_in else None %}
{% for node in mptt_tree(comment_list) recursive %}
<li id="comment-{{ node.id }}" data-revision="{{ node.revisions - 1 }}" data-max-revision="{{ node.revisions - 1 }}"
data-revision-ajax="{{ url('comment_revision_ajax', node.id) }}" class="comment">
<div class="comment-display{% if node.score <= vote_hide_threshold %} bad-comment{% endif %}">
<div class="info">
<div class="vote">
{% if logged_in %}
<a href="javascript:comment_upvote({{ node.id }})"
class="upvote-link fa fa-chevron-up fa-fw{% if node.vote_score == 1 %} voted{% endif %}"></a>
{% else %}
<a href="javascript:alert('{{ _('Please login to vote')|escapejs }}')"
title="{{ _('Please login to vote') }}" class="upvote-link fa fa-chevron-up fa-fw"></a>
{% endif %}
<br>
<div class="comment-score">{{ node.score }}</div>
{% if logged_in %}
<a href="javascript:comment_downvote({{ node.id }})"
class="downvote-link fa fa-chevron-down fa-fw{% if node.vote_score == -1 %} voted{% endif %}"></a>
{% else %}
<a href="javascript:alert('{{ _('Please login to vote')|escapejs }}')"
title="{{ _('Please login to vote') }}" class="downvote-link fa fa-chevron-down fa-fw"></a>
{% endif %}
</div>
</div>
<div class="detail">
<div class="header">
{% with author=node.author, user=node.author.user %}
<a href="{{ url('user_page', user.username) }}" class="user comment-img">
<img src="{{ gravatar(author, 135) }}" class="gravatar">
</a>
{% endwith %}
{{ link_user(node.author) }},&nbsp;
{{ relative_time(node.time, abs=_('{time}'), rel=_('{time}')) }}
<span class="comment-spacer"></span>
<span class="comment-operation">
{% if node.revisions > 1 %}
<span class="comment-edits">
<a href="javascript:show_revision({{ node.id }}, -1)" class="previous-revision">&larr;</a>
<span class="comment-edit-text">
{% if node.revisions > 2 %}
{% trans edits=node.revisions - 1 %}edit {{ edits }}{% endtrans %}
{% else %}
{{ _('edited') }}
{% endif %}
</span>
<a href="javascript:show_revision({{ node.id }}, 1)" style="visibility: hidden"
class="next-revision">&rarr;</a>
</span>
{% else %}
<span class="comment-edits"></span>
{% endif %}
<a href="#comment-{{ node.id }}" title="{{ _('Link') }}" class="comment-link">
<i class="fa fa-link fa-fw"></i>
</a>
{% if logged_in and not comment_lock %}
{% set can_edit = node.author.id == profile.id and not profile.mute %}
{% if can_edit %}
<a data-featherlight="{{ url('comment_edit_ajax', node.id) }}"
href="{{ url('comment_edit', node.id) }}" title="{{ _('Edit') }}" class="edit-link">
<i class="fa fa-pencil fa-fw"></i>
</a>
{% else %}
<a href="javascript:reply_comment({{ node.id }})" title="{{ _('Reply') }}">
<i class="fa fa-reply fa-fw"></i>
</a>
{% endif %}
{% if perms.judge.change_comment %}
{% if can_edit %}
<a href="javascript:reply_comment({{ node.id }})" title="{{ _('Reply') }}"><i
class="fa fa-reply fa-fw"></i></a>
{% else %}
<a data-featherlight="{{ url('comment_edit_ajax', node.id) }}"
href="{{ url('comment_edit', node.id) }}" title="{{ _('Edit') }}" class="edit-link"><i
class="fa fa-pencil fa-fw"></i></a>
{% endif %}
<a href="javascript:" title="{{ _('Hide') }}" data-id="{{ node.id }}" class="hide-comment"><i
class="fa fa-trash fa-fw"></i></a>
<a href="{{ url('admin:judge_comment_change', node.id) }}" title="{{ _('Admin') }}"><i
class="fa fa-cog fa-fw"></i></a>
{% endif %}
{% endif %}
</span>
</div>
<div class="content content-description">
<div class="comment-body" {% if node.score <=vote_hide_threshold %} style="display:none" {% endif %}>
{{ node.body|markdown(lazy_load=True)|reference|str|safe }}
</div>
{% if node.score <= vote_hide_threshold %} <div class="comment-body bad-comment-body">
<p>
{% trans id=node.id %}This comment is hidden due to too much negative feedback. Click <a
href="javascript:comment_show_content({{ id }})">here</a> to view it.{% endtrans %}
</p>
</div>
{% endif %}
</div>
</div>
</div>
{% if node.count_replies > 1 %}
<a href="javascript:comment_get_replies({{ node.id }}, 0)" class="show_more_reply">
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-arrow-forward" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M15 11l4 4l-4 4m4 -4h-11a4 4 0 0 1 0 -8h1"></path>
</svg>
{{ node.count_replies }} {{ _('replies') }} </a>
{% elif node.count_replies %}
<a href="javascript:comment_get_replies({{ node.id }}, 0)" class="show_more_reply">
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-arrow-forward" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M15 11l4 4l-4 4m4 -4h-11a4 4 0 0 1 0 -8h1"></path>
</svg>
{{ node.count_replies }} {{ _('reply') }} </a>
{% endif %}
</li>
<ul id="comment-{{ node.id }}-reply" class="reply-comment" hidden></ul>
<ul id="comment-{{ node.id }}-children" class="comments"> </ul>
{% endfor %}
{% set comment_more = comment_count - offset %}
{% if comment_more == 1 %}
<a href="javascript:comment_show_more({{ comment_root_id }}, {{ comment_parrent_none }}, {{ offset }}, {{ comment_remove }})" class="show_more_comment">
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-chevron-down" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M6 9l6 6l6 -6"></path>
</svg>
{{ comment_count - offset }} {{ _('comment more') }}</a>
{% elif comment_more > 1 %}
<a href="javascript:comment_show_more({{ comment_root_id }}, {{ comment_parrent_none }}, {{ offset }}, {{ comment_remove }})" class="show_more_comment">
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-chevron-down" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M6 9l6 6l6 -6"></path>
</svg>
{{ comment_count - offset }} {{ _('comments more') }}</a>
{% endif %}

View file

@ -36,11 +36,12 @@
{% endif %} {% endif %}
</div> </div>
{% endif %} {% endif %}
{% if has_comments %} {% if has_comments or comment_all_list %}
<ul class="comments top-level-comments new-comments"> <ul class="comments top-level-comments new-comments" id="comment-0">
{% set logged_in = request.user.is_authenticated %} {% set logged_in = request.user.is_authenticated %}
{% set profile = request.profile if logged_in else None %} {% set profile = request.profile if logged_in else None %}
{% for node in mptt_tree(comment_list) recursive %} {% if comment_all_list %}
{% for node in mptt_tree(comment_all_list) recursive %}
<li id="comment-{{ node.id }}" data-revision="{{ node.revisions - 1 }}" <li id="comment-{{ node.id }}" data-revision="{{ node.revisions - 1 }}"
data-max-revision="{{ node.revisions - 1 }}" data-max-revision="{{ node.revisions - 1 }}"
data-revision-ajax="{{ url('comment_revision_ajax', node.id) }}" class="comment"> data-revision-ajax="{{ url('comment_revision_ajax', node.id) }}" class="comment">
@ -149,6 +150,28 @@
{% endif %} {% endif %}
{% endwith %} {% endwith %}
{% endfor %} {% endfor %}
{% set comment_more = comment_count - offset %}
{% if comment_more == 1 %}
<a href="javascript:comment_show_more({{ comment_root_id }}, {{ comment_parrent_none }}, {{ offset }}, {{ comment_remove }})" class="show_more_comment">
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-chevron-down" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M6 9l6 6l6 -6"></path>
</svg>
{{ comment_count - offset }} {{ _('comment more') }}
</a>
{% elif comment_more > 1 %}
<a href="javascript:comment_show_more({{ comment_root_id }}, {{ comment_parrent_none }}, {{ offset }}, {{ comment_remove }})" class="show_more_comment">
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-chevron-down" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M6 9l6 6l6 -6"></path>
</svg>
{{ comment_count - offset }} {{ _('comments more') }}
</a>
{% endif %}
{% else %}
{% include "comments/content-list.html" %}
{% endif %}
</ul> </ul>
{% elif not comment_lock %} {% elif not comment_lock %}
<p class="no-comments-message">{{ _('There are no comments at the moment.') }}</p> <p class="no-comments-message">{{ _('There are no comments at the moment.') }}</p>

View file

@ -119,6 +119,77 @@
} }
}); });
} }
const queryString = window.location.search;
const urlParams = new URLSearchParams(queryString);
const comment_remove = urlParams.get('comment-id');
console.log(comment_remove);
window.comment_get_replies = function (id, parrent_none) {
var $comment_show_btn = $("#comment-" + id + " .show_more_reply");
$comment_show_btn.hide();
var $comment = $("#comment-" + id + "-children");
$comment.append("<p class='loading'> Loading... </p>");
ajax_get_reply('{{ url('comment_get_replies') }}', id, parrent_none);
}
function ajax_get_reply(url, id, parrent_none) {
return $.ajax({
url: url,
type: 'GET',
data: {
id: id,
parrent_none: parrent_none,
},
success: function(data) {
var $comment_loading = $("#comment-" + id + "-children .loading");
$comment_loading.hide();
var $comment = $("#comment-" + id + "-children");
$comment.append(data);
}
})
}
window.comment_show_more = function (id, parrent_none, offset, comment_remove) {
console.log(parrent_none)
if (parrent_none == 1) {
var $comment_show_btn = $("#comment-0" + " .show_more_comment");
$comment_show_btn.hide();
var $comment = $("#comment-0");
$comment.append("<p class='loading'> Loading... </p>");
} else {
var $comment_show_btn = $("#comment-" + id + "-children" + " .show_more_comment");
$comment_show_btn.hide();
var $comment = $("#comment-" + id + "-children");
$comment.append("<p class='loading'> Loading... </p>");
}
ajax_comment_show_more('{{ url('comment_show_more') }}', id, parrent_none, offset, comment_remove);
}
function ajax_comment_show_more(url, id, parrent_none, offset, comment_remove) {
return $.ajax({
url: url,
type: 'GET',
data: {
id: id,
parrent_none: parrent_none,
offset: offset,
comment_remove: comment_remove,
},
success: function(data) {
if (parrent_none == 1) {
var $comment_loading = $("#comment-0" + " .loading");
$comment_loading.hide();
var $comment = $("#comment-0");
$comment.append(data);
} else {
var $comment_loading = $("#comment-" + id + "-children .loading");
$comment_loading.hide();
var $comment = $("#comment-" + id + "-children");
$comment.append(data);
}
}
})
}
var get_$votes = function (id) { var get_$votes = function (id) {
var $comment = $('#comment-' + id); var $comment = $('#comment-' + id);