Merge pull request #679 from liangliangyy/dev

增加多语言支持
sh_branch
且听风吟 2 years ago committed by GitHub
commit 383613aa60
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,8 +1,6 @@
bin/data/
# virtualenv
venv/
migrations/
!migrations/__init__.py
collectedstatic/
djangoblog/whoosh_index/
uploads/

@ -1,8 +1,9 @@
FROM python:3
ENV PYTHONUNBUFFERED 1
WORKDIR /code/djangoblog/
RUN apt-get install default-libmysqlclient-dev -y && \
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
RUN apt-get update && \
apt-get install default-libmysqlclient-dev gettext -y && \
rm -rf /var/lib/apt/lists/*
ADD requirements.txt requirements.txt
RUN pip install --upgrade pip && \
pip install --no-cache-dir -r requirements.txt && \

@ -1,6 +1,5 @@
from django import forms
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.forms import ReadOnlyPasswordHashField
from django.contrib.auth.forms import UserChangeForm
from django.contrib.auth.forms import UsernameField
from django.utils.translation import gettext_lazy as _
@ -10,8 +9,8 @@ from .models import BlogUser
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 +21,7 @@ class BlogUserCreationForm(forms.ModelForm):
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):
@ -36,16 +35,6 @@ class BlogUserCreationForm(forms.ModelForm):
class BlogUserChangeForm(UserChangeForm):
password = ReadOnlyPasswordHashField(
label=_("Password"),
help_text=_(
"Raw passwords are not stored, so there is no way to see this "
"user's password, but you can change the password using "
"<a href=\"{}\">this form</a>."
),
)
email = forms.EmailField(label="Email", widget=forms.EmailInput)
class Meta:
model = BlogUser
fields = '__all__'

@ -3,7 +3,7 @@ from django.contrib.auth import get_user_model, password_validation
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 @@ class RegisterForm(UserCreationForm):
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 RegisterForm(UserCreationForm):
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 @@ class ForgetPasswordForm(forms.Form):
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 @@ class ForgetPasswordForm(forms.Form):
email=user_email
).exists():
# todo 这里的报错提示可以判断一个邮箱是不是注册过,如果不想暴露可以修改
raise ValidationError("未找到邮箱对应的用户")
raise ValidationError(_("email does not exist"))
return user_email
def clean_code(self):
@ -113,5 +113,5 @@ class ForgetPasswordForm(forms.Form):
class ForgetPasswordCodeForm(forms.Form):
email = forms.EmailField(
label="邮箱号"
label=_('Email'),
)

@ -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'),
),
]

@ -2,17 +2,17 @@ from django.contrib.auth.models import AbstractUser
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 @@ class BlogUser(AbstractUser):
class Meta:
ordering = ['-id']
verbose_name = "用户"
verbose_name = _('user')
verbose_name_plural = verbose_name
get_latest_by = 'id'

@ -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 @@ class AccountTest(TestCase):
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 @@ class AccountTest(TestCase):
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 @@ class AccountTest(TestCase):
response=resp,
form="form",
field="email",
errors="未找到邮箱对应的用户"
errors=_("email does not exist")
)
def test_forget_password_email_code_error(self):
@ -213,5 +213,5 @@ class AccountTest(TestCase):
response=resp,
form="form",
field="code",
errors="验证码错误"
errors=_('Verification code error')
)

@ -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 @@ from .forms import LoginForm
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'),
]

@ -2,20 +2,24 @@ import typing
from datetime import timedelta
from django.core.cache import cache
from django.utils.translation import gettext
from django.utils.translation import gettext_lazy as _
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 = _(
"You are resetting the password, the verification code is%(code)s, valid within 5 minutes, please keep it "
"properly") % {'code': code}
send_email([to_mail], subject, html_content)
@ -32,7 +36,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):

@ -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

@ -1,28 +1,25 @@
#!/usr/bin/env bash
NAME="djangoblog" # Name of the application
DJANGODIR=/code/djangoblog # Django project directory
USER=root # the user to run as
GROUP=root # the group to run as
NUM_WORKERS=1 # how many worker processes should Gunicorn spawn
#DJANGO_SETTINGS_MODULE=djangoblog.settings # which settings file should Django use
DJANGO_WSGI_MODULE=djangoblog.wsgi # WSGI module name
NAME="djangoblog"
DJANGODIR=/code/djangoblog
USER=root
GROUP=root
NUM_WORKERS=1
DJANGO_WSGI_MODULE=djangoblog.wsgi
echo "Starting $NAME as `whoami`"
# Activate the virtual environment
cd $DJANGODIR
export PYTHONPATH=$DJANGODIR:$PYTHONPATH
#pip install -Ur requirements.txt -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com && \
# pip install gunicorn -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com
python manage.py makemigrations && \
python manage.py migrate && \
python manage.py collectstatic --noinput && \
python manage.py compress --force && \
python manage.py build_index
# Start your Django Unicorn
# Programs meant to be run under supervisor should not daemonize themselves (do not use --daemon)
python manage.py build_index && \
python manage.py compilemessages
exec gunicorn ${DJANGO_WSGI_MODULE}:application \
--name $NAME \
--workers $NUM_WORKERS \

@ -10,7 +10,7 @@ from .models import Article
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 @@ class ArticlelAdmin(admin.ModelAdmin):
link = reverse('admin:%s_%s_change' % info, args=(obj.category.id,))
return format_html(u'<a href="%s">%s</a>' % (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 @@ class ArticlelAdmin(admin.ModelAdmin):
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):

@ -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'),
),
]

@ -17,17 +17,17 @@ logger = logging.getLogger(__name__)
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 @@ class BaseModel(models.Model):
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 @@ class Article(BaseModel):
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 @@ class Article(BaseModel):
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 @@ class Category(BaseModel):
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 @@ class Tag(BaseModel):
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 @@ class Links(models.Model):
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 @@ class SideBar(models.Model):
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(
@ -349,7 +349,7 @@ class BlogSettings(models.Model):
'评论是否需要审核', default=False, null=False)
class Meta:
verbose_name = '网站配置'
verbose_name = _('Website configuration')
verbose_name_plural = verbose_name
def __str__(self):
@ -357,7 +357,7 @@ class BlogSettings(models.Model):
def clean(self):
if BlogSettings.objects.exclude(id=self.id).count():
raise ValidationError(_('只能有一个配置'))
raise ValidationError(_('There can only be one configuration'))
def save(self, *args, **kwargs):
super().save(*args, **kwargs)

@ -30,42 +30,51 @@ $(document).ready(function () {
});
/** 侧边栏回到顶部 */
var rocket = $('#rocket');
$(window).on('scroll', debounce(slideTopSet, 300));
function debounce(func, wait) {
var timeout;
return function() {
clearTimeout(timeout);
timeout = setTimeout(func, wait);
};
};
var timeout;
return function () {
clearTimeout(timeout);
timeout = setTimeout(func, wait);
};
}
function slideTopSet() {
var top = $(document).scrollTop();
var top = $(document).scrollTop();
if (top > 200) {
rocket.addClass('show');
} else {
rocket.removeClass('show');
}
if (top > 200) {
rocket.addClass('show');
} else {
rocket.removeClass('show');
}
}
$(document).on('click', '#rocket', function(event) {
rocket.addClass('move');
$('body, html').animate({
scrollTop: 0
}, 800);
$(document).on('click', '#rocket', function (event) {
rocket.addClass('move');
$('body, html').animate({
scrollTop: 0
}, 800);
});
$(document).on('animationEnd', function() {
setTimeout(function() {
rocket.removeClass('move');
}, 400);
$(document).on('animationEnd', function () {
setTimeout(function () {
rocket.removeClass('move');
}, 400);
});
$(document).on('webkitAnimationEnd', function() {
setTimeout(function() {
rocket.removeClass('move');
}, 400);
$(document).on('webkitAnimationEnd', function () {
setTimeout(function () {
rocket.removeClass('move');
}, 400);
});
// $(document).ready(function () {
// var form = $('#i18n-form');
// var selector = $('.i18n-select');
// selector.on('change', function () {
// form.submit();
// });
// });

@ -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; }

@ -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(

@ -46,7 +46,7 @@ class ArticleTest(TestCase):
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 @@ class ArticleTest(TestCase):
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 @@ class ArticleTest(TestCase):
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

@ -55,4 +55,8 @@ urlpatterns = [
r'upload',
views.fileupload,
name='upload'),
path(
r'clean',
views.clean_cache_view,
name='clean'),
]

@ -9,6 +9,7 @@ from django.shortcuts import get_object_or_404
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
@ -344,7 +345,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 +353,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 +366,10 @@ 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)
def clean_cache_view(request):
cache.clear()
return HttpResponse('ok')

@ -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 @@ class CommentAdmin(admin.ModelAdmin):
return format_html(
u'<a href="%s">%s</a>' % (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')

@ -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'),
),
]

@ -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 @@ from blog.models import Article
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'

@ -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 @@ from djangoblog.utils import get_max_articleid_commentid
# Create your tests here.
class CommentsTest(TestCase):
class CommentsTest(TransactionTestCase):
def setUp(self):
self.client = Client()
self.factory = RequestFactory()
@ -20,6 +19,11 @@ class CommentsTest(TestCase):
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 @@ class CommentsTest(TestCase):
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'

@ -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 @@ logger = logging.getLogger(__name__)
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 = """
<p>非常感谢您在本站发表评论</p>
您可以访问
<a href="%s" rel="bookmark">%s</a>
来查看您的评论
再次感谢您
<br />
如果上面链接无法打开请将此链接复制至浏览器
%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 = _("""<p>Thank you very much for your comments on this site</p>
You can visit <a href="%(article_url)s" rel="bookmark">%(article_title)s</a>
to review your comments,
Thank you again!
<br />
If the link above cannot be opened, please copy this link to your browser.
%(article_url)s""") % {'article_url': article_url, 'article_title': comment.article.title}
tomail = comment.author.email
send_email([tomail], subject, html_content)
try:
if comment.parent_comment:
html_content = """
您在 <a href="%s" rel="bookmark">%s</a> 的评论 <br/> %s <br/> 收到回复啦.快去看看吧
<br/>
如果上面链接无法打开请将此链接复制至浏览器
%s
""" % (article_url, comment.article.title, comment.parent_comment.body, article_url)
html_content = _("""Your comment on <a href="%(article_url)s" rel="bookmark">%(article_title)s</a><br/> has
received a reply. <br/> %(comment_body)s
<br/>
go check it out!
<br/>
If the link above cannot be opened, please copy this link to your browser.
%(article_url)s
""") % {'article_url': article_url, 'article_title': comment.article.title,
'comment_body': comment.parent_comment.body}
tomail = comment.parent_comment.author.email
send_email([tomail], subject, html_content)
except Exception as e:

@ -6,6 +6,7 @@ from django.utils.decorators import method_decorator
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 @@ class CommentPostView(FormView):
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 @@ class CommentPostView(FormView):
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(

@ -1,45 +1,14 @@
from django.contrib import admin
from django.contrib.admin.models import LogEntry, ADDITION, CHANGE, DELETION
from django.contrib.admin.models import DELETION
from django.contrib.contenttypes.models import ContentType
from django.urls import reverse, NoReverseMatch
from django.utils.encoding import force_str
from django.utils.html import escape
from django.utils.safestring import mark_safe
from django.utils.translation import pgettext_lazy, gettext_lazy as _
action_names = {
ADDITION: pgettext_lazy('logentry_admin:action_type', 'Addition'),
DELETION: pgettext_lazy('logentry_admin:action_type', 'Deletion'),
CHANGE: pgettext_lazy('logentry_admin:action_type', 'Change'),
}
from django.utils.translation import gettext_lazy as _
class LogEntryAdmin(admin.ModelAdmin):
date_hierarchy = 'action_time'
readonly_fields = ([f.name for f in LogEntry._meta.fields] +
['object_link', 'action_description', 'user_link',
'get_change_message'])
fieldsets = (
(_('Metadata'), {
'fields': (
'action_time',
'user_link',
'action_description',
'object_link',
)
}),
(_('Details'), {
'fields': (
'get_change_message',
'content_type',
'object_id',
'object_repr',
)
}),
)
list_filter = [
'content_type'
]
@ -58,7 +27,6 @@ class LogEntryAdmin(admin.ModelAdmin):
'user_link',
'content_type',
'object_link',
'action_description',
'get_change_message',
]
@ -67,9 +35,9 @@ class LogEntryAdmin(admin.ModelAdmin):
def has_change_permission(self, request, obj=None):
return (
request.user.is_superuser or
request.user.has_perm('admin.change_logentry')
) and request.method != 'POST'
request.user.is_superuser or
request.user.has_perm('admin.change_logentry')
) and request.method != 'POST'
def has_delete_permission(self, request, obj=None):
return False
@ -121,13 +89,3 @@ class LogEntryAdmin(admin.ModelAdmin):
if 'delete_selected' in actions:
del actions['delete_selected']
return actions
def action_description(self, obj):
return action_names[obj.action_flag]
action_description.short_description = _('action')
def get_change_message(self, obj):
return obj.get_change_message()
get_change_message.short_description = _('change message')

@ -12,6 +12,8 @@ https://docs.djangoproject.com/en/1.10/ref/settings/
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 @@ INSTALLED_APPS = [
]
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 @@ AUTH_PASSWORD_VALIDATORS = [
},
]
# 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'

@ -23,7 +23,7 @@ class ArticleSiteMap(Sitemap):
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 @@ class CategorySiteMap(Sitemap):
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 @@ class TagSiteMap(Sitemap):
return Tag.objects.all()
def lastmod(self, obj):
return obj.last_mod_time
return obj.last_modify_time
class UserSiteMap(Sitemap):

@ -14,9 +14,10 @@ Including another URLconf
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 @@ sitemaps = {
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=False) + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL,
document_root=settings.MEDIA_ROOT)

@ -0,0 +1,685 @@
# 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 <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-09-13 16:02+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"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:12
msgid "password"
msgstr "password"
#: .\accounts\admin.py:13
msgid "Enter password again"
msgstr "Enter password again"
#: .\accounts\admin.py:24 .\accounts\forms.py:89
msgid "passwords do not match"
msgstr "passwords do not match"
#: .\accounts\forms.py:36
msgid "email already exists"
msgstr "email already exists"
#: .\accounts\forms.py:46 .\accounts\forms.py:50
msgid "New password"
msgstr "New password"
#: .\accounts\forms.py:60
msgid "Confirm password"
msgstr "Confirm 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 .\oauth\models.py:17
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:81
msgid "user"
msgstr "user"
#: .\accounts\tests.py:216 .\accounts\utils.py:39
msgid "Verification code error"
msgstr "Verification code error"
#: .\accounts\utils.py:13
msgid "Verify Email"
msgstr "Verify Email"
#: .\accounts\utils.py:21
#, python-format
msgid ""
"You are resetting the password, the verification code is%(code)s, valid "
"within 5 minutes, please keep it properly"
msgstr ""
"You are resetting the password, the verification code is%(code)s, valid "
"within 5 minutes, please keep it properly"
#: .\blog\admin.py:13 .\blog\models.py:92 .\comments\models.py:17
#: .\oauth\models.py:12
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\sidebar.html:40
msgid "category"
msgstr "category"
#: .\blog\models.py:20 .\blog\models.py:179 .\templates\share_layout\nav.html:8
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
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 "site description"
#: .\blog\models.py:311
msgid "site seo description"
msgstr "site seo description"
#: .\blog\models.py:313
msgid "site keywords"
msgstr "site keywords"
#: .\blog\models.py:318
msgid "article sub length"
msgstr "article sub length"
#: .\blog\models.py:319
msgid "sidebar article count"
msgstr "sidebar article count"
#: .\blog\models.py:320
msgid "sidebar comment count"
msgstr "sidebar comment count"
#: .\blog\models.py:321
msgid "article comment count"
msgstr "article comment count"
#: .\blog\models.py:322
msgid "show adsense"
msgstr "show adsense"
#: .\blog\models.py:324
msgid "adsense code"
msgstr "adsense code"
#: .\blog\models.py:325
msgid "open site comment"
msgstr "open site comment"
#: .\blog\models.py:352
msgid "Website configuration"
msgstr "Website configuration"
#: .\blog\models.py:360
msgid "There can only be one configuration"
msgstr "There can only be one configuration"
#: .\blog\views.py:348
msgid ""
"Sorry, the page you requested is not found, please click the home page to "
"see other?"
msgstr ""
"Sorry, the page you requested is not found, please click the home page to "
"see other?"
#: .\blog\views.py:356
msgid "Sorry, the server is busy, please click the home page to see other?"
msgstr "Sorry, the server is busy, please click the home page to see other?"
#: .\blog\views.py:369
msgid "Sorry, you do not have permission to access this page?"
msgstr "Sorry, you do not have permission to access this page?"
#: .\comments\admin.py:15
msgid "Disable comments"
msgstr "Disable comments"
#: .\comments\admin.py:16
msgid "Enable comments"
msgstr "Enable comments"
#: .\comments\admin.py:46
msgid "User"
msgstr "User"
#: .\comments\models.py:25
msgid "parent comment"
msgstr "parent comment"
#: .\comments\models.py:29
msgid "enable"
msgstr "enable"
#: .\comments\models.py:34 .\templates\blog\tags\article_info.html:30
msgid "comment"
msgstr "comment"
#: .\comments\utils.py:13
msgid "Thanks for your comment"
msgstr "Thanks for your comment"
#: .\comments\utils.py:15
#, python-format
msgid ""
"<p>Thank you very much for your comments on this site</p>\n"
" You can visit <a href=\"%(article_url)s\" rel=\"bookmark"
"\">%(article_title)s</a>\n"
" to review your comments,\n"
" Thank you again!\n"
" <br />\n"
" If the link above cannot be opened, please copy this "
"link to your browser.\n"
" %(article_url)s"
msgstr ""
"<p>Thank you very much for your comments on this site</p>\n"
" You can visit <a href=\"%(article_url)s\" rel=\"bookmark"
"\">%(article_title)s</a>\n"
" to review your comments,\n"
" Thank you again!\n"
" <br />\n"
" If the link above cannot be opened, please copy this "
"link to your browser.\n"
" %(article_url)s"
#: .\comments\utils.py:26
#, python-format
msgid ""
"Your comment on <a href=\"%(article_url)s\" rel=\"bookmark\">"
"%(article_title)s</a><br/> has \n"
" received a reply. <br/> %(comment_body)s\n"
" <br/> \n"
" go check it out!\n"
" <br/>\n"
" If the link above cannot be opened, please copy this "
"link to your browser.\n"
" %(article_url)s\n"
" "
msgstr ""
"Your comment on <a href=\"%(article_url)s\" rel=\"bookmark\">"
"%(article_title)s</a><br/> has \n"
" received a reply. <br/> %(comment_body)s\n"
" <br/> \n"
" go check it out!\n"
" <br/>\n"
" If the link above cannot be opened, please copy this "
"link to your browser.\n"
" %(article_url)s\n"
" "
#: .\djangoblog\logentryadmin.py:63
msgid "object"
msgstr "object"
#: .\djangoblog\settings.py:140
msgid "English"
msgstr "English"
#: .\djangoblog\settings.py:141
msgid "Simplified Chinese"
msgstr "Simplified Chinese"
#: .\djangoblog\settings.py:142
msgid "Traditional Chinese"
msgstr "Traditional Chinese"
#: .\oauth\models.py:30
msgid "oauth user"
msgstr "oauth user"
#: .\oauth\models.py:37
msgid "weibo"
msgstr "weibo"
#: .\oauth\models.py:38
msgid "google"
msgstr "google"
#: .\oauth\models.py:48
msgid "callback url"
msgstr "callback url"
#: .\oauth\models.py:59
msgid "already exists"
msgstr "already exists"
#: .\oauth\views.py:154
#, python-format
msgid ""
"\n"
" <p>Congratulations, you have successfully bound your email address. You "
"can use\n"
" %(oauthuser_type)s to directly log in to this website without a "
"password.</p>\n"
" You are welcome to continue to follow this site, the address is\n"
" <a href=\"%(site)s\" rel=\"bookmark\">%(site)s</a>\n"
" Thank you again!\n"
" <br />\n"
" If the link above cannot be opened, please copy this link to your "
"browser.\n"
" %(site)s\n"
" "
msgstr ""
"\n"
" <p>Congratulations, you have successfully bound your email address. You "
"can use\n"
" %(oauthuser_type)s to directly log in to this website without a "
"password.</p>\n"
" You are welcome to continue to follow this site, the address is\n"
" <a href=\"%(site)s\" rel=\"bookmark\">%(site)s</a>\n"
" Thank you again!\n"
" <br />\n"
" If the link above cannot be opened, please copy this link to your "
"browser.\n"
" %(site)s\n"
" "
#: .\oauth\views.py:165
msgid "Congratulations on your successful binding!"
msgstr "Congratulations on your successful binding!"
#: .\oauth\views.py:217
#, python-format
msgid ""
"\n"
" <p>Please click the link below to bind your email</p>\n"
"\n"
" <a href=\"%(url)s\" rel=\"bookmark\">%(url)s</a>\n"
"\n"
" Thank you again!\n"
" <br />\n"
" If the link above cannot be opened, please copy this link "
"to your browser.\n"
" <br />\n"
" %(url)s\n"
" "
msgstr ""
"\n"
" <p>Please click the link below to bind your email</p>\n"
"\n"
" <a href=\"%(url)s\" rel=\"bookmark\">%(url)s</a>\n"
"\n"
" Thank you again!\n"
" <br />\n"
" If the link above cannot be opened, please copy this link "
"to your browser.\n"
" <br />\n"
" %(url)s\n"
" "
#: .\oauth\views.py:228 .\oauth\views.py:240
msgid "Bind your email"
msgstr "Bind your email"
#: .\oauth\views.py:242
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 ""
"Congratulations, the binding is just one step away. Please log in to your "
"email to check the email to complete the binding. Thank you."
#: .\oauth\views.py:245
msgid "Binding successful"
msgstr "Binding successful"
#: .\oauth\views.py:247
#, python-format
msgid ""
"Congratulations, you have successfully bound your email address. You can use "
"%(oauthuser_type)s to directly log in to this website without a password. "
"You are welcome to continue to follow this site."
msgstr ""
"Congratulations, you have successfully bound your email address. You can use "
"%(oauthuser_type)s to directly log in to this website without a password. "
"You are welcome to continue to follow this site."
#: .\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\login.html:36
msgid "Create Account"
msgstr "Create Account"
#: .\templates\account\login.html:42
#, fuzzy
#| msgid "forget the password"
msgid "Forget Password"
msgstr "forget the password"
#: .\templates\account\result.html:18 .\templates\blog\tags\sidebar.html:126
msgid "login"
msgstr "login"
#: .\templates\account\result.html:22
msgid "back to the homepage"
msgstr "back to the homepage"
#: .\templates\blog\article_archives.html:7
#: .\templates\blog\article_archives.html:24
msgid "article archive"
msgstr "article archive"
#: .\templates\blog\article_archives.html:32
msgid "year"
msgstr "year"
#: .\templates\blog\article_archives.html:36
msgid "month"
msgstr "month"
#: .\templates\blog\tags\article_info.html:12
msgid "pin to top"
msgstr "pin to top"
#: .\templates\blog\tags\article_info.html:28
msgid "comments"
msgstr "comments"
#: .\templates\blog\tags\article_info.html:58
msgid "toc"
msgstr "toc"
#: .\templates\blog\tags\article_meta_info.html:6
msgid "posted in"
msgstr "posted in"
#: .\templates\blog\tags\article_meta_info.html:14
msgid "and tagged"
msgstr "and tagged"
#: .\templates\blog\tags\article_meta_info.html:25
msgid "by "
msgstr "by"
#: .\templates\blog\tags\article_meta_info.html:29
#, 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:44
msgid "on"
msgstr "on"
#: .\templates\blog\tags\article_meta_info.html:54
msgid "edit"
msgstr "edit"
#: .\templates\blog\tags\article_pagination.html:4
msgid "article navigation"
msgstr "article navigation"
#: .\templates\blog\tags\article_pagination.html:9
msgid "earlier articles"
msgstr "earlier articles"
#: .\templates\blog\tags\article_pagination.html:12
msgid "newer articles"
msgstr "newer articles"
#: .\templates\blog\tags\article_tag_list.html:5
msgid "tags"
msgstr "tags"
#: .\templates\blog\tags\sidebar.html:7
msgid "search"
msgstr "search"
#: .\templates\blog\tags\sidebar.html:50
msgid "recent comments"
msgstr "recent comments"
#: .\templates\blog\tags\sidebar.html:57
msgid "published on"
msgstr "published on"
#: .\templates\blog\tags\sidebar.html:65
msgid "recent articles"
msgstr "recent articles"
#: .\templates\blog\tags\sidebar.html:77
msgid "bookmark"
msgstr "bookmark"
#: .\templates\blog\tags\sidebar.html:96
msgid "Tag Cloud"
msgstr "Tag Cloud"
#: .\templates\blog\tags\sidebar.html:107
msgid "Welcome to star or fork the source code of this site"
msgstr "Welcome to star or fork the source code of this site"
#: .\templates\blog\tags\sidebar.html:118
msgid "Function"
msgstr "Function"
#: .\templates\blog\tags\sidebar.html:120
msgid "management site"
msgstr "management site"
#: .\templates\blog\tags\sidebar.html:122
msgid "logout"
msgstr "logout"
#: .\templates\blog\tags\sidebar.html:129
msgid "Track record"
msgstr "Track record"
#: .\templates\blog\tags\sidebar.html:135
msgid "Click me to return to the top"
msgstr "Click me to return to the top"
#: .\templates\oauth\oauth_applications.html:5
#| msgid "login"
msgid "quick login"
msgstr "quick login"
#: .\templates\share_layout\nav.html:26
msgid "Article archive"
msgstr "Article archive"

@ -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 <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-09-13 16:02+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"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:12
msgid "password"
msgstr "密码"
#: .\accounts\admin.py:13
msgid "Enter password again"
msgstr "再次输入密码"
#: .\accounts\admin.py:24 .\accounts\forms.py:89
msgid "passwords do not match"
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 .\oauth\models.py:17
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:81
msgid "user"
msgstr "用户"
#: .\accounts\tests.py:216 .\accounts\utils.py:39
msgid "Verification code error"
msgstr "验证码错误"
#: .\accounts\utils.py:13
msgid "Verify Email"
msgstr "验证邮箱"
#: .\accounts\utils.py:21
#, python-format
msgid ""
"You are resetting the password, the verification code is%(code)s, valid "
"within 5 minutes, please keep it properly"
msgstr "您正在重置密码,验证码为:%(code)s5分钟内有效 请妥善保管."
#: .\blog\admin.py:13 .\blog\models.py:92 .\comments\models.py:17
#: .\oauth\models.py:12
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\sidebar.html:40
msgid "category"
msgstr "分类目录"
#: .\blog\models.py:20 .\blog\models.py:179 .\templates\share_layout\nav.html:8
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
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:352
msgid "Website configuration"
msgstr "网站配置"
#: .\blog\models.py:360
msgid "There can only be one configuration"
msgstr "只能有一个配置"
#: .\blog\views.py:348
msgid ""
"Sorry, the page you requested is not found, please click the home page to "
"see other?"
msgstr "抱歉,你所访问的页面找不到,请点击首页看看别的?"
#: .\blog\views.py:356
msgid "Sorry, the server is busy, please click the home page to see other?"
msgstr "抱歉,服务出错了,请点击首页看看别的?"
#: .\blog\views.py:369
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-format
msgid ""
"<p>Thank you very much for your comments on this site</p>\n"
" You can visit <a href=\"%(article_url)s\" rel=\"bookmark"
"\">%(article_title)s</a>\n"
" to review your comments,\n"
" Thank you again!\n"
" <br />\n"
" If the link above cannot be opened, please copy this "
"link to your browser.\n"
" %(article_url)s"
msgstr ""
"<p>非常感谢您对此网站的评论</p>\n"
" 您可以访问<a href=\"%(article_url)s\" rel=\"书签\">%(article_title)s</a>\n"
"查看您的评论,\n"
"再次感谢您!\n"
" <br />\n"
" 如果上面的链接打不开,请复制此链接链接到您的浏览器。\n"
"%(article_url)s"
#: .\comments\utils.py:26
#, python-format
msgid ""
"Your comment on <a href=\"%(article_url)s\" rel=\"bookmark\">"
"%(article_title)s</a><br/> has \n"
" received a reply. <br/> %(comment_body)s\n"
" <br/> \n"
" go check it out!\n"
" <br/>\n"
" If the link above cannot be opened, please copy this "
"link to your browser.\n"
" %(article_url)s\n"
" "
msgstr ""
"您对 <a href=\"%(article_url)s\" rel=\"bookmark\">%(article_title)s</a><br/> "
"的评论有\n"
" 收到回复。<br/> %(comment_body)s\n"
"<br/>\n"
"快去看看吧!\n"
"<br/>\n"
" 如果上面的链接打不开,请复制此链接链接到您的浏览器。\n"
" %(article_url)s\n"
" "
#: .\djangoblog\logentryadmin.py:63
msgid "object"
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: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
#, python-format
msgid ""
"\n"
" <p>Congratulations, you have successfully bound your email address. You "
"can use\n"
" %(oauthuser_type)s to directly log in to this website without a "
"password.</p>\n"
" You are welcome to continue to follow this site, the address is\n"
" <a href=\"%(site)s\" rel=\"bookmark\">%(site)s</a>\n"
" Thank you again!\n"
" <br />\n"
" If the link above cannot be opened, please copy this link to your "
"browser.\n"
" %(site)s\n"
" "
msgstr ""
"\n"
" <p>恭喜你已经绑定成功 你可以使用\n"
" %(oauthuser_type)s 来免密登录本站 </p>\n"
" 欢迎继续关注本站, 地址是\n"
" <a href=\"%(site)s\" rel=\"bookmark\">%(site)s</a>\n"
" 再次感谢你\n"
" <br />\n"
" 如果上面链接无法打开,请复制此链接到你的浏览器 \n"
" %(site)s\n"
" "
#: .\oauth\views.py:165
msgid "Congratulations on your successful binding!"
msgstr "恭喜你绑定成功"
#: .\oauth\views.py:217
#, python-format
msgid ""
"\n"
" <p>Please click the link below to bind your email</p>\n"
"\n"
" <a href=\"%(url)s\" rel=\"bookmark\">%(url)s</a>\n"
"\n"
" Thank you again!\n"
" <br />\n"
" If the link above cannot be opened, please copy this link "
"to your browser.\n"
" <br />\n"
" %(url)s\n"
" "
msgstr ""
"\n"
" <p>请点击下面的链接绑定您的邮箱</p>\n"
"\n"
" <a href=\"%(url)s\" rel=\"bookmark\">%(url)s</a>\n"
"\n"
"再次感谢您!\n"
" <br />\n"
"如果上面的链接打不开,请复制此链接到您的浏览器。\n"
"%(url)s\n"
" "
#: .\oauth\views.py:228 .\oauth\views.py:240
msgid "Bind your email"
msgstr "绑定邮箱"
#: .\oauth\views.py:242
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:245
msgid "Binding successful"
msgstr "绑定成功"
#: .\oauth\views.py:247
#, python-format
msgid ""
"Congratulations, you have successfully bound your email address. You can use "
"%(oauthuser_type)s to directly log in to this website without a password. "
"You are welcome to continue to follow this site."
msgstr ""
"恭喜您绑定成功,您以后可以使用%(oauthuser_type)s来直接免密码登录本站啦感谢"
"您对本站对关注。"
#: .\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\login.html:36
msgid "Create Account"
msgstr "创建账号"
#: .\templates\account\login.html:42
#| msgid "forget the password"
msgid "Forget Password"
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:6
msgid "posted in"
msgstr "发布于"
#: .\templates\blog\tags\article_meta_info.html:14
msgid "and tagged"
msgstr "并标记为"
#: .\templates\blog\tags\article_meta_info.html:25
msgid "by "
msgstr "由"
#: .\templates\blog\tags\article_meta_info.html:29
#, 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:44
msgid "on"
msgstr "在"
#: .\templates\blog\tags\article_meta_info.html:54
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 on"
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 "欢迎您STAR或者FORK本站源代码"
#: .\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 "点我返回顶部"
#: .\templates\oauth\oauth_applications.html:5
#| msgid "login"
msgid "quick login"
msgstr "快捷登录"
#: .\templates\share_layout\nav.html:26
msgid "Article archive"
msgstr "文章归档"

@ -0,0 +1,668 @@
# 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 <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-09-13 16:02+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"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:12
msgid "password"
msgstr "密碼"
#: .\accounts\admin.py:13
msgid "Enter password again"
msgstr "再次輸入密碼"
#: .\accounts\admin.py:24 .\accounts\forms.py:89
msgid "passwords do not match"
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 .\oauth\models.py:17
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:81
msgid "user"
msgstr "用戶"
#: .\accounts\tests.py:216 .\accounts\utils.py:39
msgid "Verification code error"
msgstr "驗證碼錯誤"
#: .\accounts\utils.py:13
msgid "Verify Email"
msgstr "驗證郵箱"
#: .\accounts\utils.py:21
#, python-format
msgid ""
"You are resetting the password, the verification code is%(code)s, valid "
"within 5 minutes, please keep it properly"
msgstr "您正在重置密碼,驗證碼為:%(code)s5分鐘內有效 請妥善保管."
#: .\blog\admin.py:13 .\blog\models.py:92 .\comments\models.py:17
#: .\oauth\models.py:12
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\sidebar.html:40
msgid "category"
msgstr "分類目錄"
#: .\blog\models.py:20 .\blog\models.py:179 .\templates\share_layout\nav.html:8
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
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:352
msgid "Website configuration"
msgstr "網站配置"
#: .\blog\models.py:360
msgid "There can only be one configuration"
msgstr "只能有一個配置"
#: .\blog\views.py:348
msgid ""
"Sorry, the page you requested is not found, please click the home page to "
"see other?"
msgstr "抱歉,你所訪問的頁面找不到,請點擊首頁看看別的?"
#: .\blog\views.py:356
msgid "Sorry, the server is busy, please click the home page to see other?"
msgstr "抱歉,服務出錯了,請點擊首頁看看別的?"
#: .\blog\views.py:369
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-format
msgid ""
"<p>Thank you very much for your comments on this site</p>\n"
" You can visit <a href=\"%(article_url)s\" rel=\"bookmark"
"\">%(article_title)s</a>\n"
" to review your comments,\n"
" Thank you again!\n"
" <br />\n"
" If the link above cannot be opened, please copy this "
"link to your browser.\n"
" %(article_url)s"
msgstr ""
"<p>非常感謝您對此網站的評論</p>\n"
" 您可以訪問<a href=\"%(article_url)s\" rel=\"書簽\">%(article_title)s</a>\n"
"查看您的評論,\n"
"再次感謝您!\n"
" <br />\n"
" 如果上面的鏈接打不開,請復製此鏈接鏈接到您的瀏覽器。\n"
"%(article_url)s"
#: .\comments\utils.py:26
#, python-format
msgid ""
"Your comment on <a href=\"%(article_url)s\" rel=\"bookmark\">"
"%(article_title)s</a><br/> has \n"
" received a reply. <br/> %(comment_body)s\n"
" <br/> \n"
" go check it out!\n"
" <br/>\n"
" If the link above cannot be opened, please copy this "
"link to your browser.\n"
" %(article_url)s\n"
" "
msgstr ""
"您對 <a href=\"%(article_url)s\" rel=\"bookmark\">%(article_title)s</a><br/> "
"的評論有\n"
" 收到回復。<br/> %(comment_body)s\n"
"<br/>\n"
"快去看看吧!\n"
"<br/>\n"
" 如果上面的鏈接打不開,請復製此鏈接鏈接到您的瀏覽器。\n"
" %(article_url)s\n"
" "
#: .\djangoblog\logentryadmin.py:63
msgid "object"
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: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
#, python-format
msgid ""
"\n"
" <p>Congratulations, you have successfully bound your email address. You "
"can use\n"
" %(oauthuser_type)s to directly log in to this website without a "
"password.</p>\n"
" You are welcome to continue to follow this site, the address is\n"
" <a href=\"%(site)s\" rel=\"bookmark\">%(site)s</a>\n"
" Thank you again!\n"
" <br />\n"
" If the link above cannot be opened, please copy this link to your "
"browser.\n"
" %(site)s\n"
" "
msgstr ""
"\n"
" <p>恭喜你已經綁定成功 你可以使用\n"
" %(oauthuser_type)s 來免密登錄本站 </p>\n"
" 歡迎繼續關註本站, 地址是\n"
" <a href=\"%(site)s\" rel=\"bookmark\">%(site)s</a>\n"
" 再次感謝你\n"
" <br />\n"
" 如果上面鏈接無法打開,請復製此鏈接到你的瀏覽器 \n"
" %(site)s\n"
" "
#: .\oauth\views.py:165
msgid "Congratulations on your successful binding!"
msgstr "恭喜你綁定成功"
#: .\oauth\views.py:217
#, python-format
msgid ""
"\n"
" <p>Please click the link below to bind your email</p>\n"
"\n"
" <a href=\"%(url)s\" rel=\"bookmark\">%(url)s</a>\n"
"\n"
" Thank you again!\n"
" <br />\n"
" If the link above cannot be opened, please copy this link "
"to your browser.\n"
" <br />\n"
" %(url)s\n"
" "
msgstr ""
"\n"
" <p>請點擊下面的鏈接綁定您的郵箱</p>\n"
"\n"
" <a href=\"%(url)s\" rel=\"bookmark\">%(url)s</a>\n"
"\n"
"再次感謝您!\n"
" <br />\n"
"如果上面的鏈接打不開,請復製此鏈接到您的瀏覽器。\n"
"%(url)s\n"
" "
#: .\oauth\views.py:228 .\oauth\views.py:240
msgid "Bind your email"
msgstr "綁定郵箱"
#: .\oauth\views.py:242
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:245
msgid "Binding successful"
msgstr "綁定成功"
#: .\oauth\views.py:247
#, python-format
msgid ""
"Congratulations, you have successfully bound your email address. You can use "
"%(oauthuser_type)s to directly log in to this website without a password. "
"You are welcome to continue to follow this site."
msgstr ""
"恭喜您綁定成功,您以後可以使用%(oauthuser_type)s來直接免密碼登錄本站啦感謝"
"您對本站對關註。"
#: .\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\login.html:36
msgid "Create Account"
msgstr "創建賬號"
#: .\templates\account\login.html:42
#, fuzzy
#| msgid "forget the password"
msgid "Forget Password"
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:6
msgid "posted in"
msgstr "發布於"
#: .\templates\blog\tags\article_meta_info.html:14
msgid "and tagged"
msgstr "並標記為"
#: .\templates\blog\tags\article_meta_info.html:25
msgid "by "
msgstr "由"
#: .\templates\blog\tags\article_meta_info.html:29
#, 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:44
msgid "on"
msgstr "在"
#: .\templates\blog\tags\article_meta_info.html:54
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 on"
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 "歡迎您STAR或者FORK本站源代碼"
#: .\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 "點我返回頂部"
#: .\templates\oauth\oauth_applications.html:5
#| msgid "login"
msgid "quick login"
msgstr "快捷登錄"
#: .\templates\share_layout\nav.html:26
msgid "Article archive"
msgstr "文章歸檔"

@ -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'),
),
]

@ -9,54 +9,54 @@ from django.utils.translation import gettext_lazy as _
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=_('nick name'))
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 @@ class OAuthConfig(models.Model):
class Meta:
verbose_name = 'oauth配置'
verbose_name_plural = verbose_name
ordering = ['-created_time']
ordering = ['-creation_time']

@ -13,6 +13,7 @@ from django.shortcuts import get_object_or_404
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 = '''
<p>恭喜您您已经成功绑定您的邮箱您可以使用{type}来直接免密码登录本网站.欢迎您继续关注本站地址是</p>
<a href="{url}" rel="bookmark">{url}</a>
再次感谢您
<br />
如果上面链接无法打开请将此链接复制至浏览器
{url}
'''.format(type=oauthuser.type, url='http://' + site)
send_email(emailto=[oauthuser.email, ], title='恭喜您绑定成功!', content=content)
site = 'http://' + get_current_site().domain
content = _('''
<p>Congratulations, you have successfully bound your email address. You can use
%(oauthuser_type)s to directly log in to this website without a password.</p>
You are welcome to continue to follow this site, the address is
<a href="%(site)s" rel="bookmark">%(site)s</a>
Thank you again!
<br />
If the link above cannot be opened, please copy this link to your browser.
%(site)s
''') % {'oauthuser_type': oauthuser.type, 'site': site}
send_email(emailto=[oauthuser.email, ], title=_('Congratulations on your successful binding!'), content=content)
url = reverse('oauth:bindsuccess', kwargs={
'oauthid': id
})
@ -213,17 +214,18 @@ class RequireEmailView(FormView):
})
url = "http://{site}{path}".format(site=site, path=path)
content = """
<p>请点击下面链接绑定您的邮箱</p>
content = _("""
<p>Please click the link below to bind your email</p>
<a href="{url}" rel="bookmark">{url}</a>
<a href="%(url)s" rel="bookmark">%(url)s</a>
再次感谢您
<br />
如果上面链接无法打开请将此链接复制至浏览器
{url}
""".format(url=url)
send_email(emailto=[email, ], title='绑定您的电子邮箱', content=content)
Thank you again!
<br />
If the link above cannot be opened, please copy this link to your browser.
<br />
%(url)s
""") % {'url': url}
send_email(emailto=[email, ], title=_('Bind your email'), content=content)
url = reverse('oauth:bindsuccess', kwargs={
'oauthid': oauthid
})
@ -235,12 +237,16 @@ 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 = _(
"Congratulations, you have successfully bound your email address. You can use %(oauthuser_type)s"
" to directly log in to this website without a password. You are welcome to continue to follow this site." % {
'oauthuser_type': oauthuser.type})
return render(request, 'oauth/bindsuccess.html', {
'title': title,
'content': content

@ -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',
),
]

@ -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'

@ -5,12 +5,14 @@ import json
import logging
from itertools import groupby
import django.utils.timezone
import requests
from django.contrib.auth.decorators import login_required
from django.http import HttpResponse
from django.http import JsonResponse
from django.shortcuts import render
from django.utils import timezone
from django.utils.timezone import utc
from django.views.decorators.csrf import csrf_exempt
from .models import OwnTrackLog
@ -59,7 +61,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 = {
@ -95,9 +97,6 @@ def convert_to_amap(locations):
@login_required
def get_datas(request):
import django.utils.timezone
from django.utils.timezone import utc
now = django.utils.timezone.now().replace(tzinfo=utc)
querydate = django.utils.timezone.datetime(
now.year, now.month, now.day, 0, 0, 0)
@ -108,7 +107,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(
@ -118,7 +117,7 @@ def get_datas(request):
d["name"] = tid
paths = list()
locations = convert_to_amap(
sorted(item, key=lambda x: x.created_time))
sorted(item, key=lambda x: x.creation_time))
for i in locations.split(';'):
paths.append(i.split(','))
d["path"] = paths

@ -1,4 +1,4 @@
coverage==7.3.0
coverage==7.3.1
bleach==6.0.0
Django==4.2.5
django-compressor==4.4
@ -8,7 +8,7 @@ django-mdeditor==0.1.20
django-uuslug==2.0.0
elasticsearch==7.16.1
elasticsearch-dsl==7.4.0
gevent==23.9.0.post1
gevent==23.9.1
jieba==0.42.1
jsonpickle==3.0.2
Markdown==3.4.4
@ -17,7 +17,7 @@ Pillow==10.0.0
Pygments==2.16.1
python-logstash==0.4.8
python-slugify==8.0.1
pytz==2023.3
pytz==2023.3.post1
requests==2.31.0
WeRoBot==1.13.1
Whoosh==2.7.4

@ -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):

@ -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',
),
]

@ -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 @@ class EmailSendLog(models.Model):
class Meta:
verbose_name = '邮件发送log'
verbose_name_plural = verbose_name
ordering = ['-created_time']
ordering = ['-creation_time']

@ -30,8 +30,6 @@ class ServerManagerTest(TestCase):
c = Category()
c.name = "categoryccc"
c.created_time = timezone.now()
c.last_mod_time = timezone.now()
c.save()
article = Article()

@ -1,9 +1,10 @@
{% extends 'share_layout/base_account.html' %}
{% load i18n %}
{% load static %}
{% block content %}
<div class="container">
<h2 class="form-signin-heading text-center">忘记密码</h2>
<h2 class="form-signin-heading text-center">{% trans 'forget the password' %}</h2>
<div class="card card-signin">
<img class="img-circle profile-img" src="{% static 'blog/img/avatar.png' %}" alt="">
@ -14,8 +15,8 @@
{{ field }}
{{ field.errors }}
{% endfor %}
<input type="button" class="button" id="btn" value="获取验证码">
<button class="btn btn-lg btn-primary btn-block" type="submit">提交</button>
<input type="button" class="button" id="btn" value="{% trans 'get verification code' %}">
<button class="btn btn-lg btn-primary btn-block" type="submit">{% trans 'submit' %}</button>
</form>
</div>

@ -1,5 +1,6 @@
{% extends 'share_layout/base_account.html' %}
{% load static %}
{% load i18n %}
{% block content %}
<div class="container">
@ -9,10 +10,6 @@
<img class="img-circle profile-img" src="{% static 'blog/img/avatar.png' %}" alt="">
<form class="form-signin" action="{% url 'account:login' %}" method="post">
{% csrf_token %}
{% comment %}<label for="inputEmail" class="sr-only">Email address</label>
<input type="email" id="inputEmail" class="form-control" placeholder="Email" required autofocus>
<label for="inputPassword" class="sr-only">Password</label>
<input type="password" id="inputPassword" class="form-control" placeholder="Password" required>{% endcomment %}
{{ form.non_field_errors }}
{% for field in form %}
{{ field }}
@ -34,11 +31,15 @@
</div>
<p class="text-center">
<a href="{% url "account:register" %}">Create Account</a>
<a href="{% url "account:register" %}">
{% trans 'Create Account' %}
</a>
|
<a href="/">Home Page</a>
|
<a href="{% url "account:forget_password" %}">忘记密码</a>
<a href="{% url "account:forget_password" %}">
{% trans 'Forget Password' %}
</a>
</p>
</div> <!-- /container -->

@ -1,4 +1,5 @@
{% extends 'share_layout/base.html' %}
{% load i18n %}
{% block header %}
<title> {{ title }}</title>
{% endblock %}
@ -13,9 +14,13 @@
<br/>
<header class="archive-header" style="text-align: center">
<a href="{% url "account:login" %}">登录</a>
<a href="{% url "account:login" %}">
{% trans 'login' %}
</a>
|
<a href="/">回到首页</a>
<a href="/">
{% trans 'back to the homepage' %}
</a>
</header><!-- .archive-header -->
</div>
</div>

@ -1,9 +1,10 @@
{% extends 'share_layout/base.html' %}
{% load blog_tags %}
{% load cache %}
{% load i18n %}
{% block header %}
<title>文章归档 | {{ SITE_DESCRIPTION }}</title>
<title>{% trans 'article archive' %} | {{ SITE_DESCRIPTION }}</title>
<meta name="description" content="{{ SITE_SEO_DESCRIPTION }}"/>
<meta name="keywords" content="{{ SITE_KEYWORDS }}"/>
@ -20,7 +21,7 @@
<header class="archive-header">
<p class="archive-title">文章归档</p>
<p class="archive-title">{% trans 'article archive' %}</p>
</header><!-- .archive-header -->
<div class="entry-content">
@ -28,11 +29,11 @@
{% regroup article_list by pub_time.year as year_post_group %}
<ul>
{% for year in year_post_group %}
<li>{{ year.grouper }}
<li>{{ year.grouper }} {% trans 'year' %}
{% regroup year.list by pub_time.month as month_post_group %}
<ul>
{% for month in month_post_group %}
<li>{{ month.grouper }}
<li>{{ month.grouper }} {% trans 'month' %}
<ul>
{% for article in month.list %}
<li><a href="{{ article.get_absolute_url }}">{{ article.title }}</a>

@ -1,5 +1,6 @@
{% load blog_tags %}
{% load cache %}
{% load i18n %}
<article id="post-{{ article.pk }} "
class="post-{{ article.pk }} post type-post status-publish format-standard hentry">
<header class="entry-header">
@ -8,7 +9,7 @@
{% if isindex %}
{% if article.article_order > 0 %}
<a href="{{ article.get_absolute_url }}"
rel="bookmark">【置顶】{{ article.title }}</a>
rel="bookmark">【{% trans 'pin to top' %}】{{ article.title }}</a>
{% else %}
<a href="{{ article.get_absolute_url }}"
rel="bookmark">{{ article.title }}</a>
@ -24,9 +25,9 @@
rel="nofollow">
<span class="leave-reply">
{% if article.comment_set and article.comment_set.count %}
{{ article.comment_set.count }}个评论
{{ article.comment_set.count }} {% trans 'comments' %}
{% else %}
发表评论
{% trans 'comment' %}
{% endif %}
</span>
</a>
@ -54,14 +55,14 @@
{% if article.show_toc %}
{% get_markdown_toc article.body as toc %}
<b>目录:</b>
<b>{% trans 'toc' %}:</b>
{{ toc|safe }}
<hr class="break_line"/>
{% endif %}
<div class="article">
{{ article.body|custom_markdown|escape }}
{{ article.body|custom_markdown|escape }}
</div>
{% endif %}

@ -1,36 +1,34 @@
{% load i18n %}
{% load blog_tags %}
{% load cache %}
{% with article.id|add:user.is_authenticated as cachekey %}
{% cache 36000 metainfo cachekey %}
<footer class="entry-meta">
本条目发布于<a href="{{ article.get_absolute_url }}" title="{% datetimeformat article.pub_time %}"
itemprop="datePublished" content="{% datetimeformat article.pub_time %}"
rel="bookmark">
<time class="entry-date updated"
datetime="{{ article.pub_time }}">
{% datetimeformat article.pub_time %}</time>
</a>
{% if article.type == 'a' %}
。属于<a href="{{ article.category.get_absolute_url }}" rel="category tag">{{ article.category.name }}</a>
分类,
{% if article.tags.all %}
被贴了
{% for t in article.tags.all %}
<a href="{{ t.get_absolute_url }}" rel="tag">{{ t.name }}</a>
{% if t != article.tags.all.last %}
{% endif %}
{% endfor %}
标签。
<footer class="entry-meta">
{% trans 'posted in' %}
<a href="{{ article.category.get_absolute_url }}" rel="category tag">{{ article.category.name }}</a>
</a>
{% if article.type == 'a' %}
{% if article.tags.all %}
{% trans 'and tagged' %}
{% for t in article.tags.all %}
<a href="{{ t.get_absolute_url }}" rel="tag">{{ t.name }}</a>
{% if t != article.tags.all.last %}
,
{% endif %}
{% endif %}
<span class="by-author">作者是
{% endfor %}
{% endif %}
{% endif %}
.{% trans 'by ' %}
<span class="by-author">
<span class="author vcard">
<a class="url fn n" href="{{ article.author.get_absolute_url }}"
title="查看所有由{{ article.author.username }}发布的文章"
{% blocktranslate %}
title="View all articles published by {{ article.author.username }}"
{% endblocktranslate %}
rel="author">
<span itemprop="author" itemscope itemtype="http://schema.org/Person">
@ -40,12 +38,22 @@
</span>
</span>
</a>
</span>
{% if user.is_superuser %}
<a href="{{ article.get_admin_url }}">编辑</a>
{% endif %}
</span>
{% trans 'on' %}
<a href="{{ article.get_absolute_url }}"
title="{% datetimeformat article.pub_time %}"
itemprop="datePublished" content="{% datetimeformat article.pub_time %}"
rel="bookmark">
<time class="entry-date updated"
datetime="{{ article.pub_time }}">
{% datetimeformat article.pub_time %}</time>
{% if user.is_superuser %}
<a href="{{ article.get_admin_url }}">{% trans 'edit' %}</a>
{% endif %}
</span>
</footer><!-- .entry-meta -->
</footer><!-- .entry-meta -->
{% endcache %}
{% endwith %}

@ -1,12 +1,15 @@
{% load i18n %}
<nav id="nav-below" class="navigation" role="navigation">
<h3 class="assistive-text">文章导航</h3>
<h3 class="assistive-text">
{% trans 'article navigation' %}
</h3>
{% if page_obj.has_next and next_url%}
<div class="nav-previous"><a
href="{{ next_url }}"><span
class="meta-nav">&larr;</span> 早期文章</a></div>
class="meta-nav">&larr;</span> {% trans 'earlier articles' %}</a></div>
{% endif %}
{% if page_obj.has_previous and previous_url %}
<div class="nav-next"><a href="{{ previous_url }}">较新文章
<div class="nav-next"><a href="{{ previous_url }}">{% trans 'newer articles' %}
<span
class="meta-nav">→</span></a>
</div>

@ -1,6 +1,9 @@
{% load i18n %}
{% if article_tags_list %}
<div class="panel panel-default">
<div class="panel-heading">标签</div>
<div class="panel-heading">
{% trans 'tags' %}
</div>
<div class="panel-body">
{% for url,count,tag,color in article_tags_list %}

@ -1,11 +1,12 @@
{% load blog_tags %}
{% load i18n %}
<div id="secondary" class="widget-area" role="complementary">
<aside id="search-2" class="widget widget_search">
<form role="search" method="get" id="searchform" class="searchform" action="/search">
<div>
<label class="screen-reader-text" for="s">搜索</label>
<label class="screen-reader-text" for="s">{% trans 'search' %}</label>
<input type="text" value="" name="q" id="q"/>
<input type="submit" id="searchsubmit" value="搜索"/>
<input type="submit" id="searchsubmit" />
</div>
</form>
</aside>
@ -36,7 +37,7 @@
</aside>
{% endif %}
{% if sidebar_categorys %}
<aside id="su_siloed_terms-2" class="widget widget_su_siloed_terms"><p class="widget-title">分类目录</p>
<aside id="su_siloed_terms-2" class="widget widget_su_siloed_terms"><p class="widget-title">{% trans 'category' %}</p>
<ul>
{% for c in sidebar_categorys %}
<li class="cat-item cat-item-184"><a href={{ c.get_absolute_url }}>{{ c.name }}</a>
@ -46,15 +47,14 @@
</aside>
{% endif %}
{% if sidebar_comments and open_site_comment %}
<aside id="ds-recent-comments-4" class="widget ds-widget-recent-comments"><p class="widget-title">近期评论</p>
{% comment %}<ul class="ds-recent-comments" data-num-items="5" data-show-avatars="1" data-show-time="1"
data-show-title="1" data-show-admin="1" data-avatar-size="30" data-excerpt-length="70"></ul>{% endcomment %}
<aside id="ds-recent-comments-4" class="widget ds-widget-recent-comments"><p class="widget-title">{% trans 'recent comments' %}</p>
<ul id="recentcomments">
{% for c in sidebar_comments %}
<li class="recentcomments">
<span class="comment-author-link">
{{ c.author.username }}</span>
发表在
{% trans 'published on' %}
<a href="{{ c.article.get_absolute_url }}#comment-{{ c.pk }}">{{ c.article.title }}</a>
</li>
{% endfor %}
@ -62,7 +62,7 @@
</aside>
{% endif %}
{% if recent_articles %}
<aside id="recent-posts-2" class="widget widget_recent_entries"><p class="widget-title">近期文章</p>
<aside id="recent-posts-2" class="widget widget_recent_entries"><p class="widget-title">{% trans 'recent articles' %}</p>
<ul>
{% for a in recent_articles %}
@ -74,7 +74,7 @@
</aside>
{% endif %}
{% if sidabar_links %}
<aside id="linkcat-0" class="widget widget_links"><p class="widget-title">书签</p>
<aside id="linkcat-0" class="widget widget_links"><p class="widget-title">{% trans 'bookmark' %}</p>
<ul class='xoxo blogroll'>
{% for l in sidabar_links %}
<li>
@ -93,7 +93,7 @@
</aside>
{% endif %}
{% if sidebar_tags %}
<aside id="tag_cloud-2" class="widget widget_tag_cloud"><p class="widget-title">标签云</p>
<aside id="tag_cloud-2" class="widget widget_tag_cloud"><p class="widget-title">{% trans 'Tag Cloud' %}</p>
<div class="tagcloud">
{% for tag,count,size in sidebar_tags %}
<a href="{{ tag.get_absolute_url }}"
@ -104,7 +104,7 @@
</div>
</aside>
{% endif %}
<aside id="text-2" class="widget widget_text"><p class="widget-title">欢迎您star或者fork本站源代码</p>
<aside id="text-2" class="widget widget_text"><p class="widget-title">{% trans 'Welcome to star or fork the source code of this site' %}</p>
<div class="textwidget">
<p><a href="https://github.com/liangliangyy/DjangoBlog" rel="nofollow"><img
@ -115,22 +115,22 @@
</div>
</aside>
<aside id="meta-3" class="widget widget_meta"><p class="widget-title">功能</p>
<aside id="meta-3" class="widget widget_meta"><p class="widget-title">{% trans 'Function' %}</p>
<ul>
<li><a href="/admin/" rel="nofollow">管理站点</a></li>
<li><a href="/admin/" rel="nofollow">{% trans 'management site' %}</a></li>
{% if user.is_authenticated %}
<li><a href="{% url "account:logout" %}" rel="nofollow">登出</a>
<li><a href="{% url "account:logout" %}" rel="nofollow">{% trans 'logout' %}</a>
</li>
{% else %}
<li><a href="{% url "account:login" %}" rel="nofollow">登录</a></li>
<li><a href="{% url "account:login" %}" rel="nofollow">{% trans 'login' %}</a></li>
{% endif %}
{% if user.is_superuser %}
<li><a href="{% url 'owntracks:show_dates' %}" target="_blank">运动轨迹记录</a></li>
<li><a href="{% url 'owntracks:show_dates' %}" target="_blank">{% trans 'Track record' %}</a></li>
{% endif %}
<li><a href="http://gitbook.lylinux.net" target="_blank" rel="nofollow">GitBook</a></li>
</ul>
</aside>
<div id="rocket" class="show" title="点我返回顶部"></div>
<div id="rocket" class="show" title="{% trans 'Click me to return to the top' %}"></div>
</div><!-- #secondary -->

@ -21,7 +21,7 @@
</div>
<div class="comment-meta commentmetadata">
<div>{{ comment_item.created_time }}</div>
<div>{{ comment_item.creation_time }}</div>
<div>回复给:@{{ comment_item.author.parent_comment.username }}</div>
</div>
<p>{{ comment_item.body|escape|comment_markdown }}</p>

@ -22,7 +22,7 @@
</div>
<div class="comment-meta commentmetadata">
{{ comment_item.created_time }}
{{ comment_item.creation_time }}
</div>
<p>
{% if comment_item.parent_comment %}

@ -1,7 +1,8 @@
{% load i18n %}
<div class="widget-login">
{% if apps %}
<small>
快捷登录:
{% trans 'quick login' %}:
</small>
{% for icon,url in apps %}
<a href="{{ url }}" rel="nofollow">

@ -1,5 +1,6 @@
{% load static %}
{% load cache %}
{% load i18n %}
{% load compress %}
<!DOCTYPE html>
<!--[if IE 7]>
@ -57,10 +58,29 @@
</h1>
<h2 class="site-description">{{ SITE_DESCRIPTION }}</h2>
</hgroup>
{% load i18n %}
{# <div class="i18n-selector">#}
{# <form action="{% url 'set_language' %}" method="post" id="i18n-form">{% csrf_token %}#}
{# <input name="next" type="hidden" value="{{ redirect_to }}">#}
{# <select name="language" class="i18n-select" >#}
{# {% get_current_language as LANGUAGE_CODE %}#}
{# {% get_available_languages as LANGUAGES %}#}
{# {% get_language_info_list for LANGUAGES as languages %}#}
{# {% for language in languages %}#}
{# <option value="{{ language.code }}"{% if language.code == LANGUAGE_CODE %} selected{% endif %}>#}
{# {{ language.name_local }} ({{ language.code }})#}
{# </option>#}
{# {% endfor %}#}
{# </select>#}
{# <input type="submit" value="Go">#}
{# </form>#}
{# </div>#}
{% include 'share_layout/nav.html' %}
{% cache 36000 nav %}
{% include 'share_layout/nav.html' %}
{% endcache %}
</header><!-- #masthead -->
<div id="main" class="wrapper">

@ -1,11 +1,11 @@
{% load i18n %}
<nav id="site-navigation" class="main-navigation" role="navigation">
<button class="menu-toggle">菜单</button>
<a class="assistive-text" href="#content" title="跳至正文">跳至正文</a>
<div class="menu-%e8%8f%9c%e5%8d%95-container">
<ul id="menu-%e8%8f%9c%e5%8d%95" class="nav-menu">
<li id="menu-item-3498"
class="menu-item menu-item-type-custom menu-item-object-custom current-menu-item current_page_item menu-item-home menu-item-3498">
<a href="/">首页</a></li>
<a href="/">{% trans 'index' %}</a></li>
{% load blog_tags %}
{% query nav_category_list parent_category=None as root_categorys %}
@ -23,7 +23,7 @@
{% endif %}
<li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-has-children">
<a href="{% url "blog:archives" %}">文章归档</a>
<a href="{% url "blog:archives" %}">{% trans 'Article archive' %}</a>
</li>
</ul>
</div>

Loading…
Cancel
Save