Merge branch 'develop'

This commit is contained in:
syuilo 2023-01-22 17:11:00 +09:00
commit 945129c371
16 changed files with 263 additions and 87 deletions

View file

@ -9,6 +9,14 @@
You should also include the user name that made the change. You should also include the user name that made the change.
--> -->
## 13.1.4 (2023/01/22)
### Improvements
- 新たな実績を追加
### Bugfixes
- Client: ローカリゼーション更新時にリロードが繰り返されることがあるのを修正
## 13.1.3 (2023/01/22) ## 13.1.3 (2023/01/22)
### Bugfixes ### Bugfixes
@ -65,6 +73,7 @@ You should also include the user name that made the change.
- Node.js 18.x or later is required - Node.js 18.x or later is required
- PostgreSQL 15.x is required - PostgreSQL 15.x is required
- Misskey not using 15 specific features at 13.0.0, but may do so in the future. - Misskey not using 15 specific features at 13.0.0, but may do so in the future.
- Docker環境でPostgreSQLのアップデートを行う際のガイドはこちら: https://github.com/misskey-dev/misskey/pull/9641#issue-1536336620
- Elasticsearchのサポートが削除されました - Elasticsearchのサポートが削除されました
- 代わりに今後任意の検索プロバイダを設定できる仕組みを構想しています。その仕組みを使えば今まで通りElasticsearchも利用できます - 代わりに今後任意の検索プロバイダを設定できる仕組みを構想しています。その仕組みを使えば今まで通りElasticsearchも利用できます
- Yarnからpnpmに移行されました - Yarnからpnpmに移行されました

View file

@ -1048,6 +1048,9 @@ _achievements:
_noteFavorited1: _noteFavorited1:
title: "Sternengucker" title: "Sternengucker"
description: "Eine Notiz als Favorit markiert" description: "Eine Notiz als Favorit markiert"
_myNoteFavorited1:
title: "Sternensucher"
description: "Ein anderer Benutzer hat eine deiner Notizen als Favoriten markiert"
_profileFilled: _profileFilled:
title: "Perfekte Vorbereitung" title: "Perfekte Vorbereitung"
description: "Fülle dein Profil aus" description: "Fülle dein Profil aus"

View file

@ -1048,6 +1048,9 @@ _achievements:
_noteFavorited1: _noteFavorited1:
title: "Stargazer" title: "Stargazer"
description: "Favorite your first note" description: "Favorite your first note"
_myNoteFavorited1:
title: "Seeking Stars"
description: "Have somebody else favorite one of your notes"
_profileFilled: _profileFilled:
title: "Well-prepared" title: "Well-prepared"
description: "Set up your profile" description: "Set up your profile"

View file

@ -1,7 +1,7 @@
--- ---
_lang_: "Italiano" _lang_: "Italiano"
headlineMisskey: "Rete collegata tramite note" headlineMisskey: "Rete collegata tramite note"
introMisskey: "Eccoci! Misskey è un servizio di microblogging decentralizzato, libero e aperto. \n📡 Puoi pubblicare «Note» per condividere ciò che sta succedendo o per dire a tutti qualcosa su di te. \n👍 Puoi reagire inviando emoji rapidi alle «Note» provenienti da altri profili nel Fediverso.\n🚀 Esplora un nuovo mondo insieme a noi!" introMisskey: "Eccoci! Misskey è un servizio di microblogging decentralizzato, libero e aperto. \n\n📡 Puoi pubblicare «Note» per condividere ciò che sta succedendo o per dire a tutti qualcosa su di te. \n\n👍 Puoi reagire inviando emoji rapidi alle «Note» provenienti da altri profili nel Fediverso.\n\n🚀 Esplora un nuovo mondo insieme a noi!"
poweredByMisskeyDescription: "{name} è uno dei servizi (chiamati istanze) che utilizzano la piattaforma open source <b>Misskey</b>." poweredByMisskeyDescription: "{name} è uno dei servizi (chiamati istanze) che utilizzano la piattaforma open source <b>Misskey</b>."
monthAndDay: "{day}/{month}" monthAndDay: "{day}/{month}"
search: "Cerca" search: "Cerca"
@ -943,79 +943,79 @@ _achievements:
earnedAt: "Data di conseguimento" earnedAt: "Data di conseguimento"
_types: _types:
_notes1: _notes1:
title: "Ho iniziato a usare Misskey" title: "Hai iniziato a usare Misskey"
description: "Ho pubblicato la mia prima Nota" description: "Hai pubblicato la prima Nota"
flavor: "Goditi la vita su Misskey!" flavor: "Goditi la vita su Misskey!"
_notes10: _notes10:
title: "Alcune Note" title: "Alcune Note"
description: "Ho inserito 10 Note" description: "Hai inserito 10 Note"
_notes100: _notes100:
title: "Un po' di Note" title: "Un po' di Note"
description: "Ho inserito 100 Note" description: "Hai inserito 100 Note"
_notes500: _notes500:
title: "Un bel po' di Note" title: "Un bel po' di Note"
description: "Ho inserito 500 Note" description: "Hai inserito 500 Note"
_notes1000: _notes1000:
title: "Una montagna di Note" title: "Una montagna di Note"
description: "Ho inserito 1.000 Note" description: "Hai inserito 1.000 Note"
_notes5000: _notes5000:
title: "Un sovraccarico di Note!" title: "Un sovraccarico di Note!"
description: "Ho inserito 5.000 Note" description: "Hai inserito 5.000 Note"
_notes10000: _notes10000:
title: "SuperNote!" title: "SuperNote!"
description: "Ho inserito 10.000 Note" description: "Hai inserito 10.000 Note"
_notes20000: _notes20000:
title: "Voglio più... Note!" title: "Voglio più... Note!"
description: "Ho inserito 20.000 Note" description: "Hai inserito 20.000 Note"
_notes30000: _notes30000:
title: "Note, Note, Note!" title: "Note, Note, Note!"
description: "Ho inserito 30.000 Note" description: "Hai inserito 30.000 Note"
_notes40000: _notes40000:
title: "Una fabbrica di Note" title: "Una fabbrica di Note"
description: "Ho inserito 40.000 Note" description: "Hai inserito 40.000 Note"
_notes50000: _notes50000:
title: "Un pianeta di Note" title: "Un pianeta di Note"
description: "Ho inserito 50.000 Note" description: "Hai inserito 50.000 Note"
_notes60000: _notes60000:
title: "Un quasar di Note" title: "Un quasar di Note"
description: "Ho inserito 60.000 Note" description: "Hai inserito 60.000 Note"
_notes70000: _notes70000:
title: "Un buco nero supermassiccio di Note" title: "Un buco nero supermassiccio di Note"
description: "Ho inserito 70.000 Note" description: "Hai inserito 70.000 Note"
_notes80000: _notes80000:
title: "Una galassia di Note" title: "Una galassia di Note"
description: "Ho inserito 80.000 Note" description: "Hai inserito 80.000 Note"
_notes90000: _notes90000:
title: "Un universo di Note!" title: "Un universo di Note!"
description: "Ho inserito 90.000 Note" description: "Hai inserito 90.000 Note"
_notes100000: _notes100000:
title: "ALL YOUR NOTE ARE BELONG TO US" title: "ALL YOUR NOTE ARE BELONG TO US"
description: "Ho inserito 100.000 Note" description: "Hai inserito 100.000 Note"
flavor: "Hai molto da scrivere?" flavor: "Hai molto da scrivere?"
_login3: _login3:
title: "Principiante I" title: "Principiante I"
description: "Accedi per 3 giorni di fila" description: "Accedi per un totale di 3 giorni"
flavor: "Da oggi, chiamatemi Misskist" flavor: "Da oggi, chiamatemi Misskist"
_login7: _login7:
title: "Principiante II" title: "Principiante II"
description: "Accedi per 7 giorni di fila" description: "Accedi per un totale di 7 giorni"
flavor: "Ti sembra di avere la situazione sotto controllo?" flavor: "Ti sembra di avere la situazione sotto controllo?"
_login15: _login15:
title: "Principiante III" title: "Principiante III"
description: "Accedi per 15 giorni di fila" description: "Accedi per un totale di 15 giorni"
_login30: _login30:
title: "Misskist I" title: "Misskist I"
description: "Accedi per 30 giorni di fila" description: "Accedi per un totale di 30 giorni"
_login60: _login60:
title: "Misskeist II" title: "Misskeist II"
description: "Accedi per 60 giorni di fila" description: "Accedi per un totale di 60 giorni"
_login100: _login100:
title: "Misskeist III" title: "Misskeist III"
description: "Accedi per 100 giorni di fila" description: "Accedi per un totale di 100 giorni"
flavor: "Violent Misskeist" flavor: "Violent Misskeist"
_login200: _login200:
title: "Regolare I" title: "Regolare I"
description: "Accedi per 200 giorni totali" description: "Accedi per un totale di 200 giorni"
_login300: _login300:
title: "Regolare II" title: "Regolare II"
description: "Accedi per un totale di 300 giorni" description: "Accedi per un totale di 300 giorni"
@ -1090,9 +1090,82 @@ _achievements:
description: "Hai ottenuto 500 Follower" description: "Hai ottenuto 500 Follower"
_followers1000: _followers1000:
title: "Influenzer" title: "Influenzer"
description: "Hai superato i 1.000 Follower"
_collectAchievements30:
title: "Collezionista di successi"
description: "Hai raggiunto 30 obiettivi"
_viewAchievements3min:
title: "Mi piacciono i risultati"
description: "Guarda la tua collezione di obiettivi per almeno 3 minuti"
_iLoveMisskey:
title: "I LOVE Misskey"
description: "Pubblica «I ♥ #Misskey»"
flavor: "Grazie per aver utilizzato Misskey! Dal team di sviluppo"
_client30min:
title: "Piccola pausa"
description: "Hai passato più di 30 minuti di fila su Misskey"
_noteDeletedWithin1min:
title: "Ooops!"
description: "Hai eliminato una nota entro un minuto dalla sua pubblicazione"
_postedAtLateNight:
title: "Biassanot!"
description: "Hai pubblicato una nota in tarda notte"
flavor: "Andiamo a dormire presto"
_postedAt0min0sec:
title: "Mezzanotte"
description: "Hai pubblicato una Nota a mezzanotte in punto"
flavor: "tic, tac, tic, tac! Gong!"
_selfQuote:
title: "Autoreferenziale"
description: "Hai citato una delle tue Note"
_htl20npm:
title: "Timeline scorrevole"
description: "La tua Timeline personale ha superato la velocità di 20 Note orarie (Note al minuto)"
_outputHelloWorldOnScratchpad:
title: "Hello, world!"
description: "Hai scritto «Hello world» nel blocco appunti"
_open3windows:
title: "Finestrato"
description: "Hai aperto almeno 3 finestre contemporaneamente"
_driveFolderCircularReference:
title: "Riferimento circolare"
description: "Hai provato a nidificare in modo ricorsivo le cartelle del Drive"
_reactWithoutRead:
title: "Hai letto bene?"
description: "Hai reagito ad una Nota più lunga di 100 caratteri entro 3 secondi dalla sua pubblicazione"
_clickedClickHere:
title: "Clicca qui"
description: "Hai cliccato qui"
_justPlainLucky:
title: "Proprio fortunato"
description: "Ottenuto con una probabilità dello 0,01% ogni 10 secondi"
_setNameToSyuilo:
title: "Complesso divino"
description: "Hai impostati il tuo nome in «syuilo»"
_passedSinceAccountCreated1:
title: "Primo Anniversario"
description: "È passato un anno da quando hai creato il profilo"
_passedSinceAccountCreated2:
title: "Secondo Anniversario"
description: "Sono passati due anni da quando hai creato il profilo"
_passedSinceAccountCreated3:
title: "Terzo Anniversario"
description: "Sono passati tre anni da quando hai creato il profilo"
_loggedInOnBirthday:
title: "Buon compleanno!"
description: "Hai effettuato l'accesso il giorno del tuo compleanno"
_loggedInOnNewYearsDay:
title: "Buon anno nuovo!"
description: "Hai usato effettuato l'accesso il giorno di capodanno"
flavor: "Anche quest'anno, grazie per il tuo continuo supporto a questa istanza"
_cookieClicked:
title: "Clicca il biscotto"
description: "Hai giocato a cliccare il cookie"
flavor: "Hai autorizzato i cookie?"
_brainDiver: _brainDiver:
title: "Brain Diver" title: "Brain Diver"
description: "Pubblica un link a Brain Diver" description: "Pubblica un link a Brain Diver"
flavor: "Sulle note di Brain Diver"
_role: _role:
new: "Nuovo ruolo" new: "Nuovo ruolo"
edit: "Modifica ruolo" edit: "Modifica ruolo"

View file

@ -1049,6 +1049,9 @@ _achievements:
_noteFavorited1: _noteFavorited1:
title: "星をみるひと" title: "星をみるひと"
description: "初めてノートをお気に入りに登録した" description: "初めてノートをお気に入りに登録した"
_myNoteFavorited1:
title: "星が欲しい"
description: "自分のノートが他の人からお気に入りに登録された"
_profileFilled: _profileFilled:
title: "準備万端" title: "準備万端"
description: "プロフィール設定を行った" description: "プロフィール設定を行った"

View file

@ -891,19 +891,48 @@ cannotUploadBecauseNoFreeSpace: "Файл не может быть загруж
beta: "Бета" beta: "Бета"
enableAutoSensitive: "Автоматическое определение NSFW" enableAutoSensitive: "Автоматическое определение NSFW"
enableAutoSensitiveDescription: "Если доступно, используйте машинное обучение для автоматической установки флага NSFW на носителе. Даже если эта функция отключена, она может быть установлена ​​автоматически в зависимости от инстанта." enableAutoSensitiveDescription: "Если доступно, используйте машинное обучение для автоматической установки флага NSFW на носителе. Даже если эта функция отключена, она может быть установлена ​​автоматически в зависимости от инстанта."
navbar: "Панель навигации"
shuffle: "Перемешать"
account: "Учётные записи" account: "Учётные записи"
move: "Переместить"
pushNotification: "Push-уведомления"
subscribePushNotification: "Включить push-уведомления"
unsubscribePushNotification: "Выключить push-уведомления"
pushNotificationAlreadySubscribed: "Push-уведомления уже включены"
pushNotificationNotSupported: "Push-уведмления не поддерживаются инстансом или браузером"
sendPushNotificationReadMessage: "Удалять push-уведомления когда сообщение или прочитано"
sendPushNotificationReadMessageCaption: "На мгновение появится уведомление \"{emptyPushNotificationMessage}\". Расход заряда батареи может увеличиться "
windowMaximize: "Развернуть" windowMaximize: "Развернуть"
windowRestore: "Восстановить" windowRestore: "Восстановить"
caption: "Подпись (Automatic Translation)"
loggedInAsBot: "Вы под аккаунтом бота!" loggedInAsBot: "Вы под аккаунтом бота!"
tools: "Инструменты"
cannotLoad: "Не удалось загрузить"
numberOfProfileView: "Количество профилей для просмотра"
like: "Нравится!" like: "Нравится!"
unlike: "Отменить «нравится»" unlike: "Отменить «нравится»"
numberOfLikes: "Количество лайков"
show: "Отображение" show: "Отображение"
neverShow: "Больше не показывать"
remindMeLater: "Напомнить позже"
didYouLikeMisskey: "Вам нравится Misskey?"
pleaseDonate: "Сайт {host} работает на Misskey. Это бесплатное программное обеспечение, и ваши пожертвования очень бы помогли продолжать его разработку!" pleaseDonate: "Сайт {host} работает на Misskey. Это бесплатное программное обеспечение, и ваши пожертвования очень бы помогли продолжать его разработку!"
roles: "Роли" roles: "Роли"
role: "Роль" role: "Роль"
normalUser: "Обычный пользователь"
undefined: "неопределён"
assign: "Назначить"
unassign: "Отменить назначение"
color: "Цвет" color: "Цвет"
manageCustomEmojis: "Управлять пользовательскими эмодзи"
youCannotCreateAnymore: "Вы достигли лимита создания."
cannotPerformTemporary: "Временно недоступен"
cannotPerformTemporaryDescription: "Это действие временно невозможно выполнить из-за превышения лимита выполнения."
preset: "Шаблоны"
selectFromPresets: "Выбрать из шаблонов"
achievements: "Достижения" achievements: "Достижения"
_achievements: _achievements:
earnedAt: "Разблокировано в"
_types: _types:
_notes1: _notes1:
title: "Первые шаги в Misskey" title: "Первые шаги в Misskey"
@ -975,6 +1004,7 @@ _achievements:
_login100: _login100:
title: "Мискиец Ⅲ" title: "Мискиец Ⅲ"
description: "100 дней на сайте" description: "100 дней на сайте"
flavor: "Жестокий Misskist "
_login200: _login200:
title: "Завсегдатай " title: "Завсегдатай "
description: "200 дней на сайте" description: "200 дней на сайте"
@ -1010,6 +1040,9 @@ _achievements:
_noteFavorited1: _noteFavorited1:
title: "Смотрящий на звёзды" title: "Смотрящий на звёзды"
description: "Первое добавление в избранное" description: "Первое добавление в избранное"
_myNoteFavorited1:
title: "В поиске звёзд"
description: "Кому-то понравилась ваша заметка"
_profileFilled: _profileFilled:
title: "Приготовления закончены" title: "Приготовления закончены"
description: "Заполнен профиль" description: "Заполнен профиль"
@ -1130,14 +1163,24 @@ _achievements:
flavor: "Мисски-Мисски Ла-Ту-Ма" flavor: "Мисски-Мисски Ла-Ту-Ма"
_role: _role:
new: "Новая роль" new: "Новая роль"
edit: "Изменить роль"
name: "Название роли" name: "Название роли"
description: "Описание роли" description: "Описание роли"
permission: "Ролевые полномочия" permission: "Ролевые полномочия"
descriptionOfPermission: "<b>Модераторы</b> могут изменять базовые операции для модераторов.\n<b>Администраторы</b> могут изменять полностью настройки инстанса."
assignTarget: "Метод присвоения" assignTarget: "Метод присвоения"
descriptionOfAssignTarget: "<b>Вручную</b> чтобы указать кому выдавать роль, а кому нет.\n<b>По условию<b> чтобы автоматически выдавать и удалять роль при условиях."
manual: "Вручную" manual: "Вручную"
conditional: "По условию" conditional: "По условию"
condition: "Условия"
isConditionalRole: "Эта роль выдаётся по условию."
isPublic: "Общедоступная роль" isPublic: "Общедоступная роль"
descriptionOfIsPublic: "Список тех, кому назначена эта роль будет доступен всем. Кроме того эта роль будет отмечена у каждого в профиле." descriptionOfIsPublic: "Список тех, кому назначена эта роль будет доступен всем. Кроме того эта роль будет отмечена у каждого в профиле."
options: "Настройки ролей"
policies: "Политики"
baseRole: "Шаблон роли"
useBaseValue: "Использовать значение из шаблона"
chooseRoleToAssign: "Выберите роль, которую хотите выдать"
canEditMembersByModerator: "Могут назначать модераторы" canEditMembersByModerator: "Могут назначать модераторы"
descriptionOfCanEditMembersByModerator: "Если включено, на эту роль могут назначать пользователей как администраторы, так и модераторы. Если выключено, назначать могут только администраторы." descriptionOfCanEditMembersByModerator: "Если включено, на эту роль могут назначать пользователей как администраторы, так и модераторы. Если выключено, назначать могут только администраторы."
priority: "Приоритет" priority: "Приоритет"
@ -1145,6 +1188,8 @@ _role:
low: "Низкий" low: "Низкий"
middle: "Средне" middle: "Средне"
high: "Высокий" high: "Высокий"
_options:
canManageCustomEmojis: "Управлять пользовательскими эмодзи"
_sensitiveMediaDetection: _sensitiveMediaDetection:
description: "Машинное обучение может быть использовано для автоматического обнаружения чувствительных медиа для модерации. Нагрузка на сервер увеличивается незначительно." description: "Машинное обучение может быть использовано для автоматического обнаружения чувствительных медиа для модерации. Нагрузка на сервер увеличивается незначительно."
setSensitiveFlagAutomatically: "Установить флаг NSFW" setSensitiveFlagAutomatically: "Установить флаг NSFW"
@ -1191,6 +1236,11 @@ _plugin:
install: "Установка расширений" install: "Установка расширений"
installWarn: "Пожалуйста, не устанавливайте расширения, которым не доверяете." installWarn: "Пожалуйста, не устанавливайте расширения, которым не доверяете."
manage: "Управление расширениями" manage: "Управление расширениями"
_preferencesBackups:
saveConfirm: "Сохранить бэкап как {name}?"
deleteConfirm: "Удалить резервную копию {name}?"
renameConfirm: "Переименовать резервную копию с \"{old}\" на \"{new}\"?"
noBackups: "Резервной копии не существует. Вы можете создать резервную копию в настройках на этом инстансе с помощью \"Создать новую резервную копию\"."
_registry: _registry:
scope: "Область" scope: "Область"
key: "Ключ" key: "Ключ"

View file

@ -992,22 +992,53 @@ _achievements:
title: "ALL YOUR NOTE ARE BELONG TO US" title: "ALL YOUR NOTE ARE BELONG TO US"
description: "发布了100,000篇帖子" description: "发布了100,000篇帖子"
flavor: "真的有那么多可以写的东西吗?" flavor: "真的有那么多可以写的东西吗?"
_login3:
title: "初学者 I"
description: "连续登录3天"
_login7:
description: "连续登录7天"
_login15:
description: "连续登录15天"
_login30:
description: "连续登录30天"
_login60:
description: "连续登录60天"
_login1000: _login1000:
flavor: "感谢您使用Misskey" flavor: "感谢您使用Misskey"
_noteFavorited1: _noteFavorited1:
title: "观星者" title: "观星者"
_markedAsCat: _markedAsCat:
title: "我是猫" title: "我是猫"
description: "将账户设定为一只猫"
_following10:
title: "关注,跟随"
_following50: _following50:
title: "我的朋友很多" title: "我的朋友很多"
_following300:
description: "关注数超过300"
_followers100:
title: "胜友如云"
_collectAchievements30:
description: "获得超过30个成就"
_viewAchievements3min: _viewAchievements3min:
description: "盯着成就看三分钟" description: "盯着成就看三分钟"
_iLoveMisskey: _iLoveMisskey:
title: "I Love Misskey" title: "I Love Misskey"
description: "发布\"I ❤ #Misskey\"帖子" description: "发布\"I ❤ #Misskey\"帖子"
flavor: "感谢您使用 Misskey by 开发团队" flavor: "感谢您使用 Misskey by 开发团队"
_noteDeletedWithin1min:
description: "发帖后一分钟内就将其删除"
_postedAtLateNight:
title: "夜行者"
description: "深夜发布帖子"
_outputHelloWorldOnScratchpad: _outputHelloWorldOnScratchpad:
title: "Hello, world!" title: "Hello, world!"
_passedSinceAccountCreated1:
description: "账户创建时间超过1年"
_passedSinceAccountCreated2:
description: "账户创建时间超过2年"
_passedSinceAccountCreated3:
description: "账户创建时间超过3年"
_loggedInOnBirthday: _loggedInOnBirthday:
title: "生日快乐" title: "生日快乐"
description: "在生日当天登录" description: "在生日当天登录"

View file

@ -1042,6 +1042,18 @@ _achievements:
title: "貼文大師ⅠⅠⅠ" title: "貼文大師ⅠⅠⅠ"
description: "總登入天數為1,000天" description: "總登入天數為1,000天"
flavor: "感謝您使用Misskey" flavor: "感謝您使用Misskey"
_noteClipped1:
title: "忍不住要收進摘錄裡"
description: "第一次將貼文收進摘錄"
_noteFavorited1:
title: "觀星者"
description: "第一次將貼文收進我的最愛"
_profileFilled:
title: "有備而來"
description: "設定了個人檔案"
_markedAsCat:
title: "我是貓"
description: "已將帳戶設定為貓"
_followers500: _followers500:
title: "基站" title: "基站"
description: "超過500名追隨者" description: "超過500名追隨者"

View file

@ -1,6 +1,6 @@
{ {
"name": "misskey", "name": "misskey",
"version": "13.1.3", "version": "13.1.4",
"codename": "nasubi", "codename": "nasubi",
"repository": { "repository": {
"type": "git", "type": "git",

View file

@ -44,6 +44,7 @@ const ACHIEVEMENT_TYPES = [
'loggedInOnNewYearsDay', 'loggedInOnNewYearsDay',
'noteClipped1', 'noteClipped1',
'noteFavorited1', 'noteFavorited1',
'myNoteFavorited1',
'profileFilled', 'profileFilled',
'markedAsCat', 'markedAsCat',
'following1', 'following1',
@ -94,7 +95,7 @@ export class AchievementService {
@bindThis @bindThis
public async create( public async create(
userId: User['id'], userId: User['id'],
type: string, type: typeof ACHIEVEMENT_TYPES[number],
): Promise<void> { ): Promise<void> {
if (!ACHIEVEMENT_TYPES.includes(type)) return; if (!ACHIEVEMENT_TYPES.includes(type)) return;

View file

@ -6,6 +6,7 @@ import { Endpoint } from '@/server/api/endpoint-base.js';
import { GetterService } from '@/server/api/GetterService.js'; import { GetterService } from '@/server/api/GetterService.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import { ApiError } from '../../../error.js'; import { ApiError } from '../../../error.js';
import { AchievementService } from '@/core/AchievementService.js';
export const meta = { export const meta = {
tags: ['notes', 'favorites'], tags: ['notes', 'favorites'],
@ -51,6 +52,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
private idService: IdService, private idService: IdService,
private getterService: GetterService, private getterService: GetterService,
private achievementService: AchievementService,
) { ) {
super(meta, paramDef, async (ps, me) => { super(meta, paramDef, async (ps, me) => {
// Get favoritee // Get favoritee
@ -76,6 +78,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
noteId: note.id, noteId: note.id,
userId: me.id, userId: me.id,
}); });
if (note.userHost == null) {
this.achievementService.create(note.userId, 'myNoteFavorited1');
}
}); });
} }
} }

View file

@ -22,18 +22,13 @@
renderError('SOMETHING_HAPPENED_IN_PROMISE', e); renderError('SOMETHING_HAPPENED_IN_PROMISE', e);
}; };
const v = localStorage.getItem('v') || VERSION;
let forceError = localStorage.getItem('forceError'); let forceError = localStorage.getItem('forceError');
if (forceError != null) { if (forceError != null) {
renderError('FORCED_ERROR', 'This error is forced by having forceError in local storage.') renderError('FORCED_ERROR', 'This error is forced by having forceError in local storage.')
} }
//#region Detect language & fetch translations //#region Detect language & fetch translations
const localeVersion = localStorage.getItem('localeVersion'); if (!localStorage.hasOwnProperty('locale')) {
const localeOutdated = (localeVersion == null || localeVersion !== v);
if (!localStorage.hasOwnProperty('locale') || localeOutdated) {
const supportedLangs = LANGS; const supportedLangs = LANGS;
let lang = localStorage.getItem('lang'); let lang = localStorage.getItem('lang');
if (lang == null || !supportedLangs.includes(lang)) { if (lang == null || !supportedLangs.includes(lang)) {
@ -47,13 +42,31 @@
} }
} }
const res = await window.fetch(`/assets/locales/${lang}.${v}.json`); const metaRes = await window.fetch('/api/meta', {
if (res.status === 200) { method: 'POST',
body: JSON.stringify({}),
credentials: 'omit',
cache: 'no-cache',
headers: {
'Content-Type': 'application/json',
},
});
if (metaRes.status !== 200) {
renderError('META_FETCH');
return;
}
const meta = await res.json();
const v = meta.version;
if (v == null) {
renderError('META_FETCH_V');
return;
}
const localRes = await window.fetch(`/assets/locales/${lang}.${v}.json`);
if (localRes.status === 200) {
localStorage.setItem('lang', lang); localStorage.setItem('lang', lang);
localStorage.setItem('locale', await res.text()); localStorage.setItem('locale', await localRes.text());
localStorage.setItem('localeVersion', v); localStorage.setItem('localeVersion', v);
} else { } else {
await checkUpdate();
renderError('LOCALE_FETCH'); renderError('LOCALE_FETCH');
return; return;
} }
@ -64,7 +77,6 @@
function importAppScript() { function importAppScript() {
import(`/vite/${CLIENT_ENTRY}`) import(`/vite/${CLIENT_ENTRY}`)
.catch(async e => { .catch(async e => {
await checkUpdate();
console.error(e); console.error(e);
renderError('APP_IMPORT', e); renderError('APP_IMPORT', e);
}); });
@ -291,48 +303,4 @@
} }
`) `)
} }
// eslint-disable-next-line no-inner-declarations
async function checkUpdate() {
try {
const res = await window.fetch('/api/meta', {
method: 'POST',
cache: 'no-cache',
body: '{}',
headers: {
'Content-Type': 'application/json',
},
});
const meta = await res.json();
if (meta.version == null) {
throw new Error('failed to fetch instance metadata');
}
if (meta.version != v) {
localStorage.setItem('v', meta.version);
refresh();
}
} catch (e) {
console.error(e);
renderError('UPDATE_CHECK', e);
throw e;
}
}
// eslint-disable-next-line no-inner-declarations
function refresh() {
// Clear cache (service worker)
try {
navigator.serviceWorker.controller.postMessage('clear');
navigator.serviceWorker.getRegistrations().then(registrations => {
registrations.forEach(registration => registration.unregister());
});
} catch (e) {
console.error(e);
}
location.reload();
}
})(); })();

View file

@ -10,8 +10,12 @@ export const apiUrl = url + '/api';
export const wsUrl = url.replace('http://', 'ws://').replace('https://', 'wss://') + '/streaming'; export const wsUrl = url.replace('http://', 'ws://').replace('https://', 'wss://') + '/streaming';
export const lang = miLocalStorage.getItem('lang'); export const lang = miLocalStorage.getItem('lang');
export const langs = _LANGS_; export const langs = _LANGS_;
export const locale = JSON.parse(miLocalStorage.getItem('locale')); export let locale = JSON.parse(miLocalStorage.getItem('locale'));
export const version = _VERSION_; export const version = _VERSION_;
export const instanceName = siteName === 'Misskey' ? host : siteName; export const instanceName = siteName === 'Misskey' ? host : siteName;
export const ui = miLocalStorage.getItem('ui'); export const ui = miLocalStorage.getItem('ui');
export const debug = miLocalStorage.getItem('debug') === 'true'; export const debug = miLocalStorage.getItem('debug') === 'true';
export function updateLocale(newLocale) {
locale = newLocale;
}

View file

@ -3,3 +3,7 @@ import { locale } from '@/config';
import { I18n } from '@/scripts/i18n'; import { I18n } from '@/scripts/i18n';
export const i18n = markRaw(new I18n(locale)); export const i18n = markRaw(new I18n(locale));
export function updateI18n(newLocale) {
i18n.ts = newLocale;
}

View file

@ -25,10 +25,10 @@ import JSON5 from 'json5';
import widgets from '@/widgets'; import widgets from '@/widgets';
import directives from '@/directives'; import directives from '@/directives';
import components from '@/components'; import components from '@/components';
import { version, ui, lang, host } from '@/config'; import { version, ui, lang, host, updateLocale } from '@/config';
import { applyTheme } from '@/scripts/theme'; import { applyTheme } from '@/scripts/theme';
import { isDeviceDarkmode } from '@/scripts/is-device-darkmode'; import { isDeviceDarkmode } from '@/scripts/is-device-darkmode';
import { i18n } from '@/i18n'; import { i18n, updateI18n } from '@/i18n';
import { confirm, alert, post, popup, toast } from '@/os'; import { confirm, alert, post, popup, toast } from '@/os';
import { stream } from '@/stream'; import { stream } from '@/stream';
import * as sound from '@/scripts/sound'; import * as sound from '@/scripts/sound';
@ -87,9 +87,12 @@ import { fetchCustomEmojis } from './custom-emojis';
if (localeOutdated) { if (localeOutdated) {
const res = await window.fetch(`/assets/locales/${lang}.${version}.json`); const res = await window.fetch(`/assets/locales/${lang}.${version}.json`);
if (res.status === 200) { if (res.status === 200) {
miLocalStorage.setItem('locale', await res.text()); const newLocale = await res.text();
const parsedNewLocale = JSON.parse(newLocale);
miLocalStorage.setItem('locale', newLocale);
miLocalStorage.setItem('localeVersion', version); miLocalStorage.setItem('localeVersion', version);
location.reload(); updateLocale(parsedNewLocale);
updateI18n(parsedNewLocale);
} }
} }
//#endregion //#endregion

View file

@ -40,6 +40,7 @@ export const ACHIEVEMENT_TYPES = [
'loggedInOnNewYearsDay', 'loggedInOnNewYearsDay',
'noteClipped1', 'noteClipped1',
'noteFavorited1', 'noteFavorited1',
'myNoteFavorited1',
'profileFilled', 'profileFilled',
'markedAsCat', 'markedAsCat',
'following1', 'following1',
@ -240,6 +241,11 @@ export const ACHIEVEMENT_BADGES = {
bg: null, bg: null,
frame: 'bronze', frame: 'bronze',
}, },
'myNoteFavorited1': {
img: '/fluent-emoji/1f320.png',
bg: null,
frame: 'silver',
},
'profileFilled': { 'profileFilled': {
img: '/fluent-emoji/1f44c.png', img: '/fluent-emoji/1f44c.png',
bg: 'linear-gradient(0deg, rgb(187 183 59), rgb(255 143 77))', bg: 'linear-gradient(0deg, rgb(187 183 59), rgb(255 143 77))',