This commit is contained in:
Your Name 2024-03-24 22:28:22 -04:00 committed by Henri Dickson
parent 4fb4e2834a
commit 3e301ad453
16 changed files with 125 additions and 88 deletions

View file

@ -1,5 +1,6 @@
from django import template
from django.utils import timezone
from django.utils.translation import gettext as _
register = template.Library()
@ -10,12 +11,12 @@ def prettydate(d):
diff = timezone.now() - d
s = diff.seconds
if diff.days > 14 or diff.days < 0:
return d.strftime("%Y%m月%d")
return d.strftime("%Y-%m-%d")
elif diff.days >= 1:
return "{} 天前".format(diff.days)
return "{}d".format(diff.days)
elif s < 120:
return "刚刚"
return _("just now")
elif s < 3600:
return "{} 分钟前".format(s // 60)
return "{}m".format(s // 60)
else:
return "{} 小时前".format(s // 3600)
return "{}h".format(s // 3600)

View file

@ -22,7 +22,7 @@ class CollectionMember(ListMember):
"Collection", related_name="members", on_delete=models.CASCADE
)
note = jsondata.CharField(_("备注"), null=True, blank=True)
note = jsondata.CharField(_("note"), null=True, blank=True)
@property
def ap_object(self):
@ -45,8 +45,8 @@ class Collection(List):
catalog_item = models.OneToOneField(
CatalogCollection, on_delete=models.PROTECT, related_name="journal_item"
)
title = models.CharField(_("标题"), max_length=1000, default="")
brief = models.TextField(_("简介"), blank=True, default="")
title = models.CharField(_("title"), max_length=1000, default="")
brief = models.TextField(_("description"), blank=True, default="")
cover = models.ImageField(
upload_to=piece_cover_path, default=DEFAULT_ITEM_COVER, blank=True
)

View file

@ -23,9 +23,9 @@ if TYPE_CHECKING:
class VisibilityType(models.IntegerChoices):
Public = 0, _("公开")
Follower_Only = 1, _("仅关注者")
Private = 2, _("仅自己")
Public = 0, _("Public")
Follower_Only = 1, _("Followers Only")
Private = 2, _("Mentioned Only")
def q_owned_piece_visible_to_user(viewing_user: User, owner: APIdentity):

View file

@ -69,7 +69,7 @@ class Mark:
@property
def action_label_for_feed(self) -> str:
return re.sub(r"不(.+)了", r"不再\1", str(self.action_label)) # TODO i18n
return str(self.action_label)
@property
def shelf_label(self) -> str | None:

View file

@ -18,44 +18,44 @@ if TYPE_CHECKING:
class ShelfType(models.TextChoices):
WISHLIST = ("wishlist", "未开始")
PROGRESS = ("progress", "进行中")
COMPLETE = ("complete", "完成")
DROPPED = ("dropped", "放弃")
WISHLIST = ("wishlist", _("WISHLIST"))
PROGRESS = ("progress", _("PROGRESS"))
COMPLETE = ("complete", _("COMPLETE"))
DROPPED = ("dropped", _("DROPPED"))
SHELF_LABELS = [
[ItemCategory.Book, ShelfType.WISHLIST, _("想读")],
[ItemCategory.Book, ShelfType.PROGRESS, _("在读")],
[ItemCategory.Book, ShelfType.COMPLETE, _("读过")],
[ItemCategory.Book, ShelfType.DROPPED, _("不读了")],
[ItemCategory.Movie, ShelfType.WISHLIST, _("想看")],
[ItemCategory.Movie, ShelfType.PROGRESS, _("在看")],
[ItemCategory.Movie, ShelfType.COMPLETE, _("看过")],
[ItemCategory.Movie, ShelfType.DROPPED, _("不看了")],
[ItemCategory.TV, ShelfType.WISHLIST, _("想看")],
[ItemCategory.TV, ShelfType.PROGRESS, _("在看")],
[ItemCategory.TV, ShelfType.COMPLETE, _("看过")],
[ItemCategory.TV, ShelfType.DROPPED, _("不看了")],
[ItemCategory.Music, ShelfType.WISHLIST, _("想听")],
[ItemCategory.Music, ShelfType.PROGRESS, _("在听")],
[ItemCategory.Music, ShelfType.COMPLETE, _("听过")],
[ItemCategory.Music, ShelfType.DROPPED, _("不听了")],
[ItemCategory.Game, ShelfType.WISHLIST, _("想玩")],
[ItemCategory.Game, ShelfType.PROGRESS, _("在玩")],
[ItemCategory.Game, ShelfType.COMPLETE, _("玩过")],
[ItemCategory.Game, ShelfType.DROPPED, _("不玩了")],
[ItemCategory.Podcast, ShelfType.WISHLIST, _("想听")],
[ItemCategory.Podcast, ShelfType.PROGRESS, _("在听")],
[ItemCategory.Podcast, ShelfType.COMPLETE, _("听过")],
[ItemCategory.Podcast, ShelfType.DROPPED, _("不听了")],
# disable all shelves for PodcastEpisode
[ItemCategory.Performance, ShelfType.WISHLIST, _("想看")],
[ItemCategory.Book, ShelfType.WISHLIST, _("wants to read")],
[ItemCategory.Book, ShelfType.PROGRESS, _("started reading")],
[ItemCategory.Book, ShelfType.COMPLETE, _("finished reading")],
[ItemCategory.Book, ShelfType.DROPPED, _("stopped reading")],
[ItemCategory.Movie, ShelfType.WISHLIST, _("wants to watch")],
[ItemCategory.Movie, ShelfType.PROGRESS, _("started watching")],
[ItemCategory.Movie, ShelfType.COMPLETE, _("finished watching")],
[ItemCategory.Movie, ShelfType.DROPPED, _("stopped watching")],
[ItemCategory.TV, ShelfType.WISHLIST, _("wants to watch")],
[ItemCategory.TV, ShelfType.PROGRESS, _("started watching")],
[ItemCategory.TV, ShelfType.COMPLETE, _("finished watching")],
[ItemCategory.TV, ShelfType.DROPPED, _("stopped watching")],
[ItemCategory.Music, ShelfType.WISHLIST, _("wants to listen")],
[ItemCategory.Music, ShelfType.PROGRESS, _("started listening")],
[ItemCategory.Music, ShelfType.COMPLETE, _("finished listening")],
[ItemCategory.Music, ShelfType.DROPPED, _("stopped listening")],
[ItemCategory.Game, ShelfType.WISHLIST, _("wants to play")],
[ItemCategory.Game, ShelfType.PROGRESS, _("started playing")],
[ItemCategory.Game, ShelfType.COMPLETE, _("finished playing")],
[ItemCategory.Game, ShelfType.DROPPED, _("stopped playing")],
[ItemCategory.Podcast, ShelfType.WISHLIST, _("wants to listen")],
[ItemCategory.Podcast, ShelfType.PROGRESS, _("started listening")],
[ItemCategory.Podcast, ShelfType.COMPLETE, _("finished listening")],
[ItemCategory.Podcast, ShelfType.DROPPED, _("stopped listening")],
[ItemCategory.Performance, ShelfType.WISHLIST, _("wants to see")],
# disable progress shelf for Performance
[ItemCategory.Performance, ShelfType.PROGRESS, ""],
[ItemCategory.Performance, ShelfType.COMPLETE, _("看过")],
[ItemCategory.Performance, ShelfType.DROPPED, _("不看了")],
[ItemCategory.Performance, ShelfType.COMPLETE, _("finished seeing")],
[ItemCategory.Performance, ShelfType.DROPPED, _("stopped seeing")],
]
# grammatically problematic, for translation only
def get_shelf_labels_for_category(item_category: ItemCategory):
@ -206,7 +206,7 @@ class ShelfLogEntry(models.Model):
if self.shelf_type:
return ShelfManager.get_action_label(self.shelf_type, self.item.category)
else:
return _("移除标记")
return _("removed mark")
def link_post_id(self, post_id: int):
ShelfLogEntryPost.objects.get_or_create(log_entry=self, post_id=post_id)
@ -297,7 +297,7 @@ class ShelfManager:
ic = ItemCategory(item_category).label
st = cls.get_action_label(shelf_type, item_category)
return (
_("{shelf_label}{item_category}").format(shelf_label=st, item_category=ic)
_("{shelf_label} {item_category}").format(shelf_label=st, item_category=ic)
if st
else None
)

View file

@ -40,7 +40,8 @@ def add_to_collection(request: AuthedHttpRequest, item_uuid):
cid = int(request.POST.get("collection_id", default=0))
if not cid:
cid = Collection.objects.create(
owner=request.user.identity, title=f"{request.user.display_name}的收藏单"
owner=request.user.identity,
title=_("Collection by {0}").format(request.user.display_name),
).id
collection = Collection.objects.get(owner=request.user.identity, id=cid)
collection.append_item(item, note=request.POST.get("note"))
@ -196,7 +197,7 @@ def collection_append_item(request: AuthedHttpRequest, collection_uuid):
collection.save()
msg = None
else:
msg = _("条目链接无法识别,请输入本站已有条目的链接。")
msg = _("Unable to find the item, please use item url from this site.")
return collection_retrieve_items(request, collection_uuid, True, msg)

View file

@ -29,16 +29,16 @@ def render_relogin(request):
"common/error.html",
{
"url": reverse("users:connect") + "?domain=" + request.user.mastodon_site,
"msg": _("信息已保存,但是未能分享到联邦宇宙"),
"msg": _("Data saved but unable to repost to Fediverse."),
"secondary_msg": _(
"可能是你在联邦宇宙(Mastodon/Pleroma/...)的登录状态过期了,正在跳转到联邦宇宙重新登录😼"
"Redirecting to your Mastodon instance now to re-authenticate."
),
},
)
def render_list_not_found(request):
msg = _("相关列表不存在")
msg = _("List not found.")
return render(
request,
"common/error.html",

View file

@ -106,12 +106,16 @@ def mark(request: AuthedHttpRequest, item_uuid):
return render_relogin(request)
except ValueError as e:
_logger.warn(f"post to mastodon error {e} {request.user}")
err = _("内容长度超出实例限制") if str(e) == "422" else str(e)
err = (
_("Content too long for your Mastodon instance.")
if str(e) == "422"
else str(e)
)
return render(
request,
"common/error.html",
{
"msg": _("标记已保存,但是未能分享到联邦宇宙"),
"msg": _("Data saved but unable to repost to Fediverse."),
"secondary_msg": err,
},
)
@ -140,7 +144,7 @@ def mark_log(request: AuthedHttpRequest, item_uuid, log_id):
def comment(request: AuthedHttpRequest, item_uuid):
item = get_object_or_404(Item, uid=get_uuid_or_404(item_uuid))
if not item.class_name in ["podcastepisode", "tvepisode"]:
raise BadRequest("不支持评论此类型的条目")
raise BadRequest("Commenting this type of items is not supported yet.")
comment = Comment.objects.filter(owner=request.user.identity, item=item).first()
if request.method == "GET":
return render(

View file

@ -70,7 +70,9 @@ def profile(request: AuthedHttpRequest, user_name):
.order_by("-created_time")
)
shelf_list[category]["reviewed"] = {
"title": "评论过的" + category.label,
"title": _("{shelf_label} {item_category}").format(
shelf_label="reviewed", item_category=category.label
),
"count": reviews.count(),
"members": reviews[:10].prefetch_related("item"),
}

View file

@ -109,18 +109,22 @@ class ReviewFeed(Feed):
return APIdentity.get_by_handle(kwargs["username"])
def title(self, owner):
return "%s的评论" % owner.display_name if owner else "无效链接"
return (
_("Reviews by {0}").format(owner.display_name)
if owner
else _("link unavailable")
)
def link(self, owner):
return owner.url if owner else settings.SITE_INFO["site_url"]
def description(self, owner):
if not owner:
return "无效链接"
return _("link unavailable")
elif not owner.anonymous_viewable:
return "该用户已关闭匿名查看"
return _("anonymous access disabled by owner")
else:
return "%s的评论合集 - NeoDB" % owner.display_name
return _("Reviews by {0}").format(owner.display_name)
def items(self, owner):
if owner is None or not owner.anonymous_viewable:
@ -129,7 +133,9 @@ class ReviewFeed(Feed):
return reviews
def item_title(self, item: Review):
return f"{item.title} - 评论《{item.item.title}"
return _("{review_title} - a review of {item_title}").format(
review_title=item.title, item_title=item.item.title
)
def item_description(self, item: Review):
target_html = (

View file

@ -56,11 +56,11 @@ def user_tag_edit(request):
else None
)
if not tag or not tag_title:
msg.error(request.user, _("无效标签"))
msg.error(request.user, _("Invalid tag."))
return HttpResponseRedirect(request.META.get("HTTP_REFERER"))
if request.POST.get("delete"):
tag.delete()
msg.info(request.user, _("标签已删除"))
msg.info(request.user, _("Tag deleted."))
return redirect(
reverse("journal:user_tag_list", args=[request.user.username])
)
@ -70,13 +70,13 @@ def user_tag_edit(request):
owner=request.user.identity, title=tag_title
).exists()
):
msg.error(request.user, _("标签已存在"))
msg.error(request.user, _("Duplicated tag."))
return HttpResponseRedirect(request.META.get("HTTP_REFERER"))
tag.title = tag_title
tag.visibility = int(request.POST.get("visibility", 0))
tag.visibility = 0 if tag.visibility == 0 else 2
tag.save()
msg.info(request.user, _("标签已修改"))
msg.info(request.user, _("Tag updated."))
return redirect(
reverse(
"journal:user_tag_member_list",

View file

@ -138,5 +138,5 @@ class WrappedShareView(LoginRequiredMixin, TemplateView):
)
elif post:
boost_toot_later(user, post.url)
messages.add_message(request, messages.INFO, _("已分享到时间轴。"))
messages.add_message(request, messages.INFO, _("Summary posted to timeline."))
return HttpResponseRedirect(request.META.get("HTTP_REFERER", "/"))

View file

@ -1,5 +1,4 @@
import functools
import html
import random
import re
import string
@ -9,6 +8,7 @@ from urllib.parse import quote
import django_rq
import requests
from django.conf import settings
from django.utils.translation import gettext_lazy as _
from loguru import logger
from mastodon.utils import rating_to_emoji
@ -350,7 +350,7 @@ def detect_server_info(login_domain) -> tuple[str, str, str]:
try:
response = get(url, headers={"User-Agent": USER_AGENT})
j = response.json()
except:
except Exception:
api_domain = login_domain
logger.info(
f"detect_server_info: {login_domain} {domain} {api_domain} {server_version}"
@ -487,7 +487,9 @@ def get_status_id_by_url(url):
def get_spoiler_text(text, item):
if text.find(">!") != -1:
spoiler_text = f"关于《{item.display_title}》 可能有关键情节等敏感内容"
spoiler_text = _(
"regarding {item_title}, may contain spoiler or triggering content"
).format(item_title=item.display_title)
return spoiler_text, text.replace(">!", "").replace("!<", "")
else:
return None, text
@ -506,6 +508,7 @@ def get_toot_visibility(visibility, user):
def share_comment(comment):
from catalog.common import ItemCategory
from journal.models import ShelfManager, ShelfType
user = comment.owner.user
visibility = get_toot_visibility(comment.visibility, user)
@ -517,7 +520,8 @@ def share_comment(comment):
if user.preference.mastodon_append_tag
else ""
)
content = f"评论《{comment.item.display_title}\n{comment.text}\n{comment.item.absolute_url}{tags}"
action = ShelfManager.get_action_label(ShelfType.PROGRESS, comment.item.category)
content = f"{action} {comment.item.display_title}\n{comment.text}\n{comment.item.absolute_url}{tags}"
update_id = None
if comment.metadata.get(
"shared_link"
@ -597,7 +601,10 @@ def share_review(review):
if user.preference.mastodon_append_tag
else ""
)
content = f"发布了关于《{review.item.display_title}》的评论\n{review.title}\n{review.absolute_url}{tags}"
content = (
"wrote a review of {item_title}".format(item_title=review.item.display_title)
+ "\n{review.title}\n{review.absolute_url}{tags}"
)
update_id = None
if review.metadata.get(
"shared_link"
@ -622,20 +629,23 @@ def share_review(review):
def share_collection(collection, comment, user, visibility_no, link):
visibility = get_toot_visibility(visibility_no, user)
tags = (
"\n" + user.preference.mastodon_append_tag.replace("[category]", "收藏单")
"\n"
+ user.preference.mastodon_append_tag.replace("[category]", _("collection"))
if user.preference.mastodon_append_tag
else ""
)
user_str = (
""
_("shared my collection")
if user == collection.owner.user
else (
" @" + collection.owner.user.mastodon_acct + " "
_("shared {username}'s collection").format(
username=" @" + collection.owner.user.mastodon_acct + " "
if collection.owner.user.mastodon_acct
else " " + collection.owner.username + " "
)
)
content = f"分享{user_str}的收藏单《{collection.title}\n{link}\n{comment}{tags}"
)
content = f"{user_str}:{collection.title}\n{link}\n{comment}{tags}"
response = post_toot(user.mastodon_site, content, visibility, user.mastodon_token)
if response is not None and response.status_code in [200, 201]:
return True

View file

@ -15,7 +15,9 @@ def mastodon_request_included(func):
return func(*args, **kwargs)
except (Timeout, ConnectionError):
return render(
args[0], "common/error.html", {"msg": _("联邦宇宙请求超时叻_(´ཀ`」 ∠)__ ")}
args[0],
"common/error.html",
{"msg": _("Timeout connecting to Fediverse.")},
)
return wrapper

View file

@ -1,6 +1,7 @@
{% load static %}
{% load i18n %}
{% load l10n %}
{% load humanize %}
{% load admin_url %}
{% load mastodon %}
{% load oauth_token %}
@ -17,7 +18,7 @@
<div>
<div>
<span class="time">
<span>{{ activity.action_object.created_time|prettydate }}</span>
<span>{{ activity.action_object.created_time|naturaltime }}</span>
</span>
<div class="spacing">
<span>

View file

@ -5,6 +5,7 @@ import blurhash
from django.conf import settings
from django.core.cache import cache
from django.core.files.images import ImageFile
from django.utils.translation import gettext_lazy as _
from PIL import Image
from .models import *
@ -18,7 +19,7 @@ if TYPE_CHECKING:
def _int(s: str):
try:
return int(s)
except:
except Exception:
return -1
@ -509,7 +510,9 @@ class Takahe:
@staticmethod
def get_spoiler_text(text, item):
if text and text.find(">!") != -1:
spoiler_text = f"关于《{item.display_title}》 可能有关键情节等敏感内容"
spoiler_text = _(
"regarding {item_title}, may contain spoiler or triggering content"
).format(item_title=item.display_title)
return spoiler_text, text.replace(">!", "").replace("!<", "")
else:
return None, text or ""
@ -547,12 +550,9 @@ class Takahe:
}
if existing_post and existing_post.type_data == data:
return existing_post
action_label = "创建"
category = "收藏单"
action = _("created collection")
item_link = collection.absolute_url
pre_conetent = (
f'{action_label}{category} <a href="{item_link}">{collection.title}</a><br>'
)
pre_conetent = f'{action} <a href="{item_link}">{collection.title}</a><br>'
content = collection.plain_content
if len(content) > 360:
content = content[:357] + "..."
@ -581,6 +581,7 @@ class Takahe:
@staticmethod
def post_comment(comment, share_as_new_post: bool) -> Post | None:
from catalog.common import ItemCategory
from journal.models import ShelfManager, ShelfType
user = comment.owner.user
category = str(ItemCategory(comment.item.category).label)
@ -590,8 +591,12 @@ class Takahe:
else ""
)
item_link = f"{settings.SITE_INFO['site_url']}/~neodb~{comment.item_url}"
action_label = "评论" if comment.text else "分享"
pre_conetent = f'{action_label}{category} <a href="{item_link}">{comment.item.display_title}</a><br>'
action = ShelfManager.get_action_label(
ShelfType.PROGRESS, comment.item.category
)
pre_conetent = (
f'{action} <a href="{item_link}">{comment.item.display_title}</a><br>'
)
spoiler, txt = Takahe.get_spoiler_text(comment.text, comment.item)
content = f"{txt}\n{tags}"
data = {
@ -634,7 +639,12 @@ class Takahe:
stars = _rating_to_emoji(review.rating_grade, 1)
item_link = f"{settings.SITE_INFO['site_url']}/~neodb~{review.item.url}"
pre_conetent = f'发布了关于 <a href="{item_link}">{review.item.display_title}</a> 的评论:<br><a href="{review.absolute_url}">{review.title}</a>'
pre_conetent = (
"wrote a review of {item_title}".format(
item_title=f'<a href="{item_link}">{review.item.display_title}</a>'
)
+ f'<br><a href="{review.absolute_url}">{review.title}</a>'
)
content = f"{stars}\n{tags}"
data = {
"object": {