Compare commits

..

136 Commits

Author SHA1 Message Date
github-actions[bot] 01230f6990 Bump version to 2025.4.1-beta.7 2025-04-28 04:08:47 +00:00
renovate[bot] b09bf25e14 chore(deps): update actions/setup-node action to v4.4.0 (#15901)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-28 13:03:36 +09:00
zyoshoka 7041a3de2a chore: fix Chromatic CI diff strategy (#15902) 2025-04-28 12:57:47 +09:00
syuilo cf07e1e4b9 perf(frontend): improve timeline performance 2025-04-28 12:53:58 +09:00
renovate[bot] e8eb4e1965 fix(deps): update [frontend] update dependencies (#15809)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-28 11:41:23 +09:00
かっこかり b5268fa240 fix(test): fix federation test (#15900) 2025-04-28 11:24:26 +09:00
renovate[bot] 359af232fc fix(deps): update [root] update dependencies (#15691)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-28 11:24:18 +09:00
github-actions[bot] 5d71a5bc23 Bump version to 2025.4.1-beta.6 2025-04-28 01:17:27 +00:00
かっこかり 6acb743e5e deps: update pnpm to v10.10.0 (#15899)
Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
2025-04-28 10:12:04 +09:00
syuilo 4054f1a0c4 🎨 2025-04-28 10:07:23 +09:00
syuilo 76bd33f4c8 Merge branch 'develop' of https://github.com/misskey-dev/misskey into develop 2025-04-28 09:46:43 +09:00
syuilo c99f4dc4ce enhance(frontend): add drive tip 2025-04-28 09:46:41 +09:00
renovate[bot] 0c06e5bef5 chore(deps): update [misskey-js] update dependencies (#15791)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-28 09:35:37 +09:00
renovate[bot] d9ff6011e3 chore(deps): update [tools] update dependencies (#15810)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-28 09:31:34 +09:00
renovate[bot] b94ff3590b fix(deps): update [backend] update dependencies (#15811)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-28 09:29:52 +09:00
syuilo 7c23e53034 refactor 2025-04-28 09:28:23 +09:00
syuilo e0fd1c8f48 tweak custom-emojis-manager 2025-04-28 08:49:37 +09:00
syuilo 8718d1c271 Update CHANGELOG.md 2025-04-28 07:21:52 +09:00
anatawa12 ec92bf47f1 Exclude blocked instance note from most timelines (#15792)
* Exclude blocked instance note from most timelines

* Exclude blocked instance note from FTT timelines

* Exclude blocked instance note from featured

* fix type
2025-04-28 07:21:00 +09:00
syuilo 7581331713 Merge branch 'develop' of https://github.com/misskey-dev/misskey into develop 2025-04-27 21:29:36 +09:00
syuilo 2fbb2e9a9f Update CHANGELOG.md 2025-04-27 21:29:15 +09:00
github-actions[bot] 7bc536c948 Bump version to 2025.4.1-beta.5 2025-04-27 12:27:19 +00:00
syuilo 3f08e41818 🎨 2025-04-27 21:14:59 +09:00
syuilo 04b7dd0948 fix(frontend): tweak spacer style 2025-04-27 20:51:57 +09:00
syuilo ddb41ba821 Merge branch 'develop' of https://github.com/misskey-dev/misskey into develop 2025-04-27 20:42:43 +09:00
syuilo ee49c42410 fix lint 2025-04-27 20:42:41 +09:00
github-actions[bot] 8670ddaffd Bump version to 2025.4.1-beta.4 2025-04-27 11:08:50 +00:00
syuilo d9bff2cd15 New Crowdin updates (#15849)
* New translations ja-jp.yml (Spanish)

* New translations ja-jp.yml (Spanish)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (German)

* New translations ja-jp.yml (English)

* New translations ja-jp.yml (English)

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (Dutch)

* New translations ja-jp.yml (Romanian)

* New translations ja-jp.yml (Romanian)

* New translations ja-jp.yml (Romanian)

* New translations ja-jp.yml (Dutch)

* New translations ja-jp.yml (Romanian)

* New translations ja-jp.yml (Dutch)

* New translations ja-jp.yml (Romanian)

* New translations ja-jp.yml (Romanian)

* New translations ja-jp.yml (Romanian)

* New translations ja-jp.yml (Dutch)

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

* New translations ja-jp.yml (German)

* New translations ja-jp.yml (English)

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (Romanian)

* New translations ja-jp.yml (Romanian)

* New translations ja-jp.yml (Romanian)

* New translations ja-jp.yml (Romanian)

* New translations ja-jp.yml (Romanian)

* New translations ja-jp.yml (Dutch)

* New translations ja-jp.yml (Romanian)

* New translations ja-jp.yml (Romanian)

* New translations ja-jp.yml (Romanian)

* New translations ja-jp.yml (English)

* New translations ja-jp.yml (Romanian)

* New translations ja-jp.yml (Romanian)

* New translations ja-jp.yml (Portuguese)

* New translations ja-jp.yml (Portuguese)

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

* New translations ja-jp.yml (English)

* New translations ja-jp.yml (Spanish)

* New translations ja-jp.yml (Italian)

* New translations ja-jp.yml (Vietnamese)

* New translations ja-jp.yml (Vietnamese)

* New translations ja-jp.yml (Thai)

* New translations ja-jp.yml (Vietnamese)

* New translations ja-jp.yml (Vietnamese)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Spanish)

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

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

* New translations ja-jp.yml (Vietnamese)

* New translations ja-jp.yml (Vietnamese)

* New translations ja-jp.yml (Vietnamese)

* New translations ja-jp.yml (Vietnamese)

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

* New translations ja-jp.yml (English)

* New translations ja-jp.yml (German)

* New translations ja-jp.yml (Catalan)

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

* New translations ja-jp.yml (Dutch)

* New translations ja-jp.yml (Vietnamese)
2025-04-27 20:04:42 +09:00
syuilo cb2948bf94 Merge branch 'develop' of https://github.com/misskey-dev/misskey into develop 2025-04-27 20:04:15 +09:00
syuilo 83893ce52f fix syntax errors 2025-04-27 20:04:13 +09:00
github-actions[bot] 0083386882 Bump version to 2025.4.1-beta.3 2025-04-27 10:58:53 +00:00
syuilo 03e5502d63 add todo 2025-04-27 19:57:19 +09:00
syuilo 0a1ff77f23 perf(frontend): use css-native implementation for spacer rather than vue component 2025-04-27 19:55:56 +09:00
syuilo c4f13a0472 Update CHANGELOG.md 2025-04-27 17:50:08 +09:00
github-actions[bot] 5e294f4c65 Bump version to 2025.4.1-beta.2 2025-04-27 08:44:59 +00:00
syuilo 0f9dff0521 enhance(frontend): improve usability 2025-04-27 17:43:30 +09:00
syuilo 14d3439a42 enhance(frontend): タイムラインをスワイプで切り替えられるように
Resolve #15722
2025-04-27 17:38:48 +09:00
syuilo 889295d621 fix(frontend): スワイプが効かないなど、不具合の元になるmarginをgapに置き換え 2025-04-27 17:29:17 +09:00
syuilo 5b5756d4eb Merge branch 'develop' of https://github.com/misskey-dev/misskey into develop 2025-04-27 17:16:54 +09:00
syuilo e24a2362fd refactor(frontend): PageWithHeaderにMkSwiperを持たせるように 2025-04-27 17:16:51 +09:00
github-actions[bot] 2e03c0f425 Bump version to 2025.4.1-beta.1 2025-04-27 05:59:23 +00:00
syuilo 66187174d4 🎨 2025-04-27 13:41:41 +09:00
syuilo 73b86d9276 enhance(frontend): improve new emojis manager 2025-04-27 13:31:07 +09:00
zyoshoka d91a4e3dec fix(ci): change Chromatic build to be triggered when frontend package.json is edited instead of lockfile (#15793)
* fix(ci): correct invalid condition for skipping Chromatic build

* fix: change to be triggered when frontend `package.json` is edited instead of lockfile

* chore: disable automatic rebase of frontend Renovate PRs
2025-04-27 10:49:23 +09:00
かっこかり 6a69e4180b fix(frontend): PageWithHeaderからPageHeaderに全Propsが伝わっていなかった問題を修正 (#15858) 2025-04-27 10:46:55 +09:00
syuilo 3b3bb36c49 enhance(frontend): 通知ページをスワイプで切り替えられるように 2025-04-27 10:14:41 +09:00
syuilo 69cfd34545 Update CHANGELOG.md 2025-04-27 10:01:44 +09:00
syuilo 9481b5a6e8 feat: アップロード可能な最大ファイルサイズをロールごとに設定可能に 2025-04-27 09:35:44 +09:00
github-actions[bot] effc84b9cc Bump version to 2025.4.1-beta.0 2025-04-27 00:22:13 +00:00
なっかあ de073d6d69 Fix #15876 絵文字がアニメーションしない問題を修正 (#15881) 2025-04-27 09:16:41 +09:00
syuilo 5042a0aa8f fix(frontend): タイムラインでノートが重複して表示されることがあるのを修正
Fix #15870
Close #15874
2025-04-27 09:16:17 +09:00
饺子w (Yumechi) 7a41cfe28b enhance(backend): DB note (userId) インデクス -> (userId, id) 複合インデクスにする (#15879)
* enhance(backend): use composite index for ordering notes by user

Signed-off-by: eternal-flame-AD <yume@yumechi.jp>

* fixup! enhance(backend): use composite index for ordering notes by user

---------

Signed-off-by: eternal-flame-AD <yume@yumechi.jp>
2025-04-23 14:29:42 +09:00
renovate[bot] 0a604285a0 fix(deps): update dependency fastify to v5.3.2 [security] (#15866)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-19 21:07:10 +09:00
syuilo c99723b59e fix html 2025-04-19 21:01:51 +09:00
syuilo 96bb36f77e 🎨 2025-04-19 14:42:54 +09:00
syuilo 388ef3de08 🎨 2025-04-19 14:42:09 +09:00
syuilo ff85eff209 🎨 2025-04-19 14:32:19 +09:00
github-actions[bot] a0b9f456e7 Bump version to 2025.4.1-alpha.2 2025-04-19 05:10:26 +00:00
syuilo 7b38806413 feat: Job queue inspector (#15856)
* wip

* wip

* Update job-queue.vue

* wip

* wip

* Update job-queue.vue

* wip

* Update job-queue.vue

* wip

* Update QueueService.ts

* Update QueueService.ts

* Update QueueService.ts

* Update job-queue.vue

* wip

* wip

* wip

* Update job-queue.vue

* wip

* Update MkTl.vue

* wip

* Update index.vue

* wip

* wip

* Update MkTl.vue

* 🎨

* jobs search

* wip

* Update job-queue.vue

* wip

* wip

* Update job-queue.vue

* Update job-queue.vue

* Update job-queue.vue

* Update job-queue.vue

* wip

* Update job-queue.job.vue

* wip

* wip

* wip

* Update MkCode.vue

* wip

* Update job-queue.job.vue

* wip

* Update job-queue.job.vue

* Update misskey-js.api.md

* Update CHANGELOG.md

* Update job-queue.job.vue
2025-04-19 14:00:38 +09:00
zyoshoka 978ab2f848 fix(storybook): implement missing stories (#15862) 2025-04-18 18:56:46 +09:00
syuilo 74d9cc4e38 🎨 2025-04-18 17:11:35 +09:00
syuilo 7a29aed17c enhance(frontend): improve usability 2025-04-17 20:25:59 +09:00
syuilo fd61ac5221 refactor(frontend): refactor styles 2025-04-17 20:23:27 +09:00
かっこかり 96de18b096 fix(deps): update vite to v6.3.1 (#15857) 2025-04-17 02:57:53 +00:00
syuilo eda2f587a3 enhance: コントロールパネルでジョブキューをクリアできるように 2025-04-16 16:47:03 +09:00
github-actions[bot] f2aeafaddb Bump version to 2025.4.1-alpha.1 2025-04-16 02:27:40 +00:00
anatawa12 5a9f54a07a Complete unicode emoji after last colon (#13384)
* chore: add types on MkAutocomplete

* feat: complete `:emoji:` to unicode emoji

* chore: do not use fuzzy match for emojiComplete

* docs(changelog): Unicode絵文字をslugから入力する際に`🆗`のように最後の`:`を入力したあとにUnicode絵文字に変換できるように

* docs(changelog): update changelog insertion position

* chore: improve indent

---------

Co-authored-by: Sayamame-beans <61457993+Sayamame-beans@users.noreply.github.com>
Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
2025-04-16 11:25:21 +09:00
anatawa12 0257d54add fix: ノートの直後のノートを表示する機能で表示が逆順になっていた問題を修正 (#15841)
* fix: 特定のノート直前のノートを表示する機能で表示が逆順になっていた問題を修正

* docs(changelog): ノートの直後のノートを表示する機能で表示が逆順になっていた問題を修正

---------

Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
2025-04-16 11:16:14 +09:00
syuilo d18bb1dda0 add todo 2025-04-16 11:06:37 +09:00
syuilo 81c24ddcc5 Update CHANGELOG.md 2025-04-16 11:00:38 +09:00
syuilo 17e7340933 enhance(frontend): テーマでページヘッダーの色を変更できるように 2025-04-16 10:59:05 +09:00
syuilo 29f475b17a 🎨 2025-04-16 10:42:25 +09:00
syuilo 6d90e09a58 enhance(frontend): タイムライン以外でもスクロール位置の保持を試みるように 2025-04-16 10:35:05 +09:00
syuilo 35d4b43c95 Merge branch 'develop' of https://github.com/misskey-dev/misskey into develop 2025-04-16 10:15:20 +09:00
syuilo ef477ce1b5 🎨 2025-04-16 10:15:18 +09:00
anatawa12 4bd23c4c8c feat: migrate antenna on account move (#15843)
* feat: migrate antenna on account move

* docs(changelog): アカウントの移行時にアンテナのフィルターのユーザが更新されない問題を修正

* refactor: move to AntennaService
2025-04-16 09:49:27 +09:00
syuilo 46a5aa9ede Merge branch 'develop' of https://github.com/misskey-dev/misskey into develop 2025-04-16 09:25:17 +09:00
syuilo 75267f87d5 refactor(frontend): アカウント情報はstore管理に 2025-04-16 09:25:13 +09:00
anatawa12 c5f1ce60fa fix(sw): type error in sw (#15844) 2025-04-16 07:51:41 +09:00
anatawa12 86774ad753 fix: improve flaky federation test (#15845) 2025-04-16 07:51:21 +09:00
syuilo de19d9a4d4 refactor(frontend): MkHorizontalSwipe -> MkSwiper 2025-04-15 20:48:25 +09:00
syuilo 165830d6c8 コミット忘れ 2025-04-15 20:34:00 +09:00
syuilo ee29f31324 fix(frontend): make keep scroll pos of timeline 2025-04-15 20:33:04 +09:00
github-actions[bot] f5a89c2533 Bump version to 2025.4.1-alpha.0 2025-04-15 09:32:12 +00:00
syuilo 45d65ffbba New Crowdin updates (#15786)
* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Korean)

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

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Italian)

* New translations ja-jp.yml (Italian)

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (Spanish)

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

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

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (Italian)

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (German)

* New translations ja-jp.yml (Italian)

* 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)
2025-04-15 18:29:22 +09:00
syuilo fc6037af46 enhance(backend): push notification for chat message
Resolve #15831
2025-04-15 18:27:45 +09:00
Kisaragi fff2783c1b docs: バックアップとログアウトの設定クリアについて書き方を変える (#15808)
1. 「新しいクライアントからログインしたとき」がすでにログインしたことのあるクライアントだとバックアップが必要ないと読めるので「新しい」を外す
2. ログアウトしてから設定データをブラウザから削除したあとで復元できるのはバックアップをとっているときのみであることを強調

cc 1312fe34c1
2025-04-15 16:15:56 +09:00
anatawa12 b2e3e65896 fix: use ftt for outbox (#15819)
* fix: use ftt for outbox

* chore: check for enableFanoutTimeline

* lint: fix lint
2025-04-15 16:15:27 +09:00
anatawa12 f454e820bd feat: render quote note with quote-inline class for ap compatibility (#15818) 2025-04-15 16:14:52 +09:00
anatawa12 d5fe6e36ae fix: avatarId が null のときにも avatarUrl が non null 担ってることがある問題 (#15833) 2025-04-15 16:10:17 +09:00
anatawa12 6bd45a27b1 fix: フォルダを開いた状態でメニューからアップロードしてもルートフォルダにアップロードされる問題 (#15836)
* fix: フォルダを開いた状態でメニューからアップロードしてもルートフォルダにアップロードされる問題

* docs(changelog): Fix: フォルダを開いた状態でメニューからアップロードしてもルートフォルダにアップロードされる問題を修正 #15836
2025-04-15 16:09:04 +09:00
syuilo 525b6a7677 feat(frontend): chat widget 2025-04-15 15:37:29 +09:00
syuilo 7c0806f208 feat(frontend): chat column
Resolve #15830
2025-04-15 15:36:53 +09:00
おさむのひと 0d4feed6d3 enhance(backend): フォローしているユーザーならフォロワー限定投稿のノートでもアンテナで検知できるように (#15264)
* フォローしているユーザーなら鍵ノートでもアンテナにひっかかるように

Co-authored-by: kozakura913 <98575220+kozakura913@users.noreply.github.com>
Co-authored-by: mai <74494945+chan-mai@users.noreply.github.com>

* Eliminate build errors by resolving conflicts

* 低コストな判定文を前にもってきて重い判定文に入る可能性を少しでも下げる

* fix CHANGELOG.md

* fix CHANGELOG.md

* fix diff

* removed comment

* fix CHANGELOG.md

---------

Co-authored-by: kozakura913 <98575220+kozakura913@users.noreply.github.com>
Co-authored-by: mai <74494945+chan-mai@users.noreply.github.com>
Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
2025-04-13 20:48:18 +09:00
おさむのひと 1f0621b085 レプリケーション設定時におけるinsertOne()の挙動を調整 (#15109)
* returningを含むクエリをmasterで動かす

* wip

* wip

* fix CHANGELOG.md

* 調整

* fix

* fix import
2025-04-13 20:44:44 +09:00
anatawa12 4c473eb76d fix: resolve with non-lowercased acct is broken (#15813)
* fix: resolve with non-lowercased acct is broken

* docs(changelog): Fix: 大文字を含むユーザの URL で紹介された場合に 404 エラーを返す問題
2025-04-13 18:34:33 +09:00
かっこかり f7195d54d0 fix(frontend): 自動バックアップが設定されていない環境では設定が消滅する旨の警告を出すように (#15802)
* fix(frontend): 自動バックアップが設定されていない環境ではローカルの設定を削除しないように

* Update Changelog

* fix lint

* fix: 警告を出すだけのみにする

* fix

* apply suggestion
2025-04-13 16:59:01 +09:00
かっこかり 8edf1bc208 fix(backend): サーバー名の変更をシステムアカウントの名前に反映するように (#15806)
* fix(backend): サーバー名の変更をシステムアカウントの名前に反映するように

* Update Changelog
2025-04-13 16:21:18 +09:00
かっこかり dd5dd6184a fix(frontend): keyval-storeの値が削除できずに処理が止まる問題を修正 (#15803)
* fix(frontend): keyval-storeの値が削除できずに処理が止まる問題を修正

* Update Changelog

* implement abortcontroller

* fix lint
2025-04-13 15:48:43 +09:00
renovate[bot] 81bf139e3e fix(deps): update dependency @nestjs/common to v11.0.16 [security] (#15800)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-12 16:04:20 +09:00
renovate[bot] a0e9895764 fix(deps): update [backend] update dependencies (#15690)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-10 19:50:25 +09:00
かっこかり 413324a278 refactor(frontend): frontendの検索インデックス作成のスタンドアロンコマンド実装を完全に削除 (#15790)
This reverts commit e594fb0037.
2025-04-10 18:48:40 +09:00
renovate[bot] e2b68aabae fix(deps): update [frontend] update dependencies (#15736)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-10 18:26:01 +09:00
github-actions[bot] 0aaeb6d136 [skip ci] Update CHANGELOG.md (prepend template) 2025-04-09 02:17:33 +00:00
github-actions[bot] fb277501a0 Release: 2025.4.0 2025-04-09 02:17:29 +00:00
syuilo 718138509f Update CHANGELOG.md 2025-04-09 10:56:57 +09:00
github-actions[bot] a1ef38a606 Bump version to 2025.4.0-rc.5 2025-04-08 23:21:42 +00:00
zyoshoka 4a8b7ef23e fix(ci): correct condition for skipping Chromatic build (#15783) 2025-04-09 08:10:17 +09:00
anatawa12 1f17161dfb feat: show file name for warning / errors of [create-search-index] (#15785) 2025-04-09 08:10:04 +09:00
syuilo 2488708934 New Crowdin updates (#15781)
* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (German)

* New translations ja-jp.yml (Italian)

* 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 (German)

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

* New translations ja-jp.yml (English)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (Korean)
2025-04-09 08:09:43 +09:00
anatawa12 628a0c71a9 fix: direct does not work in nested route (#15784) 2025-04-09 08:09:08 +09:00
syuilo b40f5b9021 fix typo 2025-04-09 08:08:28 +09:00
syuilo 0f79db6a4d refactor 2025-04-09 08:05:27 +09:00
syuilo 910e097480 add missing SearchMarker 2025-04-09 08:04:00 +09:00
syuilo a8acbd6e68 refactor 2025-04-09 08:01:10 +09:00
syuilo c19f51a2ab resolve promise
https://github.com/misskey-dev/misskey/pull/15735#discussion_r2033387035
2025-04-09 07:56:20 +09:00
syuilo 1cf370882e add missing SearchMarker 2025-04-09 07:51:24 +09:00
syuilo 58cb7cf179 update i18n 2025-04-08 20:58:56 +09:00
syuilo a51192bac5 Merge branch 'develop' of https://github.com/misskey-dev/misskey into develop 2025-04-08 20:50:41 +09:00
syuilo c500e4392a hideNotesInSensitiveChannel -> excludeNotesInSensitiveChannel 2025-04-08 20:50:38 +09:00
syuilo 799226412f Update CHANGELOG.md
Co-authored-by: anatawa12 <anatawa12@icloud.com>
2025-04-08 20:44:15 +09:00
syuilo 0d18c0169f New Crowdin updates (#15776)
* New translations ja-jp.yml (German)

* New translations ja-jp.yml (English)

* New translations ja-jp.yml (Korean)

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

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (Korean)
2025-04-08 18:18:02 +09:00
syuilo 863fb5dd7f Update CHANGELOG.md 2025-04-08 15:20:36 +09:00
syuilo 177943b06a Update CHANGELOG.md 2025-04-08 15:19:33 +09:00
syuilo 2aa7630466 🎨 2025-04-08 15:10:51 +09:00
syuilo c96f345f01 fix(frontend): fix control panel style 2025-04-08 10:56:52 +09:00
syuilo baf04a1e25 fix(frontend): Fix #15764 2025-04-08 10:38:04 +09:00
syuilo 40097d4aac clean up 2025-04-08 10:37:44 +09:00
github-actions[bot] 01cd398799 Bump version to 2025.4.0-rc.4 2025-04-07 23:44:45 +00:00
syuilo 3d206d2a0f enhance(frontend): 設定検索時に対象が含まれるMkFolderを自動で開いておくように 2025-04-08 08:43:56 +09:00
syuilo e8758bf77d Merge branch 'develop' of https://github.com/misskey-dev/misskey into develop 2025-04-08 08:31:54 +09:00
syuilo 278629046a 🎨 2025-04-08 08:31:52 +09:00
syuilo 3374a587a1 refactor 2025-04-08 08:28:17 +09:00
syuilo ce721a8066 New Crowdin updates (#15773)
* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (German)

* New translations ja-jp.yml (Italian)

* 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 (Korean)

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

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Chinese Simplified)
2025-04-08 08:19:44 +09:00
syuilo 547d6361b7 Merge branch 'develop' of https://github.com/misskey-dev/misskey into develop 2025-04-08 08:18:51 +09:00
syuilo f765b374c7 refactor 2025-04-08 08:18:48 +09:00
346 changed files with 10972 additions and 7294 deletions
+1 -1
View File
@@ -8,7 +8,7 @@
"version": "22.11.0"
},
"ghcr.io/devcontainers-extra/features/pnpm:2": {
"version": "10.6.1"
"version": "10.10.0"
}
},
"forwardPorts": [3000],
+1 -1
View File
@@ -22,7 +22,7 @@ jobs:
uses: pnpm/action-setup@v4.1.0
- name: Setup Node.js
uses: actions/setup-node@v4.3.0
uses: actions/setup-node@v4.4.0
with:
node-version-file: '.node-version'
cache: 'pnpm'
+1 -1
View File
@@ -14,7 +14,7 @@ jobs:
- name: Checkout head
uses: actions/checkout@v4.2.2
- name: Setup Node.js
uses: actions/setup-node@v4.3.0
uses: actions/setup-node@v4.4.0
with:
node-version-file: '.node-version'
@@ -29,7 +29,7 @@ jobs:
- name: setup node
id: setup-node
uses: actions/setup-node@v4.3.0
uses: actions/setup-node@v4.4.0
with:
node-version-file: '.node-version'
cache: pnpm
+1 -1
View File
@@ -33,7 +33,7 @@ jobs:
- name: Setup pnpm
uses: pnpm/action-setup@v4.1.0
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4.3.0
uses: actions/setup-node@v4.4.0
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
+3 -3
View File
@@ -38,7 +38,7 @@ jobs:
submodules: true
- name: Setup pnpm
uses: pnpm/action-setup@v4.1.0
- uses: actions/setup-node@v4.3.0
- uses: actions/setup-node@v4.4.0
with:
node-version-file: '.node-version'
cache: 'pnpm'
@@ -69,7 +69,7 @@ jobs:
submodules: true
- name: Setup pnpm
uses: pnpm/action-setup@v4.1.0
- uses: actions/setup-node@v4.3.0
- uses: actions/setup-node@v4.4.0
with:
node-version-file: '.node-version'
cache: 'pnpm'
@@ -99,7 +99,7 @@ jobs:
submodules: true
- name: Setup pnpm
uses: pnpm/action-setup@v4.1.0
- uses: actions/setup-node@v4.3.0
- uses: actions/setup-node@v4.4.0
with:
node-version-file: '.node-version'
cache: 'pnpm'
+1 -1
View File
@@ -20,7 +20,7 @@ jobs:
submodules: true
- name: Setup pnpm
uses: pnpm/action-setup@v4.1.0
- uses: actions/setup-node@v4.3.0
- uses: actions/setup-node@v4.4.0
with:
node-version-file: '.node-version'
cache: 'pnpm'
+1 -1
View File
@@ -26,7 +26,7 @@ jobs:
- name: Setup pnpm
uses: pnpm/action-setup@v4.1.0
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4.3.0
uses: actions/setup-node@v4.4.0
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
+7 -19
View File
@@ -15,11 +15,7 @@ on:
jobs:
build:
# Chromatic is not likely to be available for fork repositories, so we disable for fork repositories.
# Neither Dependabot nor Renovate will change the actual behavior for components.
if: >-
github.repository == 'misskey-dev/misskey' &&
startsWith(github.ref, 'refs/heads/dependabot/') != true &&
startsWith(github.ref, 'refs/heads/renovate/') != true
if: github.repository == 'misskey-dev/misskey'
runs-on: ubuntu-latest
env:
@@ -39,14 +35,11 @@ jobs:
ref: "refs/pull/${{ github.event.number }}/merge"
- name: Checkout actual HEAD
if: github.event_name == 'pull_request_target'
id: rev
run: |
echo "base=$(git rev-list --parents -n1 HEAD | cut -d" " -f2)" >> $GITHUB_OUTPUT
git checkout $(git rev-list --parents -n1 HEAD | cut -d" " -f3)
run: git checkout "$(git rev-list --parents -n1 HEAD | cut -d" " -f3)"
- name: Setup pnpm
uses: pnpm/action-setup@v4.1.0
- name: Use Node.js 20.x
uses: actions/setup-node@v4.3.0
uses: actions/setup-node@v4.4.0
with:
node-version-file: '.node-version'
cache: 'pnpm'
@@ -85,21 +78,16 @@ jobs:
if: github.event_name == 'pull_request_target'
id: chromatic_pull_request
run: |
DIFF="${{ steps.rev.outputs.base }} HEAD"
if [ "$DIFF" = "0000000000000000000000000000000000000000 HEAD" ]; then
DIFF="HEAD"
fi
CHROMATIC_PARAMETER="$(node packages/frontend/.storybook/changes.js $(git diff-tree --no-commit-id --name-only -r $(echo "$DIFF") | xargs))"
CHROMATIC_PARAMETER="$(node packages/frontend/.storybook/changes.js $(git diff-tree --no-commit-id --name-only -r origin/${GITHUB_BASE_REF}...origin/${GITHUB_HEAD_REF} | xargs))"
if [ "$CHROMATIC_PARAMETER" = " --skip" ]; then
echo "skip=true" >> $GITHUB_OUTPUT
fi
BRANCH="${{ github.event.pull_request.head.user.login }}:$HEAD_REF"
if [ "$BRANCH" = "misskey-dev:$HEAD_REF" ]; then
BRANCH="$HEAD_REF"
BRANCH="${{ github.event.pull_request.head.user.login }}:$GITHUB_HEAD_REF"
if [ "$BRANCH" = "misskey-dev:$GITHUB_HEAD_REF" ]; then
BRANCH="$GITHUB_HEAD_REF"
fi
pnpm --filter frontend chromatic --exit-once-uploaded -d storybook-static --branch-name "$BRANCH" $(echo "$CHROMATIC_PARAMETER")
env:
HEAD_REF: ${{ github.event.pull_request.head.ref }}
CHROMATIC_PROJECT_TOKEN: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
- name: Notify that Chromatic detects changes
uses: actions/github-script@v7.0.1
+2 -2
View File
@@ -62,7 +62,7 @@ jobs:
fi
done
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4.3.0
uses: actions/setup-node@v4.4.0
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
@@ -109,7 +109,7 @@ jobs:
- name: Setup pnpm
uses: pnpm/action-setup@v4.1.0
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4.3.0
uses: actions/setup-node@v4.4.0
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
+1 -1
View File
@@ -44,7 +44,7 @@ jobs:
fi
done
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4.3.0
uses: actions/setup-node@v4.4.0
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
+2 -2
View File
@@ -38,7 +38,7 @@ jobs:
- name: Setup pnpm
uses: pnpm/action-setup@v4.1.0
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4.3.0
uses: actions/setup-node@v4.4.0
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
@@ -93,7 +93,7 @@ jobs:
- name: Setup pnpm
uses: pnpm/action-setup@v4.1.0
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4.3.0
uses: actions/setup-node@v4.4.0
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
+1 -1
View File
@@ -33,7 +33,7 @@ jobs:
uses: pnpm/action-setup@v4.1.0
- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4.3.0
uses: actions/setup-node@v4.4.0
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
+1 -1
View File
@@ -26,7 +26,7 @@ jobs:
- name: Setup pnpm
uses: pnpm/action-setup@v4.1.0
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4.3.0
uses: actions/setup-node@v4.4.0
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
+1 -1
View File
@@ -27,7 +27,7 @@ jobs:
- name: Setup pnpm
uses: pnpm/action-setup@v4.1.0
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4.3.0
uses: actions/setup-node@v4.4.0
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
+44 -5
View File
@@ -1,7 +1,43 @@
## 2025.4.1
### General
- Feat: bull-boardに代わるジョブキューの管理ツールが実装されました
- Feat: アップロード可能な最大ファイルサイズをロールごとに設定可能に
- デフォルトで10MBになっています
- Enhance: チャットの新規メッセージをプッシュ通知するように
- Enhance: サーバーブロックの対象になっているサーバーについて、当該サーバーのユーザーや既知投稿を見えないように
- Enhance: 依存関係の更新
- Enhance: 翻訳の更新
### Client
- Feat: チャットウィジェットを追加
- Feat: デッキにチャットカラムを追加
- Enhance: Unicode絵文字をslugから入力する際に`:ok:`のように最後の`:`を入力したあとにUnicode絵文字に変換できるように
- Enhance: コントロールパネルでジョブキューをクリアできるように
- Enhance: テーマでページヘッダーの色を変更できるように
- Enhance: スワイプでのタブ切り替えを強化
- Enhance: デザインのブラッシュアップ
- Fix: ログアウトした際に処理が終了しない問題を修正
- Fix: 自動バックアップが設定されている環境でログアウト直前に設定をバックアップするように
- Fix: フォルダを開いた状態でメニューからアップロードしてもルートフォルダにアップロードされる問題を修正 #15836
- Fix: タイムラインのスクロール位置を記憶するように修正
- Fix: ノートの直後のノートを表示する機能で表示が逆順になっていた問題を修正 #15841
- Fix: アカウントの移行時にアンテナのフィルターのユーザが更新されない問題を修正 #15843
- Fix: タイムラインでノートが重複して表示されることがあるのを修正
### Server
- Enhance: ジョブキューの成功/失敗したジョブも一定数・一定期間保存するようにし、後から問題を調査することを容易に
- Enhance: フォローしているユーザーならフォロワー限定投稿のノートでもアンテナで検知できるように
(Cherry-picked from https://github.com/yojo-art/cherrypick/pull/568 and https://github.com/team-shahu/misskey/pull/38)
- Enhance: ユーザーごとにノートの表示が高速化するように
- Fix: システムアカウントの名前がサーバー名と同期されない問題を修正
- Fix: 大文字を含むユーザの URL で紹介された場合に 404 エラーを返す問題 #15813
- Fix: リードレプリカ設定時にレコードの追加・更新・削除を伴うクエリを発行した際はmasterノードで実行されるように調整( #10897 )
## 2025.4.0
### General
- Feat: チャットがリニューアルして復活しました(beta)
- Feat: チャット(ダイレクトメッセージ)がリニューアルして復活しました
- 既存のDM機能よりも便利で効率的な実装になっています
- チャットを受け付ける相手を制限可能です
- 誰でも / フォローユーザーのみ / フォロワーのみ / 相互のみ / 受け付けない から選択できます
@@ -11,7 +47,8 @@
- 過去自分が送ったメッセージ・自分に送られたメッセージの検索が可能です
- 参加中のルームをミュートして通知が来ないように設定可能です
- メッセージにはリアクションも可能です
- Feat: アカウントのマイグレーション時に古いアカウントからロールをコピーできるようになりました。
- 現在、リモートユーザーがチャットを受け付ける設定になっているかどうかを取得する術がないため、ローカルユーザー間でのみ利用可能です
- Feat: アカウントの移行時に古いアカウントからあたらしいアカウントにロールをコピーできるようになりました。
- 管理者がロールの設定でマイグレーション時にコピーするかを指定できるようになります。
- Enhance: セキュリティを強化するため、ジョブキューのダッシュボード(bull-board)統合が削除されました。
- Misskeyネイティブでダッシュボードを実装予定です
@@ -29,7 +66,7 @@
- プラグイン、テーマ、クライアントに追加されたすべてのアカウント情報も含まれるようになりました
- 自動で設定データをサーバーにバックアップできるように
- 設定→設定のプロファイル→自動バックアップ で有効にできます
- 新しいデバイスからログインした、ブラウザから設定データが消えてしまったときに自動で復元されます(復元をスキップすることも可能)
- ログインしたとき、ブラウザから設定データが消えてしまったときに自動で復元されます(復元をスキップすることも可能)
- 任意の設定項目をデバイス間で同期できるように
- 設定項目の「...」メニュー→「デバイス間で同期」
- 同期をオンにした際にサーバーに保存された値とローカルの値が競合する場合はどちらを優先するか選択できます
@@ -38,7 +75,7 @@
- アカウントごとに設定値が分離される設定とそうでないクライアント設定が混在していた(かつ分離するかどうかを設定不可だった)のを、基本的に一律でクライアント全体に適用されるようにし、個別でアカウントごとに異なる設定を行えるように
- 設定項目の「...」メニュー→「アカウントで上書き」をオンにすることで、設定値をそのアカウントでだけ適用するようにできます
- ログアウトすると設定データもブラウザから消去されるようになりプライバシーが向上しました
- 再度ログインすればサーバーのバックアップから設定データを復元可能です
- バックアップを有効にしている場合、ログインした後にバックアップから設定データを復元可能です
- エクスポートした設定データを他のサーバーでインポートして適用すること(設定の持ち運び)が可能になりました
- 設定情報の移行は自動で行われますが、何らかの理由で失敗した場合、設定→その他→旧設定情報を移行 で再試行可能です
- 過去に作成されたバックアップデータとは現在互換性がありませんのでご注意ください
@@ -60,11 +97,13 @@
- Enhance: 2段階認証時のリカバリーコードのファイル名にサーバーURLを含めるように
- Enhance: 全体的なブラッシュアップ
- Enhance 全体的なパフォーマンス向上
- Enhance: ファイルのアップロードでデフォルトで圧縮するかどうかのオプションが廃止され、アップロード時に圧縮するかどうかを選択するようになりました
- 画像データの貼り付け、ドロップ時は圧縮されるようになりました
- Fix: 読み込み直後にスクロールしようとすると途中で止まる場合があるのを修正
- Fix: テーマ切り替え時に一部の色が変わらない問題を修正
- Fix: iPadOSでdeck uiをマウスカーソルによってスクロールできない問題を修正
- NOTE: 構造上クラシックUIを新しいデザインシステムに移行することが困難なため、クラシックUIが削除されました
- デッキUIでカラムを中央寄せにし、メインカラムの左右にウィジェットカラムを配置し、ナビゲーションバーを上部に表示することである程度クラシックUIを再現できます
- Fix: iPadOSでdeck uiをマウスカーソルによってスクロールできない問題を修正
### Server
- Enhance 全体的なパフォーマンス向上
+33 -25
View File
@@ -280,7 +280,7 @@ featured: "Destacat"
usernameOrUserId: "Nom o ID d'usuari"
noSuchUser: "No s'ha trobat l'usuari"
lookup: "Cerca"
announcements: "Anuncis"
announcements: "Avisos"
imageUrl: "URL de la imatge"
remove: "Eliminar"
removed: "Eliminat"
@@ -356,7 +356,7 @@ banner: "Bàner"
displayOfSensitiveMedia: "Visualització de contingut sensible"
whenServerDisconnected: "Quan es perdi la connexió al servidor"
disconnectedFromServer: "Desconnectat pel servidor"
reload: "Actualitza"
reload: "Actualitzar"
doNothing: "Ignora"
reloadConfirm: "Vols recarregar?"
watch: "Veure"
@@ -424,7 +424,7 @@ antennaExcludeBots: "Exclou els bots"
antennaKeywordsDescription: "Separar amb espais per la condició AND o amb salts de línia per la condició OR."
notifyAntenna: "Notifica'm les publicacions noves"
withFileAntenna: "Només les publicacions amb fitxers"
hideNotesInSensitiveChannel: "Amaga les notes a canals sensibles "
excludeNotesInSensitiveChannel: "Excloure notes a canals sensibles"
enableServiceworker: "Activar les notificacions al navegador"
antennaUsersDescription: "Llistar un nom d'usuari per línia"
caseSensitive: "Sensible a majúscules i minúscules "
@@ -537,7 +537,7 @@ mediaListWithOneImageAppearance: "Altura de la llista de fitxers amb una única
limitTo: "Limita a {x}"
noFollowRequests: "No tens sol·licituds de seguiment"
openImageInNewTab: "Obre imatges a una nova pestanya"
dashboard: "Taulell de control"
dashboard: "Tauler de control"
local: "Local"
remote: "Remot"
total: "Total"
@@ -652,7 +652,7 @@ manage: "Administració"
plugins: "Extensions"
preferencesBackups: "Configuracions de les Còpies de seguretat"
deck: "Escriptori"
undeck: "Tanca l'escriptori"
undeck: "Tanca el tauler"
useBlurEffectForModal: "Utilitzar l'efecte de difuminació a modals"
useFullReactionPicker: "Utilitza el cercador de reaccions d'escala sencera"
width: "Amplada"
@@ -708,7 +708,7 @@ notificationSetting: "Paràmetres de notificacions"
notificationSettingDesc: "Selecciona els tipus de notificacions que es mostraran"
useGlobalSetting: "Fer servir la configuració global"
useGlobalSettingDesc: "Si s'activa, es farà servir la configuració de notificacions del teu comte. Si no s'activa es poden fer configuracions individuals."
other: "Altre"
other: "Altres"
regenerateLoginToken: "Regenerar clau de seguretat d'inici de sessió"
regenerateLoginTokenDescription: "Regenera la clau de seguretat que es fa servir internament durant l'inici de sessió. Normalment aquesta acció no és necessària. Si es regenera es tancarà la sessió a tots els dispositius amb una sessió activa."
theKeywordWhenSearchingForCustomEmoji: "Cercar un emoji personalitzat "
@@ -871,7 +871,7 @@ gallery: "Galeria"
recentPosts: "Articles recents"
popularPosts: "Articles populars"
shareWithNote: "Comparteix amb una nota"
ads: "Anuncis"
ads: "Publicitat "
expiration: ""
startingperiod: "Inici"
memo: "Recordatori"
@@ -915,7 +915,7 @@ off: "Desactivar"
emailRequiredForSignup: "Demanar correu electrònic per registrar-se "
unread: "Sense llegir"
filter: "Filtrar"
controlPanel: "Taulell de control"
controlPanel: "Tauler de control"
manageAccounts: "Gestionar comptes"
makeReactionsPublic: "Reaccions públiques "
makeReactionsPublicDescription: "Això fa que totes les teves reaccions siguin visibles públicament "
@@ -979,6 +979,7 @@ document: "Documentació"
numberOfPageCache: "Nombre de pàgines a la memòria cau"
numberOfPageCacheDescription: "Incrementant aquest nombre farà que millori l'experiència de l'usuari, però es farà servir més memòria al dispositiu de l'usuari."
logoutConfirm: "Vols sortir?"
logoutWillClearClientData: "En tancar la sessió, la informació del client al navegador s'esborrarà. Per garantir que la informació de configuració es pugui restaurar en tornar a iniciar sessió activa la còpia de seguretat automàtica de la configuració."
lastActiveDate: "Fet servir per última vegada"
statusbar: "Barra d'estat"
pleaseSelect: "Selecciona una opció"
@@ -1109,7 +1110,7 @@ accountMigration: "Migració del compte"
accountMoved: "Aquest usuari té un compte nou:"
accountMovedShort: "Aquest compte ha sigut migrat"
operationForbidden: "Operació no permesa "
forceShowAds: "Mostra els anuncis sempre "
forceShowAds: "Mostrar publicitat sempre "
addMemo: "Afegir recordatori"
editMemo: "Editar recordatori"
reactionsList: "Reaccions"
@@ -1184,8 +1185,8 @@ iHaveReadXCarefullyAndAgree: "He llegit {x} i estic d'acord."
dialog: "Diàleg "
icon: "Icona"
forYou: "Per a tu"
currentAnnouncements: "Informes actuals"
pastAnnouncements: "Informes passats"
currentAnnouncements: "Avisos actuals"
pastAnnouncements: "Avisos passats"
youHaveUnreadAnnouncements: "Tens informes per llegir."
useSecurityKey: "Segueix les instruccions del teu navegador O dispositiu per fer servir el teu passkey."
replies: "Respostes"
@@ -1334,14 +1335,17 @@ postForm: "Formulari de publicació"
textCount: "Nombre de caràcters "
information: "Informació"
chat: "Xat"
migrateOldSettings: "Migració de la configuració antiga "
migrateOldSettings: "Migrar la configuració anterior"
migrateOldSettings_description: "Normalment això es fa automàticament, però si la transició no es fa, el procés es pot iniciar manualment. S'esborrarà la configuració actual."
compress: "Comprimir "
right: "Dreta"
bottom: "A baix "
top: "A dalt "
embed: "Incrustar"
settingsMigrating: "Estem fent la migració de la teva configuració. Si us plau espera un moment... (També pots fer la migració més tard i manualment anant a Preferències → Altres configuracions → Migrar configuració antiga)"
settingsMigrating: "Estem migrant la teva configuració. Si us plau espera un moment... (També pots fer la migració més tard, manualment, anant a Preferències → Altres → Migrar configuració antiga)"
readonly: "Només lectura"
goToDeck: "Tornar al tauler"
federationJobs: "Treballs sindicats "
_chat:
noMessagesYet: "Encara no tens missatges "
newMessage: "Missatge nou"
@@ -1357,7 +1361,7 @@ _chat:
noInvitations: "No tens cap invitació "
history: "Historial de converses "
noHistory: "No hi ha un registre previ"
noRooms: "No hi ha habitacions"
noRooms: "No hi ha cap sala"
inviteUser: "Invitar usuaris"
sentInvitations: "Enviar invitacions"
join: "Afegir-se "
@@ -1371,6 +1375,7 @@ _chat:
muteThisRoom: "Silenciar aquesta sala"
deleteRoom: "Esborrar la sala"
chatNotAvailableForThisAccountOrServer: "El xat no està disponible per aquest servidor o aquest compte."
chatIsReadOnlyForThisAccountOrServer: "El xat és només de lectura en aquest servidor o compte. No es poden escriure nous missatges ni crear o unir-se a sales de xat."
chatNotAvailableInOtherAccount: "La funció de xat es troba desactivada al compte de l'altre usuari."
cannotChatWithTheUser: "No pots xatejar amb aquest usuari"
cannotChatWithTheUser_description: "El xat està desactivat o l'altra part encara no l'ha obert."
@@ -1414,8 +1419,8 @@ _settings:
makeEveryTextElementsSelectable_description: "L'activació pot reduir la usabilitat en determinades ocasions."
useStickyIcons: "Utilitza icones fixes"
showNavbarSubButtons: "Mostrar sub botons a la barra de navegació "
ifOn: "Quan s'encén "
ifOff: "Quan s'apaga "
ifOn: "Quan s'activa"
ifOff: "Quan es desactiva"
enableSyncThemesBetweenDevices: "Sincronitzar els temes instal·lats entre dispositius"
_chat:
showSenderName: "Mostrar el nom del remitent"
@@ -1483,7 +1488,7 @@ _announcement:
needConfirmationToRead: "Es necessita confirmació de lectura de la notificació "
needConfirmationToReadDescription: "Si s'activa es mostrarà un diàleg per confirmar la lectura d'aquesta notificació. A més aquesta notificació serà exclosa de qualsevol funcionalitat com \"Marcar tot com a llegit\"."
end: "Final de la notificació "
tooManyActiveAnnouncementDescription: "Tenir massa notificacions actives pot empitjorar l'experiència de l'usuari. Considera finalitzar els anuncis que siguin antics."
tooManyActiveAnnouncementDescription: "Tenir massa notificacions actives pot empitjorar l'experiència de l'usuari. Considera finalitzar els avisos que siguin antics."
readConfirmTitle: "Marcar com llegida?"
readConfirmText: "Això marcarà el contingut de \"{title}\" com llegit."
shouldNotBeUsedToPresentPermanentInfo: "Ja que l'ús de notificacions pot impactar l'experiència dels nous usuaris, és recomanable fer servir les notificacions amb el flux d'informació en comptes de fer-les servir en un únic bloc."
@@ -1601,7 +1606,7 @@ _accountMigration:
moveTo: "Migrar aquest compte a un altre"
moveToLabel: "Compte al qual es vol migrar:"
moveCannotBeUndone: "Les migracions dels comptes no es poden desfer."
moveAccountDescription: "Això migrarà la teva compte a un altre diferent.\n ・Els seguidors d'aquest compte és passaran al compte nou de forma automàtica\n ・Es deixaran de seguir a tots els usuaris que es segueixen actualment en aquest compte\n ・No es poden crear notes noves, etc. en aquest compte\n\nSi bé la migració de seguidors es automàtica, has de preparar alguns pasos manualment per migrar la llista d'usuaris que segueixes. Per fer això has d'exportar els seguidors que després importaraes al compte nou mitjançant el menú de configuració. El mateix procediment s'ha de seguir per less teves llistes i els teus usuaris silenciats i bloquejats.\n\n(Aquesta explicació s'aplica a Misskey v13.12.0 i posteriors. Altres aplicacions, com Mastodon, poden funcionar diferent.)"
moveAccountDescription: "Això migrarà el teu compte a un altre diferent.\n ・Els seguidors d'aquest compte és passaran al compte nou de forma automàtica\n ・Es deixaran de seguir a tots els usuaris que es segueixen actualment en aquest compte\n ・No es poden crear notes noves, etc. en aquest compte\n\nSi bé la migració de seguidors es automàtica, has de preparar alguns pasos manualment per migrar la llista d'usuaris que segueixes. Per fer això has d'exportar els seguidors que després importaraes al compte nou mitjançant el menú de configuració. El mateix procediment s'ha de seguir per less teves llistes i els teus usuaris silenciats i bloquejats.\n\n(Aquesta explicació s'aplica a Misskey v13.12.0 i posteriors. Altres aplicacions, com Mastodon, poden funcionar diferent.)"
moveAccountHowTo: "Per fer la migració, primer has de crear un àlies per aquest compte al compte al qual vols migrar.\nDesprés de crear l'àlies, introdueix el compte al qual vols migrar amb el format següent: @nomusuari@servidor.exemple.com"
startMigration: "Migrar"
migrationConfirm: "Vols migrar aquest compte a {account}? Una vegada comenci la migració no es podrà parar O fer marxa enrere i no podràs tornar a fer servir aquest compte mai més."
@@ -1910,6 +1915,7 @@ _role:
canManageCustomEmojis: "Gestiona els emojis personalitzats"
canManageAvatarDecorations: "Gestiona les decoracions dels avatars "
driveCapacity: "Capacitat del disc"
maxFileSize: "Mida màxima de l'arxiu que es pot carregar"
alwaysMarkNsfw: "Marca sempre els fitxers com a sensibles"
canUpdateBioMedia: "Permet l'edició d'una icona o un bàner"
pinMax: "Nombre màxim de notes fixades"
@@ -1922,7 +1928,7 @@ _role:
userEachUserListsMax: "Nombre màxim d'usuaris dintre d'una llista d'usuaris "
rateLimitFactor: "Limitador"
descriptionOfRateLimitFactor: "Límits baixos són menys restrictius, límits alts són més restrictius."
canHideAds: "Pot amagar els anuncis"
canHideAds: "Pot amagar la publicitat"
canSearchNotes: "Pot cercar notes"
canUseTranslator: "Pot fer servir el traductor"
avatarDecorationLimit: "Nombre màxim de decoracions que es poden aplicar els avatars"
@@ -1931,7 +1937,7 @@ _role:
canImportFollowing: "Autoritza la importació de seguidors"
canImportMuting: "Autoritza la importació de silenciats"
canImportUserLists: "Autoritza la importació de llistes d'usuaris "
canChat: "Pot xatejar"
chatAvailability: "Es permet xatejar"
_condition:
roleAssignedTo: "Assignat a rols manuals"
isLocal: "Usuari local"
@@ -1987,8 +1993,8 @@ _ad:
reduceFrequencyOfThisAd: "Mostrar menys aquest anunci"
hide: "No mostrar mai"
timezoneinfo: "El dia de la setmana ve determinat del fus horari del servidor."
adsSettings: "Configuració d'anuncis "
notesPerOneAd: "Interval d'emplaçament d'anuncis en temps real (Notes per anuncis)"
adsSettings: "Configurar la publicitat"
notesPerOneAd: "Interval d'emplaçament publicitari en temps real (Notes per anuncis)"
setZeroToDisable: "Ajusta aquest valor a 0 per deshabilitar l'actualització d'anuncis en temps real"
adsTooClose: "L'interval actual pot fer que l'experiència de l'usuari sigui dolenta perquè l'interval és molt baix."
_forgotPassword:
@@ -2123,7 +2129,7 @@ _theme:
fg: "Text"
focus: "Enfocament"
indicator: "Indicador"
panel: "Taulell "
panel: "Tauler"
shadow: "Ombra"
header: "Capçalera"
navBg: "Fons de la barra lateral"
@@ -2365,6 +2371,7 @@ _widgets:
chooseList: "Tria una llista"
clicker: "Clicker"
birthdayFollowings: "Usuaris que fan l'aniversari avui"
chat: "Xat"
_cw:
hide: "Amagar"
show: "Carregar més"
@@ -2601,7 +2608,7 @@ _deck:
columnGap: "Espai entre columnes"
deckMenuPosition: "Posició del menú del tauler"
navbarPosition: "Posició de la barra de navegació "
addColumn: "Afig una columna"
addColumn: "Afegeix una columna"
newNoteNotificationSettings: "Configuració de notificacions per a notes noves"
configureColumn: "Configuració de columnes"
swapLeft: "Mou a lesquerra"
@@ -2631,6 +2638,7 @@ _deck:
mentions: "Mencions"
direct: "Publicacions directes"
roleTimeline: "Línia de temps dels rols"
chat: "Xat"
_dialog:
charactersExceeded: "Has arribat al màxim de caràcters! Actualment és {current} de {max}"
charactersBelow: "Ets per sota del mínim de caràcters! Actualment és {current} de {min}"
@@ -2796,7 +2804,7 @@ _hemisphere:
_reversi:
reversi: "Reversi"
gameSettings: "Opcions del joc"
chooseBoard: "Escull un taulell"
chooseBoard: "Escull un tauler"
blackOrWhite: "Negres/Blanques"
blackIs: "{name} juga amb negres "
rules: "Regles"
+11 -2
View File
@@ -424,7 +424,7 @@ antennaExcludeBots: "Bot-Accounts ausschließen"
antennaKeywordsDescription: "Zum Nutzen einer \"UND\"-Verknüpfung Einträge mit Leerzeichen trennen, zum Nutzen einer \"ODER\"-Verknüpfung Einträge mit einem Zeilenumbruch trennen"
notifyAntenna: "Über neue Notizen benachrichtigen"
withFileAntenna: "Nur Notizen mit Dateien"
hideNotesInSensitiveChannel: "Verstecke Notizen von sensitive Kanäle"
excludeNotesInSensitiveChannel: "Schließe Notizen von sensitive Kanäle aus"
enableServiceworker: "Push-Benachrichtigungen im Browser aktivieren"
antennaUsersDescription: "Benutzernamen getrennt durch Zeilenumbrüche angeben"
caseSensitive: "Groß-/Kleinschreibung unterscheiden"
@@ -979,6 +979,7 @@ document: "Dokumentation"
numberOfPageCache: "Seitencachegröße"
numberOfPageCacheDescription: "Das Erhöhen dieses Caches führt zu einer angenehmerern Benutzererfahrung, aber erhöht Last und Arbeitsspeicherauslastung auf dem Nutzergerät."
logoutConfirm: "Wirklich abmelden?"
logoutWillClearClientData: "Beim Abmelden werden die Konfigurationsdaten des Clients aus dem Browser gelöscht. Um sicherzustellen, dass die Konfigurationsdaten beim erneuten Einloggen wiederhergestellt werden können, aktivieren Sie bitte die automatische Sicherung der Konfiguration."
lastActiveDate: "Zuletzt verwendet am"
statusbar: "Statusleiste"
pleaseSelect: "Wähle eine Option"
@@ -1341,6 +1342,10 @@ right: "Rechts"
bottom: "Unten"
top: "Oben"
embed: "Einbetten"
settingsMigrating: "Ihre Einstellungen werden gerade migriert, Bitte warten Sie einen Moment... (Sie können die Einstellungen später auch manuell migrieren, indem Sie zu Einstellungen → Sonstiges → Alte Einstellungen migrieren gehen)"
readonly: "Nur Lesezugriff"
goToDeck: "Zurück zum Deck"
federationJobs: "Föderation Jobs"
_chat:
noMessagesYet: "Noch keine Nachrichten"
newMessage: "Neue Nachricht"
@@ -1370,6 +1375,7 @@ _chat:
muteThisRoom: "Raum stummschalten"
deleteRoom: "Raum löschen"
chatNotAvailableForThisAccountOrServer: "Der Chat ist auf diesem Server oder für dieses Konto nicht aktiviert."
chatIsReadOnlyForThisAccountOrServer: "Der Chat ist auf dieser Instanz oder diesem Konto nur zum Lesen freigegeben. Es ist nicht möglich, neue Nachrichten zu schreiben oder Chaträume zu erstellen oder zu betreten."
chatNotAvailableInOtherAccount: "Die Chatfunktion wurde vom anderen Benutzer deaktiviert."
cannotChatWithTheUser: "Starten eines Chats mit diesem Benutzer nicht möglich"
cannotChatWithTheUser_description: "Der Chat ist entweder nicht verfügbar oder die andere Seite hat den Chat nicht aktiviert."
@@ -1909,6 +1915,7 @@ _role:
canManageCustomEmojis: "Benutzerdefinierte Emojis verwalten"
canManageAvatarDecorations: "Profilbilddekorationen verwalten"
driveCapacity: "Drive-Kapazität"
maxFileSize: "Maximale Dateigröße, die hochgeladen werden kann"
alwaysMarkNsfw: "Dateien immer als NSFW markieren"
canUpdateBioMedia: "Kann ein Profil- oder ein Bannerbild bearbeiten"
pinMax: "Maximale Anzahl an angehefteten Notizen"
@@ -1930,7 +1937,7 @@ _role:
canImportFollowing: "Importieren von Gefolgten zulassen"
canImportMuting: "Importieren von Stummgeschalteten zulassen"
canImportUserLists: "Importieren von Listen erlauben"
canChat: "Chatten erlauben"
chatAvailability: "Chatten erlauben"
_condition:
roleAssignedTo: "Manuellen Rollen zugewiesen"
isLocal: "Lokaler Benutzer"
@@ -2364,6 +2371,7 @@ _widgets:
chooseList: "Liste auswählen"
clicker: "Klickzähler"
birthdayFollowings: "Nutzer, die heute Geburtstag haben"
chat: "Chat"
_cw:
hide: "Inhalt verbergen"
show: "Inhalt anzeigen"
@@ -2630,6 +2638,7 @@ _deck:
mentions: "Erwähnungen"
direct: "Direktnachrichten"
roleTimeline: "Rollenchronik"
chat: "Chat"
_dialog:
charactersExceeded: "Maximallänge überschritten! Momentan {current} von {max}"
charactersBelow: "Minimallänge unterschritten! Momentan {current} von {min}"
+14 -5
View File
@@ -424,7 +424,7 @@ antennaExcludeBots: "Exclude bot accounts"
antennaKeywordsDescription: "Separate with spaces for an AND condition or with line breaks for an OR condition."
notifyAntenna: "Notify about new notes"
withFileAntenna: "Only notes with files"
hideNotesInSensitiveChannel: "Hide notes from sensitive channels"
excludeNotesInSensitiveChannel: "Exclude notes from sensitive channels"
enableServiceworker: "Enable Push-Notifications for your Browser"
antennaUsersDescription: "List one username per line"
caseSensitive: "Case sensitive"
@@ -978,7 +978,8 @@ deleteAccount: "Delete account"
document: "Documentation"
numberOfPageCache: "Number of cached pages"
numberOfPageCacheDescription: "Increasing this number will improve convenience for but cause more load as more memory usage on the user's device."
logoutConfirm: "Really log out?"
logoutConfirm: "Are you sure you want to log out?"
logoutWillClearClientData: "Logging out will erase the settings of the client from the browser. In order to be able to restore the settings upon logging in again, you must enable automatic backup of your settings."
lastActiveDate: "Last used at"
statusbar: "Status bar"
pleaseSelect: "Select an option"
@@ -1271,7 +1272,7 @@ notUsePleaseLeaveBlank: "Leave blank if not used"
useTotp: "Enter the One-Time Password"
useBackupCode: "Use the backup codes"
launchApp: "Launch the app"
useNativeUIForVideoAudioPlayer: "Use UI of browser when play video and audio"
useNativeUIForVideoAudioPlayer: "Use UI of browser when play video and audio\n"
keepOriginalFilename: "Keep original file name"
keepOriginalFilenameDescription: "If you turn off this setting, files names will be replaced with random string automatically when you upload files."
noDescription: "There is no explanation"
@@ -1341,6 +1342,10 @@ right: "Right"
bottom: "Bottom"
top: "Top"
embed: "Embed"
settingsMigrating: "Settings are being migrated, please wait a moment... (You can also migrate manually later by going to Settings→Others→Migrate old settings)"
readonly: "Read only"
goToDeck: "Return to Deck"
federationJobs: "Federation Jobs"
_chat:
noMessagesYet: "No messages yet"
newMessage: "New message"
@@ -1370,6 +1375,7 @@ _chat:
muteThisRoom: "Mute room"
deleteRoom: "Delete room"
chatNotAvailableForThisAccountOrServer: "Chat is not enabled on this server or for this account."
chatIsReadOnlyForThisAccountOrServer: "Chat is read-only on this instance or this account. You cannot write new messages or create/join chat rooms."
chatNotAvailableInOtherAccount: "The chat function is disabled for the other user."
cannotChatWithTheUser: "Cannot start a chat with this user"
cannotChatWithTheUser_description: "Chat is either unavailable or the other party has not enabled chat."
@@ -1909,6 +1915,7 @@ _role:
canManageCustomEmojis: "Can manage custom emojis"
canManageAvatarDecorations: "Manage avatar decorations"
driveCapacity: "Drive capacity"
maxFileSize: "Upload-able max file size"
alwaysMarkNsfw: "Always mark files as NSFW"
canUpdateBioMedia: "Can edit an icon or a banner image"
pinMax: "Maximum number of pinned notes"
@@ -1930,7 +1937,7 @@ _role:
canImportFollowing: "Allow importing following"
canImportMuting: "Allow importing muting"
canImportUserLists: "Allow importing lists"
canChat: "Allow Chat"
chatAvailability: "Allow Chat"
_condition:
roleAssignedTo: "Assigned to manual roles"
isLocal: "Local user"
@@ -2364,6 +2371,7 @@ _widgets:
chooseList: "Select a list"
clicker: "Clicker"
birthdayFollowings: "Today's Birthdays"
chat: "Chat"
_cw:
hide: "Hide"
show: "Show content"
@@ -2630,6 +2638,7 @@ _deck:
mentions: "Mentions"
direct: "Direct notes"
roleTimeline: "Role Timeline"
chat: "Chat"
_dialog:
charactersExceeded: "You've exceeded the maximum character limit! Currently at {current} of {max}."
charactersBelow: "You're below the minimum character limit! Currently at {current} of {min}."
@@ -2909,7 +2918,7 @@ _customEmojisManager:
confirmDeleteEmojisDescription: "Delete checked {count} Emoji(s). Are you sure to continue?"
confirmResetDescription: ""
confirmMovePageDesciption: "Changes have been made to the Emojis on this page.\nIf you leave the page without saving, all changes made on this page will be discarded."
dialogSelectRoleTitle: "Search by roll set in Emojis"
dialogSelectRoleTitle: "Search by role set in Emojis"
_register:
uploadSettingTitle: "Upload settings"
uploadSettingDescription: "On this screen, you can configure the behavior when uploading Emojis."
+81 -1
View File
@@ -301,6 +301,7 @@ uploadFromUrlMayTakeTime: "Subir el fichero puede tardar un tiempo."
explore: "Explorar"
messageRead: "Ya leído"
noMoreHistory: "El historial se ha acabado"
startChat: "Nuevo Chat"
nUsersRead: "Leído por {n} personas"
agreeTo: "De acuerdo con {0}"
agree: "De acuerdo."
@@ -423,6 +424,7 @@ antennaExcludeBots: "Excluir bots"
antennaKeywordsDescription: "Separar con espacios es una declaración AND, separar con una linea nueva es una declaración OR"
notifyAntenna: "Notificar nueva nota"
withFileAntenna: "Sólo notas con archivos adjuntados"
excludeNotesInSensitiveChannel: "Excluir notas en canales sensibles"
enableServiceworker: "Activar ServiceWorker"
antennaUsersDescription: "Elegir nombres de usuarios separados por una linea nueva"
caseSensitive: "Distinguir mayúsculas de minúsculas"
@@ -694,6 +696,7 @@ userSaysSomethingAbout: "{name} dijo algo sobre {word}"
makeActive: "Activar"
display: "Apariencia"
copy: "Copiar"
copiedToClipboard: "Texto copiado al portapapeles"
metrics: "Métricas"
overview: "Resumen"
logs: "Registros"
@@ -976,6 +979,7 @@ document: "Documento"
numberOfPageCache: "Cantidad de páginas cacheadas"
numberOfPageCacheDescription: "Al aumentar el número mejora la conveniencia pero tambien puede aumentar la carga y la memoria a usarse"
logoutConfirm: "¿Cerrar sesión?"
logoutWillClearClientData: "Al cerrar la sesión, la información de configuración del cliente se borra del navegador. Para garantizar que la información de configuración se pueda restaurar al volver a iniciar sesión, active la copia de seguridad automática de la configuración."
lastActiveDate: "Utilizado por última vez el"
statusbar: "Barra de estado"
pleaseSelect: "Selecciona una opción"
@@ -1071,7 +1075,7 @@ reactionAcceptance: "Aceptación de reacciones"
likeOnly: "Sólo 'me gusta'"
likeOnlyForRemote: "Sólo reacciones de instancias remotas"
nonSensitiveOnly: "Solo no sensible"
nonSensitiveOnlyForLocalLikeOnlyForRemote: "Sólo no contenido sensible (sólo me gusta en remote)"
nonSensitiveOnlyForLocalLikeOnlyForRemote: "Sólo no contenido sensible (sólo me gusta en remoto)"
rolesAssignedToMe: "Roles asignados a mí"
resetPasswordConfirm: "¿Realmente quieres cambiar la contraseña?"
sensitiveWords: "Palabras sensibles"
@@ -1293,19 +1297,93 @@ passkeyVerificationFailed: "La verificación de la clave de acceso ha fallado."
passkeyVerificationSucceededButPasswordlessLoginDisabled: "La verificación de la clave de acceso ha sido satisfactoria pero se ha deshabilitado el inicio de sesión sin contraseña."
messageToFollower: "Mensaje a seguidores"
target: "Para"
testCaptchaWarning: "Esta función está pensada para probar CAPTCHAs.<strong>No utilizar en un entorno de producción.</strong>"
prohibitedWordsForNameOfUser: "Palabras prohibidas para nombres de usuario"
prohibitedWordsForNameOfUserDescription: "Si alguna de las cadenas de esta lista está incluida en el nombre del usuario, el nombre será denegado. Los usuarios con privilegios de moderador no se ven afectados por esta restricción."
yourNameContainsProhibitedWords: "Tu nombre contiene palabras prohibidas"
yourNameContainsProhibitedWordsDescription: "Si deseas usar este nombre, por favor contacta con tu administrador/a de tu servidor"
thisContentsAreMarkedAsSigninRequiredByAuthor: " Establecido por el autor: requiere iniciar sesión para ver"
lockdown: "Bloqueo"
pleaseSelectAccount: "Seleccione una cuenta, por favor."
availableRoles: "Roles disponibles "
acknowledgeNotesAndEnable: "Activar después de comprender las precauciones"
federationSpecified: "Este servidor opera en una federación de listas blancas. No puede interactuar con otros servidores que no sean los especificados por el administrador."
federationDisabled: "La federación está desactivada en este servidor. No puede interactuar con usuarios de otros servidores"
confirmOnReact: "Confirmar la reacción"
reactAreYouSure: "¿Quieres añadir una reacción «{emoji}»?"
markAsSensitiveConfirm: "¿Desea establecer este medio multimedia(Imagen,vídeo...) como sensible?"
unmarkAsSensitiveConfirm: "¿Desea eliminar la designación de sensible para este adjunto?"
preferences: "Preferencias"
accessibility: "Accesibilidad"
preferencesProfile: "Configuración del perfil"
copyPreferenceId: "Copiar ID de la configuración"
resetToDefaultValue: "Revertir a valor predeterminado"
overrideByAccount: "Anulado por la cuenta"
untitled: "Sin título"
noName: "No hay nombre."
skip: "Saltar"
restore: "Restaurar"
syncBetweenDevices: "Sincronizar entre dispositivos"
preferenceSyncConflictTitle: "Los valores configurados existen en el servidor."
preferenceSyncConflictText: "Los ajustes de sincronización activados guardarán sus valores en el servidor. Sin embargo, hay valores existentes en el servidor. ¿Qué conjunto de valores desea sobrescribir?"
emojiPalette: "Paleta emoji"
postForm: "Formulario"
information: "Información"
chat: "Chat"
migrateOldSettings: "Migrar la configuración anterior"
right: "Derecha"
bottom: "Abajo"
top: "Arriba"
embed: "Insertar"
settingsMigrating: "La configuración está siendo migrada, por favor espera un momento... (También puedes migrar manualmente más tarde yendo a Ajustes otros migrar configuración antigua"
readonly: "Solo Lectura"
_chat:
noMessagesYet: "Aún no hay mensajes"
newMessage: "Mensajes nuevos"
individualChat: "Chat individual"
individualChat_description: "Mantén una conversación privada con otra persona."
invitations: "Invitar"
noHistory: "No hay datos en el historial"
members: "Miembros"
home: "Inicio"
send: "Enviar"
chatNotAvailableInOtherAccount: "La función de chat está desactivada para el otro usuario."
cannotChatWithTheUser: "No se puede iniciar un chat con este usuario"
cannotChatWithTheUser_description: "El chat no está disponible o la otra parte no ha habilitado el chat."
chatWithThisUser: "Chatear"
thisUserAllowsChatOnlyFromFollowers: "Este usuario sólo acepta chats de seguidores."
thisUserAllowsChatOnlyFromFollowing: "Este usuario sólo acepta chats de los usuarios a los que sigue."
thisUserAllowsChatOnlyFromMutualFollowing: "Este usuario sólo acepta chats de usuarios que son seguidores mutuos."
thisUserNotAllowedChatAnyone: "Este usuario no acepta chats de nadie."
chatAllowedUsers: "A quién permitir chatear."
chatAllowedUsers_note: "Puedes chatear con cualquier persona a la que hayas enviado un mensaje de chat, independientemente de esta configuración."
_chatAllowedUsers:
everyone: "Todos"
followers: "Sólo sus propios seguidores."
following: "Solo usuarios que sigues"
mutual: "Solo seguidores mutuos"
none: "Nadie"
_emojiPalette:
palettes: "Paleta\n"
_settings:
api: "API"
webhook: "Webhook"
makeEveryTextElementsSelectable_description: "Activar esta opción puede reducir la usabilidad en algunas situaciones."
useStickyIcons: "Hacer que los iconos te sigan cuando desplaces"
showNavbarSubButtons: "Mostrar los sub-botones en la barra de navegación."
ifOn: "Si está activado"
enableSyncThemesBetweenDevices: "Sincronizar los temas instalados entre dispositivos."
_chat:
showSenderName: "Mostrar el nombre del remitente"
sendOnEnter: "Intro para enviar"
_preferencesProfile:
profileName: "Nombre de perfil"
profileNameDescription: "Establece un nombre que identifique al dispositivo"
profileNameDescription2: "Por ejemplo: \"PC Principal\",\"Teléfono\""
_preferencesBackup:
autoBackup: "Respaldo automático"
restoreFromBackup: "Restaurar desde copia de seguridad"
noBackupsFoundTitle: "No se encontró una copia de seguridad"
_accountSettings:
requireSigninToViewContents: "Se requiere iniciar sesión para ver el contenido"
requireSigninToViewContentsDescription1: "Requiere iniciar sesión para ver todas las notas y otros contenidos que hayas creado. Se espera que esto evite que los rastreadores recopilen información."
@@ -2196,6 +2274,7 @@ _widgets:
chooseList: "Seleccione una lista"
clicker: "Cliqueador"
birthdayFollowings: "Hoy cumplen años"
chat: "Chat"
_cw:
hide: "Ocultar"
show: "Ver más"
@@ -2443,6 +2522,7 @@ _deck:
mentions: "Menciones"
direct: "Notas directas"
roleTimeline: "Linea de tiempo del rol"
chat: "Chat"
_dialog:
charactersExceeded: "¡Has excedido el límite de caracteres! Actualmente {current} de {max}."
charactersBelow: "¡Estás por debajo del límite de caracteres! Actualmente {current} de {min}."
+33 -2
View File
@@ -1715,9 +1715,9 @@ export interface Locale extends ILocale {
*/
"withFileAntenna": string;
/**
*
*
*/
"hideNotesInSensitiveChannel": string;
"excludeNotesInSensitiveChannel": string;
/**
*
*/
@@ -3934,6 +3934,10 @@ export interface Locale extends ILocale {
*
*/
"logoutConfirm": string;
/**
*
*/
"logoutWillClearClientData": string;
/**
*
*/
@@ -5390,6 +5394,21 @@ export interface Locale extends ILocale {
*
*/
"readonly": string;
/**
*
*/
"goToDeck": string;
/**
*
*/
"federationJobs": string;
/**
* <br>
* 稿<br>
* <b>使()</b><br>
*
*/
"driveAboutTip": string;
"_chat": {
/**
*
@@ -7452,6 +7471,10 @@ export interface Locale extends ILocale {
*
*/
"driveCapacity": string;
/**
*
*/
"maxFileSize": string;
/**
* NSFWを常に付与
*/
@@ -9199,6 +9222,10 @@ export interface Locale extends ILocale {
*
*/
"birthdayFollowings": string;
/**
*
*/
"chat": string;
};
"_cw": {
/**
@@ -10222,6 +10249,10 @@ export interface Locale extends ILocale {
*
*/
"roleTimeline": string;
/**
*
*/
"chat": string;
};
};
"_dialog": {
+15 -8
View File
@@ -382,7 +382,7 @@ disconnectService: "Disconnetti"
enableLocalTimeline: "Abilita la timeline locale"
enableGlobalTimeline: "Abilita la timeline federata"
disablingTimelinesInfo: "Anche disabilitandole, gli Amministratori e i Moderatori potranno comunque accedervi."
registration: "Iscriviti"
registration: "Registrazione"
invite: "Invita"
driveCapacityPerLocalAccount: "Capienza del Drive per profilo locale"
driveCapacityPerRemoteAccount: "Capienza del Drive per profilo remoto"
@@ -424,7 +424,7 @@ antennaExcludeBots: "Escludere i Bot"
antennaKeywordsDescription: "Sparando con uno spazio indichi la condizione E (and). Separando con un a capo, indichi la condizione O (or)."
notifyAntenna: "Invia notifiche delle nuove note"
withFileAntenna: "Solo note con file in allegato"
hideNotesInSensitiveChannel: "Nascondere le Note dai canali espliciti"
excludeNotesInSensitiveChannel: "Escludere le Note dai canali espliciti"
enableServiceworker: "Abilita ServiceWorker"
antennaUsersDescription: "Elenca un nome utente per riga"
caseSensitive: "Sensibile alla distinzione tra maiuscole e minuscole"
@@ -728,7 +728,7 @@ reporterOrigin: "Segnalazione da"
send: "Inviare"
openInNewTab: "Apri in una nuova scheda"
openInSideView: "Apri in vista laterale"
defaultNavigationBehaviour: "Navigazione preimpostata"
defaultNavigationBehaviour: "Tipo di navigazione predefinita"
editTheseSettingsMayBreakAccount: "Modificare queste impostazioni può danneggiare il profilo"
instanceTicker: "Informazioni sull'istanza da cui vengono le note"
waitingFor: "Aspettando {x}"
@@ -867,7 +867,7 @@ noBotProtectionWarning: "Non è stata impostata alcuna protezione dai Bot"
configure: "Imposta"
postToGallery: "Pubblicare nella galleria"
postToHashtag: "Pubblica a questo hashtag"
gallery: "Galleria"
gallery: "Gallerie"
recentPosts: "Pubblicazioni recenti"
popularPosts: "Le più visualizzate"
shareWithNote: "Condividere in nota"
@@ -979,6 +979,7 @@ document: "Documentazione"
numberOfPageCache: "Numero di pagine cache"
numberOfPageCacheDescription: "Aumenta l'usabilità, ma aumenta anche il carico e l'utilizzo della memoria."
logoutConfirm: "Vuoi davvero uscire da Misskey? "
logoutWillClearClientData: "All'uscita, la configurazione del client viene rimossa dal browser. Per ripristinarla quando si effettua nuovamente l'accesso, abilitare il backup automatico."
lastActiveDate: "Data dell'ultimo utilizzo"
statusbar: "Barra di stato"
pleaseSelect: "Scegli un'opzione"
@@ -1341,6 +1342,9 @@ right: "Destra"
bottom: "Sotto"
top: "Sopra"
embed: "Incorporare"
settingsMigrating: "Migrazione delle impostazioni. Attendere prego ... (Puoi anche migrare manualmente in un secondo momento, nel menu: Impostazioni → Altro → Migrazione delle impostazioni)"
readonly: "Sola lettura"
goToDeck: "Torna al Deck"
_chat:
noMessagesYet: "Ancora nessun messaggio"
newMessage: "Nuovo messaggio"
@@ -1370,6 +1374,7 @@ _chat:
muteThisRoom: "Silenzia stanza"
deleteRoom: "Elimina stanza"
chatNotAvailableForThisAccountOrServer: "Questo server, o questo profilo ha disabilitato la chat."
chatIsReadOnlyForThisAccountOrServer: "Le chat, su questo server o su questo profilo, sono di sola lettura. Impossibile scrivere in chat o creare e partecipare a stanze."
chatNotAvailableInOtherAccount: "La chat non è disponibile nel profilo dell'altra persona."
cannotChatWithTheUser: "Impossibile chattare con questa persona"
cannotChatWithTheUser_description: "La chat potrebbe non essere disponibile, oppure l'altra persona potrebbe non esserlo."
@@ -1930,7 +1935,7 @@ _role:
canImportFollowing: "Può importare Following"
canImportMuting: "Può importare Silenziati"
canImportUserLists: "Può importare liste di Profili"
canChat: "Chat consentita"
chatAvailability: "Chat consentita"
_condition:
roleAssignedTo: "Assegnato a ruoli manualmente"
isLocal: "Profilo locale"
@@ -2364,6 +2369,7 @@ _widgets:
chooseList: "Seleziona una lista"
clicker: "Cliccheria"
birthdayFollowings: "Compleanni del giorno"
chat: "Chat"
_cw:
hide: "Nascondere"
show: "Continua la lettura..."
@@ -2596,8 +2602,8 @@ _notification:
renote: "Rinota"
_deck:
alwaysShowMainColumn: "Mostra sempre la colonna principale"
columnAlign: "Allineare colonne"
columnGap: "Margine tra le colonne"
columnAlign: "Allineamento delle colonne"
columnGap: "Spessore del margine tra colonne"
deckMenuPosition: "Posizione del menu Deck"
navbarPosition: "Posizione barra di navigazione"
addColumn: "Aggiungi colonna"
@@ -2626,10 +2632,11 @@ _deck:
tl: "Timeline"
antenna: "Antenne"
list: "Liste"
channel: "Canale"
channel: "Canali"
mentions: "Menzioni"
direct: "Note Dirette"
roleTimeline: "Timeline Ruolo"
chat: "Chat"
_dialog:
charactersExceeded: "Hai superato il limite di {max} caratteri! ({current})"
charactersBelow: "Sei al di sotto del minimo di {min} caratteri! ({current})"
+8 -1
View File
@@ -424,7 +424,7 @@ antennaExcludeBots: "Botアカウントを除外"
antennaKeywordsDescription: "スペースで区切るとAND指定になり、改行で区切るとOR指定になります"
notifyAntenna: "新しいノートを通知する"
withFileAntenna: "ファイルが添付されたノートのみ"
hideNotesInSensitiveChannel: "センシティブなチャンネルのノートを非表示"
excludeNotesInSensitiveChannel: "センシティブなチャンネルのノートを除外"
enableServiceworker: "ブラウザへのプッシュ通知を有効にする"
antennaUsersDescription: "ユーザー名を改行で区切って指定します"
caseSensitive: "大文字小文字を区別する"
@@ -979,6 +979,7 @@ document: "ドキュメント"
numberOfPageCache: "ページキャッシュ数"
numberOfPageCacheDescription: "多くすると利便性が向上しますが、負荷とメモリ使用量が増えます。"
logoutConfirm: "ログアウトしますか?"
logoutWillClearClientData: "ログアウトするとクライアントの設定情報がブラウザから消去されます。再ログイン時に設定情報を復元できるようにするためには、設定の自動バックアップを有効にしてください。"
lastActiveDate: "最終利用日時"
statusbar: "ステータスバー"
pleaseSelect: "選択してください"
@@ -1343,6 +1344,9 @@ top: "上"
embed: "埋め込み"
settingsMigrating: "設定を移行しています。しばらくお待ちください... (後ほど、設定→その他→旧設定情報を移行 で手動で移行することもできます)"
readonly: "読み取り専用"
goToDeck: "デッキへ戻る"
federationJobs: "連合ジョブ"
driveAboutTip: "ドライブでは、過去にアップロードしたファイルの一覧が表示されます。<br>\nノートに添付する際に再利用したり、あとで投稿するファイルを予めアップロードしておくこともできます。<br>\n<b>ファイルを削除すると、今までそのファイルを使用した全ての場所(ノート、ページ、アバター、バナー等)からも見えなくなるので注意してください。</b><br>\nフォルダを作って整理することもできます。"
_chat:
noMessagesYet: "まだメッセージはありません"
@@ -1931,6 +1935,7 @@ _role:
canManageCustomEmojis: "カスタム絵文字の管理"
canManageAvatarDecorations: "アバターデコレーションの管理"
driveCapacity: "ドライブ容量"
maxFileSize: "アップロード可能な最大ファイルサイズ"
alwaysMarkNsfw: "ファイルにNSFWを常に付与"
canUpdateBioMedia: "アイコンとバナーの更新を許可"
pinMax: "ノートのピン留めの最大数"
@@ -2419,6 +2424,7 @@ _widgets:
chooseList: "リストを選択"
clicker: "クリッカー"
birthdayFollowings: "今日誕生日のユーザー"
chat: "チャット"
_cw:
hide: "隠す"
@@ -2703,6 +2709,7 @@ _deck:
mentions: "あなた宛て"
direct: "ダイレクト"
roleTimeline: "ロールタイムライン"
chat: "チャット"
_dialog:
charactersExceeded: "最大文字数を超えています! 現在 {current} / 制限 {max}"
+198 -190
View File
@@ -64,8 +64,8 @@ copyNoteId: "노트 ID 복사"
copyFileId: "파일 ID 복사"
copyFolderId: "폴더 ID 복사"
copyProfileUrl: "프로필 URL 복사"
searchUser: "사용자 검색"
searchThisUsersNotes: "사용자의 노트 검색"
searchUser: "유저 검색"
searchThisUsersNotes: "유저의 노트 검색"
reply: "답글"
loadMore: "더 보기"
showMore: "더 보기"
@@ -267,7 +267,7 @@ publishing: "배포 중"
notResponding: "응답 없음"
instanceFollowing: "서버의 팔로잉"
instanceFollowers: "서버의 팔로워"
instanceUsers: "서버의 사용자"
instanceUsers: "서버의 유저"
changePassword: "비밀번호 변경"
security: "보안"
retypedNotMatch: "입력이 일치하지 않습니다."
@@ -385,12 +385,12 @@ disablingTimelinesInfo: "특정 타임라인을 비활성화하더라도 관리
registration: "등록"
invite: "초대"
driveCapacityPerLocalAccount: "로컬 유저 한 명당 드라이브 용량"
driveCapacityPerRemoteAccount: "원격 사용자별 드라이브 용량"
driveCapacityPerRemoteAccount: "리모트 유저별 드라이브 용량"
inMb: "메가바이트 단위"
bannerUrl: "배너 이미지 URL"
backgroundImageUrl: "배경 이미지 URL"
basicInfo: "기본 정보"
pinnedUsers: "고정한 사용자"
pinnedUsers: "고정한 유저"
pinnedUsersDescription: "\"발견하기\" 페이지 등에 고정하고 싶은 유저를 한 줄에 한 명씩 적습니다."
pinnedPages: "고정한 페이지"
pinnedPagesDescription: "서버의 대문에 고정하고 싶은 페이지의 경로를 한 줄에 하나씩 적습니다."
@@ -418,13 +418,13 @@ antennas: "안테나"
manageAntennas: "안테나 관리"
name: "이름"
antennaSource: "받을 소스"
antennaKeywords: "받을 검색어"
antennaExcludeKeywords: "제외할 검색어"
antennaKeywords: "받을 키워드"
antennaExcludeKeywords: "제외할 키워드"
antennaExcludeBots: "봇 계정 제외"
antennaKeywordsDescription: "공백으로 구분하는 경우 AND, 줄바꿈으로 구분하는 경우 OR로 지정됩니다"
notifyAntenna: "새로운 노트를 알림"
withFileAntenna: "파일이 첨부된 노트만"
hideNotesInSensitiveChannel: "민감한 채널의 노트 숨기기"
excludeNotesInSensitiveChannel: "민감한 채널의 노트 제외"
enableServiceworker: "ServiceWorker 사용"
antennaUsersDescription: "유저명을 한 줄에 한 명씩 적습니다"
caseSensitive: "대소문자를 구분"
@@ -436,11 +436,11 @@ silence: "사일런스"
silenceConfirm: "이 계정을 사일런스로 설정하시겠습니까?"
unsilence: "사일런스 해제"
unsilenceConfirm: "이 계정의 사일런스를 해제하시겠습니까?"
popularUsers: "인기 사용자"
recentlyUpdatedUsers: "최근에 활동한 사용자"
recentlyRegisteredUsers: "최근에 가입한 사용자"
recentlyDiscoveredUsers: "최근에 발견한 사용자"
exploreUsersCount: "{count}명의 사용자가 있습니다"
popularUsers: "인기 유저"
recentlyUpdatedUsers: "최근에 활동한 유저"
recentlyRegisteredUsers: "최근에 가입한 유저"
recentlyDiscoveredUsers: "최근에 발견한 유저"
exploreUsersCount: "{count}명의 유저가 있습니다"
exploreFediverse: "연합우주를 탐색"
popularTags: "인기 태그"
userList: "리스트"
@@ -489,7 +489,7 @@ next: "다음"
retype: "다시 입력"
noteOf: "{user}의 노트"
quoteAttached: "인용함"
quoteQuestion: "인용해서 작성하시겠습니까?"
quoteQuestion: "인용해서 첨부하시겠습니까?"
attachAsFileQuestion: "붙여넣으려는 글이 너무 깁니다. 텍스트 파일로 첨부하시겠습니까?"
onlyOneFileCanBeAttached: "메시지에 첨부할 수 있는 파일은 하나까지입니다"
signinRequired: "진행하기 전에 로그인을 해 주세요"
@@ -508,7 +508,7 @@ strongPassword: "강한 비밀번호"
passwordMatched: "일치합니다"
passwordNotMatched: "일치하지 않습니다"
signinWith: "{x}로 로그인"
signinFailed: "로그인할 수 없습니다. 사용자 이름과 비밀번호를 확인해 주십시오."
signinFailed: "로그인할 수 없습니다. 유저 이름과 비밀번호를 확인해 주십시오."
or: "혹은"
language: "언어"
uiLanguage: "UI 표시 언어"
@@ -520,7 +520,7 @@ style: "스타일"
drawer: "서랍"
popup: "팝업"
showNoteActionsOnlyHover: "마우스가 올라간 때에만 노트 동작 버튼을 표시하기"
showReactionsCount: "노트의 반응 수를 표시하기"
showReactionsCount: "노트의 리액션 수를 표시하기"
noHistory: "기록이 없습니다"
signinHistory: "로그인 기록"
enableAdvancedMfm: "고급 MFM을 활성화"
@@ -571,8 +571,8 @@ objectStorageSetPublicRead: "업로드할 때 'public-read'를 설정하기"
s3ForcePathStyleDesc: "s3ForcePathStyle을 활성화하면, 버킷 이름을 URL의 호스트명이 아닌 경로의 일부로써 취급합니다. 셀프 호스트 Minio와 같은 서비스를 사용할 경우 활성화해야 할 수 있습니다."
serverLogs: "서버 로그"
deleteAll: "모두 삭제"
showFixedPostForm: "타임라인 상단에 글 작성란을 표시"
showFixedPostFormInChannel: "채널 타임라인 상단에 글 작성란을 표시"
showFixedPostForm: "타임라인 상단에 글 입력란을 표시"
showFixedPostFormInChannel: "채널 타임라인 상단에 글 입력란을 표시"
withRepliesByDefaultForNewlyFollowed: "팔로우 할 때 기본적으로 답글을 타임라인에 나오게 하기"
newNoteRecived: "새 노트가 있습니다"
sounds: "소리"
@@ -607,7 +607,7 @@ uiInspectorDescription: "메모리에 있는 UI 컴포넌트의 인스턴트 목
output: "출력"
script: "스크립트"
disablePagesScript: "Pages 에서 AiScript 를 사용하지 않음"
updateRemoteUser: "원격 사용자 정보 갱신"
updateRemoteUser: "리모트 유저 정보 갱신"
unsetUserAvatar: "아바타 제거"
unsetUserAvatarConfirm: "아바타를 제거할까요?"
unsetUserBanner: "배너 제거"
@@ -616,7 +616,7 @@ deleteAllFiles: "모든 파일 삭제"
deleteAllFilesConfirm: "모든 파일을 삭제하시겠습니까?"
removeAllFollowing: "모든 팔로잉 해제"
removeAllFollowingDescription: "{host} 서버의 모든 팔로잉을 해제합니다. 해당 서버가 더 이상 존재하지 않는 경우 등에 실행해 주세요."
userSuspended: "이 사용자는 정지되었습니다."
userSuspended: "이 유저는 정지되었습니다."
userSilenced: "이 계정은 사일런스된 상태입니다."
yourAccountSuspendedTitle: "계정이 정지되었습니다"
yourAccountSuspendedDescription: "이 계정은 서버의 이용 약관을 위반하거나, 기타 다른 이유로 인해 정지되었습니다. 자세한 사항은 관리자에게 문의해 주십시오. 계정을 새로 생성하지 마십시오."
@@ -677,7 +677,7 @@ emailAddress: "메일 주소"
smtpConfig: "SMTP 서버 설정"
smtpHost: "호스트"
smtpPort: "포트"
smtpUser: "사용자 이름"
smtpUser: "유저 이름"
smtpPass: "비밀번호"
emptyToDisableSmtpAuth: "SMTP 인증을 사용하지 않으려면 공란으로 비워둡니다."
smtpSecure: "SMTP 연결에 Implicit SSL/TTS 사용"
@@ -720,7 +720,7 @@ abuseReports: "신고"
reportAbuse: "신고"
reportAbuseRenote: "리노트 신고하기"
reportAbuseOf: "{name} 신고하기"
fillAbuseReportDescription: "신고하려는 이유를 자세히 알려주세요. 특정 게시물을 신고할 때에는 게시물의 URL도 포함해 주세요."
fillAbuseReportDescription: "신고유를 자세히 기재해 주세요. 대상 노트나 페이지 등이 있는 경우에는 해당 URL도 기재해 주세요."
abuseReported: "신고를 보냈습니다. 신고해 주셔서 감사합니다."
reporter: "신고자"
reporteeOrigin: "피신고자"
@@ -754,8 +754,8 @@ repliedCount: "받은 답글 수"
renotedCount: "받은 리노트 수"
followingCount: "팔로우 수"
followersCount: "팔로워 수"
sentReactionsCount: "반응 수"
receivedReactionsCount: "받은 반응 수"
sentReactionsCount: "리액션 수"
receivedReactionsCount: "받은 리액션 수"
pollVotesCount: "투표 수"
pollVotedCount: "받은 투표 수"
yes: "예"
@@ -763,7 +763,7 @@ no: "아니오"
driveFilesCount: "드라이브에 있는 파일 수"
driveUsage: "드라이브 사용량"
noCrawle: "검색엔진의 인덱싱 거부"
noCrawleDescription: "검색엔진에 사용자 페이지, 노트, 페이지 등의 콘텐츠를 인덱싱되지 않게 합니다."
noCrawleDescription: "검색엔진에 유저 페이지, 노트, 페이지 등의 콘텐츠를 인덱싱되지 않게 합니다."
lockedAccountInfo: "팔로우를 승인으로 승인받더라도 노트의 공개 범위를 '팔로워'로 하지 않는 한 누구나 당신의 노트를 볼 수 있습니다."
alwaysMarkSensitive: "미디어를 항상 열람 주의로 설정"
loadRawImages: "첨부한 이미지의 썸네일을 원본화질로 표시"
@@ -795,7 +795,7 @@ needReloadToApply: "변경 사항은 새로고침하면 적용됩니다."
showTitlebar: "타이틀 바를 표시하기"
clearCache: "캐시 비우기"
onlineUsersCount: "{n}명이 접속 중"
nUsers: "{n} 사용자"
nUsers: "{n} 유저"
nNotes: "{n} 노트"
sendErrorReports: "오류 보고서 보내기"
sendErrorReportsDescription: "이 설정을 활성화하면, 문제가 발생했을 때 오류에 대한 상세 정보를 Misskey에 보내어 더 나은 소프트웨어를 만드는 데에 도움을 줄 수 있습니다."
@@ -825,7 +825,7 @@ editCode: "코드 수정"
apply: "적용"
receiveAnnouncementFromInstance: "이 서버의 알림을 이메일로 수신할게요"
emailNotification: "메일 알림"
publish: "게시"
publish: "공개"
inChannelSearch: "채널에서 검색"
useReactionPickerForContextMenu: "우클릭하여 리액션 선택기 열기"
typingUsers: "{users}님이 입력 중"
@@ -841,7 +841,7 @@ addDescription: "설명 추가"
userPagePinTip: "각 노트의 메뉴에서 「프로필에 고정」을 선택하는 것으로, 여기에 노트를 표시해 둘 수 있어요."
notSpecifiedMentionWarning: "수신자가 선택되지 않은 멘션이 있어요"
info: "정보"
userInfo: "사용자 정보"
userInfo: "유저 정보"
unknown: "알 수 없음"
onlineStatus: "온라인 상태"
hideOnlineStatus: "온라인 상태 숨기기"
@@ -857,7 +857,7 @@ switchAccount: "계정 바꾸기"
enabled: "활성화"
disabled: "비활성화"
quickAction: "빠른 동작"
user: "사용자"
user: "유저"
administration: "관리"
accounts: "계정"
switch: "전환"
@@ -868,8 +868,8 @@ configure: "설정하기"
postToGallery: "갤러리에 업로드"
postToHashtag: "이 해시태그에 게시"
gallery: "갤러리"
recentPosts: "최근 포스트"
popularPosts: "인기 포스트"
recentPosts: "최근 게시물"
popularPosts: "인기 게시물"
shareWithNote: "노트로 공유"
ads: "광고"
expiration: "기한"
@@ -898,7 +898,7 @@ whatIsNew: "패치 정보 보기"
translate: "번역"
translatedFrom: "{x}에서 번역"
accountDeletionInProgress: "계정 삭제 작업을 진행하고 있습니다"
usernameInfo: "서버상에서 계정을 식별하기 위한 이름. 알파벳(a~z, A~Z), 숫자(0~9) 및 언더바(_)를 사용할 수 있습니다. 사용자명은 나중에 변경할 수 없습니다."
usernameInfo: "서버상에서 계정을 식별하기 위한 이름. 알파벳(a~z, A~Z), 숫자(0~9) 및 언더바(_)를 사용할 수 있습니다. 유저명은 나중에 변경할 수 없습니다."
aiChanMode: "아이 모드"
devMode: "개발자 모드"
keepCw: "CW 유지하기"
@@ -979,6 +979,7 @@ document: "문서"
numberOfPageCache: "페이지 캐시 수"
numberOfPageCacheDescription: "숫자가 클 수록 편리성이 높아지지만, 시스템 자원과 메모리를 더 많이 사용합니다."
logoutConfirm: "로그아웃 하시겠습니까?"
logoutWillClearClientData: "로그아웃하면 클라이언트의 설정 데이터가 브라우저에서 지워지게 됩니다. 다시 로그인할 때 설정 데이터를 복원할 수 있도록 하려면 설정 자동 백업을 활성화하세요."
lastActiveDate: "마지막 이용"
statusbar: "상태바"
pleaseSelect: "선택해 주세요"
@@ -1032,7 +1033,7 @@ correspondingSourceIsAvailable: "소스 코드는 {anchor}에서 받아보실
roles: "역할"
role: "역할"
noRole: "역할이 없습니다"
normalUser: "일반 사용자"
normalUser: "일반 유저"
undefined: "정의되지 않음"
assign: "할당"
unassign: "할당 취소"
@@ -1056,7 +1057,7 @@ thisPostMayBeAnnoyingHome: "홈에 게시"
thisPostMayBeAnnoyingCancel: "그만두기"
thisPostMayBeAnnoyingIgnore: "이대로 게시"
collapseRenotes: "이미 본 리노트를 간략화하기"
collapseRenotesDescription: "반응이나 리노트를 한 노트를 접어서 표시합니다."
collapseRenotesDescription: "리액션이나 리노트를 한 노트를 접어서 표시합니다."
internalServerError: "내부 서버 오류"
internalServerErrorDescription: "내부 서버에서 예기치 않은 오류가 발생했습니다."
copyErrorInfo: "오류 정보 복사"
@@ -1080,8 +1081,8 @@ resetPasswordConfirm: "비밀번호를 재설정하시겠습니까?"
sensitiveWords: "민감한 단어"
sensitiveWordsDescription: "설정한 단어가 포함된 노트의 공개 범위를 '홈'으로 강제합니다. 개행으로 구분하여 여러 개를 지정할 수 있습니다."
sensitiveWordsDescription2: "공백으로 구분하면 AND 지정이 되며, 키워드를 슬래시로 둘러싸면 정규 표현식이 됩니다."
prohibitedWords: "금지 워드"
prohibitedWordsDescription: "설정된 워드가 포함되는 노트를 작성하려고 하면, 에러가 발생하도록 합니다. 줄바꿈으로 구분지어 복수 설정할 수 있습니다."
prohibitedWords: "금지 단어"
prohibitedWordsDescription: "설정된 단어가 포함되는 노트를 게시하려고 하면, 오류가 발생하도록 합니다. 줄바꿈으로 구분지어 복수 설정할 수 있습니다."
prohibitedWordsDescription2: "공백으로 구분하면 AND 지정이 되며, 키워드를 슬래시로 둘러싸면 정규 표현식이 됩니다."
hiddenTags: "숨긴 해시태그"
hiddenTagsDescription: "설정한 태그를 트렌드에 표시하지 않도록 합니다. 줄 바꿈으로 하나씩 나눠서 설정할 수 있습니다."
@@ -1106,7 +1107,7 @@ audio: "소리"
audioFiles: "소리"
dataSaver: "데이터 절약 모드"
accountMigration: "계정 이동"
accountMoved: "이 사용자는 다음 계정으로 이사했습니다:"
accountMoved: "이 유저는 다음 계정으로 이사했습니다:"
accountMovedShort: "이사한 계정입니다"
operationForbidden: "사용할 수 없습니다"
forceShowAds: "광고를 항상 표시"
@@ -1127,8 +1128,8 @@ serverRules: "서버 규칙"
pleaseConfirmBelowBeforeSignup: "이 서버에 가입하기 전에 아래 사항을 확인하여 주십시오."
pleaseAgreeAllToContinue: "계속하시려면 모든 항목에 동의하십시오."
continue: "계속"
preservedUsernames: "예약한 사용자 이름"
preservedUsernamesDescription: "예약할 사용자명을 한 줄에 하나씩 입력합니다. 여기에서 지정한 사용자명으로는 계정을 생성할 수 없게 됩니다. 단, 관리자 권한으로 계정을 생성할 때에는 해당되지 않으며, 이미 존재하는 계정도 영향을 받지 않습니다."
preservedUsernames: "예약한 유저명"
preservedUsernamesDescription: "예약할 유저명을 한 줄에 하나씩 입력합니다. 여기에서 지정한 유저명으로는 계정을 생성할 수 없게 됩니다. 단, 관리자 권한으로 계정을 생성할 때에는 해당되지 않으며, 이미 존재하는 계정도 영향을 받지 않습니다."
createNoteFromTheFile: "이 파일로 노트를 작성"
archive: "아카이브"
archived: "아카이브 됨"
@@ -1142,7 +1143,7 @@ youFollowing: "팔로잉"
preventAiLearning: "기계학습(생성형 AI)으로의 사용을 거부"
preventAiLearningDescription: "외부의 문장 생성 AI나 이미지 생성 AI에 대해 제출한 노트나 이미지 등의 콘텐츠를 학습의 대상으로 사용하지 않도록 요구합니다. 다만, 이 요구사항을 지킬 의무는 없기 때문에 학습을 완전히 방지하는 것은 아닙니다."
options: "옵션"
specifyUser: "사용자 지정"
specifyUser: "유저 지정"
lookupConfirm: "조회 할까요?"
openTagPageConfirm: "해시태그의 페이지를 열까요?"
specifyHost: "호스트 지정"
@@ -1297,8 +1298,8 @@ passkeyVerificationSucceededButPasswordlessLoginDisabled: "입력된 패스키
messageToFollower: "팔로워에게 보낼 메시지"
target: "대상"
testCaptchaWarning: "CAPTCHA를 테스트하기 위한 기능입니다. <strong>실제 환경에서는 사용하지 마세요.</strong>"
prohibitedWordsForNameOfUser: "금지 단어 (사용자 이름)"
prohibitedWordsForNameOfUserDescription: "이 목록에 포함되는 키워드가 사용자 이름에 있는 경우, 일반 사용자는 이름을 바꿀 수 없습니다. 모더레이터 권한을 가진 사용자는 제한 대상에서 제외됩니다."
prohibitedWordsForNameOfUser: "금지 단어 (유저명)"
prohibitedWordsForNameOfUserDescription: "이 목록에 포함되는 키워드가 유저명에 있는 경우, 일반 유저는 이름을 바꿀 수 없습니다. 모더레이터 권한을 가진 유저는 제한 대상에서 제외됩니다."
yourNameContainsProhibitedWords: "바꾸려는 이름에 금지된 키워드가 포함되어 있습니다."
yourNameContainsProhibitedWordsDescription: "이름에 금지된 키워드가 있습니다. 이름을 사용해야 하는 경우, 서버 관리자에 문의하세요."
thisContentsAreMarkedAsSigninRequiredByAuthor: "게시자에 의해 로그인해야 볼 수 있도록 설정되어 있습니다."
@@ -1341,15 +1342,19 @@ right: "오른쪽"
bottom: "아래"
top: "위"
embed: "임베드"
settingsMigrating: "설정을 이전하는 중입니다. 잠시 기다려주십시오... (나중에 '환경설정 → 기타 → 기존 설정 정보를 이전'에서 수동으로 이전할 수도 있습니다)"
readonly: "읽기 전용"
goToDeck: "덱으로 돌아가기"
federationJobs: "연합 작업"
_chat:
noMessagesYet: "아직 메시지가 없습니다"
newMessage: "새로운 메시지"
individualChat: "개인 대화"
individualChat_description: "특정 사용자와 일대일 채팅을 할 수 있습니다."
individualChat_description: "특정 유저와 일대일 채팅을 할 수 있습니다."
roomChat: "룸 채팅"
roomChat_description: "여러 명이 함께 채팅할 수 있습니다.\n또한, 개인 채팅을 허용하지 않은 사용자와도 상대방이 수락하면 채팅을 할 수 있습니다."
roomChat_description: "여러 명이 함께 채팅할 수 있습니다.\n또한, 개인 채팅을 허용하지 않은 유저와도 상대방이 수락하면 채팅을 할 수 있습니다."
createRoom: "룸을 생성"
inviteUserToChat: "사용자를 초대하여 채팅을 시작하세요"
inviteUserToChat: "유저를 초대하여 채팅을 시작하세요"
yourRooms: "생성한 룸"
joiningRooms: "참가 중인 룸"
invitations: "초대"
@@ -1357,7 +1362,7 @@ _chat:
history: "이력"
noHistory: "기록이 없습니다"
noRooms: "룸이 없습니다"
inviteUser: "사용자를 초대"
inviteUser: "유저를 초대"
sentInvitations: "초대를 보내기"
join: "참여"
ignore: "무시"
@@ -1370,21 +1375,22 @@ _chat:
muteThisRoom: "이 룸을 뮤트"
deleteRoom: "룸을 삭제"
chatNotAvailableForThisAccountOrServer: "이 서버 또는 이 계정에서 채팅이 활성화되어 있지 않습니다."
chatIsReadOnlyForThisAccountOrServer: "이 서버 또는 이 계정에서 채팅은 읽기 전용입니다. 새로 쓰거나 채팅 룸을 만들거나 참가할 수 없습니다."
chatNotAvailableInOtherAccount: "상대방 계정에서 채팅 기능을 사용할 수 없는 상태입니다."
cannotChatWithTheUser: "이 사용자와 채팅을 시작할 수 없습니다"
cannotChatWithTheUser: "이 유저와 채팅을 시작할 수 없습니다"
cannotChatWithTheUser_description: "채팅을 사용할 수 없는 상태이거나 상대방이 채팅을 열지 않은 상태입니다."
chatWithThisUser: "채팅하기"
thisUserAllowsChatOnlyFromFollowers: "이 사용자는 팔로워만 채팅을 할 수 있습니다."
thisUserAllowsChatOnlyFromFollowing: "이 사용자는 이 사용자가 팔로우하는 사용자만 채팅을 허용합니다."
thisUserAllowsChatOnlyFromMutualFollowing: "이 사용자는 상호 팔로우하는 사용자만 채팅을 허용합니다."
thisUserNotAllowedChatAnyone: "이 사용자는 다른 사람의 채팅을 받지 않습니다."
thisUserAllowsChatOnlyFromFollowers: "이 유저는 팔로워만 채팅을 할 수 있습니다."
thisUserAllowsChatOnlyFromFollowing: "이 유저는 이 유저가 팔로우하는 유저만 채팅을 허용합니다."
thisUserAllowsChatOnlyFromMutualFollowing: "이 유저는 상호 팔로우하는 유저만 채팅을 허용합니다."
thisUserNotAllowedChatAnyone: "이 유저는 다른 사람의 채팅을 받지 않습니다."
chatAllowedUsers: "채팅을 허용한 상대"
chatAllowedUsers_note: "내가 채팅 메시지를 보낸 상대와는 이 설정과 상관없이 채팅이 가능합니다."
_chatAllowedUsers:
everyone: "누구나"
followers: "자신의 팔로워만"
following: "자신이 팔로우한 사용자만"
mutual: "상호 팔로우한 사용자만"
following: "자신이 팔로우한 유저만"
mutual: "상호 팔로우한 유저만"
none: "아무도 허락하지 않기"
_emojiPalette:
palettes: "팔레트"
@@ -1410,7 +1416,7 @@ _settings:
soundsBanner: "클라이언트에서 재생할 소리에 대한 설정을 합니다."
timelineAndNote: "타임라인과 노트"
makeEveryTextElementsSelectable: "모든 텍스트 요소를 선택할 수 있도록 함"
makeEveryTextElementsSelectable_description: "활성화 시, 일부 동작에서 사용자의 접근성이 나빠질 수도 있습니다."
makeEveryTextElementsSelectable_description: "활성화 시, 일부 동작에서 유저의 접근성이 나빠질 수도 있습니다."
useStickyIcons: "아이콘이 스크롤을 따라가도록 하기"
showNavbarSubButtons: "내비게이션 바에 보조 버튼 표시"
ifOn: "켜져 있을 때"
@@ -1436,12 +1442,12 @@ _accountSettings:
requireSigninToViewContents: "콘텐츠 열람을 위해 로그인을 필수로 설정하기"
requireSigninToViewContentsDescription1: "자신이 작성한 모든 노트 등의 콘텐츠를 보기 위해 로그인을 필수로 설정합니다. 크롤러가 정보 수집하는 것을 방지하는 효과를 기대할 수 있습니다."
requireSigninToViewContentsDescription2: "URL 미리보기(OGP), 웹페이지에 삽입, 노트 인용을 지원하지 않는 서버에서 볼 수 없게 됩니다."
requireSigninToViewContentsDescription3: "원격 서버에 연합된 콘텐츠에는 이러한 제한이 적용되지 않을 수 있습니다."
requireSigninToViewContentsDescription3: "리모트 서버에 연합된 콘텐츠에는 이러한 제한이 적용되지 않을 수 있습니다."
makeNotesFollowersOnlyBefore: "과거 노트는 팔로워만 볼 수 있도록 설정하기"
makeNotesFollowersOnlyBeforeDescription: "이 기능이 활성화되어 있는 동안, 설정된 날짜 및 시간보다 과거 또는 설정된 시간이 지난 노트는 팔로워만 볼 수 있게 됩니다. 비활성화하면 노트의 공개 상태도 원래대로 돌아갑니다."
makeNotesHiddenBefore: "과거 노트 비공개로 전환하기"
makeNotesHiddenBeforeDescription: "이 기능이 활성화되어 있는 동안 설정한 날짜 및 시간보다 과거 또는 설정한 시간이 지난 노트는 본인만 볼 수 있게(비공개로 전환) 됩니다. 비활성화하면 노트의 공개 상태도 원래대로 돌아갑니다."
mayNotEffectForFederatedNotes: "원격 서버에 연합된 노트에는 효과가 없을 수도 있습니다."
mayNotEffectForFederatedNotes: "리모트 서버에 연합된 노트에는 효과가 없을 수도 있습니다."
mayNotEffectSomeSituations: "여기서 설정하는 제한은 모더레이션이나 리모트 서버에서 볼 때 등 일부 환경에서는 적용되지 않을 수도 있습니다."
notesHavePassedSpecifiedPeriod: "지정한 시간이 경과된 노트"
notesOlderThanSpecifiedDateAndTime: "지정된 날짜 및 시간 이전의 노트"
@@ -1482,11 +1488,11 @@ _announcement:
needConfirmationToRead: "읽음으로 표시하기 전에 확인하기"
needConfirmationToReadDescription: "활성화하면 이 공지사항을 읽음으로 표시하기 전에 확인 알림창을 띄웁니다. '모두 읽음'의 대상에서도 제외됩니다."
end: "공지에서 내리기"
tooManyActiveAnnouncementDescription: "공지사항이 너무 많을 경우, 사용자 경험에 영향을 끼칠 가능성이 있습니다. 오래된 공지사항은 아카이브하시는 것을 권장드립니다."
tooManyActiveAnnouncementDescription: "공지사항이 너무 많을 경우, 유저 경험에 영향을 끼칠 가능성이 있습니다. 오래된 공지사항은 아카이브하시는 것을 권장드립니다."
readConfirmTitle: "읽음으로 표시합니까?"
readConfirmText: "〈{title}〉의 내용을 읽음으로 표시합니다."
shouldNotBeUsedToPresentPermanentInfo: "신규 유저의 이용 경험에 악영향을 끼칠 수 있으므로, 일시적인 알림 수단으로만 사용하고 고정된 정보에는 사용을 지양하는 것을 추천합니다."
dialogAnnouncementUxWarn: "다이얼로그 형태의 알림이 동시에 2개 이상 존재하는 경우, 사용자 경험에 악영향을 끼칠 수 있으므로 신중히 결정하십시오."
dialogAnnouncementUxWarn: "다이얼로그 형태의 알림이 동시에 2개 이상 존재하는 경우, 유저 경험에 악영향을 끼칠 수 있으므로 신중히 결정하십시오."
silence: "조용히 알림"
silenceDescription: "활성화하면 공지사항에 대한 알림이 가지 않게 되며, 확인 버튼을 누를 필요가 없게 됩니다."
_initialAccountSetting:
@@ -1538,7 +1544,7 @@ _initialTutorial:
description3: "이 외에도, '리스트 타임라인'이나 '채널 타임라인' 등이 있습니다. 자세한 사항은 {link}에서 확인하실 수 있습니다."
_postNote:
title: "노트 게시 설정"
description1: "Misskey에 노트를 때에는 다양한 옵션 설정할 수 있습니다. 노트를 작성하는 화면은 이렇게 생겼습니다."
description1: "Misskey에 노트를 게시할 때에는 다양한 옵션 설정이 가능합니다. 노트를 게시할 때 쓰이는 '글 입력란'은 이렇게 생겼습니다."
_visibility:
description: "노트를 볼 수 있는 사람을 제한할 수 있습니다."
public: "모든 유저에게 공개합니다."
@@ -1558,7 +1564,7 @@ _initialTutorial:
_howToMakeAttachmentsSensitive:
title: "첨부 파일을 열람주의로 설정하려면?"
description: "서버의 가이드라인에 따라 필요한 이미지, 또는 그대로 노출되기에 부적절한 미디어는 '열람 주의'를 설정해 주세요."
tryThisFile: "이 작성 창에 첨부된 이미지를 열람 주의로 설정해 보세요!"
tryThisFile: "이 입력란에 첨부된 이미지를 열람 주의로 설정해 보세요!"
_exampleNote:
note: "낫또 뚜껑 뜯다가 실수했다…"
method: "첨부 파일을 열람 주의로 설정하려면, 해당 파일을 클릭하여 메뉴를 열고, '열람주의로 설정'을 클릭합니다."
@@ -1612,53 +1618,53 @@ _achievements:
_types:
_notes1:
title: "미스키 계정 만들었어요"
description: "첫 노트를 작성했습니다"
description: "첫 노트를 게시했다"
flavor: "Misskey에 어서 오세요!"
_notes10:
title: "몇 가지 노트"
description: "10개의 노트를 작성했습니다"
description: "10개의 노트를 게시했다"
_notes100:
title: "많은 노트"
description: "100개의 노트를 작성했습니다"
description: "100개의 노트를 게시했다"
_notes500:
title: "노트 범벅"
description: "500개의 노트를 작성했습니다"
description: "500개의 노트를 게시했다"
_notes1000:
title: "노트가 산더미"
description: "1,000개의 노트를 작성했습니다"
description: "1,000개의 노트를 게시했다"
_notes5000:
title: "솟아나는 노트"
description: "5,000개의 노트를 작성했습니다"
description: "5,000개의 노트를 게시했다"
_notes10000:
title: "슈퍼 노트"
description: "10,000개의 노트를 작성했습니다"
description: "10,000개의 노트를 게시했다"
_notes20000:
title: "노트가 필요해요"
description: "20,000개의 노트를 작성했습니다"
title: "노트가 필요해요"
description: "20,000개의 노트를 게시했다"
_notes30000:
title: "노트노트노트"
description: "30,000개의 노트를 작성했습니다"
description: "30,000개의 노트를 게시했다"
_notes40000:
title: "노트 공장"
description: "40,000개의 노트를 작성했습니다"
description: "40,000개의 노트를 게시했다"
_notes50000:
title: "노트 행성"
description: "50,000개의 노트를 작성했습니다"
description: "50,000개의 노트를 게시했다"
_notes60000:
title: "노트 퀘이사"
description: "60,000개의 노트를 작성했습니다"
description: "60,000개의 노트를 게시했다"
_notes70000:
title: "노트 블랙홀"
description: "70,000개의 노트를 작성했습니다"
description: "70,000개의 노트를 게시했다"
_notes80000:
title: "노트 은하"
description: "80,000개의 노트를 작성했습니다"
description: "80,000개의 노트를 게시했다"
_notes90000:
title: "노트 우주"
description: "90,000개의 노트를 작성했습니다"
description: "90,000개의 노트를 게시했다"
_notes100000:
title: "ALL YOUR NOTE ARE BELONG TO US"
description: "100,000개의 노트를 작성했습니다"
description: "100,000개의 노트를 게시했다"
flavor: "이렇게나 쓸 게 있어요?"
_login3:
title: "초보자 I"
@@ -1683,181 +1689,181 @@ _achievements:
flavor: "그 유저, 미스키스트이다"
_login200:
title: "단골 I"
description: "총 200일간 로그인했습니다"
description: "총 로그인한 날이 200일"
_login300:
title: "단골 II"
description: "총 300일간 로그인했습니다"
description: "총 로그인한 날이 300일"
_login400:
title: "단골 III"
description: "총 400일간 로그인했습니다"
description: "총 로그인한 날이 400일"
_login500:
title: "베테랑 I"
description: "총 500일간 로그인했습니다"
description: "총 로그인한 날이 500일"
flavor: "제군, 나는 노트가 좋다"
_login600:
title: "베테랑 II"
description: "총 600일간 로그인했습니다"
description: "총 로그인한 날이 600일"
_login700:
title: "베테랑 III"
description: "총 700일간 로그인했습니다"
description: "총 로그인한 날이 700일"
_login800:
title: "노트 마스터 I"
description: "총 800일간 로그인했습니다"
description: "총 로그인한 날이 800일"
_login900:
title: "노트 마스터 II"
description: "총 900일간 로그인했습니다"
description: "총 로그인한 날이 900일"
_login1000:
title: "노트 마스터 III"
description: "총 1,000일간 로그인했습니다"
description: "총 로그인한 날이 1,000일"
flavor: "Misskey를 사용해 주셔서 감사합니다!"
_noteClipped1:
title: "클립할 수밖에 없었어"
description: "처음으로 노트를 클립했습니다"
description: "처음으로 노트를 클립했다"
_noteFavorited1:
title: "별을 바라보는 자"
description: "처음으로 노트를 즐겨찾기했습니다"
description: "처음으로 노트를 즐겨찾기했다"
_myNoteFavorited1:
title: "별을 원하는 자"
description: "다른 사람이 당신의 노트를 즐겨찾기했습니다"
description: "다른 사람이 당신의 노트를 즐겨찾기했다"
_profileFilled:
title: "준비 완료"
description: "프로필 설정을 완료했습니다"
description: "프로필 설정을 완료했다"
_markedAsCat:
title: "나는 고양이다냥!"
description: "계정을 고양이로 설정했습니다냥"
description: "계정을 고양이로 설정했다냥"
flavor: "냐냐냐냐냐냐아아아아앙!"
_following1:
title: "첫 팔로우"
description: "사용자를 처음으로 팔로우했습니다"
description: "유저를 처음으로 팔로우했다"
_following10:
title: "팔로우, 팔로우"
description: "10명의 사용자를 팔로우했습니다"
description: "10명의 유저를 팔로우했다"
_following50:
title: "친구 잔뜩"
description: "50명의 사용자를 팔로우했습니다"
description: "50명의 유저를 팔로우했다"
_following100:
title: "주소록 한 권으론 부족해"
description: "100명의 사용자를 팔로우했습니다"
description: "100명의 유저를 팔로우했다"
_following300:
title: "친구가 넘쳐나"
description: "300명의 사용자를 팔로우했습니다"
description: "300명의 유저를 팔로우했다"
_followers1:
title: "첫 팔로워"
description: "사용자가 처음으로 팔로잉했습니다"
description: "유저가 처음으로 팔로잉했다"
_followers10:
title: "팔로우 미!"
description: "10명의 사용자가 팔로우했습니다"
description: "10명의 유저가 팔로우했다"
_followers50:
title: "이곳저곳"
description: "50명의 사용자가 팔로우했습니다"
description: "50명의 유저가 팔로우했다"
_followers100:
title: "인기왕"
description: "100명의 사용자가 팔로우했습니다"
description: "100명의 유저가 팔로우했다"
_followers300:
title: "줄 좀 서봐요"
description: "100명의 사용자가 팔로우했습니다"
description: "100명의 유저가 팔로우했다"
_followers500:
title: "기지국"
description: "500명의 사용자가 팔로우했습니다"
description: "500명의 유저가 팔로우했다"
_followers1000:
title: "유명인사"
description: "1,000명의 사용자가 팔로우했습니다"
description: "1,000명의 유저가 팔로우했다"
_collectAchievements30:
title: "도전 과제 콜렉터"
description: "30개의 도전과제를 획득했습니다"
description: "30개의 도전과제를 획득했다"
_viewAchievements3min:
title: "저 도전과제 좋아해요"
description: "도전 과제 목록을 3분 이상 쳐다봤습니다"
description: "도전 과제 목록을 3분 이상 쳐다봤다"
_iLoveMisskey:
title: "I Love Misskey"
description: "\"I ❤ #Misskey\"를 포스트했습니다"
description: "\"I ❤ #Misskey\"를 게시했다"
flavor: "Misskey를 이용해 주셔서 감사합니다! ― 개발 팀"
_foundTreasure:
title: "보물찾기"
description: "숨겨진 보물을 발견했습니다"
description: "숨겨진 보물을 발견했다"
_client30min:
title: "잠시 쉬어요"
description: "클라이언트를 시작하고 30분이 경과하였습니다"
description: "클라이언트를 시작하고 30분이 경과다"
_client60min:
title: "No \"Miss\" in Misskey"
description: "클라이언트를 시작하고 60분이 경과하였습니다"
description: "클라이언트를 시작하고 60분이 경과다"
_noteDeletedWithin1min:
title: "있었는데요 없었습니다"
description: "노트를 포스트한 후 1분 이내에 삭제했습니다"
description: "노트를 게시한 후 1분 이내에 삭제했다"
_postedAtLateNight:
title: "올빼미"
description: "한밤중에 노트를 포스트했습니다"
description: "한밤중에 노트를 게시했다"
flavor: "잠 좀 자세요. 걱정돼요."
_postedAt0min0sec:
title: "정각"
description: "0분 0초 정각에 노트를 작성했습니다"
description: "0분 0초 정각에 노트를 게시했다"
flavor: "째깍 째깍 째깍 땡!"
_selfQuote:
title: "혼잣말"
description: "자기 노트를 인용했습니다"
description: "자기 노트를 인용했다"
_htl20npm:
title: "타임라인 폭주 중"
description: "1분 사이에 홈 타임라인에 노트가 20개 넘게 생성되었습니다"
description: "1분 사이에 홈 타임라인에 노트가 20개 넘게 생성되었다"
_viewInstanceChart:
title: "애널리스트"
description: "서버의 차트를 열었습니다"
description: "서버의 차트를 열었다"
_outputHelloWorldOnScratchpad:
title: "Hello, world!"
description: "스크래치패드에서 hello world를 출력했습니다"
description: "스크래치패드에서 hello world를 출력했다"
_open3windows:
title: "멀티 윈도우"
description: "3개 이상의 창을 열었습니다"
description: "3개 이상의 창을 열었다"
_driveFolderCircularReference:
title: "순환 참조"
description: "드라이브 폴더에 스스로를 넣게 했습니다"
description: "드라이브 폴더에 스스로를 넣게 했다"
_reactWithoutRead:
title: "읽고 답하긴 하시는 건가요?"
description: "100자가 넘는 노트를 작성한 지 3초 안에 반응했어요"
description: "100자가 넘는 노트를 게시한 지 3초 안에 리액션했다"
_clickedClickHere:
title: "여기를 누르세요"
description: "여기를 눌렀습니다"
title: "여길 눌러보세요"
description: "여기를 눌렀다"
_justPlainLucky:
title: "그냥 운이 좋았어"
description: "매 10초마다 0.01%의 확률로 달성됩니다"
description: "매 10초마다 0.01%의 확률로 달성다"
_setNameToSyuilo:
title: "신 콤플렉스"
description: "이름을 syuilo로 설정했습니다"
description: "이름을 syuilo로 설정했다"
_passedSinceAccountCreated1:
title: "1주년"
description: "계정을 생성하고 1년이 지났습니다"
description: "계정을 생성하고 1년이 지났다"
_passedSinceAccountCreated2:
title: "2주년"
description: "계정을 생성하고 2년이 지났습니다"
description: "계정을 생성하고 2년이 지났다"
_passedSinceAccountCreated3:
title: "3주년"
description: "계정을 생성하고 3년이 지났습니다"
description: "계정을 생성하고 3년이 지났다"
_loggedInOnBirthday:
title: "생일 축하합니다!"
description: "생일에 로그인했습니다"
description: "생일에 로그인했다"
_loggedInOnNewYearsDay:
title: "새해 복 많이 받으세요"
description: "새해 첫 날에 로그인했습니다"
description: "새해 첫 날에 로그인했다"
flavor: "올해에도 저희 서버에 관심을 가져 주셔서 감사합니다"
_cookieClicked:
title: "쿠키를 클릭하는 게임"
description: "쿠키를 클릭했습니다"
description: "쿠키를 클릭했다"
flavor: "소프트웨어 착각하지 않으셨나요?"
_brainDiver:
title: "Brain Diver"
description: "Brain Diver로의 링크를 첨부했습니다"
description: "Brain Diver로의 링크를 첨부했다"
flavor: "Misskey-Misskey La-Tu-Ma"
_smashTestNotificationButton:
title: "테스트 과잉"
description: "매우 짧은 시간 안에 알림 테스트를 여러 번 수행했습니다"
description: "매우 짧은 시간 안에 알림 테스트를 여러 번 수행했다"
_tutorialCompleted:
title: "Misskey 입문자 과정 수료증"
description: "튜토리얼을 완료했습니다"
description: "튜토리얼을 완료했다"
_bubbleGameExplodingHead:
title: "🤯"
description: "버블 게임에서 가장 큰 물건을 내놓았다"
_bubbleGameDoubleExplodingHead:
title: "더블 🤯"
description: "버블게임에서 가장 큰 물건 2개를 동시에 내놓았다."
description: "버블게임에서 가장 큰 물건 2개를 동시에 내놓았다"
flavor: "이 정도만 도시락통에 🤯 🤯 조금만 더"
_role:
new: "새 역할 생성"
@@ -1867,7 +1873,7 @@ _role:
permission: "역할 권한"
descriptionOfPermission: "<b>조정자</b>는 기본적인 조정 작업을 진행할 수 있습니다.\n<b>관리자</b>는 서버의 모든 설정을 변경할 수 있습니다."
assignTarget: "할당 대상"
descriptionOfAssignTarget: "<b>수동</b>을 선택하면 누가 이 역할에 포함되는지를 수동으로 관리할 수 있습니다.\n<b>조건부</b>를 선택하면 조건을 설정해 일치하는 사용자를 자동으로 포함되게 할 수 있습니다."
descriptionOfAssignTarget: "<b>수동</b>을 선택하면 누가 이 역할에 포함되는지를 수동으로 관리할 수 있습니다.\n<b>조건부</b>를 선택하면 조건을 설정해 일치하는 유저를 자동으로 포함되게 할 수 있습니다."
manual: "수동"
manualRoles: "수동 역할"
conditional: "조건부"
@@ -1875,7 +1881,7 @@ _role:
condition: "조건"
isConditionalRole: "조건부 역할입니다."
isPublic: "역할 공개"
descriptionOfIsPublic: "역할에 할당된 사용자를 누구나 볼 수 있습니다. 또한 사용자 프로필에 이 역할이 표시됩니다."
descriptionOfIsPublic: "역할에 할당된 유저를 누구나 볼 수 있습니다. 또한 유저 프로필에 이 역할이 표시됩니다."
options: "옵션"
policies: "정책"
baseRole: "기본 역할"
@@ -1888,10 +1894,10 @@ _role:
descriptionOfIsExplorable: "활성화하면 역할 타임라인을 공개합니다. 비활성화 시 타임라인이 공개되지 않습니다."
displayOrder: "표시 순서"
descriptionOfDisplayOrder: "값이 클 수록 UI에서 먼저 표시됩니다."
preserveAssignmentOnMoveAccount: "마이그레이션 대상 계정에도 할당 상태 전달"
preserveAssignmentOnMoveAccount_description: "켜면 이 역할이 부여된 계정이 마이그레이션될 때 마이그레이션 대상 계정에도 이 역할이 승계됩니다."
preserveAssignmentOnMoveAccount: "이전 대상 계정에도 할당 상태 전달"
preserveAssignmentOnMoveAccount_description: "켜면 이 역할이 부여된 계정이 이전될 때 마이그레이션 대상 계정에도 이 역할이 승계됩니다."
canEditMembersByModerator: "모더레이터의 역할 수정 허용"
descriptionOfCanEditMembersByModerator: "이 옵션을 켜면 모더레이터도 이 역할에 사용자를 할당하거나 삭제할 수 있습니다. 꺼져 있으면 관리자만 할당이 가능합니다."
descriptionOfCanEditMembersByModerator: "이 옵션을 켜면 모더레이터도 이 역할에 유저를 할당하거나 삭제할 수 있습니다. 꺼져 있으면 관리자만 할당이 가능합니다."
priority: "우선순위"
_priority:
low: "낮음"
@@ -1917,8 +1923,8 @@ _role:
webhookMax: "만들 수 있는 Webhook 수"
clipMax: "만들 수 있는 클립 수"
noteEachClipsMax: "클립에 넣을 수 있는 노트 수"
userListMax: "만들 수 있는 사용자 리스트 수"
userEachUserListsMax: "사용자 리스트에 넣을 수 있는 사용자 수"
userListMax: "만들 수 있는 유저 리스트 수"
userEachUserListsMax: "유저 리스트에 넣을 수 있는 유저 수"
rateLimitFactor: "요청 빈도 제한"
descriptionOfRateLimitFactor: "작을수록 제한이 완화되고, 클수록 제한이 강화됩니다."
canHideAds: "광고 숨기기"
@@ -1930,24 +1936,24 @@ _role:
canImportFollowing: "팔로우 가져오기 허용"
canImportMuting: "뮤트 목록 가져오기 허용"
canImportUserLists: "리스트 목록 가져오기 허용"
canChat: "채팅을 허락"
chatAvailability: "채팅을 허락"
_condition:
roleAssignedTo: "수동 역할에 이미 할당됨"
isLocal: "로컬 사용자"
isRemote: "원격 사용자"
isCat: "고양이 사용자"
isBot: "봇 사용자"
isSuspended: "정지된 사용자"
isLocked: "잠금 계정 사용자"
isExplorable: "‘계정을 쉽게 발견하도록 하기’를 활성화한 사용자"
isLocal: "로컬 유저"
isRemote: "리모트 유저"
isCat: "고양이 유저"
isBot: "봇 유저"
isSuspended: "정지된 유저"
isLocked: "잠금 계정 유저"
isExplorable: "‘계정을 쉽게 발견하도록 하기’를 활성화한 유저"
createdLessThan: "가입한 지 다음 일수 이내인 유저"
createdMoreThan: "가입한 지 다음 일수 이상인 유저"
followersLessThanOrEq: "팔로워 수가 다음 이하인 유저"
followersMoreThanOrEq: "팔로워 수가 다음보다 많은 사용자"
followersMoreThanOrEq: "팔로워 수가 다음보다 많은 유저"
followingLessThanOrEq: "팔로잉 수가 다음 이하인 유저"
followingMoreThanOrEq: "팔로잉 수가 다음보다 많은 사용자"
followingMoreThanOrEq: "팔로잉 수가 다음보다 많은 유저"
notesLessThanOrEq: "노트 수가 다음 이하인 유저"
notesMoreThanOrEq: "노트 수가 다음보다 많은 사용자"
notesMoreThanOrEq: "노트 수가 다음보다 많은 유저"
and: "다음을 모두 만족"
or: "다음을 하나라도 만족"
not: "다음을 만족하지 않음"
@@ -1989,7 +1995,7 @@ _ad:
adsSettings: "광고 표시 설정"
notesPerOneAd: "실시간으로 갱신되는 타임라인에서 광고를 노출시키는 간격 (노트 당)"
setZeroToDisable: "0으로 지정하면 실시간 타임라인에서의 광고를 비활성화합니다"
adsTooClose: "광고의 표시 간격이 매우 작아, 사용자 경험에 부정적인 영향을 미칠 수 있습니다."
adsTooClose: "광고의 표시 간격이 매우 작아, 유저 경험에 부정적인 영향을 미칠 수 있습니다."
_forgotPassword:
enterEmail: "여기에 계정에 등록한 메일 주소를 입력해 주세요. 입력한 메일 주소로 비밀번호 재설정 링크를 발송합니다."
ifNoEmail: "메일 주소를 등록하지 않은 경우, 관리자에 문의해 주십시오."
@@ -2244,7 +2250,7 @@ _permissions:
"write:pages": "페이지를 수정합니다"
"read:page-likes": "페이지의 좋아요를 확인합니다"
"write:page-likes": "페이지에 좋아요를 추가하거나 취소합니다"
"read:user-groups": "사용자 그룹 보기"
"read:user-groups": "유저 그룹 보기"
"write:user-groups": "유저 그룹을 만들거나, 초대하거나, 이름을 변경하거나, 양도하거나, 삭제합니다"
"read:channels": "채널을 보기"
"write:channels": "채널을 추가하거나 삭제합니다"
@@ -2256,23 +2262,23 @@ _permissions:
"write:flash": "Play를 조작합니다"
"read:flash-likes": "Play의 좋아요를 봅니다"
"write:flash-likes": "Play의 좋아요를 조작합니다"
"read:admin:abuse-user-reports": "사용자 신고 보기"
"write:admin:delete-account": "사용자 계정 삭제하기"
"write:admin:delete-all-files-of-a-user": "모든 사용자 파일 삭제하기"
"read:admin:abuse-user-reports": "유저 신고 보기"
"write:admin:delete-account": "유저 계정 삭제하기"
"write:admin:delete-all-files-of-a-user": "모든 유저 파일 삭제하기"
"read:admin:index-stats": "데이터베이스 색인 정보 보기"
"read:admin:table-stats": "데이터베이스 테이블 정보 보기"
"read:admin:user-ips": "사용자 IP 주소 보기"
"read:admin:user-ips": "유저 IP 주소 보기"
"read:admin:meta": "인스턴스 메타데이터 보기"
"write:admin:reset-password": "사용자 비밀번호 재설정하기"
"write:admin:resolve-abuse-user-report": "사용자 신고 처리하기"
"write:admin:reset-password": "유저 비밀번호 재설정하기"
"write:admin:resolve-abuse-user-report": "유저 신고 처리하기"
"write:admin:send-email": "이메일 보내기"
"read:admin:server-info": "서버 정보 보기"
"read:admin:show-moderation-log": "조정 기록 보기"
"read:admin:show-user": "사용자 개인정보 보기"
"write:admin:suspend-user": "사용자 정지하기"
"write:admin:unset-user-avatar": "사용자 아바타 삭제하기"
"write:admin:unset-user-banner": "사용자 배너 삭제하기"
"write:admin:unsuspend-user": "사용자 정지 해제하기"
"read:admin:show-user": "유저 개인정보 보기"
"write:admin:suspend-user": "유저 정지하기"
"write:admin:unset-user-avatar": "유저 아바타 삭제하기"
"write:admin:unset-user-banner": "유저 배너 삭제하기"
"write:admin:unsuspend-user": "유저 정지 해제하기"
"write:admin:meta": "인스턴스 메타데이터 수정하기"
"write:admin:user-note": "조정 기록 수정하기"
"write:admin:roles": "역할 수정하기"
@@ -2286,15 +2292,15 @@ _permissions:
"write:admin:avatar-decorations": "아바타 꾸미기 수정하기"
"read:admin:avatar-decorations": "아바타 꾸미기 보기"
"write:admin:federation": "연합 정보 수정하기"
"write:admin:account": "사용자 계정 수정하기"
"read:admin:account": "사용자 정보 보기"
"write:admin:account": "유저 계정 수정하기"
"read:admin:account": "유저 정보 보기"
"write:admin:emoji": "이모지 수정하기"
"read:admin:emoji": "이모지 보기"
"write:admin:queue": "작업 대기열 수정하기"
"read:admin:queue": "작업 대기열 정보 보기"
"write:admin:promo": "홍보 기록 수정하기"
"write:admin:drive": "사용자 드라이브 수정하기"
"read:admin:drive": "사용자 드라이브 정보 보기"
"write:admin:drive": "유저 드라이브 수정하기"
"read:admin:drive": "유저 드라이브 정보 보기"
"read:admin:stream": "관리자용 Websocket API 사용하기"
"write:admin:ad": "광고 수정하기"
"read:admin:ad": "광고 보기"
@@ -2316,7 +2322,7 @@ _auth:
callback: "앱으로 돌아갑니다"
accepted: "접근 권한이 부여되었습니다."
denied: "접근이 거부되었습니다"
scopeUser: "다음 사용자로 활동하고 있습니다."
scopeUser: "다음 유저로 활동하고 있습니다."
pleaseLogin: "어플리케이션의 접근을 허가하려면 로그인하십시오."
byClickingYouWillBeRedirectedToThisUrl: "접근을 허용하면 자동으로 다음 URL로 이동합니다."
_antennaSources:
@@ -2353,7 +2359,7 @@ _widgets:
postForm: "글 입력란"
slideshow: "슬라이드 쇼"
button: "버튼"
onlineUsers: "온라인 사용자"
onlineUsers: "온라인 유저"
jobQueue: "작업 대기열"
serverMetric: "서버 통계"
aiscript: "AiScript 콘솔"
@@ -2363,7 +2369,8 @@ _widgets:
_userList:
chooseList: "리스트 선택"
clicker: "클리커"
birthdayFollowings: "오늘이 생일인 사용자"
birthdayFollowings: "오늘이 생일인 유저"
chat: "채팅"
_cw:
hide: "숨기기"
show: "더 보기"
@@ -2415,7 +2422,7 @@ _postForm:
f: "작성해주시길 기다리고 있어요..."
_profile:
name: "이름"
username: "사용자 이름"
username: "유저명"
description: "자기소개"
youCanIncludeHashtags: "해시 태그를 포함할 수 있습니다."
metadata: "추가 정보"
@@ -2446,7 +2453,7 @@ _charts:
apRequest: "요청"
usersIncDec: "유저 수 증감"
usersTotal: "유저 수 합계"
activeUsers: "활동 사용자 수"
activeUsers: "활동 유저 수"
notesIncDec: "노트 수 증감"
localNotesIncDec: "로컬 노트 수 증감"
remoteNotesIncDec: "리모트 노트 수 증감"
@@ -2457,8 +2464,8 @@ _charts:
storageUsageTotal: "스토리지 사용량 합계"
_instanceCharts:
requests: "요청"
users: "사용자 수 차이"
usersTotal: "누적 사용자 수"
users: "유저 수 차이"
usersTotal: "누적 유저 수"
notes: "노트 수 증감"
notesTotal: "누적 노트 수"
ff: "팔로잉/팔로워 증감"
@@ -2561,7 +2568,7 @@ _notification:
checkNotificationBehavior: "알림 표시를 체크하기"
sendTestNotification: "테스트 알림 보내기"
notificationWillBeDisplayedLikeThis: "알림이 이렇게 표시됩니다"
reactedBySomeUsers: "{n}명이 반응했습니다"
reactedBySomeUsers: "{n}명이 리액션했습니다"
likedBySomeUsers: "{n}명이 좋아요를 했습니다"
renotedBySomeUsers: "{n}명이 리노트했습니다"
followedBySomeUsers: "{n}명에게 팔로우됨"
@@ -2572,18 +2579,18 @@ _notification:
createTokenDescription: "만약 기억이 나지 않는다면 '{text}'를 통해 액세스 토큰을 삭제해 주세요."
_types:
all: "전부"
note: "사용자의 새 글"
note: "유저의 새 글"
follow: "팔로잉"
mention: "멘션"
reply: "답글"
renote: "리노트"
quote: "인용"
reaction: "반응"
reaction: "리액션"
pollEnded: "투표가 종료됨"
receiveFollowRequest: "팔로우 요청을 받았을 때"
followRequestAccepted: "팔로우 요청이 승인되었을 때"
roleAssigned: "역할이 부여 됨"
chatRoomInvitationReceived: "채팅 룸에 초대받았습니다"
roleAssigned: "역할이 부여됨"
chatRoomInvitationReceived: "채팅 룸에 초대받"
achievementEarned: "도전 과제 획득"
exportCompleted: "추출을 성공함"
login: "로그인"
@@ -2630,6 +2637,7 @@ _deck:
mentions: "받은 멘션"
direct: "다이렉트"
roleTimeline: "역할 타임라인"
chat: "채팅"
_dialog:
charactersExceeded: "최대 글자수를 초과하였습니다! 현재 {current} / 최대 {max}"
charactersBelow: "최소 글자수 미만입니다! 현재 {current} / 최소 {min}"
@@ -2671,10 +2679,10 @@ _abuseReport:
mail: "이메일"
webhook: "Webhook"
_captions:
mail: "모더레이터 권한을 가진 사용자의 이메일 주소에 알림을 보냅니다 (신고를 받은 때에만)"
mail: "모더레이터 권한을 가진 유저의 이메일 주소에 알림을 보냅니다 (신고를 받은 때에만)"
webhook: "지정한 SystemWebhook에 알림을 보냅니다 (신고를 받은 때와 해결했을 때에 송신)"
keywords: "키워드"
notifiedUser: "알릴 사용자"
notifiedUser: "알릴 유저"
notifiedWebhook: "사용할 Webhook"
deleteConfirm: "수신자를 삭제하시겠습니까?"
_moderationLogTypes:
@@ -2693,11 +2701,11 @@ _moderationLogTypes:
deleteDriveFile: "파일 삭제"
deleteNote: "노트 삭제"
createGlobalAnnouncement: "전역 공지사항 생성"
createUserAnnouncement: "사용자 공지사항 만들기"
createUserAnnouncement: "유저에게 공지사항 만들기"
updateGlobalAnnouncement: "모든 공지사항 수정"
updateUserAnnouncement: "사용자 공지사항 수정"
updateUserAnnouncement: "유저의 공지사항 수정"
deleteGlobalAnnouncement: "모든 공지사항 삭제"
deleteUserAnnouncement: "사용자 공지사항 삭제"
deleteUserAnnouncement: "유저의 공지사항 삭제"
resetPassword: "비밀번호 재설정"
suspendRemoteInstance: "리모트 서버를 정지"
unsuspendRemoteInstance: "리모트 서버의 정지를 해제"
@@ -2725,7 +2733,7 @@ _moderationLogTypes:
deleteAccount: "계정을 삭제"
deletePage: "페이지를 삭제"
deleteFlash: "Play를 삭제"
deleteGalleryPost: "갤러리 포스트를 삭제"
deleteGalleryPost: "갤러리 게시물을 삭제"
deleteChatRoom: "채팅 룸 삭제"
updateProxyAccountDescription: "프록시 계정의 설명 업데이트"
_fileViewer:
@@ -2939,7 +2947,7 @@ _embedCodeGen:
_selfXssPrevention:
warning: "경고"
title: "“이 화면에 뭔가를 붙여넣어라\"는 것은 모두 사기입니다."
description1: "여기에 무언가를 붙여넣으면 악의적인 사용자에게 계정을 탈취당하거나 개인정보를 도용당할 수 있습니다."
description1: "여기에 무언가를 붙여넣으면 악의적인 유저에게 계정을 탈취당하거나 개인정보를 도용당할 수 있습니다."
description2: "붙여 넣으려는 항목이 무엇인지 정확히 이해하지 못하는 경우, %c지금 바로 작업을 중단하고 이 창을 닫으십시오."
description3: "자세한 내용은 여기를 확인해 주세요. {link}"
_followRequest:
@@ -2972,8 +2980,8 @@ _captcha:
title: "CAPTCHA 검증을 실패했습니다."
text: "설정이 올바른지 다시 한 번 확인해보세요."
_unknown:
title: "CAPTCHA 에러"
text: "알 수 없는 에러가 발생했습니다."
title: "CAPTCHA 오류"
text: "알 수 없는 오류가 발생했습니다."
_bootErrors:
title: "로딩이 실패함"
serverError: "잠시 기다렸다가 다시 로드해도 여전히 문제가 해결되지 않으면 아래 Error ID와 함께 서버 관리자에게 연락해 주세요."
@@ -2990,7 +2998,7 @@ _search:
searchScopeAll: "전체"
searchScopeLocal: "로컬"
searchScopeServer: "서버 지정"
searchScopeUser: "사용자 지정"
searchScopeUser: "유저 지정"
pleaseEnterServerHost: "서버의 호스트를 입력해 주세요."
pleaseSelectUser: "유저를 선택해주세요"
serverHostPlaceholder: "예: misskey.example.com"
+458 -1
View File
@@ -118,6 +118,8 @@ renotedToX: "Renoted naar {name}"
cantRenote: "Dit bericht kan niet worden herdeeld"
cantReRenote: "Een herdeling kan niet worden herdeeld"
quote: "Quote"
inChannelRenote: "Alleen-kanaal Renote"
inChannelQuote: "Alleen-kanaal Citaat"
renoteToChannel: "Renote naar kanaal"
renoteToOtherChannel: "Renote naar ander kanaal"
pinnedNote: "Vastgemaakte notitie"
@@ -143,6 +145,8 @@ unmarkAsSensitive: "Geen NSFW"
enterFileName: "Invoeren bestandsnaam"
mute: "Dempen"
unmute: "Stop dempen"
renoteMute: "Renotes dempen"
renoteUnmute: "Dempen Renotes opheffen"
block: "Blokkeren"
unblock: "Deblokkeren"
suspend: "Opschorten"
@@ -152,7 +156,10 @@ unblockConfirm: "Ben je zeker dat je deze account wil blokkeren?"
suspendConfirm: "Ben je zeker dat je deze account wil suspenderen?"
unsuspendConfirm: "Ben je zeker dat je deze account wil opnieuw aanstellen?"
selectList: "Kies een lijst."
editList: "Lijst bewerken"
selectChannel: "Kanaal selecteren"
selectAntenna: "Kies een antenne"
editAntenna: "Antenne bewerken"
createAntenna: "Antenne aanmaken"
selectWidget: "Kies een widget"
editWidgets: "Bewerk widgets"
@@ -166,6 +173,9 @@ addEmoji: "Toevoegen emoji"
settingGuide: "Aanbevolen instellingen"
cacheRemoteFiles: "Externe bestanden cachen"
cacheRemoteFilesDescription: "Als deze instelling uitgeschakeld is worden bestanden altijd direct van remote servers geladen. Hiermee wordt opslagruimte bespaard, maar doordat er geen thumbnails worden gegenereerd, zal netwerkverkeer toenemen."
youCanCleanRemoteFilesCache: "Klik op de 🗑️ knop in de bestandsbeheerweergave om de cache te wissen."
cacheRemoteSensitiveFiles: "Gevoelige bestanden van externe instances in de cache bewaren"
cacheRemoteSensitiveFilesDescription: "Als deze instelling is uitgeschakeld, worden gevoelige bestanden op afstand direct vanuit de instantie op afstand geladen zonder caching."
flagAsBot: "Markeer dit account als een robot."
flagAsBotDescription: "Als dit account van een programma wordt beheerd, zet deze vlag aan. Het aanzetten helpt andere ontwikkelaars om bijvoorbeeld onbedoelde feedback loops te doorbreken of om Misskey meer geschikt te maken."
flagAsCat: "Markeer dit account als een kat."
@@ -174,6 +184,7 @@ flagShowTimelineReplies: "Toon antwoorden op de tijdlijn."
flagShowTimelineRepliesDescription: "Als je dit vlag aanzet, toont de tijdlijn ook antwoorden op andere en niet alleen jouw eigen notities."
autoAcceptFollowed: "Accepteer verzoeken om jezelf te volgen vanzelf als je de verzoeker al volgt."
addAccount: "Account toevoegen"
reloadAccountsList: "Accountlijst opnieuw laden"
loginFailed: "Aanmelding mislukt."
showOnRemote: "Toon op de externe instantie."
continueOnRemote: "Verder op remote server"
@@ -205,6 +216,7 @@ perHour: "Per uur"
perDay: "Per dag"
stopActivityDelivery: "Stop met versturen activiteiten"
blockThisInstance: "Blokkeer deze server"
silenceThisInstance: "Instantie dempen"
mediaSilenceThisInstance: "Media van deze server dempen"
operations: "Verwerkingen"
software: "Software"
@@ -225,6 +237,7 @@ clearCachedFiles: "Cache opschonen"
clearCachedFilesConfirm: "Weet je zeker dat je alle externe bestanden in de cache wilt verwijderen?"
blockedInstances: "Geblokkeerde servers"
blockedInstancesDescription: "Maak een lijst van de servers die moeten worden geblokkeerd, gescheiden door regeleinden. Geblokkeerde servers kunnen niet meer communiceren met deze server."
silencedInstances: "Gedempte instanties"
silencedInstancesDescription: "Geef de hostnamen van de servers die je wil dempen op, elk op hun eigen regel. Alle accounts die bij de opgegeven servers horen worden als gedempt behandeld, kunnen alleen maar volgverzoeken maken, en kunnen lokale accounts niet vermelden als ze niet gevolgd worden. Geblokkeerde servers worden hier niet door beïnvloed."
mediaSilencedInstances: "Media-gedempte servers"
mediaSilencedInstancesDescription: "Geef de hostnamen van de servers die je wil media-dempen op, elk op hun eigen regel. Alle accounts die bij de opgegeven servers horen worden als gedempt behandeld, en kunnen geen eigen emojis gebruiken. Geblokkeerde servers worden hier niet door beïnvloed."
@@ -291,6 +304,10 @@ noMoreHistory: "Er is geen verdere geschiedenis"
startChat: "Chat starten"
nUsersRead: "gelezen door {n}"
agreeTo: "Ik stem in met {0}"
agree: "Akkoord"
agreeBelow: "Ik ga akkoord met de volgende"
basicNotesBeforeCreateAccount: "Belangrijke informatie"
termsOfService: "Gebruiksvoorwaarden"
start: "Aan de slag"
home: "Startpagina"
remoteUserCaution: "Aangezien deze gebruiker van een externe server afkomstig is, kan de weergegeven informatie onvolledig zijn."
@@ -336,6 +353,7 @@ copyUrl: "URL kopiëren"
rename: "Hernoemen"
avatar: "Avatar"
banner: "Banner"
displayOfSensitiveMedia: "Weergave van gevoelige media"
whenServerDisconnected: "Wanneer de verbinding met de server wordt onderbroken"
disconnectedFromServer: "Verbinding met de server onderbroken."
reload: "Verversen"
@@ -373,7 +391,10 @@ bannerUrl: "Banner URL"
backgroundImageUrl: "URL afbeelding"
basicInfo: "Basisinformatie"
pinnedUsers: "Vastgeprikte gebruikers"
pinnedUsersDescription: "Een lijst met gebruikersnamen, gescheiden door regeleinden, die moet worden vastgemaakt in het tabblad “Verkennen”"
pinnedPages: "Vastgeprikte pagina's"
pinnedPagesDescription: "Voer de paden in van de Pagina's die je aan de bovenste pagina van deze instantie wilt vastmaken, gescheiden door regeleinden."
pinnedClipId: "ID van de clip die moet worden vastgepind"
pinnedNotes: "Vastgemaakte notitie"
hcaptcha: "hCaptcha"
enableHcaptcha: "Inschakelen hCaptcha"
@@ -392,6 +413,7 @@ turnstile: "Tourniquet"
enableTurnstile: "Inschakelen tourniquet"
turnstileSiteKey: "Site sleutel"
turnstileSecretKey: "Geheime sleutel"
avoidMultiCaptchaConfirm: "Het gebruik van meerdere Captcha-systemen kan interferentie tussen deze systemen veroorzaken. Wil je de andere Captcha-systemen die momenteel actief zijn uitschakelen? Als je wilt dat ze ingeschakeld blijven, druk dan op annuleren."
antennas: "Antennes"
manageAntennas: "Antennes beheren"
name: "Naam"
@@ -399,6 +421,13 @@ antennaSource: "Bron antenne"
antennaKeywords: "Sleutelwoorden"
antennaExcludeKeywords: "Blokkeerwoorden"
antennaExcludeBots: "Bot-accounts uitsluiten"
antennaKeywordsDescription: "Scheid met spaties voor een EN-voorwaarde of met regeleinden voor een OF-voorwaarde."
notifyAntenna: "Houd een notificatie bij nieuwe notities"
withFileAntenna: "Alleen notities met bestanden"
excludeNotesInSensitiveChannel: "Sluit notities uit van gevoelige kanalen"
enableServiceworker: "Activeer pushmeldingen in de browser"
antennaUsersDescription: "Lijst één gebruikersnaam per regel"
caseSensitive: "Hoofdlettergevoelig"
withReplies: "Antwoorden toevoegen"
connectedTo: "De volgende accounts zijn verbonden"
notesAndReplies: "Berichten en reacties"
@@ -419,18 +448,30 @@ about: "Over"
aboutMisskey: "Over Misskey"
administrator: "Beheerder"
token: "Token"
2fa: "Twee factor authenticatie"
setupOf2fa: "Tweefactorauthenticatie instellen"
totp: "Verificatie-App"
totpDescription: "Log in via de verificatie-app met het eenmalige wachtwoord"
moderator: "Moderator"
moderation: "Moderatie"
moderationNote: "Moderatienotitie"
moderationNoteDescription: "Voer hier notities in. Deze zijn alleen zichtbaar voor de moderators."
addModerationNote: "Moderatienotitie toevoegen"
moderationLogs: "Moderatieprotocollen"
nUsersMentioned: "Vermeld door {n} gebruikers"
securityKeyAndPasskey: "Beveiligings- en pasjessleutels"
securityKey: "Beveiligingssleutel"
lastUsed: "Laatst gebruikt"
lastUsedAt: "Laatst gebruikt: {t}"
unregister: "Uitschrijven"
passwordLessLogin: "Inloggen zonder wachtwoord"
passwordLessLoginDescription: "Maakt aanmelden zonder wachtwoord mogelijk met een beveiligingstoken of -wachtsleutel"
resetPassword: "Wachtwoord terugzetten"
newPasswordIs: "Het nieuwe wachtwoord is „{password}”."
reduceUiAnimation: "Verminder beweging in de UI"
share: "Delen"
notFound: "Niet gevonden"
notFoundDescription: "Er is geen pagina gevonden onder deze URL."
uploadFolder: "Standaardmap voor uploaden"
markAsReadAllNotifications: "Markeer alle meldingen als gelezen"
markAsReadAllUnreadNotes: "Markeer alle berichten als gelezen"
@@ -449,13 +490,53 @@ retype: "Opnieuw invoeren"
noteOf: "Notitie van {user}"
quoteAttached: "Citaat"
quoteQuestion: "Toevoegen als citaat?"
attachAsFileQuestion: "De tekst op het klembord is te lang. Wilt u het als een tekstbestand bijvoegen?"
onlyOneFileCanBeAttached: "Per bericht kan slechts één bestand worden bijgevoegd"
signinRequired: "Gelieve te registreren of in te loggen om verder te gaan"
signinOrContinueOnRemote: "Ga naar je eigen instantie of registreer je/log in op deze server om door te gaan."
invitations: "Uitnodigen"
invitationCode: "Uitnodigingscode"
checking: "Wordt gecheckt ..."
available: "Beschikbaar"
unavailable: "Onbeschikbaar"
usernameInvalidFormat: "Je kunt kleine letters, hoofdletters, cijfers en onderstrepingstekens gebruiken."
tooShort: "Te kort"
tooLong: "Te lang"
weakPassword: "Zwak wachtwoord"
normalPassword: "Redelijke wachtwoord"
strongPassword: "Sterk wachtwoord"
passwordMatched: "Lucifers"
passwordNotMatched: "Komt niet overeen"
signinWith: "Aanmelden met {x}"
signinFailed: "Inloggen mislukt. Controleer gebruikersnaam en wachtwoord."
or: "Of"
language: "Taal"
uiLanguage: "Taal van gebruikersinterface"
aboutX: "Over {x}"
emojiStyle: "Emoji-stijl"
native: "Inheems"
menuStyle: "Menustijl"
style: "Stijl"
drawer: "Lade"
popup: "Pop-up"
showNoteActionsOnlyHover: "Toon notitiemenu alleen bij muisaanwijzer"
showReactionsCount: "Zie het aantal reacties op notities"
noHistory: "Geen geschiedenis gevonden"
signinHistory: "Inloggeschiedenis"
enableAdvancedMfm: "Uitgebreide MFM activeren"
enableAnimatedMfm: "Geanimeerde MFM activeren"
doing: "In uitvoering..."
category: "Categorie"
tags: "Aliassen"
docSource: "Broncode van dit document"
createAccount: "Gebruikersaccount maken"
existingAccount: "Bestaand gebruikersaccount"
regenerate: "Regenereer"
fontSize: "Lettergrootte"
mediaListWithOneImageAppearance: "Hoogte van medialijsten met slechts één afbeelding"
limitTo: "Beperken tot {x}"
noFollowRequests: "Je hebt geen lopende volgverzoeken"
openImageInNewTab: "Afbeeldingen in nieuw tabblad openen"
dashboard: "Overzicht"
local: "Lokaal"
remote: "Remote"
@@ -470,38 +551,388 @@ promote: "Promoot"
numberOfDays: "Aantal dagen"
hideThisNote: "Verberg deze notitie"
showFeaturedNotesInTimeline: "Laat featured notities in tijdlijn zien"
objectStorage: "Object Storage"
useObjectStorage: "Object Storage gebruiken"
objectStorageBaseUrl: "Basis-URL"
objectStorageBaseUrlDesc: "De URL die wordt gebruikt als referentie. Als je een CDN of proxy gebruikt, voer dan de URL daarvan in. Gebruik voor S3 https://<bucket>.s3.amazonaws.com. Gebruik voor GCS of vergelijkbaar https://storage.googleapis.com/<bucket>."
objectStorageBucket: "Bucket"
objectStorageBucketDesc: "Geef de bucketnaam op die bij je provider wordt gebruikt."
objectStoragePrefix: "Prefix"
objectStoragePrefixDesc: "Bestanden worden opgeslagen in de mappen onder deze prefix."
objectStorageEndpoint: "Endpoint"
objectStorageEndpointDesc: "Laat dit leeg als je AWS S3 gebruikt, anders geef je het eindpunt op als <host> of <host>:<port>, afhankelijk van de service die je gebruikt."
objectStorageRegion: "Region"
objectStorageRegionDesc: "Voer een regio in zoals “xx-east-1”. Als je provider geen onderscheid maakt tussen regio's, voer dan “us-east-1” in. Laat leeg als je AWS-configuratiebestanden of omgevingsvariabelen gebruikt."
objectStorageUseSSL: "SSL gebruiken"
objectStorageUseSSLDesc: "Deactiveer dit als u geen HTTPS gebruikt voor API-verbindingen"
objectStorageUseProxy: "Verbinden via proxy"
objectStorageUseProxyDesc: "Deactiveer dit als u geen proxy wilt gebruiken voor verbindingen met de API"
objectStorageSetPublicRead: "Instellen op “public-read” op upload"
s3ForcePathStyleDesc: "Als s3ForcePathStyle is geactiveerd, moet de bucketnaam niet worden opgegeven in de hostnaam van de URL, maar in het pad van de URL. Deze optie moet mogelijk worden geactiveerd als services zoals een zelfbediende Minio-instantie worden gebruikt."
serverLogs: "Serverprotocollen"
deleteAll: "Alles verwijderen"
showFixedPostForm: "Het postingformulier bovenaan de tijdbalk weergeven"
showFixedPostFormInChannel: "Het postingformulier bovenaan de tijdbalk weergeven (Kanalen)"
withRepliesByDefaultForNewlyFollowed: "Toon replies van nieuw gevolgde gebruikers standaard in de tijdlijn"
newNoteRecived: "Er zijn nieuwe notities"
sounds: "Geluiden"
sound: "Geluid"
listen: "Luisteren"
none: "Niets"
showInPage: "Weergeven in een pagina"
popout: "Pop-Up"
volume: "Volume"
masterVolume: "Hoofdvolume"
notUseSound: "Geluid uitschakelen"
useSoundOnlyWhenActive: "Geluid alleen inschakelen wanneer Misskey actief is"
details: "Details"
renoteDetails: "Renote Details"
chooseEmoji: "Emoji selecteren"
unableToProcess: "De operatie kan niet worden voltooid."
recentUsed: "Recent gebruikt"
install: "Installeren"
uninstall: "Deinstalleren"
installedApps: "Geautoriseerde toepassingen"
nothing: "Niets te zien hier"
installedDate: "Geautoriseerd at"
lastUsedDate: "Laatst gebruikt at"
state: "Status"
sort: "Sorteren"
ascendingOrder: "Oplopende volgorde"
descendingOrder: "Aflopende volgorde"
scratchpad: "Testomgeving"
scratchpadDescription: "De testomgeving biedt een gebied voor AiScript experimenten. Daar kunt u AiScript schrijven en uitvoeren en de effecten ervan op Misskey controleren."
uiInspector: "UI-inspecteur"
uiInspectorDescription: "De lijst met servers van UI-componenten kan worden bekeken in de cache. De UI-component wordt gegenereerd door de functie Ui:C:"
output: "Uitvoer"
script: "Script"
disablePagesScript: "AiScript uitschakelen op pagina's"
updateRemoteUser: "Gebruikersinformatie bijwerken"
unsetUserAvatar: "Avatar verwijderen"
unsetUserAvatarConfirm: "Weet je zeker dat je je avatar wil verwijderen?"
unsetUserBanner: "Banner verwijderen"
unsetUserBannerConfirm: "Weet je zeker dat je je banner wil verwijderen?"
deleteAllFiles: "Alle bestanden verwijderen"
deleteAllFilesConfirm: "Wil je echt alle bestanden verwijderen?"
removeAllFollowing: "Ontvolg alle gevolgde gebruikers"
removeAllFollowingDescription: "Door dit uit te voeren worden alle accounts van {host} ontvolgd. Voer dit uit als de instantie bijvoorbeeld niet meer bestaat."
userSuspended: "Deze gebruiker is geschorst."
userSilenced: "Deze gebruiker is instantiebreed gedempt."
yourAccountSuspendedTitle: "Deze account is geschorst"
yourAccountSuspendedDescription: "Dit gebruikersaccount is geschorst omdat het de gebruiksvoorwaarden van deze server heeft geschonden. Neem contact op met de operator voor meer informatie. Maak geen nieuwe gebruikersaccount aan."
tokenRevoked: "Ongeldig token"
tokenRevokedDescription: "Het token is verlopen. Log opnieuw in."
accountDeleted: "Het gebruikersaccount is verwijderd"
accountDeletedDescription: "Deze account is verwijderd."
menu: "Menu"
divider: "Scheider"
addItem: "Element toevoegen"
rearrange: "Sorteren"
relays: "Relays"
addRelay: "Relay toevoegen"
inboxUrl: "Inbox-URL"
addedRelays: "Toegevoegd Relays"
serviceworkerInfo: "Moet worden geactiveerd voor pushmeldingen."
deletedNote: "Verwijderde notitie"
invisibleNote: "Privé notitie"
enableInfiniteScroll: "Automatisch meer laden"
visibility: "Zichtbaarheid"
poll: "Peiling"
useCw: "Inhoudswaarschuwing gebruiken"
enablePlayer: "Videospeler openen"
disablePlayer: "Videospeler sluiten"
expandTweet: "Notitie uitklappen"
themeEditor: "Thema-editor"
description: "Beschrijving"
describeFile: "Beschrijving toevoegen"
enterFileDescription: "Beschrijving invoeren"
author: "Auteur"
leaveConfirm: "Er zijn niet-opgeslagen wijzigingen. Wil je ze verwijderen?"
manage: "Beheer"
plugins: "Plugins"
preferencesBackups: "Instellingen Back-ups"
deck: "Dek"
undeck: "Dek verlaten"
useBlurEffectForModal: "Vervagingseffect gebruiken voor modals"
useFullReactionPicker: "Volledige reaktieselectier gebruiken"
width: "Breedte"
height: "Hoogte"
large: "Groot"
medium: "Medium"
small: "Klein"
generateAccessToken: "Toegangstoken genereren"
permission: "Machtigingen"
adminPermission: "Administratorrechten"
enableAll: "Alle activeren"
disableAll: "Alle deactiveren"
tokenRequested: "Toegang verlenen tot het gebruikersaccount"
pluginTokenRequestedDescription: "Deze plugin kan de hier geconfigureerde autorisaties gebruiken."
notificationType: "Type melding"
edit: "Bewerken"
emailServer: "Email-Server"
enableEmail: "Email distributie inschakelen"
emailConfigInfo: "Wordt gebruikt om je email te bevestigen tijdens het aanmelden of als je je wachtwoord bent vergeten"
email: "Email"
emailAddress: "Email adres"
smtpConfig: "SMTP-server configuratie"
smtpHost: "Server"
smtpPort: "Poort"
smtpUser: "Gebruikersnaam"
smtpPass: "Wachtwoord"
emptyToDisableSmtpAuth: "Laat gebruikersnaam en wachtwoord leeg om SMTP-authenticatie uit te schakelen."
smtpSecure: "Impliciet SSL/TLS gebruiken voor SMTP-verbindingen"
smtpSecureInfo: "Schakel dit uit bij gebruik van STARTTLS"
testEmail: "Emailversand testen"
wordMute: "Woord dempen"
wordMuteDescription: "Minimaliseert notities die het gespecificeerde woord of zin bevatten. Geminimaliseerde notities kunnen worden weergegeven door er op te klikken."
hardWordMute: "Harde woorddemping"
showMutedWord: "Gedempte woorden weergeven"
hardWordMuteDescription: "Verbert notities die het gespecificeerde woord of zin bevatten. In tegenstelling tot woorddemping wordt de notitie volledig verborgen."
regexpError: "Fout in reguliere expressie"
regexpErrorDescription: "Er is een fout opgetreden in de reguliere expressie op regel {line} van uw {tab} woord dempen:"
instanceMute: "Instantie dempers"
userSaysSomething: "{name} zei iets"
userSaysSomethingAbout: "{name} zei iets over '{word}'"
makeActive: "Activeren"
display: "Weergave"
copy: "Kopiëren"
copiedToClipboard: "Naar het klembord gekopieerd"
metrics: "Metrieken"
overview: "Overzicht"
logs: "Protocollen"
delayed: "Vertraagd"
database: "Database"
channel: "Kanalen"
create: "Creëer"
notificationSetting: "Instellingen meldingen"
notificationSettingDesc: "Selecteer het type meldingen dat moet worden weergegeven."
useGlobalSetting: "Globale instelling gebruiken"
useGlobalSettingDesc: "Als deze optie is ingeschakeld, worden de meldingsinstellingen van je account gebruikt. Als deze optie uitgeschakeld is, kunnen individuele configuraties worden gemaakt."
other: "Ander"
regenerateLoginToken: "Login token opnieuw genereren"
regenerateLoginTokenDescription: "Regenereren van het token dat intern wordt gebruikt om in te loggen. Dit is normaal gezien niet nodig. Alle apparaten worden afgemeld tijdens het regenereren."
theKeywordWhenSearchingForCustomEmoji: "Dit is het keyword dat gebruikt wordt bij het zoeken naar eigen emojis."
setMultipleBySeparatingWithSpace: "Scheid elementen met een spatie om meerdere instellingen te configureren."
fileIdOrUrl: "Bestands-ID of URL"
behavior: "Gedrag"
sample: "Voorbeeld"
abuseReports: "Meldt"
reportAbuse: "Meld"
reportAbuseRenote: "Meld renote"
reportAbuseOf: "Meld {name}"
fillAbuseReportDescription: "Vul s.v.p. de details in over deze melding. Geef, als het over een specifieke notitie gaat, ook de URL op."
abuseReported: "Uw rapport is verzonden. Hartelijk dank."
reporter: "Verslaggever"
reporteeOrigin: "Oorsprong van de gemelde persoon"
reporterOrigin: "Verslaggever Oorsprong"
send: "Stuur"
openInNewTab: "In nieuw tabblad openen"
openInSideView: "In zijaanzicht openen"
defaultNavigationBehaviour: "Standaard navigatie gedrag"
editTheseSettingsMayBreakAccount: "Het wijzigen van deze instellingen kan je account beschadigen."
instanceTicker: "Instantie-informatie van notities"
waitingFor: "Wachten op {x}"
random: "Willekeurig"
system: "Systeem"
switchUi: "UI omschakelen"
desktop: "Desktop"
clip: "Clip aanmaken"
createNew: "Nieuwe aanmaken"
optional: "Optioneel"
createNewClip: "Nieuwe clip aanmaken"
unclip: "Van clip verwijderen"
confirmToUnclipAlreadyClippedNote: "Deze notitie is al toegevoegd aan de clip “{name}”. Wil je deze uit deze clip verwijderen?"
public: "Openbare"
private: "Privé"
i18nInfo: "Misskey wordt in veel verschillende talen vertaald door vrijwilligers. Je kunt helpen op {link}"
manageAccessTokens: "Toegangstokens beheren"
accountInfo: "Informatie over gebruikersaccount"
notesCount: "Aantal notities"
repliesCount: "Aantal verzonden replies"
renotesCount: "Aantal verzonden renotes"
repliedCount: "Aantal ontvangen replies"
renotedCount: "Aantal ontvangen renotes"
followingCount: "Aantal gevolgde accounts"
followersCount: "Aantal volgers"
sentReactionsCount: "Aantal verzonden reacties"
receivedReactionsCount: "Aantal ontvangen reacties"
pollVotesCount: "Aantal verzonden peiling stemmen"
pollVotedCount: "Aantal ontvangen peiling stemmen"
yes: "Ja"
no: "Nee"
driveFilesCount: "Aantal bestanden in station"
driveUsage: "Schijfruimtegebruik"
noCrawle: "Crawler-indexering verwerpen"
noCrawleDescription: "Vraag zoekmachines om je eigen profielpagina, notities, pagina's, enz. niet te indexeren."
lockedAccountInfo: "Tenzij je de zichtbaarheid van je notities instelt op “Alleen volgers”, zijn je notities zichtbaar voor iedereen, zelfs als je vereist dat volgers handmatig worden goedgekeurd."
alwaysMarkSensitive: "Markeer media standaard als gevoelig"
loadRawImages: "Toon altijd originele afbeeldingen in plaats van miniaturen"
disableShowingAnimatedImages: "Speel geen geanimeerde afbeeldingen af"
highlightSensitiveMedia: "Markeer gevoelige media"
verificationEmailSent: "Er is een bevestigingsmail naar uw e-mailadres verzonden. Ga naar de link in de e-mail om het verificatieproces te voltooien."
notSet: "Niet geconfigureerd"
emailVerified: "Emailadres bevestigd"
noteFavoritesCount: "Aantal notities gemarkeerd als favoriet"
pageLikesCount: "Aantal gelikete pagina's"
pageLikedCount: "Aantal ontvangen pagina-likes"
contact: "Contact"
useSystemFont: "Het standaardlettertype van het systeem gebruiken"
clips: "Clips"
experimentalFeatures: "Experimentele functionaliteiten"
experimental: "Experimentele"
thisIsExperimentalFeature: "Dit is een experimentele functie. De functionaliteit kan worden gewijzigd en werkt mogelijk niet zoals bedoeld."
developer: "Ontwikkelaar"
makeExplorable: "Gebruikersaccount zichtbaar maken in “Verkennen”"
makeExplorableDescription: "Als deze optie is uitgeschakeld, is uw gebruikersaccount niet zichtbaar in het gedeelte “Verkennen”."
showGapBetweenNotesInTimeline: "Een gat tussen noten op de tijdlijn weergeven"
duplicate: "Dupliceren"
left: "Links"
center: "Center"
wide: "Breed"
narrow: "Smal"
reloadToApplySetting: "Deze instelling gaat pas in nadat de pagina herladen is. Nu herladen?"
needReloadToApply: "Deze instelling wordt van kracht nadat de pagina is vernieuwd."
showTitlebar: "Titelbalk weergeven"
clearCache: "Cache opschonen"
onlineUsersCount: "{n} Gebruikers zijn online"
nUsers: "{n} Gebruikers"
nNotes: "{n} Notities"
sendErrorReports: "Foutrapporten sturen"
sendErrorReportsDescription: "Als u deze optie inschakelt, wordt gedetailleerde foutinformatie met Misskey gedeeld wanneer zich een probleem voordoet. Dit helpt de kwaliteit van Misskey te verbeteren.\nDit omvat informatie zoals de versie van uw OS, welke browser u gebruikt, uw activiteit in Misskey, enz."
myTheme: "Mijn thema"
backgroundColor: "Achtergrondkleur"
accentColor: "Accentkleur"
textColor: "Tekstkleur"
saveAs: "Opslaan als…"
advanced: "Geavanceerd"
advancedSettings: "Geavanceerde instellingen"
value: "Waarde"
createdAt: "Aangemaakt at"
updatedAt: "Laatst gewijzigd at"
saveConfirm: "Wijzigingen opslaan?"
deleteConfirm: "Echt verwijderen?"
invalidValue: "Ongeldige waarde."
registry: "Registry"
closeAccount: "Gebruikersaccount sluiten"
currentVersion: "Huidige versie"
latestVersion: "Nieuwste versie"
youAreRunningUpToDateClient: "Je gebruikt de nieuwste versie van je client."
newVersionOfClientAvailable: "Er is een nieuwere versie van je client beschikbaar."
usageAmount: "Gebruik"
capacity: "Capaciteit"
inUse: "Gebruikt"
editCode: "Code bewerken"
apply: "Toepassen"
receiveAnnouncementFromInstance: "Meldingen ontvangen van deze instantie"
emailNotification: "E-mailmeldingen"
publish: "Publiceren"
inChannelSearch: "In kanaal zoeken"
useReactionPickerForContextMenu: "Open reactieselectie door rechts te klikken"
typingUsers: "{users} is/zijn aan het schrijven..."
jumpToSpecifiedDate: "Naar een specifieke datum springen"
showingPastTimeline: "Momenteel wordt een oude tijdlijn weergeven"
clear: "Terugkeren"
markAllAsRead: "Alles als gelezen markeren"
goBack: "Terug"
unlikeConfirm: "Wil je echt je like verwijderen?"
fullView: "Volledig zicht"
quitFullView: "Volledig zicht verlaten"
addDescription: "Beschrijving toevoegen"
userPagePinTip: "Je kunt hier notities tonen door “Vastmaken aan profiel” te selecteren in het menu van de individuele notities."
notSpecifiedMentionWarning: "Deze notitie bevat verwijzingen naar gebruikers die niet zijn geselecteerd als ontvangers"
info: "Over"
userInfo: "Gebruikersinformatie"
unknown: "Onbekend"
onlineStatus: "Online status"
hideOnlineStatus: "Online status verbergen"
hideOnlineStatusDescription: "Het verbergen van je online status vermindert het nut van functies zoals zoeken."
online: "Online"
active: "Actief"
offline: "Offline"
notRecommended: "Niet aanbevolen"
botProtection: "Beveiliging tegen bots"
instanceBlocking: "Geblokkeerde/gedempte Instanties"
selectAccount: "Gebruikersaccount selecteren"
switchAccount: "Account wisselen"
enabled: "Ingeschakeld"
disabled: "Uitgeschakeld"
quickAction: "Snelle acties"
user: "Gebruikers"
administration: "Beheer"
accounts: "Gebruikersaccounts"
switch: "Wissel"
noMaintainerInformationWarning: "Operatorinformatie is niet geconfigureerd."
noInquiryUrlWarning: "Contact-URL niet opgegeven"
noBotProtectionWarning: "Bescherming tegen bots is niet geconfigureerd."
configure: "Configureer"
postToGallery: "Nieuw galerijbericht maken"
postToHashtag: "Post naar deze hashtag"
gallery: "Galerij"
recentPosts: "Recente berichten"
popularPosts: "Populair berichten"
shareWithNote: "Delen met notitie"
ads: "Advertenties"
expiration: "Deadline"
startingperiod: "Start"
memo: "Memo"
priority: "Prioriteit"
high: "Hoge"
middle: "Medium"
low: "Lage"
emailNotConfiguredWarning: "E-mailadres niet ingesteld."
ratio: "Verhouding"
previewNoteText: "Show voorproefje"
customCss: "Aangepaste CSS"
customCssWarn: "Gebruik deze instelling alleen als je weet wat het doet. Ongeldige invoer kan ertoe leiden dat de client niet meer normaal functioneert."
global: "Globaal"
squareAvatars: "Toon profielfoto's as vierkant"
sent: "Verzonden"
received: "Ontvangen"
searchResult: "Zoekresultaten"
hashtags: "Hashtags"
troubleshooting: "Probleemoplossing"
useBlurEffect: "Vervagingseffecten in de UI gebruike"
learnMore: "Meer leren"
misskeyUpdated: "Misskey is bijgewerkt!"
whatIsNew: "Wijzigingen tonen"
translate: "Vertalen"
translatedFrom: "Vertaald uit {x}"
accountDeletionInProgress: "De verwijdering van je gebruikersaccount wordt momenteel verwerkt."
usernameInfo: "Een naam die kan worden gebruikt om je gebruikersaccount op deze server te identificeren. Je kunt het alfabet (a~z, A~Z), cijfers (0~9) of underscores (_) gebruiken. Gebruikersnamen kunnen later niet worden gewijzigd."
aiChanMode: "Ai Mode"
devMode: "Ontwikkelaar modus"
keepCw: "Inhoudswaarschuwingen behouden"
pubSub: "Pub/Sub Gebruikersaccounts"
lastCommunication: "Laatste communicatie"
resolved: "Opgelost"
unresolved: "Onopgelost"
breakFollow: "Volger verwijderen"
breakFollowConfirm: "Deze volger echt weghalen?"
itsOn: "Ingeschakeld"
itsOff: "Uitgeschakeld"
on: "Op"
off: "Uit"
emailRequiredForSignup: "Vereist e-mailadres voor aanmelding"
unread: "Ongelezen"
filter: "Filter"
controlPanel: "Controlepaneel"
manageAccounts: "Gebruikersaccounts beheren"
makeReactionsPublic: "Reactiegeschiedenis publiceren"
makeReactionsPublicDescription: "Hierdoor wordt de lijst met al je eerdere reacties openbaar."
classic: "Classic"
muteThread: "Discussies dempen "
unmuteThread: "Dempen van discussie ongedaan maken"
followingVisibility: "Zichtbaarheid van gevolgden"
followersVisibility: "Zichtbaarheid van volgers"
continueThread: "Bekijk draad voortzetting"
deleteAccountConfirm: "Je gebruikersaccount wordt onherroepelijk verwijderd. Wil je nog steeds doorgaan?"
incorrectPassword: "Onjuist wachtwoord."
incorrectTotp: "Het eenmalige wachtwoord is incorrect of verlopen"
voteConfirm: "Bevestig je je stem op “{choice}”?"
hide: "Verbergen"
useDrawerReactionPickerForMobile: "Toon reactiekiezer als lade op mobiel"
welcomeBackWithName: "Welkom terug, {name}"
clickToFinishEmailVerification: "Druk op [{ok}] om de e-mailbevestiging af te ronden."
searchByGoogle: "Zoeken"
threeMonths: "3 maanden"
oneYear: "1 jaar"
@@ -509,6 +940,7 @@ threeDays: "3 dagen"
cropImage: "Afbeelding bijsnijden"
cropImageAsk: "Bijsnijdengevraagd"
file: "Bestanden"
account: "Gebruikersaccounts"
pushNotification: "Pushberichten"
subscribePushNotification: "Push meldingen inschakelen"
unsubscribePushNotification: "Pushberichten uitschakelen"
@@ -516,6 +948,7 @@ pushNotificationAlreadySubscribed: "Pushberichtrn al ingeschakeld"
windowMaximize: "Maximaliseren"
windowRestore: "Herstellen"
loggedInAsBot: "Momenteel als bot ingelogd"
show: "Weergave"
correspondingSourceIsAvailable: "De bijbehorende broncode is beschikbaar bij {anchor}"
invalidParamErrorDescription: "De aanvraagparameters zijn ongeldig. Dit komt meestal door een bug, maar kan ook omdat de invoer te lang is of iets dergelijks."
collapseRenotes: "Renotes die je al gezien hebt, inklappen"
@@ -534,26 +967,40 @@ lookupConfirm: "Weet je zeker dat je dit wil opzoeken?"
openTagPageConfirm: "Wil je deze hashtagpagina openen?"
specifyHost: "Specificeer host"
icon: "Avatar"
replies: "Antwoord"
replies: "Antwoorden"
renotes: "Herdelen"
followingOrFollower: "Gevolgd of volger"
confirmShowRepliesAll: "Dit is een onomkeerbare operatie. Weet je zeker dat reacties op anderen van iedereen die je volgt, wil weergeven in je tijdlijn?"
information: "Over"
_chat:
invitations: "Uitnodigen"
noHistory: "Geen geschiedenis gevonden"
members: "Leden"
home: "Startpagina"
send: "Stuur"
_delivery:
stop: "Opgeschort"
_type:
none: "Publiceren"
_role:
priority: "Prioriteit"
_priority:
low: "Lage"
middle: "Medium"
high: "Hoge"
_ffVisibility:
public: "Publiceren"
_ad:
back: "Terug"
_email:
_follow:
title: "volgde jou"
_theme:
description: "Beschrijving"
keys:
mention: "Vermelding"
renote: "Herdelen"
divider: "Scheider"
_sfx:
note: "Notities"
notification: "Meldingen"
@@ -578,6 +1025,7 @@ _profile:
name: "Naam"
username: "Gebruikersnaam"
_exportOrImport:
clips: "Clip aanmaken"
followingList: "Volgend"
muteList: "Dempen"
blockingList: "Blokkeren"
@@ -588,6 +1036,9 @@ _charts:
federation: "Federatie"
_timelines:
home: "Startpagina"
_play:
script: "Script"
summary: "Beschrijving"
_pages:
blocks:
image: "Afbeeldingen"
@@ -610,9 +1061,15 @@ _deck:
tl: "Tijdlijn"
antenna: "Antennes"
list: "Lijsten"
channel: "Kanalen"
mentions: "Vermeldingen"
_webhookSettings:
name: "Naam"
active: "Ingeschakeld"
_abuseReport:
_notificationRecipient:
_recipientType:
mail: "Email"
_moderationLogTypes:
suspend: "Opschorten"
resetPassword: "Wachtwoord terugzetten"
+240
View File
@@ -5,6 +5,7 @@ introMisskey: "Bem-vindo! O Misskey é um serviço de microblog descentralizado
poweredByMisskeyDescription: "{name} é uma instância da plataforma de código aberto <b>Misskey</b>."
monthAndDay: "{day}/{month}"
search: "Pesquisar"
reset: "Redefinir"
notifications: "Notificações"
username: "Nome de usuário"
password: "Senha"
@@ -48,6 +49,7 @@ pin: "Fixar no perfil"
unpin: "Desafixar do perfil"
copyContent: "Copiar conteúdos"
copyLink: "Copiar link"
copyRemoteLink: "Copiar endereço remoto"
copyLinkRenote: "Copiar o link da repostagem"
delete: "Excluir"
deleteAndEdit: "Excluir e editar"
@@ -299,6 +301,7 @@ uploadFromUrlMayTakeTime: "Pode levar algum tempo para que o upload seja conclu
explore: "Explorar"
messageRead: "Lida"
noMoreHistory: "Não existe histórico anterior"
startChat: "Iniciar conversa"
nUsersRead: "{n} pessoas leram"
agreeTo: "Eu concordo com {0}"
agree: "Concordar"
@@ -421,6 +424,7 @@ antennaExcludeBots: "Ignorar contas de bot"
antennaKeywordsDescription: "Se você separá-lo com um espaço, será uma especificação AND, e se você separá-lo com uma quebra de linha, será uma especificação OR."
notifyAntenna: "Notificar novas notas"
withFileAntenna: "Apenas notas com arquivos anexados"
excludeNotesInSensitiveChannel: "Excluir notas de canais sensíveis"
enableServiceworker: "Ative as notificações push para o seu navegador"
antennaUsersDescription: "Especificar nomes de utilizador separados por quebras de linha"
caseSensitive: "Maiúsculas e minúsculas"
@@ -680,14 +684,19 @@ smtpSecure: "Use SSL/TLS implícito para conexões SMTP"
smtpSecureInfo: "Desative esta opção ao utilizar STARTTLS."
testEmail: "Testar envio de e-mail"
wordMute: "Silenciar palavras"
wordMuteDescription: "Minimizar notas que contêm a palavra ou frase especificada. Notas minimizadas são exibidas ao clicá-las."
hardWordMute: "Silenciar palavras (esconder posts)"
showMutedWord: "Exibir palavras silenciadas"
hardWordMuteDescription: "Esconder notas que contêm a palavra ou frase especificada. Diferente do silenciamento de palavras, a nota será completamente escondida."
regexpError: "Erro na expressão regular"
regexpErrorDescription: "Ocorreu um erro na expressão regular na linha {line} da palavra mutada {tab}:"
instanceMute: "Instâncias silenciadas"
userSaysSomething: "{name} disse algo"
userSaysSomethingAbout: "{name} disse algo sobre \"{word}\""
makeActive: "Ativar"
display: "Visualizar"
copy: "Copiar"
copiedToClipboard: "Copiado à área de transferência"
metrics: "Métricas"
overview: "Visão geral"
logs: "Logs"
@@ -970,6 +979,7 @@ document: "Documentação"
numberOfPageCache: "Número de cache de página"
numberOfPageCacheDescription: "Aumentar isso melhora a conveniência, mas também resulta em maior carga e uso de memória."
logoutConfirm: "Gostaria de encerrar a sessão?"
logoutWillClearClientData: "Sair irá remover as configurações do cliente do navegador. Para redefinir as configurações ao entrar, você deve habilitar o backup automático de configurações."
lastActiveDate: "Última data de uso"
statusbar: "Barra de status"
pleaseSelect: "Por favor, selecione."
@@ -1297,16 +1307,137 @@ lockdown: "Lockdown"
pleaseSelectAccount: "Selecione uma conta"
availableRoles: "Cargos disponíveis"
acknowledgeNotesAndEnable: "Ative após compreender as precauções."
federationSpecified: "Esse servidor opera com uma lista branca de federação. Interagir com servidores diferentes daqueles designados pela administração não é permitido."
federationDisabled: "Federação está desabilitada nesse servidor. Você não pode interagir com usuários de outros servidores."
confirmOnReact: "Confirmar ao reagir"
reactAreYouSure: "Você deseja adicionar uma reação \"{emoji}\"?"
markAsSensitiveConfirm: "Você deseja definir essa mídia como sensível?"
unmarkAsSensitiveConfirm: "Você deseja remover a definição dessa mídia como sensível?"
preferences: "Preferências"
accessibility: "Acessibilidade"
preferencesProfile: "Perfil de preferências"
copyPreferenceId: "Copiar ID de preferências"
resetToDefaultValue: "Reverter ao padrão"
overrideByAccount: "Sobrescrever pela conta"
untitled: "Sem título"
noName: "Sem nome"
skip: "Pular"
restore: "Redefinir"
syncBetweenDevices: "Sincronizar entre dispositivos"
preferenceSyncConflictTitle: "O valor configurado já existe no servidor."
preferenceSyncConflictText: "As preferências com a sincronização ativada irão salvar os seus valores no servidor. Porém, já existem valores no servidor. Qual conjunto de valores você deseja sobrescrever?"
preferenceSyncConflictChoiceServer: "Valor configurado no servidor"
preferenceSyncConflictChoiceDevice: "Valor configurado no dispositivo"
preferenceSyncConflictChoiceCancel: "Cancelar a habilitação de sincronização"
paste: "Colar"
emojiPalette: "Paleta de emojis"
postForm: "Campo de postagem"
textCount: "Contagem de caracteres"
information: "Informações"
chat: "Conversas"
migrateOldSettings: "Migrar configurações antigas de cliente"
migrateOldSettings_description: "Isso deve ser feito automaticamente. Caso o processo de migração tenha falhado, você pode acioná-lo manualmente. As informações atuais de migração serão substituídas."
compress: "Comprimir"
right: "Direita"
bottom: "Inferior"
top: "Superior"
embed: "Embed"
settingsMigrating: "Configurações estão sendo migradas, aguarde... (Você pode migrar manualmente em Configurações→Outros→Migrar configurações antigas de cliente)"
readonly: "Ler apenas"
goToDeck: "Voltar ao Deck"
federationJobs: "Tarefas de Federação"
_chat:
noMessagesYet: "Ainda não há mensagens"
newMessage: "Nova mensagem"
individualChat: "Conversa Particular"
individualChat_description: "Ter uma conversa particular com outra pessoa."
roomChat: "Conversa de Grupo"
roomChat_description: "Uma sala de conversas com várias pessoas. Você pode adicionar pessoas que não permitem conversas privadas se elas aceitarem o convite."
createRoom: "Criar Sala"
inviteUserToChat: "Convide usuários para começar a conversar"
yourRooms: "Salas criadas"
joiningRooms: "Salas ingressadas"
invitations: "Convidar"
noInvitations: "Sem convites"
history: "Histórico"
noHistory: "Ainda não há histórico"
noRooms: "Nenhuma sala encontrada"
inviteUser: "Convidar Usuários"
sentInvitations: "Convites Enviados"
join: "Entrar"
ignore: "Ignorar"
leave: "Deixar sala"
members: "Membros"
searchMessages: "Pesquisar mensagens"
home: "Início"
send: "Enviar"
newline: "Nova linha"
muteThisRoom: "Silenciar sala"
deleteRoom: "Excluir sala"
chatNotAvailableForThisAccountOrServer: "Conversas não estão habilitadas nesse servidor ou para essa conta."
chatIsReadOnlyForThisAccountOrServer: "Conversas são apenas para leitura nesse servidor ou para essa conta. Não é possível escrever novas mensagens ou criar/ingressar novas conversas."
chatNotAvailableInOtherAccount: "A função de conversas está desabilitadas para o outro usuário."
cannotChatWithTheUser: "Não é possível conversar com esse usuário."
cannotChatWithTheUser_description: "Conversas estão indisponíveis ou o outro usuário não as habilitou."
chatWithThisUser: "Conversar com usuário"
thisUserAllowsChatOnlyFromFollowers: "Esse usuário aceita conversar apenas com seguidores."
thisUserAllowsChatOnlyFromFollowing: "Esse usuário aceita conversar apenas com quem segue."
thisUserAllowsChatOnlyFromMutualFollowing: "Esse usuário aceita conversar apenas com seguidores mútuos."
thisUserNotAllowedChatAnyone: "Esse usuário não aceita conversar com ninguém."
chatAllowedUsers: "Com quem permitir conversas"
chatAllowedUsers_note: "Você pode conversar com qualquer um com quem tenha iniciado uma conversa independente dessa configuração."
_chatAllowedUsers:
everyone: "Todos"
followers: "Seus seguidores"
following: "Quem você segue"
mutual: "Seguidores mútuos"
none: "Ninguém"
_emojiPalette:
palettes: "Paleta"
enableSyncBetweenDevicesForPalettes: "Sincronizar paleta entre dispositivos"
paletteForMain: "Paleta principal"
paletteForReaction: "Paleta de reações"
_settings:
driveBanner: "Você consegue administrar e configurar o drive, conferir o seu uso e configurar as opções de envio de arquivos."
pluginBanner: "Você pode ampliar as funções do cliente com plugins. Você pode instalar plugins, configurar e administrar individualmente."
notificationsBanner: "Você pode configurar os tipos e intervalo das notificações do servidor, além de notificações push."
api: "API"
webhook: "Webhook"
serviceConnection: "Integração de serviço"
serviceConnectionBanner: "Administre e configure tokens de acesso e webhooks para interagir com aplicações e serviços externos."
accountData: "Dados da conta"
accountDataBanner: "Exportar e importar dados da conta."
muteAndBlockBanner: "Você pode configurar meios para esconder conteúdo e restringir ações de certos usuários."
accessibilityBanner: "Você pode personalizar o visual e comportamento do cliente, além de configurar modos de otimizar o uso."
privacyBanner: "Você pode configurar a privacidade da conta por meio da visibilidade do conteúdo, capacidade de descoberta e aprovação manual de seguidores."
securityBanner: "Você pode configurar a segurança da conta em ajustes como senha, meios de entrada, aplicativos de autenticação e chaves de acesso."
preferencesBanner: "Você pode configurar o comportamento geral do cliente segundo as suas preferências."
appearanceBanner: "Você pode configurar a aparência do cliente e ajustes de tela segundo as suas preferências."
soundsBanner: "Você pode configurar a reprodução de sons no cliente."
timelineAndNote: "Notas e linha do tempo"
makeEveryTextElementsSelectable: "Tornar todos os elementos de texto selecionáveis"
makeEveryTextElementsSelectable_description: "Habilitar isso pode reduzir a usabilidade em algumas situações"
useStickyIcons: "Fazer ícones acompanharem a rolagem da tela"
showNavbarSubButtons: "Mostrar sub-botões na barra de navegação"
ifOn: "Quando ligado"
ifOff: "Quando desligado"
enableSyncThemesBetweenDevices: "Sincronizar temas instalados entre dispositivos"
_chat:
showSenderName: "Exibir nome de usuário do remetente"
sendOnEnter: "Pressionar Enter para enviar"
_preferencesProfile:
profileName: "Nome do perfil"
profileNameDescription: "Defina o nome que identifica esse dispositivo."
profileNameDescription2: "Exemplo: \"Computador Principal\", \"Celular\""
_preferencesBackup:
autoBackup: "Backup automático"
restoreFromBackup: "Restaurar backup"
noBackupsFoundTitle: "Nenhum backup encontrado"
noBackupsFoundDescription: "Nenhum backup automático foi encontrado. Se você salvou um arquivo de backup manualmente, você pode importá-lo e restaurá-lo."
selectBackupToRestore: "Selecionar um backup para restaurar"
youNeedToNameYourProfileToEnableAutoBackup: "Um nome de perfil deve ser definido para habilitar o backup automático."
autoPreferencesBackupIsNotEnabledForThisDevice: "Backup automático de configurações não está habilitado no dispositivo."
backupFound: "Backup de configurações encontrado"
_accountSettings:
requireSigninToViewContents: "Exigir cadastro para ver o conteúdo"
requireSigninToViewContentsDescription1: "Exigir cadastro para ver todas as notas e outro conteúdo que você criou. Isso previne 'crawlers' de coletar os seus dados."
@@ -1317,6 +1448,7 @@ _accountSettings:
makeNotesHiddenBefore: "Tornar notas passadas privadas"
makeNotesHiddenBeforeDescription: "Com essa função ativada, apenas você poderá ver as notas anteriores à data e hora marcadas. Se isso for desativado, o status de publicação da nota será reestabelecido."
mayNotEffectForFederatedNotes: "Notas federadas a servidores remotos podem não ser afetadas."
mayNotEffectSomeSituations: "Essas restrições são simplificadas. Elas podem não ser aplicadas em algumas situações, como ao visualizar num servidor remoto ou durante a moderação."
notesHavePassedSpecifiedPeriod: "Notas que duraram um tempo específico."
notesOlderThanSpecifiedDateAndTime: "Notas antes do tempo específico."
_abuseUserReport:
@@ -1762,6 +1894,8 @@ _role:
descriptionOfIsExplorable: "Ao ativar, a lista de membros será pública na seção 'Explorar' e a linha do tempo do cargo ficará disponível."
displayOrder: "Ordenação"
descriptionOfDisplayOrder: "Quanto maior o número, maior a posição de destaque na interface do usuário."
preserveAssignmentOnMoveAccount: "Preservar a associação de cargos durante a migração"
preserveAssignmentOnMoveAccount_description: "Quando ligado, esse cargo será encaminhado para a conta final quando houver migração de um usuário."
canEditMembersByModerator: "Permitir a edição de membros deste cargo por moderadores"
descriptionOfCanEditMembersByModerator: "Quando ativado, os moderadores também poderão atribuir/remover usuários deste papel, além dos administradores. Quando desativado, apenas os administradores poderão fazê-lo."
priority: "Prioridade"
@@ -1802,6 +1936,7 @@ _role:
canImportFollowing: "Permitir importação de usuários seguidos"
canImportMuting: "Permitir importação de silenciamentos"
canImportUserLists: "Permitir importação de listas"
chatAvailability: "Permitir Conversas"
_condition:
roleAssignedTo: "Atribuído a cargos manuais"
isLocal: "Usuário local"
@@ -1965,6 +2100,7 @@ _theme:
installed: "{name} foi instalado"
installedThemes: "Temas instalados"
builtinThemes: "Temas nativos"
instanceTheme: "Tema do servidor"
alreadyInstalled: "Esse tema já foi instalado"
invalid: "O formato desse tema é invalido"
make: "Fazer um tema"
@@ -2027,6 +2163,7 @@ _sfx:
noteMy: "Própria nota"
notification: "Notificações"
reaction: "Ao selecionar uma reação"
chatMessage: "Mensagens em Conversas"
_soundSettings:
driveFile: "Usar um arquivo de áudio do Drive."
driveFileWarn: "Selecione um arquivo de áudio do Drive."
@@ -2174,6 +2311,7 @@ _permissions:
"read:federation": "Ver dados de federação"
"write:report-abuse": "Reportar violação"
"write:chat": "Compor ou editar mensagens de chat"
"read:chat": "Navegar Conversas"
_auth:
shareAccessTitle: "Conceder permissões do aplicativo"
shareAccess: "Você gostaria de autorizar \"{name}\" para acessar essa conta?"
@@ -2232,6 +2370,7 @@ _widgets:
chooseList: "Selecione uma lista"
clicker: "Clicker"
birthdayFollowings: "Usuários de aniversário hoje"
chat: "Conversas"
_cw:
hide: "Esconder"
show: "Carregar mais"
@@ -2422,6 +2561,7 @@ _notification:
newNote: "Nova nota"
unreadAntennaNote: "Antena {name}"
roleAssigned: "Cargo dado"
chatRoomInvitationReceived: "Você foi convidado para uma conversa"
emptyPushNotificationMessage: "As notificações de alerta foram atualizadas"
achievementEarned: "Conquista desbloqueada"
testNotification: "Notificação teste"
@@ -2435,6 +2575,8 @@ _notification:
flushNotification: "Limpar notificações"
exportOfXCompleted: "Exportação de {x} foi concluída"
login: "Alguém entrou na conta"
createToken: "Uma token de acesso foi criada"
createTokenDescription: "Se você não faz ideia, exclua o token de acesso através de \"{text}\"."
_types:
all: "Todas"
note: "Novas notas"
@@ -2448,9 +2590,11 @@ _notification:
receiveFollowRequest: "Recebeu pedidos de seguidor"
followRequestAccepted: "Aceitou pedidos de seguidor"
roleAssigned: "Cargo dado"
chatRoomInvitationReceived: "Convite de conversa recebido"
achievementEarned: "Conquista desbloqueada"
exportCompleted: "A exportação foi concluída"
login: "Iniciar sessão"
createToken: "Criar token de acesso"
test: "Notificação teste"
app: "Notificações de aplicativos conectados"
_actions:
@@ -2460,6 +2604,9 @@ _notification:
_deck:
alwaysShowMainColumn: "Sempre mostrar a coluna principal"
columnAlign: "Alinhar colunas"
columnGap: "Margem entre colunas"
deckMenuPosition: "Posição do menu do deck"
navbarPosition: "Posição da barra de navegação"
addColumn: "Adicionar coluna"
newNoteNotificationSettings: "Opções de notificação para novas notas"
configureColumn: "Configurar coluna"
@@ -2478,6 +2625,7 @@ _deck:
useSimpleUiForNonRootPages: "Usar UI simples para páginas navegadas"
usedAsMinWidthWhenFlexible: "A largura mínima será usada para isso quando o \"Ajuste automático da largura\" estiver ativado"
flexible: "Ajuste automático da largura"
enableSyncBetweenDevicesForProfiles: "Habilitar sincronização das informações do perfil entre dispositivos"
_columns:
main: "Principal"
widgets: "Widgets"
@@ -2489,6 +2637,7 @@ _deck:
mentions: "Menções"
direct: "Notas diretas"
roleTimeline: "Linha do tempo do cargo"
chat: "Conversas"
_dialog:
charactersExceeded: "Você excedeu o limite de caracteres! Atualmente em {current} de {max}."
charactersBelow: "Você está abaixo do limite mínimo de caracteres! Atualmente em {current} of {min}."
@@ -2585,6 +2734,8 @@ _moderationLogTypes:
deletePage: "Remover página"
deleteFlash: "Remover Play"
deleteGalleryPost: "Remover a publicação da galeria"
deleteChatRoom: "Sala de Conversas Excluída"
updateProxyAccountDescription: "Atualizar descrição da conta de proxy"
_fileViewer:
title: "Detalhes do arquivo"
type: "Tipo de arquivo"
@@ -2719,6 +2870,66 @@ _contextMenu:
app: "Aplicativo"
appWithShift: "Aplicativo com a tecla shift"
native: "Nativo"
_gridComponent:
_error:
requiredValue: "Esse valor é necessário"
columnTypeNotSupport: "Validação de expressões regulares (RegEx) só é permitida em colunas type:text."
patternNotMatch: "Esse valor não se encaixa no padrão de {pattern}"
notUnique: "Valor deve ser único"
_roleSelectDialog:
notSelected: "Não selecionado"
_customEmojisManager:
_gridCommon:
copySelectionRows: "Copiar linhas selecionadas"
copySelectionRanges: "Copiar seleção"
deleteSelectionRows: "Excluir linhas selecionadas"
deleteSelectionRanges: "Excluir valores selecionados"
searchSettings: "Opções de busca"
searchSettingCaption: "Definir critérios detalhados de busca."
searchLimit: "Limite de busca"
sortOrder: "Ordem de classificação"
registrationLogs: "Histórico de registros"
registrationLogsCaption: "Atualizações e remoções de emoji serão gravadas no histórico. Atualizar, remover, mover a uma nova página ou recarregar limpará o histórico"
alertEmojisRegisterFailedDescription: "Não foi possível atualizar ou remover emojis. Por favor, confira o histórico de registro para mais detalhes."
_logs:
showSuccessLogSwitch: "Exibir sucessos no histórico"
failureLogNothing: "Não há registro de falhas."
logNothing: "Não há registros."
_remote:
selectionRowDetail: "Detalhes da linha selecionada"
importSelectionRows: "Importar linhas selecionadas"
importSelectionRangesRows: "Importar linhas no intervalo"
importEmojisButton: "Importar Emojis selecionados"
confirmImportEmojisTitle: "Importar Emojis"
confirmImportEmojisDescription: "Importar {count} Emoji(s) recebidos de um servidor remoto. Por favor, preste atenção na licença do Emoji. Tem certeza que deseja continuar?"
_local:
tabTitleList: "Emojis registrados"
tabTitleRegister: "Registro de Emoji"
_list:
emojisNothing: "Não há Emojis registrados."
markAsDeleteTargetRows: "Marcar linhas selecionadas para remoção"
markAsDeleteTargetRanges: "Marcar linhas no intervalo para remoção"
alertUpdateEmojisNothingDescription: "Não há Emojis atualizados."
alertDeleteEmojisNothingDescription: "Não há Emojis marcados para remoção."
confirmMovePage: "Deseja mudar de página?"
confirmChangeView: "Deseja mudar de seção?"
confirmUpdateEmojisDescription: "Atualizando {count} Emoji(s). Deseja continuar?"
confirmDeleteEmojisDescription: "Removendo {count} Emoji(s) marcado(s). Deseja continuar?"
confirmResetDescription: "Todas as mudanças serão redefinidas."
confirmMovePageDesciption: "Mudanças foram feitas nos Emojis dessa página. Se você sair sem salvar, todas serão descartadas."
dialogSelectRoleTitle: "Buscar por cargo que pode usar esse Emoji"
_register:
uploadSettingTitle: "Configurações de envio"
uploadSettingDescription: "Nessa tela, você pode configurar o comportamento ao enviar Emojis."
directoryToCategoryLabel: "Transformar as pastas em categorias"
directoryToCategoryCaption: "Quando você arrastar um diretório, converter o caminho das pastas no campo \"categoria\"."
emojiInputAreaCaption: "Selecione Emojis que você deseja registrar utilizando um dos métodos."
emojiInputAreaList1: "Arraste arquivos de imagem ou diretórios dentro desse quadro"
emojiInputAreaList2: "Clique nesse link para abrir a seleção de arquivos"
emojiInputAreaList3: "Clique nesse link para selecionar do drive"
confirmRegisterEmojisDescription: "Registrando os Emojis da lista como novos Emojis personalizados. Deseja continuar? (Para evitar sobrecarga, apenas {count} Emoji(s) podem ser registrados em uma única operação)"
confirmClearEmojisDescription: "Descartando edições e limpando Emojis da lista. Deseja continuar?"
confirmUploadEmojisDescription: "Enviando {count} arquivo(s) arrastados ao drive. Deseja continuar?"
_embedCodeGen:
title: "Personalizar código do embed"
header: "Exibir cabeçalho"
@@ -2758,7 +2969,36 @@ _remoteLookupErrors:
_noSuchObject:
title: "Não encontrado"
description: "O recurso solicitado não foi encontrado, confira o endereço."
_captcha:
verify: "Por favor, verifique o CAPTCHA"
testSiteKeyMessage: "Você pode conferir a prévia inserindo valores de teste para o site e chaves secretas.\nVeja a página seguinte para mais detalhes."
_error:
_requestFailed:
title: "O pedido do CAPTCHA falhou"
text: "Por favor, tente novamente ou verifique as configurações."
_verificationFailed:
title: "A validação do CAPTCHA falhou"
text: "Por favor, verifique se as configurações estão corretas."
_unknown:
title: "Erro CAPTCHA"
text: "Houve um erro inexperado."
_bootErrors:
title: "Falha ao carregar"
serverError: "Se o problema persistir após esperar um momento e recarregar, contate a administração da instância com o seguinte ID de erro."
solution: "O seguinte pode resolver o problema."
solution1: "Atualize seu navegador e sistema operacional para a última versão."
solution2: "Desative o bloqueador de anúncios"
solution3: "Limpe o cache do navegador"
solution4: "Defina dom.webaudio.enabled como verdadeiro no Navegador Tor"
otherOption: "Outras opções"
otherOption1: "Excluir ajustes de cliente e cache"
otherOption2: "Iniciar o cliente simples"
otherOption3: "Iniciar ferramenta de reparo"
_search:
searchScopeAll: "Todos"
searchScopeLocal: "Local"
searchScopeServer: "Servidor específico"
searchScopeUser: "Usuário específico"
pleaseEnterServerHost: "Insira o endereço do servidor"
pleaseSelectUser: "Selecione um usuário"
serverHostPlaceholder: "Exemplo: misskey.example.com"
+711 -59
View File
File diff suppressed because it is too large Load Diff
+4
View File
@@ -5,6 +5,7 @@ introMisskey: "ยินดีต้อนรับทุกคนจ้า! Mis
poweredByMisskeyDescription: "{name} เป็นหนึ่งในเซิร์ฟเวอร์ของแพลตฟอร์มโอเพ่นซอร์ส <b>Misskey</b>"
monthAndDay: "{month}/{day}"
search: "ค้นหา"
reset: "รีเซ็ต"
notifications: "เเจ้งเตือน"
username: "ชื่อผู้ใช้"
password: "รหัสผ่าน"
@@ -1288,8 +1289,11 @@ prohibitedWordsForNameOfUser: "คำนี้ไม่สามารถใช
prohibitedWordsForNameOfUserDescription: "หากมีสตริงใดๆ ในรายการนี้ปรากฏอยู่ในชื่อของผู้ใช้ ชื่อนั้นจะถูกปฏิเสธ ผู้ใช้ที่มีสิทธิ์แต่ผู้ดูแลระบบนั้นจะไม่ได้รับผลกระทบใดๆจากข้อจำกัดนี้ค่ะ"
yourNameContainsProhibitedWords: "ชื่อของคุณนั้นมีคำที่ต้องห้าม"
yourNameContainsProhibitedWordsDescription: "ถ้าหากคุณต้องการใช้ชื่อนี้ กรุณาติดต่อผู้ดูแลระบบของเซิร์ฟเวอร์นะค่ะ"
federationDisabled: "เซิร์ฟเวอร์นี้ปิดการใช้งานการรวมกลุ่ม คุณไม่สามารถโต้ตอบกับผู้ใช้บนเซิร์ฟเวอร์อื่นได้"
postForm: "แบบฟอร์มการโพสต์"
information: "เกี่ยวกับ"
right: "ขวา"
bottom: "ภายใต้"
_chat:
invitations: "คำเชิญ"
noHistory: "ไม่มีประวัติ"
+75 -5
View File
@@ -1,10 +1,11 @@
---
_lang_: "Tiếng Nhật"
_lang_: "Tiếng Việt "
headlineMisskey: "Mạng xã hội liên hợp"
introMisskey: "Xin chào! Misskey là một nền tảng tiểu blog phi tập trung mã nguồn mở.\nViết \"tút\" để chia sẻ những suy nghĩ của bạn 📡\nBằng \"biểu cảm\", bạn có thể bày tỏ nhanh chóng cảm xúc của bạn với các tút 👍\nHãy khám phá một thế giới mới! 🚀"
poweredByMisskeyDescription: "{name} là một trong những chủ máy của <b>Misskey</b> là nền tảng mã nguồn mở"
monthAndDay: "{day} tháng {month}"
search: "Tìm kiếm"
reset: "cài lại"
notifications: "Thông báo"
username: "Tên người dùng"
password: "Mật khẩu"
@@ -48,9 +49,10 @@ pin: "Ghim"
unpin: "Bỏ ghim"
copyContent: "Chép nội dung"
copyLink: "Chép liên kết"
copyRemoteLink: "Sao chép liên kết từ xa"
copyLinkRenote: "Sao chép liên kết ghi chú"
delete: "Xóa"
deleteAndEdit: "Sửa"
deleteAndEdit: "Xóa và soạn thảo lại"
deleteAndEditConfirm: "Bạn có chắc muốn sửa tút này? Những biểu cảm, lượt trả lời và đăng lại sẽ bị mất."
addToList: "Thêm vào danh sách"
addToAntenna: "Thêm vào Ăngten"
@@ -63,6 +65,7 @@ copyFileId: "Sao chép ID tập tin"
copyFolderId: "Sao chép ID thư mục"
copyProfileUrl: "Sao chép URL hồ sơ"
searchUser: "Tìm kiếm người dùng"
searchThisUsersNotes: "Tìm kiếm ghi chú của người dùng"
reply: "Trả lời"
loadMore: "Tải thêm"
showMore: "Xem thêm"
@@ -111,6 +114,7 @@ enterEmoji: "Chèn emoji"
renote: "Đăng lại"
unrenote: "Hủy đăng lại"
renoted: "Đã đăng lại."
renotedToX: "Đã cho thuê lại {name}."
cantRenote: "Không thể đăng lại tút này."
cantReRenote: "Không thể đăng lại một tút đăng lại."
quote: "Trích dẫn"
@@ -125,6 +129,7 @@ add: "Thêm"
reaction: "Biểu cảm"
reactions: "Biểu cảm"
emojiPicker: "Bộ chọn biểu tượng cảm xúc"
emojiPickerDisplay: "Hiển thị bộ chọn"
reactionSettingDescription2: "Kéo để sắp xếp, nhấn để xóa, nhấn \"+\" để thêm."
rememberNoteVisibility: "Lưu kiểu tút mặc định"
attachCancel: "Gỡ tập tin đính kèm"
@@ -175,6 +180,8 @@ addAccount: "Thêm tài khoản"
reloadAccountsList: "Cập nhật danh sách tài khoản"
loginFailed: "Đăng nhập không thành công"
showOnRemote: "Truy cập trang của người này"
continueOnRemote: "Tiếp tục trên phiên bản từ xa"
chooseServerOnMisskeyHub: "Chọn một máy chủ từ Misskey Hub"
general: "Tổng quan"
wallpaper: "Ảnh bìa"
setWallpaper: "Đặt ảnh bìa"
@@ -185,6 +192,7 @@ followConfirm: "Bạn theo dõi {name}"
proxyAccount: "Tài khoản proxy"
proxyAccountDescription: "Tài khoản proxy là tài khoản hoạt động như một người theo dõi từ xa cho người dùng trong những điều kiện nhất định. Ví dụ: khi người dùng thêm người dùng từ xa vào danh sách, hoạt động của người dùng từ xa sẽ không được chuyển đến phiên bản nếu không có người dùng cục bộ nào theo dõi người dùng đó, vì vậy tài khoản proxy sẽ theo dõi."
host: "Host"
selectSelf: "Chọn chính bạn"
selectUser: "Chọn người dùng"
recipient: "Người nhận"
annotation: "Bình luận"
@@ -199,6 +207,7 @@ perHour: "Mỗi Giờ"
perDay: "Mỗi Ngày"
stopActivityDelivery: "Ngưng gửi hoạt động"
blockThisInstance: "Chặn máy chủ này"
silenceThisInstance: "Máy chủ im lặng"
operations: "Vận hành"
software: "Phần mềm"
version: "Phiên bản"
@@ -218,6 +227,8 @@ clearCachedFiles: "Xóa bộ nhớ đệm"
clearCachedFilesConfirm: "Bạn có chắc muốn xóa sạch bộ nhớ đệm?"
blockedInstances: "Máy chủ đã chặn"
blockedInstancesDescription: "Danh sách những máy chủ bạn muốn chặn. Chúng sẽ không thể giao tiếp với máy chủy này nữa."
silencedInstances: "Máy chủ im lặng"
silencedInstancesDescription: "Đặt máy chủ mà bạn muốn tắt tiếng, phân tách bằng dấu xuống dòng. Tất cả tài khoản trên máy chủ bị tắt tiếng sẽ được coi là \"bị tắt tiếng\" và mọi hành động theo dõi sẽ được coi là yêu cầu. Không có tác dụng với những trường hợp bị chặn."
muteAndBlock: "Ẩn và Chặn"
mutedUsers: "Người đã ẩn"
blockedUsers: "Người đã chặn"
@@ -254,8 +265,8 @@ more: "Thêm nữa!"
featured: "Nổi bật"
usernameOrUserId: "Tên người dùng hoặc ID"
noSuchUser: "Không tìm thấy người dùng"
lookup: "Tìm kiếm"
announcements: "Thông báo"
lookup: "Tra cứu"
announcements: "Thông báo máy chủ"
imageUrl: "URL ảnh"
remove: "Xóa"
removed: "Đã xóa"
@@ -426,6 +437,7 @@ totpDescription: "Nhắn mã OTP bằng ứng dụng xác thực"
moderator: "Kiểm duyệt viên"
moderation: "Kiểm duyệt"
moderationNote: "Ghi chú kiểm duyệt"
moderationNoteDescription: "Bạn có thể điền vào những ghi chú chỉ được chia sẻ giữa những người kiểm duyệt."
addModerationNote: "Thêm ghi chú kiểm duyệt"
moderationLogs: "Nhật kí quản trị"
nUsersMentioned: "Dùng bởi {n} người"
@@ -546,6 +558,7 @@ volume: "Âm lượng"
masterVolume: "Âm thanh chung"
notUseSound: "Tắt tiếng"
details: "Chi tiết"
renoteDetails: "Tìm hiểu thêm về đăng lại "
chooseEmoji: "Chọn emoji"
unableToProcess: "Không thể hoàn tất hành động"
recentUsed: "Sử dụng gần đây"
@@ -644,9 +657,11 @@ regexpError: "Lỗi biểu thức"
regexpErrorDescription: "Xảy ra lỗi biểu thức ở dòng {line} của {tab} chữ ẩn:"
instanceMute: "Những máy chủ ẩn"
userSaysSomething: "{name} nói gì đó"
userSaysSomethingAbout: "{name} đã nói gì đó về \"{word}\""
makeActive: "Kích hoạt"
display: "Hiển thị"
copy: "Sao chép"
copiedToClipboard: "Đã sao chép vào clipboard"
metrics: "Số liệu"
overview: "Tổng quan"
logs: "Nhật ký"
@@ -1003,10 +1018,14 @@ copyErrorInfo: "Sao chép thông tin lỗi"
joinThisServer: "Đăng ký trên chủ máy này"
exploreOtherServers: "Tìm chủ máy khác"
letsLookAtTimeline: "Thử xem Timeline"
disableFederationConfirm: "Bạn có muốn làm điều đó mà không cần liên minh không?"
disableFederationConfirmWarn: "Ngay cả khi bị trì hoãn, bài đăng vẫn sẽ tiếp tục là công khai trừ khi được thiết lập khác. Bạn thường không cần phải làm điều này."
disableFederationOk: "Vô hiệu hoá"
invitationRequiredToRegister: "Phiên bản này chỉ dành cho người được mời. Bạn phải nhập mã mời hợp lệ để đăng ký."
emailNotSupported: "Máy chủ này không hỗ trợ gửi email"
postToTheChannel: "Đăng lên kênh"
cannotBeChangedLater: "Không thể thay đổi sau này."
reactionAcceptance: "Phản ứng chấp nhận"
likeOnly: "Chỉ lượt thích"
rolesAssignedToMe: "Vai trò được giao cho tôi"
resetPasswordConfirm: "Bạn thực sự muốn đặt lại mật khẩu?"
@@ -1049,6 +1068,8 @@ options: "Tùy chọn"
specifyUser: "Người dùng chỉ định"
failedToPreviewUrl: "Không thể xem trước"
update: "Cập nhật"
cancelReactionConfirm: "Bạn có muốn hủy phản ứng của mình không?"
changeReactionConfirm: "Bạn có muốn thay đổi phản ứng của mình không?"
later: "Để sau"
goToMisskey: "Tới Misskey"
installed: "Đã tải xuống"
@@ -1097,6 +1118,7 @@ mutualFollow: "Theo dõi lẫn nhau"
followingOrFollower: "Đang theo dõi hoặc người theo dõi"
externalServices: "Các dịch vụ bên ngoài"
sourceCode: "Mã nguồn"
repositoryUrlDescription: "Nếu bạn có kho lưu trữ mã nguồn có thể truy cập công khai, hãy nhập URL. Nếu bạn đang sử dụng Misskey theo mặc định (không thực hiện bất kỳ thay đổi nào đối với mã nguồn), hãy nhập https://github.com/misskey-dev/misskey."
feedback: "Phản hồi"
feedbackUrl: "URL phản hồi"
privacyPolicy: "Chính sách bảo mật"
@@ -1113,8 +1135,18 @@ releaseToRefresh: "Thả để làm mới"
refreshing: "Đang làm mới"
pullDownToRefresh: "Kéo xuống để làm mới"
cwNotationRequired: "Nếu \"Ẩn nội dung\" được bật thì cần phải có chú thích."
decorate: "Trang trí"
lastNDays: "{n} ngày trước"
userSaysSomethingSensitive: "Bài đăng có chứa các tập tin nhạy cảm từ {name}"
surrender: "Từ chối"
signinWithPasskey: "Đăng nhập bằng mật khẩu của bạn"
passkeyVerificationFailed: "Xác minh mật khẩu không thành công."
messageToFollower: "Tin nhắn cho người theo dõi"
yourNameContainsProhibitedWords: "Tên bạn đang cố gắng đổi có chứa chuỗi ký tự bị cấm."
yourNameContainsProhibitedWordsDescription: "Tên có chứa chuỗi ký tự bị cấm. Nếu bạn muốn sử dụng tên này, hãy liên hệ với quản trị viên máy chủ của bạn."
federationDisabled: "Liên kết bị vô hiệu hóa trên máy chủ này. Bạn không thể tương tác với người dùng trên các máy chủ khác."
reactAreYouSure: "Bạn có muốn phản hồi với \" {emoji} \" không?"
paste: "dán"
postForm: "Mẫu đăng"
information: "Giới thiệu"
_chat:
@@ -1123,6 +1155,9 @@ _chat:
members: "Thành viên"
home: "Trang chính"
send: "Gửi"
_accountSettings:
requireSigninToViewContents: "Yêu cầu đăng nhập để xem nội dung"
requireSigninToViewContentsDescription1: "Yêu cầu đăng nhập để xem tất cả ghi chú và nội dung khác mà bạn tạo. Điều này được kỳ vọng sẽ có hiệu quả trong việc ngăn chặn thông tin bị thu thập bởi các trình thu thập thông tin."
_delivery:
stop: "Đã vô hiệu hóa"
_type:
@@ -1146,8 +1181,33 @@ _initialAccountSetting:
pushNotificationDescription: "Bật thông báo đẩy sẽ cho phép bạn nhận thông báo từ {name} trực tiếp từ thiết bị của bạn."
initialAccountSettingCompleted: "Thiết lập tài khoản thành công!"
haveFun: "Hãy tận hưởng {name} nhé!"
youCanContinueTutorial: "Bạn có thể tiếp tục xem hướng dẫn về cách sử dụng {name} (Misskey) hoặc bạn có thể thoát khỏi phần thiết lập tại đây và bắt đầu sử dụng ngay lập tức."
startTutorial: "Bắt đầu hướng dẫn"
skipAreYouSure: "Bạn thực sự muốn bỏ qua mục thiết lập tài khoản?"
laterAreYouSure: "Bạn thực sự muốn thiết lập tài khoản vào lúc khác?"
_initialTutorial:
launchTutorial: "Bắt đầu hướng dẫn"
title: "Hướng dẫn"
wellDone: "Làm tốt!"
skipAreYouSure: "Thoát khỏi hướng dẫn?"
_landing:
title: "Chào mừng đến với Hướng dẫn"
description: "Tại đây, bạn có thể tìm hiểu những điều cơ bản về cách sử dụng Misskey và các tính năng của nó."
_note:
title: "Bài Viết là gì?"
description: "Các bài đăng trên Misskey được gọi là 'Bài Viết'. Ghi chú được sắp xếp theo thứ tự thời gian trên dòng thời gian và được cập nhật theo thời gian thực."
_timeline:
home: "Bạn có thể xem ghi chú từ những tài khoản bạn theo dõi."
local: "Bạn có thể xem ghi chú từ tất cả người dùng trên máy chủ này."
social: "Ghi chú từ dòng thời gian Trang chủ và Địa phương sẽ được hiển thị."
global: "Bạn có thể xem ghi chú từ tất cả các máy chủ được kết nối."
_postNote:
_visibility:
home: "Chỉ công khai trên dòng thời gian Trang chủ. Những người truy cập trang cá nhân của bạn, thông qua người theo dõi và thông qua ghi chú lại có thể thấy thông tin đó."
_timelineDescription:
home: "Trong dòng thời gian Trang chính, bạn có thể xem ghi chú từ các tài khoản bạn theo dõi."
local: "Trong dòng thời gian cục bộ, bạn có thể xem ghi chú từ tất cả người dùng trên máy chủ này."
social: "Dòng thời gian Xã hội hiển thị các ghi chú từ cả dòng thời gian Trang chủ và Địa phương."
_serverSettings:
iconUrl: "Biểu tượng URL"
appIconResolutionMustBe: "Độ phân giải tối thiểu là {resolution}."
@@ -1308,7 +1368,7 @@ _achievements:
_postedAt0min0sec:
title: "Tín hiệu báo giờ"
description: "Đăng bài vào 0 phút 0 giây"
flavor: "Piiiiiii ĐÂY LÀ TIẾNG NÓI VIỆT NAM"
flavor: "Pin pop pop pop"
_selfQuote:
title: "Nói đến bản thân"
description: "Trích dẫn bài viết của mình"
@@ -1923,11 +1983,21 @@ _abuseReport:
_recipientType:
mail: "Email"
_moderationLogTypes:
createRole: "Tạo một vai trò"
deleteRole: "Xóa vai trò"
updateRole: "Cập nhật vai trò"
assignRole: "Chỉ định cho vai trò"
unassignRole: "Bỏ gán vai trò"
suspend: "Vô hiệu hóa"
unsuspend: "Rã đông"
resetPassword: "Đặt lại mật khẩu"
createInvitation: "Tạo lời mời"
_reversi:
total: "Tổng cộng"
_customEmojisManager:
_local:
_list:
confirmDeleteEmojisDescription: "Xóa các biểu tượng cảm xúc {count} đã chọn. Bạn có muốn chạy nó không?"
_remoteLookupErrors:
_noSuchObject:
title: "Không tìm thấy"
+11 -2
View File
@@ -424,7 +424,7 @@ antennaExcludeBots: "排除机器人账户"
antennaKeywordsDescription: "AND 条件用空格分隔,OR 条件用换行符分隔。"
notifyAntenna: "开启通知"
withFileAntenna: "仅带有附件的帖子"
hideNotesInSensitiveChannel: "隐藏敏感频道内的帖子"
excludeNotesInSensitiveChannel: "排除敏感频道内的帖子"
enableServiceworker: "启用 ServiceWorker"
antennaUsersDescription: "指定用户名,一行一个"
caseSensitive: "区分大小写"
@@ -979,6 +979,7 @@ document: "文档"
numberOfPageCache: "缓存页数"
numberOfPageCacheDescription: "设置较高的值会更方便用户,但设备的负载和内存使用量会增加。"
logoutConfirm: "是否确认登出?"
logoutWillClearClientData: "登出时将会从浏览器中删除客户端的设置信息。如果想要在再次登入时恢复设置信息,请在设置里打开自动备份。"
lastActiveDate: "最后活跃时间"
statusbar: "状态栏"
pleaseSelect: "请选择"
@@ -1341,6 +1342,10 @@ right: "右"
bottom: "下"
top: "上"
embed: "嵌入"
settingsMigrating: "正在迁移设置,请稍候。(之后也可以在设置 → 其它 → 迁移旧设置来手动迁移)"
readonly: "只读"
goToDeck: "返回至 Deck"
federationJobs: "联合作业"
_chat:
noMessagesYet: "还没有消息"
newMessage: "新消息"
@@ -1370,6 +1375,7 @@ _chat:
muteThisRoom: "静音此房间"
deleteRoom: "删除房间"
chatNotAvailableForThisAccountOrServer: "此服务器或者账户还未开启聊天功能。"
chatIsReadOnlyForThisAccountOrServer: "此服务器或者账户内的聊天为只读。无法发布新信息或创建及加入群聊。"
chatNotAvailableInOtherAccount: "对方账户目前处于无法使用聊天的状态。"
cannotChatWithTheUser: "无法与此用户聊天"
cannotChatWithTheUser_description: "可能现在无法使用聊天,或者对方未开启聊天。"
@@ -1908,6 +1914,7 @@ _role:
canManageCustomEmojis: "管理自定义表情符号"
canManageAvatarDecorations: "管理头像挂件"
driveCapacity: "网盘容量"
maxFileSize: "可上传的最大文件大小"
alwaysMarkNsfw: "总是将文件标记为 NSFW"
canUpdateBioMedia: "可以更新头像和横幅"
pinMax: "帖子置顶数量限制"
@@ -1929,7 +1936,7 @@ _role:
canImportFollowing: "允许导入关注列表"
canImportMuting: "允许导入隐藏列表"
canImportUserLists: "允许导入用户列表"
canChat: "允许聊天"
chatAvailability: "允许聊天"
_condition:
roleAssignedTo: "已分配给手动角色"
isLocal: "是本地用户"
@@ -2363,6 +2370,7 @@ _widgets:
chooseList: "选择列表"
clicker: "点击器"
birthdayFollowings: "今天是他们的生日"
chat: "聊天"
_cw:
hide: "隐藏"
show: "查看更多"
@@ -2629,6 +2637,7 @@ _deck:
mentions: "提及"
direct: "指定用户"
roleTimeline: "角色时间线"
chat: "聊天"
_dialog:
charactersExceeded: "已经超过了最大字符数! 当前字符数 {current} / 限制字符数 {max}"
charactersBelow: "低于最小字符数!当前字符数 {current} / 限制字符数 {min}"
+13 -5
View File
@@ -424,7 +424,7 @@ antennaExcludeBots: "排除機器人帳戶"
antennaKeywordsDescription: "空格代表「以及」(AND),換行代表「或者」(OR)"
notifyAntenna: "通知有新貼文"
withFileAntenna: "僅帶有附件的貼文"
hideNotesInSensitiveChannel: "隱藏敏感頻道的貼文"
excludeNotesInSensitiveChannel: "排除敏感頻道的貼文"
enableServiceworker: "啟用瀏覽器的推播通知"
antennaUsersDescription: "填寫使用者名稱,以換行分隔"
caseSensitive: "區分大小寫"
@@ -979,6 +979,7 @@ document: "文件"
numberOfPageCache: "快取頁面數"
numberOfPageCacheDescription: "增加數量會提高便利性,但也會增加負荷與記憶體使用量。"
logoutConfirm: "確定要登出嗎?"
logoutWillClearClientData: "當您登出時,客戶端的設定資訊將從瀏覽器中清除。為了能夠在重新登入時恢復您的設定資訊,請啟用設定內的自動備份選項。"
lastActiveDate: "上次使用日期及時間"
statusbar: "狀態列"
pleaseSelect: "請選擇"
@@ -1308,7 +1309,7 @@ availableRoles: "可用角色"
acknowledgeNotesAndEnable: "了解注意事項後再開啟。"
federationSpecified: "此伺服器以白名單聯邦的方式運作。除了管理員指定的伺服器外,它無法與其他伺服器互動。"
federationDisabled: "此伺服器未開啟站台聯邦。無法與其他伺服器上的使用者互動。"
confirmOnReact: "反應時確認"
confirmOnReact: "在做出反應前先確認"
reactAreYouSure: "用「 {emoji} 」反應嗎?"
markAsSensitiveConfirm: "要將這個媒體設定為敏感嗎?"
unmarkAsSensitiveConfirm: "要解除這個媒體的敏感設定嗎?"
@@ -1342,6 +1343,9 @@ bottom: "下"
top: "上"
embed: "嵌入"
settingsMigrating: "正在移轉設定。請稍候……(之後也可以到「設定 → 其他 → 舊設定資訊移轉」中手動進行移轉)"
readonly: "唯讀"
goToDeck: "回去甲板"
federationJobs: "聯邦通訊作業"
_chat:
noMessagesYet: "尚無訊息"
newMessage: "新訊息"
@@ -1371,6 +1375,7 @@ _chat:
muteThisRoom: "此聊天室已靜音"
deleteRoom: "刪除聊天室"
chatNotAvailableForThisAccountOrServer: "這個伺服器或這個帳號的聊天功能尚未啟用。"
chatIsReadOnlyForThisAccountOrServer: "在此伺服器或此帳戶上的聊天是唯讀的。您無法發布新訊息、建立或加入聊天室。"
chatNotAvailableInOtherAccount: "對方的帳號無法使用聊天功能。"
cannotChatWithTheUser: "無法與此使用者聊天"
cannotChatWithTheUser_description: "聊天功能目前無法使用,或對方尚未開放聊天功能。"
@@ -1436,14 +1441,14 @@ _preferencesBackup:
_accountSettings:
requireSigninToViewContents: "須登入以顯示內容"
requireSigninToViewContentsDescription1: "必須登入才會顯示您建立的貼文等內容。可望有效防止資訊被爬蟲蒐集。"
requireSigninToViewContentsDescription2: "來自不支援 URL 預覽 (OGP) 網頁嵌入引用貼文的伺服器,也將停止顯示。"
requireSigninToViewContentsDescription2: "針對您貼文的 URL 預覽 (OGP) 網頁嵌入功能將會無法使用。而不支援引用貼文的伺服器,也將停止顯示。"
requireSigninToViewContentsDescription3: "這些限制可能不適用於被聯邦發送至遠端伺服器的內容。"
makeNotesFollowersOnlyBefore: "讓過去的貼文僅對追隨者顯示"
makeNotesFollowersOnlyBeforeDescription: "啟用此功能後,超過設定的日期和時間或超過設定時間的貼文將僅對追隨者顯示。 如果您再次停用它,貼文的公開狀態也會恢復原狀。"
makeNotesHiddenBefore: "隱藏過去的貼文"
makeNotesHiddenBeforeDescription: "啟用此功能後,超過設定的日期和時間或超過設定時間的貼文將僅對自己顯示(私密化)。 如果您再次停用它,貼文的公開狀態也會恢復原狀。"
mayNotEffectForFederatedNotes: "聯邦發送至遠端伺服器的貼文可能會不受影響。"
mayNotEffectSomeSituations: "這些限制已經簡化。它們可能不適用於某些情況,例如在遠端伺服器上檢視或管理時。"
mayNotEffectSomeSituations: "這些限制僅是簡化版本。在某些情況,例如在遠端伺服器上瀏覽或進行審核時,可能不會套用這些限制。"
notesHavePassedSpecifiedPeriod: "早於指定時間的貼文"
notesOlderThanSpecifiedDateAndTime: "指定時間和日期之前的貼文"
_abuseUserReport:
@@ -1910,6 +1915,7 @@ _role:
canManageCustomEmojis: "管理自訂表情符號"
canManageAvatarDecorations: "管理頭像裝飾"
driveCapacity: "雲端硬碟容量"
maxFileSize: "可上傳的最大檔案大小"
alwaysMarkNsfw: "總是將檔案標記為NSFW"
canUpdateBioMedia: "允許更新大頭貼和橫幅"
pinMax: "置頂貼文的最大數量"
@@ -1931,7 +1937,7 @@ _role:
canImportFollowing: "允許匯入追隨名單"
canImportMuting: "允許匯入靜音名單"
canImportUserLists: "允許匯入清單"
canChat: "允許聊天"
chatAvailability: "允許聊天"
_condition:
roleAssignedTo: "手動指派角色完成"
isLocal: "本地使用者"
@@ -2365,6 +2371,7 @@ _widgets:
chooseList: "選擇清單"
clicker: "點擊器"
birthdayFollowings: "今天生日的使用者"
chat: "聊天"
_cw:
hide: "隱藏"
show: "顯示內容"
@@ -2631,6 +2638,7 @@ _deck:
mentions: "提及"
direct: "指定使用者"
roleTimeline: "角色時間軸"
chat: "聊天"
_dialog:
charactersExceeded: "您的貼文太長了!現時字數 {current}/限制字數 {max}"
charactersBelow: "您的貼文太短了!現時字數 {current}/限制字數 {min}"
+12 -16
View File
@@ -1,12 +1,12 @@
{
"name": "misskey",
"version": "2025.4.0-rc.3",
"version": "2025.4.1-beta.7",
"codename": "nasubi",
"repository": {
"type": "git",
"url": "https://github.com/misskey-dev/misskey.git"
},
"packageManager": "pnpm@10.6.1",
"packageManager": "pnpm@10.10.0",
"workspaces": [
"packages/frontend-shared",
"packages/frontend",
@@ -52,29 +52,29 @@
},
"dependencies": {
"cssnano": "7.0.6",
"esbuild": "0.25.3",
"execa": "9.5.2",
"fast-glob": "3.3.3",
"glob": "11.0.2",
"ignore-walk": "7.0.0",
"js-yaml": "4.1.0",
"postcss": "8.5.3",
"tar": "7.4.3",
"terser": "5.39.0",
"typescript": "5.8.2",
"esbuild": "0.25.0",
"glob": "11.0.1"
"typescript": "5.8.3"
},
"devDependencies": {
"@misskey-dev/eslint-plugin": "2.1.0",
"@types/node": "22.13.10",
"@typescript-eslint/eslint-plugin": "8.26.0",
"@typescript-eslint/parser": "8.26.0",
"@types/node": "22.15.2",
"@typescript-eslint/eslint-plugin": "8.31.0",
"@typescript-eslint/parser": "8.31.0",
"cross-env": "7.0.3",
"cypress": "14.1.0",
"eslint": "9.22.0",
"cypress": "14.3.2",
"eslint": "9.25.1",
"globals": "16.0.0",
"ncp": "2.0.0",
"pnpm": "10.6.1",
"start-server-and-test": "2.0.10"
"pnpm": "10.10.0",
"start-server-and-test": "2.0.11"
},
"optionalDependencies": {
"@tensorflow/tfjs-core": "4.22.0"
@@ -82,10 +82,6 @@
"pnpm": {
"overrides": {
"@aiscript-dev/aiscript-languageserver": "-"
},
"patchedDependencies": {
"re2": "scripts/dependency-patches/re2.patch",
"vite": "scripts/dependency-patches/vite.patch"
}
}
}
@@ -0,0 +1,16 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
export class ExcludeNotesInSensitiveChannel1744075766000 {
name = 'ExcludeNotesInSensitiveChannel1744075766000'
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "antenna" RENAME COLUMN "hideNotesInSensitiveChannel" TO "excludeNotesInSensitiveChannel"`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "antenna" RENAME COLUMN "excludeNotesInSensitiveChannel" TO "hideNotesInSensitiveChannel"`);
}
}
@@ -0,0 +1,21 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
export class CompositeNoteIndex1745378064470 {
name = 'CompositeNoteIndex1745378064470';
async up(queryRunner) {
await queryRunner.query(`CREATE INDEX "IDX_724b311e6f883751f261ebe378" ON "note" ("userId", "id" DESC)`);
await queryRunner.query(`DROP INDEX IF EXISTS "IDX_5b87d9d19127bd5d92026017a7"`);
// Flush all cached Linear Scan Plans and redo statistics for composite index
// this is important for Postgres to learn that even in highly complex queries, using this index first can reduce the result set significantly
await queryRunner.query(`ANALYZE "user", "note"`);
}
async down(queryRunner) {
await queryRunner.query(`DROP INDEX IF EXISTS "IDX_724b311e6f883751f261ebe378"`);
await queryRunner.query(`CREATE INDEX "IDX_5b87d9d19127bd5d92026017a7" ON "note" ("userId")`);
}
}
+48 -46
View File
@@ -37,17 +37,17 @@
},
"optionalDependencies": {
"@swc/core-android-arm64": "1.3.11",
"@swc/core-darwin-arm64": "1.11.11",
"@swc/core-darwin-x64": "1.11.11",
"@swc/core-darwin-arm64": "1.11.22",
"@swc/core-darwin-x64": "1.11.22",
"@swc/core-freebsd-x64": "1.3.11",
"@swc/core-linux-arm-gnueabihf": "1.11.11",
"@swc/core-linux-arm64-gnu": "1.11.11",
"@swc/core-linux-arm64-musl": "1.11.11",
"@swc/core-linux-x64-gnu": "1.11.11",
"@swc/core-linux-x64-musl": "1.11.11",
"@swc/core-win32-arm64-msvc": "1.11.11",
"@swc/core-win32-ia32-msvc": "1.11.11",
"@swc/core-win32-x64-msvc": "1.11.11",
"@swc/core-linux-arm-gnueabihf": "1.11.22",
"@swc/core-linux-arm64-gnu": "1.11.22",
"@swc/core-linux-arm64-musl": "1.11.22",
"@swc/core-linux-x64-gnu": "1.11.22",
"@swc/core-linux-x64-musl": "1.11.22",
"@swc/core-win32-arm64-msvc": "1.11.22",
"@swc/core-win32-ia32-msvc": "1.11.22",
"@swc/core-win32-x64-msvc": "1.11.22",
"@tensorflow/tfjs": "4.22.0",
"@tensorflow/tfjs-node": "4.22.0",
"bufferutil": "4.0.9",
@@ -67,8 +67,8 @@
"utf-8-validate": "6.0.5"
},
"dependencies": {
"@aws-sdk/client-s3": "3.772.0",
"@aws-sdk/lib-storage": "3.772.0",
"@aws-sdk/client-s3": "3.797.0",
"@aws-sdk/lib-storage": "3.797.0",
"@discordapp/twemoji": "15.1.0",
"@fastify/accepts": "5.0.2",
"@fastify/cookie": "11.0.2",
@@ -78,21 +78,22 @@
"@fastify/multipart": "9.0.3",
"@fastify/static": "8.1.1",
"@fastify/view": "10.0.2",
"@misskey-dev/sharp-read-bmp": "1.2.0",
"@misskey-dev/summaly": "5.2.0",
"@napi-rs/canvas": "0.1.68",
"@nestjs/common": "11.0.12",
"@nestjs/core": "11.0.12",
"@nestjs/testing": "11.0.12",
"@misskey-dev/sharp-read-bmp": "1.3.0",
"@misskey-dev/summaly": "5.2.1",
"@napi-rs/canvas": "0.1.69",
"@nestjs/common": "11.1.0",
"@nestjs/core": "11.1.0",
"@nestjs/testing": "11.1.0",
"@peertube/http-signature": "1.7.0",
"@sentry/node": "8.55.0",
"@sentry/profiling-node": "8.55.0",
"@simplewebauthn/server": "12.0.0",
"@sinonjs/fake-timers": "11.3.1",
"@smithy/node-http-handler": "2.5.0",
"@swc/cli": "0.6.0",
"@swc/core": "1.11.11",
"@swc/cli": "0.7.3",
"@swc/core": "1.11.22",
"@twemoji/parser": "15.1.1",
"@types/redis-info": "3.0.3",
"accepts": "1.3.8",
"ajv": "8.17.1",
"archiver": "7.0.1",
@@ -100,7 +101,7 @@
"bcryptjs": "2.4.3",
"blurhash": "2.0.5",
"body-parser": "1.20.3",
"bullmq": "5.44.1",
"bullmq": "5.51.1",
"cacheable-lookup": "7.0.0",
"cbor": "9.0.2",
"chalk": "5.4.1",
@@ -111,28 +112,28 @@
"content-disposition": "0.5.4",
"date-fns": "2.30.0",
"deep-email-validator": "0.1.21",
"fastify": "5.2.1",
"fastify": "5.3.2",
"fastify-raw-body": "5.0.0",
"feed": "4.2.2",
"file-type": "19.6.0",
"fluent-ffmpeg": "2.1.3",
"form-data": "4.0.2",
"got": "14.4.6",
"got": "14.4.7",
"happy-dom": "16.8.1",
"hpagent": "1.2.0",
"htmlescape": "1.1.1",
"http-link-header": "1.1.3",
"ioredis": "5.6.0",
"ioredis": "5.6.1",
"ip-cidr": "4.0.2",
"ipaddr.js": "2.2.0",
"is-svg": "5.1.0",
"js-yaml": "4.1.0",
"jsdom": "26.0.0",
"jsdom": "26.1.0",
"json5": "2.2.3",
"jsonld": "8.3.3",
"jsrsasign": "11.1.0",
"juice": "11.0.1",
"meilisearch": "0.49.0",
"meilisearch": "0.50.0",
"mfm-js": "0.24.0",
"microformats-parser": "2.0.2",
"mime-types": "2.1.35",
@@ -142,15 +143,15 @@
"nanoid": "5.1.5",
"nested-property": "4.0.0",
"node-fetch": "3.3.2",
"nodemailer": "6.10.0",
"nodemailer": "6.10.1",
"nsfwjs": "4.2.0",
"oauth": "0.10.2",
"oauth2orize": "1.12.0",
"oauth2orize-pkce": "0.1.2",
"os-utils": "0.0.14",
"otpauth": "9.3.6",
"parse5": "7.2.1",
"pg": "8.14.1",
"otpauth": "9.4.0",
"parse5": "7.3.0",
"pg": "8.15.6",
"pkce-challenge": "4.1.0",
"probe-image-size": "7.2.3",
"promise-limit": "2.7.0",
@@ -159,24 +160,25 @@
"random-seed": "0.3.0",
"ratelimiter": "3.4.1",
"re2": "1.21.4",
"redis-info": "3.1.0",
"redis-lock": "0.1.4",
"reflect-metadata": "0.2.2",
"rename": "1.0.4",
"rss-parser": "3.13.0",
"rxjs": "7.8.2",
"sanitize-html": "2.15.0",
"sanitize-html": "2.16.0",
"secure-json-parse": "3.0.2",
"sharp": "0.33.5",
"sharp": "0.34.1",
"slacc": "0.0.10",
"strict-event-emitter-types": "2.0.0",
"stringz": "2.1.0",
"systeminformation": "5.25.11",
"tinycolor2": "1.6.0",
"tmp": "0.2.3",
"tsc-alias": "1.8.11",
"tsc-alias": "1.8.15",
"tsconfig-paths": "4.2.0",
"typeorm": "0.3.21",
"typescript": "5.8.2",
"typeorm": "0.3.22",
"typescript": "5.8.3",
"ulid": "2.4.0",
"vary": "1.1.2",
"web-push": "3.6.7",
@@ -185,10 +187,10 @@
},
"devDependencies": {
"@jest/globals": "29.7.0",
"@nestjs/platform-express": "10.4.15",
"@sentry/vue": "9.8.0",
"@nestjs/platform-express": "10.4.17",
"@sentry/vue": "9.14.0",
"@simplewebauthn/types": "12.0.0",
"@swc/jest": "0.2.37",
"@swc/jest": "0.2.38",
"@types/accepts": "1.3.7",
"@types/archiver": "6.0.3",
"@types/bcryptjs": "2.4.6",
@@ -205,28 +207,28 @@
"@types/jsrsasign": "10.5.15",
"@types/mime-types": "2.1.4",
"@types/ms": "0.7.34",
"@types/node": "22.13.10",
"@types/node": "22.15.2",
"@types/nodemailer": "6.4.17",
"@types/oauth": "0.9.6",
"@types/oauth2orize": "1.11.5",
"@types/oauth2orize-pkce": "0.1.2",
"@types/pg": "8.11.11",
"@types/pg": "8.11.14",
"@types/pug": "2.0.10",
"@types/qrcode": "1.5.5",
"@types/random-seed": "0.3.5",
"@types/ratelimiter": "3.4.6",
"@types/rename": "1.0.7",
"@types/sanitize-html": "2.13.0",
"@types/semver": "7.5.8",
"@types/sanitize-html": "2.15.0",
"@types/semver": "7.7.0",
"@types/simple-oauth2": "5.0.7",
"@types/sinonjs__fake-timers": "8.1.5",
"@types/tinycolor2": "1.4.6",
"@types/tmp": "0.2.6",
"@types/vary": "1.1.3",
"@types/web-push": "3.6.4",
"@types/ws": "8.18.0",
"@typescript-eslint/eslint-plugin": "8.27.0",
"@typescript-eslint/parser": "8.27.0",
"@types/ws": "8.18.1",
"@typescript-eslint/eslint-plugin": "8.31.0",
"@typescript-eslint/parser": "8.31.0",
"aws-sdk-client-mock": "4.1.0",
"cross-env": "7.0.3",
"eslint-plugin-import": "2.31.0",
@@ -234,7 +236,7 @@
"fkill": "9.0.0",
"jest": "29.7.0",
"jest-mock": "29.7.0",
"nodemon": "3.1.9",
"nodemon": "3.1.10",
"pid-port": "1.0.2",
"simple-oauth2": "5.1.0"
}
@@ -25,6 +25,7 @@ import InstanceChart from '@/core/chart/charts/instance.js';
import PerUserFollowingChart from '@/core/chart/charts/per-user-following.js';
import { SystemAccountService } from '@/core/SystemAccountService.js';
import { RoleService } from '@/core/RoleService.js';
import { AntennaService } from '@/core/AntennaService.js';
@Injectable()
export class AccountMoveService {
@@ -63,6 +64,7 @@ export class AccountMoveService {
private queueService: QueueService,
private systemAccountService: SystemAccountService,
private roleService: RoleService,
private antennaService: AntennaService,
) {
}
@@ -123,6 +125,7 @@ export class AccountMoveService {
this.copyMutings(src, dst),
this.copyRoles(src, dst),
this.updateLists(src, dst),
this.antennaService.onMoveAccount(src, dst),
]);
} catch {
/* skip if any error happens */
+60 -13
View File
@@ -5,18 +5,20 @@
import { Inject, Injectable } from '@nestjs/common';
import * as Redis from 'ioredis';
import { In } from 'typeorm';
import { FanoutTimelineService } from '@/core/FanoutTimelineService.js';
import type { GlobalEvents } from '@/core/GlobalEventService.js';
import { GlobalEventService } from '@/core/GlobalEventService.js';
import { UtilityService } from '@/core/UtilityService.js';
import { bindThis } from '@/decorators.js';
import { DI } from '@/di-symbols.js';
import * as Acct from '@/misc/acct.js';
import type { Packed } from '@/misc/json-schema.js';
import type { AntennasRepository, UserListMembershipsRepository } from '@/models/_.js';
import type { MiAntenna } from '@/models/Antenna.js';
import type { MiNote } from '@/models/Note.js';
import type { MiUser } from '@/models/User.js';
import { GlobalEventService } from '@/core/GlobalEventService.js';
import * as Acct from '@/misc/acct.js';
import type { Packed } from '@/misc/json-schema.js';
import { DI } from '@/di-symbols.js';
import type { AntennasRepository, UserListMembershipsRepository } from '@/models/_.js';
import { UtilityService } from '@/core/UtilityService.js';
import { bindThis } from '@/decorators.js';
import type { GlobalEvents } from '@/core/GlobalEventService.js';
import { FanoutTimelineService } from '@/core/FanoutTimelineService.js';
import { CacheService } from './CacheService.js';
import type { OnApplicationShutdown } from '@nestjs/common';
@Injectable()
@@ -37,6 +39,7 @@ export class AntennaService implements OnApplicationShutdown {
@Inject(DI.userListMembershipsRepository)
private userListMembershipsRepository: UserListMembershipsRepository,
private cacheService: CacheService,
private utilityService: UtilityService,
private globalEventService: GlobalEventService,
private fanoutTimelineService: FanoutTimelineService,
@@ -111,10 +114,7 @@ export class AntennaService implements OnApplicationShutdown {
@bindThis
public async checkHitAntenna(antenna: MiAntenna, note: (MiNote | Packed<'Note'>), noteUser: { id: MiUser['id']; username: string; host: string | null; isBot: boolean; }): Promise<boolean> {
if (note.visibility === 'specified') return false;
if (note.visibility === 'followers') return false;
if (antenna.hideNotesInSensitiveChannel && note.channel?.isSensitive) return false;
if (antenna.excludeNotesInSensitiveChannel && note.channel?.isSensitive) return false;
if (antenna.excludeBots && noteUser.isBot) return false;
@@ -122,6 +122,18 @@ export class AntennaService implements OnApplicationShutdown {
if (!antenna.withReplies && note.replyId != null) return false;
if (note.visibility === 'specified') {
if (note.userId !== antenna.userId) {
if (note.visibleUserIds == null) return false;
if (!note.visibleUserIds.includes(antenna.userId)) return false;
}
}
if (note.visibility === 'followers') {
const isFollowing = Object.hasOwn(await this.cacheService.userFollowingsCache.fetch(antenna.userId), note.userId);
if (!isFollowing && antenna.userId !== note.userId) return false;
}
if (antenna.src === 'home') {
// TODO
} else if (antenna.src === 'list') {
@@ -208,6 +220,41 @@ export class AntennaService implements OnApplicationShutdown {
return this.antennas;
}
@bindThis
public async onMoveAccount(src: MiUser, dst: MiUser): Promise<void> {
// There is a possibility for users to add the srcUser to their antennas, but it's low, so we don't check it.
// Get MiAntenna[] from cache and filter to select antennas with the src user is in the users list
const srcUserAcct = this.utilityService.getFullApAccount(src.username, src.host).toLowerCase();
const antennasToMigrate = (await this.getAntennas()).filter(antenna => {
return antenna.users.some(user => {
const { username, host } = Acct.parse(user);
return this.utilityService.getFullApAccount(username, host).toLowerCase() === srcUserAcct;
});
});
if (antennasToMigrate.length === 0) return;
const antennaIds = antennasToMigrate.map(x => x.id);
// Update the antennas by appending dst users acct to the users list
const dstUserAcct = '@' + Acct.toString({ username: dst.username, host: dst.host });
await this.antennasRepository.createQueryBuilder('antenna')
.update()
.set({
users: () => 'array_append(antenna.users, :dstUserAcct)',
})
.where('antenna.id IN (:...antennaIds)', { antennaIds })
.setParameters({ dstUserAcct })
.execute();
// announce update to event
for (const newAntenna of await this.antennasRepository.findBy({ id: In(antennaIds) })) {
this.globalEventService.publishInternalEvent('antennaUpdated', newAntenna);
}
}
@bindThis
public dispose(): void {
this.redisForSub.off('message', this.onRedisMessage);
+2 -2
View File
@@ -232,7 +232,7 @@ export class ChatService {
const packedMessageForTo = await this.chatEntityService.packMessageDetailed(inserted, toUser);
this.globalEventService.publishMainStream(toUser.id, 'newChatMessage', packedMessageForTo);
//this.pushNotificationService.pushNotification(toUser.id, 'newChatMessage', packedMessageForTo);
this.pushNotificationService.pushNotification(toUser.id, 'newChatMessage', packedMessageForTo);
}, 3000);
}
@@ -302,7 +302,7 @@ export class ChatService {
if (marker == null) continue;
this.globalEventService.publishMainStream(membershipsOtherThanMe[i].userId, 'newChatMessage', packedMessageForTo);
//this.pushNotificationService.pushNotification(membershipsOtherThanMe[i].userId, 'newChatMessage', packedMessageForTo);
this.pushNotificationService.pushNotification(membershipsOtherThanMe[i].userId, 'newChatMessage', packedMessageForTo);
}
}, 3000);
@@ -522,9 +522,16 @@ export class DriveService {
const policies = await this.roleService.getUserPolicies(user.id);
const driveCapacity = 1024 * 1024 * policies.driveCapacityMb;
const maxFileSize = 1024 * 1024 * policies.maxFileSizeMb;
this.registerLogger.debug('drive capacity override applied');
this.registerLogger.debug(`overrideCap: ${driveCapacity}bytes, usage: ${usage}bytes, u+s: ${usage + info.size}bytes`);
if (maxFileSize < info.size) {
if (isLocalUser) {
throw new IdentifiableError('f9e4e5f3-4df4-40b5-b400-f236945f7073', 'Max file size exceeded.');
}
}
// If usage limit exceeded
if (driveCapacity < usage + info.size) {
if (isLocalUser) {
@@ -8,10 +8,12 @@ import { DI } from '@/di-symbols.js';
import { bindThis } from '@/decorators.js';
import type { MiUser } from '@/models/User.js';
import type { MiNote } from '@/models/Note.js';
import type { MiMeta } from '@/models/Meta.js';
import { Packed } from '@/misc/json-schema.js';
import type { NotesRepository } from '@/models/_.js';
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
import { FanoutTimelineName, FanoutTimelineService } from '@/core/FanoutTimelineService.js';
import { UtilityService } from '@/core/UtilityService.js';
import { isUserRelated } from '@/misc/is-user-related.js';
import { isQuote, isRenote } from '@/misc/is-renote.js';
import { CacheService } from '@/core/CacheService.js';
@@ -30,6 +32,7 @@ type TimelineOptions = {
alwaysIncludeMyNotes?: boolean;
ignoreAuthorFromBlock?: boolean;
ignoreAuthorFromMute?: boolean;
ignoreAuthorFromInstanceBlock?: boolean;
excludeNoFiles?: boolean;
excludeReplies?: boolean;
excludePureRenotes: boolean;
@@ -42,9 +45,13 @@ export class FanoutTimelineEndpointService {
@Inject(DI.notesRepository)
private notesRepository: NotesRepository,
@Inject(DI.meta)
private meta: MiMeta,
private noteEntityService: NoteEntityService,
private cacheService: CacheService,
private fanoutTimelineService: FanoutTimelineService,
private utilityService: UtilityService,
) {
}
@@ -54,7 +61,7 @@ export class FanoutTimelineEndpointService {
}
@bindThis
private async getMiNotes(ps: TimelineOptions): Promise<MiNote[]> {
async getMiNotes(ps: TimelineOptions): Promise<MiNote[]> {
// 呼び出し元と以下の処理をシンプルにするためにdbFallbackを置き換える
if (!ps.useDbFallback) ps.dbFallback = () => Promise.resolve([]);
@@ -119,6 +126,19 @@ export class FanoutTimelineEndpointService {
};
}
{
const parentFilter = filter;
filter = (note) => {
if (!ps.ignoreAuthorFromInstanceBlock) {
if (this.utilityService.isBlockedHost(this.meta.blockedHosts, note.userHost)) return false;
}
if (note.userId !== note.renoteUserId && this.utilityService.isBlockedHost(this.meta.blockedHosts, note.renoteUserHost)) return false;
if (note.userId !== note.replyUserId && this.utilityService.isBlockedHost(this.meta.blockedHosts, note.replyUserHost)) return false;
return parentFilter(note);
};
}
const redisTimeline: MiNote[] = [];
let readFromRedis = 0;
let lastSuccessfulRate = 1; // rateをキャッシュする?
@@ -34,6 +34,7 @@ export const webpDefault: sharp.WebpOptions = {
smartSubsample: true,
mixed: true,
effort: 2,
loop: 0,
};
export const avifDefault: sharp.AvifOptions = {
+8 -2
View File
@@ -6,7 +6,7 @@
import { URL } from 'node:url';
import { Inject, Injectable } from '@nestjs/common';
import * as parse5 from 'parse5';
import { Window, XMLSerializer } from 'happy-dom';
import { type Document, type HTMLParagraphElement, Window, XMLSerializer } from 'happy-dom';
import { DI } from '@/di-symbols.js';
import type { Config } from '@/config.js';
import { intersperse } from '@/misc/prelude/array.js';
@@ -23,6 +23,8 @@ type ChildNode = DefaultTreeAdapterMap['childNode'];
const urlRegex = /^https?:\/\/[\w\/:%#@$&?!()\[\]~.,=+\-]+/;
const urlRegexFull = /^https?:\/\/[\w\/:%#@$&?!()\[\]~.,=+\-]+$/;
export type Appender = (document: Document, body: HTMLParagraphElement) => void;
@Injectable()
export class MfmService {
constructor(
@@ -267,7 +269,7 @@ export class MfmService {
}
@bindThis
public toHtml(nodes: mfm.MfmNode[] | null, mentionedRemoteUsers: IMentionedRemoteUsers = []) {
public toHtml(nodes: mfm.MfmNode[] | null, mentionedRemoteUsers: IMentionedRemoteUsers = [], additionalAppenders: Appender[] = []) {
if (nodes == null) {
return null;
}
@@ -492,6 +494,10 @@ export class MfmService {
appendChildren(nodes, body);
for (const additionalAppender of additionalAppenders) {
additionalAppender(doc, body);
}
// Remove the unnecessary namespace
const serialized = new XMLSerializer().serializeToString(body).replace(/^\s*<p xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">/, '<p>');
@@ -576,7 +576,14 @@ export class NoteCreateService implements OnApplicationShutdown {
noteId: note.id,
}, {
delay,
removeOnComplete: true,
removeOnComplete: {
age: 3600 * 24 * 7, // keep up to 7 days
count: 30,
},
removeOnFail: {
age: 3600 * 24 * 7, // keep up to 7 days
count: 100,
},
});
}
@@ -22,6 +22,7 @@ type PushNotificationsTypes = {
note: Packed<'Note'>;
};
'readAllNotifications': undefined;
newChatMessage: Packed<'ChatMessage'>;
};
// Reduce length because push message servers have character limits
+37 -1
View File
@@ -7,7 +7,7 @@ import { Inject, Injectable } from '@nestjs/common';
import { Brackets, ObjectLiteral } from 'typeorm';
import { DI } from '@/di-symbols.js';
import type { MiUser } from '@/models/User.js';
import type { UserProfilesRepository, FollowingsRepository, ChannelFollowingsRepository, BlockingsRepository, NoteThreadMutingsRepository, MutingsRepository, RenoteMutingsRepository } from '@/models/_.js';
import type { UserProfilesRepository, FollowingsRepository, ChannelFollowingsRepository, BlockingsRepository, NoteThreadMutingsRepository, MutingsRepository, RenoteMutingsRepository, MiMeta } from '@/models/_.js';
import { bindThis } from '@/decorators.js';
import { IdService } from '@/core/IdService.js';
import type { SelectQueryBuilder } from 'typeorm';
@@ -36,6 +36,9 @@ export class QueryService {
@Inject(DI.renoteMutingsRepository)
private renoteMutingsRepository: RenoteMutingsRepository,
@Inject(DI.meta)
private meta: MiMeta,
private idService: IdService,
) {
}
@@ -251,4 +254,37 @@ export class QueryService {
q.setParameters(mutingQuery.getParameters());
}
@bindThis
public generateBlockedHostQueryForNote(q: SelectQueryBuilder<any>, excludeAuthor?: boolean): void {
let nonBlockedHostQuery: (part: string) => string;
if (this.meta.blockedHosts.length === 0) {
nonBlockedHostQuery = () => '1=1';
} else {
nonBlockedHostQuery = (match: string) => `${match} NOT ILIKE ALL(ARRAY[:...blocked])`;
q.setParameters({ blocked: this.meta.blockedHosts.flatMap(x => [x, `%.${x}`]) });
}
if (excludeAuthor) {
const instanceSuspension = (user: string) => new Brackets(qb => qb
.where(`note.${user}Id IS NULL`) // no corresponding user
.orWhere(`note.userId = note.${user}Id`)
.orWhere(`note.${user}Host IS NULL`) // local
.orWhere(nonBlockedHostQuery(`note.${user}Host`)));
q
.andWhere(instanceSuspension('replyUser'))
.andWhere(instanceSuspension('renoteUser'));
} else {
const instanceSuspension = (user: string) => new Brackets(qb => qb
.where(`note.${user}Id IS NULL`) // no corresponding user
.orWhere(`note.${user}Host IS NULL`) // local
.orWhere(nonBlockedHostQuery(`note.${user}Host`)));
q
.andWhere(instanceSuspension('user'))
.andWhere(instanceSuspension('replyUser'))
.andWhere(instanceSuspension('renoteUser'));
}
}
}
+427 -71
View File
@@ -5,6 +5,8 @@
import { randomUUID } from 'node:crypto';
import { Inject, Injectable } from '@nestjs/common';
import { MetricsTime, type JobType } from 'bullmq';
import { parse as parseRedisInfo } from 'redis-info';
import type { IActivity } from '@/core/activitypub/type.js';
import type { MiDriveFile } from '@/models/DriveFile.js';
import type { MiWebhook, WebhookEventTypes } from '@/models/Webhook.js';
@@ -38,6 +40,18 @@ import type {
import type httpSignature from '@peertube/http-signature';
import type * as Bull from 'bullmq';
export const QUEUE_TYPES = [
'system',
'endedPollNotification',
'deliver',
'inbox',
'db',
'relationship',
'objectStorage',
'userWebhookDeliver',
'systemWebhookDeliver',
] as const;
@Injectable()
export class QueueService {
constructor(
@@ -57,50 +71,58 @@ export class QueueService {
this.systemQueue.add('tickCharts', {
}, {
repeat: { pattern: '55 * * * *' },
removeOnComplete: true,
removeOnComplete: 10,
removeOnFail: 30,
});
this.systemQueue.add('resyncCharts', {
}, {
repeat: { pattern: '0 0 * * *' },
removeOnComplete: true,
removeOnComplete: 10,
removeOnFail: 30,
});
this.systemQueue.add('cleanCharts', {
}, {
repeat: { pattern: '0 0 * * *' },
removeOnComplete: true,
removeOnComplete: 10,
removeOnFail: 30,
});
this.systemQueue.add('aggregateRetention', {
}, {
repeat: { pattern: '0 0 * * *' },
removeOnComplete: true,
removeOnComplete: 10,
removeOnFail: 30,
});
this.systemQueue.add('clean', {
}, {
repeat: { pattern: '0 0 * * *' },
removeOnComplete: true,
removeOnComplete: 10,
removeOnFail: 30,
});
this.systemQueue.add('checkExpiredMutings', {
}, {
repeat: { pattern: '*/5 * * * *' },
removeOnComplete: true,
removeOnComplete: 10,
removeOnFail: 30,
});
this.systemQueue.add('bakeBufferedReactions', {
}, {
repeat: { pattern: '0 0 * * *' },
removeOnComplete: true,
removeOnComplete: 10,
removeOnFail: 30,
});
this.systemQueue.add('checkModeratorsActivity', {
}, {
// 毎時30分に起動
repeat: { pattern: '30 * * * *' },
removeOnComplete: true,
removeOnComplete: 10,
removeOnFail: 30,
});
}
@@ -122,13 +144,21 @@ export class QueueService {
isSharedInbox,
};
return this.deliverQueue.add(to, data, {
const label = to.replace('https://', '').replace('/inbox', '');
return this.deliverQueue.add(label, data, {
attempts: this.config.deliverJobMaxAttempts ?? 12,
backoff: {
type: 'custom',
},
removeOnComplete: true,
removeOnFail: true,
removeOnComplete: {
age: 3600 * 24 * 7, // keep up to 7 days
count: 30,
},
removeOnFail: {
age: 3600 * 24 * 7, // keep up to 7 days
count: 100,
},
});
}
@@ -150,12 +180,18 @@ export class QueueService {
backoff: {
type: 'custom',
},
removeOnComplete: true,
removeOnFail: true,
removeOnComplete: {
age: 3600 * 24 * 7, // keep up to 7 days
count: 30,
},
removeOnFail: {
age: 3600 * 24 * 7, // keep up to 7 days
count: 100,
},
};
await this.deliverQueue.addBulk(Array.from(inboxes.entries(), d => ({
name: d[0],
name: d[0].replace('https://', '').replace('/inbox', ''),
data: {
user,
content: contentBody,
@@ -176,13 +212,21 @@ export class QueueService {
signature,
};
return this.inboxQueue.add('', data, {
const label = (activity.id ?? '').replace('https://', '').replace('/activity', '');
return this.inboxQueue.add(label, data, {
attempts: this.config.inboxJobMaxAttempts ?? 8,
backoff: {
type: 'custom',
},
removeOnComplete: true,
removeOnFail: true,
removeOnComplete: {
age: 3600 * 24 * 7, // keep up to 7 days
count: 30,
},
removeOnFail: {
age: 3600 * 24 * 7, // keep up to 7 days
count: 100,
},
});
}
@@ -191,8 +235,14 @@ export class QueueService {
return this.dbQueue.add('deleteDriveFiles', {
user: { id: user.id },
}, {
removeOnComplete: true,
removeOnFail: true,
removeOnComplete: {
age: 3600 * 24 * 7, // keep up to 7 days
count: 30,
},
removeOnFail: {
age: 3600 * 24 * 7, // keep up to 7 days
count: 100,
},
});
}
@@ -201,8 +251,14 @@ export class QueueService {
return this.dbQueue.add('exportCustomEmojis', {
user: { id: user.id },
}, {
removeOnComplete: true,
removeOnFail: true,
removeOnComplete: {
age: 3600 * 24 * 7, // keep up to 7 days
count: 30,
},
removeOnFail: {
age: 3600 * 24 * 7, // keep up to 7 days
count: 100,
},
});
}
@@ -211,8 +267,14 @@ export class QueueService {
return this.dbQueue.add('exportNotes', {
user: { id: user.id },
}, {
removeOnComplete: true,
removeOnFail: true,
removeOnComplete: {
age: 3600 * 24 * 7, // keep up to 7 days
count: 30,
},
removeOnFail: {
age: 3600 * 24 * 7, // keep up to 7 days
count: 100,
},
});
}
@@ -221,8 +283,14 @@ export class QueueService {
return this.dbQueue.add('exportClips', {
user: { id: user.id },
}, {
removeOnComplete: true,
removeOnFail: true,
removeOnComplete: {
age: 3600 * 24 * 7, // keep up to 7 days
count: 30,
},
removeOnFail: {
age: 3600 * 24 * 7, // keep up to 7 days
count: 100,
},
});
}
@@ -231,8 +299,14 @@ export class QueueService {
return this.dbQueue.add('exportFavorites', {
user: { id: user.id },
}, {
removeOnComplete: true,
removeOnFail: true,
removeOnComplete: {
age: 3600 * 24 * 7, // keep up to 7 days
count: 30,
},
removeOnFail: {
age: 3600 * 24 * 7, // keep up to 7 days
count: 100,
},
});
}
@@ -243,8 +317,14 @@ export class QueueService {
excludeMuting,
excludeInactive,
}, {
removeOnComplete: true,
removeOnFail: true,
removeOnComplete: {
age: 3600 * 24 * 7, // keep up to 7 days
count: 30,
},
removeOnFail: {
age: 3600 * 24 * 7, // keep up to 7 days
count: 100,
},
});
}
@@ -253,8 +333,14 @@ export class QueueService {
return this.dbQueue.add('exportMuting', {
user: { id: user.id },
}, {
removeOnComplete: true,
removeOnFail: true,
removeOnComplete: {
age: 3600 * 24 * 7, // keep up to 7 days
count: 30,
},
removeOnFail: {
age: 3600 * 24 * 7, // keep up to 7 days
count: 100,
},
});
}
@@ -263,8 +349,14 @@ export class QueueService {
return this.dbQueue.add('exportBlocking', {
user: { id: user.id },
}, {
removeOnComplete: true,
removeOnFail: true,
removeOnComplete: {
age: 3600 * 24 * 7, // keep up to 7 days
count: 30,
},
removeOnFail: {
age: 3600 * 24 * 7, // keep up to 7 days
count: 100,
},
});
}
@@ -273,8 +365,14 @@ export class QueueService {
return this.dbQueue.add('exportUserLists', {
user: { id: user.id },
}, {
removeOnComplete: true,
removeOnFail: true,
removeOnComplete: {
age: 3600 * 24 * 7, // keep up to 7 days
count: 30,
},
removeOnFail: {
age: 3600 * 24 * 7, // keep up to 7 days
count: 100,
},
});
}
@@ -283,8 +381,14 @@ export class QueueService {
return this.dbQueue.add('exportAntennas', {
user: { id: user.id },
}, {
removeOnComplete: true,
removeOnFail: true,
removeOnComplete: {
age: 3600 * 24 * 7, // keep up to 7 days
count: 30,
},
removeOnFail: {
age: 3600 * 24 * 7, // keep up to 7 days
count: 100,
},
});
}
@@ -295,8 +399,14 @@ export class QueueService {
fileId: fileId,
withReplies,
}, {
removeOnComplete: true,
removeOnFail: true,
removeOnComplete: {
age: 3600 * 24 * 7, // keep up to 7 days
count: 30,
},
removeOnFail: {
age: 3600 * 24 * 7, // keep up to 7 days
count: 100,
},
});
}
@@ -312,8 +422,14 @@ export class QueueService {
user: { id: user.id },
fileId: fileId,
}, {
removeOnComplete: true,
removeOnFail: true,
removeOnComplete: {
age: 3600 * 24 * 7, // keep up to 7 days
count: 30,
},
removeOnFail: {
age: 3600 * 24 * 7, // keep up to 7 days
count: 100,
},
});
}
@@ -323,8 +439,14 @@ export class QueueService {
user: { id: user.id },
fileId: fileId,
}, {
removeOnComplete: true,
removeOnFail: true,
removeOnComplete: {
age: 3600 * 24 * 7, // keep up to 7 days
count: 30,
},
removeOnFail: {
age: 3600 * 24 * 7, // keep up to 7 days
count: 100,
},
});
}
@@ -344,8 +466,14 @@ export class QueueService {
name,
data,
opts: {
removeOnComplete: true,
removeOnFail: true,
removeOnComplete: {
age: 3600 * 24 * 7, // keep up to 7 days
count: 30,
},
removeOnFail: {
age: 3600 * 24 * 7, // keep up to 7 days
count: 100,
},
},
};
}
@@ -356,8 +484,14 @@ export class QueueService {
user: { id: user.id },
fileId: fileId,
}, {
removeOnComplete: true,
removeOnFail: true,
removeOnComplete: {
age: 3600 * 24 * 7, // keep up to 7 days
count: 30,
},
removeOnFail: {
age: 3600 * 24 * 7, // keep up to 7 days
count: 100,
},
});
}
@@ -367,8 +501,14 @@ export class QueueService {
user: { id: user.id },
fileId: fileId,
}, {
removeOnComplete: true,
removeOnFail: true,
removeOnComplete: {
age: 3600 * 24 * 7, // keep up to 7 days
count: 30,
},
removeOnFail: {
age: 3600 * 24 * 7, // keep up to 7 days
count: 100,
},
});
}
@@ -378,8 +518,14 @@ export class QueueService {
user: { id: user.id },
antenna,
}, {
removeOnComplete: true,
removeOnFail: true,
removeOnComplete: {
age: 3600 * 24 * 7, // keep up to 7 days
count: 30,
},
removeOnFail: {
age: 3600 * 24 * 7, // keep up to 7 days
count: 100,
},
});
}
@@ -389,8 +535,14 @@ export class QueueService {
user: { id: user.id },
soft: opts.soft,
}, {
removeOnComplete: true,
removeOnFail: true,
removeOnComplete: {
age: 3600 * 24 * 7, // keep up to 7 days
count: 30,
},
removeOnFail: {
age: 3600 * 24 * 7, // keep up to 7 days
count: 100,
},
});
}
@@ -440,8 +592,14 @@ export class QueueService {
withReplies: data.withReplies,
},
opts: {
removeOnComplete: true,
removeOnFail: true,
removeOnComplete: {
age: 3600 * 24 * 7, // keep up to 7 days
count: 30,
},
removeOnFail: {
age: 3600 * 24 * 7, // keep up to 7 days
count: 100,
},
...opts,
},
};
@@ -452,16 +610,28 @@ export class QueueService {
return this.objectStorageQueue.add('deleteFile', {
key: key,
}, {
removeOnComplete: true,
removeOnFail: true,
removeOnComplete: {
age: 3600 * 24 * 7, // keep up to 7 days
count: 30,
},
removeOnFail: {
age: 3600 * 24 * 7, // keep up to 7 days
count: 100,
},
});
}
@bindThis
public createCleanRemoteFilesJob() {
return this.objectStorageQueue.add('cleanRemoteFiles', {}, {
removeOnComplete: true,
removeOnFail: true,
removeOnComplete: {
age: 3600 * 24 * 7, // keep up to 7 days
count: 30,
},
removeOnFail: {
age: 3600 * 24 * 7, // keep up to 7 days
count: 100,
},
});
}
@@ -492,8 +662,14 @@ export class QueueService {
backoff: {
type: 'custom',
},
removeOnComplete: true,
removeOnFail: true,
removeOnComplete: {
age: 3600 * 24 * 7, // keep up to 7 days
count: 30,
},
removeOnFail: {
age: 3600 * 24 * 7, // keep up to 7 days
count: 100,
},
});
}
@@ -523,21 +699,201 @@ export class QueueService {
backoff: {
type: 'custom',
},
removeOnComplete: true,
removeOnFail: true,
removeOnComplete: {
age: 3600 * 24 * 7, // keep up to 7 days
count: 30,
},
removeOnFail: {
age: 3600 * 24 * 7, // keep up to 7 days
count: 100,
},
});
}
@bindThis
public destroy() {
this.deliverQueue.once('cleaned', (jobs, status) => {
//deliverLogger.succ(`Cleaned ${jobs.length} ${status} jobs`);
});
this.deliverQueue.clean(0, 0, 'delayed');
private getQueue(type: typeof QUEUE_TYPES[number]): Bull.Queue {
switch (type) {
case 'system': return this.systemQueue;
case 'endedPollNotification': return this.endedPollNotificationQueue;
case 'deliver': return this.deliverQueue;
case 'inbox': return this.inboxQueue;
case 'db': return this.dbQueue;
case 'relationship': return this.relationshipQueue;
case 'objectStorage': return this.objectStorageQueue;
case 'userWebhookDeliver': return this.userWebhookDeliverQueue;
case 'systemWebhookDeliver': return this.systemWebhookDeliverQueue;
default: throw new Error(`Unrecognized queue type: ${type}`);
}
}
this.inboxQueue.once('cleaned', (jobs, status) => {
//inboxLogger.succ(`Cleaned ${jobs.length} ${status} jobs`);
@bindThis
public async queueClear(queueType: typeof QUEUE_TYPES[number], state: '*' | 'completed' | 'wait' | 'active' | 'paused' | 'prioritized' | 'delayed' | 'failed') {
const queue = this.getQueue(queueType);
if (state === '*') {
await Promise.all([
queue.clean(0, 0, 'completed'),
queue.clean(0, 0, 'wait'),
queue.clean(0, 0, 'active'),
queue.clean(0, 0, 'paused'),
queue.clean(0, 0, 'prioritized'),
queue.clean(0, 0, 'delayed'),
queue.clean(0, 0, 'failed'),
]);
} else {
await queue.clean(0, 0, state);
}
}
@bindThis
public async queuePromoteJobs(queueType: typeof QUEUE_TYPES[number]) {
const queue = this.getQueue(queueType);
await queue.promoteJobs();
}
@bindThis
public async queueRetryJob(queueType: typeof QUEUE_TYPES[number], jobId: string) {
const queue = this.getQueue(queueType);
const job: Bull.Job | null = await queue.getJob(jobId);
if (job) {
if (job.finishedOn != null) {
await job.retry();
} else {
await job.promote();
}
}
}
@bindThis
public async queueRemoveJob(queueType: typeof QUEUE_TYPES[number], jobId: string) {
const queue = this.getQueue(queueType);
const job: Bull.Job | null = await queue.getJob(jobId);
if (job) {
await job.remove();
}
}
@bindThis
private packJobData(job: Bull.Job) {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
const stacktrace = job.stacktrace ? job.stacktrace.filter(Boolean) : [];
stacktrace.reverse();
return {
id: job.id,
name: job.name,
data: job.data,
opts: job.opts,
timestamp: job.timestamp,
processedOn: job.processedOn,
processedBy: job.processedBy,
finishedOn: job.finishedOn,
progress: job.progress,
attempts: job.attemptsMade,
delay: job.delay,
failedReason: job.failedReason,
stacktrace: stacktrace,
returnValue: job.returnvalue,
isFailed: !!job.failedReason || (Array.isArray(stacktrace) && stacktrace.length > 0),
};
}
@bindThis
public async queueGetJob(queueType: typeof QUEUE_TYPES[number], jobId: string) {
const queue = this.getQueue(queueType);
const job: Bull.Job | null = await queue.getJob(jobId);
if (job) {
return this.packJobData(job);
} else {
throw new Error(`Job not found: ${jobId}`);
}
}
@bindThis
public async queueGetJobs(queueType: typeof QUEUE_TYPES[number], jobTypes: JobType[], search?: string) {
const RETURN_LIMIT = 100;
const queue = this.getQueue(queueType);
let jobs: Bull.Job[];
if (search) {
jobs = await queue.getJobs(jobTypes, 0, 1000);
jobs = jobs.filter(job => {
const jobString = JSON.stringify(job).toLowerCase();
return search.toLowerCase().split(' ').every(term => {
return jobString.includes(term);
});
});
jobs = jobs.slice(0, RETURN_LIMIT);
} else {
jobs = await queue.getJobs(jobTypes, 0, RETURN_LIMIT);
}
return jobs.map(job => this.packJobData(job));
}
@bindThis
public async queueGetQueues() {
const fetchings = QUEUE_TYPES.map(async type => {
const queue = this.getQueue(type);
const counts = await queue.getJobCounts();
const isPaused = await queue.isPaused();
const metrics_completed = await queue.getMetrics('completed', 0, MetricsTime.ONE_WEEK);
const metrics_failed = await queue.getMetrics('failed', 0, MetricsTime.ONE_WEEK);
return {
name: type,
counts: counts,
isPaused,
metrics: {
completed: metrics_completed,
failed: metrics_failed,
},
};
});
this.inboxQueue.clean(0, 0, 'delayed');
return await Promise.all(fetchings);
}
@bindThis
public async queueGetQueue(queueType: typeof QUEUE_TYPES[number]) {
const queue = this.getQueue(queueType);
const counts = await queue.getJobCounts();
const isPaused = await queue.isPaused();
const metrics_completed = await queue.getMetrics('completed', 0, MetricsTime.ONE_WEEK);
const metrics_failed = await queue.getMetrics('failed', 0, MetricsTime.ONE_WEEK);
const db = parseRedisInfo(await (await queue.client).info());
return {
name: queueType,
qualifiedName: queue.qualifiedName,
counts: counts,
isPaused,
metrics: {
completed: metrics_completed,
failed: metrics_failed,
},
db: {
version: db.redis_version,
mode: db.redis_mode,
runId: db.run_id,
processId: db.process_id,
port: parseInt(db.tcp_port),
os: db.os,
uptime: parseInt(db.uptime_in_seconds),
memory: {
total: parseInt(db.total_system_memory) || parseInt(db.maxmemory),
used: parseInt(db.used_memory),
fragmentationRatio: parseInt(db.mem_fragmentation_ratio),
peak: parseInt(db.used_memory_peak),
},
clients: {
connected: parseInt(db.connected_clients),
blocked: parseInt(db.blocked_clients),
},
},
};
}
}
+3
View File
@@ -46,6 +46,7 @@ export type RolePolicies = {
canUseTranslator: boolean;
canHideAds: boolean;
driveCapacityMb: number;
maxFileSizeMb: number;
alwaysMarkNsfw: boolean;
canUpdateBioMedia: boolean;
pinLimit: number;
@@ -81,6 +82,7 @@ export const DEFAULT_POLICIES: RolePolicies = {
canUseTranslator: true,
canHideAds: false,
driveCapacityMb: 100,
maxFileSizeMb: 10,
alwaysMarkNsfw: false,
canUpdateBioMedia: true,
pinLimit: 5,
@@ -391,6 +393,7 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
canUseTranslator: calc('canUseTranslator', vs => vs.some(v => v === true)),
canHideAds: calc('canHideAds', vs => vs.some(v => v === true)),
driveCapacityMb: calc('driveCapacityMb', vs => Math.max(...vs)),
maxFileSizeMb: calc('maxFileSizeMb', vs => Math.max(...vs)),
alwaysMarkNsfw: calc('alwaysMarkNsfw', vs => vs.some(v => v === true)),
canUpdateBioMedia: calc('canUpdateBioMedia', vs => vs.some(v => v === true)),
pinLimit: calc('pinLimit', vs => Math.max(...vs)),
+9 -3
View File
@@ -234,6 +234,7 @@ export class SearchService {
}
this.queryService.generateVisibilityQuery(query, me);
this.queryService.generateBlockedHostQueryForNote(query);
if (me) this.queryService.generateMutedUserQueryForNotes(query, me);
if (me) this.queryService.generateBlockedUserQueryForNotes(query, me);
@@ -295,9 +296,14 @@ export class SearchService {
this.cacheService.userBlockedCache.fetch(me.id),
])
: [new Set<string>(), new Set<string>()];
const notes = (await this.notesRepository.findBy({
id: In(res.hits.map(x => x.id)),
})).filter(note => {
const query = this.notesRepository.createQueryBuilder('note');
query.where('note.id IN (:...noteIds)', { noteIds: res.hits.map(x => x.id) });
this.queryService.generateBlockedHostQueryForNote(query);
const notes = (await query.getMany()).filter(note => {
if (me && isUserRelated(note, userIdsWhoBlockingMe)) return false;
if (me && isUserRelated(note, userIdsWhoMeMuting)) return false;
return true;
@@ -5,11 +5,14 @@
import { randomUUID } from 'node:crypto';
import { Inject, Injectable } from '@nestjs/common';
import type { OnApplicationShutdown } from '@nestjs/common';
import { DataSource, IsNull } from 'typeorm';
import * as Redis from 'ioredis';
import bcrypt from 'bcryptjs';
import { MiLocalUser, MiUser } from '@/models/User.js';
import { MiSystemAccount, MiUsedUsername, MiUserKeypair, MiUserProfile, type UsersRepository, type SystemAccountsRepository } from '@/models/_.js';
import type { MiMeta, UserProfilesRepository } from '@/models/_.js';
import type { GlobalEvents } from '@/core/GlobalEventService.js';
import { MemoryKVCache } from '@/misc/cache.js';
import { DI } from '@/di-symbols.js';
import { bindThis } from '@/decorators.js';
@@ -20,10 +23,13 @@ import { genRsaKeyPair } from '@/misc/gen-key-pair.js';
export const SYSTEM_ACCOUNT_TYPES = ['actor', 'relay', 'proxy'] as const;
@Injectable()
export class SystemAccountService {
export class SystemAccountService implements OnApplicationShutdown {
private cache: MemoryKVCache<MiLocalUser>;
constructor(
@Inject(DI.redisForSub)
private redisForSub: Redis.Redis,
@Inject(DI.db)
private db: DataSource,
@@ -42,6 +48,31 @@ export class SystemAccountService {
private idService: IdService,
) {
this.cache = new MemoryKVCache<MiLocalUser>(1000 * 60 * 10); // 10m
this.redisForSub.on('message', this.onMessage);
}
@bindThis
private async onMessage(_: string, data: string): Promise<void> {
const obj = JSON.parse(data);
if (obj.channel === 'internal') {
const { type, body } = obj.message as GlobalEvents['internal']['payload'];
switch (type) {
case 'metaUpdated': {
if (body.before != null && body.before.name !== body.after.name) {
for (const account of SYSTEM_ACCOUNT_TYPES) {
await this.updateCorrespondingUserProfile(account, {
name: body.after.name,
});
}
}
break;
}
default:
break;
}
}
}
@bindThis
@@ -145,7 +176,7 @@ export class SystemAccountService {
@bindThis
public async updateCorrespondingUserProfile(type: typeof SYSTEM_ACCOUNT_TYPES[number], extra: {
name?: string;
name?: string | null;
description?: MiUserProfile['description'];
}): Promise<MiLocalUser> {
const user = await this.fetch(type);
@@ -169,4 +200,15 @@ export class SystemAccountService {
return updated;
}
@bindThis
public dispose(): void {
this.redisForSub.off('message', this.onMessage);
this.cache.dispose();
}
@bindThis
public onApplicationShutdown(signal?: string): void {
this.dispose();
}
}
@@ -411,8 +411,8 @@ export class WebhookTestService {
name: user.name,
username: user.username,
host: user.host,
avatarUrl: user.avatarUrl,
avatarBlurhash: user.avatarBlurhash,
avatarUrl: user.avatarId == null ? null : user.avatarUrl,
avatarBlurhash: user.avatarId == null ? null : user.avatarBlurhash,
avatarDecorations: user.avatarDecorations.map(it => ({
id: it.id,
angle: it.angle,
@@ -441,8 +441,8 @@ export class WebhookTestService {
createdAt: new Date().toISOString(),
updatedAt: user.updatedAt?.toISOString() ?? null,
lastFetchedAt: user.lastFetchedAt?.toISOString() ?? null,
bannerUrl: user.bannerUrl,
bannerBlurhash: user.bannerBlurhash,
bannerUrl: user.bannerId == null ? null : user.bannerUrl,
bannerBlurhash: user.bannerId == null ? null : user.bannerBlurhash,
isLocked: user.isLocked,
isSilenced: false,
isSuspended: user.isSuspended,
@@ -5,7 +5,7 @@
import { Injectable } from '@nestjs/common';
import * as mfm from 'mfm-js';
import { MfmService } from '@/core/MfmService.js';
import { MfmService, Appender } from '@/core/MfmService.js';
import type { MiNote } from '@/models/Note.js';
import { bindThis } from '@/decorators.js';
import { extractApHashtagObjects } from './models/tag.js';
@@ -25,17 +25,17 @@ export class ApMfmService {
}
@bindThis
public getNoteHtml(note: Pick<MiNote, 'text' | 'mentionedRemoteUsers'>, apAppend?: string) {
public getNoteHtml(note: Pick<MiNote, 'text' | 'mentionedRemoteUsers'>, additionalAppender: Appender[] = []) {
let noMisskeyContent = false;
const srcMfm = (note.text ?? '') + (apAppend ?? '');
const srcMfm = (note.text ?? '');
const parsed = mfm.parse(srcMfm);
if (!apAppend && parsed?.every(n => ['text', 'unicodeEmoji', 'emojiCode', 'mention', 'hashtag', 'url'].includes(n.type))) {
if (!additionalAppender.length && parsed.every(n => ['text', 'unicodeEmoji', 'emojiCode', 'mention', 'hashtag', 'url'].includes(n.type))) {
noMisskeyContent = true;
}
const content = this.mfmService.toHtml(parsed, JSON.parse(note.mentionedRemoteUsers));
const content = this.mfmService.toHtml(parsed, JSON.parse(note.mentionedRemoteUsers), additionalAppender);
return {
content,
@@ -19,7 +19,7 @@ import type { MiEmoji } from '@/models/Emoji.js';
import type { MiPoll } from '@/models/Poll.js';
import type { MiPollVote } from '@/models/PollVote.js';
import { UserKeypairService } from '@/core/UserKeypairService.js';
import { MfmService } from '@/core/MfmService.js';
import { MfmService, type Appender } from '@/core/MfmService.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js';
import type { MiUserKeypair } from '@/models/UserKeypair.js';
@@ -430,10 +430,24 @@ export class ApRendererService {
poll = await this.pollsRepository.findOneBy({ noteId: note.id });
}
let apAppend = '';
const apAppend: Appender[] = [];
if (quote) {
apAppend += `\n\nRE: ${quote}`;
// Append quote link as `<br><br><span class="quote-inline">RE: <a href="...">...</a></span>`
// the claas name `quote-inline` is used in non-misskey clients for styling quote notes.
// For compatibility, the span part should be kept as possible.
apAppend.push((doc, body) => {
body.appendChild(doc.createElement('br'));
body.appendChild(doc.createElement('br'));
const span = doc.createElement('span');
span.className = 'quote-inline';
span.appendChild(doc.createTextNode('RE: '));
const link = doc.createElement('a');
link.setAttribute('href', quote);
link.textContent = quote;
span.appendChild(link);
body.appendChild(span);
});
}
const summary = note.cw === '' ? String.fromCharCode(0x200B) : note.cw;
@@ -509,7 +523,7 @@ export class ApRendererService {
const urlPart = match[0];
const urlPartParsed = new URL(urlPart);
const restPart = maybeUrl.slice(match[0].length);
return `<a href="${urlPartParsed.href}" rel="me nofollow noopener" target="_blank">${urlPart}</a>${restPart}`;
} catch (e) {
return maybeUrl;
@@ -41,7 +41,7 @@ export class AntennaEntityService {
excludeBots: antenna.excludeBots,
withReplies: antenna.withReplies,
withFile: antenna.withFile,
hideNotesInSensitiveChannel: antenna.hideNotesInSensitiveChannel,
excludeNotesInSensitiveChannel: antenna.excludeNotesInSensitiveChannel,
isActive: antenna.isActive,
hasUnreadNote: false, // TODO
notify: false, // 後方互換性のため
@@ -486,8 +486,8 @@ export class UserEntityService implements OnModuleInit {
name: user.name,
username: user.username,
host: user.host,
avatarUrl: user.avatarUrl ?? this.getIdenticonUrl(user),
avatarBlurhash: user.avatarBlurhash,
avatarUrl: (user.avatarId == null ? null : user.avatarUrl) ?? this.getIdenticonUrl(user),
avatarBlurhash: (user.avatarId == null ? null : user.avatarBlurhash),
avatarDecorations: user.avatarDecorations.length > 0 ? this.avatarDecorationService.getAll().then(decorations => user.avatarDecorations.filter(ud => decorations.some(d => d.id === ud.id)).map(ud => ({
id: ud.id,
angle: ud.angle || undefined,
@@ -533,8 +533,8 @@ export class UserEntityService implements OnModuleInit {
createdAt: this.idService.parse(user.id).date.toISOString(),
updatedAt: user.updatedAt ? user.updatedAt.toISOString() : null,
lastFetchedAt: user.lastFetchedAt ? user.lastFetchedAt.toISOString() : null,
bannerUrl: user.bannerUrl,
bannerBlurhash: user.bannerBlurhash,
bannerUrl: user.bannerId == null ? null : user.bannerUrl,
bannerBlurhash: user.bannerId == null ? null : user.bannerBlurhash,
isLocked: user.isLocked,
isSilenced: this.roleService.getUserPolicies(user.id).then(r => !r.canPublicNote),
isSuspended: user.isSuspended,
+1 -1
View File
@@ -104,5 +104,5 @@ export class MiAntenna {
@Column('boolean', {
default: false,
})
public hideNotesInSensitiveChannel: boolean;
public excludeNotesInSensitiveChannel: boolean;
}
+1 -1
View File
@@ -10,6 +10,7 @@ import { MiUser } from './User.js';
import { MiChannel } from './Channel.js';
import type { MiDriveFile } from './DriveFile.js';
@Index(['userId', 'id'])
@Entity('note')
export class MiNote {
@PrimaryColumn(id())
@@ -65,7 +66,6 @@ export class MiNote {
})
public cw: string | null;
@Index()
@Column({
...id(),
comment: 'The ID of author.',
+4
View File
@@ -118,21 +118,25 @@ export class MiUser {
@JoinColumn()
public banner: MiDriveFile | null;
// avatarId が null になったとしてもこれが null でない可能性があるため、このフィールドを使うときは avatarId の non-null チェックをすること
@Column('varchar', {
length: 512, nullable: true,
})
public avatarUrl: string | null;
// bannerId が null になったとしてもこれが null でない可能性があるため、このフィールドを使うときは bannerId の non-null チェックをすること
@Column('varchar', {
length: 512, nullable: true,
})
public bannerUrl: string | null;
// avatarId が null になったとしてもこれが null でない可能性があるため、このフィールドを使うときは avatarId の non-null チェックをすること
@Column('varchar', {
length: 128, nullable: true,
})
public avatarBlurhash: string | null;
// bannerId が null になったとしてもこれが null でない可能性があるため、このフィールドを使うときは bannerId の non-null チェックをすること
@Column('varchar', {
length: 128, nullable: true,
})
+58 -25
View File
@@ -3,29 +3,48 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { FindOneOptions, InsertQueryBuilder, ObjectLiteral, Repository, SelectQueryBuilder } from 'typeorm';
import {
FindOneOptions,
InsertQueryBuilder,
ObjectLiteral,
QueryRunner,
Repository,
SelectQueryBuilder,
} from 'typeorm';
import { PostgresConnectionOptions } from 'typeorm/driver/postgres/PostgresConnectionOptions.js';
import { RelationCountLoader } from 'typeorm/query-builder/relation-count/RelationCountLoader.js';
import { RelationIdLoader } from 'typeorm/query-builder/relation-id/RelationIdLoader.js';
import { RawSqlResultsToEntityTransformer } from 'typeorm/query-builder/transformer/RawSqlResultsToEntityTransformer.js';
import { MiAbuseUserReport } from '@/models/AbuseUserReport.js';
import {
RawSqlResultsToEntityTransformer,
} from 'typeorm/query-builder/transformer/RawSqlResultsToEntityTransformer.js';
import { MiAbuseReportNotificationRecipient } from '@/models/AbuseReportNotificationRecipient.js';
import { MiAbuseUserReport } from '@/models/AbuseUserReport.js';
import { MiAccessToken } from '@/models/AccessToken.js';
import { MiAd } from '@/models/Ad.js';
import { MiAnnouncement } from '@/models/Announcement.js';
import { MiAnnouncementRead } from '@/models/AnnouncementRead.js';
import { MiAntenna } from '@/models/Antenna.js';
import { MiApp } from '@/models/App.js';
import { MiAvatarDecoration } from '@/models/AvatarDecoration.js';
import { MiAuthSession } from '@/models/AuthSession.js';
import { MiAvatarDecoration } from '@/models/AvatarDecoration.js';
import { MiBlocking } from '@/models/Blocking.js';
import { MiChannelFollowing } from '@/models/ChannelFollowing.js';
import { MiBubbleGameRecord } from '@/models/BubbleGameRecord.js';
import { MiChannel } from '@/models/Channel.js';
import { MiChannelFavorite } from '@/models/ChannelFavorite.js';
import { MiChannelFollowing } from '@/models/ChannelFollowing.js';
import { MiChatApproval } from '@/models/ChatApproval.js';
import { MiChatMessage } from '@/models/ChatMessage.js';
import { MiChatRoom } from '@/models/ChatRoom.js';
import { MiChatRoomInvitation } from '@/models/ChatRoomInvitation.js';
import { MiChatRoomMembership } from '@/models/ChatRoomMembership.js';
import { MiClip } from '@/models/Clip.js';
import { MiClipNote } from '@/models/ClipNote.js';
import { MiClipFavorite } from '@/models/ClipFavorite.js';
import { MiClipNote } from '@/models/ClipNote.js';
import { MiDriveFile } from '@/models/DriveFile.js';
import { MiDriveFolder } from '@/models/DriveFolder.js';
import { MiEmoji } from '@/models/Emoji.js';
import { MiFlash } from '@/models/Flash.js';
import { MiFlashLike } from '@/models/FlashLike.js';
import { MiFollowing } from '@/models/Following.js';
import { MiFollowRequest } from '@/models/FollowRequest.js';
import { MiGalleryLike } from '@/models/GalleryLike.js';
@@ -35,7 +54,6 @@ import { MiInstance } from '@/models/Instance.js';
import { MiMeta } from '@/models/Meta.js';
import { MiModerationLog } from '@/models/ModerationLog.js';
import { MiMuting } from '@/models/Muting.js';
import { MiRenoteMuting } from '@/models/RenoteMuting.js';
import { MiNote } from '@/models/Note.js';
import { MiNoteFavorite } from '@/models/NoteFavorite.js';
import { MiNoteReaction } from '@/models/NoteReaction.js';
@@ -50,42 +68,38 @@ import { MiPromoRead } from '@/models/PromoRead.js';
import { MiRegistrationTicket } from '@/models/RegistrationTicket.js';
import { MiRegistryItem } from '@/models/RegistryItem.js';
import { MiRelay } from '@/models/Relay.js';
import { MiRenoteMuting } from '@/models/RenoteMuting.js';
import { MiRetentionAggregation } from '@/models/RetentionAggregation.js';
import { MiReversiGame } from '@/models/ReversiGame.js';
import { MiRole } from '@/models/Role.js';
import { MiRoleAssignment } from '@/models/RoleAssignment.js';
import { MiSignin } from '@/models/Signin.js';
import { MiSwSubscription } from '@/models/SwSubscription.js';
import { MiSystemAccount } from '@/models/SystemAccount.js';
import { MiSystemWebhook } from '@/models/SystemWebhook.js';
import { MiUsedUsername } from '@/models/UsedUsername.js';
import { MiUser } from '@/models/User.js';
import { MiUserIp } from '@/models/UserIp.js';
import { MiUserKeypair } from '@/models/UserKeypair.js';
import { MiUserList } from '@/models/UserList.js';
import { MiUserListFavorite } from '@/models/UserListFavorite.js';
import { MiUserListMembership } from '@/models/UserListMembership.js';
import { MiUserMemo } from '@/models/UserMemo.js';
import { MiUserNotePining } from '@/models/UserNotePining.js';
import { MiUserPending } from '@/models/UserPending.js';
import { MiUserProfile } from '@/models/UserProfile.js';
import { MiUserPublickey } from '@/models/UserPublickey.js';
import { MiUserSecurityKey } from '@/models/UserSecurityKey.js';
import { MiUserMemo } from '@/models/UserMemo.js';
import { MiWebhook } from '@/models/Webhook.js';
import { MiSystemWebhook } from '@/models/SystemWebhook.js';
import { MiChannel } from '@/models/Channel.js';
import { MiRetentionAggregation } from '@/models/RetentionAggregation.js';
import { MiRole } from '@/models/Role.js';
import { MiRoleAssignment } from '@/models/RoleAssignment.js';
import { MiFlash } from '@/models/Flash.js';
import { MiFlashLike } from '@/models/FlashLike.js';
import { MiUserListFavorite } from '@/models/UserListFavorite.js';
import { MiChatMessage } from '@/models/ChatMessage.js';
import { MiChatRoom } from '@/models/ChatRoom.js';
import { MiChatRoomMembership } from '@/models/ChatRoomMembership.js';
import { MiChatRoomInvitation } from '@/models/ChatRoomInvitation.js';
import { MiChatApproval } from '@/models/ChatApproval.js';
import { MiBubbleGameRecord } from '@/models/BubbleGameRecord.js';
import { MiReversiGame } from '@/models/ReversiGame.js';
import type { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity.js';
export interface MiRepository<T extends ObjectLiteral> {
createTableColumnNames(this: Repository<T> & MiRepository<T>): string[];
insertOne(this: Repository<T> & MiRepository<T>, entity: QueryDeepPartialEntity<T>, findOptions?: Pick<FindOneOptions<T>, 'relations'>): Promise<T>;
insertOneImpl(this: Repository<T> & MiRepository<T>, entity: QueryDeepPartialEntity<T>, findOptions?: Pick<FindOneOptions<T>, 'relations'>, queryRunner?: QueryRunner): Promise<T>;
selectAliasColumnNames(this: Repository<T> & MiRepository<T>, queryBuilder: InsertQueryBuilder<T>, builder: SelectQueryBuilder<T>): void;
}
@@ -94,6 +108,21 @@ export const miRepository = {
return this.metadata.columns.filter(column => column.isSelect && !column.isVirtual).map(column => column.databaseName);
},
async insertOne(entity, findOptions?) {
const opt = this.manager.connection.options as PostgresConnectionOptions;
if (opt.replication) {
const queryRunner = this.manager.connection.createQueryRunner('master');
try {
return this.insertOneImpl(entity, findOptions, queryRunner);
} finally {
await queryRunner.release();
}
} else {
return this.insertOneImpl(entity, findOptions);
}
},
async insertOneImpl(entity, findOptions?, queryRunner?) {
// ---- insert + returningの結果を共通テーブル式(CTE)に保持するクエリを生成 ----
const queryBuilder = this.createQueryBuilder().insert().values(entity);
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const mainAlias = queryBuilder.expressionMap.mainAlias!;
@@ -101,7 +130,9 @@ export const miRepository = {
mainAlias.name = 't';
const columnNames = this.createTableColumnNames();
queryBuilder.returning(columnNames.reduce((a, c) => `${a}, ${queryBuilder.escape(c)}`, '').slice(2));
const builder = this.createQueryBuilder().addCommonTableExpression(queryBuilder, 'cte', { columnNames });
// ---- 共通テーブル式(CTE)から結果を取得 ----
const builder = this.createQueryBuilder(undefined, queryRunner).addCommonTableExpression(queryBuilder, 'cte', { columnNames });
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
builder.expressionMap.mainAlias!.tablePath = 'cte';
this.selectAliasColumnNames(queryBuilder, builder);
@@ -204,7 +235,9 @@ export {
};
export type AbuseUserReportsRepository = Repository<MiAbuseUserReport> & MiRepository<MiAbuseUserReport>;
export type AbuseReportNotificationRecipientRepository = Repository<MiAbuseReportNotificationRecipient> & MiRepository<MiAbuseReportNotificationRecipient>;
export type AbuseReportNotificationRecipientRepository =
Repository<MiAbuseReportNotificationRecipient>
& MiRepository<MiAbuseReportNotificationRecipient>;
export type AccessTokensRepository = Repository<MiAccessToken> & MiRepository<MiAccessToken>;
export type AdsRepository = Repository<MiAd> & MiRepository<MiAd>;
export type AnnouncementsRepository = Repository<MiAnnouncement> & MiRepository<MiAnnouncement>;
@@ -100,7 +100,7 @@ export const packedAntennaSchema = {
optional: false, nullable: false,
default: false,
},
hideNotesInSensitiveChannel: {
excludeNotesInSensitiveChannel: {
type: 'boolean',
optional: false, nullable: false,
default: false,
@@ -224,6 +224,10 @@ export const packedRolePoliciesSchema = {
type: 'integer',
optional: false, nullable: false,
},
maxFileSizeMb: {
type: 'integer',
optional: false, nullable: false,
},
alwaysMarkNsfw: {
type: 'boolean',
optional: false, nullable: false,
+22 -9
View File
@@ -5,7 +5,7 @@
// https://github.com/typeorm/typeorm/issues/2400
import pg from 'pg';
import { DataSource, Logger } from 'typeorm';
import { DataSource, Logger, type QueryRunner } from 'typeorm';
import * as highlight from 'cli-highlight';
import { entities as charts } from '@/core/chart/entities.js';
import { Config } from '@/config.js';
@@ -96,6 +96,7 @@ const sqlLogger = dbLogger.createSubLogger('sql', 'gray');
export type LoggerProps = {
disableQueryTruncation?: boolean;
enableQueryParamLogging?: boolean;
printReplicationMode?: boolean,
};
function highlightSql(sql: string) {
@@ -121,8 +122,10 @@ class MyCustomLogger implements Logger {
}
@bindThis
private transformQueryLog(sql: string) {
let modded = sql;
private transformQueryLog(sql: string, opts?: {
prefix?: string;
}) {
let modded = opts?.prefix ? opts.prefix + sql : sql;
if (!this.props.disableQueryTruncation) {
modded = truncateSql(modded);
}
@@ -140,18 +143,27 @@ class MyCustomLogger implements Logger {
}
@bindThis
public logQuery(query: string, parameters?: any[]) {
sqlLogger.info(this.transformQueryLog(query), this.transformParameters(parameters));
public logQuery(query: string, parameters?: any[], queryRunner?: QueryRunner) {
const prefix = (this.props.printReplicationMode && queryRunner)
? `[${queryRunner.getReplicationMode()}] `
: undefined;
sqlLogger.info(this.transformQueryLog(query, { prefix }), this.transformParameters(parameters));
}
@bindThis
public logQueryError(error: string, query: string, parameters?: any[]) {
sqlLogger.error(this.transformQueryLog(query), this.transformParameters(parameters));
public logQueryError(error: string, query: string, parameters?: any[], queryRunner?: QueryRunner) {
const prefix = (this.props.printReplicationMode && queryRunner)
? `[${queryRunner.getReplicationMode()}] `
: undefined;
sqlLogger.error(this.transformQueryLog(query, { prefix }), this.transformParameters(parameters));
}
@bindThis
public logQuerySlow(time: number, query: string, parameters?: any[]) {
sqlLogger.warn(this.transformQueryLog(query), this.transformParameters(parameters));
public logQuerySlow(time: number, query: string, parameters?: any[], queryRunner?: QueryRunner) {
const prefix = (this.props.printReplicationMode && queryRunner)
? `[${queryRunner.getReplicationMode()}] `
: undefined;
sqlLogger.warn(this.transformQueryLog(query, { prefix }), this.transformParameters(parameters));
}
@bindThis
@@ -298,6 +310,7 @@ export function createPostgresDataSource(config: Config) {
? new MyCustomLogger({
disableQueryTruncation: config.logging?.sql?.disableQueryTruncation,
enableQueryParamLogging: config.logging?.sql?.enableQueryParamLogging,
printReplicationMode: !!config.dbReplications,
})
: undefined,
maxQueryExecutionTime: 300,
@@ -44,7 +44,7 @@ import { BakeBufferedReactionsProcessorService } from './processors/BakeBuffered
import { CleanProcessorService } from './processors/CleanProcessorService.js';
import { AggregateRetentionProcessorService } from './processors/AggregateRetentionProcessorService.js';
import { QueueLoggerService } from './QueueLoggerService.js';
import { QUEUE, baseQueueOptions } from './const.js';
import { QUEUE, baseWorkerOptions } from './const.js';
// ref. https://github.com/misskey-dev/misskey/pull/7635#issue-971097019
function httpRelatedBackoff(attemptsMade: number) {
@@ -175,7 +175,7 @@ export class QueueProcessorService implements OnApplicationShutdown {
return processer(job);
}
}, {
...baseQueueOptions(this.config, QUEUE.SYSTEM),
...baseWorkerOptions(this.config, QUEUE.SYSTEM),
autorun: false,
});
@@ -232,7 +232,7 @@ export class QueueProcessorService implements OnApplicationShutdown {
return processer(job);
}
}, {
...baseQueueOptions(this.config, QUEUE.DB),
...baseWorkerOptions(this.config, QUEUE.DB),
autorun: false,
});
@@ -264,7 +264,7 @@ export class QueueProcessorService implements OnApplicationShutdown {
return this.deliverProcessorService.process(job);
}
}, {
...baseQueueOptions(this.config, QUEUE.DELIVER),
...baseWorkerOptions(this.config, QUEUE.DELIVER),
autorun: false,
concurrency: this.config.deliverJobConcurrency ?? 128,
limiter: {
@@ -304,7 +304,7 @@ export class QueueProcessorService implements OnApplicationShutdown {
return this.inboxProcessorService.process(job);
}
}, {
...baseQueueOptions(this.config, QUEUE.INBOX),
...baseWorkerOptions(this.config, QUEUE.INBOX),
autorun: false,
concurrency: this.config.inboxJobConcurrency ?? 16,
limiter: {
@@ -344,7 +344,7 @@ export class QueueProcessorService implements OnApplicationShutdown {
return this.userWebhookDeliverProcessorService.process(job);
}
}, {
...baseQueueOptions(this.config, QUEUE.USER_WEBHOOK_DELIVER),
...baseWorkerOptions(this.config, QUEUE.USER_WEBHOOK_DELIVER),
autorun: false,
concurrency: 64,
limiter: {
@@ -384,7 +384,7 @@ export class QueueProcessorService implements OnApplicationShutdown {
return this.systemWebhookDeliverProcessorService.process(job);
}
}, {
...baseQueueOptions(this.config, QUEUE.SYSTEM_WEBHOOK_DELIVER),
...baseWorkerOptions(this.config, QUEUE.SYSTEM_WEBHOOK_DELIVER),
autorun: false,
concurrency: 16,
limiter: {
@@ -434,7 +434,7 @@ export class QueueProcessorService implements OnApplicationShutdown {
return processer(job);
}
}, {
...baseQueueOptions(this.config, QUEUE.RELATIONSHIP),
...baseWorkerOptions(this.config, QUEUE.RELATIONSHIP),
autorun: false,
concurrency: this.config.relationshipJobConcurrency ?? 16,
limiter: {
@@ -479,7 +479,7 @@ export class QueueProcessorService implements OnApplicationShutdown {
return processer(job);
}
}, {
...baseQueueOptions(this.config, QUEUE.OBJECT_STORAGE),
...baseWorkerOptions(this.config, QUEUE.OBJECT_STORAGE),
autorun: false,
concurrency: 16,
});
@@ -512,7 +512,7 @@ export class QueueProcessorService implements OnApplicationShutdown {
return this.endedPollNotificationProcessorService.process(job);
}
}, {
...baseQueueOptions(this.config, QUEUE.ENDED_POLL_NOTIFICATION),
...baseWorkerOptions(this.config, QUEUE.ENDED_POLL_NOTIFICATION),
autorun: false,
});
}
+10
View File
@@ -3,6 +3,7 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { MetricsTime } from 'bullmq';
import { Config } from '@/config.js';
import type * as Bull from 'bullmq';
@@ -27,3 +28,12 @@ export function baseQueueOptions(config: Config, queueName: typeof QUEUE[keyof t
prefix: config.redisForJobQueue.prefix ? `${config.redisForJobQueue.prefix}:queue:${queueName}` : `queue:${queueName}`,
};
}
export function baseWorkerOptions(config: Config, queueName: typeof QUEUE[keyof typeof QUEUE]): Bull.WorkerOptions {
return {
...baseQueueOptions(config, queueName),
metrics: {
maxDataPoints: MetricsTime.ONE_WEEK,
},
};
}
@@ -32,6 +32,7 @@ import { isQuote, isRenote } from '@/misc/is-renote.js';
import * as Acct from '@/misc/acct.js';
import type { FastifyInstance, FastifyRequest, FastifyReply, FastifyPluginOptions, FastifyBodyParser } from 'fastify';
import type { FindOptionsWhere } from 'typeorm';
import { FanoutTimelineEndpointService } from '@/core/FanoutTimelineEndpointService.js';
const ACTIVITY_JSON = 'application/activity+json; charset=utf-8';
const LD_JSON = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"; charset=utf-8';
@@ -75,6 +76,7 @@ export class ActivityPubServerService {
private queueService: QueueService,
private userKeypairService: UserKeypairService,
private queryService: QueryService,
private fanoutTimelineEndpointService: FanoutTimelineEndpointService,
) {
//this.createServer = this.createServer.bind(this);
}
@@ -461,16 +463,28 @@ export class ActivityPubServerService {
const partOf = `${this.config.url}/users/${userId}/outbox`;
if (page) {
const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), sinceId, untilId)
.andWhere('note.userId = :userId', { userId: user.id })
.andWhere(new Brackets(qb => {
qb
.where('note.visibility = \'public\'')
.orWhere('note.visibility = \'home\'');
}))
.andWhere('note.localOnly = FALSE');
const notes = await query.limit(limit).getMany();
const notes = this.meta.enableFanoutTimeline ? await this.fanoutTimelineEndpointService.getMiNotes({
sinceId: sinceId ?? null,
untilId: untilId ?? null,
limit: limit,
allowPartial: false, // Possibly true? IDK it's OK for ordered collection.
me: null,
redisTimelines: [
`userTimeline:${user.id}`,
`userTimelineWithReplies:${user.id}`,
],
useDbFallback: true,
ignoreAuthorFromMute: true,
excludePureRenotes: false,
noteFilter: (note) => {
if (note.visibility !== 'home' && note.visibility !== 'public') return false;
if (note.localOnly) return false;
return true;
},
dbFallback: async (untilId, sinceId, limit) => {
return await this.getUserNotesFromDb(sinceId, untilId, limit, user.id);
},
}) : await this.getUserNotesFromDb(sinceId ?? null, untilId ?? null, limit, user.id);
if (sinceId) notes.reverse();
@@ -508,6 +522,20 @@ export class ActivityPubServerService {
}
}
@bindThis
private async getUserNotesFromDb(untilId: string | null, sinceId: string | null, limit: number, userId: MiUser['id']) {
return await this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), sinceId, untilId)
.andWhere('note.userId = :userId', { userId })
.andWhere(new Brackets(qb => {
qb
.where('note.visibility = \'public\'')
.orWhere('note.visibility = \'home\'');
}))
.andWhere('note.localOnly = FALSE')
.limit(limit)
.getMany();
}
@bindThis
private async userInfo(request: FastifyRequest, reply: FastifyReply, user: MiUser | null) {
if (this.meta.federation === 'none') {
@@ -735,7 +763,7 @@ export class ActivityPubServerService {
const acct = Acct.parse(request.params.acct);
const user = await this.usersRepository.findOneBy({
usernameLower: acct.username,
usernameLower: acct.username.toLowerCase(),
host: acct.host ?? IsNull(),
isSuspended: false,
});
+1 -1
View File
@@ -221,7 +221,7 @@ export class ServerService implements OnApplicationShutdown {
reply.header('Cache-Control', 'public, max-age=86400');
if (user) {
reply.redirect(user.avatarUrl ?? this.userEntityService.getIdenticonUrl(user));
reply.redirect((user.avatarId == null ? null : user.avatarUrl) ?? this.userEntityService.getIdenticonUrl(user));
} else {
reply.redirect('/static-assets/user-unknown.png');
}
@@ -138,7 +138,7 @@ fastify.get('/.well-known/change-password', async (request, reply) => {
const fromAcct = (acct: Acct.Acct): FindOptionsWhere<MiUser> | number =>
!acct.host || acct.host === this.config.host.toLowerCase() ? {
usernameLower: acct.username,
usernameLower: acct.username.toLowerCase(),
host: IsNull(),
isSuspended: false,
} : 422;
@@ -67,8 +67,14 @@ export * as 'admin/promo/create' from './endpoints/admin/promo/create.js';
export * as 'admin/queue/clear' from './endpoints/admin/queue/clear.js';
export * as 'admin/queue/deliver-delayed' from './endpoints/admin/queue/deliver-delayed.js';
export * as 'admin/queue/inbox-delayed' from './endpoints/admin/queue/inbox-delayed.js';
export * as 'admin/queue/promote' from './endpoints/admin/queue/promote.js';
export * as 'admin/queue/retry-job' from './endpoints/admin/queue/retry-job.js';
export * as 'admin/queue/remove-job' from './endpoints/admin/queue/remove-job.js';
export * as 'admin/queue/show-job' from './endpoints/admin/queue/show-job.js';
export * as 'admin/queue/promote-jobs' from './endpoints/admin/queue/promote-jobs.js';
export * as 'admin/queue/jobs' from './endpoints/admin/queue/jobs.js';
export * as 'admin/queue/stats' from './endpoints/admin/queue/stats.js';
export * as 'admin/queue/queues' from './endpoints/admin/queue/queues.js';
export * as 'admin/queue/queue-stats' from './endpoints/admin/queue/queue-stats.js';
export * as 'admin/relays/add' from './endpoints/admin/relays/add.js';
export * as 'admin/relays/list' from './endpoints/admin/relays/list.js';
export * as 'admin/relays/remove' from './endpoints/admin/relays/remove.js';
@@ -6,7 +6,7 @@
import { Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { ModerationLogService } from '@/core/ModerationLogService.js';
import { QueueService } from '@/core/QueueService.js';
import { QUEUE_TYPES, QueueService } from '@/core/QueueService.js';
export const meta = {
tags: ['admin'],
@@ -18,8 +18,11 @@ export const meta = {
export const paramDef = {
type: 'object',
properties: {},
required: [],
properties: {
queue: { type: 'string', enum: QUEUE_TYPES },
state: { type: 'string', enum: ['*', 'completed', 'wait', 'active', 'paused', 'prioritized', 'delayed', 'failed'] },
},
required: ['queue', 'state'],
} as const;
@Injectable()
@@ -29,7 +32,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
private queueService: QueueService,
) {
super(meta, paramDef, async (ps, me) => {
this.queueService.destroy();
this.queueService.queueClear(ps.queue, ps.state);
this.moderationLogService.log(me, 'clearQueue');
});
@@ -0,0 +1,38 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { ModerationLogService } from '@/core/ModerationLogService.js';
import { QUEUE_TYPES, QueueService } from '@/core/QueueService.js';
export const meta = {
tags: ['admin'],
requireCredential: true,
requireModerator: true,
kind: 'read:admin:queue',
} as const;
export const paramDef = {
type: 'object',
properties: {
queue: { type: 'string', enum: QUEUE_TYPES },
state: { type: 'array', items: { type: 'string', enum: ['active', 'wait', 'delayed', 'completed', 'failed'] } },
search: { type: 'string' },
},
required: ['queue', 'state'],
} as const;
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
constructor(
private queueService: QueueService,
) {
super(meta, paramDef, async (ps, me) => {
return this.queueService.queueGetJobs(ps.queue, ps.state, ps.search);
});
}
}
@@ -0,0 +1,39 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { ModerationLogService } from '@/core/ModerationLogService.js';
import { QUEUE_TYPES, QueueService } from '@/core/QueueService.js';
export const meta = {
tags: ['admin'],
requireCredential: true,
requireModerator: true,
kind: 'write:admin:queue',
} as const;
export const paramDef = {
type: 'object',
properties: {
queue: { type: 'string', enum: QUEUE_TYPES },
},
required: ['queue'],
} as const;
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
constructor(
private moderationLogService: ModerationLogService,
private queueService: QueueService,
) {
super(meta, paramDef, async (ps, me) => {
this.queueService.queuePromoteJobs(ps.queue);
this.moderationLogService.log(me, 'promoteQueue');
});
}
}
@@ -1,77 +0,0 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { ModerationLogService } from '@/core/ModerationLogService.js';
import { QueueService } from '@/core/QueueService.js';
export const meta = {
tags: ['admin'],
requireCredential: true,
requireModerator: true,
kind: 'write:admin:queue',
} as const;
export const paramDef = {
type: 'object',
properties: {
type: { type: 'string', enum: ['deliver', 'inbox'] },
},
required: ['type'],
} as const;
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
constructor(
private moderationLogService: ModerationLogService,
private queueService: QueueService,
) {
super(meta, paramDef, async (ps, me) => {
let delayedQueues;
switch (ps.type) {
case 'deliver':
delayedQueues = await this.queueService.deliverQueue.getDelayed();
for (let queueIndex = 0; queueIndex < delayedQueues.length; queueIndex++) {
const queue = delayedQueues[queueIndex];
try {
await queue.promote();
} catch (e) {
if (e instanceof Error) {
if (e.message.indexOf('not in a delayed state') !== -1) {
throw e;
}
} else {
throw e;
}
}
}
break;
case 'inbox':
delayedQueues = await this.queueService.inboxQueue.getDelayed();
for (let queueIndex = 0; queueIndex < delayedQueues.length; queueIndex++) {
const queue = delayedQueues[queueIndex];
try {
await queue.promote();
} catch (e) {
if (e instanceof Error) {
if (e.message.indexOf('not in a delayed state') !== -1) {
throw e;
}
} else {
throw e;
}
}
}
break;
}
this.moderationLogService.log(me, 'promoteQueue');
});
}
}
@@ -0,0 +1,36 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { ModerationLogService } from '@/core/ModerationLogService.js';
import { QUEUE_TYPES, QueueService } from '@/core/QueueService.js';
export const meta = {
tags: ['admin'],
requireCredential: true,
requireModerator: true,
kind: 'read:admin:queue',
} as const;
export const paramDef = {
type: 'object',
properties: {
queue: { type: 'string', enum: QUEUE_TYPES },
},
required: ['queue'],
} as const;
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
constructor(
private queueService: QueueService,
) {
super(meta, paramDef, async (ps, me) => {
return this.queueService.queueGetQueue(ps.queue);
});
}
}
@@ -0,0 +1,35 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { ModerationLogService } from '@/core/ModerationLogService.js';
import { QUEUE_TYPES, QueueService } from '@/core/QueueService.js';
export const meta = {
tags: ['admin'],
requireCredential: true,
requireModerator: true,
kind: 'read:admin:queue',
} as const;
export const paramDef = {
type: 'object',
properties: {
},
required: [],
} as const;
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
constructor(
private queueService: QueueService,
) {
super(meta, paramDef, async (ps, me) => {
return this.queueService.queueGetQueues();
});
}
}
@@ -0,0 +1,38 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { ModerationLogService } from '@/core/ModerationLogService.js';
import { QUEUE_TYPES, QueueService } from '@/core/QueueService.js';
export const meta = {
tags: ['admin'],
requireCredential: true,
requireModerator: true,
kind: 'write:admin:queue',
} as const;
export const paramDef = {
type: 'object',
properties: {
queue: { type: 'string', enum: QUEUE_TYPES },
jobId: { type: 'string' },
},
required: ['queue', 'jobId'],
} as const;
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
constructor(
private moderationLogService: ModerationLogService,
private queueService: QueueService,
) {
super(meta, paramDef, async (ps, me) => {
this.queueService.queueRemoveJob(ps.queue, ps.jobId);
});
}
}
@@ -0,0 +1,38 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { ModerationLogService } from '@/core/ModerationLogService.js';
import { QUEUE_TYPES, QueueService } from '@/core/QueueService.js';
export const meta = {
tags: ['admin'],
requireCredential: true,
requireModerator: true,
kind: 'write:admin:queue',
} as const;
export const paramDef = {
type: 'object',
properties: {
queue: { type: 'string', enum: QUEUE_TYPES },
jobId: { type: 'string' },
},
required: ['queue', 'jobId'],
} as const;
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
constructor(
private moderationLogService: ModerationLogService,
private queueService: QueueService,
) {
super(meta, paramDef, async (ps, me) => {
this.queueService.queueRetryJob(ps.queue, ps.jobId);
});
}
}
@@ -0,0 +1,38 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { ModerationLogService } from '@/core/ModerationLogService.js';
import { QUEUE_TYPES, QueueService } from '@/core/QueueService.js';
export const meta = {
tags: ['admin'],
requireCredential: true,
requireModerator: true,
kind: 'read:admin:queue',
} as const;
export const paramDef = {
type: 'object',
properties: {
queue: { type: 'string', enum: QUEUE_TYPES },
jobId: { type: 'string' },
},
required: ['queue', 'jobId'],
} as const;
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
constructor(
private moderationLogService: ModerationLogService,
private queueService: QueueService,
) {
super(meta, paramDef, async (ps, me) => {
return this.queueService.queueGetJob(ps.queue, ps.jobId);
});
}
}
@@ -73,7 +73,7 @@ export const paramDef = {
excludeBots: { type: 'boolean' },
withReplies: { type: 'boolean' },
withFile: { type: 'boolean' },
hideNotesInSensitiveChannel: { type: 'boolean' },
excludeNotesInSensitiveChannel: { type: 'boolean' },
},
required: ['name', 'src', 'keywords', 'excludeKeywords', 'users', 'caseSensitive', 'withReplies', 'withFile'],
} as const;
@@ -134,7 +134,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
excludeBots: ps.excludeBots,
withReplies: ps.withReplies,
withFile: ps.withFile,
hideNotesInSensitiveChannel: ps.hideNotesInSensitiveChannel,
excludeNotesInSensitiveChannel: ps.excludeNotesInSensitiveChannel,
});
this.globalEventService.publishInternalEvent('antennaCreated', antenna);
@@ -111,6 +111,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
// NOTE: センシティブ除外の設定はこのエンドポイントでは無視する。
// https://github.com/misskey-dev/misskey/pull/15346#discussion_r1929950255
this.queryService.generateBlockedHostQueryForNote(query);
this.queryService.generateVisibilityQuery(query, me);
this.queryService.generateMutedUserQueryForNotes(query, me);
this.queryService.generateBlockedUserQueryForNotes(query, me);
@@ -72,7 +72,7 @@ export const paramDef = {
excludeBots: { type: 'boolean' },
withReplies: { type: 'boolean' },
withFile: { type: 'boolean' },
hideNotesInSensitiveChannel: { type: 'boolean' },
excludeNotesInSensitiveChannel: { type: 'boolean' },
},
required: ['antennaId'],
} as const;
@@ -130,7 +130,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
excludeBots: ps.excludeBots,
withReplies: ps.withReplies,
withFile: ps.withFile,
hideNotesInSensitiveChannel: ps.hideNotesInSensitiveChannel,
excludeNotesInSensitiveChannel: ps.excludeNotesInSensitiveChannel,
isActive: true,
lastUsedAt: new Date(),
});
@@ -121,6 +121,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
.leftJoinAndSelect('renote.user', 'renoteUser')
.leftJoinAndSelect('note.channel', 'channel');
this.queryService.generateBlockedHostQueryForNote(query);
if (me) {
this.queryService.generateMutedUserQueryForNotes(query, me);
this.queryService.generateBlockedUserQueryForNotes(query, me);
@@ -85,6 +85,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
.leftJoinAndSelect('renote.user', 'renoteUser')
.andWhere('clipNote.clipId = :clipId', { clipId: clip.id });
this.queryService.generateBlockedHostQueryForNote(query);
if (me) {
this.queryService.generateVisibilityQuery(query, me);
this.queryService.generateMutedUserQueryForNotes(query, me);
@@ -10,9 +10,9 @@ import { IdentifiableError } from '@/misc/identifiable-error.js';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js';
import { DriveService } from '@/core/DriveService.js';
import { ApiError } from '../../../error.js';
import { MiMeta } from '@/models/_.js';
import { DI } from '@/di-symbols.js';
import { ApiError } from '../../../error.js';
export const meta = {
tags: ['drive'],
@@ -56,6 +56,12 @@ export const meta = {
code: 'NO_FREE_SPACE',
id: 'd08dbc37-a6a9-463a-8c47-96c32ab5f064',
},
maxFileSizeExceeded: {
message: 'Cannot upload the file because it exceeds the maximum file size.',
code: 'MAX_FILE_SIZE_EXCEEDED',
id: 'b9d8c348-33f0-4673-b9a9-5d4da058977a',
},
},
} as const;
@@ -115,6 +121,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
if (err instanceof IdentifiableError) {
if (err.id === '282f77bf-5816-4f72-9264-aa14d8261a21') throw new ApiError(meta.errors.inappropriate);
if (err.id === 'c6244ed2-a39a-4e1c-bf93-f0fbd7764fa6') throw new ApiError(meta.errors.noFreeSpace);
if (err.id === 'f9e4e5f3-4df4-40b5-b400-f236945f7073') throw new ApiError(meta.errors.maxFileSizeExceeded);
}
throw new ApiError();
} finally {
@@ -70,6 +70,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
.leftJoinAndSelect('renote.user', 'renoteUser');
this.queryService.generateVisibilityQuery(query, me);
this.queryService.generateBlockedHostQueryForNote(query);
if (me) {
this.queryService.generateMutedUserQueryForNotes(query, me);
this.queryService.generateBlockedUserQueryForNotes(query, me);
@@ -11,6 +11,7 @@ import { DI } from '@/di-symbols.js';
import { FeaturedService } from '@/core/FeaturedService.js';
import { isUserRelated } from '@/misc/is-user-related.js';
import { CacheService } from '@/core/CacheService.js';
import { QueryService } from '@/core/QueryService.js';
export const meta = {
tags: ['notes'],
@@ -52,6 +53,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
private cacheService: CacheService,
private noteEntityService: NoteEntityService,
private featuredService: FeaturedService,
private queryService: QueryService,
) {
super(meta, paramDef, async (ps, me) => {
let noteIds: string[];
@@ -94,6 +96,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
.leftJoinAndSelect('renote.user', 'renoteUser')
.leftJoinAndSelect('note.channel', 'channel');
this.queryService.generateBlockedHostQueryForNote(query);
const notes = (await query.getMany()).filter(note => {
if (me && isUserRelated(note, userIdsWhoBlockingMe)) return false;
if (me && isUserRelated(note, userIdsWhoMeMuting)) return false;
@@ -243,6 +243,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
}
this.queryService.generateVisibilityQuery(query, me);
this.queryService.generateBlockedHostQueryForNote(query);
this.queryService.generateMutedUserQueryForNotes(query, me);
this.queryService.generateBlockedUserQueryForNotes(query, me);
this.queryService.generateMutedUserRenotesQueryForNotes(query, me);
@@ -156,6 +156,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
.leftJoinAndSelect('renote.user', 'renoteUser');
this.queryService.generateVisibilityQuery(query, me);
this.queryService.generateBlockedHostQueryForNote(query);
if (me) this.queryService.generateMutedUserQueryForNotes(query, me);
if (me) this.queryService.generateBlockedUserQueryForNotes(query, me);
if (me) this.queryService.generateMutedUserRenotesQueryForNotes(query, me);
@@ -72,6 +72,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
.leftJoinAndSelect('renote.user', 'renoteUser');
this.queryService.generateVisibilityQuery(query, me);
this.queryService.generateBlockedHostQueryForNote(query);
this.queryService.generateMutedUserQueryForNotes(query, me);
this.queryService.generateMutedNoteThreadQuery(query, me);
this.queryService.generateBlockedUserQueryForNotes(query, me);
@@ -72,6 +72,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
.leftJoinAndSelect('renote.user', 'renoteUser');
this.queryService.generateVisibilityQuery(query, me);
this.queryService.generateBlockedHostQueryForNote(query);
if (me) this.queryService.generateMutedUserQueryForNotes(query, me);
if (me) this.queryService.generateBlockedUserQueryForNotes(query, me);
@@ -56,6 +56,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
.leftJoinAndSelect('renote.user', 'renoteUser');
this.queryService.generateVisibilityQuery(query, me);
this.queryService.generateBlockedHostQueryForNote(query);
if (me) this.queryService.generateMutedUserQueryForNotes(query, me);
if (me) this.queryService.generateBlockedUserQueryForNotes(query, me);
@@ -81,6 +81,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
.leftJoinAndSelect('renote.user', 'renoteUser');
this.queryService.generateVisibilityQuery(query, me);
this.queryService.generateBlockedHostQueryForNote(query);
if (me) this.queryService.generateMutedUserQueryForNotes(query, me);
if (me) this.queryService.generateBlockedUserQueryForNotes(query, me);
@@ -199,6 +199,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
}));
this.queryService.generateVisibilityQuery(query, me);
this.queryService.generateBlockedHostQueryForNote(query);
this.queryService.generateMutedUserQueryForNotes(query, me);
this.queryService.generateBlockedUserQueryForNotes(query, me);
this.queryService.generateMutedUserRenotesQueryForNotes(query, me);
@@ -184,6 +184,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
}));
this.queryService.generateVisibilityQuery(query, me);
this.queryService.generateBlockedHostQueryForNote(query);
this.queryService.generateMutedUserQueryForNotes(query, me);
this.queryService.generateBlockedUserQueryForNotes(query, me);
this.queryService.generateMutedUserRenotesQueryForNotes(query, me);
@@ -102,6 +102,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
.leftJoinAndSelect('renote.user', 'renoteUser');
this.queryService.generateVisibilityQuery(query, me);
this.queryService.generateBlockedHostQueryForNote(query);
this.queryService.generateMutedUserQueryForNotes(query, me);
this.queryService.generateBlockedUserQueryForNotes(query, me);
@@ -11,6 +11,7 @@ import { DI } from '@/di-symbols.js';
import { FeaturedService } from '@/core/FeaturedService.js';
import { CacheService } from '@/core/CacheService.js';
import { isUserRelated } from '@/misc/is-user-related.js';
import { QueryService } from '@/core/QueryService.js';
export const meta = {
tags: ['notes'],
@@ -49,6 +50,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
private noteEntityService: NoteEntityService,
private featuredService: FeaturedService,
private cacheService: CacheService,
private queryService: QueryService,
) {
super(meta, paramDef, async (ps, me) => {
const userIdsWhoBlockingMe = me ? await this.cacheService.userBlockedCache.fetch(me.id) : new Set<string>();
@@ -85,6 +87,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
.leftJoinAndSelect('renote.user', 'renoteUser')
.leftJoinAndSelect('note.channel', 'channel');
this.queryService.generateBlockedHostQueryForNote(query);
const notes = (await query.getMany()).filter(note => {
if (me && isUserRelated(note, userIdsWhoBlockingMe, false)) return false;
if (me && isUserRelated(note, userIdsWhoMeMuting, true)) return false;
@@ -129,6 +129,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
redisTimelines,
useDbFallback: true,
ignoreAuthorFromMute: true,
ignoreAuthorFromInstanceBlock: true,
excludeReplies: ps.withChannelNotes && !ps.withReplies, // userTimelineWithChannel may include replies
excludeNoFiles: ps.withChannelNotes && ps.withFiles, // userTimelineWithChannel may include notes without files
excludePureRenotes: !ps.withRenotes,
@@ -184,6 +185,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
}
this.queryService.generateVisibilityQuery(query, me);
this.queryService.generateBlockedHostQueryForNote(query, true);
if (me) {
this.queryService.generateMutedUserQueryForNotes(query, me, { id: ps.userId });
this.queryService.generateBlockedUserQueryForNotes(query, me);
@@ -102,6 +102,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
.leftJoinAndSelect('reaction.note', 'note');
this.queryService.generateVisibilityQuery(query, me);
this.queryService.generateBlockedHostQueryForNote(query);
const reactions = (await query
.limit(ps.limit)
@@ -534,7 +534,7 @@ export class ClientServerService {
return await reply.view('user', {
user, profile, me,
avatarUrl: user.avatarUrl ?? this.userEntityService.getIdenticonUrl(user),
avatarUrl: _user.avatarUrl,
sub: request.params.sub,
...await this.generateCommonPugData(this.meta),
clientCtx: htmlSafeJsonStringify({
@@ -65,7 +65,7 @@ export class FeedService {
generator: 'Misskey',
description: `${user.notesCount} Notes, ${profile.followingVisibility === 'public' ? user.followingCount : '?'} Following, ${profile.followersVisibility === 'public' ? user.followersCount : '?'} Followers${profile.description ? ` · ${profile.description}` : ''}`,
link: author.link,
image: user.avatarUrl ?? this.userEntityService.getIdenticonUrl(user),
image: (user.avatarId == null ? null : user.avatarUrl) ?? this.userEntityService.getIdenticonUrl(user),
feedLinks: {
json: `${author.link}.json`,
atom: `${author.link}.atom`,
@@ -74,10 +74,6 @@ services:
source: ../../../pnpm-workspace.yaml
target: /misskey/pnpm-workspace.yaml
read_only: true
- type: bind
source: ../../../scripts/dependency-patches
target: /misskey/scripts/dependency-patches
read_only: true
- type: bind
source: ./certificates/rootCA.crt
target: /usr/local/share/ca-certificates/rootCA.crt
@@ -70,10 +70,6 @@ services:
source: ../../../pnpm-workspace.yaml
target: /misskey/pnpm-workspace.yaml
read_only: true
- type: bind
source: ../../../scripts/dependency-patches
target: /misskey/scripts/dependency-patches
read_only: true
- type: bind
source: ./certificates/rootCA.crt
target: /usr/local/share/ca-certificates/rootCA.crt
@@ -118,10 +114,6 @@ services:
source: ../../../pnpm-workspace.yaml
target: /misskey/pnpm-workspace.yaml
read_only: true
- type: bind
source: ../../../scripts/dependency-patches
target: /misskey/scripts/dependency-patches
read_only: true
working_dir: /misskey
command: >
bash -c "

Some files were not shown because too many files have changed in this diff Show More