From 5ed71932008ca49fb6fa9fda41c60d80071aa791 Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 15 May 2024 20:41:03 -0400 Subject: [PATCH] more i18n --- catalog/common/models.py | 10 +- catalog/tv/models.py | 13 ++- common/templatetags/duration.py | 1 - journal/forms.py | 2 +- journal/importers/goodreads.py | 7 +- journal/importers/letterboxd.py | 2 +- journal/importers/opml.py | 7 +- journal/templatetags/collection.py | 42 +++---- locale/zh_Hans/LC_MESSAGES/django.po | 160 +++++++++++++++------------ takahe/models.py | 18 ++- users/data.py | 32 ++++-- 11 files changed, 171 insertions(+), 123 deletions(-) diff --git a/catalog/common/models.py b/catalog/common/models.py index 6ac38a54..a3f667d1 100644 --- a/catalog/common/models.py +++ b/catalog/common/models.py @@ -80,11 +80,11 @@ class IdType(models.TextChoices): Discogs_Release = "discogs_release", ("Discogs Release") Discogs_Master = "discogs_master", ("Discogs Master") MusicBrainz = "musicbrainz", ("MusicBrainz ID") - # DoubanBook_Author = "doubanbook_author", _("豆瓣读书作者") - # DoubanCelebrity = "doubanmovie_celebrity", _("豆瓣电影影人") - # Goodreads_Author = "goodreads_author", _("Goodreads作者") - # Spotify_Artist = "spotify_artist", _("Spotify艺术家") - # TMDB_Person = "tmdb_person", _("TMDB影人") + # DoubanBook_Author = "doubanbook_author", _("Douban Book Author") + # DoubanCelebrity = "doubanmovie_celebrity", _("Douban Movie Celebrity") + # Goodreads_Author = "goodreads_author", _("Goodreads Author") + # Spotify_Artist = "spotify_artist", _("Spotify Artist") + # TMDB_Person = "tmdb_person", _("TMDB Person") IGDB = "igdb", _("IGDB Game") BGG = "bgg", _("BGG Boardgame") Steam = "steam", _("Steam Game") diff --git a/catalog/tv/models.py b/catalog/tv/models.py index 80094803..c187ee27 100644 --- a/catalog/tv/models.py +++ b/catalog/tv/models.py @@ -401,7 +401,9 @@ class TVSeason(Item): ): return self.title else: - return f"{self.title} 第{self.season_number}季" # TODO i18n + return _("{show_title} S{season_number}").format( + show_title=self.title, season_number=self.season_number + ) else: return self.title @@ -450,7 +452,14 @@ class TVEpisode(Item): @property def display_title(self): - return f"{self.season.display_title if self.season else ''} 第{self.episode_number}集" # TODO i18n + return ( + _("{season_title} E{episode_number}") + .format( + season_title=self.season.display_title if self.season else "", + episode_number=self.episode_number, + ) + .strip() + ) @property def parent_item(self): diff --git a/common/templatetags/duration.py b/common/templatetags/duration.py index e621959d..c2d9c96d 100644 --- a/common/templatetags/duration.py +++ b/common/templatetags/duration.py @@ -33,7 +33,6 @@ def duration_format(value, unit): m = duration % 3600 // 60 s = duration % 60 return f"{h}:{m:02}:{s:02}" if h else f"{m:02}:{s:02}" - # return (f"{h}小时 " if h else "") + (f"{m}分钟" if m else "") except Exception: return f"{value} (format error)" diff --git a/journal/forms.py b/journal/forms.py index d20cec98..f910f0db 100644 --- a/journal/forms.py +++ b/journal/forms.py @@ -40,7 +40,7 @@ class CollectionForm(forms.ModelForm): # id = forms.IntegerField(required=False, widget=forms.HiddenInput()) title = forms.CharField(label=_("Title")) brief = MarkdownxFormField(label=_("Content (Markdown)"), strip=False) - # share_to_mastodon = forms.BooleanField(label=_("分享到联邦宇宙"), initial=True, required=False) + # share_to_mastodon = forms.BooleanField(label=_("Repost to Fediverse"), initial=True, required=False) visibility = forms.TypedChoiceField( label=_("Visibility"), initial=0, diff --git a/journal/importers/goodreads.py b/journal/importers/goodreads.py index b804a193..ca994364 100644 --- a/journal/importers/goodreads.py +++ b/journal/importers/goodreads.py @@ -65,7 +65,10 @@ class GoodreadsImporter: collection.append_item(book["book"], note=book["review"]) total += 1 collection.save() - msg.success(user, f'成功从Goodreads导入包含{total}本书的收藏单{shelf["title"]}。') + msg.success( + user, + f'Imported {total} books from Goodreads as a Collection {shelf["title"]}.', + ) elif match_profile: uid = match_profile[1] shelves = { @@ -104,7 +107,7 @@ class GoodreadsImporter: created_time=book["last_updated"] or timezone.now(), ) total += 1 - msg.success(user, f"成功从Goodreads用户主页导入{total}个标记。") + msg.success(user, f"Imported {total} records from Goodreads profile.") @classmethod def get_book(cls, url, user): diff --git a/journal/importers/letterboxd.py b/journal/importers/letterboxd.py index e1e80180..7b941a11 100644 --- a/journal/importers/letterboxd.py +++ b/journal/importers/letterboxd.py @@ -104,7 +104,7 @@ class LetterboxdImporter(Task): if len(text) < 360: comment = text else: - title = f"评《{item.title}》" + title = _("a review of {item_title}").format(item_title=item.title) Review.update_item_review(item, owner, title, text, visibility, dt) mark.update( shelf_type, diff --git a/journal/importers/opml.py b/journal/importers/opml.py index c06cf084..aaded6bc 100644 --- a/journal/importers/opml.py +++ b/journal/importers/opml.py @@ -32,8 +32,11 @@ class OPMLImporter: collection = None with set_actor(self.user): if self.mode == 1: + title = _("{username}'s podcast subscriptions").format( + username=self.user.display_name + ) collection = Collection.objects.create( - owner=self.user.identity, title=f"{self.user.display_name}的播客订阅列表" + owner=self.user.identity, title=title ) for feed in feeds: logger.info(f"{self.user} import {feed.url}") @@ -59,5 +62,5 @@ class OPMLImporter: logger.info(f"{self.user} import opml end") msg.success( self.user, - f"OPML导入完成,共处理{len(feeds)}篇,已存在{skip}篇。", + f"OPML import complete, {len(feeds)} feeds processed, {skip} exisiting feeds skipped.", ) diff --git a/journal/templatetags/collection.py b/journal/templatetags/collection.py index 8aeebb1c..452c0818 100644 --- a/journal/templatetags/collection.py +++ b/journal/templatetags/collection.py @@ -27,24 +27,24 @@ def user_stats_of(collection: Collection, identity: APIdentity): return collection.get_stats(identity) if identity else {} -@register.filter(is_safe=True) -@stringfilter -def prural_items(category: str): - # TODO support i18n here - # return _(f"items of {category}") - if category == "book": - return "本书" - elif category == "movie": - return "部电影" - elif category == "tv": - return "部剧集" - elif category == "album" or category == "music": - return "张专辑" - elif category == "game": - return "个游戏" - elif category == "podcast": - return "个播客" - elif category == "performance": - return "场演出" - else: - return category +# @register.filter(is_safe=True) +# @stringfilter +# def prural_items(category: str): +# # TODO support i18n here +# # return _(f"items of {category}") +# if category == "book": +# return "本书" +# elif category == "movie": +# return "部电影" +# elif category == "tv": +# return "部剧集" +# elif category == "album" or category == "music": +# return "张专辑" +# elif category == "game": +# return "个游戏" +# elif category == "podcast": +# return "个播客" +# elif category == "performance": +# return "场演出" +# else: +# return category diff --git a/locale/zh_Hans/LC_MESSAGES/django.po b/locale/zh_Hans/LC_MESSAGES/django.po index 619955dc..1b07c94d 100644 --- a/locale/zh_Hans/LC_MESSAGES/django.po +++ b/locale/zh_Hans/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-05-15 03:12-0400\n" +"POT-Creation-Date: 2024-05-15 20:31-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -817,15 +817,15 @@ msgstr "" #: catalog/templates/catalog_merge.html:21 msgid "Are you sure to merge?" -msgstr "" +msgstr "确定合并吗?" #: catalog/templates/catalog_merge.html:23 msgid "Are you sure to cancel merge?" -msgstr "" +msgstr "确定取消合并吗?" #: catalog/templates/catalog_merge.html:26 msgid "Are you sure to link?" -msgstr "" +msgstr "确定关联吗?" #: catalog/templates/discover.html:18 msgid "发现" @@ -1133,13 +1133,23 @@ msgstr "" msgid "season number" msgstr "" +#: catalog/tv/models.py:404 +#, python-brace-format +msgid "{show_title} S{season_number}" +msgstr "{show_title} 第{season_number}季" + +#: catalog/tv/models.py:455 +#, python-brace-format +msgid "{season_title} E{episode_number}" +msgstr "{season_title} 第{episode_number}集" + #: catalog/views.py:53 catalog/views.py:76 msgid "Item not found" -msgstr "" +msgstr "条目不存在" #: catalog/views.py:57 catalog/views.py:84 msgid "Item no longer exists" -msgstr "" +msgstr "条目已不存在" #: catalog/views_edit.py:125 catalog/views_edit.py:148 #: catalog/views_edit.py:200 catalog/views_edit.py:276 @@ -1153,7 +1163,7 @@ msgstr "" #: journal/views/post.py:20 journal/views/review.py:32 #: journal/views/review.py:46 msgid "Insufficient permission" -msgstr "" +msgstr "权限不足" #: catalog/views_edit.py:203 journal/views/collection.py:229 #: journal/views/collection.py:296 journal/views/common.py:81 @@ -1443,7 +1453,7 @@ msgid "Post to Fediverse" msgstr "发布到联邦宇宙" #: journal/forms.py:25 journal/forms.py:45 users/templates/users/data.html:40 -#: users/templates/users/data.html:134 +#: users/templates/users/data.html:132 msgid "Visibility" msgstr "可见性" @@ -1459,22 +1469,30 @@ msgstr "创建者和他们的互相关注" msgid "Collaborative editing" msgstr "协作编辑" +#: journal/importers/letterboxd.py:107 +msgid "a review of {item_title}" +msgstr "关于 {item} 的评论" + +#: journal/importers/opml.py:35 +msgid "{username}'s podcast subscriptions" +msgstr "{username} 的播客订阅" + #: journal/models/collection.py:25 msgid "note" msgstr "备注" #: journal/models/common.py:26 users/templates/users/data.html:49 -#: users/templates/users/data.html:143 +#: users/templates/users/data.html:141 msgid "Public" msgstr "公开" #: journal/models/common.py:27 users/templates/users/data.html:57 -#: users/templates/users/data.html:151 +#: users/templates/users/data.html:149 msgid "Followers Only" msgstr "仅关注者" #: journal/models/common.py:28 users/templates/users/data.html:65 -#: users/templates/users/data.html:159 +#: users/templates/users/data.html:157 msgid "Mentioned Only" msgstr "自己和提到的人" @@ -2248,23 +2266,27 @@ msgid "expire date" msgstr "" #: takahe/models.py:426 -msgid "昵称" +msgid "Display Name" msgstr "" #: takahe/models.py:427 -msgid "简介" +msgid "Bio" msgstr "" #: takahe/models.py:429 -msgid "手工审核关注者" +msgid "Manually approve new followers" msgstr "" #: takahe/models.py:431 -msgid "允许被发现或推荐" +msgid "Include profile and posts in search and discovery" msgstr "" #: takahe/models.py:448 -msgid "头像" +msgid "Profile picture" +msgstr "" + +#: takahe/models.py:455 +msgid "Header picture" msgstr "" #: takahe/utils.py:553 @@ -2386,41 +2408,41 @@ msgstr "" msgid "验证信息不符。" msgstr "" -#: users/data.py:119 -msgid "导出已开始。" -msgstr "" +#: users/data.py:121 +msgid "Generating exports." +msgstr "正在生成导出文件。" -#: users/data.py:130 -msgid "导出文件已过期,请重新导出" -msgstr "" +#: users/data.py:133 +msgid "Export file expired. Please export again." +msgstr "导出文件已失效,请重新导出" -#: users/data.py:140 -msgid "同步已开始。" -msgstr "" +#: users/data.py:144 +msgid "Sync in progress." +msgstr "正在同步。" -#: users/data.py:154 -msgid "同步设置已保存。" -msgstr "" +#: users/data.py:158 +msgid "Settings saved." +msgstr "设置已保存" -#: users/data.py:165 -msgid "已重置。" -msgstr "" +#: users/data.py:169 +msgid "Reset completed." +msgstr "重置已完成。" -#: users/data.py:174 -msgid "链接已保存,等待后台导入。" -msgstr "" +#: users/data.py:178 +msgid "Import in progress." +msgstr "正在导出" -#: users/data.py:176 -msgid "无法识别链接。" -msgstr "" +#: users/data.py:180 +msgid "Invalid URL." +msgstr "无效网址。" -#: users/data.py:189 users/data.py:212 users/data.py:225 -msgid "文件已上传,等待后台导入。" -msgstr "" +#: users/data.py:194 users/data.py:219 users/data.py:234 +msgid "File is uploaded and will be imported soon." +msgstr "文件已上传,等待后台导入。" -#: users/data.py:191 users/data.py:227 -msgid "无法识别文件。" -msgstr "" +#: users/data.py:197 users/data.py:237 +msgid "Invalid file." +msgstr "无效文件。" #: users/models/user.py:49 msgid "" @@ -2522,7 +2544,7 @@ msgid "Import Marks and Reviews from Douban" msgstr "导入豆瓣标记和评论" #: users/templates/users/data.html:69 users/templates/users/data.html:88 -#: users/templates/users/data.html:162 users/templates/users/data.html:207 +#: users/templates/users/data.html:160 users/templates/users/data.html:203 msgid "Import" msgstr "导入" @@ -2542,93 +2564,94 @@ msgstr "" "提交Goodreads用户主页链接将导入想读、在读、已读列表,每本书的评论导入为本站短" "评。" -#: users/templates/users/data.html:98 +#: users/templates/users/data.html:97 msgid "Shelf will be imported as a new collection." msgstr "Goodreads书架将被导入为收藏单,每本书的评论导入为收藏单条目备注。" -#: users/templates/users/data.html:103 +#: users/templates/users/data.html:101 msgid "List will be imported as a new collection." msgstr "Goodreads书单将被导入为收藏单,每本书的评论导入为收藏单条目备注。" -#: users/templates/users/data.html:115 +#: users/templates/users/data.html:112 msgid "Import from Letterboxd" msgstr "导入Letterboxd标记" -#: users/templates/users/data.html:164 +#: users/templates/users/data.html:162 msgid "Only forward changes(none->to-watch->watched) will be imported." -msgstr "导入时仅更新正向变化(未标->想看->已看)标记;不足360字符的评论会作为短评添加。" +msgstr "" +"导入时仅更新正向变化(未标->想看->已看)标记;不足360字符的评论会作为短评添加。" -#: users/templates/users/data.html:168 +#: users/templates/users/data.html:165 msgid "Last import started" msgstr "最近导入时间" -#: users/templates/users/data.html:169 +#: users/templates/users/data.html:166 msgid "Status" msgstr "状态" -#: users/templates/users/data.html:173 +#: users/templates/users/data.html:170 msgid "" "Failed links, likely due to Letterboxd error, you may have to mark them " "manually" msgstr "导入失败的链接(通常由于Letterboxd的信息错误,请手工添加标记)" -#: users/templates/users/data.html:185 +#: users/templates/users/data.html:181 msgid "Import Podcast Subscriptions" msgstr "导入播客订阅列表 (OPML)" -#: users/templates/users/data.html:191 +#: users/templates/users/data.html:187 msgid "Import Method" msgstr "导入方式" -#: users/templates/users/data.html:198 +#: users/templates/users/data.html:194 msgid "Mark as listening" msgstr "标记为在听" -#: users/templates/users/data.html:202 +#: users/templates/users/data.html:198 msgid "Import as a new collection" msgstr "导入为新收藏单" -#: users/templates/users/data.html:205 +#: users/templates/users/data.html:201 msgid "Select OPML file" msgstr "选择OPML文件" -#: users/templates/users/data.html:214 +#: users/templates/users/data.html:210 msgid "Export Data" msgstr "导出数据" -#: users/templates/users/data.html:220 +#: users/templates/users/data.html:216 msgid "Export in progress" msgstr "正在导出" -#: users/templates/users/data.html:220 +#: users/templates/users/data.html:216 msgid "Export marks and reviews" msgstr "导出标记、短评和评论" -#: users/templates/users/data.html:222 +#: users/templates/users/data.html:218 msgid "Download" msgstr "下载" -#: users/templates/users/data.html:229 +#: users/templates/users/data.html:225 msgid "View Annual Summary" msgstr "查看年度小结" -#: users/templates/users/data.html:242 +#: users/templates/users/data.html:238 msgid "重置所有标记和短评可见性" msgstr "" -#: users/templates/users/data.html:245 +#: users/templates/users/data.html:241 msgid "重置" msgstr "" -#: users/templates/users/data.html:248 +#: users/templates/users/data.html:244 msgid "公开" msgstr "" -#: users/templates/users/data.html:250 +#: users/templates/users/data.html:246 msgid "仅关注者" msgstr "" -#: users/templates/users/data.html:252 +#: users/templates/users/data.html:248 msgid "仅自己" msgstr "" @@ -2703,6 +2726,3 @@ msgstr "" #: users/templates/users/verify_email.html:8 msgid "验证电子邮件" msgstr "" - -#~ msgid "Invalid tag." -#~ msgstr "无效标签" diff --git a/takahe/models.py b/takahe/models.py index 6155d77e..4c821e67 100644 --- a/takahe/models.py +++ b/takahe/models.py @@ -423,12 +423,17 @@ class Identity(models.Model): related_name="identities", ) - name = models.CharField(max_length=500, blank=True, null=True, verbose_name=_("昵称")) - summary = models.TextField(blank=True, null=True, verbose_name=_("简介")) - manually_approves_followers = models.BooleanField( - default=False, verbose_name=_("手工审核关注者") + name = models.CharField( + max_length=500, blank=True, null=True, verbose_name=_("Display Name") + ) + summary = models.TextField(blank=True, null=True, verbose_name=_("Bio")) + manually_approves_followers = models.BooleanField( + default=False, verbose_name=_("Manually approve new followers") + ) + discoverable = models.BooleanField( + default=True, + verbose_name=_("Include profile and posts in search and discovery"), ) - discoverable = models.BooleanField(default=True, verbose_name=_("允许被发现或推荐")) profile_uri = models.CharField(max_length=500, blank=True, null=True) inbox_uri = models.CharField(max_length=500, blank=True, null=True) @@ -445,13 +450,14 @@ class Identity(models.Model): upload_to=partial(upload_namer, "profile_images"), blank=True, null=True, - verbose_name=_("头像"), + verbose_name=_("Profile picture"), storage=upload_store, ) image = models.ImageField( upload_to=partial(upload_namer, "background_images"), blank=True, null=True, + verbose_name=_("Header picture"), storage=upload_store, ) diff --git a/users/data.py b/users/data.py index 4115c4b3..2bf42ae1 100644 --- a/users/data.py +++ b/users/data.py @@ -118,7 +118,7 @@ def export_marks(request): django_rq.get_queue("export").enqueue(export_marks_task, request.user) request.user.preference.export_status["marks_pending"] = True request.user.preference.save() - messages.add_message(request, messages.INFO, _("导出已开始。")) + messages.add_message(request, messages.INFO, _("Generating exports.")) return redirect(reverse("users:data")) else: try: @@ -129,7 +129,9 @@ def export_marks(request): response["Content-Disposition"] = 'attachment;filename="marks.xlsx"' return response except Exception: - messages.add_message(request, messages.ERROR, _("导出文件已过期,请重新导出")) + messages.add_message( + request, messages.ERROR, _("Export file expired. Please export again.") + ) return redirect(reverse("users:data")) @@ -139,7 +141,7 @@ def sync_mastodon(request): django_rq.get_queue("mastodon").enqueue( refresh_mastodon_data_task, request.user.pk ) - messages.add_message(request, messages.INFO, _("同步已开始。")) + messages.add_message(request, messages.INFO, _("Sync in progress.")) return redirect(reverse("users:info")) @@ -153,7 +155,7 @@ def sync_mastodon_preference(request): request.POST.get("mastodon_sync_relationship", "") == "" ) request.user.preference.save() - messages.add_message(request, messages.INFO, _("同步设置已保存。")) + messages.add_message(request, messages.INFO, _("Settings saved.")) return redirect(reverse("users:info")) @@ -164,7 +166,7 @@ def reset_visibility(request): visibility = visibility if visibility >= 0 and visibility <= 2 else 0 reset_journal_visibility_for_user(request.user.identity, visibility) reset_social_visibility_for_user(request.user.identity, visibility) - messages.add_message(request, messages.INFO, _("已重置。")) + messages.add_message(request, messages.INFO, _("Reset completed.")) return redirect(reverse("users:data")) @@ -173,9 +175,9 @@ def import_goodreads(request): if request.method == "POST": raw_url = request.POST.get("url") if GoodreadsImporter.import_from_url(raw_url, request.user): - messages.add_message(request, messages.INFO, _("链接已保存,等待后台导入。")) + messages.add_message(request, messages.INFO, _("Import in progress.")) else: - messages.add_message(request, messages.ERROR, _("无法识别链接。")) + messages.add_message(request, messages.ERROR, _("Invalid URL.")) return redirect(reverse("users:data")) @@ -188,9 +190,11 @@ def import_douban(request): int(request.POST.get("import_mode", 0)), ) if importer.import_from_file(request.FILES["file"]): - messages.add_message(request, messages.INFO, _("文件已上传,等待后台导入。")) + messages.add_message( + request, messages.INFO, _("File is uploaded and will be imported soon.") + ) else: - messages.add_message(request, messages.ERROR, _("无法识别文件。")) + messages.add_message(request, messages.ERROR, _("Invalid file.")) return redirect(reverse("users:data")) @@ -211,7 +215,9 @@ def import_letterboxd(request): visibility=int(request.POST.get("visibility", 0)), file=f, ) - messages.add_message(request, messages.INFO, _("文件已上传,等待后台导入。")) + messages.add_message( + request, messages.INFO, _("File is uploaded and will be imported soon.") + ) return redirect(reverse("users:data")) @@ -224,7 +230,9 @@ def import_opml(request): int(request.POST.get("import_mode", 0)), ) if importer.import_from_file(request.FILES["file"]): - messages.add_message(request, messages.INFO, _("文件已上传,等待后台导入。")) + messages.add_message( + request, messages.INFO, _("File is uploaded and will be imported soon.") + ) else: - messages.add_message(request, messages.ERROR, _("无法识别文件。")) + messages.add_message(request, messages.ERROR, _("Invalid file.")) return redirect(reverse("users:data"))