From 442a03ffdc1beaff8909823f070635b9a6021c5f Mon Sep 17 00:00:00 2001 From: liangliangyy Date: Fri, 8 Sep 2023 00:24:28 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=A4=9A=E8=AF=AD?= =?UTF-8?q?=E8=A8=80=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dockerfile | 3 +- accounts/admin.py | 6 +- accounts/forms.py | 22 +- ...s_remove_bloguser_created_time_and_more.py | 46 ++ accounts/models.py | 12 +- accounts/tests.py | 16 +- accounts/urls.py | 24 +- accounts/utils.py | 9 +- accounts/views.py | 2 +- blog/admin.py | 24 +- ...options_alter_category_options_and_more.py | 300 ++++++++ blog/models.py | 122 ++-- blog/static/blog/js/blog.js | 2 +- blog/static/blog/js/nprogress.js | 2 +- blog/templatetags/blog_tags.py | 2 +- blog/tests.py | 42 +- blog/views.py | 13 +- comments/admin.py | 14 +- ...ns_remove_comment_created_time_and_more.py | 60 ++ comments/models.py | 17 +- comments/tests.py | 19 +- comments/utils.py | 39 +- comments/views.py | 5 +- djangoblog/settings.py | 28 +- djangoblog/sitemap.py | 6 +- djangoblog/urls.py | 37 +- locale/en/LC_MESSAGES/django.po | 667 ++++++++++++++++++ locale/zh_Hans/LC_MESSAGES/django.po | 665 +++++++++++++++++ locale/zh_Hant/LC_MESSAGES/django.po | 643 +++++++++++++++++ ...ptions_alter_oauthuser_options_and_more.py | 86 +++ oauth/models.py | 32 +- oauth/views.py | 50 +- ...0002_alter_owntracklog_options_and_more.py | 22 + owntracks/models.py | 6 +- owntracks/views.py | 4 +- servermanager/admin.py | 4 +- ...002_alter_emailsendlog_options_and_more.py | 32 + servermanager/models.py | 8 +- servermanager/tests.py | 2 - templates/account/forget_password.html | 7 +- templates/account/result.html | 9 +- templates/blog/article_archives.html | 9 +- templates/blog/tags/article_info.html | 11 +- templates/blog/tags/article_meta_info.html | 27 +- templates/blog/tags/article_pagination.html | 9 +- templates/blog/tags/article_tag_list.html | 5 +- templates/blog/tags/sidebar.html | 34 +- templates/comments/tags/comment_item.html | 2 +- .../comments/tags/comment_item_tree.html | 2 +- templates/share_layout/base.html | 19 + 50 files changed, 2904 insertions(+), 323 deletions(-) create mode 100644 accounts/migrations/0002_alter_bloguser_options_remove_bloguser_created_time_and_more.py create mode 100644 blog/migrations/0005_alter_article_options_alter_category_options_and_more.py create mode 100644 comments/migrations/0003_alter_comment_options_remove_comment_created_time_and_more.py create mode 100644 locale/en/LC_MESSAGES/django.po create mode 100644 locale/zh_Hans/LC_MESSAGES/django.po create mode 100644 locale/zh_Hant/LC_MESSAGES/django.po create mode 100644 oauth/migrations/0002_alter_oauthconfig_options_alter_oauthuser_options_and_more.py create mode 100644 owntracks/migrations/0002_alter_owntracklog_options_and_more.py create mode 100644 servermanager/migrations/0002_alter_emailsendlog_options_and_more.py diff --git a/Dockerfile b/Dockerfile index 03afb9b51..e4df0d56d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,8 @@ FROM python:3 ENV PYTHONUNBUFFERED 1 WORKDIR /code/djangoblog/ -RUN apt-get install default-libmysqlclient-dev -y && \ +RUN apt-get update && \ + apt-get install default-libmysqlclient-dev gettext -y && \ ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime ADD requirements.txt requirements.txt RUN pip install --upgrade pip && \ diff --git a/accounts/admin.py b/accounts/admin.py index c3fbf3532..6f27f2355 100644 --- a/accounts/admin.py +++ b/accounts/admin.py @@ -10,8 +10,8 @@ class BlogUserCreationForm(forms.ModelForm): - password1 = forms.CharField(label='密码', widget=forms.PasswordInput) - password2 = forms.CharField(label='再次输入密码', widget=forms.PasswordInput) + password1 = forms.CharField(label=_('password'), widget=forms.PasswordInput) + password2 = forms.CharField(label=_('Enter password again'), widget=forms.PasswordInput) class Meta: model = BlogUser @@ -22,7 +22,7 @@ def clean_password2(self): password1 = self.cleaned_data.get("password1") password2 = self.cleaned_data.get("password2") if password1 and password2 and password1 != password2: - raise forms.ValidationError("两次密码不一致") + raise forms.ValidationError(_("passwords do not match")) return password2 def save(self, commit=True): diff --git a/accounts/forms.py b/accounts/forms.py index 70c492b16..fce4137e3 100644 --- a/accounts/forms.py +++ b/accounts/forms.py @@ -3,7 +3,7 @@ from django.contrib.auth.forms import AuthenticationForm, UserCreationForm from django.core.exceptions import ValidationError from django.forms import widgets - +from django.utils.translation import gettext_lazy as _ from . import utils from .models import BlogUser @@ -33,7 +33,7 @@ def __init__(self, *args, **kwargs): def clean_email(self): email = self.cleaned_data['email'] if get_user_model().objects.filter(email=email).exists(): - raise ValidationError("该邮箱已经存在.") + raise ValidationError(_("email already exists")) return email class Meta: @@ -43,11 +43,11 @@ class Meta: class ForgetPasswordForm(forms.Form): new_password1 = forms.CharField( - label="新密码", + label=_("New password"), widget=forms.PasswordInput( attrs={ "class": "form-control", - 'placeholder': "密码" + 'placeholder': _("New password") } ), ) @@ -57,7 +57,7 @@ class ForgetPasswordForm(forms.Form): widget=forms.PasswordInput( attrs={ "class": "form-control", - 'placeholder': "确认密码" + 'placeholder': _("Confirm password") } ), ) @@ -67,17 +67,17 @@ class ForgetPasswordForm(forms.Form): widget=forms.TextInput( attrs={ 'class': 'form-control', - 'placeholder': "邮箱" + 'placeholder': _("Email") } ), ) code = forms.CharField( - label='验证码', + label=_('Code'), widget=forms.TextInput( attrs={ 'class': 'form-control', - 'placeholder': "验证码" + 'placeholder': _("Code") } ), ) @@ -86,7 +86,7 @@ def clean_new_password2(self): password1 = self.data.get("new_password1") password2 = self.data.get("new_password2") if password1 and password2 and password1 != password2: - raise ValidationError("两次密码不一致") + raise ValidationError(_("passwords do not match")) password_validation.validate_password(password2) return password2 @@ -97,7 +97,7 @@ def clean_email(self): email=user_email ).exists(): # todo 这里的报错提示可以判断一个邮箱是不是注册过,如果不想暴露可以修改 - raise ValidationError("未找到邮箱对应的用户") + raise ValidationError(_("email does not exist")) return user_email def clean_code(self): @@ -113,5 +113,5 @@ def clean_code(self): class ForgetPasswordCodeForm(forms.Form): email = forms.EmailField( - label="邮箱号" + label=_('Email'), ) diff --git a/accounts/migrations/0002_alter_bloguser_options_remove_bloguser_created_time_and_more.py b/accounts/migrations/0002_alter_bloguser_options_remove_bloguser_created_time_and_more.py new file mode 100644 index 000000000..1a9f50956 --- /dev/null +++ b/accounts/migrations/0002_alter_bloguser_options_remove_bloguser_created_time_and_more.py @@ -0,0 +1,46 @@ +# Generated by Django 4.2.5 on 2023-09-06 13:13 + +from django.db import migrations, models +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('accounts', '0001_initial'), + ] + + operations = [ + migrations.AlterModelOptions( + name='bloguser', + options={'get_latest_by': 'id', 'ordering': ['-id'], 'verbose_name': 'user', 'verbose_name_plural': 'user'}, + ), + migrations.RemoveField( + model_name='bloguser', + name='created_time', + ), + migrations.RemoveField( + model_name='bloguser', + name='last_mod_time', + ), + migrations.AddField( + model_name='bloguser', + name='creation_time', + field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='creation time'), + ), + migrations.AddField( + model_name='bloguser', + name='last_modify_time', + field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='last modify time'), + ), + migrations.AlterField( + model_name='bloguser', + name='nickname', + field=models.CharField(blank=True, max_length=100, verbose_name='nick name'), + ), + migrations.AlterField( + model_name='bloguser', + name='source', + field=models.CharField(blank=True, max_length=100, verbose_name='create source'), + ), + ] diff --git a/accounts/models.py b/accounts/models.py index 9f7454cd3..3baddbb2f 100644 --- a/accounts/models.py +++ b/accounts/models.py @@ -2,17 +2,17 @@ from django.db import models from django.urls import reverse from django.utils.timezone import now - +from django.utils.translation import gettext_lazy as _ from djangoblog.utils import get_current_site # Create your models here. class BlogUser(AbstractUser): - nickname = models.CharField('昵称', max_length=100, blank=True) - created_time = models.DateTimeField('创建时间', default=now) - last_mod_time = models.DateTimeField('修改时间', default=now) - source = models.CharField("创建来源", max_length=100, blank=True) + nickname = models.CharField(_('nick name'), max_length=100, blank=True) + creation_time = models.DateTimeField(_('creation time'), default=now) + last_modify_time = models.DateTimeField(_('last modify time'), default=now) + source = models.CharField(_('create source'), max_length=100, blank=True) def get_absolute_url(self): return reverse( @@ -30,6 +30,6 @@ def get_full_url(self): class Meta: ordering = ['-id'] - verbose_name = "用户" + verbose_name = _('user') verbose_name_plural = verbose_name get_latest_by = 'id' diff --git a/accounts/tests.py b/accounts/tests.py index ae3ae6987..a3085637c 100644 --- a/accounts/tests.py +++ b/accounts/tests.py @@ -1,11 +1,11 @@ -from django.conf import settings from django.test import Client, RequestFactory, TestCase from django.urls import reverse from django.utils import timezone +from django.utils.translation import gettext_lazy as _ -from djangoblog.utils import * from accounts.models import BlogUser from blog.models import Article, Category +from djangoblog.utils import * from . import utils @@ -39,8 +39,8 @@ def test_validate_account(self): category = Category() category.name = "categoryaaa" - category.created_time = timezone.now() - category.last_mod_time = timezone.now() + category.creation_time = timezone.now() + category.last_modify_time = timezone.now() category.save() article = Article() @@ -86,8 +86,8 @@ def test_validate_register(self): delete_sidebar_cache() category = Category() category.name = "categoryaaa" - category.created_time = timezone.now() - category.last_mod_time = timezone.now() + category.creation_time = timezone.now() + category.last_modify_time = timezone.now() category.save() article = Article() @@ -191,7 +191,7 @@ def test_forget_password_email_not_user(self): response=resp, form="form", field="email", - errors="未找到邮箱对应的用户" + errors=_("email does not exist") ) def test_forget_password_email_code_error(self): @@ -213,5 +213,5 @@ def test_forget_password_email_code_error(self): response=resp, form="form", field="code", - errors="验证码错误" + errors=_('Verification code error') ) diff --git a/accounts/urls.py b/accounts/urls.py index e11dd7358..107a801d1 100644 --- a/accounts/urls.py +++ b/accounts/urls.py @@ -1,5 +1,5 @@ -from django.urls import include, re_path from django.urls import path +from django.urls import re_path from . import views from .forms import LoginForm @@ -7,22 +7,22 @@ app_name = "accounts" urlpatterns = [re_path(r'^login/$', - views.LoginView.as_view(success_url='/'), - name='login', - kwargs={'authentication_form': LoginForm}), + views.LoginView.as_view(success_url='/'), + name='login', + kwargs={'authentication_form': LoginForm}), re_path(r'^register/$', - views.RegisterView.as_view(success_url="/"), - name='register'), + views.RegisterView.as_view(success_url="/"), + name='register'), re_path(r'^logout/$', - views.LogoutView.as_view(), - name='logout'), + views.LogoutView.as_view(), + name='logout'), path(r'account/result.html', views.account_result, name='result'), re_path(r'^forget_password/$', - views.ForgetPasswordView.as_view(), - name='forget_password'), + views.ForgetPasswordView.as_view(), + name='forget_password'), re_path(r'^forget_password_code/$', - views.ForgetPasswordEmailCode.as_view(), - name='forget_password_code'), + views.ForgetPasswordEmailCode.as_view(), + name='forget_password_code'), ] diff --git a/accounts/utils.py b/accounts/utils.py index 66886678c..b3348eec8 100644 --- a/accounts/utils.py +++ b/accounts/utils.py @@ -2,20 +2,23 @@ from datetime import timedelta from django.core.cache import cache +from django.utils.translation import gettext_lazy as _ +from django.utils.translation import gettext from djangoblog.utils import send_email _code_ttl = timedelta(minutes=5) -def send_verify_email(to_mail: str, code: str, subject: str = "邮件验证码"): +def send_verify_email(to_mail: str, code: str, subject: str = _("Verify Email")): """发送重设密码验证码 Args: to_mail: 接受邮箱 subject: 邮件主题 code: 验证码 """ - html_content = f"您正在重设密码,验证码为:{code}, 5分钟内有效,请妥善保管" + html_content = _( + f"You are resetting the password, the verification code is:{code}, valid within 5 minutes, please keep it properly") send_email([to_mail], subject, html_content) @@ -32,7 +35,7 @@ def verify(email: str, code: str) -> typing.Optional[str]: """ cache_code = get_code(email) if cache_code != code: - return "验证码错误" + return gettext("Verification code error") def set_code(email: str, code: str): diff --git a/accounts/views.py b/accounts/views.py index 06b6fd772..ae67aec41 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -1,5 +1,5 @@ import logging - +from django.utils.translation import gettext_lazy as _ from django.conf import settings from django.contrib import auth from django.contrib.auth import REDIRECT_FIELD_NAME diff --git a/blog/admin.py b/blog/admin.py index 9a07b3d5b..5e1e03597 100644 --- a/blog/admin.py +++ b/blog/admin.py @@ -10,7 +10,7 @@ class ArticleListFilter(admin.SimpleListFilter): - title = _("作者") + title = _("author") parameter_name = 'author' def lookups(self, request, model_admin): @@ -50,10 +50,10 @@ def open_article_commentstatus(modeladmin, request, queryset): queryset.update(comment_status='o') -makr_article_publish.short_description = '发布选中文章' -draft_article.short_description = '选中文章设置为草稿' -close_article_commentstatus.short_description = '关闭文章评论' -open_article_commentstatus.short_description = '打开文章评论' +makr_article_publish.short_description = _('Publish selected articles') +draft_article.short_description = _('Draft selected articles') +close_article_commentstatus.short_description = _('Close article comments') +open_article_commentstatus.short_description = _('Open article comments') class ArticlelAdmin(admin.ModelAdmin): @@ -65,7 +65,7 @@ class ArticlelAdmin(admin.ModelAdmin): 'title', 'author', 'link_to_category', - 'created_time', + 'creation_time', 'views', 'status', 'type', @@ -73,7 +73,7 @@ class ArticlelAdmin(admin.ModelAdmin): list_display_links = ('id', 'title') list_filter = (ArticleListFilter, 'status', 'type', 'category', 'tags') filter_horizontal = ('tags',) - exclude = ('created_time', 'last_mod_time') + exclude = ('creation_time', 'last_modify_time') view_on_site = True actions = [ makr_article_publish, @@ -86,7 +86,7 @@ def link_to_category(self, obj): link = reverse('admin:%s_%s_change' % info, args=(obj.category.id,)) return format_html(u'%s' % (link, obj.category.name)) - link_to_category.short_description = '分类目录' + link_to_category.short_description = _('category') def get_form(self, request, obj=None, **kwargs): form = super(ArticlelAdmin, self).get_form(request, obj, **kwargs) @@ -108,21 +108,21 @@ def get_view_on_site_url(self, obj=None): class TagAdmin(admin.ModelAdmin): - exclude = ('slug', 'last_mod_time', 'created_time') + exclude = ('slug', 'last_mod_time', 'creation_time') class CategoryAdmin(admin.ModelAdmin): list_display = ('name', 'parent_category', 'index') - exclude = ('slug', 'last_mod_time', 'created_time') + exclude = ('slug', 'last_mod_time', 'creation_time') class LinksAdmin(admin.ModelAdmin): - exclude = ('last_mod_time', 'created_time') + exclude = ('last_mod_time', 'creation_time') class SideBarAdmin(admin.ModelAdmin): list_display = ('name', 'content', 'is_enable', 'sequence') - exclude = ('last_mod_time', 'created_time') + exclude = ('last_mod_time', 'creation_time') class BlogSettingsAdmin(admin.ModelAdmin): diff --git a/blog/migrations/0005_alter_article_options_alter_category_options_and_more.py b/blog/migrations/0005_alter_article_options_alter_category_options_and_more.py new file mode 100644 index 000000000..d08e85341 --- /dev/null +++ b/blog/migrations/0005_alter_article_options_alter_category_options_and_more.py @@ -0,0 +1,300 @@ +# Generated by Django 4.2.5 on 2023-09-06 13:13 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone +import mdeditor.fields + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('blog', '0004_rename_analyticscode_blogsettings_analytics_code_and_more'), + ] + + operations = [ + migrations.AlterModelOptions( + name='article', + options={'get_latest_by': 'id', 'ordering': ['-article_order', '-pub_time'], 'verbose_name': 'article', 'verbose_name_plural': 'article'}, + ), + migrations.AlterModelOptions( + name='category', + options={'ordering': ['-index'], 'verbose_name': 'category', 'verbose_name_plural': 'category'}, + ), + migrations.AlterModelOptions( + name='links', + options={'ordering': ['sequence'], 'verbose_name': 'link', 'verbose_name_plural': 'link'}, + ), + migrations.AlterModelOptions( + name='sidebar', + options={'ordering': ['sequence'], 'verbose_name': 'sidebar', 'verbose_name_plural': 'sidebar'}, + ), + migrations.AlterModelOptions( + name='tag', + options={'ordering': ['name'], 'verbose_name': 'tag', 'verbose_name_plural': 'tag'}, + ), + migrations.RemoveField( + model_name='article', + name='created_time', + ), + migrations.RemoveField( + model_name='article', + name='last_mod_time', + ), + migrations.RemoveField( + model_name='category', + name='created_time', + ), + migrations.RemoveField( + model_name='category', + name='last_mod_time', + ), + migrations.RemoveField( + model_name='links', + name='created_time', + ), + migrations.RemoveField( + model_name='sidebar', + name='created_time', + ), + migrations.RemoveField( + model_name='tag', + name='created_time', + ), + migrations.RemoveField( + model_name='tag', + name='last_mod_time', + ), + migrations.AddField( + model_name='article', + name='creation_time', + field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='creation time'), + ), + migrations.AddField( + model_name='article', + name='last_modify_time', + field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='modify time'), + ), + migrations.AddField( + model_name='category', + name='creation_time', + field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='creation time'), + ), + migrations.AddField( + model_name='category', + name='last_modify_time', + field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='modify time'), + ), + migrations.AddField( + model_name='links', + name='creation_time', + field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='creation time'), + ), + migrations.AddField( + model_name='sidebar', + name='creation_time', + field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='creation time'), + ), + migrations.AddField( + model_name='tag', + name='creation_time', + field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='creation time'), + ), + migrations.AddField( + model_name='tag', + name='last_modify_time', + field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='modify time'), + ), + migrations.AlterField( + model_name='article', + name='article_order', + field=models.IntegerField(default=0, verbose_name='order'), + ), + migrations.AlterField( + model_name='article', + name='author', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='author'), + ), + migrations.AlterField( + model_name='article', + name='body', + field=mdeditor.fields.MDTextField(verbose_name='body'), + ), + migrations.AlterField( + model_name='article', + name='category', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='blog.category', verbose_name='category'), + ), + migrations.AlterField( + model_name='article', + name='comment_status', + field=models.CharField(choices=[('o', 'Open'), ('c', 'Close')], default='o', max_length=1, verbose_name='comment status'), + ), + migrations.AlterField( + model_name='article', + name='pub_time', + field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='publish time'), + ), + migrations.AlterField( + model_name='article', + name='show_toc', + field=models.BooleanField(default=False, verbose_name='show toc'), + ), + migrations.AlterField( + model_name='article', + name='status', + field=models.CharField(choices=[('d', 'Draft'), ('p', 'Published')], default='p', max_length=1, verbose_name='status'), + ), + migrations.AlterField( + model_name='article', + name='tags', + field=models.ManyToManyField(blank=True, to='blog.tag', verbose_name='tag'), + ), + migrations.AlterField( + model_name='article', + name='title', + field=models.CharField(max_length=200, unique=True, verbose_name='title'), + ), + migrations.AlterField( + model_name='article', + name='type', + field=models.CharField(choices=[('a', 'Article'), ('p', 'Page')], default='a', max_length=1, verbose_name='type'), + ), + migrations.AlterField( + model_name='article', + name='views', + field=models.PositiveIntegerField(default=0, verbose_name='views'), + ), + migrations.AlterField( + model_name='blogsettings', + name='article_comment_count', + field=models.IntegerField(default=5, verbose_name='article comment count'), + ), + migrations.AlterField( + model_name='blogsettings', + name='article_sub_length', + field=models.IntegerField(default=300, verbose_name='article sub length'), + ), + migrations.AlterField( + model_name='blogsettings', + name='google_adsense_codes', + field=models.TextField(blank=True, default='', max_length=2000, null=True, verbose_name='adsense code'), + ), + migrations.AlterField( + model_name='blogsettings', + name='open_site_comment', + field=models.BooleanField(default=True, verbose_name='open site comment'), + ), + migrations.AlterField( + model_name='blogsettings', + name='show_google_adsense', + field=models.BooleanField(default=False, verbose_name='show adsense'), + ), + migrations.AlterField( + model_name='blogsettings', + name='sidebar_article_count', + field=models.IntegerField(default=10, verbose_name='sidebar article count'), + ), + migrations.AlterField( + model_name='blogsettings', + name='sidebar_comment_count', + field=models.IntegerField(default=5, verbose_name='sidebar comment count'), + ), + migrations.AlterField( + model_name='blogsettings', + name='site_description', + field=models.TextField(default='', max_length=1000, verbose_name='site description'), + ), + migrations.AlterField( + model_name='blogsettings', + name='site_keywords', + field=models.TextField(default='', max_length=1000, verbose_name='site keywords'), + ), + migrations.AlterField( + model_name='blogsettings', + name='site_name', + field=models.CharField(default='', max_length=200, verbose_name='site name'), + ), + migrations.AlterField( + model_name='blogsettings', + name='site_seo_description', + field=models.TextField(default='', max_length=1000, verbose_name='site seo description'), + ), + migrations.AlterField( + model_name='category', + name='index', + field=models.IntegerField(default=0, verbose_name='index'), + ), + migrations.AlterField( + model_name='category', + name='name', + field=models.CharField(max_length=30, unique=True, verbose_name='category name'), + ), + migrations.AlterField( + model_name='category', + name='parent_category', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='blog.category', verbose_name='parent category'), + ), + migrations.AlterField( + model_name='links', + name='is_enable', + field=models.BooleanField(default=True, verbose_name='is show'), + ), + migrations.AlterField( + model_name='links', + name='last_mod_time', + field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='modify time'), + ), + migrations.AlterField( + model_name='links', + name='link', + field=models.URLField(verbose_name='link'), + ), + migrations.AlterField( + model_name='links', + name='name', + field=models.CharField(max_length=30, unique=True, verbose_name='link name'), + ), + migrations.AlterField( + model_name='links', + name='sequence', + field=models.IntegerField(unique=True, verbose_name='order'), + ), + migrations.AlterField( + model_name='links', + name='show_type', + field=models.CharField(choices=[('i', 'index'), ('l', 'list'), ('p', 'post'), ('a', 'all'), ('s', 'slide')], default='i', max_length=1, verbose_name='show type'), + ), + migrations.AlterField( + model_name='sidebar', + name='content', + field=models.TextField(verbose_name='content'), + ), + migrations.AlterField( + model_name='sidebar', + name='is_enable', + field=models.BooleanField(default=True, verbose_name='is enable'), + ), + migrations.AlterField( + model_name='sidebar', + name='last_mod_time', + field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='modify time'), + ), + migrations.AlterField( + model_name='sidebar', + name='name', + field=models.CharField(max_length=100, verbose_name='title'), + ), + migrations.AlterField( + model_name='sidebar', + name='sequence', + field=models.IntegerField(unique=True, verbose_name='order'), + ), + migrations.AlterField( + model_name='tag', + name='name', + field=models.CharField(max_length=30, unique=True, verbose_name='tag name'), + ), + ] diff --git a/blog/models.py b/blog/models.py index 59e72c610..8432ca750 100644 --- a/blog/models.py +++ b/blog/models.py @@ -17,17 +17,17 @@ class LinkShowType(models.TextChoices): - I = ('i', '首页') - L = ('l', '列表页') - P = ('p', '文章页面') - A = ('a', '全站') - S = ('s', '友情链接页面') + I = ('i', _('index')) + L = ('l', _('list')) + P = ('p', _('post')) + A = ('a', _('all')) + S = ('s', _('slide')) class BaseModel(models.Model): id = models.AutoField(primary_key=True) - created_time = models.DateTimeField('创建时间', default=now) - last_mod_time = models.DateTimeField('修改时间', default=now) + creation_time = models.DateTimeField(_('creation time'), default=now) + last_modify_time = models.DateTimeField(_('modify time'), default=now) def save(self, *args, **kwargs): is_update_views = isinstance( @@ -60,49 +60,49 @@ def get_absolute_url(self): class Article(BaseModel): """文章""" STATUS_CHOICES = ( - ('d', '草稿'), - ('p', '发表'), + ('d', _('Draft')), + ('p', _('Published')), ) COMMENT_STATUS = ( - ('o', '打开'), - ('c', '关闭'), + ('o', _('Open')), + ('c', _('Close')), ) TYPE = ( - ('a', '文章'), - ('p', '页面'), + ('a', _('Article')), + ('p', _('Page')), ) - title = models.CharField('标题', max_length=200, unique=True) - body = MDTextField('正文') + title = models.CharField(_('title'), max_length=200, unique=True) + body = MDTextField(_('body')) pub_time = models.DateTimeField( - '发布时间', blank=False, null=False, default=now) + _('publish time'), blank=False, null=False, default=now) status = models.CharField( - '文章状态', + _('status'), max_length=1, choices=STATUS_CHOICES, default='p') comment_status = models.CharField( - '评论状态', + _('comment status'), max_length=1, choices=COMMENT_STATUS, default='o') - type = models.CharField('类型', max_length=1, choices=TYPE, default='a') - views = models.PositiveIntegerField('浏览量', default=0) + type = models.CharField(_('type'), max_length=1, choices=TYPE, default='a') + views = models.PositiveIntegerField(_('views'), default=0) author = models.ForeignKey( settings.AUTH_USER_MODEL, - verbose_name='作者', + verbose_name=_('author'), blank=False, null=False, on_delete=models.CASCADE) article_order = models.IntegerField( - '排序,数字越大越靠前', blank=False, null=False, default=0) - show_toc = models.BooleanField("是否显示toc目录", blank=False, null=False, default=False) + _('order'), blank=False, null=False, default=0) + show_toc = models.BooleanField(_('show toc'), blank=False, null=False, default=False) category = models.ForeignKey( 'Category', - verbose_name='分类', + verbose_name=_('category'), on_delete=models.CASCADE, blank=False, null=False) - tags = models.ManyToManyField('Tag', verbose_name='标签集合', blank=True) + tags = models.ManyToManyField('Tag', verbose_name=_('tag'), blank=True) def body_to_string(self): return self.body @@ -112,16 +112,16 @@ def __str__(self): class Meta: ordering = ['-article_order', '-pub_time'] - verbose_name = "文章" + verbose_name = _('article') verbose_name_plural = verbose_name get_latest_by = 'id' def get_absolute_url(self): return reverse('blog:detailbyid', kwargs={ 'article_id': self.id, - 'year': self.created_time.year, - 'month': self.created_time.month, - 'day': self.created_time.day + 'year': self.creation_time.year, + 'month': self.creation_time.month, + 'day': self.creation_time.day }) @cache_decorator(60 * 60 * 10) @@ -168,19 +168,19 @@ def prev_article(self): class Category(BaseModel): """文章分类""" - name = models.CharField('分类名', max_length=30, unique=True) + name = models.CharField(_('category name'), max_length=30, unique=True) parent_category = models.ForeignKey( 'self', - verbose_name="父级分类", + verbose_name=_('parent category'), blank=True, null=True, on_delete=models.CASCADE) slug = models.SlugField(default='no-slug', max_length=60, blank=True) - index = models.IntegerField(default=0, verbose_name="权重排序-越大越靠前") + index = models.IntegerField(default=0, verbose_name=_('index')) class Meta: ordering = ['-index'] - verbose_name = "分类" + verbose_name = _('category') verbose_name_plural = verbose_name def get_absolute_url(self): @@ -231,7 +231,7 @@ def parse(category): class Tag(BaseModel): """文章标签""" - name = models.CharField('标签名', max_length=30, unique=True) + name = models.CharField(_('tag name'), max_length=30, unique=True) slug = models.SlugField(default='no-slug', max_length=60, blank=True) def __str__(self): @@ -246,29 +246,29 @@ def get_article_count(self): class Meta: ordering = ['name'] - verbose_name = "标签" + verbose_name = _('tag') verbose_name_plural = verbose_name class Links(models.Model): """友情链接""" - name = models.CharField('链接名称', max_length=30, unique=True) - link = models.URLField('链接地址') - sequence = models.IntegerField('排序', unique=True) + name = models.CharField(_('link name'), max_length=30, unique=True) + link = models.URLField(_('link')) + sequence = models.IntegerField(_('order'), unique=True) is_enable = models.BooleanField( - '是否显示', default=True, blank=False, null=False) + _('is show'), default=True, blank=False, null=False) show_type = models.CharField( - '显示类型', + _('show type'), max_length=1, choices=LinkShowType.choices, default=LinkShowType.I) - created_time = models.DateTimeField('创建时间', default=now) - last_mod_time = models.DateTimeField('修改时间', default=now) + creation_time = models.DateTimeField(_('creation time'), default=now) + last_mod_time = models.DateTimeField(_('modify time'), default=now) class Meta: ordering = ['sequence'] - verbose_name = '友情链接' + verbose_name = _('link') verbose_name_plural = verbose_name def __str__(self): @@ -277,16 +277,16 @@ def __str__(self): class SideBar(models.Model): """侧边栏,可以展示一些html内容""" - name = models.CharField('标题', max_length=100) - content = models.TextField("内容") - sequence = models.IntegerField('排序', unique=True) - is_enable = models.BooleanField('是否启用', default=True) - created_time = models.DateTimeField('创建时间', default=now) - last_mod_time = models.DateTimeField('修改时间', default=now) + name = models.CharField(_('title'), max_length=100) + content = models.TextField(_('content')) + sequence = models.IntegerField(_('order'), unique=True) + is_enable = models.BooleanField(_('is enable'), default=True) + creation_time = models.DateTimeField(_('creation time'), default=now) + last_mod_time = models.DateTimeField(_('modify time'), default=now) class Meta: ordering = ['sequence'] - verbose_name = '侧边栏' + verbose_name = _('sidebar') verbose_name_plural = verbose_name def __str__(self): @@ -296,33 +296,33 @@ def __str__(self): class BlogSettings(models.Model): """blog的配置""" site_name = models.CharField( - "网站名称", + _('site name'), max_length=200, null=False, blank=False, default='') site_description = models.TextField( - "网站描述", + _('site description'), max_length=1000, null=False, blank=False, default='') site_seo_description = models.TextField( - "网站SEO描述", max_length=1000, null=False, blank=False, default='') + _('site seo description'), max_length=1000, null=False, blank=False, default='') site_keywords = models.TextField( - "网站关键字", + _('site keywords'), max_length=1000, null=False, blank=False, default='') - article_sub_length = models.IntegerField("文章摘要长度", default=300) - sidebar_article_count = models.IntegerField("侧边栏文章数目", default=10) - sidebar_comment_count = models.IntegerField("侧边栏评论数目", default=5) - article_comment_count = models.IntegerField("文章页面默认显示评论数目", default=5) - show_google_adsense = models.BooleanField('是否显示谷歌广告', default=False) + article_sub_length = models.IntegerField(_('article sub length'), default=300) + sidebar_article_count = models.IntegerField(_('sidebar article count'), default=10) + sidebar_comment_count = models.IntegerField(_('sidebar comment count'), default=5) + article_comment_count = models.IntegerField(_('article comment count'), default=5) + show_google_adsense = models.BooleanField(_('show adsense'), default=False) google_adsense_codes = models.TextField( - '广告内容', max_length=2000, null=True, blank=True, default='') - open_site_comment = models.BooleanField('是否打开网站评论功能', default=True) + _('adsense code'), max_length=2000, null=True, blank=True, default='') + open_site_comment = models.BooleanField(_('open site comment'), default=True) global_header = models.TextField("公共头部", null=True, blank=True, default='') global_footer = models.TextField("公共尾部", null=True, blank=True, default='') beian_code = models.CharField( diff --git a/blog/static/blog/js/blog.js b/blog/static/blog/js/blog.js index c8f8822d5..c3d04c63f 100644 --- a/blog/static/blog/js/blog.js +++ b/blog/static/blog/js/blog.js @@ -42,7 +42,7 @@ function debounce(func, wait) { clearTimeout(timeout); timeout = setTimeout(func, wait); }; -}; +} function slideTopSet() { var top = $(document).scrollTop(); diff --git a/blog/static/blog/js/nprogress.js b/blog/static/blog/js/nprogress.js index beb9d2cb9..d29c2aac7 100644 --- a/blog/static/blog/js/nprogress.js +++ b/blog/static/blog/js/nprogress.js @@ -161,7 +161,7 @@ if (!n) { return NProgress.start(); } else if(n > 1) { - return; + } else { if (typeof amount !== 'number') { if (n >= 0 && n < 0.2) { amount = 0.1; } diff --git a/blog/templatetags/blog_tags.py b/blog/templatetags/blog_tags.py index db9c3c9ed..110b22b9e 100644 --- a/blog/templatetags/blog_tags.py +++ b/blog/templatetags/blog_tags.py @@ -146,7 +146,7 @@ def load_sidebar(user, linktype): is_enable=True).order_by('sequence') most_read_articles = Article.objects.filter(status='p').order_by( '-views')[:blogsetting.sidebar_article_count] - dates = Article.objects.datetimes('created_time', 'month', order='DESC') + dates = Article.objects.datetimes('creation_time', 'month', order='DESC') links = Links.objects.filter(is_enable=True).filter( Q(show_type=str(linktype)) | Q(show_type=LinkShowType.A)) commment_list = Comment.objects.filter(is_enable=True).order_by( diff --git a/blog/tests.py b/blog/tests.py index 7be7b473b..f6bfac058 100644 --- a/blog/tests.py +++ b/blog/tests.py @@ -46,7 +46,7 @@ def test_validate_article(self): category = Category() category.name = "category" - category.created_time = timezone.now() + category.creation_time = timezone.now() category.last_mod_time = timezone.now() category.save() @@ -105,19 +105,19 @@ def test_validate_article(self): response = self.client.get(reverse('blog:archives')) self.assertEqual(response.status_code, 200) - p = Paginator(Article.objects.all(), 2) - self.__check_pagination__(p, '', '') + p = Paginator(Article.objects.all(), settings.PAGINATE_BY) + self.check_pagination(p, '', '') - p = Paginator(Article.objects.filter(tags=tag), 2) - self.__check_pagination__(p, '分类标签归档', tag.slug) + p = Paginator(Article.objects.filter(tags=tag), settings.PAGINATE_BY) + self.check_pagination(p, '分类标签归档', tag.slug) p = Paginator( Article.objects.filter( - author__username='liangliangyy'), 2) - self.__check_pagination__(p, '作者文章归档', 'liangliangyy') + author__username='liangliangyy'), settings.PAGINATE_BY) + self.check_pagination(p, '作者文章归档', 'liangliangyy') - p = Paginator(Article.objects.filter(category=category), 2) - self.__check_pagination__(p, '分类目录归档', category.slug) + p = Paginator(Article.objects.filter(category=category), settings.PAGINATE_BY) + self.check_pagination(p, '分类目录归档', category.slug) f = BlogSearchForm() f.search() @@ -148,20 +148,16 @@ def test_validate_article(self): self.client.get('/admin/admin/logentry/') self.client.get('/admin/admin/logentry/1/change/') - def __check_pagination__(self, p, type, value): - s = load_pagination_info(p.page(1), type, value) - self.assertIsNotNone(s) - response = self.client.get(s['previous_url']) - self.assertEqual(response.status_code, 200) - response = self.client.get(s['next_url']) - self.assertEqual(response.status_code, 200) - - s = load_pagination_info(p.page(2), type, value) - self.assertIsNotNone(s) - response = self.client.get(s['previous_url']) - self.assertEqual(response.status_code, 200) - response = self.client.get(s['next_url']) - self.assertEqual(response.status_code, 200) + def check_pagination(self, p, type, value): + for page in range(1, p.num_pages + 1): + s = load_pagination_info(p.page(page), type, value) + self.assertIsNotNone(s) + if s['previous_url']: + response = self.client.get(s['previous_url']) + self.assertEqual(response.status_code, 200) + if s['next_url']: + response = self.client.get(s['next_url']) + self.assertEqual(response.status_code, 200) def test_image(self): import requests diff --git a/blog/views.py b/blog/views.py index 18bd0800a..1128d2c89 100644 --- a/blog/views.py +++ b/blog/views.py @@ -9,6 +9,7 @@ from django.shortcuts import render from django.templatetags.static import static from django.utils import timezone +from django.utils.translation import gettext_lazy as _ from django.views.decorators.csrf import csrf_exempt from django.views.generic.detail import DetailView from django.views.generic.list import ListView @@ -93,6 +94,11 @@ class IndexView(ArticleListView): # 友情链接类型 link_type = LinkShowType.I + def dispatch(self, request, *args, **kwargs): + from django.utils.translation import get_language + print(get_language()) + return super(IndexView, self).dispatch(request, *args, **kwargs) + def get_queryset_data(self): article_list = Article.objects.filter(type='a', status='p') return article_list @@ -344,7 +350,7 @@ def page_not_found_view( url = request.get_full_path() return render(request, template_name, - {'message': '哎呀,您访问的地址 ' + url + ' 是一个未知的地方。请点击首页看看别的?', + {'message': _('Sorry, the page you requested is not found, please click the home page to see other?'), 'statuscode': '404'}, status=404) @@ -352,7 +358,7 @@ def page_not_found_view( def server_error_view(request, template_name='blog/error_page.html'): return render(request, template_name, - {'message': '哎呀,出错了,我已经收集到了错误信息,之后会抓紧抢修,请点击首页看看别的?', + {'message': _('Sorry, the server is busy, please click the home page to see other?'), 'statuscode': '500'}, status=500) @@ -365,4 +371,5 @@ def permission_denied_view( logger.error(exception) return render( request, template_name, { - 'message': '哎呀,您没有权限访问此页面,请点击首页看看别的?', 'statuscode': '403'}, status=403) + 'message': _('Sorry, you do not have permission to access this page?'), + 'statuscode': '403'}, status=403) diff --git a/comments/admin.py b/comments/admin.py index 9252174d9..5622781f1 100644 --- a/comments/admin.py +++ b/comments/admin.py @@ -1,7 +1,7 @@ from django.contrib import admin -# Register your models here. from django.urls import reverse from django.utils.html import format_html +from django.utils.translation import gettext_lazy as _ def disable_commentstatus(modeladmin, request, queryset): @@ -12,8 +12,8 @@ def enable_commentstatus(modeladmin, request, queryset): queryset.update(is_enable=True) -disable_commentstatus.short_description = '禁用评论' -enable_commentstatus.short_description = '启用评论' +disable_commentstatus.short_description = _('Disable comments') +enable_commentstatus.short_description = _('Enable comments') class CommentAdmin(admin.ModelAdmin): @@ -24,10 +24,10 @@ class CommentAdmin(admin.ModelAdmin): 'link_to_userinfo', 'link_to_article', 'is_enable', - 'created_time') + 'creation_time') list_display_links = ('id', 'body', 'is_enable') list_filter = ('is_enable', 'author', 'article',) - exclude = ('created_time', 'last_mod_time') + exclude = ('creation_time', 'last_modify_time') actions = [disable_commentstatus, enable_commentstatus] def link_to_userinfo(self, obj): @@ -43,5 +43,5 @@ def link_to_article(self, obj): return format_html( u'%s' % (link, obj.article.title)) - link_to_userinfo.short_description = '用户' - link_to_article.short_description = '文章' + link_to_userinfo.short_description = _('User') + link_to_article.short_description = _('Article') diff --git a/comments/migrations/0003_alter_comment_options_remove_comment_created_time_and_more.py b/comments/migrations/0003_alter_comment_options_remove_comment_created_time_and_more.py new file mode 100644 index 000000000..a1ca9708a --- /dev/null +++ b/comments/migrations/0003_alter_comment_options_remove_comment_created_time_and_more.py @@ -0,0 +1,60 @@ +# Generated by Django 4.2.5 on 2023-09-06 13:13 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('blog', '0005_alter_article_options_alter_category_options_and_more'), + ('comments', '0002_alter_comment_is_enable'), + ] + + operations = [ + migrations.AlterModelOptions( + name='comment', + options={'get_latest_by': 'id', 'ordering': ['-id'], 'verbose_name': 'comment', 'verbose_name_plural': 'comment'}, + ), + migrations.RemoveField( + model_name='comment', + name='created_time', + ), + migrations.RemoveField( + model_name='comment', + name='last_mod_time', + ), + migrations.AddField( + model_name='comment', + name='creation_time', + field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='creation time'), + ), + migrations.AddField( + model_name='comment', + name='last_modify_time', + field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='last modify time'), + ), + migrations.AlterField( + model_name='comment', + name='article', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='blog.article', verbose_name='article'), + ), + migrations.AlterField( + model_name='comment', + name='author', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='author'), + ), + migrations.AlterField( + model_name='comment', + name='is_enable', + field=models.BooleanField(default=False, verbose_name='enable'), + ), + migrations.AlterField( + model_name='comment', + name='parent_comment', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='comments.comment', verbose_name='parent comment'), + ), + ] diff --git a/comments/models.py b/comments/models.py index 27c67eff2..7c3bbc8da 100644 --- a/comments/models.py +++ b/comments/models.py @@ -1,6 +1,7 @@ from django.conf import settings from django.db import models from django.utils.timezone import now +from django.utils.translation import gettext_lazy as _ from blog.models import Article @@ -9,28 +10,28 @@ class Comment(models.Model): body = models.TextField('正文', max_length=300) - created_time = models.DateTimeField('创建时间', default=now) - last_mod_time = models.DateTimeField('修改时间', default=now) + creation_time = models.DateTimeField(_('creation time'), default=now) + last_modify_time = models.DateTimeField(_('last modify time'), default=now) author = models.ForeignKey( settings.AUTH_USER_MODEL, - verbose_name='作者', + verbose_name=_('author'), on_delete=models.CASCADE) article = models.ForeignKey( Article, - verbose_name='文章', + verbose_name=_('article'), on_delete=models.CASCADE) parent_comment = models.ForeignKey( 'self', - verbose_name="上级评论", + verbose_name=_('parent comment'), blank=True, null=True, on_delete=models.CASCADE) - is_enable = models.BooleanField( - '是否显示', default=False, blank=False, null=False) + is_enable = models.BooleanField(_('enable'), + default=False, blank=False, null=False) class Meta: ordering = ['-id'] - verbose_name = "评论" + verbose_name = _('comment') verbose_name_plural = verbose_name get_latest_by = 'id' diff --git a/comments/tests.py b/comments/tests.py index d503d0ad6..2a7f55f1f 100644 --- a/comments/tests.py +++ b/comments/tests.py @@ -1,6 +1,5 @@ -from django.test import Client, RequestFactory, TestCase +from django.test import Client, RequestFactory, TransactionTestCase from django.urls import reverse -from django.utils import timezone from accounts.models import BlogUser from blog.models import Category, Article @@ -11,7 +10,7 @@ # Create your tests here. -class CommentsTest(TestCase): +class CommentsTest(TransactionTestCase): def setUp(self): self.client = Client() self.factory = RequestFactory() @@ -20,6 +19,11 @@ def setUp(self): value.comment_need_review = True value.save() + self.user = BlogUser.objects.create_superuser( + email="liangliangyy1@gmail.com", + username="liangliangyy1", + password="liangliangyy1") + def update_article_comment_status(self, article): comments = article.comment_set.all() for comment in comments: @@ -27,23 +31,16 @@ def update_article_comment_status(self, article): comment.save() def test_validate_comment(self): - user = BlogUser.objects.create_superuser( - email="liangliangyy1@gmail.com", - username="liangliangyy1", - password="liangliangyy1") - self.client.login(username='liangliangyy1', password='liangliangyy1') category = Category() category.name = "categoryccc" - category.created_time = timezone.now() - category.last_mod_time = timezone.now() category.save() article = Article() article.title = "nicetitleccc" article.body = "nicecontentccc" - article.author = user + article.author = self.user article.category = category article.type = 'a' article.status = 'p' diff --git a/comments/utils.py b/comments/utils.py index 0380f0823..1a12ddf97 100644 --- a/comments/utils.py +++ b/comments/utils.py @@ -1,5 +1,7 @@ import logging +from django.utils.translation import gettext_lazy as _ + from djangoblog.utils import get_current_site from djangoblog.utils import send_email @@ -8,29 +10,28 @@ def send_comment_email(comment): site = get_current_site().domain - subject = '感谢您发表的评论' - article_url = "https://{site}{path}".format( - site=site, path=comment.article.get_absolute_url()) - html_content = """ -

非常感谢您在本站发表评论

- 您可以访问 - %s - 来查看您的评论, - 再次感谢您! -
- 如果上面链接无法打开,请将此链接复制至浏览器。 - %s - """ % (article_url, comment.article.title, article_url) + subject = _('Thanks for your comment') + article_url = f"https://{site}{comment.article.get_absolute_url()}" + html_content = _(f""" +

Thank you very much for your comments on this site

+ You can visit + {comment.article.title} + to review your comments, + Thank you again! +
+ If the link above cannot be opened, please copy this link to your browser. + {article_url} + """) tomail = comment.author.email send_email([tomail], subject, html_content) try: if comment.parent_comment: - html_content = """ - 您在 %s 的评论
%s
收到回复啦.快去看看吧 -
- 如果上面链接无法打开,请将此链接复制至浏览器。 - %s - """ % (article_url, comment.article.title, comment.parent_comment.body, article_url) + html_content = _(f""" + Your comment on {comment.article.title}
{comment.parent_comment.body}
has received a reply. go check it out +
+ If the link above cannot be opened, please copy this link to your browser. + {article_url} + """) tomail = comment.parent_comment.author.email send_email([tomail], subject, html_content) except Exception as e: diff --git a/comments/views.py b/comments/views.py index 8ad0fe5d7..ad9b2b94c 100644 --- a/comments/views.py +++ b/comments/views.py @@ -6,6 +6,7 @@ from django.views.decorators.csrf import csrf_protect from django.views.generic.edit import FormView +from accounts.models import BlogUser from blog.models import Article from .forms import CommentForm from .models import Comment @@ -37,7 +38,7 @@ def form_invalid(self, form): def form_valid(self, form): """提交的数据验证合法后的逻辑""" user = self.request.user - + author = BlogUser.objects.get(pk=user.pk) article_id = self.kwargs['article_id'] article = get_object_or_404(Article, pk=article_id) @@ -49,7 +50,7 @@ def form_valid(self, form): settings = get_blog_setting() if not settings.comment_need_review: comment.is_enable = True - comment.author = user + comment.author = author if form.cleaned_data['parent_comment_id']: parent_comment = Comment.objects.get( diff --git a/djangoblog/settings.py b/djangoblog/settings.py index 5c519757c..be7104003 100644 --- a/djangoblog/settings.py +++ b/djangoblog/settings.py @@ -12,6 +12,8 @@ import os import sys +from django.utils.translation import gettext_lazy as _ + def env_to_bool(env, default): str_val = os.environ.get(env) @@ -62,8 +64,10 @@ def env_to_bool(env, default): ] MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.locale.LocaleMiddleware', 'django.middleware.gzip.GZipMiddleware', # 'django.middleware.cache.UpdateCacheMiddleware', 'django.middleware.common.CommonMiddleware', @@ -132,8 +136,14 @@ def env_to_bool(env, default): }, ] -# Internationalization -# https://docs.djangoproject.com/en/1.10/topics/i18n/ +LANGUAGES = ( + ('en', _('English')), + ('zh-hans', _('Simplified Chinese')), + ('zh-hant', _('Traditional Chinese')), +) +LOCALE_PATHS = ( + os.path.join(BASE_DIR, 'locale'), +) LANGUAGE_CODE = 'zh-hans' @@ -182,13 +192,13 @@ def env_to_bool(env, default): # http cache timeout CACHE_CONTROL_MAX_AGE = 2592000 # cache setting -CACHES = { - 'default': { - 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', - 'TIMEOUT': 10800, - 'LOCATION': 'unique-snowflake', - } -} +# CACHES = { +# 'default': { +# 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', +# 'TIMEOUT': 10800, +# 'LOCATION': 'unique-snowflake', +# } +# } # 使用redis作为缓存 if os.environ.get("DJANGO_REDIS_URL"): CACHES = { diff --git a/djangoblog/sitemap.py b/djangoblog/sitemap.py index 151492e5d..8b7d44608 100644 --- a/djangoblog/sitemap.py +++ b/djangoblog/sitemap.py @@ -23,7 +23,7 @@ def items(self): return Article.objects.filter(status='p') def lastmod(self, obj): - return obj.last_mod_time + return obj.last_modify_time class CategorySiteMap(Sitemap): @@ -34,7 +34,7 @@ def items(self): return Category.objects.all() def lastmod(self, obj): - return obj.last_mod_time + return obj.last_modify_time class TagSiteMap(Sitemap): @@ -45,7 +45,7 @@ def items(self): return Tag.objects.all() def lastmod(self, obj): - return obj.last_mod_time + return obj.last_modify_time class UserSiteMap(Sitemap): diff --git a/djangoblog/urls.py b/djangoblog/urls.py index a834684bb..fc4a6ce9c 100644 --- a/djangoblog/urls.py +++ b/djangoblog/urls.py @@ -14,9 +14,10 @@ 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) """ from django.conf import settings +from django.conf.urls.i18n import i18n_patterns from django.conf.urls.static import static from django.contrib.sitemaps.views import sitemap -from django.urls import include +from django.urls import path, include from django.urls import re_path from haystack.views import search_view_factory @@ -38,22 +39,26 @@ handler404 = 'blog.views.page_not_found_view' handler500 = 'blog.views.server_error_view' handle403 = 'blog.views.permission_denied_view' + urlpatterns = [ - re_path(r'^admin/', admin_site.urls), - re_path(r'', include('blog.urls', namespace='blog')), - re_path(r'mdeditor/', include('mdeditor.urls')), - re_path(r'', include('comments.urls', namespace='comment')), - re_path(r'', include('accounts.urls', namespace='account')), - re_path(r'', include('oauth.urls', namespace='oauth')), - re_path(r'^sitemap\.xml$', sitemap, {'sitemaps': sitemaps}, - name='django.contrib.sitemaps.views.sitemap'), - re_path(r'^feed/$', DjangoBlogFeed()), - re_path(r'^rss/$', DjangoBlogFeed()), - re_path('^search', search_view_factory(view_class=EsSearchView, form_class=ElasticSearchModelSearchForm), - name='search'), - re_path(r'', include('servermanager.urls', namespace='servermanager')), - re_path(r'', include('owntracks.urls', namespace='owntracks')) - ] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) + path('i18n/', include('django.conf.urls.i18n')), +] +urlpatterns += i18n_patterns( + re_path(r'^admin/', admin_site.urls), + re_path(r'', include('blog.urls', namespace='blog')), + re_path(r'mdeditor/', include('mdeditor.urls')), + re_path(r'', include('comments.urls', namespace='comment')), + re_path(r'', include('accounts.urls', namespace='account')), + re_path(r'', include('oauth.urls', namespace='oauth')), + re_path(r'^sitemap\.xml$', sitemap, {'sitemaps': sitemaps}, + name='django.contrib.sitemaps.views.sitemap'), + re_path(r'^feed/$', DjangoBlogFeed()), + re_path(r'^rss/$', DjangoBlogFeed()), + re_path('^search', search_view_factory(view_class=EsSearchView, form_class=ElasticSearchModelSearchForm), + name='search'), + re_path(r'', include('servermanager.urls', namespace='servermanager')), + re_path(r'', include('owntracks.urls', namespace='owntracks')) + , prefix_default_language=True) + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) if settings.DEBUG: urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) diff --git a/locale/en/LC_MESSAGES/django.po b/locale/en/LC_MESSAGES/django.po new file mode 100644 index 000000000..fb302b8b5 --- /dev/null +++ b/locale/en/LC_MESSAGES/django.po @@ -0,0 +1,667 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-09-07 23:54+0800\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: .\accounts\admin.py:13 +msgid "password" +msgstr "password" + +#: .\accounts\admin.py:14 +msgid "Enter password again" +msgstr "Enter password again" + +#: .\accounts\admin.py:25 .\accounts\forms.py:89 +msgid "passwords do not match" +msgstr "passwords do not match" + +#: .\accounts\admin.py:40 +msgid "Password" +msgstr "Password" + +#: .\accounts\admin.py:42 +msgid "" +"Raw passwords are not stored, so there is no way to see this user's " +"password, but you can change the password using this form." +msgstr "" +"Raw passwords are not stored, so there is no way to see this user's " +"password, but you can change the password using this form." + +#: .\accounts\forms.py:36 +msgid "email already exists" +msgstr "email already exists" + +#: .\accounts\forms.py:46 .\accounts\forms.py:50 +#, fuzzy +#| msgid "forget the password" +msgid "New password" +msgstr "New password" + +#: .\accounts\forms.py:60 +#, fuzzy +#| msgid "forget the password" +msgid "Confirm password" +msgstr "Confirm the password" + +#: .\accounts\forms.py:70 .\accounts\forms.py:116 +msgid "Email" +msgstr "Email" + +#: .\accounts\forms.py:76 .\accounts\forms.py:80 +msgid "Code" +msgstr "Code" + +#: .\accounts\forms.py:100 .\accounts\tests.py:194 +msgid "email does not exist" +msgstr "email does not exist" + +#: .\accounts\models.py:12 +msgid "nick name" +msgstr "nick name" + +#: .\accounts\models.py:13 .\blog\models.py:29 .\blog\models.py:266 +#: .\blog\models.py:284 .\comments\models.py:13 .\oauth\models.py:23 +#: .\oauth\models.py:53 +msgid "creation time" +msgstr "creation time" + +#: .\accounts\models.py:14 .\comments\models.py:14 .\oauth\models.py:24 +#: .\oauth\models.py:54 +msgid "last modify time" +msgstr "last modify time" + +#: .\accounts\models.py:15 +msgid "create source" +msgstr "create source" + +#: .\accounts\models.py:33 .\djangoblog\logentryadmin.py:113 +msgid "user" +msgstr "user" + +#: .\accounts\tests.py:216 .\accounts\utils.py:38 +#, fuzzy +#| msgid "get verification code" +msgid "Verification code error" +msgstr "get verification code" + +#: .\accounts\utils.py:13 +msgid "Verify Email" +msgstr "Verify Email" + +#: .\accounts\utils.py:21 +#, python-brace-format +msgid "" +"You are resetting the password, the verification code is:{code}, valid " +"within 5 minutes, please keep it properly" +msgstr "" +"You are resetting the password, the verification code is:{code}, valid " +"within 5 minutes, please keep it properly" + +#: .\blog\admin.py:13 .\blog\models.py:92 .\comments\models.py:17 +#: .\oauth\models.py:12 .\templates\blog\tags\article_meta_info.html:33 +msgid "author" +msgstr "author" + +#: .\blog\admin.py:53 +msgid "Publish selected articles" +msgstr "Publish selected articles" + +#: .\blog\admin.py:54 +msgid "Draft selected articles" +msgstr "Draft selected articles" + +#: .\blog\admin.py:55 +msgid "Close article comments" +msgstr "Close article comments" + +#: .\blog\admin.py:56 +msgid "Open article comments" +msgstr "Open article comments" + +#: .\blog\admin.py:89 .\blog\models.py:101 .\blog\models.py:183 +#: .\templates\blog\tags\article_meta_info.html:17 +#: .\templates\blog\tags\sidebar.html:40 +msgid "category" +msgstr "category" + +#: .\blog\models.py:20 .\blog\models.py:179 +msgid "index" +msgstr "index" + +#: .\blog\models.py:21 +msgid "list" +msgstr "list" + +#: .\blog\models.py:22 +msgid "post" +msgstr "post" + +#: .\blog\models.py:23 +msgid "all" +msgstr "all" + +#: .\blog\models.py:24 +msgid "slide" +msgstr "slide" + +#: .\blog\models.py:30 .\blog\models.py:267 .\blog\models.py:285 +msgid "modify time" +msgstr "modify time" + +#: .\blog\models.py:63 +msgid "Draft" +msgstr "Draft" + +#: .\blog\models.py:64 +msgid "Published" +msgstr "Published" + +#: .\blog\models.py:67 +msgid "Open" +msgstr "Open" + +#: .\blog\models.py:68 +msgid "Close" +msgstr "Close" + +#: .\blog\models.py:71 .\comments\admin.py:47 +msgid "Article" +msgstr "Article" + +#: .\blog\models.py:72 +msgid "Page" +msgstr "Page" + +#: .\blog\models.py:74 .\blog\models.py:280 +msgid "title" +msgstr "title" + +#: .\blog\models.py:75 +msgid "body" +msgstr "body" + +#: .\blog\models.py:77 +msgid "publish time" +msgstr "publish time" + +#: .\blog\models.py:79 +msgid "status" +msgstr "status" + +#: .\blog\models.py:84 +msgid "comment status" +msgstr "comment status" + +#: .\blog\models.py:88 .\oauth\models.py:43 +msgid "type" +msgstr "type" + +#: .\blog\models.py:89 +msgid "views" +msgstr "views" + +#: .\blog\models.py:97 .\blog\models.py:258 .\blog\models.py:282 +msgid "order" +msgstr "order" + +#: .\blog\models.py:98 +msgid "show toc" +msgstr "show toc" + +#: .\blog\models.py:105 .\blog\models.py:249 +#: .\templates\blog\tags\article_meta_info.html:22 +msgid "tag" +msgstr "tag" + +#: .\blog\models.py:115 .\comments\models.py:21 +msgid "article" +msgstr "article" + +#: .\blog\models.py:171 +msgid "category name" +msgstr "category name" + +#: .\blog\models.py:174 +msgid "parent category" +msgstr "parent category" + +#: .\blog\models.py:234 +msgid "tag name" +msgstr "tag name" + +#: .\blog\models.py:256 +msgid "link name" +msgstr "link name" + +#: .\blog\models.py:257 .\blog\models.py:271 +msgid "link" +msgstr "link" + +#: .\blog\models.py:260 +msgid "is show" +msgstr "is show" + +#: .\blog\models.py:262 +msgid "show type" +msgstr "show type" + +#: .\blog\models.py:281 +msgid "content" +msgstr "content" + +#: .\blog\models.py:283 .\oauth\models.py:52 +msgid "is enable" +msgstr "is enable" + +#: .\blog\models.py:289 +msgid "sidebar" +msgstr "sidebar" + +#: .\blog\models.py:299 +msgid "site name" +msgstr "site name" + +#: .\blog\models.py:305 +msgid "site description" +msgstr "" + +#: .\blog\models.py:311 +msgid "site seo description" +msgstr "" + +#: .\blog\models.py:313 +msgid "site keywords" +msgstr "" + +#: .\blog\models.py:318 +msgid "article sub length" +msgstr "" + +#: .\blog\models.py:319 +msgid "sidebar article count" +msgstr "" + +#: .\blog\models.py:320 +msgid "sidebar comment count" +msgstr "" + +#: .\blog\models.py:321 +msgid "article comment count" +msgstr "" + +#: .\blog\models.py:322 +msgid "show adsense" +msgstr "" + +#: .\blog\models.py:324 +msgid "adsense code" +msgstr "" + +#: .\blog\models.py:325 +msgid "open site comment" +msgstr "" + +#: .\blog\models.py:360 +msgid "只能有一个配置" +msgstr "" + +#: .\blog\views.py:349 +msgid "" +"Sorry, the page you requested is not found, please click the home page to " +"see other?" +msgstr "" + +#: .\blog\views.py:357 +msgid "Sorry, the server is busy, please click the home page to see other?" +msgstr "" + +#: .\blog\views.py:370 +msgid "Sorry, you do not have permission to access this page?" +msgstr "" + +#: .\comments\admin.py:15 +msgid "Disable comments" +msgstr "" + +#: .\comments\admin.py:16 +msgid "Enable comments" +msgstr "" + +#: .\comments\admin.py:46 +msgid "User" +msgstr "" + +#: .\comments\models.py:25 +msgid "parent comment" +msgstr "" + +#: .\comments\models.py:29 +msgid "enable" +msgstr "" + +#: .\comments\models.py:34 .\templates\blog\tags\article_info.html:30 +msgid "comment" +msgstr "" + +#: .\comments\utils.py:13 +msgid "Thanks for your comment" +msgstr "" + +#: .\comments\utils.py:15 +#, python-brace-format +msgid "" +"\n" +"

Thank you very much for your comments on this site\n" +" You can visit\n" +" {comment." +"article.title}\n" +" to review your comments,\n" +" Thank you again!\n" +"
\n" +" If the link above cannot be opened, please copy this " +"link to your browser.\n" +" {article_url}\n" +" " +msgstr "" + +#: .\comments\utils.py:29 +#, python-brace-format +msgid "" +"\n" +" Your comment on {comment.article.title}
{comment.parent_comment.body}
has " +"received a reply. go check it out\n" +"
\n" +" If the link above cannot be opened, please copy this " +"link to your browser.\n" +" {article_url}\n" +" " +msgstr "" + +#: .\djangoblog\logentryadmin.py:11 +msgctxt "logentry_admin:action_type" +msgid "Addition" +msgstr "" + +#: .\djangoblog\logentryadmin.py:12 +msgctxt "logentry_admin:action_type" +msgid "Deletion" +msgstr "" + +#: .\djangoblog\logentryadmin.py:13 +msgctxt "logentry_admin:action_type" +msgid "Change" +msgstr "" + +#: .\djangoblog\logentryadmin.py:25 +msgid "Metadata" +msgstr "" + +#: .\djangoblog\logentryadmin.py:33 +msgid "Details" +msgstr "" + +#: .\djangoblog\logentryadmin.py:95 +msgid "object" +msgstr "" + +#: .\djangoblog\logentryadmin.py:128 +msgid "action" +msgstr "" + +#: .\djangoblog\logentryadmin.py:133 +msgid "change message" +msgstr "" + +#: .\djangoblog\settings.py:140 +msgid "English" +msgstr "" + +#: .\djangoblog\settings.py:141 +msgid "Simplified Chinese" +msgstr "" + +#: .\djangoblog\settings.py:142 +msgid "Traditional Chinese" +msgstr "" + +#: .\oauth\models.py:17 +msgid "nickname" +msgstr "" + +#: .\oauth\models.py:30 +msgid "oauth user" +msgstr "" + +#: .\oauth\models.py:37 +msgid "weibo" +msgstr "" + +#: .\oauth\models.py:38 +msgid "google" +msgstr "" + +#: .\oauth\models.py:48 +msgid "callback url" +msgstr "" + +#: .\oauth\models.py:59 +msgid "already exists" +msgstr "" + +#: .\oauth\views.py:154 +msgid "" +"\n" +"

Congratulations, you have successfully bound your email address. You " +"can use {oauthuser.type} to directly log in to this website without a " +"password. You are welcome to continue to follow this site, the address is\n" +"\n" +" {'http://' " +"+ site}\n" +"\n" +" Thank you again!\n" +"
\n" +" If the link above cannot be opened, please copy this link " +"to your browser.\n" +" {site}\n" +" " +msgstr "" + +#: .\oauth\views.py:165 +msgid "Congratulations on your successful binding!" +msgstr "" + +#: .\oauth\views.py:217 +#, python-brace-format +msgid "" +"\n" +"

Please click the link below to bind your email

\n" +"\n" +" {url}\n" +"\n" +" Thank you again!\n" +"
\n" +" If the link above cannot be opened, please copy this link " +"to your browser.\n" +" {url}\n" +" " +msgstr "" + +#: .\oauth\views.py:227 .\oauth\views.py:239 +msgid "Bind your email" +msgstr "" + +#: .\oauth\views.py:241 +msgid "" +"Congratulations, the binding is just one step away. Please log in to your " +"email to check the email to complete the binding. Thank you." +msgstr "" + +#: .\oauth\views.py:243 +msgid "Binding successful" +msgstr "" + +#: .\oauth\views.py:245 +#, python-brace-format +msgid "" +"Congratulations, you have successfully bound your email address. You can use " +"{oauthuser.type} to directly log in to this website without a password. You " +"are welcome to continue to follow this site." +msgstr "" + +#: .\templates\account\forget_password.html:7 +msgid "forget the password" +msgstr "forget the password" + +#: .\templates\account\forget_password.html:18 +msgid "get verification code" +msgstr "get verification code" + +#: .\templates\account\forget_password.html:19 +msgid "submit" +msgstr "submit" + +#: .\templates\account\result.html:18 .\templates\blog\tags\sidebar.html:126 +msgid "login" +msgstr "" + +#: .\templates\account\result.html:22 +msgid "back to the homepage" +msgstr "" + +#: .\templates\blog\article_archives.html:7 +#: .\templates\blog\article_archives.html:24 +msgid "article archive" +msgstr "" + +#: .\templates\blog\article_archives.html:32 +msgid "year" +msgstr "" + +#: .\templates\blog\article_archives.html:36 +msgid "month" +msgstr "" + +#: .\templates\blog\tags\article_info.html:12 +msgid "pin to top" +msgstr "" + +#: .\templates\blog\tags\article_info.html:28 +msgid "comments" +msgstr "" + +#: .\templates\blog\tags\article_info.html:58 +msgid "toc" +msgstr "" + +#: .\templates\blog\tags\article_meta_info.html:7 +#, fuzzy +#| msgid "Published" +msgid "Published on" +msgstr "Published" + +#: .\templates\blog\tags\article_meta_info.html:36 +#, python-format +msgid "" +"\n" +" title=\"View all articles published by " +"%(article.author.username)s\"\n" +" " +msgstr "" +"\n" +" title=\"View all articles published by " +"%(article.author.username)s\"\n" +" " +#: .\templates\blog\tags\article_meta_info.html:50 +msgid "edit" +msgstr "edit" + +#: .\templates\blog\tags\article_pagination.html:4 +msgid "article navigation" +msgstr "" + +#: .\templates\blog\tags\article_pagination.html:9 +msgid "earlier articles" +msgstr "" + +#: .\templates\blog\tags\article_pagination.html:12 +msgid "newer articles" +msgstr "" + +#: .\templates\blog\tags\article_tag_list.html:5 +msgid "tags" +msgstr "tags" + +#: .\templates\blog\tags\sidebar.html:7 +msgid "search" +msgstr "" + +#: .\templates\blog\tags\sidebar.html:50 +msgid "recent comments" +msgstr "" + +#: .\templates\blog\tags\sidebar.html:57 +msgid "published in" +msgstr "" + +#: .\templates\blog\tags\sidebar.html:65 +msgid "recent articles" +msgstr "" + +#: .\templates\blog\tags\sidebar.html:77 +msgid "bookmark" +msgstr "" + +#: .\templates\blog\tags\sidebar.html:96 +msgid "Tag Cloud" +msgstr "" + +#: .\templates\blog\tags\sidebar.html:107 +msgid "Welcome to star or fork the source code of this site" +msgstr "" + +#: .\templates\blog\tags\sidebar.html:118 +msgid "Function" +msgstr "" + +#: .\templates\blog\tags\sidebar.html:120 +msgid "management site" +msgstr "" + +#: .\templates\blog\tags\sidebar.html:122 +msgid "logout" +msgstr "" + +#: .\templates\blog\tags\sidebar.html:129 +msgid "Track record" +msgstr "" + +#: .\templates\blog\tags\sidebar.html:135 +msgid "Click me to return to the top" +msgstr "" + +#~ msgid "This entry was published on" +#~ msgstr "This entry was published on" + +#~ msgid "belongs" +#~ msgstr "belongs" + +#~ msgid "been" +#~ msgstr "been" diff --git a/locale/zh_Hans/LC_MESSAGES/django.po b/locale/zh_Hans/LC_MESSAGES/django.po new file mode 100644 index 000000000..b1a531ddb --- /dev/null +++ b/locale/zh_Hans/LC_MESSAGES/django.po @@ -0,0 +1,665 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-09-07 23:54+0800\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#: .\accounts\admin.py:13 +msgid "password" +msgstr "密码" + +#: .\accounts\admin.py:14 +msgid "Enter password again" +msgstr "再次输入密码" + +#: .\accounts\admin.py:25 .\accounts\forms.py:89 +msgid "passwords do not match" +msgstr "密码不匹配" + +#: .\accounts\admin.py:40 +msgid "Password" +msgstr "密码" + +#: .\accounts\admin.py:42 +msgid "" +"Raw passwords are not stored, so there is no way to see this user's " +"password, but you can change the password using this form." +msgstr "" +"未存储原始密码,因此无法看到此用户的密码,但您可以使用”更改密码此表单。" + +#: .\accounts\forms.py:36 +msgid "email already exists" +msgstr "邮箱已存在" + +#: .\accounts\forms.py:46 .\accounts\forms.py:50 +#, fuzzy +#| msgid "forget the password" +msgid "New password" +msgstr "新密码" + +#: .\accounts\forms.py:60 +#, fuzzy +#| msgid "forget the password" +msgid "Confirm password" +msgstr "确认密码" + +#: .\accounts\forms.py:70 .\accounts\forms.py:116 +msgid "Email" +msgstr "邮箱" + +#: .\accounts\forms.py:76 .\accounts\forms.py:80 +msgid "Code" +msgstr "验证码" + +#: .\accounts\forms.py:100 .\accounts\tests.py:194 +msgid "email does not exist" +msgstr "邮箱不存在" + +#: .\accounts\models.py:12 +msgid "nick name" +msgstr "昵称" + +#: .\accounts\models.py:13 .\blog\models.py:29 .\blog\models.py:266 +#: .\blog\models.py:284 .\comments\models.py:13 .\oauth\models.py:23 +#: .\oauth\models.py:53 +msgid "creation time" +msgstr "创建时间" + +#: .\accounts\models.py:14 .\comments\models.py:14 .\oauth\models.py:24 +#: .\oauth\models.py:54 +msgid "last modify time" +msgstr "最后修改时间" + +#: .\accounts\models.py:15 +msgid "create source" +msgstr "来源" + +#: .\accounts\models.py:33 .\djangoblog\logentryadmin.py:113 +msgid "user" +msgstr "用户" + +#: .\accounts\tests.py:216 .\accounts\utils.py:38 +#, fuzzy +#| msgid "get verification code" +msgid "Verification code error" +msgstr "验证码错误" + +#: .\accounts\utils.py:13 +msgid "Verify Email" +msgstr "验证邮箱" + +#: .\accounts\utils.py:21 +#, python-brace-format +msgid "" +"You are resetting the password, the verification code is:{code}, valid " +"within 5 minutes, please keep it properly" +msgstr "您正在重置密码,验证码为:{code},5分钟内有效 请妥善保管" + +#: .\blog\admin.py:13 .\blog\models.py:92 .\comments\models.py:17 +#: .\oauth\models.py:12 .\templates\blog\tags\article_meta_info.html:33 +msgid "author" +msgstr "作者" + +#: .\blog\admin.py:53 +msgid "Publish selected articles" +msgstr "发布选中的文章" + +#: .\blog\admin.py:54 +msgid "Draft selected articles" +msgstr "选中文章设为草稿" + +#: .\blog\admin.py:55 +msgid "Close article comments" +msgstr "关闭文章评论" + +#: .\blog\admin.py:56 +msgid "Open article comments" +msgstr "打开文章评论" + +#: .\blog\admin.py:89 .\blog\models.py:101 .\blog\models.py:183 +#: .\templates\blog\tags\article_meta_info.html:17 +#: .\templates\blog\tags\sidebar.html:40 +msgid "category" +msgstr "分类目录" + +#: .\blog\models.py:20 .\blog\models.py:179 +msgid "index" +msgstr "首页" + +#: .\blog\models.py:21 +msgid "list" +msgstr "列表" + +#: .\blog\models.py:22 +msgid "post" +msgstr "文章" + +#: .\blog\models.py:23 +msgid "all" +msgstr "所有" + +#: .\blog\models.py:24 +msgid "slide" +msgstr "侧边栏" + +#: .\blog\models.py:30 .\blog\models.py:267 .\blog\models.py:285 +msgid "modify time" +msgstr "修改时间" + +#: .\blog\models.py:63 +msgid "Draft" +msgstr "草稿" + +#: .\blog\models.py:64 +msgid "Published" +msgstr "发布" + +#: .\blog\models.py:67 +msgid "Open" +msgstr "打开" + +#: .\blog\models.py:68 +msgid "Close" +msgstr "关闭" + +#: .\blog\models.py:71 .\comments\admin.py:47 +msgid "Article" +msgstr "文章" + +#: .\blog\models.py:72 +msgid "Page" +msgstr "页面" + +#: .\blog\models.py:74 .\blog\models.py:280 +msgid "title" +msgstr "标题" + +#: .\blog\models.py:75 +msgid "body" +msgstr "内容" + +#: .\blog\models.py:77 +msgid "publish time" +msgstr "发布时间" + +#: .\blog\models.py:79 +msgid "status" +msgstr "状态" + +#: .\blog\models.py:84 +msgid "comment status" +msgstr "评论状态" + +#: .\blog\models.py:88 .\oauth\models.py:43 +msgid "type" +msgstr "类型" + +#: .\blog\models.py:89 +msgid "views" +msgstr "阅读量" + +#: .\blog\models.py:97 .\blog\models.py:258 .\blog\models.py:282 +msgid "order" +msgstr "排序" + +#: .\blog\models.py:98 +msgid "show toc" +msgstr "显示目录" + +#: .\blog\models.py:105 .\blog\models.py:249 +#: .\templates\blog\tags\article_meta_info.html:22 +msgid "tag" +msgstr "标签" + +#: .\blog\models.py:115 .\comments\models.py:21 +msgid "article" +msgstr "文章" + +#: .\blog\models.py:171 +msgid "category name" +msgstr "分类名" + +#: .\blog\models.py:174 +msgid "parent category" +msgstr "上级分类" + +#: .\blog\models.py:234 +msgid "tag name" +msgstr "标签名" + +#: .\blog\models.py:256 +msgid "link name" +msgstr "链接名" + +#: .\blog\models.py:257 .\blog\models.py:271 +msgid "link" +msgstr "链接" + +#: .\blog\models.py:260 +msgid "is show" +msgstr "是否显示" + +#: .\blog\models.py:262 +msgid "show type" +msgstr "显示类型" + +#: .\blog\models.py:281 +msgid "content" +msgstr "内容" + +#: .\blog\models.py:283 .\oauth\models.py:52 +msgid "is enable" +msgstr "是否启用" + +#: .\blog\models.py:289 +msgid "sidebar" +msgstr "侧边栏" + +#: .\blog\models.py:299 +msgid "site name" +msgstr "站点名称" + +#: .\blog\models.py:305 +msgid "site description" +msgstr "站点描述" + +#: .\blog\models.py:311 +msgid "site seo description" +msgstr "站点SEO描述" + +#: .\blog\models.py:313 +msgid "site keywords" +msgstr "关键字" + +#: .\blog\models.py:318 +msgid "article sub length" +msgstr "文章摘要长度" + +#: .\blog\models.py:319 +msgid "sidebar article count" +msgstr "侧边栏文章数目" + +#: .\blog\models.py:320 +msgid "sidebar comment count" +msgstr "侧边栏评论数目" + +#: .\blog\models.py:321 +msgid "article comment count" +msgstr "文章页面默认显示评论数目" + +#: .\blog\models.py:322 +msgid "show adsense" +msgstr "是否显示广告" + +#: .\blog\models.py:324 +msgid "adsense code" +msgstr "广告内容" + +#: .\blog\models.py:325 +msgid "open site comment" +msgstr "公共头部" + +#: .\blog\models.py:360 +msgid "只能有一个配置" +msgstr "" + +#: .\blog\views.py:349 +msgid "" +"Sorry, the page you requested is not found, please click the home page to " +"see other?" +msgstr "" + +#: .\blog\views.py:357 +msgid "Sorry, the server is busy, please click the home page to see other?" +msgstr "" + +#: .\blog\views.py:370 +msgid "Sorry, you do not have permission to access this page?" +msgstr "" + +#: .\comments\admin.py:15 +msgid "Disable comments" +msgstr "" + +#: .\comments\admin.py:16 +msgid "Enable comments" +msgstr "" + +#: .\comments\admin.py:46 +msgid "User" +msgstr "" + +#: .\comments\models.py:25 +msgid "parent comment" +msgstr "" + +#: .\comments\models.py:29 +msgid "enable" +msgstr "" + +#: .\comments\models.py:34 .\templates\blog\tags\article_info.html:30 +msgid "comment" +msgstr "" + +#: .\comments\utils.py:13 +msgid "Thanks for your comment" +msgstr "" + +#: .\comments\utils.py:15 +#, python-brace-format +msgid "" +"\n" +"

Thank you very much for your comments on this site\n" +" You can visit\n" +" {comment." +"article.title}\n" +" to review your comments,\n" +" Thank you again!\n" +"
\n" +" If the link above cannot be opened, please copy this " +"link to your browser.\n" +" {article_url}\n" +" " +msgstr "" + +#: .\comments\utils.py:29 +#, python-brace-format +msgid "" +"\n" +" Your comment on {comment.article.title}
{comment.parent_comment.body}
has " +"received a reply. go check it out\n" +"
\n" +" If the link above cannot be opened, please copy this " +"link to your browser.\n" +" {article_url}\n" +" " +msgstr "" + +#: .\djangoblog\logentryadmin.py:11 +msgctxt "logentry_admin:action_type" +msgid "Addition" +msgstr "" + +#: .\djangoblog\logentryadmin.py:12 +msgctxt "logentry_admin:action_type" +msgid "Deletion" +msgstr "" + +#: .\djangoblog\logentryadmin.py:13 +msgctxt "logentry_admin:action_type" +msgid "Change" +msgstr "" + +#: .\djangoblog\logentryadmin.py:25 +msgid "Metadata" +msgstr "" + +#: .\djangoblog\logentryadmin.py:33 +msgid "Details" +msgstr "" + +#: .\djangoblog\logentryadmin.py:95 +msgid "object" +msgstr "" + +#: .\djangoblog\logentryadmin.py:128 +msgid "action" +msgstr "" + +#: .\djangoblog\logentryadmin.py:133 +msgid "change message" +msgstr "" + +#: .\djangoblog\settings.py:140 +msgid "English" +msgstr "" + +#: .\djangoblog\settings.py:141 +msgid "Simplified Chinese" +msgstr "" + +#: .\djangoblog\settings.py:142 +msgid "Traditional Chinese" +msgstr "" + +#: .\oauth\models.py:17 +msgid "nickname" +msgstr "" + +#: .\oauth\models.py:30 +msgid "oauth user" +msgstr "" + +#: .\oauth\models.py:37 +msgid "weibo" +msgstr "" + +#: .\oauth\models.py:38 +msgid "google" +msgstr "" + +#: .\oauth\models.py:48 +msgid "callback url" +msgstr "" + +#: .\oauth\models.py:59 +msgid "already exists" +msgstr "" + +#: .\oauth\views.py:154 +msgid "" +"\n" +"

Congratulations, you have successfully bound your email address. You " +"can use {oauthuser.type} to directly log in to this website without a " +"password. You are welcome to continue to follow this site, the address is\n" +"\n" +" {'http://' " +"+ site}\n" +"\n" +" Thank you again!\n" +"
\n" +" If the link above cannot be opened, please copy this link " +"to your browser.\n" +" {site}\n" +" " +msgstr "" + +#: .\oauth\views.py:165 +msgid "Congratulations on your successful binding!" +msgstr "" + +#: .\oauth\views.py:217 +#, python-brace-format +msgid "" +"\n" +"

Please click the link below to bind your email

\n" +"\n" +" {url}\n" +"\n" +" Thank you again!\n" +"
\n" +" If the link above cannot be opened, please copy this link " +"to your browser.\n" +" {url}\n" +" " +msgstr "" + +#: .\oauth\views.py:227 .\oauth\views.py:239 +msgid "Bind your email" +msgstr "" + +#: .\oauth\views.py:241 +msgid "" +"Congratulations, the binding is just one step away. Please log in to your " +"email to check the email to complete the binding. Thank you." +msgstr "" + +#: .\oauth\views.py:243 +msgid "Binding successful" +msgstr "" + +#: .\oauth\views.py:245 +#, python-brace-format +msgid "" +"Congratulations, you have successfully bound your email address. You can use " +"{oauthuser.type} to directly log in to this website without a password. You " +"are welcome to continue to follow this site." +msgstr "" + +#: .\templates\account\forget_password.html:7 +msgid "forget the password" +msgstr "忘记密码" + +#: .\templates\account\forget_password.html:18 +msgid "get verification code" +msgstr "获取验证码" + +#: .\templates\account\forget_password.html:19 +msgid "submit" +msgstr "提交" + +#: .\templates\account\result.html:18 .\templates\blog\tags\sidebar.html:126 +msgid "login" +msgstr "" + +#: .\templates\account\result.html:22 +msgid "back to the homepage" +msgstr "" + +#: .\templates\blog\article_archives.html:7 +#: .\templates\blog\article_archives.html:24 +msgid "article archive" +msgstr "" + +#: .\templates\blog\article_archives.html:32 +msgid "year" +msgstr "" + +#: .\templates\blog\article_archives.html:36 +msgid "month" +msgstr "" + +#: .\templates\blog\tags\article_info.html:12 +msgid "pin to top" +msgstr "" + +#: .\templates\blog\tags\article_info.html:28 +msgid "comments" +msgstr "" + +#: .\templates\blog\tags\article_info.html:58 +msgid "toc" +msgstr "" + +#: .\templates\blog\tags\article_meta_info.html:7 +#, fuzzy +#| msgid "Published" +msgid "Published on" +msgstr "发表于" + +#: .\templates\blog\tags\article_meta_info.html:36 +#, python-format +msgid "" +"\n" +" title=\"View all articles published by " +"%(article.author.username)s\"\n" +" " +msgstr "" +"\n" +" title=\"查看所有由 " +"%(article.author.username)s\"发布的文章\n" +" " +#: .\templates\blog\tags\article_meta_info.html:50 +msgid "edit" +msgstr "编辑" + +#: .\templates\blog\tags\article_pagination.html:4 +msgid "article navigation" +msgstr "" + +#: .\templates\blog\tags\article_pagination.html:9 +msgid "earlier articles" +msgstr "" + +#: .\templates\blog\tags\article_pagination.html:12 +msgid "newer articles" +msgstr "" + +#: .\templates\blog\tags\article_tag_list.html:5 +msgid "tags" +msgstr "标签" + +#: .\templates\blog\tags\sidebar.html:7 +msgid "search" +msgstr "" + +#: .\templates\blog\tags\sidebar.html:50 +msgid "recent comments" +msgstr "" + +#: .\templates\blog\tags\sidebar.html:57 +msgid "published in" +msgstr "" + +#: .\templates\blog\tags\sidebar.html:65 +msgid "recent articles" +msgstr "" + +#: .\templates\blog\tags\sidebar.html:77 +msgid "bookmark" +msgstr "" + +#: .\templates\blog\tags\sidebar.html:96 +msgid "Tag Cloud" +msgstr "" + +#: .\templates\blog\tags\sidebar.html:107 +msgid "Welcome to star or fork the source code of this site" +msgstr "" + +#: .\templates\blog\tags\sidebar.html:118 +msgid "Function" +msgstr "" + +#: .\templates\blog\tags\sidebar.html:120 +msgid "management site" +msgstr "" + +#: .\templates\blog\tags\sidebar.html:122 +msgid "logout" +msgstr "" + +#: .\templates\blog\tags\sidebar.html:129 +msgid "Track record" +msgstr "" + +#: .\templates\blog\tags\sidebar.html:135 +msgid "Click me to return to the top" +msgstr "" + +#~ msgid "This entry was published on" +#~ msgstr "这篇文章发布在 " + +#~ msgid "belongs" +#~ msgstr "属于" + +#~ msgid "been" +#~ msgstr "贴了" diff --git a/locale/zh_Hant/LC_MESSAGES/django.po b/locale/zh_Hant/LC_MESSAGES/django.po new file mode 100644 index 000000000..8f8250ee7 --- /dev/null +++ b/locale/zh_Hant/LC_MESSAGES/django.po @@ -0,0 +1,643 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-09-07 23:54+0800\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#: .\accounts\admin.py:13 +msgid "password" +msgstr "" + +#: .\accounts\admin.py:14 +msgid "Enter password again" +msgstr "" + +#: .\accounts\admin.py:25 .\accounts\forms.py:89 +msgid "passwords do not match" +msgstr "" + +#: .\accounts\admin.py:40 +msgid "Password" +msgstr "" + +#: .\accounts\admin.py:42 +msgid "" +"Raw passwords are not stored, so there is no way to see this user's " +"password, but you can change the password using this form." +msgstr "" + +#: .\accounts\forms.py:36 +msgid "email already exists" +msgstr "" + +#: .\accounts\forms.py:46 .\accounts\forms.py:50 +msgid "New password" +msgstr "" + +#: .\accounts\forms.py:60 +msgid "Confirm password" +msgstr "" + +#: .\accounts\forms.py:70 .\accounts\forms.py:116 +msgid "Email" +msgstr "" + +#: .\accounts\forms.py:76 .\accounts\forms.py:80 +msgid "Code" +msgstr "" + +#: .\accounts\forms.py:100 .\accounts\tests.py:194 +msgid "email does not exist" +msgstr "" + +#: .\accounts\models.py:12 +msgid "nick name" +msgstr "" + +#: .\accounts\models.py:13 .\blog\models.py:29 .\blog\models.py:266 +#: .\blog\models.py:284 .\comments\models.py:13 .\oauth\models.py:23 +#: .\oauth\models.py:53 +msgid "creation time" +msgstr "" + +#: .\accounts\models.py:14 .\comments\models.py:14 .\oauth\models.py:24 +#: .\oauth\models.py:54 +msgid "last modify time" +msgstr "" + +#: .\accounts\models.py:15 +msgid "create source" +msgstr "" + +#: .\accounts\models.py:33 .\djangoblog\logentryadmin.py:113 +msgid "user" +msgstr "" + +#: .\accounts\tests.py:216 .\accounts\utils.py:38 +msgid "Verification code error" +msgstr "" + +#: .\accounts\utils.py:13 +msgid "Verify Email" +msgstr "" + +#: .\accounts\utils.py:21 +#, python-brace-format +msgid "" +"You are resetting the password, the verification code is:{code}, valid " +"within 5 minutes, please keep it properly" +msgstr "" + +#: .\blog\admin.py:13 .\blog\models.py:92 .\comments\models.py:17 +#: .\oauth\models.py:12 .\templates\blog\tags\article_meta_info.html:33 +msgid "author" +msgstr "" + +#: .\blog\admin.py:53 +msgid "Publish selected articles" +msgstr "" + +#: .\blog\admin.py:54 +msgid "Draft selected articles" +msgstr "" + +#: .\blog\admin.py:55 +msgid "Close article comments" +msgstr "" + +#: .\blog\admin.py:56 +msgid "Open article comments" +msgstr "" + +#: .\blog\admin.py:89 .\blog\models.py:101 .\blog\models.py:183 +#: .\templates\blog\tags\article_meta_info.html:17 +#: .\templates\blog\tags\sidebar.html:40 +msgid "category" +msgstr "" + +#: .\blog\models.py:20 .\blog\models.py:179 +msgid "index" +msgstr "" + +#: .\blog\models.py:21 +msgid "list" +msgstr "" + +#: .\blog\models.py:22 +msgid "post" +msgstr "" + +#: .\blog\models.py:23 +msgid "all" +msgstr "" + +#: .\blog\models.py:24 +msgid "slide" +msgstr "" + +#: .\blog\models.py:30 .\blog\models.py:267 .\blog\models.py:285 +msgid "modify time" +msgstr "" + +#: .\blog\models.py:63 +msgid "Draft" +msgstr "" + +#: .\blog\models.py:64 +msgid "Published" +msgstr "" + +#: .\blog\models.py:67 +msgid "Open" +msgstr "" + +#: .\blog\models.py:68 +msgid "Close" +msgstr "" + +#: .\blog\models.py:71 .\comments\admin.py:47 +msgid "Article" +msgstr "" + +#: .\blog\models.py:72 +msgid "Page" +msgstr "" + +#: .\blog\models.py:74 .\blog\models.py:280 +msgid "title" +msgstr "" + +#: .\blog\models.py:75 +msgid "body" +msgstr "" + +#: .\blog\models.py:77 +msgid "publish time" +msgstr "" + +#: .\blog\models.py:79 +msgid "status" +msgstr "" + +#: .\blog\models.py:84 +msgid "comment status" +msgstr "" + +#: .\blog\models.py:88 .\oauth\models.py:43 +msgid "type" +msgstr "" + +#: .\blog\models.py:89 +msgid "views" +msgstr "" + +#: .\blog\models.py:97 .\blog\models.py:258 .\blog\models.py:282 +msgid "order" +msgstr "" + +#: .\blog\models.py:98 +msgid "show toc" +msgstr "" + +#: .\blog\models.py:105 .\blog\models.py:249 +#: .\templates\blog\tags\article_meta_info.html:22 +msgid "tag" +msgstr "" + +#: .\blog\models.py:115 .\comments\models.py:21 +msgid "article" +msgstr "" + +#: .\blog\models.py:171 +msgid "category name" +msgstr "" + +#: .\blog\models.py:174 +msgid "parent category" +msgstr "" + +#: .\blog\models.py:234 +msgid "tag name" +msgstr "" + +#: .\blog\models.py:256 +msgid "link name" +msgstr "" + +#: .\blog\models.py:257 .\blog\models.py:271 +msgid "link" +msgstr "" + +#: .\blog\models.py:260 +msgid "is show" +msgstr "" + +#: .\blog\models.py:262 +msgid "show type" +msgstr "" + +#: .\blog\models.py:281 +msgid "content" +msgstr "" + +#: .\blog\models.py:283 .\oauth\models.py:52 +msgid "is enable" +msgstr "" + +#: .\blog\models.py:289 +msgid "sidebar" +msgstr "" + +#: .\blog\models.py:299 +msgid "site name" +msgstr "" + +#: .\blog\models.py:305 +msgid "site description" +msgstr "" + +#: .\blog\models.py:311 +msgid "site seo description" +msgstr "" + +#: .\blog\models.py:313 +msgid "site keywords" +msgstr "" + +#: .\blog\models.py:318 +msgid "article sub length" +msgstr "" + +#: .\blog\models.py:319 +msgid "sidebar article count" +msgstr "" + +#: .\blog\models.py:320 +msgid "sidebar comment count" +msgstr "" + +#: .\blog\models.py:321 +msgid "article comment count" +msgstr "" + +#: .\blog\models.py:322 +msgid "show adsense" +msgstr "" + +#: .\blog\models.py:324 +msgid "adsense code" +msgstr "" + +#: .\blog\models.py:325 +msgid "open site comment" +msgstr "" + +#: .\blog\models.py:360 +msgid "只能有一个配置" +msgstr "" + +#: .\blog\views.py:349 +msgid "" +"Sorry, the page you requested is not found, please click the home page to " +"see other?" +msgstr "" + +#: .\blog\views.py:357 +msgid "Sorry, the server is busy, please click the home page to see other?" +msgstr "" + +#: .\blog\views.py:370 +msgid "Sorry, you do not have permission to access this page?" +msgstr "" + +#: .\comments\admin.py:15 +msgid "Disable comments" +msgstr "" + +#: .\comments\admin.py:16 +msgid "Enable comments" +msgstr "" + +#: .\comments\admin.py:46 +msgid "User" +msgstr "" + +#: .\comments\models.py:25 +msgid "parent comment" +msgstr "" + +#: .\comments\models.py:29 +msgid "enable" +msgstr "" + +#: .\comments\models.py:34 .\templates\blog\tags\article_info.html:30 +msgid "comment" +msgstr "" + +#: .\comments\utils.py:13 +msgid "Thanks for your comment" +msgstr "" + +#: .\comments\utils.py:15 +#, python-brace-format +msgid "" +"\n" +"

Thank you very much for your comments on this site\n" +" You can visit\n" +" {comment." +"article.title}\n" +" to review your comments,\n" +" Thank you again!\n" +"
\n" +" If the link above cannot be opened, please copy this " +"link to your browser.\n" +" {article_url}\n" +" " +msgstr "" + +#: .\comments\utils.py:29 +#, python-brace-format +msgid "" +"\n" +" Your comment on {comment.article.title}
{comment.parent_comment.body}
has " +"received a reply. go check it out\n" +"
\n" +" If the link above cannot be opened, please copy this " +"link to your browser.\n" +" {article_url}\n" +" " +msgstr "" + +#: .\djangoblog\logentryadmin.py:11 +msgctxt "logentry_admin:action_type" +msgid "Addition" +msgstr "" + +#: .\djangoblog\logentryadmin.py:12 +msgctxt "logentry_admin:action_type" +msgid "Deletion" +msgstr "" + +#: .\djangoblog\logentryadmin.py:13 +msgctxt "logentry_admin:action_type" +msgid "Change" +msgstr "" + +#: .\djangoblog\logentryadmin.py:25 +msgid "Metadata" +msgstr "" + +#: .\djangoblog\logentryadmin.py:33 +msgid "Details" +msgstr "" + +#: .\djangoblog\logentryadmin.py:95 +msgid "object" +msgstr "" + +#: .\djangoblog\logentryadmin.py:128 +msgid "action" +msgstr "" + +#: .\djangoblog\logentryadmin.py:133 +msgid "change message" +msgstr "" + +#: .\djangoblog\settings.py:140 +msgid "English" +msgstr "" + +#: .\djangoblog\settings.py:141 +msgid "Simplified Chinese" +msgstr "" + +#: .\djangoblog\settings.py:142 +msgid "Traditional Chinese" +msgstr "" + +#: .\oauth\models.py:17 +msgid "nickname" +msgstr "" + +#: .\oauth\models.py:30 +msgid "oauth user" +msgstr "" + +#: .\oauth\models.py:37 +msgid "weibo" +msgstr "" + +#: .\oauth\models.py:38 +msgid "google" +msgstr "" + +#: .\oauth\models.py:48 +msgid "callback url" +msgstr "" + +#: .\oauth\models.py:59 +msgid "already exists" +msgstr "" + +#: .\oauth\views.py:154 +msgid "" +"\n" +"

Congratulations, you have successfully bound your email address. You " +"can use {oauthuser.type} to directly log in to this website without a " +"password. You are welcome to continue to follow this site, the address is\n" +"\n" +" {'http://' " +"+ site}\n" +"\n" +" Thank you again!\n" +"
\n" +" If the link above cannot be opened, please copy this link " +"to your browser.\n" +" {site}\n" +" " +msgstr "" + +#: .\oauth\views.py:165 +msgid "Congratulations on your successful binding!" +msgstr "" + +#: .\oauth\views.py:217 +#, python-brace-format +msgid "" +"\n" +"

Please click the link below to bind your email

\n" +"\n" +" {url}\n" +"\n" +" Thank you again!\n" +"
\n" +" If the link above cannot be opened, please copy this link " +"to your browser.\n" +" {url}\n" +" " +msgstr "" + +#: .\oauth\views.py:227 .\oauth\views.py:239 +msgid "Bind your email" +msgstr "" + +#: .\oauth\views.py:241 +msgid "" +"Congratulations, the binding is just one step away. Please log in to your " +"email to check the email to complete the binding. Thank you." +msgstr "" + +#: .\oauth\views.py:243 +msgid "Binding successful" +msgstr "" + +#: .\oauth\views.py:245 +#, python-brace-format +msgid "" +"Congratulations, you have successfully bound your email address. You can use " +"{oauthuser.type} to directly log in to this website without a password. You " +"are welcome to continue to follow this site." +msgstr "" + +#: .\templates\account\forget_password.html:7 +msgid "forget the password" +msgstr "" + +#: .\templates\account\forget_password.html:18 +msgid "get verification code" +msgstr "" + +#: .\templates\account\forget_password.html:19 +msgid "submit" +msgstr "" + +#: .\templates\account\result.html:18 .\templates\blog\tags\sidebar.html:126 +msgid "login" +msgstr "" + +#: .\templates\account\result.html:22 +msgid "back to the homepage" +msgstr "" + +#: .\templates\blog\article_archives.html:7 +#: .\templates\blog\article_archives.html:24 +msgid "article archive" +msgstr "" + +#: .\templates\blog\article_archives.html:32 +msgid "year" +msgstr "" + +#: .\templates\blog\article_archives.html:36 +msgid "month" +msgstr "" + +#: .\templates\blog\tags\article_info.html:12 +msgid "pin to top" +msgstr "" + +#: .\templates\blog\tags\article_info.html:28 +msgid "comments" +msgstr "" + +#: .\templates\blog\tags\article_info.html:58 +msgid "toc" +msgstr "" + +#: .\templates\blog\tags\article_meta_info.html:7 +msgid "Published on" +msgstr "发表于" + +#: .\templates\blog\tags\article_meta_info.html:36 +#, python-format +msgid "" +"\n" +" title=\"View all articles published by " +"%(article.author.username)s\"\n" +" " +msgstr "" + +#: .\templates\blog\tags\article_meta_info.html:50 +msgid "edit" +msgstr "" + +#: .\templates\blog\tags\article_pagination.html:4 +msgid "article navigation" +msgstr "" + +#: .\templates\blog\tags\article_pagination.html:9 +msgid "earlier articles" +msgstr "" + +#: .\templates\blog\tags\article_pagination.html:12 +msgid "newer articles" +msgstr "" + +#: .\templates\blog\tags\article_tag_list.html:5 +msgid "tags" +msgstr "" + +#: .\templates\blog\tags\sidebar.html:7 +msgid "search" +msgstr "" + +#: .\templates\blog\tags\sidebar.html:50 +msgid "recent comments" +msgstr "" + +#: .\templates\blog\tags\sidebar.html:57 +msgid "published in" +msgstr "" + +#: .\templates\blog\tags\sidebar.html:65 +msgid "recent articles" +msgstr "" + +#: .\templates\blog\tags\sidebar.html:77 +msgid "bookmark" +msgstr "" + +#: .\templates\blog\tags\sidebar.html:96 +msgid "Tag Cloud" +msgstr "" + +#: .\templates\blog\tags\sidebar.html:107 +msgid "Welcome to star or fork the source code of this site" +msgstr "" + +#: .\templates\blog\tags\sidebar.html:118 +msgid "Function" +msgstr "" + +#: .\templates\blog\tags\sidebar.html:120 +msgid "management site" +msgstr "" + +#: .\templates\blog\tags\sidebar.html:122 +msgid "logout" +msgstr "" + +#: .\templates\blog\tags\sidebar.html:129 +msgid "Track record" +msgstr "" + +#: .\templates\blog\tags\sidebar.html:135 +msgid "Click me to return to the top" +msgstr "" diff --git a/oauth/migrations/0002_alter_oauthconfig_options_alter_oauthuser_options_and_more.py b/oauth/migrations/0002_alter_oauthconfig_options_alter_oauthuser_options_and_more.py new file mode 100644 index 000000000..d5cc70ef2 --- /dev/null +++ b/oauth/migrations/0002_alter_oauthconfig_options_alter_oauthuser_options_and_more.py @@ -0,0 +1,86 @@ +# Generated by Django 4.2.5 on 2023-09-06 13:13 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('oauth', '0001_initial'), + ] + + operations = [ + migrations.AlterModelOptions( + name='oauthconfig', + options={'ordering': ['-creation_time'], 'verbose_name': 'oauth配置', 'verbose_name_plural': 'oauth配置'}, + ), + migrations.AlterModelOptions( + name='oauthuser', + options={'ordering': ['-creation_time'], 'verbose_name': 'oauth user', 'verbose_name_plural': 'oauth user'}, + ), + migrations.RemoveField( + model_name='oauthconfig', + name='created_time', + ), + migrations.RemoveField( + model_name='oauthconfig', + name='last_mod_time', + ), + migrations.RemoveField( + model_name='oauthuser', + name='created_time', + ), + migrations.RemoveField( + model_name='oauthuser', + name='last_mod_time', + ), + migrations.AddField( + model_name='oauthconfig', + name='creation_time', + field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='creation time'), + ), + migrations.AddField( + model_name='oauthconfig', + name='last_modify_time', + field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='last modify time'), + ), + migrations.AddField( + model_name='oauthuser', + name='creation_time', + field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='creation time'), + ), + migrations.AddField( + model_name='oauthuser', + name='last_modify_time', + field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='last modify time'), + ), + migrations.AlterField( + model_name='oauthconfig', + name='callback_url', + field=models.CharField(default='', max_length=200, verbose_name='callback url'), + ), + migrations.AlterField( + model_name='oauthconfig', + name='is_enable', + field=models.BooleanField(default=True, verbose_name='is enable'), + ), + migrations.AlterField( + model_name='oauthconfig', + name='type', + field=models.CharField(choices=[('weibo', 'weibo'), ('google', 'google'), ('github', 'GitHub'), ('facebook', 'FaceBook'), ('qq', 'QQ')], default='a', max_length=10, verbose_name='type'), + ), + migrations.AlterField( + model_name='oauthuser', + name='author', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='author'), + ), + migrations.AlterField( + model_name='oauthuser', + name='nickname', + field=models.CharField(max_length=50, verbose_name='nickname'), + ), + ] diff --git a/oauth/models.py b/oauth/models.py index ff82607d0..5f76f23ed 100644 --- a/oauth/models.py +++ b/oauth/models.py @@ -9,54 +9,54 @@ class OAuthUser(models.Model): author = models.ForeignKey( settings.AUTH_USER_MODEL, - verbose_name='用户', + verbose_name=_('author'), blank=True, null=True, on_delete=models.CASCADE) openid = models.CharField(max_length=50) - nickname = models.CharField(max_length=50, verbose_name='昵称') + nickname = models.CharField(max_length=50, verbose_name=_('nickname')) token = models.CharField(max_length=150, null=True, blank=True) picture = models.CharField(max_length=350, blank=True, null=True) type = models.CharField(blank=False, null=False, max_length=50) email = models.CharField(max_length=50, null=True, blank=True) metadata = models.TextField(null=True, blank=True) - created_time = models.DateTimeField('创建时间', default=now) - last_mod_time = models.DateTimeField('修改时间', default=now) + creation_time = models.DateTimeField(_('creation time'), default=now) + last_modify_time = models.DateTimeField(_('last modify time'), default=now) def __str__(self): return self.nickname class Meta: - verbose_name = 'oauth用户' + verbose_name = _('oauth user') verbose_name_plural = verbose_name - ordering = ['-created_time'] + ordering = ['-creation_time'] class OAuthConfig(models.Model): TYPE = ( - ('weibo', '微博'), - ('google', '谷歌'), + ('weibo', _('weibo')), + ('google', _('google')), ('github', 'GitHub'), ('facebook', 'FaceBook'), ('qq', 'QQ'), ) - type = models.CharField('类型', max_length=10, choices=TYPE, default='a') + type = models.CharField(_('type'), max_length=10, choices=TYPE, default='a') appkey = models.CharField(max_length=200, verbose_name='AppKey') appsecret = models.CharField(max_length=200, verbose_name='AppSecret') callback_url = models.CharField( max_length=200, - verbose_name='回调地址', + verbose_name=_('callback url'), blank=False, - default='http://www.baidu.com') + default='') is_enable = models.BooleanField( - '是否显示', default=True, blank=False, null=False) - created_time = models.DateTimeField('创建时间', default=now) - last_mod_time = models.DateTimeField('修改时间', default=now) + _('is enable'), default=True, blank=False, null=False) + creation_time = models.DateTimeField(_('creation time'), default=now) + last_modify_time = models.DateTimeField(_('last modify time'), default=now) def clean(self): if OAuthConfig.objects.filter( type=self.type).exclude(id=self.id).count(): - raise ValidationError(_(self.type + '已经存在')) + raise ValidationError(_(self.type + _('already exists'))) def __str__(self): return self.type @@ -64,4 +64,4 @@ def __str__(self): class Meta: verbose_name = 'oauth配置' verbose_name_plural = verbose_name - ordering = ['-created_time'] + ordering = ['-creation_time'] diff --git a/oauth/views.py b/oauth/views.py index 00ec4c990..83524fd51 100644 --- a/oauth/views.py +++ b/oauth/views.py @@ -13,6 +13,7 @@ from django.shortcuts import render from django.urls import reverse from django.utils import timezone +from django.utils.translation import gettext_lazy as _ from django.views.generic import FormView from djangoblog.blog_signals import oauth_user_login_signal @@ -149,19 +150,19 @@ def emailconfirm(request, id, sign): id=oauthuser.id) login(request, author) - site = get_current_site().domain - content = ''' -

恭喜您,您已经成功绑定您的邮箱,您可以使用{type}来直接免密码登录本网站.欢迎您继续关注本站,地址是

+ site = 'http://' + get_current_site().domain + content = _(f''' +

Congratulations, you have successfully bound your email address. You can use {oauthuser.type} to directly log in to this website without a password. You are welcome to continue to follow this site, the address is

- {url} + {'http://' + site} - 再次感谢您! -
- 如果上面链接无法打开,请将此链接复制至浏览器。 - {url} - '''.format(type=oauthuser.type, url='http://' + site) + Thank you again! +
+ If the link above cannot be opened, please copy this link to your browser. + {site} + ''') - send_email(emailto=[oauthuser.email, ], title='恭喜您绑定成功!', content=content) + send_email(emailto=[oauthuser.email, ], title=_('Congratulations on your successful binding!'), content=content) url = reverse('oauth:bindsuccess', kwargs={ 'oauthid': id }) @@ -213,17 +214,17 @@ def form_valid(self, form): }) url = "http://{site}{path}".format(site=site, path=path) - content = """ -

请点击下面链接绑定您的邮箱

+ content = _(f""" +

Please click the link below to bind your email

- {url} + {url} - 再次感谢您! -
- 如果上面链接无法打开,请将此链接复制至浏览器。 - {url} - """.format(url=url) - send_email(emailto=[email, ], title='绑定您的电子邮箱', content=content) + Thank you again! +
+ If the link above cannot be opened, please copy this link to your browser. + {url} + """) + send_email(emailto=[email, ], title=_('Bind your email'), content=content) url = reverse('oauth:bindsuccess', kwargs={ 'oauthid': oauthid }) @@ -235,12 +236,13 @@ def bindsuccess(request, oauthid): type = request.GET.get('type', None) oauthuser = get_object_or_404(OAuthUser, pk=oauthid) if type == 'email': - title = '绑定成功' - content = "恭喜您,还差一步就绑定成功了,请登录您的邮箱查看邮件完成绑定,谢谢。" + title = _('Bind your email') + content = _( + 'Congratulations, the binding is just one step away. Please log in to your email to check the email to complete the binding. Thank you.') else: - title = '绑定成功' - content = "恭喜您绑定成功,您以后可以使用{type}来直接免密码登录本站啦,感谢您对本站对关注。".format( - type=oauthuser.type) + title = _('Binding successful') + content = _( + f"Congratulations, you have successfully bound your email address. You can use {oauthuser.type} to directly log in to this website without a password. You are welcome to continue to follow this site.") return render(request, 'oauth/bindsuccess.html', { 'title': title, 'content': content diff --git a/owntracks/migrations/0002_alter_owntracklog_options_and_more.py b/owntracks/migrations/0002_alter_owntracklog_options_and_more.py new file mode 100644 index 000000000..b4f8decc5 --- /dev/null +++ b/owntracks/migrations/0002_alter_owntracklog_options_and_more.py @@ -0,0 +1,22 @@ +# Generated by Django 4.2.5 on 2023-09-06 13:19 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('owntracks', '0001_initial'), + ] + + operations = [ + migrations.AlterModelOptions( + name='owntracklog', + options={'get_latest_by': 'creation_time', 'ordering': ['creation_time'], 'verbose_name': 'OwnTrackLogs', 'verbose_name_plural': 'OwnTrackLogs'}, + ), + migrations.RenameField( + model_name='owntracklog', + old_name='created_time', + new_name='creation_time', + ), + ] diff --git a/owntracks/models.py b/owntracks/models.py index 30f6ec17e..760942c66 100644 --- a/owntracks/models.py +++ b/owntracks/models.py @@ -8,13 +8,13 @@ class OwnTrackLog(models.Model): tid = models.CharField(max_length=100, null=False, verbose_name='用户') lat = models.FloatField(verbose_name='纬度') lon = models.FloatField(verbose_name='经度') - created_time = models.DateTimeField('创建时间', default=now) + creation_time = models.DateTimeField('创建时间', default=now) def __str__(self): return self.tid class Meta: - ordering = ['created_time'] + ordering = ['creation_time'] verbose_name = "OwnTrackLogs" verbose_name_plural = verbose_name - get_latest_by = 'created_time' + get_latest_by = 'creation_time' diff --git a/owntracks/views.py b/owntracks/views.py index 27a89c8cd..859022c4a 100644 --- a/owntracks/views.py +++ b/owntracks/views.py @@ -59,7 +59,7 @@ def show_maps(request): @login_required def show_log_dates(request): - dates = OwnTrackLog.objects.values_list('created_time', flat=True) + dates = OwnTrackLog.objects.values_list('creation_time', flat=True) results = list(sorted(set(map(lambda x: x.strftime('%Y-%m-%d'), dates)))) context = { @@ -108,7 +108,7 @@ def get_datas(request): querydate = django.utils.timezone.make_aware(querydate) nextdate = querydate + datetime.timedelta(days=1) models = OwnTrackLog.objects.filter( - created_time__range=(querydate, nextdate)) + creation_time__range=(querydate, nextdate)) result = list() if models and len(models): for tid, item in groupby( diff --git a/servermanager/admin.py b/servermanager/admin.py index 361b92351..f26f4f6be 100644 --- a/servermanager/admin.py +++ b/servermanager/admin.py @@ -7,12 +7,12 @@ class CommandsAdmin(admin.ModelAdmin): class EmailSendLogAdmin(admin.ModelAdmin): - list_display = ('title', 'emailto', 'send_result', 'created_time') + list_display = ('title', 'emailto', 'send_result', 'creation_time') readonly_fields = ( 'title', 'emailto', 'send_result', - 'created_time', + 'creation_time', 'content') def has_add_permission(self, request): diff --git a/servermanager/migrations/0002_alter_emailsendlog_options_and_more.py b/servermanager/migrations/0002_alter_emailsendlog_options_and_more.py new file mode 100644 index 000000000..48588574b --- /dev/null +++ b/servermanager/migrations/0002_alter_emailsendlog_options_and_more.py @@ -0,0 +1,32 @@ +# Generated by Django 4.2.5 on 2023-09-06 13:19 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('servermanager', '0001_initial'), + ] + + operations = [ + migrations.AlterModelOptions( + name='emailsendlog', + options={'ordering': ['-creation_time'], 'verbose_name': '邮件发送log', 'verbose_name_plural': '邮件发送log'}, + ), + migrations.RenameField( + model_name='commands', + old_name='created_time', + new_name='creation_time', + ), + migrations.RenameField( + model_name='commands', + old_name='last_mod_time', + new_name='last_modify_time', + ), + migrations.RenameField( + model_name='emailsendlog', + old_name='created_time', + new_name='creation_time', + ), + ] diff --git a/servermanager/models.py b/servermanager/models.py index f75c93069..4326c6582 100644 --- a/servermanager/models.py +++ b/servermanager/models.py @@ -6,8 +6,8 @@ class commands(models.Model): title = models.CharField('命令标题', max_length=300) command = models.CharField('命令', max_length=2000) describe = models.CharField('命令描述', max_length=300) - created_time = models.DateTimeField('创建时间', auto_now_add=True) - last_mod_time = models.DateTimeField('修改时间', auto_now=True) + creation_time = models.DateTimeField('创建时间', auto_now_add=True) + last_modify_time = models.DateTimeField('修改时间', auto_now=True) def __str__(self): return self.title @@ -22,7 +22,7 @@ class EmailSendLog(models.Model): title = models.CharField('邮件标题', max_length=2000) content = models.TextField('邮件内容') send_result = models.BooleanField('结果', default=False) - created_time = models.DateTimeField('创建时间', auto_now_add=True) + creation_time = models.DateTimeField('创建时间', auto_now_add=True) def __str__(self): return self.title @@ -30,4 +30,4 @@ def __str__(self): class Meta: verbose_name = '邮件发送log' verbose_name_plural = verbose_name - ordering = ['-created_time'] + ordering = ['-creation_time'] diff --git a/servermanager/tests.py b/servermanager/tests.py index 40fa9ec99..22a66892e 100644 --- a/servermanager/tests.py +++ b/servermanager/tests.py @@ -30,8 +30,6 @@ def test_validate_comment(self): c = Category() c.name = "categoryccc" - c.created_time = timezone.now() - c.last_mod_time = timezone.now() c.save() article = Article() diff --git a/templates/account/forget_password.html b/templates/account/forget_password.html index 1016c14a0..338453155 100644 --- a/templates/account/forget_password.html +++ b/templates/account/forget_password.html @@ -1,9 +1,10 @@ {% extends 'share_layout/base_account.html' %} +{% load i18n %} {% load static %} {% block content %}
- + diff --git a/templates/account/result.html b/templates/account/result.html index 4bee77c63..23c909431 100644 --- a/templates/account/result.html +++ b/templates/account/result.html @@ -1,4 +1,5 @@ {% extends 'share_layout/base.html' %} +{% load i18n %} {% block header %} {{ title }} {% endblock %} @@ -13,9 +14,13 @@

{{ content }}


- 登录 + + {% trans 'login' %} + | - 回到首页 + + {% trans 'back to the homepage' %} +
diff --git a/templates/blog/article_archives.html b/templates/blog/article_archives.html index 971e2c51d..959319eee 100644 --- a/templates/blog/article_archives.html +++ b/templates/blog/article_archives.html @@ -1,9 +1,10 @@ {% extends 'share_layout/base.html' %} {% load blog_tags %} {% load cache %} +{% load i18n %} {% block header %} - 文章归档 | {{ SITE_DESCRIPTION }} + {% trans 'article archive' %} | {{ SITE_DESCRIPTION }} @@ -20,7 +21,7 @@
-

文章归档

+

{% trans 'article archive' %}

@@ -28,11 +29,11 @@ {% regroup article_list by pub_time.year as year_post_group %}
    {% for year in year_post_group %} -
  • {{ year.grouper }} 年 +
  • {{ year.grouper }} {% trans 'year' %} {% regroup year.list by pub_time.month as month_post_group %}
      {% for month in month_post_group %} -
    • {{ month.grouper }} 月 +
    • {{ month.grouper }} {% trans 'month' %}
        {% for article in month.list %}
      • {{ article.title }} diff --git a/templates/blog/tags/article_info.html b/templates/blog/tags/article_info.html index 993c978c2..3deec44fd 100644 --- a/templates/blog/tags/article_info.html +++ b/templates/blog/tags/article_info.html @@ -1,5 +1,6 @@ {% load blog_tags %} {% load cache %} +{% load i18n %}
        @@ -8,7 +9,7 @@

        {% if isindex %} {% if article.article_order > 0 %} 【置顶】{{ article.title }} + rel="bookmark">【{% trans 'pin to top' %}】{{ article.title }} {% else %} {{ article.title }} @@ -24,9 +25,9 @@

        rel="nofollow"> {% if article.comment_set and article.comment_set.count %} - {{ article.comment_set.count }}个评论 + {{ article.comment_set.count }} {% trans 'comments' %} {% else %} - 发表评论 + {% trans 'comment' %} {% endif %} @@ -54,14 +55,14 @@

        {% if article.show_toc %} {% get_markdown_toc article.body as toc %} - 目录: + {% trans 'toc' %}: {{ toc|safe }}
        {% endif %}
        - {{ article.body|custom_markdown|escape }} + {{ article.body|custom_markdown|escape }}
        {% endif %} diff --git a/templates/blog/tags/article_meta_info.html b/templates/blog/tags/article_meta_info.html index 40960557c..b6b2b056a 100644 --- a/templates/blog/tags/article_meta_info.html +++ b/templates/blog/tags/article_meta_info.html @@ -1,22 +1,25 @@ {% load blog_tags %} {% load cache %} +{% load i18n %} {% with article.id|add:user.is_authenticated as cachekey %} {% cache 36000 metainfo cachekey %} diff --git a/templates/blog/tags/article_pagination.html b/templates/blog/tags/article_pagination.html index ad3c2f46d..95514ff3d 100644 --- a/templates/blog/tags/article_pagination.html +++ b/templates/blog/tags/article_pagination.html @@ -1,12 +1,15 @@ +{% load i18n %}

{% endif %} {% if page_obj.has_previous and previous_url %} -