From 7d74290d3d81bf041914aa37e32f2fb27cfe6e0e Mon Sep 17 00:00:00 2001 From: StanR Date: Mon, 1 Jul 2024 01:02:04 +0500 Subject: [PATCH] Minor fixes, add FR, CN, TW locales --- .../Interfaces/IUserRelationsUpdateJob.cs | 5 +- .../Jobs/Interfaces/IUserUpdateJob.cs | 3 +- .../Mutualify/Jobs/UserRelationsUpdateJob.cs | 11 +-- backend/Mutualify/Jobs/UserUpdateJob.cs | 10 ++- backend/Mutualify/Program.cs | 4 +- frontend/locales/fi-FI.json | 10 +-- frontend/locales/fr-FR.json | 78 +++++++++++++++++++ frontend/locales/zh-CN.json | 78 +++++++++++++++++++ frontend/locales/zh-TW.json | 78 +++++++++++++++++++ frontend/next.config.js | 2 +- frontend/src/components/locale.js | 16 +--- 11 files changed, 259 insertions(+), 36 deletions(-) create mode 100644 frontend/locales/fr-FR.json create mode 100644 frontend/locales/zh-CN.json create mode 100644 frontend/locales/zh-TW.json diff --git a/backend/Mutualify/Jobs/Interfaces/IUserRelationsUpdateJob.cs b/backend/Mutualify/Jobs/Interfaces/IUserRelationsUpdateJob.cs index cca3f62..3b1c6cd 100644 --- a/backend/Mutualify/Jobs/Interfaces/IUserRelationsUpdateJob.cs +++ b/backend/Mutualify/Jobs/Interfaces/IUserRelationsUpdateJob.cs @@ -1,9 +1,8 @@ -using Hangfire; -using Hangfire.Server; +using Hangfire.Server; namespace Mutualify.Jobs.Interfaces; public interface IUserRelationsUpdateJob { - Task Run(PerformContext context, IJobCancellationToken token); + Task Run(PerformContext context, CancellationToken token); } diff --git a/backend/Mutualify/Jobs/Interfaces/IUserUpdateJob.cs b/backend/Mutualify/Jobs/Interfaces/IUserUpdateJob.cs index b795450..3d58c44 100644 --- a/backend/Mutualify/Jobs/Interfaces/IUserUpdateJob.cs +++ b/backend/Mutualify/Jobs/Interfaces/IUserUpdateJob.cs @@ -1,9 +1,8 @@ using Hangfire.Server; -using Hangfire; namespace Mutualify.Jobs.Interfaces; public interface IUserUpdateJob { - Task Run(PerformContext context, IJobCancellationToken token); + Task Run(PerformContext context, CancellationToken token); } diff --git a/backend/Mutualify/Jobs/UserRelationsUpdateJob.cs b/backend/Mutualify/Jobs/UserRelationsUpdateJob.cs index cdd272e..550bfab 100644 --- a/backend/Mutualify/Jobs/UserRelationsUpdateJob.cs +++ b/backend/Mutualify/Jobs/UserRelationsUpdateJob.cs @@ -1,5 +1,4 @@ -using Hangfire; -using Hangfire.Server; +using Hangfire.Server; using Microsoft.EntityFrameworkCore; using Mutualify.Database; using Mutualify.Jobs.Interfaces; @@ -27,10 +26,12 @@ public UserRelationsUpdateJob(IUsersService usersService, IRelationsService rela _databaseContext = databaseContext; } - public async Task Run(PerformContext context, IJobCancellationToken token) + public async Task Run(PerformContext context, CancellationToken token) { var jobId = context.BackgroundJob.Id; + using var _ = _logger.BeginScope("[UserRelationsUpdateJob - {JobId}]", jobId); + _logger.LogInformation("[{JobId}] Starting user relations update job...", jobId); if (_isRunning && _lastStartDate.AddDays(1.5) > DateTime.Now) @@ -44,7 +45,7 @@ public async Task Run(PerformContext context, IJobCancellationToken token) var userUpdateQueue = await _databaseContext.Tokens.AsNoTracking() .Select(x => x.UserId) - .ToListAsync(); + .ToListAsync(cancellationToken: token); for (var i = 0; i < userUpdateQueue.Count; i++) { @@ -93,7 +94,7 @@ public async Task Run(PerformContext context, IJobCancellationToken token) var elapsed = endTime - startTime; var timeout = elapsed.TotalSeconds < _interval ? _interval - (int) elapsed.TotalSeconds : 0; - await Task.Delay(timeout * 1000); + await Task.Delay(timeout * 1000, token); } } diff --git a/backend/Mutualify/Jobs/UserUpdateJob.cs b/backend/Mutualify/Jobs/UserUpdateJob.cs index 3d13ad2..474414b 100644 --- a/backend/Mutualify/Jobs/UserUpdateJob.cs +++ b/backend/Mutualify/Jobs/UserUpdateJob.cs @@ -1,4 +1,4 @@ -using Hangfire; + using Hangfire.Server; using Microsoft.EntityFrameworkCore; using Mutualify.Database; @@ -25,10 +25,12 @@ public UserUpdateJob(IUsersService usersService, ILogger logger, _databaseContext = databaseContext; } - public async Task Run(PerformContext context, IJobCancellationToken token) + public async Task Run(PerformContext context, CancellationToken token) { var jobId = context.BackgroundJob.Id; + using var _ = _logger.BeginScope("[UserUpdateJob - {JobId}]", jobId); + _logger.LogInformation("[{JobId}] Starting user update job...", jobId); if (_isRunning && _lastStartDate.AddDays(1.5) > DateTime.Now) @@ -43,7 +45,7 @@ public async Task Run(PerformContext context, IJobCancellationToken token) var userUpdateQueue = await _databaseContext.Users.AsNoTracking() .Where(x=> x.UpdatedAt == null || x.UpdatedAt < DateTime.UtcNow.AddDays(-1)) .Select(x => x.Id) - .ToListAsync(); + .ToListAsync(cancellationToken: token); for (var i = 0; i < userUpdateQueue.Count; i++) { @@ -95,7 +97,7 @@ public async Task Run(PerformContext context, IJobCancellationToken token) var elapsed = endTime - startTime; var timeout = elapsed.TotalSeconds < _interval ? _interval - (int) elapsed.TotalSeconds : 0; - await Task.Delay(timeout * 1000); + await Task.Delay(timeout * 1000, token); } } diff --git a/backend/Mutualify/Program.cs b/backend/Mutualify/Program.cs index 6cc988c..d122d12 100644 --- a/backend/Mutualify/Program.cs +++ b/backend/Mutualify/Program.cs @@ -236,8 +236,8 @@ static Task UnauthorizedRedirect(RedirectContext co }); app.MapHangfireDashboard(); -RecurringJob.AddOrUpdate("user-relations-update", x => x.Run(null!, JobCancellationToken.Null), Cron.Daily()); -RecurringJob.AddOrUpdate("users-update", x => x.Run(null!, JobCancellationToken.Null), Cron.Daily()); +RecurringJob.AddOrUpdate("user-relations-update", x => x.Run(null!, CancellationToken.None), Cron.Daily(12)); +RecurringJob.AddOrUpdate("users-update", x => x.Run(null!, CancellationToken.None), Cron.Daily()); //BackgroundJob.Enqueue(x => x.Run(null!, JobCancellationToken.Null)); try diff --git a/frontend/locales/fi-FI.json b/frontend/locales/fi-FI.json index 7564e09..b44c281 100644 --- a/frontend/locales/fi-FI.json +++ b/frontend/locales/fi-FI.json @@ -25,10 +25,10 @@ "faq-a": "V", "faq-q1": "Mikä tämä on?", "faq-a1": "Mutualify on tietokanta osu! pelaajien kaverilistoille. Se tallentaa jokaisen sisäänkirjautuneen pelaajan kaverilistan sekä muita asiaankuuluvia tietoja.", - "faq-q2": "Kuinka se toimii?", + "faq-q2": "Kuinka Mutualify toimii?", "faq-a2": "osu! API sallii verkkosivustojen nähdä pelaajan kaverilistan. Mutualify tarkistaa kaikkien rekisteröityneiden pelaajien kaverilistat nähdäkseen, kuka seuraa ketä.", - "faq-q3": "Voiko se varastaa tilini/salasanani/yksityiset tiedot?", - "faq-a3": "Ei, se voi käyttää vain mitä osu! verkkosivusto näyttää sinulle kirjautuessasi sisään joka on kaverilistasi, julkiset profiilitietosi ja kaverisi julkiset profiilitiedot. Se ei koskaan kysy kirjautumistunnustasi / salasanaasi tai muuta vastaavaa.", + "faq-q3": "Voiko Mutualify varastaa tilini/salasanani/yksityiset tiedot?", + "faq-a3": "Ei, Mutualify voi käyttää vain mitä osu! verkkosivusto näyttää sinulle kirjautuessasi sisään joka on kaverilistasi, julkiset profiilitietosi ja kaverisi julkiset profiilitiedot. Mutualify ei koskaan kysy kirjautumistunnustasi / salasanaasi tai muuta vastaavaa.", "faq-q4": "Miksi voin nähdä vain joitakin seuraajistani?", "faq-a4": "Mutualify löytää vain aiemmin sisäänkirjautuneita ihmisiä, joten levitä sanaa! Enemmän rekisteröityneitä tarkoittaa enemmän tietoa seuraajista." }, @@ -56,7 +56,7 @@ }, "User": { "unknown-user-title": "Tuntematon käyttäjä", - "unknown-user-message": "Tämä käyttäjä ei ole koskaan kirjautunut sisään! Voit halutessasi kertoa heille ;)", + "unknown-user-message": "Tämä käyttäjä ei ole koskaan kirjautunut sisään! Voit halutessasi ehdottaa heille ;)", "private-list": "Käyttäjän {username} kaveriluettelo on yksityinen.", "friend-count": "Käyttäjällä {username} on {friendsCount} kaveria." }, @@ -65,7 +65,7 @@ "refresh": "Päivitä kaverilistasi", "refresh-success": "Päivitetty", "refresh-tooltip": "Päivitetty {updatedAgo} sitten", - "allow-friendlist-access": "Salli muiden käyttäjien käyttää kaveriluetteloasi", + "allow-friendlist-access": "Salli muiden käyttäjien nähdä kaveriluettelosi", "profile-link": "Kaverilistasi linkki" }, "Restricted": { diff --git a/frontend/locales/fr-FR.json b/frontend/locales/fr-FR.json new file mode 100644 index 0000000..9cdf71f --- /dev/null +++ b/frontend/locales/fr-FR.json @@ -0,0 +1,78 @@ +{ + "Generic": { + "loading": "Chargement...", + "page-not-found": "Cette page n'existe pas", + "sort-by-rank": "Trier par rang" + }, + "Header": { + "friends": "Amis", + "followers": "Abonnés", + "leaderboard": "Classements", + "login": "Se connecter", + "logout": "Se déconnecter", + "settings": "Paramètres", + "user-tooltip": "Ouvrir les paramètres" + }, + "Footer": { + "made-by": "Créé par StanR, icône par Arhella.", + "stats": "Statistiques", + "source": "Code source", + "donate": "Faire un don ❤" + }, + "Home": { + "faq-title": "Mutualify - une base de données pour votre liste d'amis osu!", + "faq-q": "Q", + "faq-a": "A", + "faq-q1": "Qu'est-ce que c'est ?", + "faq-a1": "Mutualify est une base de données pour les listes d'amis des joueurs osu! Elle stocke les listes d'amis de tous les joueurs qui se sont connectés ainsi que d'autres données pertinentes.", + "faq-q2": "Comment ça marche ?", + "faq-a2": "L'API de osu! permet aux sites web d'obtenir la liste d'amis d'un joueur. Mutualify compare les listes d'amis de tous les joueurs enregistrés pour voir qui suit qui.", + "faq-q3": "Est-il possible que Mutualify vole mon compte/mot de passe/données privées?", + "faq-a3": "Non, il ne peut accéder qu'à ce que le site osu! vous montre lorsque vous vous connectez, c'est-à-dire votre liste d'amis, les données de votre profil public et les données du profil public de vos amis. Il ne te demandera jamais ton login/mot de passe ou quoi que ce soit d'autre.", + "faq-q4": "Pourquoi ne puis-je voir que certains de mes abonnés?", + "faq-a4": "Mutualify ne peut trouver que les personnes qui se sont déjà connectées, alors faites passer le mot ! Plus il y a de personnes enregistrées, plus il y a d'informations sur les followers." + }, + "Stats": { + "title": "Statistiques", + "registered": "Utilisateurs enregistrés : {registered} ({lastDayRegistered} dans les dernières 24h)", + "relations": "Nombre de relations : {relations}", + "autoupdate": "Utilisateurs éligibles pour la mise à jour automatique : {eligible}" + }, + "Leaderboard": { + "title": "Classement", + "your-rank": "Votre rang est #{rank}.", + "table-header-rank": "#", + "table-header-player": "Joueur", + "table-header-followers": "Abonnés" + }, + "Followers": { + "title": "Abonnés", + "followers-count": "Abonnés connus : {knownCount} sur {totalCount}.", + "hide-mutuals": "Masquer les amis mutuels" + }, + "Friends": { + "title": "Amis", + "friend-count": "Vous avez {friendCount} amis." + }, + "User": { + "unknown-user-title": "Utilisateur inconnu", + "unknown-user-message": "Cet utilisateur ne s'est jamais connecté! Vous devriez lui dire de le faire ;)", + "private-list": "La liste d'amis de {username}est privée.", + "friend-count": "{username} a {friendsCount} amis." + }, + "Settings": { + "title": "Paramètres", + "refresh": "Actualisez votre liste d'amis", + "refresh-success": "Actualisé!", + "refresh-tooltip": "Mise à jour {updatedAgo}", + "allow-friendlist-access": "Autoriser d'autres utilisateurs à accéder à votre liste d'amis", + "profile-link": "Lien vers votre liste d'amis" + }, + "Restricted": { + "title": "Non autorisé", + "message": "Désolé, mais les joueurs bannis ne sont pas autorisés à se connecter!" + }, + "Unauthorized": { + "message": "Connectez-vous d'abord!" + } +} \ No newline at end of file diff --git a/frontend/locales/zh-CN.json b/frontend/locales/zh-CN.json new file mode 100644 index 0000000..1b99173 --- /dev/null +++ b/frontend/locales/zh-CN.json @@ -0,0 +1,78 @@ +{ + "Generic": { + "loading": "加载中...", + "page-not-found": "找不到页面", + "sort-by-rank": "按排名排序" + }, + "Header": { + "friends": "好友", + "followers": "关注者", + "leaderboard": "排名", + "login": "登录", + "logout": "登出", + "settings": "设置", + "user-tooltip": "前往设置" + }, + "Footer": { + "made-by": "由 StanR开发,图标由 Arhella 绘制。", + "stats": "统计资料", + "source": "源代码", + "donate": "捐助 ❤️" + }, + "Home": { + "faq-title": "Mutualify - 一个 osu! 好友列表的数据库", + "faq-q": "问", + "faq-a": "答", + "faq-q1": "这是什么?", + "faq-a1": "Mutualify 是一个 osu! 玩家的好友列表数据库。 它保存每个在此登录过的玩家的好友列表以及其他一些相关的数据。", + "faq-q2": "它是如何工作的?", + "faq-a2": "osu! API 允许我们获取玩家的好友列表。Mutualify 通过交叉检查所有注册玩家的好友列表,来查看谁跟随了哪个人。", + "faq-q3": "它会盗取我的帐户/密码/私人数据吗?", + "faq-a3": "不能,它只能在您登录时使用您 osu! 网站上显示的好友列表、公开个人资料数据和您好友的公开个人资料数据。它永远不会要求您的登录密码或类似的任何其他信息。", + "faq-q4": "为什么我只能看到我的追随者的一部分?", + "faq-a4": "Mutualify 只能找到登录过这里的人,所以传播这个网站吧!更多在这里注册过的人就意味着更多有关追随者的信息。" + }, + "Stats": { + "title": "统计", + "registered": "共有 {registered} 个用户注册,(过去24小时内{lastDayRegistered} 个用户注册)", + "relations": "关系数量: {relations}", + "autoupdate": "允许自动更新的用户: {eligible}" + }, + "Leaderboard": { + "title": "排行榜", + "your-rank": "您的排名是 #{rank}。", + "table-header-rank": "#", + "table-header-player": "玩家", + "table-header-followers": "关注者" + }, + "Followers": { + "title": "关注者", + "followers-count": "已知的关注者有 {knownCount} 个,共计 {totalCount} 个。", + "hide-mutuals": "隐藏互关" + }, + "Friends": { + "title": "我的好友", + "friend-count": "你有 {friendCount} 个好友。" + }, + "User": { + "unknown-user-title": "未知用户", + "unknown-user-message": "此用户从未在此登录过!你可以告诉他们来试试 ;)", + "private-list": "{username}的好友列表是私密的。", + "friend-count": "{username} 有 {friendsCount} 个好友。" + }, + "Settings": { + "title": "设置", + "refresh": "刷新好友列表", + "refresh-success": "已更新!", + "refresh-tooltip": "在 {updatedAgo} 更新", + "allow-friendlist-access": "允许其他用户访问您的好友列表", + "profile-link": "您的好友列表链接" + }, + "Restricted": { + "title": "不允许", + "message": "抱歉,但受限制的玩家不允许登录!" + }, + "Unauthorized": { + "message": "请先登录!" + } +} \ No newline at end of file diff --git a/frontend/locales/zh-TW.json b/frontend/locales/zh-TW.json new file mode 100644 index 0000000..782ceb8 --- /dev/null +++ b/frontend/locales/zh-TW.json @@ -0,0 +1,78 @@ +{ + "Generic": { + "loading": "正在載入…", + "page-not-found": "無法找到此頁面", + "sort-by-rank": "按排名排序" + }, + "Header": { + "friends": "好友", + "followers": "粉絲", + "leaderboard": "排行榜", + "login": "登入", + "logout": "登出", + "settings": "設定", + "user-tooltip": "打開設定" + }, + "Footer": { + "made-by": "製作:StanR 圖標:Arhella", + "stats": "統計數據", + "source": "原始碼", + "donate": "捐贈 ❤" + }, + "Home": { + "faq-title": "Mutualify - osu! 的好友列表資料庫", + "faq-q": "問", + "faq-a": "答", + "faq-q1": "Mutualify 是甚麼?", + "faq-a1": "Mutualify 是一個 osu! 玩家好友列表的資料庫。它保存了每個在此登入的玩家的好友列表以及一些相關資料。", + "faq-q2": "它是如何運作的?", + "faq-a2": "Mutualify 通過 osu! API 獲取所有已登記玩家的好友列表,透過檢查其他玩家的好友列表得知誰追蹤了你。", + "faq-q3": "它能盜取我的帳號/密碼/私人資料嗎?", + "faq-a3": "不能,它只能夠查看你在登入時顯示的 osu! 授權請求上的項目。也就是你的追蹤列表、你的公開個人資料以及你的好友的公開個人資料。它並不會要求你輸入登入帳號/密碼或其他類似的私人資料。", + "faq-q4": "為甚麼我只能見到我部分的粉絲?", + "faq-a4": "Mutualify 只能夠找到已登記的玩家,所以多宣傳一下吧!登記的玩家越多粉絲相關的資訊就越多。" + }, + "Stats": { + "title": "統計數據", + "registered": "已登記玩家:{registered} (過去24小時:{lastDayRegistered})", + "relations": "總追蹤數:{relations}", + "autoupdate": "能夠自動更新的已登記玩家:{eligible}" + }, + "Leaderboard": { + "title": "排行榜", + "your-rank": "你的排名:#{rank}", + "table-header-rank": "#", + "table-header-player": "玩家", + "table-header-followers": "粉絲" + }, + "Followers": { + "title": "粉絲", + "followers-count": "已知的粉絲:{knownCount}/{totalCount}", + "hide-mutuals": "隐藏已添加粉絲" + }, + "Friends": { + "title": "好友", + "friend-count": "你有 {friendCount} 個好友。" + }, + "User": { + "unknown-user-title": "未知的玩家", + "unknown-user-message": "這位玩家從未在此登記過!你可能會想叫他來登記一下 ;)", + "private-list": "{username} 的好友列表沒有公開。", + "friend-count": "{username} 有 {friendsCount} 個好友。" + }, + "Settings": { + "title": "設定", + "refresh": "刷新你的好友列表", + "refresh-success": "已更新!", + "refresh-tooltip": "上次更新:{updatedAgo}", + "allow-friendlist-access": "允許其他玩家訪問你的好友列表", + "profile-link": "你的好友列表連結" + }, + "Restricted": { + "title": "無法登記", + "message": "抱歉,但受限制的玩家不能夠登入!" + }, + "Unauthorized": { + "message": "請先登入!" + } +} \ No newline at end of file diff --git a/frontend/next.config.js b/frontend/next.config.js index da1b1e6..c19c10b 100644 --- a/frontend/next.config.js +++ b/frontend/next.config.js @@ -4,7 +4,7 @@ module.exports = { emotion: true, }, i18n: { - locales: ["en-US", "fi-FI", "pl-PL", "ru-RU", "sv-SE"], + locales: ["en-US", "fi-FI", "fr-FR", "pl-PL", "ru-RU", "sv-SE", "zh-CN", "zh-TW"], defaultLocale: "en-US" }, output: 'standalone' diff --git a/frontend/src/components/locale.js b/frontend/src/components/locale.js index 7ab1337..ffbbf06 100644 --- a/frontend/src/components/locale.js +++ b/frontend/src/components/locale.js @@ -1,20 +1,8 @@ import Image from 'next/image'; export default function Locale({locale}) { - let localeUrl = 'http://purecatamphetamine.github.io/country-flag-icons/3x2/NP.svg' - switch(locale) { - case 'en-US': - localeUrl = 'http://purecatamphetamine.github.io/country-flag-icons/3x2/US.svg'; break; - case 'ru-RU': - localeUrl = 'http://purecatamphetamine.github.io/country-flag-icons/3x2/RU.svg'; break; - case 'fi-FI': - localeUrl = 'http://purecatamphetamine.github.io/country-flag-icons/3x2/FI.svg'; break; - case 'pl-PL': - localeUrl = 'http://purecatamphetamine.github.io/country-flag-icons/3x2/PL.svg'; break; - case 'sv-SE': - localeUrl = 'http://purecatamphetamine.github.io/country-flag-icons/3x2/SE.svg'; break; - } - + let localeCountry = locale.split('-')[1]; + let localeUrl = `http://purecatamphetamine.github.io/country-flag-icons/3x2/${localeCountry}.svg` return ( <>