Compare commits

..

85 Commits

Author SHA1 Message Date
syuilo
ae63a1f494 Merge branch 'develop' 2023-01-24 17:30:59 +09:00
syuilo
117ac53505 13.2.1 2023-01-24 17:30:51 +09:00
syuilo
2c379732d2 New Crowdin updates (#9696)
* New translations ja-JP.yml (Chinese Simplified)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Thai)

* New translations ja-JP.yml (Italian)

* New translations ja-JP.yml (Thai)

* New translations ja-JP.yml (Italian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Chinese Traditional)

* New translations ja-JP.yml (Italian)

* New translations ja-JP.yml (Chinese Traditional)
2023-01-24 17:28:38 +09:00
syuilo
9ca1197759 🎨 2023-01-24 17:26:49 +09:00
syuilo
8d3283e2a5 tweak ti style 2023-01-24 17:25:52 +09:00
tamaina
6589e8a390 Fix #9710 ? (#9712)
* wip

* update pnpm-lock

* use our own DevNull

* fix

* deliverJobConcurrencyをmacSocketsで割ってソケット数にする
2023-01-24 15:54:14 +09:00
syuilo
b62894ff56 use minified css 2023-01-24 15:02:16 +09:00
syuilo
da274cd458 update deps 2023-01-24 14:49:29 +09:00
syuilo
a2268a95be 🎨 2023-01-24 14:10:26 +09:00
tamaina
9fd1b35d95 fix TypeError: Cannot read properties of undefined (reading 'getLogger') 2023-01-24 01:34:14 +00:00
syuilo
869854eae7 コミット漏れ 2023-01-24 08:32:17 +09:00
syuilo
238f923b41 refactor(server): httpRequestServiceのUndiciFetcher依存をなるべくカプセル化 2023-01-24 08:31:02 +09:00
syuilo
a5df2b0293 Merge branch 'develop' 2023-01-23 20:13:46 +09:00
syuilo
e6eae558d3 13.2.0 2023-01-23 20:13:38 +09:00
syuilo
083fa53d9c update deps 2023-01-23 20:13:18 +09:00
syuilo
7b73dd2d62 enhance(server): onlyServer / onlyQueue オプションを復活 2023-01-23 20:07:48 +09:00
syuilo
7028b7331b 他人の実績閲覧時は獲得条件を表示しないように 2023-01-23 16:40:31 +09:00
syuilo
eefebab530 アニメーション減らすオプション有効時はリアクションのアニメーションを無効に 2023-01-23 16:36:47 +09:00
syuilo
683ddbef3e update contributors 2023-01-23 16:33:47 +09:00
syuilo
bd23522c76 enhance(client): カスタム絵文字一覧のパフォーマンスを改善 2023-01-23 16:19:13 +09:00
nexryai
c1dfbe2623 Hide the value of the object storage secret key input form in the control panel (#9706) 2023-01-23 16:08:09 +09:00
syuilo
ed9facbb33 fix(client): Aiscript: button is not defined
Fix #9704
2023-01-23 12:53:44 +09:00
syuilo
70df8c77fa Merge branch 'develop' 2023-01-22 21:30:06 +09:00
syuilo
2c52655b17 13.1.8 2023-01-22 21:29:57 +09:00
syuilo
6c4c071ae9 New Crowdin updates (#9692)
* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Ukrainian)
2023-01-22 21:28:34 +09:00
tamaina
b19dba80f4 Fix #9691 2023-01-22 12:25:55 +00:00
syuilo
09f4b9e546 Merge branch 'develop' 2023-01-22 21:01:52 +09:00
syuilo
2e6d8c792b 13.1.7 2023-01-22 21:01:42 +09:00
syuilo
e6338a555d mfmにscaleを追加
Resolve #9609
2023-01-22 20:58:52 +09:00
syuilo
313a489ba0 New Crowdin updates (#9689)
* New translations ja-JP.yml (Chinese Traditional)

* New translations ja-JP.yml (Chinese Simplified)

* New translations ja-JP.yml (Italian)

* New translations ja-JP.yml (Ukrainian)
2023-01-22 20:46:43 +09:00
syuilo
b906ff3fed add an achievement 2023-01-22 20:30:56 +09:00
syuilo
ede96eca28 🎨 2023-01-22 20:25:10 +09:00
syuilo
42f3d9188b add a secret achievement 2023-01-22 20:22:38 +09:00
syuilo
a35e0e9261 Merge branch 'develop' 2023-01-22 17:30:12 +09:00
syuilo
80a400a67c 13.1.6 2023-01-22 17:30:04 +09:00
syuilo
7a6534f30b カスタム絵文字のURLが空文字列になる場合があるのを修正 2023-01-22 17:29:31 +09:00
syuilo
68a523ec6d Merge branch 'develop' 2023-01-22 17:19:13 +09:00
syuilo
97d6c1ee86 13.1.5 2023-01-22 17:19:03 +09:00
syuilo
19c93151ce tweak boot.js 2023-01-22 17:18:48 +09:00
syuilo
039a2af3ab tweak boot.js 2023-01-22 17:18:39 +09:00
syuilo
945129c371 Merge branch 'develop' 2023-01-22 17:11:00 +09:00
syuilo
da32be3ef3 13.1.4 2023-01-22 17:10:49 +09:00
syuilo
468ec36830 New Crowdin updates (#9685)
* New translations ja-JP.yml (Italian)

* New translations ja-JP.yml (Italian)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Chinese Simplified)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Chinese Simplified)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Chinese Traditional)
2023-01-22 17:09:26 +09:00
syuilo
492fb9a115 Update CHANGELOG.md 2023-01-22 17:06:18 +09:00
syuilo
bd8b624bae tweak bootstrap of client 2023-01-22 17:04:51 +09:00
syuilo
9dacf11702 fix(client): ローカリゼーション更新時にリロードが繰り返されることがあるのを修正 2023-01-22 16:52:15 +09:00
syuilo
26ae2dfc0f add achievement 2023-01-22 08:00:42 +09:00
syuilo
a7f43d5312 Merge branch 'develop' 2023-01-22 07:05:13 +09:00
syuilo
7fdf298bd4 13.1.3 2023-01-22 07:04:58 +09:00
syuilo
7d7167df6d New Crowdin updates (#9680)
* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Italian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Italian)

* New translations ja-JP.yml (Russian)
2023-01-22 07:04:30 +09:00
syuilo
aa339be2ab fix(client): リアクションのカスタム絵文字が表示されないことがあるのを修正
Fix #9683
2023-01-22 07:04:20 +09:00
syuilo
1217d6fbb4 Merge branch 'develop' 2023-01-22 05:40:56 +09:00
syuilo
ccb22539e1 13.1.2 2023-01-22 05:40:48 +09:00
syuilo
957eff0e63 fix(client): リアクションのカスタム絵文字が表示されないのを修正
Fix #9682
2023-01-22 05:39:33 +09:00
syuilo
363d727c55 refactor 2023-01-22 05:33:26 +09:00
syuilo
31dcf713cc Merge branch 'develop' 2023-01-22 04:28:55 +09:00
syuilo
7800a12e52 13.1.1 2023-01-22 04:28:43 +09:00
syuilo
d6ff50a30b New Crowdin updates (#9676)
* New translations ja-JP.yml (German)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Chinese Simplified)

* New translations ja-JP.yml (Chinese Traditional)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Chinese Traditional)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Chinese Simplified)

* New translations ja-JP.yml (Chinese Traditional)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Chinese Simplified)

* New translations ja-JP.yml (Chinese Traditional)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Russian)
2023-01-22 04:28:19 +09:00
syuilo
ead931211c fix(client): 実績解除リクエストの間隔をあけるように
Fix #9674
2023-01-22 04:24:38 +09:00
syuilo
a3aafa03ad update deps 2023-01-22 04:17:58 +09:00
syuilo
307a882649 tweak fetchCustomEmojis timing 2023-01-21 20:53:11 +09:00
syuilo
3e112da486 ローカルのカスタム絵文字については直接オリジナルURLにリクエストするように 2023-01-21 20:40:09 +09:00
syuilo
bd469420fa fix(client): クライアント起動時にも言語ファイルのチェックを行うように
Fix #9005
2023-01-21 20:24:15 +09:00
syuilo
38fde26d60 Merge branch 'develop' 2023-01-21 18:45:50 +09:00
syuilo
dc4fd3e505 13.1.0 2023-01-21 18:45:41 +09:00
syuilo
4dc00ee72a New translations ja-JP.yml (English) (#9673) 2023-01-21 18:41:53 +09:00
CyberRex
bd3d75df6b Update chokidar and use pnpm exec (#9640)
* Fix for dev mode

* Update packages/frontend/package.json

Co-authored-by: tamaina <tamaina@hotmail.co.jp>

Co-authored-by: tamaina <tamaina@hotmail.co.jp>
2023-01-21 18:41:30 +09:00
syuilo
d56fc41865 Merge branch 'develop' 2023-01-16 15:21:43 +09:00
rinsuki
fcabc99303 masterブランチをmaster_securityとマージ (#9260)
* Fix: forkbomb 2

* 12.119.2

Co-authored-by: mei23 <m@m544.net>
2022-12-04 05:34:51 +09:00
syuilo
fccd9c32e8 12.119.1 2022-12-03 18:42:19 +09:00
syuilo
58a3a0b7d4 forkbomb DOS mitigation 2022-12-03 18:42:06 +09:00
syuilo
a2a1636c10 Merge branch 'develop' 2022-09-10 19:26:43 +09:00
syuilo
46ec0303b7 Merge branch 'develop' 2022-08-08 11:39:04 +09:00
syuilo
3b1669fb6b Merge branch 'develop' 2022-08-07 00:39:21 +09:00
syuilo
09591fa4ae Merge branch 'develop' 2022-07-19 17:22:32 +09:00
syuilo
85ce00adc0 Merge branch 'develop' 2022-07-18 05:07:12 +09:00
syuilo
f25518af91 Merge branch 'develop' 2022-07-17 05:35:36 +09:00
syuilo
b796aacf7f Merge branch 'develop' 2022-07-16 23:53:24 +09:00
syuilo
ff24811676 Merge branch 'develop' 2022-07-16 18:21:44 +09:00
syuilo
4c8a1867f0 Merge branch 'develop' 2022-07-15 22:45:13 +09:00
syuilo
bce48dfee9 Merge branch 'develop' 2022-07-13 21:59:47 +09:00
syuilo
c20311b8a7 Merge branch 'develop' 2022-07-09 18:32:55 +09:00
syuilo
fb14ac50b8 Merge branch 'develop' 2022-07-08 17:34:53 +09:00
syuilo
84d984bd31 Merge branch 'develop' 2022-07-07 21:23:03 +09:00
syuilo
1bc856c451 Merge pull request #8821 from misskey-dev/develop
Release: 12.111.1
2022-06-13 00:41:09 +09:00
55 changed files with 2497 additions and 622 deletions

View File

@@ -9,7 +9,56 @@
You should also include the user name that made the change.
-->
## 13.x.x (unreleased)
## 13.2.1 (2023/01/24)
### Improvements
- デザインの調整
- サーバーのパフォーマンスを改善
## 13.2.0 (2023/01/23)
### Improvements
- onlyServer / onlyQueue オプションを復活
- 他人の実績閲覧時は獲得条件を表示しないように
- アニメーション減らすオプション有効時はリアクションのアニメーションを無効に
- カスタム絵文字一覧のパフォーマンスを改善
### Bugfixes
- Aiscript: button is not defined
## 13.1.7 (2023/01/22)
### Improvements
- 新たな実績を追加
- MFMにscaleタグを追加
## 13.1.4 (2023/01/22)
### Improvements
- 新たな実績を追加
### Bugfixes
- Client: ローカリゼーション更新時にリロードが繰り返されることがあるのを修正
## 13.1.3 (2023/01/22)
### Bugfixes
- Client: リアクションのカスタム絵文字の表示の問題を修正
## 13.1.2 (2023/01/22)
### Bugfixes
- Client: リアクションのカスタム絵文字の表示の問題を修正
## 13.1.1 (2023/01/22)
### Improvements
- ローカルのカスタム絵文字を表示する際のパフォーマンスを改善
- Client: 瞬間的に大量の実績を解除した際の挙動を改善
### Bugfixes
- Client: アップデート時にローカリゼーションデータが更新されないことがあるのを修正
## 13.1.0 (2023/01/21)
### Improvements
- 実績機能
@@ -46,6 +95,7 @@ You should also include the user name that made the change.
- Node.js 18.x or later is required
- PostgreSQL 15.x is required
- 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も利用できます
- Yarnからpnpmに移行されました

View File

@@ -20,7 +20,7 @@ gulp.task('copy:frontend:fonts', () =>
);
gulp.task('copy:frontend:tabler-icons', () =>
gulp.src('./packages/frontend/node_modules/@tabler/icons/iconfont/**/*').pipe(gulp.dest('./built/_frontend_dist_/tabler-icons/'))
gulp.src('./packages/frontend/node_modules/@tabler/icons-webfont/**/*').pipe(gulp.dest('./built/_frontend_dist_/tabler-icons/'))
);
gulp.task('copy:frontend:locales', cb => {

View File

@@ -938,6 +938,243 @@ cannotPerformTemporary: "Vorübergehend nicht verfügbar"
cannotPerformTemporaryDescription: "Diese Aktion ist wegen des Überschreitenes des Ausführungslimits temporär nicht verfügbar. Bitte versuche es nach einiger Zeit erneut."
preset: "Vorlage"
selectFromPresets: "Aus Vorlagen wählen"
achievements: "Errungenschaften"
_achievements:
earnedAt: "Freigeschaltet am"
_types:
_notes1:
title: "Hallo Misskey!"
description: "Sende deine erste Notiz"
flavor: "Hab eine schöne Zeit mit Misskey!"
_notes10:
title: "Ein paar Notizen"
description: "10 Notizen gesendet"
_notes100:
title: "Viele Notizen"
description: "100 Notizen gesendet"
_notes500:
title: "Überschüttet mit Notizen"
description: "500 Notizen gesendet"
_notes1000:
title: "Berg an Notizen"
description: "1.000 Notizen gesendet"
_notes5000:
title: "Überquellende Notizen"
description: "5.000 Notizen gesendet"
_notes10000:
title: "Supernotiz"
description: "10.000 Notizen gesendet"
_notes20000:
title: "Brauche... mehr... Notizen"
description: "20.000 Notizen gesendet"
_notes30000:
title: "Notizen, Notizen, Notizen"
description: "30.000 Notizen gesendet"
_notes40000:
title: "Notizfabrik"
description: "40.000 Notizen gesendet"
_notes50000:
title: "Planet der Notizen"
description: "50.000 Notizen gesendet"
_notes60000:
title: "Notizquasar"
description: "60.000 Notizen gesendet"
_notes70000:
title: "Schwarzes Notizloch"
description: "70.000 Notizen gesendet"
_notes80000:
title: "Notizgalaxie"
description: "80.000 Notizen gesendet"
_notes90000:
title: "Notizversum"
description: "90.000 Notizen gesendet"
_notes100000:
title: "ALL YOUR NOTE ARE BELONG TO US"
description: "100.000 Notizen gesendet"
flavor: "Du hast wirklich viel zu sagen."
_login3:
title: "Anfänger "
description: "An 3 Tagen eingeloggt"
flavor: "Nenn' mich ab heute Misskist"
_login7:
title: "Anfänger Ⅱ"
description: "An 7 Tagen eingeloggt"
flavor: "Na, eingewöht?"
_login15:
title: "Anfänger Ⅲ"
description: "An 15 Tagen eingeloggt"
_login30:
title: "Misskist "
description: "An 30 Tagen eingeloggt"
_login60:
title: "Misskist Ⅱ"
description: "An 60 Tagen eingeloggt"
_login100:
title: "Misskist Ⅲ"
description: "An 100 Tagen eingeloggt"
flavor: "Violent Misskist"
_login200:
title: "Stammbesucher "
description: "An 200 Tagen eingeloggt"
_login300:
title: "Stammbesucher Ⅱ"
description: "An 300 Tagen eingeloggt"
_login400:
title: "Stammbesucher Ⅲ"
description: "An 400 Tagen eingeloggt"
_login500:
title: "Veteran "
description: "An 500 Tagen eingeloggt"
flavor: "Meine Kameraden, ich liebe sie, die Notizen."
_login600:
title: "Veteran Ⅱ"
description: "An 600 Tagen eingeloggt"
_login700:
title: "Veteran Ⅲ"
description: "An 700 Tagen eingeloggt"
_login800:
title: "Meister der Notizen "
description: "An 800 Tagen eingeloggt"
_login900:
title: "Meister der Notizen Ⅱ"
description: "An 900 Tagen eingeloggt"
_login1000:
title: "Meister der Notizen Ⅲ"
description: "An 1000 Tagen eingeloggt"
flavor: "Danke, dass du Misskey nutzt!"
_noteClipped1:
title: "Muss... clippen..."
description: "Die erste Notiz geclippt"
_noteFavorited1:
title: "Sternengucker"
description: "Eine Notiz als Favorit markiert"
_myNoteFavorited1:
title: "Sternensucher"
description: "Ein anderer Benutzer hat eine deiner Notizen als Favoriten markiert"
_profileFilled:
title: "Perfekte Vorbereitung"
description: "Fülle dein Profil aus"
_markedAsCat:
title: "Ich der Kater"
description: "Markiere dein Konto als Katze"
flavor: "Einen Namen bekommst du später. "
_following1:
title: "Das Folgen beginnt"
description: "Du folgst deiner ersten Person"
_following10:
title: "Folge ihnen... folge ihnen..."
description: "Du folgst über 10 Leuten"
_following50:
title: "Viele Freunde"
description: "Du folgst über 50 Leuten"
_following100:
title: "100 Freunde"
description: "Du folgst über 100 Leuten"
_following300:
title: "Freundeüberschuss"
description: "Du folgst über 300 Leuten"
_followers1:
title: "Der erste Follower"
description: "Du hast deinen ersten Follower erhalten"
_followers10:
title: "Mir nach!"
description: "Die Anzahl deiner Follower hat 10 überschritten"
_followers50:
title: "Wirrwarr"
description: "Die Anzahl deiner Follower hat 50 überschritten"
_followers100:
title: "Beliebt"
description: "Die Anzahl deiner Follower hat 100 überschritten"
_followers300:
title: "Stellt euch bitte in einer Reihe auf"
description: "Die Anzahl deiner Follower hat 300 überschritten"
_followers500:
title: "Funkmast"
description: "Die Anzahl deiner Follower hat 500 überschritten"
_followers1000:
title: "Influencer"
description: "Die Anzahl deiner Follower hat 1000 überschritten"
_collectAchievements30:
title: "Sammler der Errungenschaften"
description: "Schalte 30 Errungenschaften frei"
_viewAchievements3min:
title: "Fan von Errungenschaften"
description: "Schau dir die Liste deiner Errungenschaften für mindestens 3 Minuten an"
_iLoveMisskey:
title: "I Love Misskey"
description: "Sende \"I ❤ #Misskey\""
flavor: "Danke, dass du Misskey verwendest! - vom Entwicklerteam"
_foundTreasure:
title: "Schatzsuche"
description: "Du hast einen verborgenen Schatz gefunden"
_client30min:
title: "Kurze Pause"
description: "Habe Misskey für 30 Minuten geöffnet"
_noteDeletedWithin1min:
title: "Ups"
description: "Lösche eine Notiz innerhalb von 1 Minute nachdem sie gesendet wurde"
_postedAtLateNight:
title: "Nachtaktiv"
description: "Sende mitten in der Nacht eine Notiz"
flavor: "Geh bald schlafen."
_postedAt0min0sec:
title: "Zeitansage"
description: "Sende um 00:00 eine Notiz"
flavor: "Klick Klick Klick Dooong"
_selfQuote:
title: "Selbstzitat"
description: "Zitiere eine eigene Notiz"
_htl20npm:
title: "Fließende Chronik"
description: "Deine Startseitenchronik erreicht eine Geschwindigkeit von 20 npm (Notizen pro Minute)"
_viewInstanceChart:
title: "Analyst"
description: "Schau dir die Messwerte der Instanz an"
_outputHelloWorldOnScratchpad:
title: "Hallo Welt!"
description: "Gib \"hello world\" in der Testumgebung aus"
_open3windows:
title: "Splitscreen"
description: "Habe zur gleichen Zeit mindestens 3 Fenster offen"
_driveFolderCircularReference:
title: "Zyklischer Verweis"
description: "Versuche, in Drive einen Zirkelbezug von Ordnern herzustellen"
_reactWithoutRead:
title: "Hast du das wirklich gelesen?"
description: "Reagiere auf eine Notiz mit mindestens 100 Zeichen innerhalb von 3 Sekunden der Erstellung der Notiz"
_clickedClickHere:
title: "Klicke hier"
description: "Du hast hier geklickt"
_justPlainLucky:
title: "Pures Glück"
description: "Kann alle 10 Sekunden mit einer Warscheinlichkeit von 0.01% erhalten werden"
_setNameToSyuilo:
title: "Gottkomplex"
description: "Setze deinen Namen auf \"syuilo\""
_passedSinceAccountCreated1:
title: "Einjahresjubiläum"
description: "Seit der Erstellung deines Kontos ist 1 Jahr vergangen"
_passedSinceAccountCreated2:
title: "Zweijahresjubiläum"
description: "Seit der Erstellung deines Kontos sind 2 Jahre vergangen"
_passedSinceAccountCreated3:
title: "Dreijahresjubiläum"
description: "Seit der Erstellung deines Kontos sind 3 Jahre vergangen"
_loggedInOnBirthday:
title: "Alles Gute Zum Geburtstag"
description: "Logge dich an deinem Geburtstag ein"
_loggedInOnNewYearsDay:
title: "Frohes Neujahr"
description: "Logge dich am Neujahrstag ein"
flavor: "Auf ein weiteres tolles Jahr in dieser Instanz"
_cookieClicked:
title: "Ein Spiel, in dem du auf einen Keks klickst"
description: "Den Keks geklickt"
flavor: "Bist du hier richtig?"
_brainDiver:
title: "Brain Diver"
description: "Sende den Link zu Brain Diver"
flavor: "Misskey-Misskey La-Tu-Ma"
_role:
new: "Rolle erstellen"
edit: "Rolle bearbeiten"
@@ -1587,6 +1824,7 @@ _notification:
pollEnded: "Umfrageergebnisse sind verfügbar"
unreadAntennaNote: "Antenne {name}"
emptyPushNotificationMessage: "Push-Benachrichtigungen wurden aktualisiert"
achievementEarned: "Errungenschaft freigeschaltet"
_types:
all: "Alle"
follow: "Neue Follower"

View File

@@ -938,6 +938,243 @@ cannotPerformTemporary: "Temporarily unavailable"
cannotPerformTemporaryDescription: "This action cannot be performed temporarily due to exceeding the execution limit. Please wait for a while and then try again."
preset: "Preset"
selectFromPresets: "Choose from presets"
achievements: "Achievements"
_achievements:
earnedAt: "Unlocked at"
_types:
_notes1:
title: "just setting up my msky"
description: "Post your first note"
flavor: "Have a good time with Misskey!"
_notes10:
title: "Some notes"
description: "Post 10 notes"
_notes100:
title: "A lot of notes"
description: "Post 100 notes"
_notes500:
title: "Covered in notes"
description: "Post 500 notes"
_notes1000:
title: "A mountain of notes"
description: "Post 1,000 notes"
_notes5000:
title: "Overflowing notes"
description: "Post 5,000 notes"
_notes10000:
title: "Supernote"
description: "Post 10,000 notes"
_notes20000:
title: "Need... more... notes..."
description: "Post 20,000 notes"
_notes30000:
title: "Notes notes notes!"
description: "Post 30,000 notes"
_notes40000:
title: "Note factory"
description: "Post 40,000 notes"
_notes50000:
title: "Planet of notes"
description: "Post 50,000 notes"
_notes60000:
title: "Note quasar"
description: "Post 60,000 notes"
_notes70000:
title: "Note black hole"
description: "Post 70,000 notes"
_notes80000:
title: "Note galaxy"
description: "Post 80,000 notes"
_notes90000:
title: "Note universe"
description: "Post 90,000 notes"
_notes100000:
title: "ALL YOUR NOTE ARE BELONG TO US"
description: "Post 100,000 notes"
flavor: "You sure have a lot to say."
_login3:
title: "Beginner I"
description: "Log in for a total of 3 days"
flavor: "Starting today, just call me Misskist"
_login7:
title: "Beginner II"
description: "Log in for a total of 7 days"
flavor: "Feel like you've gotten the hang of things yet?"
_login15:
title: "Beginner III"
description: "Log in for a total of 15 days"
_login30:
title: "Misskist I"
description: "Log in for a total of 30 days"
_login60:
title: "Misskist II"
description: "Log in for a total of 60 days"
_login100:
title: "Misskist III"
description: "Log in for a total of 100 days"
flavor: "Violent Misskist"
_login200:
title: "Regular I"
description: "Log in for a total of 200 days"
_login300:
title: "Regular II"
description: "Log in for a total of 300 days"
_login400:
title: "Regular III"
description: "Log in for a total of 400 days"
_login500:
title: "Expert I"
description: "Log in for a total of 500 days"
flavor: "My friends, it has often been said that I like notes"
_login600:
title: "Expert II"
description: "Log in for a total of 600 days"
_login700:
title: "Expert III"
description: "Log in for a total of 700 days"
_login800:
title: "Master of Notes I"
description: "Log in for a total of 800 days"
_login900:
title: "Master of Notes II"
description: "Log in for a total of 900 days"
_login1000:
title: "Master of Notes III"
description: "Log in for a total of 1,000 days"
flavor: "Thank you for using Misskey!"
_noteClipped1:
title: "Must... clip..."
description: "Clip your first note"
_noteFavorited1:
title: "Stargazer"
description: "Favorite your first note"
_myNoteFavorited1:
title: "Seeking Stars"
description: "Have somebody else favorite one of your notes"
_profileFilled:
title: "Well-prepared"
description: "Set up your profile"
_markedAsCat:
title: "I Am a Cat"
description: "Mark your account as a cat"
flavor: "I'll give you a name later."
_following1:
title: "Following your first user"
description: "Follow a user"
_following10:
title: "Keep up... keep up..."
description: "Follow 10 users"
_following50:
title: "Lots of friends"
description: "Follow 50 accounts"
_following100:
title: "100 Friends"
description: "Follow 100 accounts"
_following300:
title: "Friend overload"
description: "Follow 300 accounts"
_followers1:
title: "First follower"
description: "Gain 1 follower"
_followers10:
title: "Follow me!"
description: "Gain 10 followers"
_followers50:
title: "Coming in crowds"
description: "Gain 50 followers"
_followers100:
title: "Popular"
description: "Gain 100 followers"
_followers300:
title: "Please form a single line"
description: "Gain 300 followers"
_followers500:
title: "Radio Tower"
description: "Gain 500 followers"
_followers1000:
title: "Influencer"
description: "Gain 1,000 followers"
_collectAchievements30:
title: "Achievement Collector"
description: "Earn 30 achievements"
_viewAchievements3min:
title: "Likes Achievements"
description: "Look at your list of achievements for at least 3 minutes"
_iLoveMisskey:
title: "I Love Misskey"
description: "Post \"I ❤ #Misskey\""
flavor: "Misskey's development team greatly appreciates your support!"
_foundTreasure:
title: "Treasure Hunt"
description: "You've found the hidden treasure"
_client30min:
title: "Short break"
description: "Spend 30 minutes on Misskey"
_noteDeletedWithin1min:
title: "Nevermind"
description: "Delete a note within a minute of posting it"
_postedAtLateNight:
title: "Nocturnal"
description: "Post a note late at night"
flavor: "It's about time to go to bed."
_postedAt0min0sec:
title: "Speaking Clock"
description: "Post a note at 00:00"
flavor: "Click Click Click Claaang"
_selfQuote:
title: "Self-Reference"
description: "Quote your own note"
_htl20npm:
title: "Flowing Timeline"
description: "Have the speed of your home timeline exceed 20 npm (notes per minute)"
_viewInstanceChart:
title: "Analyst"
description: "View your instance's charts"
_outputHelloWorldOnScratchpad:
title: "Hello, world!"
description: "Output \"hello world\" in the Scratchpad"
_open3windows:
title: "Multi-Window"
description: "Have at least 3 windows open at the same time"
_driveFolderCircularReference:
title: "Circular Reference"
description: "Attempt to create a recursively nested folder in Drive"
_reactWithoutRead:
title: "Did you really read that?"
description: "React on a note that's over 100 characters long within 3 seconds of it being posted"
_clickedClickHere:
title: "Click here"
description: "You've clicked here"
_justPlainLucky:
title: "Just Plain Lucky"
description: "Has a chance to be obtained with a probability of 0.01% every 10 seconds"
_setNameToSyuilo:
title: "God Complex"
description: "Set your name to \"syuilo\""
_passedSinceAccountCreated1:
title: "One Year Anniversary"
description: "One year has passed since your account was created"
_passedSinceAccountCreated2:
title: "Two Year Anniversary"
description: "Two years have passed since your account was created"
_passedSinceAccountCreated3:
title: "Three Year Anniversary"
description: "Three years have passed since your account was created"
_loggedInOnBirthday:
title: "Happy Birthday"
description: "Log in on your birthday"
_loggedInOnNewYearsDay:
title: "Happy New Year!"
description: "Logged in on the first day of the year"
flavor: "To another great year on this instance"
_cookieClicked:
title: "A game in which you click cookies"
description: "Clicked the cookie"
flavor: "Wait, are you on the correct website?"
_brainDiver:
title: "Brain Diver"
description: "Post the link to Brain Diver"
flavor: "Misskey-Misskey La-Tu-Ma"
_role:
new: "New role"
edit: "Edit role"
@@ -1587,6 +1824,7 @@ _notification:
pollEnded: "Poll results have become available"
unreadAntennaNote: "Antenna {name}"
emptyPushNotificationMessage: "Push notifications have been updated"
achievementEarned: "Achievement unlocked"
_types:
all: "All"
follow: "New followers"

View File

@@ -1,7 +1,7 @@
---
_lang_: "Italiano"
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>."
monthAndDay: "{day}/{month}"
search: "Cerca"
@@ -95,7 +95,7 @@ follow: "Segui"
followRequest: "Richiesta di follow"
followRequests: "Richieste di follow"
unfollow: "Smetti di seguire"
followRequestPending: "La richiesta di follow deve essere approvata"
followRequestPending: "Richiesta in approvazione"
enterEmoji: "Inserisci emoji"
renote: "Rinota"
unrenote: "Annulla rinota"
@@ -938,6 +938,243 @@ cannotPerformTemporary: "Indisponibilità temporanea"
cannotPerformTemporaryDescription: "L'attività non può essere svolta, poiché si è raggiunto il limite di esecuzioni possibili. Per favore, riprova più tardi."
preset: "Preimpostato"
selectFromPresets: "Seleziona preimpostato"
achievements: "Obiettivi raggiunti"
_achievements:
earnedAt: "Data di conseguimento"
_types:
_notes1:
title: "Hai iniziato a usare Misskey"
description: "Hai pubblicato la prima Nota"
flavor: "Goditi la vita su Misskey!"
_notes10:
title: "Alcune Note"
description: "Hai inserito 10 Note"
_notes100:
title: "Un po' di Note"
description: "Hai inserito 100 Note"
_notes500:
title: "Un bel po' di Note"
description: "Hai inserito 500 Note"
_notes1000:
title: "Una montagna di Note"
description: "Hai inserito 1.000 Note"
_notes5000:
title: "Un sovraccarico di Note!"
description: "Hai inserito 5.000 Note"
_notes10000:
title: "SuperNote!"
description: "Hai inserito 10.000 Note"
_notes20000:
title: "Voglio più... Note!"
description: "Hai inserito 20.000 Note"
_notes30000:
title: "Note, Note, Note!"
description: "Hai inserito 30.000 Note"
_notes40000:
title: "Una fabbrica di Note"
description: "Hai inserito 40.000 Note"
_notes50000:
title: "Un pianeta di Note"
description: "Hai inserito 50.000 Note"
_notes60000:
title: "Un quasar di Note"
description: "Hai inserito 60.000 Note"
_notes70000:
title: "Un buco nero supermassiccio di Note"
description: "Hai inserito 70.000 Note"
_notes80000:
title: "Una galassia di Note"
description: "Hai inserito 80.000 Note"
_notes90000:
title: "Un universo di Note!"
description: "Hai inserito 90.000 Note"
_notes100000:
title: "ALL YOUR NOTE ARE BELONG TO US"
description: "Hai inserito 100.000 Note"
flavor: "Hai molto da scrivere?"
_login3:
title: "Principiante I"
description: "Accedi per un totale di 3 giorni"
flavor: "Da oggi, chiamatemi Misskist"
_login7:
title: "Principiante II"
description: "Accedi per un totale di 7 giorni"
flavor: "Ti sembra di avere la situazione sotto controllo?"
_login15:
title: "Principiante III"
description: "Accedi per un totale di 15 giorni"
_login30:
title: "Misskist I"
description: "Accedi per un totale di 30 giorni"
_login60:
title: "Misskeist II"
description: "Accedi per un totale di 60 giorni"
_login100:
title: "Misskeist III"
description: "Accedi per un totale di 100 giorni"
flavor: "Violent Misskeist"
_login200:
title: "Regolare I"
description: "Accedi per un totale di 200 giorni"
_login300:
title: "Regolare II"
description: "Accedi per un totale di 300 giorni"
_login400:
title: "Regolare III"
description: "Accedi per un totale di 400 giorni"
_login500:
title: "Professionista I"
description: "Accedi per un totale di 500 giorni"
flavor: "Amici cari, mi piacciono le Note"
_login600:
title: "Professionista II"
description: "Accedi per un totale di 600 giorni"
_login700:
title: "Professionista III"
description: "Accedi per un totale di 700 giorni"
_login800:
title: "Maestro di Note I"
description: "Accedi per un totale di 800 giorni"
_login900:
title: "Maestro di Note II"
description: "Accedi per un totale di 900 giorni"
_login1000:
title: "Maestro di Note III"
description: "Accedi per un totale di 1.000 giorni"
flavor: "Grazie per aver usato Misskey!"
_noteClipped1:
title: "Devo clippare!"
description: "Ho raccolto in Clip la prima Nota"
_noteFavorited1:
title: "Guarda le stelle"
description: "Aggiungi una Nota ai preferiti per la prima volta"
_myNoteFavorited1:
title: "Fornitura stelline"
description: "Qualcuno ha preferito una delle tue Note"
_profileFilled:
title: "Perfettamente"
description: "Imposta il tuo profilo"
_markedAsCat:
title: "Io sono un gatto"
description: "Aggiungi le orecchie da gatto al tuo profilo"
flavor: "Ti chiamerò..."
_following1:
title: "Il mio primo Follow"
description: "Hai seguito il tuo primo profilo"
_following10:
title: "Segui, segui!"
description: "Hai seguito 10 profili"
_following50:
title: "Tanti amici"
description: "Hai seguito 50 profili"
_following100:
title: "Cento amici"
description: "Hai seguito 100 profili"
_following300:
title: "Sovraccarico di amici"
description: "Hai seguito 300 profili"
_followers1:
title: "Il primo profilo tuo Follower"
description: "Hai ottenuto il tuo primo Follower"
_followers10:
title: "Follow me!"
description: "Hai ottenuto 10 profili Follower"
_followers50:
title: "Follower a frotte"
description: "Hai ottenuto 50 Follower"
_followers100:
title: "Popolare"
description: "Hai ottenuto 100 profili Follower"
_followers300:
title: "Mettetevi in fila"
description: "Hai ottenuto 300 Follower"
_followers500:
title: "Trasmettitore"
description: "Hai ottenuto 500 Follower"
_followers1000:
title: "Influenzer"
description: "Hai superato i 1.000 profili 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"
_foundTreasure:
title: "Caccia al tesoro"
description: "Hai trovato un tesoro nascosto"
_client30min:
title: "Piccola pausa"
description: "Hai passato più di 30 minuti 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)"
_viewInstanceChart:
title: "Analista"
description: "Visualizza i grafici dell'istanza"
_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:
title: "Brain Diver"
description: "Pubblica un link a Brain Diver"
flavor: "Sulle note di Brain Diver"
_role:
new: "Nuovo ruolo"
edit: "Modifica ruolo"
@@ -1270,8 +1507,8 @@ _sfx:
channel: "Notifiche di canale"
_ago:
future: "Futuro"
justNow: "Ora"
secondsAgo: "{n}s fa"
justNow: "Adesso"
secondsAgo: "{n} sec fa"
minutesAgo: "{n} min fa"
hoursAgo: "{n} ore fa"
daysAgo: "{n} gg fa"
@@ -1293,7 +1530,7 @@ _tutorial:
step3_1: "Hai finito di impostare il tuo profilo?"
step3_2: "Ora puoi pubblicare una «Nota». Proviamo subito! Premi il bottone con l'icona «penna» per iniziare a scrivere in una finestra di dialogo. "
step3_3: "Scritto il testo della nota, puoi pubblicarla premendo il pulsante nella parte superiore destra della finestra di dialogo."
step3_4: "Non ti viene niente in mente? Perché non scrivi semplicemente \"Ho appena cominciato a usare Misskey\"?"
step3_4: "Non ti viene niente in mente? Perché non scrivi semplicemente \"Ho appena iniziato a usare Misskey\"?"
step4_1: "Hai pubblicato qualcosa?"
step4_2: "Se puoi visualizzare la tua nota sulla timeline, ce l'hai fatta!"
step5_1: "Adesso, cerca di seguire altre persone per vivacizzare la tua timeline. "
@@ -1587,6 +1824,7 @@ _notification:
pollEnded: "Risultati del sondaggio."
unreadAntennaNote: "Antenna {name}"
emptyPushNotificationMessage: "Le notifiche push sono state aggiornate."
achievementEarned: "Obiettivo raggiunto"
_types:
all: "Tutto"
follow: "Novità follower"

View File

@@ -1049,6 +1049,9 @@ _achievements:
_noteFavorited1:
title: "星をみるひと"
description: "初めてノートをお気に入りに登録した"
_myNoteFavorited1:
title: "星が欲しい"
description: "自分のノートが他の人からお気に入りに登録された"
_profileFilled:
title: "準備万端"
description: "プロフィール設定を行った"
@@ -1102,6 +1105,9 @@ _achievements:
title: "I Love Misskey"
description: "\"I ❤ #Misskey\"を投稿した"
flavor: "Misskeyを使ってくださりありがとうございます by 開発チーム"
_foundTreasure:
title: "宝探し"
description: "隠されたお宝を発見した"
_client30min:
title: "ひとやすみ"
description: "クライアントを起動してから30分以上経過した"
@@ -1122,6 +1128,9 @@ _achievements:
_htl20npm:
title: "流れるTL"
description: "ホームタイムラインの流速が20npmを越す"
_viewInstanceChart:
title: "アナリスト"
description: "インスタンスのチャートを表示した"
_outputHelloWorldOnScratchpad:
title: "Hello, world!"
description: "スクラッチパッドで hello world を出力した"

View File

@@ -938,13 +938,13 @@ cannotPerformTemporary: "일시적으로 사용할 수 없음"
cannotPerformTemporaryDescription: "조작 횟수 제한을 초과하여 일시적으로 사용이 불가합니다. 잠시 후 다시 시도해 주세요."
preset: "프리셋"
selectFromPresets: "프리셋에서 선택"
achievements: "도전과제"
achievements: "도전 과제"
_achievements:
earnedAt: "달성 일시"
_types:
_notes1:
title: "미스키 설정하고 있었는데요"
description: "첫 노트를 포스트했습니다"
title: "미스키 시작했는데요"
description: "첫 노트를 작성했습니다"
flavor: "Misskey에 오신 것을 환영합니다!"
_notes10:
title: "노트 조금"
@@ -962,7 +962,7 @@ _achievements:
title: "노트가 어디서 솟아?"
description: "5,000개의 노트를 작성했습니다"
_notes10000:
title: "슈퍼-노트"
title: "슈퍼 노트"
description: "10,000개의 노트를 작성했습니다"
_notes20000:
title: "노트 더 없어?"
@@ -989,7 +989,7 @@ _achievements:
title: "노트 우주"
description: "90,000개의 노트를 작성했습니다"
_notes100000:
title: "네 모든 노트는 내 거야"
title: "ALL YOUR NOTE ARE BELONG TO US"
description: "100,000개의 노트를 작성했습니다"
flavor: "이만큼 쓸 일도 없겠지만... 다른 할 일이 있진 않으신가요?"
_login3:
@@ -1012,7 +1012,7 @@ _achievements:
_login100:
title: "미스키스트 III"
description: "총 100일간 로그인했습니다"
flavor: "그 유저, 미스키스트를 위하여"
flavor: "그 유저, 미스키스트이다"
_login200:
title: "단골 I"
description: "총 200일간 로그인했습니다"
@@ -1025,7 +1025,7 @@ _achievements:
_login500:
title: "베테랑 I"
description: "총 500일간 로그인했습니다"
flavor: "여러분, 저 이 노트아해요"
flavor: "제군, 나는 노트"
_login600:
title: "베테랑 II"
description: "총 600일간 로그인했습니다"
@@ -1041,13 +1041,16 @@ _achievements:
_login1000:
title: "노트 마스터 III"
description: "총 1,000일간 로그인했습니다"
flavor: "미스키를 사용해 주셔서 감사합니다!"
flavor: "Misskey를 사용해 주셔서 감사합니다!"
_noteClipped1:
title: "클립할 수밖에 없었어"
description: "처음으로 노트를 클립했습니다"
_noteFavorited1:
title: "별을 바라보는 자"
description: "처음으로 노트를 즐겨찾기했습니다"
_myNoteFavorited1:
title: "별을 원하는 자"
description: "다른 사람이 당신의 노트를 즐겨찾기했습니다"
_profileFilled:
title: "준비 완료"
description: "프로필 설정을 완료했습니다"
@@ -1074,7 +1077,7 @@ _achievements:
title: "첫 팔로워"
description: "사용자가 처음으로 팔로잉했습니다"
_followers10:
title: "날 따라와!"
title: "팔로우 미!"
description: "10명의 사용자가 팔로우했습니다"
_followers50:
title: "이곳저곳"
@@ -1092,12 +1095,18 @@ _achievements:
title: "유명인사"
description: "1,000명의 사용자가 팔로우했습니다"
_collectAchievements30:
title: "도전과제 콜렉터"
title: "도전 과제 콜렉터"
description: "30개의 도전과제를 획득했습니다"
_viewAchievements3min:
title: "저 도전과제 좋아해요"
description: "도전 과제 목록을 3분 이상 쳐다봤습니다"
_iLoveMisskey:
title: "I Love Misskey"
description: "\"I ❤ #Misskey\"를 포스트했습니다"
flavor: "Misskey를 이용해주셔서 감사합니다! - 개발팀 일동"
_foundTreasure:
title: "보물찾기"
description: "숨겨진 보물을 발견했습니다"
_client30min:
title: "잠깐 쉬어"
description: "클라이언트를 시작하고 30분이 경과하였습니다"
@@ -1110,7 +1119,7 @@ _achievements:
flavor: "잠 좀 자세요. 걱정돼요."
_postedAt0min0sec:
title: "정각"
description: "1초도 어긋나지 않은 정각에 노트를 포스트했습니다"
description: "0분 0초 정각에 노트를 작성했습니다"
flavor: "째깍 째깍 째깍 땡!"
_selfQuote:
title: "혼잣말"
@@ -1118,15 +1127,24 @@ _achievements:
_htl20npm:
title: "타임라인 폭주 중"
description: "1분 사이에 홈 타임라인에 노트가 20개 넘게 생성되었습니다"
_viewInstanceChart:
title: "애널리스트"
description: "인스턴스의 차트를 열었습니다"
_outputHelloWorldOnScratchpad:
title: "Hello, world!"
description: "스크래치패드에서 hello world를 출력했습니다"
_open3windows:
title: "멀티 윈도우"
description: "3개 이상의 창을 열었습니다"
_driveFolderCircularReference:
title: "순환 참조"
description: "드라이브 폴더를 자신을 가리키도록 만드려 시도했습니다"
_reactWithoutRead:
title: "읽고 답하긴 하시는 건가요?"
description: "100자가 넘는 포스트에 3초 안에 포스트했습니다"
description: "100자가 넘는 노트가 작성되고 3초 안에 반응했습니다"
_clickedClickHere:
title: "여길 눌러보세요"
description: "이 곳을 눌러봤습니다"
description: "여길을 눌러봤습니다"
_justPlainLucky:
title: "그냥 운이 좋았어"
description: "매 10초마다 0.01%의 확률로 달성됩니다"
@@ -1134,21 +1152,25 @@ _achievements:
title: "신 콤플렉스"
description: "이름을 syuilo로 설정했습니다"
_passedSinceAccountCreated1:
title: "1년"
title: "1년"
description: "계정을 생성하고 1년이 지났습니다"
_passedSinceAccountCreated2:
title: "2년"
title: "2년"
description: "계정을 생성하고 2년이 지났습니다"
_passedSinceAccountCreated3:
title: "3년"
title: "3년"
description: "계정을 생성하고 3년이 지났습니다"
_loggedInOnBirthday:
title: "생일 축하합니다!"
description: "설정한 생일에 로그인했습니다"
description: "생일에 로그인했습니다"
_loggedInOnNewYearsDay:
title: "새해 복 많이 받으세요"
description: "새해 첫 날에 로그인했습니다"
flavor: "올해에도 저희 인스턴스에 관심을 가져 주셔서 감사합니다"
_cookieClicked:
title: "쿠키 클리커 게임"
title: "쿠키릭하는 게임"
description: "쿠키를 클릭했습니다"
flavor: "뭔가 문제가 있나요?"
flavor: "소프트웨어 착각하지 않으셨나요?"
_brainDiver:
title: "Brain Diver"
description: "Brain Diver로의 링크를 첨부했습니다"

View File

@@ -2,6 +2,7 @@
_lang_: "Русский"
headlineMisskey: "Сеть, сплетённая из заметок"
introMisskey: "Добро пожаловать! Misskey — это децентрализованный сервис микроблогов с открытым исходным кодом.\nПишите «заметки» — делитесь со всеми происходящим вокруг или рассказывайте о себе 📡\nСтавьте «реакции» — выражайте свои чувства и эмоции от заметок других 👍\nОткройте для себя новый мир 🚀"
poweredByMisskeyDescription: "{name} один из инстансов (также называемый экземпляром Misskey), использующий платформу с открытым исходным кодом <b>Misskey</b>."
monthAndDay: "{day}.{month}"
search: "Поиск"
notifications: "Уведомления"
@@ -12,6 +13,7 @@ fetchingAsApObject: "Приём с других сайтов"
ok: "Окей"
gotIt: "Ясно!"
cancel: "Отмена"
noThankYou: "Нет, спасибо"
enterUsername: "Введите имя пользователя"
renotedBy: "{user} делится"
noNotes: "Нет ни одной заметки"
@@ -47,6 +49,7 @@ deleteAndEdit: "Удалить и отредактировать"
deleteAndEditConfirm: "Удалить эту заметку и создать отредактированную? Все реакции, ссылки и ответы на существующую будут будут потеряны."
addToList: "Добавить в список"
sendMessage: "Отправить сообщение"
copyRSS: "Скопировать RSS"
copyUsername: "Скопировать имя пользователя"
searchUser: "Поиск людей"
reply: "Ответить"
@@ -452,6 +455,7 @@ language: "Язык"
uiLanguage: "Язык интерфейса"
groupInvited: "Приглашение в группу"
aboutX: "Описание {x}"
emojiStyle: "Стиль эмодзи"
disableDrawer: "Не использовать выдвижные меню"
youHaveNoGroups: "У вас нет ни одной группы"
joinOrCreateGroup: "Получайте приглашения в группы или создавайте свои собственные"
@@ -709,6 +713,7 @@ accentColor: "Акцент"
textColor: "Текст"
saveAs: "Сохранить под названием…"
advanced: "Для продвинутых"
advancedSettings: "Расширенные настройки "
value: "Значения"
createdAt: "Создано"
updatedAt: "Обновлено"
@@ -840,40 +845,351 @@ numberOfColumn: "Количество столбцов"
searchByGoogle: "Поиск"
instanceDefaultLightTheme: "Светлая тема по умолчанию"
instanceDefaultDarkTheme: "Темная тема по умолчанию"
instanceDefaultThemeDescription: "Описание темы по умолчанию для инстанса"
mutePeriod: "Продолжительность скрытия"
indefinitely: "вечно"
tenMinutes: "10 минут"
oneHour: "1 час"
oneDay: "1 день"
oneWeek: "1 неделя"
reflectMayTakeTime: "Изменения могут занять время для отображения"
failedToFetchAccountInformation: "Не удалось получить информацию об аккаунте"
cropImage: "Кадрирование"
cropImageAsk: "Нужно ли кадрировать изображение?"
file: "Файлы"
recentNHours: "Последние {n} ч"
recentNDays: "Последние {n} сут"
noEmailServerWarning: "Почтовый сервер не установлен "
thereIsUnresolvedAbuseReportWarning: "Остались нерешённые жалобы"
recommended: "Рекомендуем"
check: "Проверить"
driveCapOverrideLabel: "Изменение лимита дискового пространства для этого пользователя"
driveCapOverrideCaption: "Укажите меньше или равное нулю для отмены"
requireAdminForView: "Для просмотра необходимо иметь аккаунт администратора"
isSystemAccount: "Данная учётная запись создана автоматически и управляется системой"
typeToConfirm: "Введите {x} для продолжения"
deleteAccount: "Удаление учётной записи"
document: "Документ"
numberOfPageCache: "Количество сохранённых страниц в кэше"
numberOfPageCacheDescription: "Описание количества страниц в кэше"
logoutConfirm: "Вы хотите выйти из аккаунта?"
lastActiveDate: "Последняя дата использования"
statusbar: "Статусбар"
pleaseSelect: "Пожалуйста, выберите"
reverse: "Переворот"
colored: "Выделена цветом"
refreshInterval: "Интервал перезагрузки"
label: "Метка"
type: "Тип"
speed: "Скорость"
sensitiveMediaDetection: "Определение содержимого деликатного характера"
localOnly: "Локально"
remoteOnly: "Только удалённо"
failedToUpload: "Сбой выгрузки"
cannotUploadBecauseInappropriate: "Файл не может быть загружен, так как было установлено, что он может содержать неприемлемое содержимое."
cannotUploadBecauseNoFreeSpace: "Файл не может быть загружен, так как не осталось места на диске"
beta: "Бета"
enableAutoSensitive: "Автоматическое определение NSFW"
enableAutoSensitiveDescription: "Если доступно, используйте машинное обучение для автоматической установки флага NSFW на носителе. Даже если эта функция отключена, она может быть установлена ​​автоматически в зависимости от инстанта."
navbar: "Панель навигации"
shuffle: "Перемешать"
account: "Учётные записи"
move: "Переместить"
pushNotification: "Push-уведомления"
subscribePushNotification: "Включить push-уведомления"
unsubscribePushNotification: "Выключить push-уведомления"
pushNotificationAlreadySubscribed: "Push-уведомления уже включены"
pushNotificationNotSupported: "Push-уведмления не поддерживаются инстансом или браузером"
sendPushNotificationReadMessage: "Удалять push-уведомления когда сообщение или прочитано"
sendPushNotificationReadMessageCaption: "На мгновение появится уведомление \"{emptyPushNotificationMessage}\". Расход заряда батареи может увеличиться "
windowMaximize: "Развернуть"
windowRestore: "Восстановить"
caption: "Подпись (Automatic Translation)"
loggedInAsBot: "Вы под аккаунтом бота!"
tools: "Инструменты"
cannotLoad: "Не удалось загрузить"
numberOfProfileView: "Количество профилей для просмотра"
like: "Нравится!"
unlike: "Отменить «нравится»"
numberOfLikes: "Количество лайков"
show: "Отображение"
neverShow: "Больше не показывать"
remindMeLater: "Напомнить позже"
didYouLikeMisskey: "Вам нравится Misskey?"
pleaseDonate: "Сайт {host} работает на Misskey. Это бесплатное программное обеспечение, и ваши пожертвования очень бы помогли продолжать его разработку!"
roles: "Роли"
role: "Роль"
normalUser: "Обычный пользователь"
undefined: "неопределён"
assign: "Назначить"
unassign: "Отменить назначение"
color: "Цвет"
manageCustomEmojis: "Управлять пользовательскими эмодзи"
youCannotCreateAnymore: "Вы достигли лимита создания."
cannotPerformTemporary: "Временно недоступен"
cannotPerformTemporaryDescription: "Это действие временно невозможно выполнить из-за превышения лимита выполнения."
preset: "Шаблоны"
selectFromPresets: "Выбрать из шаблонов"
achievements: "Достижения"
_achievements:
earnedAt: "Разблокировано в"
_types:
_notes1:
title: "Первые шаги в Misskey"
description: "Опубликована первая заметка"
flavor: "Приятных дней с Misskey!"
_notes10:
title: "Несколько заметок"
description: "Опубликовано 10 заметок"
_notes100:
title: "Много заметок"
description: "Опубликовано 100 заметок"
_notes500:
title: "Всё в заметках"
description: "Опубликовано 500 заметок"
_notes1000:
title: "Гора заметок"
description: "Опубликовано 1000 заметок"
_notes5000:
title: "Заметки льются рекой"
description: "Опубликовано 5000 заметок"
_notes10000:
title: "Превосходство в заметках"
description: "Опубликовано 10000 заметок"
_notes20000:
title: "Нужно больше заметок!"
description: "Опубликовано 20000 заметок"
_notes30000:
title: "Заметки, заметки, заметки"
description: "Опубликовано 30000 заметок"
_notes40000:
title: "Фабрика заметок"
description: "Опубликовано 40000 заметок"
_notes50000:
title: "Планета заметок"
description: "Опубликовано 50000 заметок"
_notes60000:
title: "Замет-квазар"
description: "Опубликовано 60000 заметок"
_notes70000:
title: "Чёрная дыра из заметок"
description: "Опубликовано 70000 заметок"
_notes80000:
title: "Галактика заметок"
description: "Опубликовано 80000 заметок"
_notes90000:
title: "Вселенная заметок"
description: "Опубликовано 90000 заметок"
_notes100000:
title: "ALL YOUR NOTE ARE BELONG TO US"
description: "Опубликовано 100000 заметок"
flavor: "Вам правда нужно столько писать?"
_login3:
title: "Новичок "
description: "3 дня на сайте"
flavor: "С сегодняшнего дня зовите меня просто мискиец"
_login7:
title: "Новичок Ⅱ"
description: "Неделя на сайте"
flavor: "Кажется, вы начали свыкаться с этим, нет?"
_login15:
title: "Новичок Ⅲ"
description: "15 дней на сайте"
_login30:
title: "Мискиец "
description: "30 дней на сайте"
_login60:
title: "Мискиец Ⅱ"
description: "60 дней на сайте"
_login100:
title: "Мискиец Ⅲ"
description: "100 дней на сайте"
flavor: "Жестокий мискиец"
_login200:
title: "Завсегдатай "
description: "200 дней на сайте"
_login300:
title: "Завсегдатай Ⅱ"
description: "300 дней на сайте"
_login400:
title: "Завсегдатай Ⅲ"
description: "400 дней на сайте"
_login500:
title: "Ветеран "
description: "500 дней на сайте"
flavor: "Господа, я люблю заметки"
_login600:
title: "Ветеран Ⅱ"
description: "600 дней на сайте"
_login700:
title: "Ветеран Ⅲ"
description: "700 дней на сайте"
_login800:
title: "Повелитель заметок "
description: "800 дней на сайте"
_login900:
title: "Повелитель заметок Ⅱ"
description: "900 дней на сайте"
_login1000:
title: "Повелитель заметок Ⅲ"
description: "1000 дней на сайте"
flavor: "Спасибо, что пользуетесь Misskey!"
_noteClipped1:
title: "Нельзя не сохранить"
description: "Первая заметка в подборке"
_noteFavorited1:
title: "Смотрящий на звёзды"
description: "Первое добавление в избранное"
_myNoteFavorited1:
title: "В поиске звёзд"
description: "Кому-то понравилась ваша заметка"
_profileFilled:
title: "Приготовления закончены"
description: "Заполнен профиль"
_markedAsCat:
title: "Ваш покорный слуга кот"
description: "Включена опция «Аккаунт кота»"
flavor: "Позвольте представиться: я — кот, просто кот, у меня еще нет имени."
_following1:
title: "Я не один"
description: "Сделана первая подписка"
_following10:
title: "Не останавливайся… Не останавливайся…"
description: "Количество подписок достигло 10"
_following50:
title: "Много друзей"
description: "Количество подписок достигло 50"
_following100:
title: "Сотня друзей"
description: "Количество подписок достигло 100"
_following300:
title: "Друзья в избытке"
description: "Количество подписок достигло 300"
_followers1:
title: "Первый подписчик"
description: "Появился 1 подписчик"
_followers10:
title: "Следуй за мной!"
description: "Количество подписчиков достигло 10"
_followers50:
title: "Один за другим"
description: "Количество подписчиков достигло 50"
_followers100:
title: "Всеобщий любимец"
description: "Количество подписчиков достигло 100"
_followers300:
title: "В очередь!"
description: "Количество подписчиков достигло 300"
_followers500:
title: "Радиостанция"
description: "Количество подписчиков достигло 500"
_followers1000:
title: "Авторитет"
description: "Количество подписчиков достигло 1000"
_collectAchievements30:
title: "Достигатор"
description: "Получено 30 достижений"
_viewAchievements3min:
title: "Любовь к успехам"
description: "Более 3 минут любования достижениями"
_iLoveMisskey:
title: "Я люблю Misskey"
description: "Написана заметка «I ❤ #Misskey»"
flavor: "Спасибо за поддержку Misskey! Ваша команда разработчиков"
_client30min:
title: "Перерыв на обед"
description: "Прошло 30 минут с момента запуска клиента"
_noteDeletedWithin1min:
title: "Ой, нет!"
description: "Заметка удалена через минуту после публикации"
_postedAtLateNight:
title: "Житель ночи"
description: "Заметка опубликована в глухую ночь"
flavor: "Вроде бы пора спать"
_postedAt0min0sec:
title: "Говорящие часы"
description: "Заметка опубликована ровно в 0 минут 0 секунд"
flavor: "Дин-дон дин-дон"
_selfQuote:
title: "Самовоспроизведение"
description: "Процитирована собственная заметка"
_htl20npm:
title: "В потоке"
description: "Достигнута скорость домашней ленты в 20 з/мин (заметок минуту)"
_outputHelloWorldOnScratchpad:
title: "Привет, мир!"
description: "Выведен текст «hello world» в Когтеточке"
_open3windows:
title: "Многооконный"
description: "Открыто одновременно 3 окна"
_driveFolderCircularReference:
title: "Циклическая ссылка"
description: "Попытка создать на «диске» рекурсивно вложенную папку"
_reactWithoutRead:
title: "Не читай @ отвечай!"
description: "На заметку более чем 100 знаков написан ответ в первые же 3 секунды с её появления."
_clickedClickHere:
title: "Нажмите здесь"
description: "Нажато здесь"
_justPlainLucky:
title: "Чистая удача"
description: "Может достаться с вероятностью 0,01% каждые 10 секунд."
_setNameToSyuilo:
title: "Комплекс бога"
description: "Установлено «syuilo» в качестве имени"
_passedSinceAccountCreated1:
title: "Первая годовщина"
description: "Прошёл 1 год с момента регистрации"
_passedSinceAccountCreated2:
title: "Вторая годовщина"
description: "Прошло 2 года с момента регистрации"
_passedSinceAccountCreated3:
title: "Третья годовщина"
description: "Прошло 3 года с момента регистрации"
_loggedInOnBirthday:
title: "С днём рождения!"
description: "Вход на сайт в свой день рождения"
_loggedInOnNewYearsDay:
title: "С Новым годом!"
description: "Вход на сайт в первый день года"
flavor: "Желаем отличного года на нашем сайте!"
_cookieClicked:
title: "Игра, в которой вы щёлкаете по печенькам"
description: "Нажато печенье"
flavor: "Стоп, вы вообще на том сайте-то?"
_brainDiver:
title: "Brain Diver"
description: "Опубликована ссылка на песню «Brain Diver»"
flavor: "Мисски-Мисски Ла-Ту-Ма"
_role:
new: "Новая роль"
edit: "Изменить роль"
name: "Название роли"
description: "Описание роли"
permission: "Ролевые полномочия"
descriptionOfPermission: "<b>Модераторы</b> могут изменять базовые операции для модераторов.\n<b>Администраторы</b> могут изменять полностью настройки инстанса."
assignTarget: "Метод присвоения"
descriptionOfAssignTarget: "<b>Вручную</b> чтобы указать кому выдавать роль, а кому нет.\n<b>По условию<b> чтобы автоматически выдавать и удалять роль при условиях."
manual: "Вручную"
conditional: "По условию"
condition: "Условия"
isConditionalRole: "Эта роль выдаётся по условию."
isPublic: "Общедоступная роль"
descriptionOfIsPublic: "Список тех, кому назначена эта роль будет доступен всем. Кроме того эта роль будет отмечена у каждого в профиле."
options: "Настройки ролей"
policies: "Политики"
baseRole: "Шаблон роли"
useBaseValue: "Использовать значение из шаблона"
chooseRoleToAssign: "Выберите роль, которую хотите выдать"
canEditMembersByModerator: "Могут назначать модераторы"
descriptionOfCanEditMembersByModerator: "Если включено, на эту роль могут назначать пользователей как администраторы, так и модераторы. Если выключено, назначать могут только администраторы."
priority: "Приоритет"
_priority:
low: "Низкий"
middle: "Средне"
high: "Высокий"
_options:
canManageCustomEmojis: "Управлять пользовательскими эмодзи"
_sensitiveMediaDetection:
description: "Машинное обучение может быть использовано для автоматического обнаружения чувствительных медиа для модерации. Нагрузка на сервер увеличивается незначительно."
setSensitiveFlagAutomatically: "Установить флаг NSFW"
@@ -920,6 +1236,11 @@ _plugin:
install: "Установка расширений"
installWarn: "Пожалуйста, не устанавливайте расширения, которым не доверяете."
manage: "Управление расширениями"
_preferencesBackups:
saveConfirm: "Сохранить бэкап как {name}?"
deleteConfirm: "Удалить резервную копию {name}?"
renameConfirm: "Переименовать резервную копию с \"{old}\" на \"{new}\"?"
noBackups: "Резервной копии не существует. Вы можете создать резервную копию в настройках на этом инстансе с помощью \"Создать новую резервную копию\"."
_registry:
scope: "Область"
key: "Ключ"
@@ -1416,6 +1737,7 @@ _notification:
youReceivedFollowRequest: "У вас новый запрос на подписку."
yourFollowRequestAccepted: "Ваш запрос на подписку одобрен."
youWereInvitedToGroup: "Вы приглашены в группу."
achievementEarned: "Получено достижение"
_types:
all: "Все"
follow: "Подписки"

View File

@@ -942,14 +942,51 @@ achievements: "ความสำเร็จ"
_achievements:
earnedAt: "ได้รับเมื่อ"
_types:
_notes1:
title: "เพียงแค่ตั้งค่า msky ของฉัน"
_followers100:
title: "บุคคลที่เป็นที่นิยม"
_followers500:
title: "เสาสัญญาณ"
_followers1000:
title: "ผู้ทรงอิทธิพล"
_iLoveMisskey:
title: "ฉันรัก Misskey"
description: "โพสต์ \"I ❤ #Misskey\""
_foundTreasure:
title: "ล่าสมบัติ"
description: "คุณพบสมบัติที่ซ่อนอยู่"
_client30min:
title: "พักผ่อนสักหน่อย"
_noteDeletedWithin1min:
title: "ไม่เป็นไร"
_postedAtLateNight:
title: "กลางคืน"
_viewInstanceChart:
title: "วิเคราะห์"
description: "ดูแผนภูมิอินสแตนซ์ของคุณ"
_driveFolderCircularReference:
title: "อ้างอิงวงจร"
_clickedClickHere:
title: "คลิ๊กที่นี่"
description: "คุณได้คลิกที่นี่"
_passedSinceAccountCreated1:
title: "ครบรอบหนึ่งปี"
_passedSinceAccountCreated2:
title: "ครบรอบสองปี"
_passedSinceAccountCreated3:
title: "ครบรอบสามปี"
_loggedInOnBirthday:
title: "สุขสันต์วันเกิด"
description: "เข้าสู่ระบบในวันเกิดของคุณ"
_loggedInOnNewYearsDay:
title: "สวัสดีปีใหม่!"
description: "เข้าสู่ระบบในวันแรกของปี"
_cookieClicked:
description: "คลิกคุกกี้"
_brainDiver:
title: "Brain Diver"
flavor: "Misskey-Misskey La-Tu-Ma"
_role:
new: "บทบาทใหม่"
edit: "แก้ไขบทบาท"

View File

@@ -899,6 +899,91 @@ unlike: "Не вподобати"
numberOfLikes: "Вподобання"
show: "Відображення"
color: "Колір"
achievements: "Досягнення"
_achievements:
_types:
_notes1:
title: "налаштовую свій msky"
description: "Перша нотатка"
flavor: "Приємного часу з Misskey!"
_notes10:
title: "Декілька нотаток"
description: "10 нотаток відправлено"
_notes100:
title: "Купа нотаток"
description: "100 нотаток відправлено"
_notes500:
title: "Все в нотатках"
description: "500 нотаток відправлено"
_notes1000:
title: "Гора нотаток"
description: "1 000 нотаток відправлено"
_notes5000:
title: "Переповнюючі нотатки"
description: "5 000 нотаток відправлено"
_notes10000:
title: "Супернотатка"
description: "10 000 нотаток відправлено"
_notes20000:
title: "Треба Більше Нотаток"
description: "20 000 нотаток відправлено"
_notes30000:
title: "Нотатки нотатки нотатки"
description: "30 000 нотаток відправлено"
_notes40000:
title: "Фабрика нотаток"
description: "40 000 нотаток відправлено"
_notes50000:
title: "Планета нотаток"
description: "50 000 нотаток відправлено"
_notes60000:
title: "Нотатковий квазар"
description: "60 000 нотаток відправлено"
_notes70000:
title: "Чорна нотаткова діра"
description: "70 000 нотаток відправлено"
_notes80000:
title: "Галактика нотаток"
description: "80 000 нотаток відправлено"
_notes90000:
title: "Нотатковерс"
description: "90 000 нотаток відправлено"
_notes100000:
title: "ALL YOUR NOTE ARE BELONG TO US"
description: "100 000 нотаток відправлено"
flavor: "Так багато потрібно сказати?"
_login3:
title: "Новачок I"
_login7:
title: "Новачок II"
_login15:
title: "Новачок III"
_login30:
title: "Міскієць I"
_login60:
title: "Міскієць II"
_login100:
title: "Міскієць III"
_login200:
title: "Завсідник I"
_login300:
title: "Завсідник II"
_login400:
title: "Завсідник III"
_login500:
title: "Ветеран I"
_login600:
title: "Ветеран II"
_login700:
title: "Ветеран III"
_login1000:
flavor: "Дякуємо, що користуєтеся Misskey!"
_passedSinceAccountCreated3:
description: "Минуло 3 роки з моменту створення акаунта"
_loggedInOnBirthday:
title: "З Днем народження!"
_brainDiver:
flavor: "Misskey-Misskey La-Tu-Ma"
_role:
priority: "Пріоритет"
_priority:

View File

@@ -938,6 +938,116 @@ cannotPerformTemporary: "暂时不可用"
cannotPerformTemporaryDescription: "因操作过于频繁,暂时不可用,请稍后再试。"
preset: "預設值"
selectFromPresets: "從預設值中選擇"
achievements: "成就"
_achievements:
earnedAt: "达成时间"
_types:
_notes1:
title: "初来乍到"
description: "第一次发帖"
flavor: "祝您在Misskey玩的愉快"
_notes10:
title: "一些帖子"
description: "发布了10篇帖子"
_notes100:
title: "很多帖子"
description: "发布了100篇帖子"
_notes500:
title: "满是帖子"
description: "发布了500篇帖子"
_notes1000:
title: "积帖成山"
description: "发布了1,000篇帖子"
_notes5000:
title: "帖如泉涌"
description: "发布了5,000篇帖子"
_notes10000:
title: "超级帖"
description: "发布了10,000篇帖子"
_notes20000:
title: "还想要更多帖子"
description: "发布了20,000篇帖子"
_notes30000:
title: "帖子帖子帖子"
description: "发布了30,000篇帖子"
_notes40000:
title: "帖子工厂"
description: "发布了40,000篇帖子"
_notes50000:
title: "帖子星球"
description: "发布了50,000篇帖子"
_notes60000:
title: "帖子类星体"
description: "发布了60,000篇帖子"
_notes70000:
title: "帖子黑洞"
description: "发布了70,000篇帖子"
_notes80000:
title: "帖子星系"
description: "发布了80,000篇帖子"
_notes90000:
title: "帖子起源"
description: "发布了90,000篇帖子"
_notes100000:
title: "ALL YOUR NOTE ARE BELONG TO US"
description: "发布了100,000篇帖子"
flavor: "真的有那么多可以写的东西吗?"
_login3:
title: "初学者 I"
description: "连续登录3天"
_login7:
description: "连续登录7天"
_login15:
description: "连续登录15天"
_login30:
description: "连续登录30天"
_login60:
description: "连续登录60天"
_login1000:
flavor: "感谢您使用Misskey"
_noteFavorited1:
title: "观星者"
_profileFilled:
title: "整装待发"
description: "设置了个人资料"
_markedAsCat:
title: "我是猫"
description: "将账户设定为一只猫"
_following10:
title: "关注,跟随"
_following50:
title: "我的朋友很多"
_following300:
description: "关注数超过300"
_followers100:
title: "胜友如云"
_collectAchievements30:
description: "获得超过30个成就"
_viewAchievements3min:
description: "盯着成就看三分钟"
_iLoveMisskey:
title: "I Love Misskey"
description: "发布\"I ❤ #Misskey\"帖子"
flavor: "感谢您使用 Misskey by 开发团队"
_noteDeletedWithin1min:
description: "发帖后一分钟内就将其删除"
_postedAtLateNight:
title: "夜行者"
description: "深夜发布帖子"
_outputHelloWorldOnScratchpad:
title: "Hello, world!"
_passedSinceAccountCreated1:
description: "账户创建时间超过1年"
_passedSinceAccountCreated2:
description: "账户创建时间超过2年"
_passedSinceAccountCreated3:
description: "账户创建时间超过3年"
_loggedInOnBirthday:
title: "生日快乐"
description: "在生日当天登录"
_loggedInOnNewYearsDay:
title: "恭贺新禧"
description: "在元旦登入"
_role:
new: "创建角色"
edit: "编辑角色"
@@ -1587,6 +1697,7 @@ _notification:
pollEnded: "问卷调查结果已生成。"
unreadAntennaNote: "天线 {name}"
emptyPushNotificationMessage: "推送通知已更新"
achievementEarned: "获得成就"
_types:
all: "全部"
follow: "关注中"

View File

@@ -950,13 +950,13 @@ _achievements:
title: "若干貼文"
description: "發表了10則貼文"
_notes100:
title: "許多貼文"
title: "許多貼文"
description: "發表了100則貼文"
_notes500:
title: "滿滿的貼文"
description: "發表了500則貼文"
_notes1000:
title: "堆貼文"
title: "堆積如山的貼文"
description: "發表了1000則貼文"
_notes5000:
title: "滔滔不絕的貼文"
@@ -989,11 +989,192 @@ _achievements:
title: "貼文宇宙"
description: "發表了90000則貼文"
_notes100000:
title: "ALL YOUR NOTE ARE BELONG TO US"
description: "發表了100,000則貼文"
flavor: "有這麼多東西要寫嗎?"
_login3:
title: "初學者 I"
title: "初學者"
description: "總登入天數為3天"
flavor: "從今天開始我就是Misskeyist"
_login7:
title: "初學者ⅠⅠ"
description: "總登入天數為7天"
flavor: "您開始習慣了嗎?"
_login15:
title: "初學者III"
description: "總登入天數為15天"
_login30:
title: "Misskeyist "
description: "總登入天數為30天"
_login60:
title: "Misskeyist "
description: "總登入天數為60天"
_login100:
title: "Misskeyist "
description: "總登入天數為100天"
flavor: "辣個 Misskeyist 用戶"
_login200:
title: "普通Ⅰ"
description: "總登入天數為200天"
_login300:
title: "普通I"
description: "總登入天數為300天"
_login400:
title: "普通II"
description: "總登入天數為400天"
_login500:
title: "老兵Ⅰ"
description: "總登入天數為500天"
flavor: "諸君,我喜歡貼文"
_login600:
title: "老兵ⅠⅠ"
description: "總登入天數為600天"
_login700:
title: "老兵ⅠⅠⅠ"
description: "總登入天數為700天"
_login800:
title: "貼文大師Ⅰ"
description: "總登入天數為800天"
_login900:
title: "貼文大師ⅠⅠ"
description: "總登入天數為900天"
_login1000:
title: "貼文大師ⅠⅠⅠ"
description: "總登入天數為1,000天"
flavor: "感謝您使用Misskey"
_noteClipped1:
title: "忍不住要收進摘錄裡"
description: "第一次將貼文收進摘錄"
_noteFavorited1:
title: "觀星者"
description: "第一次將貼文收藏至我的最愛"
_myNoteFavorited1:
title: "想要星星"
description: "自己的貼文被他人收藏至「我的最愛」了"
_profileFilled:
title: "有備而來"
description: "設定了個人檔案"
_markedAsCat:
title: "我是貓"
description: "已將帳戶設定為貓"
flavor: "還沒有名字。"
_following1:
title: "首次追隨"
description: "首次追隨了"
_following10:
title: "跟著跟著"
description: "跟隨超過10人了"
_following50:
title: "朋友很多"
description: "跟隨超過50人了"
_following100:
title: "100位朋友"
description: "跟隨超過100人了"
_following300:
title: "朋友過多"
description: "跟隨超過300人了"
_followers1:
title: "第一個追隨者"
description: "第一次被追隨"
_followers10:
title: "Follow me!"
description: "跟隨者超過10人了"
_followers50:
title: "成群結隊"
description: "跟隨者超過50人了"
_followers100:
title: "紅人"
description: "跟隨者超過100人了"
_followers300:
title: "請排成一排"
description: "跟隨者超過300人了"
_followers500:
title: "基站"
description: "超過500名追隨者了"
_followers1000:
title: "影響者"
description: "超過1000名追隨者了"
_collectAchievements30:
title: "成就收藏家"
description: "獲得30個以上的成就"
_viewAchievements3min:
title: "喜愛成就"
description: "看成就列表要花3分鐘以上"
_iLoveMisskey:
title: "I Love Misskey"
description: "發布「I ❤ #Misskey」"
flavor: "感謝您使用Misskey by 開發團隊"
_foundTreasure:
title: "尋寶"
description: "發現了隱藏的寶藏"
_client30min:
title: "休息一下"
description: "用戶端啟動已超過30分鐘"
_noteDeletedWithin1min:
title: "現在沒有"
description: "發文後1分鐘內刪文"
_postedAtLateNight:
title: "夜行性"
description: "在深夜發佈貼文"
flavor: "該去睡覺了。"
_postedAt0min0sec:
title: "報時"
description: "在0分0秒發佈貼文"
flavor: "啵.啵.啵.嗶ー"
_selfQuote:
title: "自我引用"
description: "引用了自己的貼文"
_htl20npm:
title: "流動的TL"
description: "在首頁時間軸的流速超過20npm"
_viewInstanceChart:
title: "分析師"
description: "顯示了實例的圖表"
_outputHelloWorldOnScratchpad:
title: "Hello world!"
description: "在暫存記憶體輸出了 hello world"
_open3windows:
title: "多重視窗"
description: "開啟了3個以上的視窗"
_driveFolderCircularReference:
title: "循環引用"
description: "試圖遞迴套入雲端硬碟資料夾"
_reactWithoutRead:
title: "有好好讀過嗎?"
description: "對包含100字以上內容的貼文做出情感反應"
_clickedClickHere:
title: "點擊這裡"
description: "已點擊這裡了"
_justPlainLucky:
title: "只是運氣好"
description: "每10秒有0.01%的機率獲得"
_setNameToSyuilo:
title: "神的情結"
description: "將名稱設定為 syuilo"
_passedSinceAccountCreated1:
title: "一周年"
description: "自建立帳戶開始過了1年"
_passedSinceAccountCreated2:
title: "二周年"
description: "自建立帳戶開始過了2年"
_passedSinceAccountCreated3:
title: "三周年"
description: "自建立帳戶開始過了3年"
_loggedInOnBirthday:
title: "生日快樂"
description: "在生日當天登入了"
_loggedInOnNewYearsDay:
title: "新年快樂"
description: "在元旦當天登入了"
flavor: "今年也請對敝實例多多指教"
_cookieClicked:
title: "點擊餅乾的遊戲"
description: "點擊了餅乾"
flavor: "是不是軟體有問題?"
_brainDiver:
title: "Brain Driver"
description: "發佈了Brain Driver的連結"
flavor: "Misskey-Misskey La-Tu-Ma"
_role:
new: "建立角色"
edit: "編輯角色"
@@ -1643,6 +1824,7 @@ _notification:
pollEnded: "問卷調查已產生結果"
unreadAntennaNote: "天線 {name}"
emptyPushNotificationMessage: "推送通知已更新"
achievementEarned: "獲得成就"
_types:
all: "全部 "
follow: "追隨中"

View File

@@ -1,6 +1,6 @@
{
"name": "misskey",
"version": "13.1.0-beta.2",
"version": "13.2.1",
"codename": "nasubi",
"repository": {
"type": "git",
@@ -38,7 +38,7 @@
"cleanall": "pnpm clean-all"
},
"resolutions": {
"chokidar": "^3.3.1",
"chokidar": "^3.5.3",
"lodash": "^4.17.21"
},
"dependencies": {
@@ -54,12 +54,12 @@
"devDependencies": {
"@types/gulp": "4.0.10",
"@types/gulp-rename": "2.0.1",
"@typescript-eslint/eslint-plugin": "5.48.1",
"@typescript-eslint/parser": "5.48.1",
"@typescript-eslint/eslint-plugin": "5.49.0",
"@typescript-eslint/parser": "5.49.0",
"cross-env": "7.0.3",
"cypress": "12.3.0",
"eslint": "^8.31.0",
"start-server-and-test": "1.15.2"
"eslint": "^8.32.0",
"start-server-and-test": "1.15.3"
},
"optionalDependencies": {
"@tensorflow/tfjs-core": "^4.2.0"

View File

@@ -19,13 +19,13 @@
"test-and-coverage": "pnpm jest-and-coverage"
},
"optionalDependencies": {
"@tensorflow/tfjs": "^4.1.0",
"@tensorflow/tfjs-node": "4.1.0"
"@tensorflow/tfjs": "^4.2.0",
"@tensorflow/tfjs-node": "4.2.0"
},
"dependencies": {
"@bull-board/api": "^4.10.2",
"@bull-board/fastify": "^4.10.2",
"@bull-board/ui": "^4.10.2",
"@bull-board/api": "^4.11.0",
"@bull-board/fastify": "^4.11.0",
"@bull-board/ui": "^4.11.0",
"@discordapp/twemoji": "14.0.2",
"@fastify/accepts": "4.1.0",
"@fastify/cookie": "^8.3.0",
@@ -58,9 +58,9 @@
"date-fns": "2.29.3",
"deep-email-validator": "0.1.21",
"escape-regexp": "0.0.1",
"fastify": "4.11.0",
"fastify": "4.12.0",
"feed": "4.2.2",
"file-type": "18.1.0",
"file-type": "18.2.0",
"fluent-ffmpeg": "2.1.2",
"form-data": "^4.0.0",
"got": "12.5.3",
@@ -69,9 +69,8 @@
"ip-cidr": "3.0.11",
"is-svg": "4.3.2",
"js-yaml": "4.1.0",
"jsdom": "21.0.0",
"jsdom": "21.1.0",
"json5": "2.2.3",
"json5-loader": "4.0.1",
"jsonld": "8.1.0",
"jsrsasign": "10.6.1",
"mfm-js": "0.23.3",
@@ -89,7 +88,7 @@
"probe-image-size": "7.2.3",
"promise-limit": "2.7.0",
"pug": "3.0.2",
"punycode": "2.2.0",
"punycode": "2.3.0",
"pureimage": "0.3.15",
"qrcode": "1.5.1",
"random-seed": "0.3.0",
@@ -120,7 +119,7 @@
"typeorm": "0.3.11",
"typescript": "4.9.4",
"ulid": "2.3.0",
"undici": "^5.15.0",
"undici": "^5.16.0",
"unzipper": "0.10.11",
"uuid": "9.0.0",
"vary": "1.1.2",
@@ -132,7 +131,7 @@
"devDependencies": {
"@redocly/openapi-core": "1.0.0-beta.120",
"@swc/cli": "^0.1.59",
"@swc/core": "1.3.26",
"@swc/core": "1.3.27",
"@swc/jest": "0.2.24",
"@types/accepts": "1.3.5",
"@types/archiver": "5.3.1",
@@ -144,7 +143,7 @@
"@types/escape-regexp": "0.0.1",
"@types/fluent-ffmpeg": "2.1.20",
"@types/ioredis": "4.28.10",
"@types/jest": "29.2.5",
"@types/jest": "29.2.6",
"@types/js-yaml": "4.0.5",
"@types/jsdom": "20.0.1",
"@types/jsonld": "1.5.8",
@@ -176,11 +175,11 @@
"@types/web-push": "3.3.2",
"@types/websocket": "1.0.5",
"@types/ws": "8.5.4",
"@typescript-eslint/eslint-plugin": "5.48.1",
"@typescript-eslint/parser": "5.48.1",
"@typescript-eslint/eslint-plugin": "5.49.0",
"@typescript-eslint/parser": "5.49.0",
"cross-env": "7.0.3",
"eslint": "8.31.0",
"eslint-plugin-import": "2.27.4",
"eslint": "8.32.0",
"eslint-plugin-import": "2.27.5",
"execa": "6.1.0",
"jest": "29.3.1",
"jest-mock": "^29.3.1",

View File

@@ -0,0 +1,35 @@
import { NestFactory } from '@nestjs/core';
import { ChartManagementService } from '@/core/chart/ChartManagementService.js';
import { QueueProcessorService } from '@/queue/QueueProcessorService.js';
import { NestLogger } from '@/NestLogger.js';
import { QueueProcessorModule } from '@/queue/QueueProcessorModule.js';
import { JanitorService } from '@/daemons/JanitorService.js';
import { QueueStatsService } from '@/daemons/QueueStatsService.js';
import { ServerStatsService } from '@/daemons/ServerStatsService.js';
import { ServerService } from '@/server/ServerService.js';
import { MainModule } from '@/MainModule.js';
export async function server() {
const app = await NestFactory.createApplicationContext(MainModule, {
logger: new NestLogger(),
});
app.enableShutdownHooks();
const serverService = app.get(ServerService);
serverService.launch();
app.get(ChartManagementService).start();
app.get(JanitorService).start();
app.get(QueueStatsService).start();
app.get(ServerStatsService).start();
}
export async function jobQueue() {
const jobQueue = await NestFactory.createApplicationContext(QueueProcessorModule, {
logger: new NestLogger(),
});
jobQueue.enableShutdownHooks();
jobQueue.get(QueueProcessorService).start();
jobQueue.get(ChartManagementService).start();
}

View File

@@ -6,21 +6,12 @@ import cluster from 'node:cluster';
import chalk from 'chalk';
import chalkTemplate from 'chalk-template';
import semver from 'semver';
import { NestFactory } from '@nestjs/core';
import Logger from '@/logger.js';
import { loadConfig } from '@/config.js';
import type { Config } from '@/config.js';
import { lessThan } from '@/misc/prelude/array.js';
import { showMachineInfo } from '@/misc/show-machine-info.js';
import { DaemonModule } from '@/daemons/DaemonModule.js';
import { JanitorService } from '@/daemons/JanitorService.js';
import { QueueStatsService } from '@/daemons/QueueStatsService.js';
import { ServerStatsService } from '@/daemons/ServerStatsService.js';
import { NestLogger } from '@/NestLogger.js';
import { ChartManagementService } from '@/core/chart/ChartManagementService.js';
import { ServerService } from '@/server/ServerService.js';
import { MainModule } from '@/MainModule.js';
import { envOption } from '../env.js';
import { envOption } from '@/env.js';
import { jobQueue, server } from './common.js';
const _filename = fileURLToPath(import.meta.url);
const _dirname = dirname(_filename);
@@ -73,14 +64,13 @@ export async function masterMain() {
process.exit(1);
}
const app = await NestFactory.createApplicationContext(MainModule, {
logger: new NestLogger(),
});
app.enableShutdownHooks();
// start server
const serverService = app.get(ServerService);
serverService.launch();
if (envOption.onlyServer) {
await server();
} else if (envOption.onlyQueue) {
await jobQueue();
} else {
await server();
}
bootLogger.succ('Misskey initialized');
@@ -89,11 +79,6 @@ export async function masterMain() {
}
bootLogger.succ(`Now listening on port ${config.port} on ${config.url}`, null, true);
app.get(ChartManagementService).start();
app.get(JanitorService).start();
app.get(QueueStatsService).start();
app.get(ServerStatsService).start();
}
function showEnvironment(): void {

View File

@@ -1,23 +1,18 @@
import cluster from 'node:cluster';
import { NestFactory } from '@nestjs/core';
import { ChartManagementService } from '@/core/chart/ChartManagementService.js';
import { QueueProcessorService } from '@/queue/QueueProcessorService.js';
import { NestLogger } from '@/NestLogger.js';
import { QueueProcessorModule } from '@/queue/QueueProcessorModule.js';
import { envOption } from '@/env.js';
import { jobQueue, server } from './common.js';
/**
* Init worker process
*/
export async function workerMain() {
const jobQueue = await NestFactory.createApplicationContext(QueueProcessorModule, {
logger: new NestLogger(),
});
jobQueue.enableShutdownHooks();
// start job queue
jobQueue.get(QueueProcessorService).start();
jobQueue.get(ChartManagementService).start();
if (envOption.onlyServer) {
await server();
} else if (envOption.onlyQueue) {
await jobQueue();
} else {
await jobQueue();
}
if (cluster.isWorker) {
// Send a 'ready' message to parent process

View File

@@ -44,6 +44,7 @@ const ACHIEVEMENT_TYPES = [
'loggedInOnNewYearsDay',
'noteClipped1',
'noteFavorited1',
'myNoteFavorited1',
'profileFilled',
'markedAsCat',
'following1',
@@ -61,12 +62,14 @@ const ACHIEVEMENT_TYPES = [
'collectAchievements30',
'viewAchievements3min',
'iLoveMisskey',
'foundTreasure',
'client30min',
'noteDeletedWithin1min',
'postedAtLateNight',
'postedAt0min0sec',
'selfQuote',
'htl20npm',
'viewInstanceChart',
'outputHelloWorldOnScratchpad',
'open3windows',
'driveFolderCircularReference',
@@ -94,7 +97,7 @@ export class AchievementService {
@bindThis
public async create(
userId: User['id'],
type: string,
type: typeof ACHIEVEMENT_TYPES[number],
): Promise<void> {
if (!ACHIEVEMENT_TYPES.includes(type)) return;

View File

@@ -4,8 +4,8 @@ import * as util from 'node:util';
import { Inject, Injectable } from '@nestjs/common';
import IPCIDR from 'ip-cidr';
import PrivateIp from 'private-ip';
import got, * as Got from 'got';
import chalk from 'chalk';
import { buildConnector } from 'undici';
import { DI } from '@/di-symbols.js';
import type { Config } from '@/config.js';
import { HttpRequestService, UndiciFetcher } from '@/core/HttpRequestService.js';
@@ -13,7 +13,6 @@ import { createTemp } from '@/misc/create-temp.js';
import { StatusError } from '@/misc/status-error.js';
import { LoggerService } from '@/core/LoggerService.js';
import type Logger from '@/logger.js';
import { buildConnector } from 'undici';
const pipeline = util.promisify(stream.pipeline);
import { bindThis } from '@/decorators.js';
@@ -32,23 +31,20 @@ export class DownloadService {
) {
this.logger = this.loggerService.getLogger('download');
this.undiciFetcher = new UndiciFetcher(this.httpRequestService.getStandardUndiciFetcherOption(
{
connect: process.env.NODE_ENV === 'development' ?
this.httpRequestService.clientDefaults.connect
:
this.httpRequestService.getConnectorWithIpCheck(
buildConnector({
...this.httpRequestService.clientDefaults.connect,
}),
(ip) => !this.isPrivateIp(ip)
),
bodyTimeout: 30 * 1000,
},
{
connect: this.httpRequestService.clientDefaults.connect,
}
), this.logger);
this.undiciFetcher = this.httpRequestService.createFetcher({
connect: process.env.NODE_ENV === 'development' ?
this.httpRequestService.clientDefaults.connect
:
this.httpRequestService.getConnectorWithIpCheck(
buildConnector({
...this.httpRequestService.clientDefaults.connect,
}),
(ip) => !this.isPrivateIp(ip),
),
bodyTimeout: 30 * 1000,
}, {
connect: this.httpRequestService.clientDefaults.connect,
}, this.logger);
}
@bindThis

View File

@@ -1,14 +1,14 @@
import * as http from 'node:http';
import * as https from 'node:https';
import { LookupFunction } from 'node:net';
import CacheableLookup from 'cacheable-lookup';
import { HttpProxyAgent, HttpsProxyAgent } from 'hpagent';
import { Inject, Injectable } from '@nestjs/common';
import * as undici from 'undici';
import { DI } from '@/di-symbols.js';
import type { Config } from '@/config.js';
import { StatusError } from '@/misc/status-error.js';
import { bindThis } from '@/decorators.js';
import * as undici from 'undici';
import { LookupFunction } from 'node:net';
import { LoggerService } from '@/core/LoggerService.js';
import type Logger from '@/logger.js';
@@ -62,7 +62,7 @@ export class UndiciFetcher {
undici.buildConnector(args.agentOptions.connect as undici.buildConnector.BuildOptions)(options, (err, socket) => {
this.logger?.debug('Socket connector called', socket);
if (err) {
this.logger?.debug(`Socket error`, err);
this.logger?.debug('Socket error', err);
cb(new Error(`Error while socket connecting\n${err}`), null);
return;
}
@@ -79,20 +79,20 @@ export class UndiciFetcher {
uri: args.proxy.uri,
connect: (process.env.NODE_ENV !== 'production' && typeof (args.proxy?.options?.connect ?? args.agentOptions.connect) !== 'function')
connect: (process.env.NODE_ENV !== 'production' && typeof (args.proxy.options?.connect ?? args.agentOptions.connect) !== 'function')
? (options, cb) => {
// Custom connector for debug
undici.buildConnector((args.proxy?.options?.connect ?? args.agentOptions.connect) as undici.buildConnector.BuildOptions)(options, (err, socket) => {
this.logger?.debug('Socket connector called (secure)', socket);
if (err) {
this.logger?.debug(`Socket error`, err);
this.logger?.debug('Socket error', err);
cb(new Error(`Error while socket connecting\n${err}`), null);
return;
}
this.logger?.debug(`Socket connected (secure): port ${socket.localPort} => remote ${socket.remoteAddress}`);
cb(null, socket);
});
} : (args.proxy?.options?.connect ?? args.agentOptions.connect),
} : (args.proxy.options?.connect ?? args.agentOptions.connect),
})
: this.nonProxiedAgent;
}
@@ -115,7 +115,7 @@ export class UndiciFetcher {
public async fetch(
url: string | URL,
options: undici.RequestInit = {},
privateOptions: { noOkError?: boolean; bypassProxy?: boolean; } = { noOkError: false, bypassProxy: false }
privateOptions: { noOkError?: boolean; bypassProxy?: boolean; } = { noOkError: false, bypassProxy: false },
): Promise<undici.Response> {
const res = await undici.fetch(url, {
dispatcher: this.getAgentByUrl(new URL(url), privateOptions.bypassProxy),
@@ -134,32 +134,57 @@ export class UndiciFetcher {
return res;
}
@bindThis
public async request(
url: string | URL,
options: { dispatcher?: undici.Dispatcher } & Omit<undici.Dispatcher.RequestOptions, 'origin' | 'path' | 'method'> & Partial<Pick<undici.Dispatcher.RequestOptions, 'method'>> = {},
privateOptions: { noOkError?: boolean; bypassProxy?: boolean; } = { noOkError: false, bypassProxy: false },
): Promise<undici.Dispatcher.ResponseData> {
const res = await undici.request(url, {
dispatcher: this.getAgentByUrl(new URL(url), privateOptions.bypassProxy),
...options,
headers: {
'user-agent': this.userAgent ?? '',
...(options.headers ?? {}),
},
}).catch((err) => {
this.logger?.error(`fetch error to ${typeof url === 'string' ? url : url.href}`, err);
throw new StatusError('Resource Unreachable', 500, 'Resource Unreachable');
});
if (res.statusCode >= 400) {
throw new StatusError(`${res.statusCode}`, res.statusCode, '');
}
return res;
}
@bindThis
public async getJson<T extends unknown>(url: string, accept = 'application/json, */*', headers?: Record<string, string>): Promise<T> {
const res = await this.fetch(
const { body } = await this.request(
url,
{
headers: Object.assign({
Accept: accept,
}, headers ?? {}),
}
},
);
return await res.json() as T;
return await body.json() as T;
}
@bindThis
public async getHtml(url: string, accept = 'text/html, */*', headers?: Record<string, string>): Promise<string> {
const res = await this.fetch(
const { body } = await this.request(
url,
{
headers: Object.assign({
Accept: accept,
}, headers ?? {}),
}
},
);
return await res.text();
return await body.text();
}
}
@@ -167,6 +192,7 @@ export class UndiciFetcher {
export class HttpRequestService {
public defaultFetcher: UndiciFetcher;
public fetch: UndiciFetcher['fetch'];
public request: UndiciFetcher['request'];
public getHtml: UndiciFetcher['getHtml'];
public defaultJsonFetcher: UndiciFetcher;
public getJson: UndiciFetcher['getJson'];
@@ -219,18 +245,19 @@ export class HttpRequestService {
maxCachedSessions: 300, // TLSセッションのキャッシュ数 https://github.com/nodejs/undici/blob/v5.14.0/lib/core/connect.js#L80
lookup: this.dnsCache.lookup as LookupFunction, // https://github.com/nodejs/undici/blob/v5.14.0/lib/core/connect.js#L98
},
}
};
this.maxSockets = Math.max(64, this.config.deliverJobConcurrency ?? 128);
this.maxSockets = Math.max(64, ((this.config.deliverJobConcurrency ?? 128) / (this.config.clusterLimit ?? 1)));
this.defaultFetcher = new UndiciFetcher(this.getStandardUndiciFetcherOption(), this.logger);
this.defaultFetcher = this.createFetcher({}, {}, this.logger);
this.fetch = this.defaultFetcher.fetch;
this.request = this.defaultFetcher.request;
this.getHtml = this.defaultFetcher.getHtml;
this.defaultJsonFetcher = new UndiciFetcher(this.getStandardUndiciFetcherOption({
this.defaultJsonFetcher = this.createFetcher({
maxResponseSize: 1024 * 256,
}), this.logger);
}, {}, this.logger);
this.getJson = this.defaultJsonFetcher.getJson;
@@ -272,23 +299,28 @@ export class HttpRequestService {
}
@bindThis
public getStandardUndiciFetcherOption(opts: undici.Agent.Options = {}, proxyOpts: undici.Agent.Options = {}) {
private getStandardUndiciFetcherOption(opts: undici.Agent.Options = {}, proxyOpts: undici.Agent.Options = {}) {
return {
agentOptions: {
...this.clientDefaults,
...opts,
},
...(this.config.proxy ? {
proxy: {
uri: this.config.proxy,
options: {
connections: this.maxSockets,
...proxyOpts,
}
}
proxy: {
uri: this.config.proxy,
options: {
connections: this.maxSockets,
...proxyOpts,
},
},
} : {}),
userAgent: this.config.userAgent,
}
};
}
@bindThis
public createFetcher(opts: undici.Agent.Options = {}, proxyOpts: undici.Agent.Options = {}, logger: Logger) {
return new UndiciFetcher(this.getStandardUndiciFetcherOption(opts, proxyOpts), logger);
}
/**
@@ -314,13 +346,13 @@ export class HttpRequestService {
connector(options, (err, socket) => {
this.logger.debug('Socket connector (with ip checker) called', socket);
if (err) {
this.logger.error(`Socket error`, err)
this.logger.error('Socket error', err);
cb(new Error(`Error while socket connecting\n${err}`), null);
return;
}
if (socket.remoteAddress == undefined) {
this.logger.error(`Socket error: remoteAddress is undefined`);
this.logger.error('Socket error: remoteAddress is undefined');
cb(new Error('remoteAddress is undefined (maybe socket destroyed)'), null);
return;
}

View File

@@ -9,10 +9,12 @@ import { HttpRequestService, UndiciFetcher } from '@/core/HttpRequestService.js'
import { LoggerService } from '@/core/LoggerService.js';
import { bindThis } from '@/decorators.js';
import type Logger from '@/logger.js';
import type { Dispatcher } from 'undici';
import { DevNull } from '@/misc/dev-null.js';
type Request = {
url: string;
method: string;
method: Dispatcher.HttpMethod;
headers: Record<string, string>;
};
@@ -41,10 +43,10 @@ export class ApRequestService {
private httpRequestService: HttpRequestService,
private loggerService: LoggerService,
) {
this.logger = this.loggerService?.getLogger('ap-request'); // なぜか TypeError: Cannot read properties of undefined (reading 'getLogger') と言われる
this.undiciFetcher = new UndiciFetcher(this.httpRequestService.getStandardUndiciFetcherOption({
this.logger = this.loggerService.getLogger('ap-request'); // なぜか TypeError: Cannot read properties of undefined (reading 'getLogger') と言われる
this.undiciFetcher = this.httpRequestService.createFetcher({
maxRedirections: 0,
}), this.logger );
}, {}, this.logger);
}
@bindThis
@@ -163,14 +165,15 @@ export class ApRequestService {
},
});
await this.undiciFetcher.fetch(
const response = await this.undiciFetcher.request(
url,
{
method: req.request.method,
headers: req.request.headers,
body,
}
},
);
response.body.pipe(new DevNull());
}
/**
@@ -197,7 +200,7 @@ export class ApRequestService {
{
method: req.request.method,
headers: req.request.headers,
}
},
);
return await res.json();

View File

@@ -8,13 +8,13 @@ import { HttpRequestService, UndiciFetcher } from '@/core/HttpRequestService.js'
import { DI } from '@/di-symbols.js';
import { UtilityService } from '@/core/UtilityService.js';
import { bindThis } from '@/decorators.js';
import { LoggerService } from '@/core/LoggerService.js';
import type Logger from '@/logger.js';
import { isCollectionOrOrderedCollection } from './type.js';
import { ApDbResolverService } from './ApDbResolverService.js';
import { ApRendererService } from './ApRendererService.js';
import { ApRequestService } from './ApRequestService.js';
import { LoggerService } from '@/core/LoggerService.js';
import type { IObject, ICollection, IOrderedCollection } from './type.js';
import type Logger from '@/logger.js';
export class Resolver {
private history: Set<string>;
@@ -39,10 +39,10 @@ export class Resolver {
private recursionLimit = 100,
) {
this.history = new Set();
this.logger = this.loggerService?.getLogger('ap-resolve'); // なぜか TypeError: Cannot read properties of undefined (reading 'getLogger') と言われる
this.undiciFetcher = new UndiciFetcher(this.httpRequestService.getStandardUndiciFetcherOption({
this.logger = this.loggerService?.getLogger('ap-resolve'); // なぜか TypeError: Cannot read properties of undefined (reading 'getLogger') と言われる
this.undiciFetcher = this.httpRequestService.createFetcher({
maxRedirections: 0,
}), this.logger);
}, {}, this.logger);
}
@bindThis

View File

@@ -22,7 +22,7 @@ export class EmojiEntityService {
@bindThis
public async pack(
src: Emoji['id'] | Emoji,
opts: { omitHost?: boolean; omitId?: boolean; } = {},
opts: { omitHost?: boolean; omitId?: boolean; withUrl?: boolean; } = {},
): Promise<Packed<'Emoji'>> {
const emoji = typeof src === 'object' ? src : await this.emojisRepository.findOneByOrFail({ id: src });
@@ -32,13 +32,15 @@ export class EmojiEntityService {
name: emoji.name,
category: emoji.category,
host: opts.omitHost ? undefined : emoji.host,
// || emoji.originalUrl してるのは後方互換性のためpublicUrlはstringなので??はだめ)
url: opts.withUrl ? (emoji.publicUrl || emoji.originalUrl) : undefined,
};
}
@bindThis
public packMany(
emojis: any[],
opts: { omitHost?: boolean; omitId?: boolean; } = {},
opts: { omitHost?: boolean; omitId?: boolean; withUrl?: boolean; } = {},
) {
return Promise.all(emojis.map(x => this.pack(x, opts)));
}

View File

@@ -0,0 +1,11 @@
import { Writable, WritableOptions } from "node:stream";
export class DevNull extends Writable implements NodeJS.WritableStream {
constructor(opts?: WritableOptions) {
super(opts);
}
_write (chunk: any, encoding: BufferEncoding, cb: (err?: Error | null) => void) {
setImmediate(cb);
}
}

View File

@@ -29,5 +29,9 @@ export const packedEmojiSchema = {
optional: true, nullable: true,
description: 'The local host is represented with `null`.',
},
url: {
type: 'string',
optional: true, nullable: false,
},
},
} as const;

View File

@@ -83,6 +83,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
emojis: await this.emojiEntityService.packMany(emojis, {
omitId: true,
omitHost: true,
withUrl: true,
}),
};
});

View File

@@ -6,6 +6,7 @@ import { Endpoint } from '@/server/api/endpoint-base.js';
import { GetterService } from '@/server/api/GetterService.js';
import { DI } from '@/di-symbols.js';
import { ApiError } from '../../../error.js';
import { AchievementService } from '@/core/AchievementService.js';
export const meta = {
tags: ['notes', 'favorites'],
@@ -51,6 +52,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
private idService: IdService,
private getterService: GetterService,
private achievementService: AchievementService,
) {
super(meta, paramDef, async (ps, me) => {
// Get favoritee
@@ -76,6 +78,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
noteId: note.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);
};
const v = localStorage.getItem('v') || VERSION;
let forceError = localStorage.getItem('forceError');
if (forceError != null) {
renderError('FORCED_ERROR', 'This error is forced by having forceError in local storage.')
}
//#region Detect language & fetch translations
const localeVersion = localStorage.getItem('localeVersion');
const localeOutdated = (localeVersion == null || localeVersion !== v);
if (!localStorage.hasOwnProperty('locale') || localeOutdated) {
if (!localStorage.hasOwnProperty('locale')) {
const supportedLangs = LANGS;
let lang = localStorage.getItem('lang');
if (lang == null || !supportedLangs.includes(lang)) {
@@ -47,13 +42,31 @@
}
}
const res = await window.fetch(`/assets/locales/${lang}.${v}.json`);
if (res.status === 200) {
const metaRes = await window.fetch('/api/meta', {
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 metaRes.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('locale', await res.text());
localStorage.setItem('locale', await localRes.text());
localStorage.setItem('localeVersion', v);
} else {
await checkUpdate();
renderError('LOCALE_FETCH');
return;
}
@@ -64,7 +77,6 @@
function importAppScript() {
import(`/vite/${CLIENT_ENTRY}`)
.catch(async e => {
await checkUpdate();
console.error(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

@@ -35,7 +35,7 @@ html
link(rel='prefetch' href='https://xn--931a.moe/assets/info.jpg')
link(rel='prefetch' href='https://xn--931a.moe/assets/not-found.jpg')
link(rel='prefetch' href='https://xn--931a.moe/assets/error.jpg')
link(rel='stylesheet' href='/assets/tabler-icons/tabler-icons.css')
link(rel='stylesheet' href='/assets/tabler-icons/tabler-icons.min.css')
link(rel='modulepreload' href=`/vite/${clientEntry.file}`)
if !config.clientManifestExists

View File

@@ -8,20 +8,20 @@
},
"dependencies": {
"@discordapp/twemoji": "14.0.2",
"@rollup/plugin-alias": "4.0.2",
"@rollup/plugin-alias": "4.0.3",
"@rollup/plugin-json": "6.0.0",
"@rollup/pluginutils": "5.0.2",
"@syuilo/aiscript": "0.12.2",
"@tabler/icons": "^1.118.0",
"@tabler/icons-webfont": "^2.0.0",
"@vitejs/plugin-vue": "4.0.0",
"@vue/compiler-sfc": "3.2.45",
"autobind-decorator": "2.4.0",
"autosize": "5.0.2",
"blurhash": "2.0.4",
"broadcast-channel": "4.20.1",
"broadcast-channel": "4.20.2",
"browser-image-resizer": "git+https://github.com/misskey-dev/browser-image-resizer#v2.2.1-misskey.3",
"canvas-confetti": "^1.6.0",
"chart.js": "4.1.2",
"chart.js": "4.2.0",
"chartjs-adapter-date-fns": "3.0.0",
"chartjs-chart-matrix": "^1.3.0",
"chartjs-plugin-gradient": "0.6.1",
@@ -41,10 +41,10 @@
"misskey-js": "0.0.14",
"photoswipe": "5.3.4",
"prismjs": "1.29.0",
"punycode": "2.2.0",
"punycode": "2.3.0",
"querystring": "0.2.1",
"rndstr": "1.0.0",
"rollup": "3.10.0",
"rollup": "3.10.1",
"s-age": "1.1.2",
"sanitize-html": "^2.8.1",
"sass": "1.57.1",
@@ -69,7 +69,7 @@
},
"devDependencies": {
"@types/escape-regexp": "0.0.1",
"@types/glob": "8.0.0",
"@types/glob": "8.0.1",
"@types/gulp": "4.0.10",
"@types/gulp-rename": "2.0.1",
"@types/matter-js": "0.18.2",
@@ -82,15 +82,15 @@
"@types/uuid": "9.0.0",
"@types/websocket": "1.0.5",
"@types/ws": "8.5.4",
"@typescript-eslint/eslint-plugin": "5.48.1",
"@typescript-eslint/parser": "5.48.1",
"@typescript-eslint/eslint-plugin": "5.49.0",
"@typescript-eslint/parser": "5.49.0",
"@vue/runtime-core": "3.2.45",
"cross-env": "7.0.3",
"cypress": "12.3.0",
"eslint": "8.31.0",
"eslint-plugin-import": "2.27.4",
"eslint": "8.32.0",
"eslint-plugin-import": "2.27.5",
"eslint-plugin-vue": "9.9.0",
"start-server-and-test": "1.15.2",
"start-server-and-test": "1.15.3",
"vue-eslint-parser": "^9.1.0",
"vue-tsc": "^1.0.24"
}

View File

@@ -16,8 +16,8 @@
<time v-tooltip="new Date(achievement.unlockedAt).toLocaleString()">{{ new Date(achievement.unlockedAt).getFullYear() }}/{{ new Date(achievement.unlockedAt).getMonth() + 1 }}/{{ new Date(achievement.unlockedAt).getDate() }}</time>
</span>
</div>
<div :class="$style.description">{{ i18n.ts._achievements._types['_' + achievement.name].description }}</div>
<div v-if="i18n.ts._achievements._types['_' + achievement.name].flavor" :class="$style.flavor">{{ i18n.ts._achievements._types['_' + achievement.name].flavor }}</div>
<div :class="$style.description">{{ withDescription ? i18n.ts._achievements._types['_' + achievement.name].description : '???' }}</div>
<div v-if="i18n.ts._achievements._types['_' + achievement.name].flavor && withDescription" :class="$style.flavor">{{ i18n.ts._achievements._types['_' + achievement.name].flavor }}</div>
</div>
</div>
<template v-if="withLocked">
@@ -49,8 +49,10 @@ import { ACHIEVEMENT_TYPES, ACHIEVEMENT_BADGES, claimAchievement } from '@/scrip
const props = withDefaults(defineProps<{
user: misskey.entities.User;
withLocked: boolean;
withDescription: boolean;
}>(), {
withLocked: true,
withDescription: true,
});
let achievements = $ref();

View File

@@ -15,7 +15,7 @@
<i v-else-if="notification.type === 'mention'" class="ti ti-at"></i>
<i v-else-if="notification.type === 'quote'" class="ti ti-quote"></i>
<i v-else-if="notification.type === 'pollEnded'" class="ti ti-chart-arrows"></i>
<i v-else-if="notification.type === 'achievementEarned'" class="ti ti-military-award"></i>
<i v-else-if="notification.type === 'achievementEarned'" class="ti ti-medal"></i>
<!-- notification.reaction null になることはまずないがここでoptional chaining使うと一部ブラウザで刺さるので念の為 -->
<MkReactionIcon
v-else-if="notification.type === 'reaction'"
@@ -249,7 +249,7 @@ useTooltip(reactionRef, (showing) => {
.t_achievementEarned {
padding: 3px;
background: #88a6b7;
background: #cb9a11;
pointer-events: none;
}

View File

@@ -21,6 +21,7 @@ import { useTooltip } from '@/scripts/use-tooltip';
import { $i } from '@/account';
import MkReactionEffect from '@/components/MkReactionEffect.vue';
import { claimAchievement } from '@/scripts/achievements';
import { defaultStore } from '@/store';
const props = defineProps<{
reaction: string;
@@ -61,6 +62,7 @@ const toggleReaction = () => {
const anime = () => {
if (document.hidden) return;
if (!defaultStore.state.animation) return;
const rect = buttonEl.value.getBoundingClientRect();
const x = rect.left + 16;

View File

@@ -12,6 +12,7 @@ import { getStaticImageUrl } from '@/scripts/media-proxy';
import { char2twemojiFilePath, char2fluentEmojiFilePath } from '@/scripts/emoji-base';
import { defaultStore } from '@/store';
import { getEmojiName } from '@/scripts/emojilist';
import { customEmojis } from '@/custom-emojis';
const props = defineProps<{
emoji: string;
@@ -24,12 +25,15 @@ const props = defineProps<{
const char2path = defaultStore.state.emojiStyle === 'twemoji' ? char2twemojiFilePath : char2fluentEmojiFilePath;
const isCustom = computed(() => props.emoji.startsWith(':'));
const customEmojiName = props.emoji.substr(1, props.emoji.length - 2);
const customEmojiName = props.emoji.substr(1, props.emoji.length - 2).replace('@.', '');
const char = computed(() => isCustom.value ? undefined : props.emoji);
const useOsNativeEmojis = computed(() => defaultStore.state.emojiStyle === 'native' && !props.isReaction);
const url = computed(() => {
if (char.value) {
return char2path(char.value);
} else if (props.host == null && !customEmojiName.includes('@')) {
const found = customEmojis.find(x => x.name === customEmojiName);
return found ? found.url : null;
} else {
const rawUrl = props.host ? `/emoji/${customEmojiName}@${props.host}.webp` : `/emoji/${customEmojiName}.webp`;
return defaultStore.state.disableShowingAnimatedImages
@@ -38,7 +42,7 @@ const url = computed(() => {
}
});
const alt = computed(() => isCustom.value ? `:${customEmojiName}:` : char.value);
let errored = $ref(false);
let errored = $ref(isCustom.value && url.value == null);
// Searching from an array with 2000 items for every emoji felt like too energy-consuming, so I decided to do it lazily on pointerenter
function computeTitle(event: PointerEvent): void {

View File

@@ -200,6 +200,12 @@ export default defineComponent({
style = `transform: translateX(${x}em) translateY(${y}em);`;
break;
}
case 'scale': {
const x = Math.min(parseInt(token.props.args.x ?? '1'), 5);
const y = Math.min(parseInt(token.props.args.y ?? '1'), 5);
style = `transform: scale(${x}, ${y});`;
break;
}
case 'fg': {
let color = token.props.args.color;
if (!/^[0-9a-f]{3,6}$/i.test(color)) color = 'f00';

View File

@@ -10,8 +10,12 @@ export const apiUrl = url + '/api';
export const wsUrl = url.replace('http://', 'ws://').replace('https://', 'wss://') + '/streaming';
export const lang = miLocalStorage.getItem('lang');
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 instanceName = siteName === 'Misskey' ? host : siteName;
export const ui = miLocalStorage.getItem('ui');
export const debug = miLocalStorage.getItem('debug') === 'true';
export function updateLocale(newLocale) {
locale = newLocale;
}

View File

@@ -2,14 +2,17 @@ import { api } from './os';
import { miLocalStorage } from './local-storage';
const storageCache = miLocalStorage.getItem('emojis');
export let customEmojis = storageCache ? JSON.parse(storageCache) : [];
fetchCustomEmojis();
export let customEmojis: {
name: string;
aliases: string[];
category: string;
url: string;
}[] = storageCache ? JSON.parse(storageCache) : [];
export async function fetchCustomEmojis() {
const now = Date.now();
const lastFetchedAt = miLocalStorage.getItem('lastEmojisFetchedAt');
if (lastFetchedAt && (now - parseInt(lastFetchedAt)) < 1000 * 60 * 60) return;
if (lastFetchedAt && (now - parseInt(lastFetchedAt)) < 1000 * 60 * 60 * 24) return;
const res = await api('emojis', {});

View File

@@ -3,3 +3,7 @@ import { locale } from '@/config';
import { I18n } from '@/scripts/i18n';
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 directives from '@/directives';
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 { isDeviceDarkmode } from '@/scripts/is-device-darkmode';
import { i18n } from '@/i18n';
import { i18n, updateI18n } from '@/i18n';
import { confirm, alert, post, popup, toast } from '@/os';
import { stream } from '@/stream';
import * as sound from '@/scripts/sound';
@@ -45,6 +45,7 @@ import { getUrlWithoutLoginId } from '@/scripts/login-id';
import { getAccountFromId } from '@/scripts/get-account-from-id';
import { miLocalStorage } from './local-storage';
import { claimAchievement, claimedAchievements } from './scripts/achievements';
import { fetchCustomEmojis } from './custom-emojis';
(async () => {
console.info(`Misskey v${version}`);
@@ -80,6 +81,22 @@ import { claimAchievement, claimedAchievements } from './scripts/achievements';
});
}
//#region Detect language & fetch translations
const localeVersion = miLocalStorage.getItem('localeVersion');
const localeOutdated = (localeVersion == null || localeVersion !== version);
if (localeOutdated) {
const res = await window.fetch(`/assets/locales/${lang}.${version}.json`);
if (res.status === 200) {
const newLocale = await res.text();
const parsedNewLocale = JSON.parse(newLocale);
miLocalStorage.setItem('locale', newLocale);
miLocalStorage.setItem('localeVersion', version);
updateLocale(parsedNewLocale);
updateI18n(parsedNewLocale);
}
}
//#endregion
// タッチデバイスでCSSの:hoverを機能させる
document.addEventListener('touchend', () => {}, { passive: true });
@@ -165,6 +182,10 @@ import { claimAchievement, claimedAchievements } from './scripts/achievements';
initializeSw();
});
try {
await fetchCustomEmojis();
} catch (err) {}
const app = createApp(
window.location.search === '?zen' ? defineAsyncComponent(() => import('@/ui/zen.vue')) :
!$i ? defineAsyncComponent(() => import('@/ui/visitor.vue')) :

View File

@@ -19,6 +19,7 @@ type Keys =
'fontSize' |
'ui' |
'locale' |
'localeVersion' |
'theme' |
'customCss' |
'message_drafts' |

View File

@@ -105,7 +105,7 @@ export const navbarItemDef = reactive({
},
achievements: {
title: i18n.ts.achievements,
icon: 'ti ti-military-award',
icon: 'ti ti-medal',
show: computed(() => $i != null),
to: '/my/achievements',
},

View File

@@ -4,11 +4,14 @@
<div style="overflow: clip;">
<MkSpacer :content-max="600" :margin-min="20">
<div class="_gaps_m znqjceqz">
<div ref="containerEl" v-panel class="about" :class="{ playing: easterEggEngine != null }">
<img src="/client-assets/about-icon.png" alt="" class="icon" draggable="false" @load="iconLoaded" @click="gravity"/>
<div class="misskey">Misskey</div>
<div class="version">v{{ version }}</div>
<span v-for="emoji in easterEggEmojis" :key="emoji.id" class="emoji" :data-physics-x="emoji.left" :data-physics-y="emoji.top" :class="{ _physics_circle_: !emoji.emoji.startsWith(':') }"><MkEmoji class="emoji" :emoji="emoji.emoji" :is-reaction="false" :normal="true" :no-style="true"/></span>
<div v-panel class="about">
<div ref="containerEl" class="container" :class="{ playing: easterEggEngine != null }">
<img src="/client-assets/about-icon.png" alt="" class="icon" draggable="false" @load="iconLoaded" @click="gravity"/>
<div class="misskey">Misskey</div>
<div class="version">v{{ version }}</div>
<span v-for="emoji in easterEggEmojis" :key="emoji.id" class="emoji" :data-physics-x="emoji.left" :data-physics-y="emoji.top" :class="{ _physics_circle_: !emoji.emoji.startsWith(':') }"><MkEmoji class="emoji" :emoji="emoji.emoji" :is-reaction="false" :normal="true" :no-style="true"/></span>
</div>
<button v-if="thereIsTreasure" class="_button treasure" @click="getTreasure"><img src="/fluent-emoji/1f3c6.png" class="treasureImg"></button>
</div>
<div style="text-align: center;">
{{ i18n.ts._aboutMisskey.about }}<br><a href="https://misskey-hub.net/docs/misskey.html" target="_blank" class="_link">{{ i18n.ts.learnMore }}</a>
@@ -37,11 +40,31 @@
</FormSection>
<FormSection>
<template #label>{{ i18n.ts._aboutMisskey.contributors }}</template>
<div class="_formLinksGrid">
<FormLink to="https://github.com/syuilo" external>@syuilo</FormLink>
<FormLink to="https://github.com/tamaina" external>@tamaina</FormLink>
<FormLink to="https://github.com/acid-chicken" external>@acid-chicken</FormLink>
<FormLink to="https://github.com/rinsuki" external>@rinsuki</FormLink>
<div :class="$style.contributors">
<a href="https://github.com/syuilo" target="_blank" :class="$style.contributor">
<img src="https://avatars.githubusercontent.com/u/4439005?v=4" :class="$style.contributorAvatar">
<span :class="$style.contributorUsername">@syuilo</span>
</a>
<a href="https://github.com/tamaina" target="_blank" :class="$style.contributor">
<img src="https://avatars.githubusercontent.com/u/7973572?v=4" :class="$style.contributorAvatar">
<span :class="$style.contributorUsername">@tamaina</span>
</a>
<a href="https://github.com/acid-chicken" target="_blank" :class="$style.contributor">
<img src="https://avatars.githubusercontent.com/u/20679825?v=4" :class="$style.contributorAvatar">
<span :class="$style.contributorUsername">@acid-chicken</span>
</a>
<a href="https://github.com/rinsuki" target="_blank" :class="$style.contributor">
<img src="https://avatars.githubusercontent.com/u/6533808?v=4" :class="$style.contributorAvatar">
<span :class="$style.contributorUsername">@rinsuki</span>
</a>
<a href="https://github.com/mei23" target="_blank" :class="$style.contributor">
<img src="https://avatars.githubusercontent.com/u/30769358?v=4" :class="$style.contributorAvatar">
<span :class="$style.contributorUsername">@mei23</span>
</a>
<a href="https://github.com/robflop" target="_blank" :class="$style.contributor">
<img src="https://avatars.githubusercontent.com/u/8159402?v=4" :class="$style.contributorAvatar">
<span :class="$style.contributorUsername">@robflop</span>
</a>
</div>
<template #caption><MkLink url="https://github.com/misskey-dev/misskey/graphs/contributors">{{ i18n.ts._aboutMisskey.allContributors }}</MkLink></template>
</FormSection>
@@ -70,6 +93,8 @@ import { i18n } from '@/i18n';
import { defaultStore } from '@/store';
import * as os from '@/os';
import { definePageMetadata } from '@/scripts/page-metadata';
import { claimAchievement, claimedAchievements } from '@/scripts/achievements';
import { $i } from '@/account';
const patrons = [
'まっちゃとーにゅ',
@@ -152,6 +177,8 @@ const patrons = [
'pixeldesu',
];
let thereIsTreasure = $ref($i && !claimedAchievements.includes('foundTreasure'));
let easterEggReady = false;
let easterEggEmojis = $ref([]);
let easterEggEngine = $ref(null);
@@ -187,6 +214,11 @@ function iLoveMisskey() {
});
}
function getTreasure() {
thereIsTreasure = false;
claimAchievement('foundTreasure');
}
onBeforeUnmount(() => {
if (easterEggEngine) {
easterEggEngine.stop();
@@ -207,54 +239,114 @@ definePageMetadata({
.znqjceqz {
> .about {
position: relative;
text-align: center;
padding: 16px;
border-radius: var(--radius);
&.playing {
&, * {
user-select: none;
}
* {
will-change: transform;
}
> .emoji {
visibility: visible;
}
}
> .icon {
display: block;
width: 80px;
margin: 0 auto;
border-radius: 16px;
}
> .misskey {
margin: 0.75em auto 0 auto;
width: max-content;
}
> .version {
margin: 0 auto;
width: max-content;
opacity: 0.5;
}
> .emoji {
> .treasure {
position: absolute;
top: 0;
top: 60px;
left: 0;
visibility: hidden;
right: 0;
margin: 0 auto;
width: min-content;
> .treasureImg {
width: 25px;
vertical-align: bottom;
}
}
> .container {
position: relative;
text-align: center;
padding: 16px;
&.playing {
&, * {
user-select: none;
}
* {
will-change: transform;
}
> .emoji {
visibility: visible;
}
}
> .icon {
display: block;
width: 80px;
margin: 0 auto;
border-radius: 16px;
position: relative;
z-index: 1;
}
> .misskey {
margin: 0.75em auto 0 auto;
width: max-content;
position: relative;
z-index: 1;
}
> .version {
margin: 0 auto;
width: max-content;
opacity: 0.5;
position: relative;
z-index: 1;
}
> .emoji {
pointer-events: none;
font-size: 24px;
width: 24px;
position: absolute;
z-index: 1;
top: 0;
left: 0;
visibility: hidden;
> .emoji {
pointer-events: none;
font-size: 24px;
width: 24px;
}
}
}
}
}
</style>
<style lang="scss" module>
.contributors {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
grid-gap: 12px;
}
.contributor {
display: flex;
align-items: center;
padding: 12px;
background: var(--buttonBg);
border-radius: 6px;
&:hover {
text-decoration: none;
background: var(--buttonHoverBg);
}
&.active {
color: var(--accent);
background: var(--buttonHoverBg);
}
}
.contributorAvatar {
width: 30px;
border-radius: 100%;
}
.contributorUsername {
margin-left: 12px;
}
</style>

View File

@@ -86,7 +86,7 @@
</template>
<script lang="ts" setup>
import { ref, computed } from 'vue';
import { ref, computed, watch } from 'vue';
import XEmojis from './about.emojis.vue';
import XFederation from './about.federation.vue';
import { version, instanceName, host } from '@/config';
@@ -100,6 +100,7 @@ import * as os from '@/os';
import number from '@/filters/number';
import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata';
import { claimAchievement } from '@/scripts/achievements';
const props = withDefaults(defineProps<{
initialTab?: string;
@@ -110,6 +111,12 @@ const props = withDefaults(defineProps<{
let stats = $ref(null);
let tab = $ref(props.initialTab);
watch($$(tab), () => {
if (tab === 'charts') {
claimAchievement('viewInstanceChart');
}
});
const initStats = () => os.api('stats', {
}).then((res) => {
stats = res;

View File

@@ -45,7 +45,7 @@ onDeactivated(() => {
definePageMetadata({
title: i18n.ts.achievements,
icon: 'ti ti-military-award',
icon: 'ti ti-medal',
});
</script>

View File

@@ -38,7 +38,7 @@
<template #label>Access key</template>
</MkInput>
<MkInput v-model="objectStorageSecretKey">
<MkInput v-model="objectStorageSecretKey" type="password">
<template #prefix><i class="ti ti-key"></i></template>
<template #label>Secret key</template>
</MkInput>

View File

@@ -1,6 +1,6 @@
<template>
<button class="zuvgdzyu _button" @click="menu">
<img :src="`/emoji/${emoji.name}.webp`" class="img" loading="lazy"/>
<img :src="emoji.url" class="img" loading="lazy"/>
<div class="body">
<div class="name _monospace">{{ emoji.name }}</div>
<div class="info">{{ emoji.aliases.join(' ') }}</div>
@@ -15,7 +15,12 @@ import copyToClipboard from '@/scripts/copy-to-clipboard';
import { i18n } from '@/i18n';
const props = defineProps<{
emoji: Record<string, unknown>; // TODO
emoji: {
name: string;
aliases: string[];
category: string;
url: string;
};
}>();
function menu(ev) {

View File

@@ -1,6 +1,6 @@
<template>
<MkSpacer :content-max="1200">
<MkAchievements :user="user" :with-locked="false"/>
<MkAchievements :user="user" :with-locked="false" :with-description="$i != null && (props.user.id === $i.id)"/>
</MkSpacer>
</template>

View File

@@ -81,7 +81,7 @@ const headerTabs = $computed(() => user ? [{
}, ...(user.host == null ? [{
key: 'achievements',
title: i18n.ts.achievements,
icon: 'ti ti-military-award',
icon: 'ti ti-medal',
}] : []), ...($i && ($i.id === user.id)) || user.publicReactions ? [{
key: 'reactions',
title: i18n.ts.reaction,

View File

@@ -40,6 +40,7 @@ export const ACHIEVEMENT_TYPES = [
'loggedInOnNewYearsDay',
'noteClipped1',
'noteFavorited1',
'myNoteFavorited1',
'profileFilled',
'markedAsCat',
'following1',
@@ -57,12 +58,14 @@ export const ACHIEVEMENT_TYPES = [
'collectAchievements30',
'viewAchievements3min',
'iLoveMisskey',
'foundTreasure',
'client30min',
'noteDeletedWithin1min',
'postedAtLateNight',
'postedAt0min0sec',
'selfQuote',
'htl20npm',
'viewInstanceChart',
'outputHelloWorldOnScratchpad',
'open3windows',
'driveFolderCircularReference',
@@ -240,6 +243,11 @@ export const ACHIEVEMENT_BADGES = {
bg: null,
frame: 'bronze',
},
'myNoteFavorited1': {
img: '/fluent-emoji/1f320.png',
bg: null,
frame: 'silver',
},
'profileFilled': {
img: '/fluent-emoji/1f44c.png',
bg: 'linear-gradient(0deg, rgb(187 183 59), rgb(255 143 77))',
@@ -325,6 +333,11 @@ export const ACHIEVEMENT_BADGES = {
bg: 'linear-gradient(0deg, rgb(255 77 77), rgb(247 155 214))',
frame: 'silver',
},
'foundTreasure': {
img: '/fluent-emoji/1f3c6.png',
bg: 'linear-gradient(0deg, rgb(197 69 192), rgb(2 112 155))',
frame: 'gold',
},
'client30min': {
img: '/fluent-emoji/1f552.png',
bg: 'linear-gradient(0deg, rgb(220 223 225), rgb(172 192 207))',
@@ -355,6 +368,11 @@ export const ACHIEVEMENT_BADGES = {
bg: 'linear-gradient(0deg, rgb(220 223 225), rgb(172 192 207))',
frame: 'bronze',
},
'viewInstanceChart': {
img: '/fluent-emoji/1f4ca.png',
bg: 'linear-gradient(0deg, rgb(58 231 198), rgb(37 194 255))',
frame: 'bronze',
},
'outputHelloWorldOnScratchpad': {
img: '/fluent-emoji/1f530.png',
bg: 'linear-gradient(0deg, rgb(58 231 198), rgb(37 194 255))',
@@ -431,18 +449,25 @@ export const ACHIEVEMENT_BADGES = {
frame: 'bronze' | 'silver' | 'gold' | 'platinum';
}>;
export const claimedAchievements = ($i && $i.achievements) ? $i.achievements.map(x => x.name) : [];
export const claimedAchievements: typeof ACHIEVEMENT_TYPES[number][] = ($i && $i.achievements) ? $i.achievements.map(x => x.name) : [];
export function claimAchievement(type: typeof ACHIEVEMENT_TYPES[number]) {
const claimingQueue = new Set<string>();
export async function claimAchievement(type: typeof ACHIEVEMENT_TYPES[number]) {
if ($i == null) return;
if (claimedAchievements.includes(type)) return;
os.api('i/claim-achievement', { name: type });
claimingQueue.add(type);
claimedAchievements.push(type);
await new Promise(resolve => setTimeout(resolve, (claimingQueue.size - 1) * 500));
window.setTimeout(() => {
claimingQueue.delete(type);
}, 500);
os.api('i/claim-achievement', { name: type });
}
if (_DEV_) {
(window as any).unlockAllAchievements = async () => {
(window as any).unlockAllAchievements = () => {
for (const t of ACHIEVEMENT_TYPES) {
await new Promise(resolve => setTimeout(resolve, 100));
claimAchievement(t);
}
};

View File

@@ -303,7 +303,7 @@ function getButtonOptions(def: values.Value | undefined, call: (fn: values.VFn,
if (primary) utils.assertBoolean(primary);
const rounded = def.value.get('rounded');
if (rounded) utils.assertBoolean(rounded);
const disabled = button.value.get('disabled');
const disabled = def.value.get('disabled');
if (disabled) utils.assertBoolean(disabled);
return {

View File

@@ -1 +1 @@
export const MFM_TAGS = ['tada', 'jelly', 'twitch', 'shake', 'spin', 'jump', 'bounce', 'flip', 'x2', 'x3', 'x4', 'position', 'fg', 'bg', 'font', 'blur', 'rainbow', 'sparkle', 'rotate'];
export const MFM_TAGS = ['tada', 'jelly', 'twitch', 'shake', 'spin', 'jump', 'bounce', 'flip', 'x2', 'x3', 'x4', 'scale', 'position', 'fg', 'bg', 'font', 'blur', 'rainbow', 'sparkle', 'rotate'];

View File

@@ -127,11 +127,13 @@ hr {
}
.ti {
vertical-align: -10%;
line-height: 0.9em;
vertical-align: -40%;
line-height: 1em;
&:before {
font-size: 130%;
display: inline-block;
font-size: 165%;
width: 0.74em;
}
}

View File

@@ -54,6 +54,8 @@ export default defineConfig(({ command, mode }) => {
'@/': __dirname + '/src/',
'/client-assets/': __dirname + '/assets/',
'/static-assets/': __dirname + '/../backend/assets/',
'/fluent-emojis/': __dirname + '/../../fluent-emojis/dist/',
'/fluent-emoji/': __dirname + '/../../fluent-emojis/dist/',
},
},

761
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -14,7 +14,7 @@ const fs = require('fs');
stderr: process.stderr,
});
execa('pnpm', ['dlx', 'gulp', 'watch'], {
execa('pnpm', ['exec', 'gulp', 'watch'], {
cwd: __dirname + '/../',
stdout: process.stdout,
stderr: process.stderr,