Compare commits

..

174 Commits

Author SHA1 Message Date
github-actions[bot]
73419e8a61 [skip ci] Update CHANGELOG.md (prepend template) 2025-07-18 00:28:02 +00:00
github-actions[bot]
9852196ddc Release: 2025.7.0 2025-07-18 00:27:57 +00:00
github-actions[bot]
598641de48 Bump version to 2025.7.0-rc.1 2025-07-17 11:07:00 +00:00
syuilo
4d643c77c5 New Crowdin updates (#16274)
* New translations ja-jp.yml (Chinese Simplified)

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

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Spanish)

* New translations ja-jp.yml (Thai)

* New translations ja-jp.yml (Spanish)

* New translations ja-jp.yml (Spanish)

* New translations ja-jp.yml (Spanish)

* New translations ja-jp.yml (English)

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (German)

* New translations ja-jp.yml (Portuguese)

* New translations ja-jp.yml (English)
2025-07-17 20:03:13 +09:00
syuilo
a686592734 enhance(frontend): disable InfiniteScroll to improve stability
#16229
2025-07-17 20:02:55 +09:00
syuilo
0619dba04d remove unused code 2025-07-17 20:00:05 +09:00
github-actions[bot]
fbd6b67f1f Bump version to 2025.7.0-rc.0 2025-07-17 08:33:52 +00:00
かっこかり
e5c2be15f7 fix(deps): Node.jsの最小バージョンを引き上げ (#16296)
* Update package.json

* Update min.node-version

* Update CHANGELOG.md
2025-07-17 13:20:43 +09:00
renovate[bot]
1b791258ce fix(deps): update [frontend] update dependencies (#16202)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-17 12:14:19 +09:00
renovate[bot]
49cac2f72b fix(deps): update [root] update dependencies (#16200)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-17 11:56:55 +09:00
renovate[bot]
5d5aa09459 chore(deps): update [misskey-js] update dependencies (#16199)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-17 11:42:34 +09:00
github-actions[bot]
e1834beae8 Bump version to 2025.7.0-beta.2 2025-07-16 06:52:02 +00:00
anatawa12
6f6fdfe28e Migration cleanup (#16288)
* chore: apply several @Index and @ManyToOne to match actual migration code

* chore: several decorator updates with typeorm bug workaround with patches

* feat: add final cleanup migration

* dev: add .editorconfig settings for generated migrations

* chore: update dockerfile to build package with patches

* chore: update federation test compose to include patches

* chore: revert few dependency update

* chore: don't check disableRegistration on test env

* test: add test for checking migration script

* chore: set proxyRemoteFiles true in test config

* chore: enter invitation code in signup test

* fix: register send button is not disabled when invitationCode is not input
2025-07-16 15:49:05 +09:00
tamaina
ad7bf096e1 enhance(backend): usernameに対してもprohibitedWordsForNameOfUserを適用 (#16282)
* enhance(backend): usernameに対してもprohibitedWordsForNameOfUserを適用
Resolve #16281

* fix locales/index/d.ts
2025-07-15 09:32:46 +09:00
anatawa12
08cc5a99bb Don't remove notes when reply / renote is removed (#16287)
* chore: make NO ACTION on channel/reply/renote removal

* chore(docs): add description to show a possibility of reply null with replyId non-null

* fix: packing NoteDraft fails when reply / renote is removed

* feat: show drafts targeting removed renote / reply as "削除された投稿への投稿"
2025-07-15 09:20:48 +09:00
github-actions[bot]
f954b1e276 Bump version to 2025.7.0-beta.1 2025-07-12 06:17:58 +00:00
syuilo
5ecaf5095e enhance: ウォーターマーク機能をロールで制御可能に 2025-07-12 15:13:35 +09:00
syuilo
d2c4f79886 New Crowdin updates (#16258)
* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Korean)

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

* New translations ja-jp.yml (Spanish)

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

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (Ukrainian)

* New translations ja-jp.yml (English)

* New translations ja-jp.yml (Thai)

* New translations ja-jp.yml (Thai)

* New translations ja-jp.yml (Thai)

* New translations ja-jp.yml (Thai)

* New translations ja-jp.yml (Thai)

* New translations ja-jp.yml (Thai)

* New translations ja-jp.yml (Thai)

* New translations ja-jp.yml (Thai)

* New translations ja-jp.yml (Thai)
2025-07-12 15:00:30 +09:00
anatawa12
e26369ed48 fix: unable to horizontally scroll when pull to refresh is enabled (#16273) 2025-07-12 15:00:06 +09:00
syuilo
c165749a29 chore(frontend): fix type errors 2025-07-06 20:54:02 +09:00
syuilo
c4fdf5a47c chore(frontend): fix type errors 2025-07-06 20:47:31 +09:00
syuilo
288f0abeac chore(frontend): fix type errors 2025-07-06 20:37:09 +09:00
かっこかり
89ed8be8ff fix(frontend): MkRange/MkSelectでdisabledが効かなくなっている問題を修正 (#16263)
* fix(frontend): MkRange/MkSelectでdisabledが効かなくなっている問題を修正

* Update Changelog

* 誤字
2025-07-06 19:38:09 +09:00
かっこかり
a8abb03d17 refactor(frontend): Formまわりの型強化 (#16260)
* refactor(frontend): Formまわりの型強化

* fix

* avoid non-null assertion and add null check for safety

* refactor

* avoid non-null assertion and add null check for safety

* Update clip.vue

---------

Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
2025-07-06 19:36:11 +09:00
syuilo
c2a01551a7 Merge branch 'develop' of https://github.com/misskey-dev/misskey into develop 2025-07-06 19:32:33 +09:00
syuilo
553ccff77c chore(frontend): tweak selector to improve rendering performance 2025-07-06 19:32:31 +09:00
かっこかり
9dddc84750 refactor(frontend): menuの型定義の可読性向上 (#16261) 2025-07-06 17:24:34 +09:00
syuilo
004cfd5e4b clean up 2025-07-06 15:57:21 +09:00
syuilo
40a35968f0 clean up 2025-07-06 15:54:33 +09:00
syuilo
e6ec15e397 feat: 特定のドライブファイルを添付しているチャットメッセージを一覧できるように 2025-07-06 09:54:49 +09:00
syuilo
8430256f22 clean up 2025-07-05 19:29:18 +09:00
Souma
abde15979b enhance(backend): Add display name to email (#16256)
* feat(backend): Add display name to email

Make it clear who sent emails.

* docs(changelog): Add a description about this change

Users can notice what's changed by this PR.
2025-07-05 18:22:08 +09:00
syuilo
f128682200 fix type errors 2025-07-05 17:13:29 +09:00
syuilo
cc4cdd1ec0 clean up 2025-07-05 12:13:08 +09:00
syuilo
075df75afa Merge branch 'develop' of https://github.com/misskey-dev/misskey into develop 2025-07-05 11:56:22 +09:00
syuilo
64eb338d65 🎨 2025-07-05 11:56:20 +09:00
tamaina
d986da745b ノートのサーバー情報(InstanceTicker)のデザイン/パフォーマンス改善(-webkit-text-stroke ver) (#16225)
* Revert "enhance(frontend): Instance Tickerのデザイン改善 (#15946)"

This reverts commit 04928ba7d1.

* enhance(frontend): Instance Tickerのデザイン改善(-webkit-text-stroke)

* 🎨

* use theme fg/bg

* use panel
2025-07-05 09:59:48 +09:00
syuilo
50f5b29290 New Crowdin updates (#16237)
* New translations ja-jp.yml (Indonesian)

* New translations ja-jp.yml (Indonesian)

* New translations ja-jp.yml (Spanish)

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Spanish)

* New translations ja-jp.yml (Portuguese)

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

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

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

* New translations ja-jp.yml (Indonesian)
2025-07-05 09:07:25 +09:00
syuilo
a460bb7913 perf(frontend): improve rendering performance 2025-07-05 09:05:47 +09:00
syuilo
7cf1eccd04 clean up 2025-07-05 08:31:20 +09:00
syuilo
73397e1b7e Merge branch 'develop' of https://github.com/misskey-dev/misskey into develop 2025-07-05 08:18:56 +09:00
tamaina
bf17092b41 test: VS Code上で複数のjestテストを表示できるように (#16251) 2025-07-05 08:18:15 +09:00
github-actions[bot]
6d1018f42b Bump version to 2025.7.0-beta.0 2025-07-04 09:52:01 +00:00
かっこかり
7667011266 fix(frontend): ウェルカムタイムラインのメディア表示がCWを考慮していない問題を修正 (#16247)
* fix(frontend): ウェルカムタイムラインのメディア表示がCWを考慮していない問題を修正

* Update Changelog
2025-07-04 18:49:21 +09:00
syuilo
a45ccc18b4 refactor 2025-07-04 18:33:41 +09:00
syuilo
c29a4d9503 fix(test): Play検索機能でBackend Unit Testが壊れている 2025-07-04 18:31:34 +09:00
syuilo
5caf2b27cf fix(test): Play検索機能でBackend Unit Testが壊れている
Fix #16248
2025-07-04 16:32:56 +09:00
syuilo
dd87d26bdc feat: Playを検索できるように
#13115
2025-07-04 10:20:00 +09:00
かっこかり
b7a6301c2e fix(frontend): プラグインのアンインストール時にローカルのセーブデータを削除するように (#16246)
* fix(frontend): プラグインのアンインストール時にローカルのセーブデータを削除するように

* Update Changelog

* remove unused import

---------

Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
2025-07-04 07:40:00 +09:00
syuilo
73e8d950df enhance(frontend): 投稿フォームにファイルをペースト/ドロップした際のUXを改善
Resolve #16205
2025-07-03 19:11:46 +09:00
syuilo
45033974f7 Update CHANGELOG.md 2025-07-03 19:03:34 +09:00
github-actions[bot]
7acfbc23d6 Bump version to 2025.7.0-alpha.0 2025-07-03 09:57:13 +00:00
github-actions[bot]
a9a746edce Bump version to 2025.6.4-alpha.4 2025-07-03 09:55:33 +00:00
かっこかり
179d990c39 fix(frontend): タブが不可視なあいだのpaginationのアップデートを停止するように (#16243)
* fix(frontend): タブが不可視なあいだのpaginationのアップデートを停止するように

* fix lint

* 待たない
2025-07-03 18:52:16 +09:00
4ster1sk
7c44881ca8 enhance(backend): avatarUrlの上限文字数の引き上げ (#16235) 2025-07-03 18:03:02 +09:00
tamaina
ccbc4cffaa enhance(frontend): 共有ページで、titleとtextに同じ内容が入っていた際の削除ロジックを強化 (#16226)
* enhance(frontend): 共有ページで、titleとtextに同じ内容が入っていた際の削除ロジックを強化
Fix #16224

* fix

* +→*

* fix

* use RegExp.test

* Update packages/frontend/src/pages/share.vue

Co-authored-by: zyoshoka <107108195+zyoshoka@users.noreply.github.com>

---------

Co-authored-by: zyoshoka <107108195+zyoshoka@users.noreply.github.com>
2025-07-03 18:00:43 +09:00
tamaina
706244925d fix(frontend): 条件により保存できない場合のメッセージを汎用的なものへ (#16238)
Fix #16228
2025-07-03 17:59:55 +09:00
かっこかり
09a5e4b10a fix(frontend): Paginatorの型エラー解消 (#16230)
* fix(frontend): fix paginator type error

* fix

* refactor

* fix

* fix

* fix(paginator): remove readonly type

* fix

* typo

* fix: R -> E

* remove any

---------

Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
2025-07-03 11:20:26 +09:00
syuilo
c48acad04b 🎨 2025-06-29 17:21:43 +09:00
github-actions[bot]
5d3bb02f4b Bump version to 2025.6.4-alpha.3 2025-06-29 06:47:43 +00:00
syuilo
933e252687 fix of f1deb89e34 2025-06-29 15:36:39 +09:00
syuilo
f1deb89e34 refactor(frontend): improve pagination implementation 2025-06-29 15:11:25 +09:00
syuilo
8bc822d829 feat(backend): クリップ内でノートを検索できるように 2025-06-29 15:10:51 +09:00
syuilo
c215cccf1d enhance(frontend): ファイルアップロード時にセンシティブ設定されているか表示するように 2025-06-29 08:50:55 +09:00
github-actions[bot]
0685bdf05c Bump version to 2025.6.4-alpha.2 2025-06-28 12:52:32 +00:00
syuilo
3394ed2122 New Crowdin updates (#16207)
* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (Spanish)

* New translations ja-jp.yml (Spanish)

* New translations ja-jp.yml (German)

* New translations ja-jp.yml (German)

* New translations ja-jp.yml (Thai)

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

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (Spanish)

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

* 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 (Chinese Traditional)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (Catalan)

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

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Spanish)

* New translations ja-jp.yml (English)

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

* New translations ja-jp.yml (Portuguese)

* New translations ja-jp.yml (English)

* New translations ja-jp.yml (Portuguese)

* New translations ja-jp.yml (English)
2025-06-28 21:43:22 +09:00
syuilo
c5a440cf22 Update types.ts 2025-06-28 21:43:14 +09:00
syuilo
3c6f07fc8c feat: モデログを検索できるように 2025-06-28 21:38:54 +09:00
syuilo
3c5ed0ffbb enhance(frontend): improve modlog pagination 2025-06-28 21:18:36 +09:00
syuilo
b8e8f3ad25 enhance: ページネーション(一覧表示)の基準日時を指定できるように sinceId/untilIdが指定可能なエンドポイントにおいて、sinceDate/untilDateも指定可能に 2025-06-28 20:21:21 +09:00
syuilo
012b2a9764 enhance(frontend): improve MkTl rendering 2025-06-28 19:24:55 +09:00
syuilo
dfbc40f868 lint 2025-06-28 19:20:02 +09:00
syuilo
32ddaa0cf8 Update about-misskey.vue 2025-06-28 12:02:16 +09:00
syuilo
bf6e218355 refactor 2025-06-28 12:00:15 +09:00
syuilo
19ef6c0b14 Update about-misskey.vue 2025-06-27 20:10:17 +09:00
syuilo
535b86f05e lint 2025-06-27 10:02:49 +09:00
taichan
01a94eaecb chore(CI): cache ffmpeg (#16223)
* ci: use daily cache for ffmpeg

* fix(ci): input type

* Fix current date

* Just use Daily cache

* fix condition
2025-06-26 19:08:47 +09:00
syuilo
9a28fa0534 refactor(frontend/pref): refactor preferences manager
Refactored preferences manager to decouple account context and storage provider, improving normalization and loading of profiles. Replaced static profile creation/normalization with instance-based logic, and updated usage in preferences.ts to pass account context explicitly. This enhances maintainability and prepares for better guest account handling.
2025-06-26 16:25:43 +09:00
github-actions[bot]
899273554a Bump version to 2025.6.4-alpha.1 2025-06-26 04:38:12 +00:00
syuilo
bf57557ba3 refactor(frontend): refactor uploader image editing features and menu
Replaces separate 'effect' and 'crop' features with a unified 'imageEditing' feature in the uploader. Groups crop and effect actions under a new parent 'editImage' menu item, adds localization for 'editImage', and updates supported types accordingly.
2025-06-26 12:10:15 +09:00
syuilo
8fda4fefaf refactor 2025-06-26 12:06:53 +09:00
syuilo
f1983d1aa5 Update type from UploaderDialogFeatures to UploaderFeatures
Replaces the UploaderDialogFeatures type with UploaderFeatures in the select function and SelectFileOptions type to ensure consistency and correct type usage.
2025-06-26 12:02:25 +09:00
syuilo
60649f4d66 add note 2025-06-26 12:01:56 +09:00
syuilo
525a330637 tweak eslint config 2025-06-26 10:49:41 +09:00
taichan
b455e63da7 chore(frontend): 開発モード時に言語ファイルの変更を自動で反映するように (#16215)
* chore(frontend): 開発モード時に言語ファイルの変更を自動で反映するように

* fix message

* naming

* SPDX
2025-06-26 08:26:44 +09:00
syuilo
5626677e86 Update CHANGELOG.md 2025-06-25 20:30:49 +09:00
keito
c424554d4a ジョブキューのProgressの値を正しく計算する (#16218)
* fix: ジョブキューのProgressの値の範囲を 0~100 に統一

* fix(backend): ジョブキューのProgressの計算に用いる総数を最初に一度だけ取得する
2025-06-25 20:30:17 +09:00
syuilo
eee9a5f853 enhance(frontend): ページネーションの並び順を逆にできるように 2025-06-25 20:26:20 +09:00
github-actions[bot]
4d72d6caf4 Bump version to 2025.6.4-alpha.0 2025-06-25 08:50:37 +00:00
taichan
b752dc72e5 feat: ノートの下書き(draft of note) (#15298)
* WIp (backend)

* Remove unused

* 下書きbackend 続き

* fix(backedn): visibilityが下書きに反映されない

* Update packages/backend/src/postgres.ts

Co-authored-by: かっこかり <67428053+kakkokari-gtyih@users.noreply.github.com>

* Fix : import order

* fix(backend) : createでcwが効かない

* FIX FOREGIN KEY

* wip: frontend(既存の下書きを挿入)

まだ:チャンネル表示、下書きの作成、削除

* WIP: ノート選択ダイアログ
投稿時に下書きを削除

* Promiseに変更

* 連合なし、チャンネルも表示

* Hashtagの値抜け漏れ

* hasthagを0文字でも作成可能に

* 下書きの保存機構

* chore(misskey-js): build types

* localOnly抜け漏れ

* チャンネル情報の書き換え

* enhance(frontend): ヘッダ部の表示改善

* fix(frontend): ファイル添付できない

* fix: no file

* fix(frontend): 投票が反映されない

* ハッシュタグの展開(コメントアウト外し忘れ)

* fix: visibleUserIdsが反映されない

* enhance: APIの型を整備

* refactor: 型が整備できたのでasを削除

* Add userhost

* fix

* enhance: paginationを使う

* fix

* fix: 自分のアカウントでの投稿でしか下書きを利用できないように

完全に塞ぐことはできないが一応

* 🎨

* APIのエラーIDを追加

* enhance: スタイル調整

* remove unused code

* 🎨

* fix: ロールポリシーの型

* ロールの編集画面

* ダイアログの挙動改善

* 下書き機能が利用できない場合は表示しないように

* refactor

* fix: ダブルクリックが効かない問題を修正

* add comments

* fix

* fix: 保存時のエラーの種別にかかわらずmodalを閉じないように

* fix()backend: NoteDraftのreply, renoteの型が間違ってたので修正 (migtrationはあってた)

* fix: 投稿フォームを空白にして通常リノートできるやつは下書きとしては弾くように

* fix(backend): テキストが0文字でも下書きは保存できるように

* Fix(backend): replyIdの型定義がミスっているのを修正

* chore(misskey-js): update types

* Add CHANGELOG

* lint

* 常にサーバー下書きに保存し、上限を超えた場合のみ尋ねるように

* NoteDraftServiceにcreate, updateの処理を移譲

* Fix typeerror

* remove tooltip

* Remove Mkbutton:short and use iconOnly

* 不要なコメントの削除

* Remove Short Completely

* wip

* escキーまわりの挙動を改善

* 下書き選択時に下書き可能数と現在の量が分かるように

* cleanUp

* wip

* wi

* wip

* Update MkPostForm.vue

---------

Co-authored-by: かっこかり <67428053+kakkokari-gtyih@users.noreply.github.com>
Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
2025-06-25 17:09:23 +09:00
syuilo
06d31c0b78 fix(frontend): ファイルがドライブの既定アップロード先に指定したフォルダにアップロードされない問題を修正
Fix #16206
2025-06-25 10:55:30 +09:00
syuilo
32d4c312ef enhance(frontend): ファイルアップロード前にキャプション設定を行えるように
Resolve #16210
2025-06-25 10:49:58 +09:00
syuilo
36fde67992 enhance(frontend): improve theme settings 2025-06-25 10:23:39 +09:00
syuilo
43abbce2af enhance(frontend): 全てのページネーションにおいてコンテキストメニューからリロードできるように 2025-06-25 10:08:44 +09:00
syuilo
684424f26a enhance(frontend): improve useScrollPositionKeeper 2025-06-24 20:30:32 +09:00
syuilo
36989e0cd3 Update about-misskey.vue 2025-06-24 20:24:34 +09:00
syuilo
d518682e73 add note 2025-06-24 11:44:16 +09:00
syuilo
0ada970337 enhance(frontend): 設定の自動バックアップをオンにした直後に自動バックアップするように 2025-06-23 17:12:25 +09:00
github-actions[bot]
a812dfe853 [skip ci] Update CHANGELOG.md (prepend template) 2025-06-16 11:13:27 +00:00
github-actions[bot]
2baec208f5 Release: 2025.6.3 2025-06-16 11:13:22 +00:00
github-actions[bot]
4093616e23 Bump version to 2025.6.3-alpha.0 2025-06-16 10:52:09 +00:00
syuilo
062d5170df fix(frontend): キャッシュを削除しないとクライアントが使用できないことがある問題を修正
Fix #16196
2025-06-16 19:51:26 +09:00
github-actions[bot]
a279bd4d49 [skip ci] Update CHANGELOG.md (prepend template) 2025-06-16 08:58:37 +00:00
github-actions[bot]
978ae706eb Release: 2025.6.2 2025-06-16 08:58:31 +00:00
syuilo
824643a44e [skip ci] Update CHANGELOG.md 2025-06-16 17:57:09 +09:00
github-actions[bot]
213c569242 Bump version to 2025.6.2-alpha.0 2025-06-16 05:08:24 +00:00
syuilo
a1cf2d3074 New Crowdin updates (#16192)
* New translations ja-jp.yml (Chinese Traditional)

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

* New translations ja-jp.yml (Catalan)

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

* New translations ja-jp.yml (Spanish)

* New translations ja-jp.yml (English)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Chinese Simplified)
2025-06-16 14:07:48 +09:00
syuilo
4ea7c76c02 fix(frontend): キャッシュを削除しないとクライアントが使用できないことがある問題を修正 2025-06-16 13:55:27 +09:00
github-actions[bot]
1782a353d3 [skip ci] Update CHANGELOG.md (prepend template) 2025-06-16 02:33:19 +00:00
github-actions[bot]
c69a13b592 Release: 2025.6.1 2025-06-16 02:33:14 +00:00
syuilo
40e35c051a Update CHANGELOG.md 2025-06-15 11:10:03 +09:00
syuilo
b93717be33 Update CHANGELOG.md
Co-authored-by: おさむのひと <46447427+samunohito@users.noreply.github.com>
2025-06-15 11:08:53 +09:00
syuilo
fe805fb7f0 enhance(frontend/image-effector): tweak fxs 2025-06-15 11:06:46 +09:00
syuilo
e9af9d4451 enhance(frontend/image-effector): tweak fxs 2025-06-15 10:57:29 +09:00
syuilo
ce90fee586 enhance(frontend/image-effector): add blockNoise fx 2025-06-15 10:55:11 +09:00
syuilo
5bec8ba6b0 enhance(frontend/image-effector): tweak fxs 2025-06-15 10:19:42 +09:00
syuilo
3dbfd80d65 enhance(frontend/image-effector): tweak colorAdjust fx 2025-06-15 09:25:57 +09:00
syuilo
b33eeb1366 enhance(frontend/image-effector): tweak distort fx 2025-06-15 08:47:59 +09:00
syuilo
420756d744 Update CHANGELOG.md 2025-06-14 19:50:56 +09:00
かっこかり
32d721abf1 refactor(frontend): checkWordMuteの返り値が誤っている問題を修正 (#16188)
* refactor(frontend): checkWordMuteの返り値が誤っている問題を修正

* fix lint
2025-06-14 16:08:14 +09:00
github-actions[bot]
8ea6aa2ef3 Bump version to 2025.6.1-rc.0 2025-06-14 03:16:12 +00:00
syuilo
bc07b79a23 fix(frontend): デッキのタイムラインカラムで新着ノート時のサウンドが再生されない問題を修正
Fix #16164
2025-06-14 11:36:42 +09:00
syuilo
aae7961540 New Crowdin updates (#16187)
* New translations ja-jp.yml (Chinese Simplified)

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

* New translations ja-jp.yml (Chinese Simplified)
2025-06-13 10:31:14 +09:00
github-actions[bot]
1ad32990cb Bump version to 2025.6.1-beta.2 2025-06-12 10:07:07 +00:00
zyoshoka
89db7b3fa8 fix(frontend): display reactions correctly in welcome timeline (#16186) 2025-06-12 19:05:24 +09:00
syuilo
151121a567 New Crowdin updates (#16183)
* New translations ja-jp.yml (Vietnamese)

* New translations ja-jp.yml (Thai)

* New translations ja-jp.yml (Italian)
2025-06-12 17:34:12 +09:00
mochi33i
966e0812f5 fix(misskey-js) : misskey-jsの drive/file/create でファイルアップロードができない問題を修正 (#16028)
* fix(misskey-js): drive/file/createが動かない問題を修正

* CHANGELOG.mdに修正内容を追加
2025-06-12 16:54:59 +09:00
syuilo
d378156212 Update CHANGELOG.md 2025-06-12 16:08:07 +09:00
renovate[bot]
568021498f fix(deps): update [root] update dependencies (#16142)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-11 14:39:49 +09:00
github-actions[bot]
8f66ffc14d Bump version to 2025.6.1-beta.1 2025-06-11 03:45:02 +00:00
syuilo
63e8935c86 fix(frontend): disable note_view_interruptor temporary to prevent rendering glitch 2025-06-11 12:42:49 +09:00
renovate[bot]
b16a05b9a7 fix(deps): update [backend] update dependencies (#16143)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-11 09:56:29 +09:00
おさむのひと
090262f3c6 fix: pnpm-lock.yamlの再生成 (#16182) 2025-06-11 08:57:42 +09:00
renovate[bot]
bc5a33d87f chore(deps): update [misskey-js] update dependencies (#16140)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-10 16:08:04 +09:00
renovate[bot]
0ffd9e267a fix(deps): update [frontend] update dependencies (#16144)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-10 16:07:34 +09:00
renovate[bot]
81bc27d804 chore(deps): update [tools] update dependencies (#16141)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-10 15:53:04 +09:00
github-actions[bot]
f50abed98d Bump version to 2025.6.1-beta.0 2025-06-10 04:43:58 +00:00
syuilo
8ab574a31a New Crowdin updates (#16163)
* New translations ja-jp.yml (Chinese Simplified)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (Spanish)

* New translations ja-jp.yml (Spanish)

* New translations ja-jp.yml (English)

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

* New translations ja-jp.yml (Spanish)

* New translations ja-jp.yml (English)

* New translations ja-jp.yml (Italian)

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

* New translations ja-jp.yml (Spanish)

* New translations ja-jp.yml (Catalan)

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

* New translations ja-jp.yml (English)

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

* New translations ja-jp.yml (Korean)

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

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

* New translations ja-jp.yml (Spanish)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (German)

* New translations ja-jp.yml (German)

* New translations ja-jp.yml (German)
2025-06-10 13:42:09 +09:00
syuilo
9a3219f12e fix(frontend): Plugin:register_note_view_interruptor()によるノートの書き換えが機能しない問題を修正
Fix #16180
2025-06-10 09:51:45 +09:00
zyoshoka
b5767c315a fix(backend): correct outbox pagination (#16176) 2025-06-08 09:12:59 +09:00
github-actions[bot]
ac9206f192 Bump version to 2025.6.1-alpha.4 2025-06-07 10:52:03 +00:00
かっこかり
e2b38edb3a deps(misskey-js): Update openapi-typescript to v7 (#15491)
* deps(misskey-js): Update openapi-typescript to v7

* update openapi-typescript to v7.7.3

* generate misskey-js types

* bump openapi-typescript

* enhance: 生成物からnever型を除去するように

* regenerate api types

* refactor: 処理共通化

---------

Co-authored-by: zyoshoka <107108195+zyoshoka@users.noreply.github.com>
2025-06-07 19:36:00 +09:00
syuilo
c5dc0fd51b Merge branch 'develop' of https://github.com/misskey-dev/misskey into develop 2025-06-07 09:26:51 +09:00
syuilo
dda2ad6bcd fix(frontend): support non-image files 2025-06-07 09:26:49 +09:00
github-actions[bot]
a5429ebeee Bump version to 2025.6.1-alpha.3 2025-06-06 23:36:20 +00:00
syuilo
1c3604c7fb 🎨 2025-06-07 08:15:31 +09:00
syuilo
4906f1f45c 🎨 2025-06-07 08:07:23 +09:00
syuilo
6506429f09 enhance(frontend): アップローダー内でセンシティブフラグを設定可能に 2025-06-07 07:57:23 +09:00
syuilo
9bd5f887de enhance(frontend): 投稿フォームにアップローダーを埋め込み (#16173)
* wip

* Update MkPostForm.vue

* wip

* wip

* Update MkPostForm.vue

* wip

* wip

* add tip

* Update tips.ts

* Update MkPostForm.vue
2025-06-07 07:47:43 +09:00
syuilo
be35fe468b refactor(frontend): refactor tips 2025-06-06 21:03:35 +09:00
syuilo
4b9b3ced01 enhance(frontend): improve MkTip usability 2025-06-06 20:59:01 +09:00
syuilo
20b8148ddf chore(frontend): tweak ui 2025-06-06 09:02:47 +09:00
github-actions[bot]
019dfbdc1c Bump version to 2025.6.1-alpha.2 2025-06-05 13:27:28 +00:00
かっこかり
95ea62f222 enhance(frontend): 画像エフェクトの操作でRangeをダブルクリックしたらデフォルトの値に戻るように (#16171)
* enhance(frontend): エフェクトの操作でRangeをダブルクリックしたらデフォルトの値に戻るように

* fix: trackの計算方法を修正

* remove unnecessary async
2025-06-05 22:25:49 +09:00
syuilo
fde67dca74 enhance(frontend): tweak server setup wizard 2025-06-05 21:05:11 +09:00
かっこかり
a603a4970e enhance(frontend): 画像エフェクト「色調補正」を追加 (#16170) 2025-06-05 20:29:02 +09:00
zyoshoka
f37a1e84bd chore: fix failure to publish misskey-js to npm registry (#16169) 2025-06-05 19:21:15 +09:00
syuilo
6c9e055aae add note 2025-06-05 15:05:00 +09:00
syuilo
a971e44cee refactor(frontend): refactor ImageEffector 2025-06-05 15:00:17 +09:00
syuilo
c6808f1eb6 refactor(frontend): refactor ImageEffector 2025-06-05 12:58:32 +09:00
syuilo
2a78360588 refactor(frontend): refactor ImageEffector 2025-06-05 12:25:22 +09:00
zyoshoka
65ba33867b fix(backend): avoid deadlock when deleting account (#16162) 2025-06-04 19:14:11 +09:00
syuilo
b55cc03621 New Crowdin updates (#16155)
* 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 (Catalan)

* New translations ja-jp.yml (Catalan)

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

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

* New translations ja-jp.yml (French)

* New translations ja-jp.yml (Spanish)

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

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

* New translations ja-jp.yml (Thai)

* New translations ja-jp.yml (Japanese, Kansai)
2025-06-04 18:25:39 +09:00
かっこかり
80f73c6712 enhance(gh): renovateのicons-subsetterをfrontendグループに統合 (#16161) 2025-06-04 16:39:06 +09:00
syuilo
60fc9a5195 🎨 2025-06-04 16:33:55 +09:00
かっこかり
b43dfa260b fix/refactor(frontend): 画像編集機能の修正・型強化 (#16156)
* enhance: refine uploadFile

* fix: missing locale

* refactor: harden types

* refactor: シェーダーファイルをlazy-loadingできるように

* fix(frontend): omit console.log in production environment

* fix: glslのバージョン表記は最初の行になければならない

* fix: シェーダーの読み込みが完了してからレンダリングを行うように

* fix merge failure

* fix: ウォーターマークのプリセットがない場合にdividerが2重に表示される問題を修正

* fix: アップローダーダイアログの機能設定でウォーターマークが無効な場合でもデフォルトのプリセットが適用されてしまう問題を修正

* fix lint

* Revert "fix: シェーダーの読み込みが完了してからレンダリングを行うように"

This reverts commit e06f37a7d453ca581858252eae422d8a9e470dc3.

* Revert "fix: glslのバージョン表記は最初の行になければならない"

This reverts commit afcc37d886106c4acd545e4c2922e67f94e1037b.

* Revert "refactor: シェーダーファイルをlazy-loadingできるように"

This reverts commit a1ab2fa38c2b7485c069f9cd089bc7de59416c9d.

* fix: ウォーターマークのFX定義を分ける

* Update packages/frontend/src/components/MkWatermarkEditorDialog.vue

* Update packages/frontend/src/components/MkWatermarkEditorDialog.vue

* Update packages/frontend/src/components/MkWatermarkEditorDialog.vue

---------

Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
2025-06-04 16:22:09 +09:00
syuilo
e3b57a118d 🎨 2025-06-04 16:15:06 +09:00
syuilo
fdcb6a09a9 fix(frontend): タッチ操作時にチャートのツールチップが消えなくなる場合がある問題を修正 2025-06-04 16:10:57 +09:00
syuilo
218df19d9c enhance(frontend): スマホでのMkModalWindowの表示を最適化 2025-06-04 12:28:50 +09:00
syuilo
b766589c00 enhance(frontend): ミュートした絵文字をデバイス間で同期できるように
Resolve #16158
2025-06-04 12:01:33 +09:00
かっこかり
d94bdff639 fix(misskey-js): build misskey-js with types (#16159) 2025-06-04 11:49:29 +09:00
github-actions[bot]
3a4288fe24 Bump version to 2025.6.1-alpha.1 2025-06-03 12:13:26 +00:00
syuilo
12c71de4c7 New Crowdin updates (#16153)
* New translations ja-jp.yml (Romanian)

* New translations ja-jp.yml (French)

* New translations ja-jp.yml (Spanish)

* New translations ja-jp.yml (Arabic)

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (Czech)

* New translations ja-jp.yml (German)

* New translations ja-jp.yml (Greek)

* New translations ja-jp.yml (Italian)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Dutch)

* New translations ja-jp.yml (Norwegian)

* New translations ja-jp.yml (Polish)

* New translations ja-jp.yml (Portuguese)

* New translations ja-jp.yml (Russian)

* New translations ja-jp.yml (Slovak)

* New translations ja-jp.yml (Swedish)

* New translations ja-jp.yml (Turkish)

* New translations ja-jp.yml (Ukrainian)

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

* New translations ja-jp.yml (Indonesian)

* New translations ja-jp.yml (Bengali)

* New translations ja-jp.yml (Thai)

* New translations ja-jp.yml (Uzbek)

* New translations ja-jp.yml (Lao)

* New translations ja-jp.yml (Japanese, Kansai)

* New translations ja-jp.yml (Korean (Gyeongsang))
2025-06-03 21:07:02 +09:00
syuilo
b7aa013a41 feat: 全てのチャットメッセージを既読にできるように 2025-06-03 21:06:37 +09:00
392 changed files with 49487 additions and 36251 deletions

View File

@@ -13,3 +13,7 @@ trim_trailing_whitespace = false
[*.{yml,yaml}]
indent_style = space
[packages/backend/migration/*.js]
indent_style = space
indent_size = 4

View File

@@ -1 +1 @@
20.10.0
20.18.1

View File

@@ -15,3 +15,5 @@ redis:
host: 127.0.0.1
port: 56312
id: aidx
proxyRemoteFiles: true

View File

@@ -26,6 +26,8 @@ jobs:
with:
node-version-file: '.node-version'
cache: 'pnpm'
# see https://docs.github.com/actions/use-cases-and-examples/publishing-packages/publishing-nodejs-packages#publishing-packages-to-the-npm-registry
registry-url: 'https://registry.npmjs.org'
- name: Publish package
run: |
pnpm i --frozen-lockfile

View File

@@ -18,6 +18,14 @@ on:
- packages/misskey-js/**
- .github/workflows/test-backend.yml
- .github/misskey/test.yml
workflow_dispatch:
inputs:
force_ffmpeg_cache_update:
description: 'Force update ffmpeg cache'
required: false
default: false
type: boolean
jobs:
unit:
name: Unit tests (backend)
@@ -47,7 +55,22 @@ jobs:
submodules: true
- name: Setup pnpm
uses: pnpm/action-setup@v4.1.0
- name: Get current date
id: current-date
run: echo "today=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT
- name: Setup and Restore ffmpeg/ffprobe Cache
id: cache-ffmpeg
uses: actions/cache@v4
with:
path: |
/usr/local/bin/ffmpeg
/usr/local/bin/ffprobe
# daily cache
key: ${{ runner.os }}-ffmpeg-${{ steps.current-date.outputs.today }}
restore-keys: |
${{ runner.os }}-ffmpeg-${{ steps.current-date.outputs.today }}
- name: Install FFmpeg
if: steps.cache-ffmpeg.outputs.cache-hit != 'true' || github.event.inputs.force_ffmpeg_cache_update == true
run: |
for i in {1..3}; do
echo "Attempt $i: Installing FFmpeg..."
@@ -129,3 +152,47 @@ jobs:
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./packages/backend/coverage/coverage-final.json
migration:
name: Migration tests (backend)
runs-on: ubuntu-latest
strategy:
matrix:
node-version-file:
- .node-version
#- .github/min.node-version
services:
postgres:
image: postgres:15
ports:
- 54312:5432
env:
POSTGRES_DB: test-misskey
POSTGRES_HOST_AUTH_METHOD: trust
steps:
- uses: actions/checkout@v4.2.2
with:
submodules: true
- name: Setup pnpm
uses: pnpm/action-setup@v4.1.0
- name: Get current date
id: current-date
run: echo "today=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT
- name: Use Node.js
uses: actions/setup-node@v4.4.0
with:
node-version-file: ${{ matrix.node-version-file }}
cache: 'pnpm'
- run: pnpm i --frozen-lockfile
- name: Check pnpm-lock.yaml
run: git diff --exit-code pnpm-lock.yaml
- name: Copy Configure
run: cp .github/misskey/test.yml .config
- name: Build
run: pnpm build
- name: Run migrations
run: MISSKEY_CONFIG_YML=test.yml pnpm --filter backend migrate
- name: Check no migrations are remaining
run: MISSKEY_CONFIG_YML=test.yml pnpm --filter backend check-migrations

View File

@@ -14,6 +14,13 @@ on:
- packages/backend/**
- packages/misskey-js/**
- .github/workflows/test-federation.yml
workflow_dispatch:
inputs:
force_ffmpeg_cache_update:
description: 'Force update ffmpeg cache'
required: false
default: false
type: boolean
jobs:
test:
@@ -30,7 +37,22 @@ jobs:
submodules: true
- name: Setup pnpm
uses: pnpm/action-setup@v4.1.0
- name: Get current date
id: current-date
run: echo "today=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT
- name: Setup and Restore ffmpeg/ffprobe Cache
id: cache-ffmpeg
uses: actions/cache@v4
with:
path: |
/usr/local/bin/ffmpeg
/usr/local/bin/ffprobe
# daily cache
key: ${{ runner.os }}-ffmpeg-${{ steps.current-date.outputs.today }}
restore-keys: |
${{ runner.os }}-ffmpeg-${{ steps.current-date.outputs.today }}
- name: Install FFmpeg
if: steps.cache-ffmpeg.outputs.cache-hit != 'true' || github.event.inputs.force_ffmpeg_cache_update == true
run: |
for i in {1..3}; do
echo "Attempt $i: Installing FFmpeg..."

View File

@@ -6,8 +6,12 @@
"files.associations": {
"*.test.ts": "typescript"
},
"jest.jestCommandLine": "pnpm run jest",
"jest.runMode": "on-demand",
"jest.virtualFolders": [
{ "name": "backend unit", "jestCommandLine": "pnpm -F backend run test" },
{ "name": "backend e2e", "jestCommandLine": "pnpm -F backend run test:e2e"},
{ "name": "misskey-js", "jestCommandLine": "pnpm -F misskey-js run jest" }
],
"editor.codeActionsOnSave": {
"source.fixAll": "explicit"
},

View File

@@ -1,19 +1,89 @@
## 2025.6.1
## Unreleased
### General
-
### Client
- Feat: 画像にウォーターマークを付与できるようになりました
- Enhance: ノートのリアクション一覧で、押せるリアクションを優先して表示できるようにするオプションを追加
- Fix: ドライブファイルの選択が不安定な問題を修正
- Fix: コントロールパネルのファイル欄などのデザインが崩れている問題を修正
- Fix: ユーザーの検索結果を追加で読み込むことができない問題を修正
-
### Server
-
## 2025.7.0
### Note
- Node.jsの最小バージョンを20.10.0から20.18.1に引き上げました
- なお、特に必要がない限りNode.jsは推奨バージョンであるv22を使用するようにしてください
### General
- Feat: ノートの下書き機能
- Feat: クリップ内でノートを検索できるように
- Feat: Playを検索できるように
- Feat: モデレーションにおいて、特定のドライブファイルを添付しているチャットメッセージを一覧できるように
- Enhance: ウォーターマーク機能をロールで制御可能に
### Client
- Note: 「自動でもっと見る」オプションは無効になっています
- Feat: モデログを検索できるように
- Enhance: 設定の自動バックアップをオンにした直後に自動バックアップするように
- Enhance: ファイルアップロード前にキャプション設定を行えるように
- Enhance: ファイルアップロード時にセンシティブ設定されているか表示するように
- Enhance: 投稿フォームにファイルをペースト/ドロップした際のUXを改善
- Enhance: ページネーション(一覧表示)の並び順を逆にできるように
- Enhance: ページネーション(一覧表示)の基準日時を指定できるように
- Enhance: レンダリングパフォーマンスの向上
- Fix: ファイルがドライブの既定アップロード先に指定したフォルダにアップロードされない問題を修正
- Fix: プラグインをアンインストールしてもセーブデータが残る問題を修正
- Fix: 数時間後Misskeyのタブに戻った際に、タブがスロットリングされている間の更新アニメーションを延々見せ続けられる問題を修正
- Fix: 非ログイン時のハイライトートの画像がCWの有無を考慮せず表示される問題を修正
- Fix: レンジ選択・ドロップダウンにて、操作を無効にすべきところで無効にならない問題を修正
- Fix: Pull to refreshが有効なときに横スクロールができない問題を修正
### Server
- Enhance: sinceId/untilIdが指定可能なエンドポイントにおいて、sinceDate/untilDateも指定可能に
- Enhance: メールの送信者としてサーバー名を表示するように (サーバー名が設定されている場合)
- Fix: ジョブキューのProgressの値を正しく計算する
## 2025.6.3
### Client
- Fix: キャッシュを削除しないとクライアントが使用できないことがある問題を修正
## 2025.6.2
### Client
- Fix: キャッシュを削除しないとクライアントが使用できないことがある問題を修正
- 翻訳の更新
## 2025.6.1
### Note
- AiScript Misskey拡張APIMisskey Webプラグインの[note_view_interruptor](https://misskey-hub.net/ja/docs/for-developers/plugin/plugin-api-reference/#pluginregister_note_view_interruptorfn)は不具合の影響により現在一時的に無効化されています。
- Misskey Web投稿フォームのプレビュー切り替えは「...」メニュー内に配置されました
### Client
- Feat: 画像にウォーターマークを付与できるようになりました
- Feat: 画像の加工ができるようになりました(実験的)
- Enhance: ノートのリアクション一覧で、押せるリアクションを優先して表示できるようにするオプションを追加
- Enhance: 全てのチャットメッセージを既読にできるように(設定→その他)
- Enhance: ミュートした絵文字をデバイス間で同期できるように
- Fix: ドライブファイルの選択が不安定な問題を修正
- Fix: コントロールパネルのファイル欄などのデザインが崩れている問題を修正
- Fix: ユーザーの検索結果を追加で読み込むことができない問題を修正
- Fix: タッチ操作時にチャートのツールチップが消えなくなる場合がある問題を修正
- Fix: ウェルカムタイムラインでリアクションが表示されない問題を修正
- Fix: デッキのタイムラインカラムで新着ノート時のサウンドが再生されない問題を修正
### Server
- Feat: 全てのチャットメッセージを既読にするAPIを追加(chat/read-all)
- Fix: アカウント削除が正常に行われないことがあった問題を修正
- Fix: outboxのページネーションが正しく行われない問題を修正
### Misskey.js
- Fix: misskey-jsの drive/file/create でファイルアップロードができない問題を修正
## 2025.6.0
### Client

View File

@@ -18,6 +18,7 @@ WORKDIR /misskey
COPY --link ["pnpm-lock.yaml", "pnpm-workspace.yaml", "package.json", "./"]
COPY --link ["scripts", "./scripts"]
COPY --link ["patches", "./patches"]
COPY --link ["packages/backend/package.json", "./packages/backend/"]
COPY --link ["packages/frontend-shared/package.json", "./packages/frontend-shared/"]
COPY --link ["packages/frontend/package.json", "./packages/frontend/"]
@@ -53,6 +54,7 @@ WORKDIR /misskey
COPY --link ["pnpm-lock.yaml", "pnpm-workspace.yaml", "package.json", "./"]
COPY --link ["scripts", "./scripts"]
COPY --link ["patches", "./patches"]
COPY --link ["packages/backend/package.json", "./packages/backend/"]
COPY --link ["packages/misskey-js/package.json", "./packages/misskey-js/"]
COPY --link ["packages/misskey-reversi/package.json", "./packages/misskey-reversi/"]

View File

@@ -34,7 +34,6 @@ describe('Before setup instance', () => {
cy.intercept('POST', '/api/admin/update-meta').as('update-meta');
cy.get('[data-cy-next]').click();
cy.get('[data-cy-next]').click();
cy.get('[data-cy-server-name] input').type('Testskey');
cy.get('[data-cy-server-setup-wizard-apply]').click();
@@ -79,6 +78,8 @@ describe('After setup instance', () => {
cy.get('[data-cy-signup-password] input').type('alice1234');
cy.get('[data-cy-signup-submit]').should('be.disabled');
cy.get('[data-cy-signup-password-retype] input').type('alice1234');
cy.get('[data-cy-signup-submit]').should('be.disabled');
cy.get('[data-cy-signup-invitation-code] input').type('test-invitation-code');
cy.get('[data-cy-signup-submit]').should('not.be.disabled');
cy.get('[data-cy-signup-submit]').click();

View File

@@ -1589,3 +1589,11 @@ _search:
searchScopeAll: "الكل"
searchScopeLocal: "المحلي"
searchScopeUser: "مستخدم محدد"
_watermarkEditor:
opacity: "الشفافية"
scale: "الحجم"
text: "نص"
position: "الموضع"
type: "نوع"
image: "صور"
advanced: "متقدم"

View File

@@ -1349,3 +1349,9 @@ _remoteLookupErrors:
_search:
searchScopeAll: "সবগুলো"
searchScopeLocal: "স্থানীয়"
_watermarkEditor:
opacity: "অস্বচ্ছতা"
scale: "আকার"
text: "লেখা"
image: "ছবি"
advanced: "উন্নত"

View File

@@ -1313,6 +1313,7 @@ availableRoles: "Roles disponibles "
acknowledgeNotesAndEnable: "Activa'l després de comprendre els possibles perills."
federationSpecified: "Aquest servidor treballa amb una federació de llistes blanques. No pot interactuar amb altres servidors que no siguin els especificats per l'administrador."
federationDisabled: "La unió es troba deshabilitada en aquest servidor. No es pot interactuar amb usuaris d'altres servidors."
draft: "Esborrany "
confirmOnReact: "Confirmar en reaccionar"
reactAreYouSure: "Vols reaccionar amb \"{emoji}\"?"
markAsSensitiveConfirm: "Vols marcar aquest contingut com a sensible?"
@@ -1350,7 +1351,7 @@ embed: "Incrustar"
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 "
federationJobs: "Treballs de federació"
driveAboutTip: "Al Disc veure's una llista de tots els arxius que has anat pujant.<br>\nPots tornar-los a fer servir adjuntant-los a notes noves o pots adelantar-te i pujar arxius per publicar-los més tard!<br>\n<b>Tingués en compte que si esborres un arxiu també desapareixerà de tots els llocs on l'has fet servir (notes, pàgines, avatars, imatges de capçalera, etc.)</b><br>\nTambé pots crear carpetes per organitzar les."
scrollToClose: "Desplaçar per tancar"
advice: "Consell"
@@ -1365,6 +1366,11 @@ abort: "Cancel·lar"
tip: "Trucs i consells"
redisplayAllTips: "Torna ha mostrat tots els trucs i consells"
hideAllTips: "Amagar tots els trucs i consells"
defaultImageCompressionLevel: "Nivell de comprensió de la imatge per defecte"
defaultImageCompressionLevel_description: "Baixa, conserva la qualitat de la imatge però la mida de l'arxiu és més gran. <br>Alta, redueix la mida de l'arxiu però també la qualitat de la imatge."
_order:
newest: "Més recent"
oldest: "Cronològic"
_chat:
noMessagesYet: "Encara no tens missatges "
newMessage: "Missatge nou"
@@ -1452,6 +1458,7 @@ _settings:
contentsUpdateFrequency_description: "Com més alt sigui l'adquisició de contingut en temps real, més baixa el rendiment i més consum de dades i bateria."
contentsUpdateFrequency_description2: "Quan s'activa el mode en temps real, el contingut s'actualitza en temps real, independentment d'aquesta configuració."
showUrlPreview: "Mostrar vista prèvia d'URL"
showAvailableReactionsFirstInNote: "Mostra les reacciones que pots fer servir al damunt"
_chat:
showSenderName: "Mostrar el nom del remitent"
sendOnEnter: "Introdueix per enviar"
@@ -1990,6 +1997,8 @@ _role:
uploadableFileTypes: "Tipus de fitxers que en podeu pujar"
uploadableFileTypes_caption: "Especifica el tipus MIME. Es poden especificar diferents tipus MIME separats amb una nova línia, i es poden especificar comodins amb asteriscs (*). (Per exemple: image/*)"
uploadableFileTypes_caption2: "Pot que no sigui possible determinar el tipus MIME d'alguns arxius. Per permetre aquests tipus d'arxius afegeix {x} a les especificacions."
noteDraftLimit: "Nombre possible d'esborranys de notes al servidor"
watermarkAvailable: "Pots fer servir la marca d'aigua"
_condition:
roleAssignedTo: "Assignat a rols manuals"
isLocal: "Usuari local"
@@ -2149,6 +2158,7 @@ _theme:
install: "Instal·lar un tema"
manage: "Gestionar els temes "
code: "Codi del tema"
copyThemeCode: "Copiar el codi del tema"
description: "Descripció"
installed: "{name} Instal·lat "
installedThemes: "Temes instal·lats "
@@ -2462,6 +2472,8 @@ _visibility:
disableFederation: "Sense federar"
disableFederationDescription: "No enviar a altres servidors"
_postForm:
quitInspiteOfThereAreUnuploadedFilesConfirm: "Hi ha arxius que no s'han carregat, vols descartar-los i tancar el formulari?"
uploaderTip: "L'arxiu encara no s'ha carregat. Des del menú arxiu pots canviar el nom, retallar imatges, posar marques d'aigua i comprimir o no l'arxiu. Els arxius es carreguen automàticament quan públiques una nota."
replyPlaceholder: "Contestar..."
quotePlaceholder: "Citar..."
channelPlaceholder: "Publicar a un canal..."
@@ -2795,6 +2807,7 @@ _fileViewer:
url: "URL"
uploadedAt: "Pujat el"
attachedNotes: "Notes amb aquest fitxer"
usage: "Ús "
thisPageCanBeSeenFromTheAuthor: "Aquesta pàgina només la pot veure l'usuari que ha pujat aquest fitxer."
_externalResourceInstaller:
title: "Instal·lar des d'un lloc extern"
@@ -3098,6 +3111,7 @@ _serverSetupWizard:
text2: "Si ho desitges, agrairíem molt la teva donació per poder seguir desenvolupant el projecte."
text3: "També hi ha privilegis especials per als donants!"
_uploader:
editImage: "Edició d'imatges"
compressedToX: "Comprimit a {x}"
savedXPercent: "{x}% d'estalvi "
abortConfirm: "Hi ha un arxiu que no s'ha pujat, vols cancel·lar?"
@@ -3117,3 +3131,67 @@ _clip:
tip: "Clip és una funció que permet organitzar les teves notes."
_userLists:
tip: "Es poden crear llistes amb qualsevol usuari. La llista creada es pot mostrar com una línia de temps."
watermark: "Marca d'aigua "
defaultPreset: "Per defecte"
_watermarkEditor:
tip: "A la imatge es pot afegir una marca d'aigua com informació sobre drets."
quitWithoutSaveConfirm: "Sortir sense desar?"
driveFileTypeWarn: "Aquest arxiu no és compatible"
driveFileTypeWarnDescription: "Selecciona un arxiu d'imatge "
title: "Editar la marca d'aigua "
cover: "Cobrir-ho tot"
repeat: "Repetir"
opacity: "Opacitat"
scale: "Mida"
text: "Text"
position: "Posició "
type: "Tipus"
image: "Imatges"
advanced: "Avançat"
stripe: "Bandes"
stripeWidth: "Amplada de la banda"
stripeFrequency: "Freqüència de la banda"
angle: "Angle"
polkadot: "Lunars"
checker: "Escacs"
polkadotMainDotOpacity: "Opacitat del lunar principal"
polkadotMainDotRadius: "Mida del lunar principal"
polkadotSubDotOpacity: "Opacitat del lunar secundari"
polkadotSubDotRadius: "Mida del lunar secundari"
polkadotSubDotDivisions: "Nombre de punts secundaris"
_imageEffector:
title: "Efecte"
addEffect: "Afegeix un efecte"
discardChangesConfirm: "Vols descartar els canvis i sortir?"
_fxs:
chromaticAberration: "Aberració cromàtica"
glitch: "Glitch"
mirror: "Mirall"
invert: "Inversió cromàtica "
grayscale: "Monocrom "
colorAdjust: "Correcció de color"
colorClamp: "Compressió cromàtica "
colorClampAdvanced: "Compressió de cromàtica avançada "
distort: "Distorsió "
threshold: "Binarització"
zoomLines: "Saturació de línies "
stripe: "Bandes"
polkadot: "Lunars"
checker: "Escacs"
blockNoise: "Bloqueig de soroll"
tearing: "Trencament d'imatge "
drafts: "Esborrany "
_drafts:
select: "Seleccionar esborrany"
cannotCreateDraftAnymore: "S'ha sobrepassat el nombre màxim d'esborranys que es poden crear."
cannotCreateDraft: "Amb aquest contingut no es poden crear esborranys."
delete: "Esborrar esborranys"
deleteAreYouSure: "Vols esborrar els esborranys?"
noDrafts: "No hi ha esborranys"
replyTo: "Respondre a {user}"
quoteOf: "Citar les notes de {user}"
postTo: "Destinat a {channel}"
saveToDraft: "Desar com a esborrany"
restoreFromDraft: "Restaurar des dels esborranys"
restore: "Restaurar esborrany"
listDrafts: "Llistat d'esborranys"

View File

@@ -2043,3 +2043,11 @@ _search:
searchScopeAll: "Vše"
searchScopeLocal: "Místní"
searchScopeUser: "Upřesnit uživatele"
_watermarkEditor:
opacity: "Průhlednost"
scale: "Velikost"
text: "Text"
position: "Pozice"
type: "Typ"
image: "Obrázky"
advanced: "Pokročilé"

View File

@@ -298,6 +298,7 @@ uploadFromUrl: "Von einer URL hochladen"
uploadFromUrlDescription: "URL der hochzuladenden Datei"
uploadFromUrlRequested: "Upload angefordert"
uploadFromUrlMayTakeTime: "Es kann eine Weile dauern, bis das Hochladen abgeschlossen ist."
uploadNFiles: "Lade {n} Dateien hoch"
explore: "Erkunden"
messageRead: "Gelesen"
noMoreHistory: "Kein weiterer Verlauf vorhanden"
@@ -326,6 +327,7 @@ dark: "Dunkel"
lightThemes: "Helle Farbschemata"
darkThemes: "Dunkle Farbschemata"
syncDeviceDarkMode: "Einstellung deines Geräts übernehmen"
switchDarkModeManuallyWhenSyncEnabledConfirm: "\"{x}\" ist eingeschaltet. Möchtest du die Synchronisation ausschalten und den Modus manuell wechseln?"
drive: "Drive"
fileName: "Dateiname"
selectFile: "Datei auswählen"
@@ -575,8 +577,10 @@ showFixedPostForm: "Bereich zum Schreiben neuer Notizen am Anfang der Chronik an
showFixedPostFormInChannel: "Bereich zum Schreiben neuer Notizen am Anfang der Chronik anzeigen (Kanäle)"
withRepliesByDefaultForNewlyFollowed: "Standardmäßig Antworten von neu gefolgten Benutzern in der Chronik anzeigen"
newNoteRecived: "Es gibt neue Notizen"
newNote: "Neue Notiz"
sounds: "Töne"
sound: "Töne"
notificationSoundSettings: "Benachrichtigungston festlegen"
listen: "Anhören"
none: "Nichts"
showInPage: "In einer Seite anzeigen"
@@ -791,6 +795,7 @@ wide: "Breit"
narrow: "Schmal"
reloadToApplySetting: "Diese Einstellung tritt nach einer Aktualisierung der Seite in Kraft. Jetzt aktualisieren?"
needReloadToApply: "Diese Einstellung tritt nach einer Aktualisierung der Seite in Kraft."
needToRestartServerToApply: "Diese Einstellung tritt nach einem Neustart des Servers in Kraft."
showTitlebar: "Titelleiste anzeigen"
clearCache: "Cache leeren"
onlineUsersCount: "{n} Benutzer sind online"
@@ -997,6 +1002,7 @@ failedToUpload: "Hochladen fehlgeschlagen"
cannotUploadBecauseInappropriate: "Diese Datei kann nicht hochgeladen werden, da Anteile der Datei als möglicherweise unangebracht festgestellt wurden."
cannotUploadBecauseNoFreeSpace: "Die Datei konnte nicht hochgeladen werden, da dein Drive-Speicherplatz aufgebraucht ist."
cannotUploadBecauseExceedsFileSizeLimit: "Diese Datei kann wegen Überschreitung der Maximalgröße nicht hochgeladen werden."
cannotUploadBecauseUnallowedFileType: "Hochladen nicht möglich wegen unzulässigem Dateityp."
beta: "Beta"
enableAutoSensitive: "Automarkierung sensibler Medien"
enableAutoSensitiveDescription: "Setzt soweit möglich durch Verwendung von Machine Learning automatisch Markierungen für sensible Medien. Auch wenn du diese Option deaktiviert hast, ist sie möglicherweise auf Instanzebene aktiviert."
@@ -1307,6 +1313,7 @@ availableRoles: "Verfügbare Rollen"
acknowledgeNotesAndEnable: "Schalten Sie dies erst ein, wenn Sie die Vorsichtsmaßnahmen verstanden haben."
federationSpecified: "Dieser Server arbeitet mit Whitelist-Föderation. Er kann nicht mit anderen als den vom Administrator angegebenen Servern interagieren."
federationDisabled: "Föderation ist auf diesem Server deaktiviert. Es ist nicht möglich, mit Benutzern auf anderen Servern zu interagieren."
draft: "Entwurf"
confirmOnReact: "Reagieren bestätigen"
reactAreYouSure: "Willst du eine \"{emoji}\"-Reaktion hinzufügen?"
markAsSensitiveConfirm: "Möchtest du dieses Medium als sensibel kennzeichnen?"
@@ -1324,6 +1331,7 @@ restore: "Wiederherstellen"
syncBetweenDevices: "Zwischen Geräten synchronisieren"
preferenceSyncConflictTitle: "Der konfigurierte Wert ist auf dem Server bereits vorhanden."
preferenceSyncConflictText: "Die Einstellungen mit aktivierter Synchronisierung werden ihre Werte auf dem Server speichern. Es gibt jedoch bereits Werte auf dem Server. Welche Einstellungswerte sollen überschrieben werden?"
preferenceSyncConflictChoiceMerge: "Zusammenführen"
preferenceSyncConflictChoiceServer: "Konfigurierte Werte auf dem Server"
preferenceSyncConflictChoiceDevice: "Konfigurierte Werte auf dem Gerät"
preferenceSyncConflictChoiceCancel: "Einrichten der Synchronisierung abbrechen"
@@ -1340,12 +1348,29 @@ 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)"
settingsMigrating: "Deine Einstellungen werden gerade migriert. Bitte warte einen Moment... (Du kannst die Einstellungen später auch manuell migrieren, indem du zu Einstellungen → Anderes → Alte Einstellungen migrieren gehst)"
readonly: "Nur Lesezugriff"
goToDeck: "Zurück zum Deck"
federationJobs: "Föderation Jobs"
driveAboutTip: "In Drive sehen Sie eine Liste der Dateien, die Sie in der Vergangenheit hochgeladen haben. <br>\nSie können diese Dateien wiederverwenden um sie zu beispiel an Notizen anzuhängen, oder sie können Dateien vorab hochzuladen, um sie später zu versenden! <br>\n<b>Wenn Sie eine Datei löschen, verschwindet sie auch von allen Stellen, an denen Sie sie verwendet haben (Notizen, Seiten, Avatare, Banner usw.).</b><br>\nSie können auch Ordner erstellen, um sie zu organisieren."
scrollToClose: "Zum Schließen scrollen"
advice: "Tipps"
realtimeMode: "Echtzeit-Modus"
turnItOn: "Einschalten"
turnItOff: "Ausschalten"
emojiMute: "Emoji stummschalten"
emojiUnmute: "Emoji-Stummschaltung aufheben"
muteX: "{x} stummschalten"
unmuteX: "Stummschaltung von {x} aufheben"
abort: "Abbrechen"
tip: "Tipps und Tricks"
redisplayAllTips: "Alle „Tipps und Tricks“ wieder anzeigen"
hideAllTips: "Alle „Tipps und Tricks“ ausblenden"
defaultImageCompressionLevel: "Standard-Bildkomprimierungsstufe"
defaultImageCompressionLevel_description: "Ein niedrigerer Wert erhält die Bildqualität, erhöht aber die Dateigröße. <br>Höhere Werte reduzieren die Dateigröße, verringern aber die Bildqualität."
_order:
newest: "Neueste zuerst"
oldest: "Älteste zuerst"
_chat:
noMessagesYet: "Noch keine Nachrichten"
newMessage: "Neue Nachricht"
@@ -1379,6 +1404,8 @@ _chat:
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."
youAreNotAMemberOfThisRoomButInvited: "Du bist kein Teilnehmer in diesem Raum, aber du hast eine Einladung erhalten. Bitte nimm die Einladung an, um beizutreten."
doYouAcceptInvitation: "Nimmst du die Einladung an?"
chatWithThisUser: "Mit dem Benutzer chatten"
thisUserAllowsChatOnlyFromFollowers: "Dieser Benutzer nimmt nur Chats von Followern an."
thisUserAllowsChatOnlyFromFollowing: "Dieser Benutzer nimmt nur Chats von Benutzern an, denen er folgt."
@@ -1418,12 +1445,20 @@ _settings:
makeEveryTextElementsSelectable: "Alle Textelemente auswählbar machen"
makeEveryTextElementsSelectable_description: "Die Aktivierung kann in manchen Situationen die Benutzerfreundlichkeit beeinträchtigen."
useStickyIcons: "Icons beim Scrollen folgen lassen"
enableHighQualityImagePlaceholders: "Zeige Platzhalter für Bilder in hoher Qualität an"
uiAnimations: "Animationen der Benutzeroberfläche"
showNavbarSubButtons: "Unterschaltflächen in der Navigationsleiste anzeigen"
ifOn: "Wenn eingeschaltet"
ifOff: "Wenn ausgeschaltet"
enableSyncThemesBetweenDevices: "Synchronisierung von installierten Themen auf verschiedenen Endgeräten"
enablePullToRefresh: "Ziehen zum Aktualisieren"
enablePullToRefresh_description: "Bei Benutzung einer Maus, mit gedrücktem Mausrad ziehen"
realtimeMode_description: "Stellt eine Verbindung mit dem Server her und aktualisiert die Inhalte in Echtzeit. Kann zu mehr Datenverkehr einem höheren Akkuverbrauch führen."
contentsUpdateFrequency: "Häufigkeit des Abrufs von Inhalten"
contentsUpdateFrequency_description: "Je höher der Wert, desto häufiger werden die Inhalte aktualisiert, aber die Leistung sinkt und der Datenverkehr und der Akkuverbrauch steigen."
contentsUpdateFrequency_description2: "Wenn der Echtzeitmodus aktiviert ist, werden die Inhalte unabhängig von dieser Einstellung in Echtzeit aktualisiert."
showUrlPreview: "URL-Vorschau anzeigen"
showAvailableReactionsFirstInNote: "Zeige die verfügbaren Reaktionen im oberen Bereich an."
_chat:
showSenderName: "Name des Absenders anzeigen"
sendOnEnter: "Eingabetaste sendet Nachricht"
@@ -1604,6 +1639,21 @@ _serverSettings:
thisSettingWillAutomaticallyOffWhenModeratorsInactive: "Wenn über einen bestimmten Zeitraum keine Moderatorenaktivität festgestellt wird, wird diese Einstellung automatisch deaktiviert, um Spam zu verhindern."
deliverSuspendedSoftware: "Software, die nicht mehr beliefert wird"
deliverSuspendedSoftwareDescription: "Sie können eine Auswahl von Namen und Versionen verschiedener Serversoftware angeben, um die Zustellung zu stoppen, z. B. aufgrund von Sicherheitslücken. Diese Versionsinformationen werden vom Server bereitgestellt und ihre Zuverlässigkeit ist nicht garantiert. Es wird jedoch empfohlen, eine Vorabversion anzugeben, wie z. B. >= 2024.3.1-0, da die Angabe >= 2024.3.1 keine benutzerdefinierten Versionen wie 2024.3.1-custom.0 einschließt."
singleUserMode: "Einzelbenutzermodus"
singleUserMode_description: "Wenn du der einzige Benutzer dieses Servers bist, optimiert die Aktivierung dieses Modus die Leistung des Servers."
signToActivityPubGet: "ActivityPub-GET-Anfragen signieren"
signToActivityPubGet_description: "Normalerweise sollte diese Option aktiviert sein. Die Deaktivierung kann Probleme im Zusammenhang mit der Föderation beheben, aber andererseits könnte sie die Föderation mit einigen anderen Servern deaktivieren."
proxyRemoteFiles: "Proxy für Dateien fremder Instanzen"
proxyRemoteFiles_description: "Wenn diese Einstellung aktiviert ist, werden fremde Dateien über einen Proxyserver übertragen und bereitgestellt. Dies hilft bei der Erstellung von Vorschaubildern und schützt die Privatsphäre der Benutzer."
allowExternalApRedirect: "Weiterleitungen für Anfragen über ActivityPub zulassen"
allowExternalApRedirect_description: "Wenn diese Option aktiviert ist, können andere Server Inhalte von Drittanbietern über diesen Server abfragen, was jedoch zu Content-Spoofing führen kann."
userGeneratedContentsVisibilityForVisitor: "Sichtbarkeit von nutzergenerierten Inhalten für Gäste"
userGeneratedContentsVisibilityForVisitor_description: "Dies ist nützlich, um zu verhindern, dass unangemessene Inhalte, die nicht gut moderiert sind, ungewollt über deinen eigenen Server im Internet veröffentlicht werden."
userGeneratedContentsVisibilityForVisitor_description2: "Die uneingeschränkte Veröffentlichung aller Inhalte des Servers im Internet, einschließlich der vom Server empfangenen Fremdinhalte, birgt Risiken. Dies ist besonders wichtig für Betrachter, die sich des dezentralen Charakters der Inhalte nicht bewusst sind, da sie selbst fremde Inhalte fälschlicherweise als auf dem Server erstellte Inhalte wahrnehmen könnten."
_userGeneratedContentsVisibilityForVisitor:
all: "Alles ist öffentlich"
localOnly: "Nur lokale Inhalte werden veröffentlicht, fremde Inhalte bleiben privat"
none: "Alles ist privat"
_accountMigration:
moveFrom: "Von einem anderen Konto zu diesem migrieren"
moveFromSub: "Alias für ein anderes Konto erstellen"
@@ -1944,6 +1994,11 @@ _role:
canImportMuting: "Importieren von Stummgeschalteten zulassen"
canImportUserLists: "Importieren von Listen erlauben"
chatAvailability: "Chatten erlauben"
uploadableFileTypes: "Hochladbare Dateitypen"
uploadableFileTypes_caption: "Gibt die zulässigen MIME-/Dateitypen an. Mehrere MIME-Typen können durch einen Zeilenumbruch getrennt angegeben werden, und Platzhalter können mit einem Sternchen (*) angegeben werden. (z. B. image/*)"
uploadableFileTypes_caption2: "Bei manchen Dateien ist es nicht möglich, den Typ zu bestimmen. Um solche Dateien zuzulassen, füge {x} der Spezifikation hinzu."
noteDraftLimit: "Anzahl der möglichen Entwürfe für serverseitige Notizen"
watermarkAvailable: "Kann die Wasserzeichenfunktion verwenden"
_condition:
roleAssignedTo: "Manuellen Rollen zugewiesen"
isLocal: "Lokaler Benutzer"
@@ -2103,6 +2158,7 @@ _theme:
install: "Farbschemata installieren"
manage: "Farbschemaverwaltung"
code: "Farbschemencode"
copyThemeCode: "Farbschemencode kopieren"
description: "Beschreibung"
installed: "{name} wurde installiert"
installedThemes: "Installierte Farbschemata"
@@ -2416,6 +2472,8 @@ _visibility:
disableFederation: "Deföderieren"
disableFederationDescription: "Nicht an andere Instanzen übertragen"
_postForm:
quitInspiteOfThereAreUnuploadedFilesConfirm: "Es gibt Dateien, die nicht hochgeladen wurden. Möchtest du diese verwerfen und das Formular schließen?"
uploaderTip: "Die Datei wurde noch nicht hochgeladen. Über das Dateimenü kannst du sie umbenennen, das Bild zuschneiden, ein Wasserzeichen hinzufügen, komprimieren usw. Die Datei wird automatisch hochgeladen, wenn du eine Notiz veröffentlichst."
replyPlaceholder: "Dieser Notiz antworten …"
quotePlaceholder: "Diese Notiz zitieren …"
channelPlaceholder: "In einen Kanal senden"
@@ -2796,6 +2854,12 @@ _dataSaver:
_avatar:
title: "Animierte Profilbilder deaktivieren"
description: "Die Animation von Profilbildern wird angehalten. Da animierte Bilder eine größere Dateigröße haben können als normale Bilder, kann dies den Datenverkehr weiter reduzieren."
_urlPreviewThumbnail:
title: "URL-Vorschaubilder ausblenden"
description: "URL-Vorschaubilder werden nicht mehr geladen."
_disableUrlPreview:
title: "URL-Vorschau deaktivieren"
description: "Deaktiviert die URL-Vorschaufunktion. Anders als bei reinen Vorschaubildern wird dadurch das Laden der verlinkten Informationen selbst reduziert."
_code:
title: "Code-Hervorhebungen ausblenden"
description: "Wenn Code-Hervorhebungen in MFM usw. verwendet werden, werden sie erst geladen, wenn sie angetippt werden. Die Syntaxhervorhebung erfordert das Herunterladen der Definitionsdateien für jede Programmiersprache. Es ist daher zu erwarten, dass die Deaktivierung des automatischen Ladens dieser Dateien die Menge des Datenverkehrs reduziert."
@@ -2853,6 +2917,8 @@ _offlineScreen:
_urlPreviewSetting:
title: "Einstellungen der URL-Vorschau"
enable: "URL-Vorschau aktivieren"
allowRedirect: "Umleitung von URL-Vorschauen erlauben"
allowRedirectDescription: "Wenn für eine URL eine Umleitung festgelegt ist, kann diese Funktion aktiviert werden, um der Umleitung zu folgen und eine Vorschau des umgeleiteten Inhalts anzuzeigen. Die Deaktivierung spart Serverressourcen, aber der Inhalt des Weiterleitungsziels wird nicht angezeigt."
timeout: "Zeitüberschreitung beim Abrufen der Vorschau (ms)"
timeoutDescription: "Übersteigt die für die Vorschau benötigte Zeit diesen Wert, wird keine Vorschau generiert."
maximumContentLength: "Maximale Content-Length (Bytes)"
@@ -3001,3 +3067,121 @@ _search:
pleaseEnterServerHost: "Gib den Server-Host ein"
pleaseSelectUser: "Benutzer auswählen"
serverHostPlaceholder: "Beispiel: misskey.example.com"
_serverSetupWizard:
installCompleted: "Die Installation von Misskey ist abgeschlossen!"
firstCreateAccount: "Erstelle zunächst ein Administratorkonto."
accountCreated: "Ein Administratorkonto wurde angelegt!"
serverSetting: "Servereinstellungen"
youCanEasilyConfigureOptimalServerSettingsWithThisWizard: "Mit diesem Assistenten lässt sich die optimale Serverkonfiguration leicht einrichten."
settingsYouMakeHereCanBeChangedLater: "Die Einstellungen hier können später geändert werden."
howWillYouUseMisskey: "Wie wirst du Misskey verwenden?"
_use:
single: "Ein-Personen-Server"
single_description: "Verwende den Server alleine als deinen eigenen."
single_youCanCreateMultipleAccounts: "Bei Bedarf können mehrere Konten eingerichtet werden, auch wenn es sich um einen Ein-Personen-Server handelt."
group: "Gruppenserver"
group_description: "Lade andere vertrauenswürdige Benutzer ein und verwende es mit mehreren Personen."
open: "Offener Server"
open_description: "Registrierung für alle öffnen."
openServerAdvice: "Die Aufnahme einer unbestimmten Anzahl von Nutzern birgt Risiken. Es wird empfohlen, mit einem zuverlässigen Moderationssystem zu arbeiten, um eventuell auftretende Probleme behandeln zu können."
openServerAntiSpamAdvice: "Große Sorgfalt muss auch auf die Sicherheit gelegt werden, z. B. durch die Aktivierung von Anti-Bot-Funktionen wie reCAPTCHA, um sicherzustellen, dass der Server nicht zum Verbreiten von Spam genutzt wird."
howManyUsersDoYouExpect: "Mit wie vielen Benutzern rechnest du?"
_scale:
small: "Weniger als 100 (kleiner Maßstab)"
medium: "Mehr als 100 und weniger als 1000 Benutzer (mittelgroß)"
large: "Mehr als 1000 (großer Maßstab)"
largeScaleServerAdvice: "Für große Server sind unter Umständen fortgeschrittene Kenntnisse erforderlich, z. B. Lastverteilung und Datenbankreplikation."
doYouConnectToFediverse: "Mit dem Fediverse verbinden?"
doYouConnectToFediverse_description1: "Bei Anschluss an ein Netz von verteilten Servern (Fediverse) können Inhalte mit anderen Servern ausgetauscht werden."
doYouConnectToFediverse_description2: "Die Verbindung mit dem Fediverse wird auch als „Föderation“ bezeichnet."
youCanConfigureMoreFederationSettingsLater: "Erweiterte Einstellungen, wie z. B. die Angabe von föderierbaren Servern, können später vorgenommen werden."
adminInfo: "Administrator-Informationen"
adminInfo_description: "Legt die Administrator-Informationen fest, die für den Empfang von Anfragen verwendet werden."
adminInfo_mustBeFilled: "Dies ist auf einem offenen Server oder bei aktivierter Föderation erforderlich."
followingSettingsAreRecommended: "Die folgenden Einstellungen werden empfohlen"
applyTheseSettings: "Diese Einstellungen anwenden"
skipSettings: "Konfiguration überspringen"
settingsCompleted: "Einrichtung abgeschlossen!"
settingsCompleted_description: "Vielen Dank für deine Zeit. Jetzt, wo alles fertig ist, kannst du den Server sofort benutzen."
settingsCompleted_description2: "Detaillierte Servereinstellungen können über die „Systemsteuerung“ vorgenommen werden."
donationRequest: "Spendenaufruf"
_donationRequest:
text1: "Misskey ist eine freie Software, die von Freiwilligen entwickelt wird."
text2: "Wir würden uns über deine Unterstützung freuen, damit wir dieses Projekt auch in Zukunft weiterentwickeln können."
text3: "Für Unterstützer gibt es auch besondere Vorteile!"
_uploader:
editImage: "Bild bearbeiten"
compressedToX: "Komprimiert zu {x}"
savedXPercent: "{x}% gespart"
abortConfirm: "Einige Dateien wurden nicht hochgeladen. Möchtest du den Vorgang abbrechen?"
doneConfirm: "Einige Dateien wurden nicht hochgeladen. Möchtest du den Vorgang fortsetzen?"
maxFileSizeIsX: "Die maximale Dateigröße, die hochgeladen werden kann, beträgt {x}."
allowedTypes: "Hochladbare Dateitypen"
tip: "Die Datei ist noch nicht hochgeladen worden. In diesem Dialog kannst du die Datei vor dem Hochladen anzeigen, umbenennen, komprimieren und zuschneiden. Wenn du fertig bist, klicke auf „Hochladen“, um den Upload zu starten."
_clientPerformanceIssueTip:
makeSureDisabledAdBlocker: "Deaktiviere deinen Adblocker"
makeSureDisabledAdBlocker_description: "Adblocker können die Leistung beeinträchtigen; vergewissere dich, ob in deinem Betriebssystem, Browser oder deinen Add-ons Adblocker aktiviert sind."
makeSureDisabledCustomCss: "Benutzerdefiniertes CSS deaktivieren"
makeSureDisabledCustomCss_description: "Das Überschreiben von Stilen kann die Leistung beeinträchtigen. Stelle daher sicher, dass du kein benutzerdefiniertes CSS oder Erweiterungen aktiviert hast, die Stile überschreiben."
makeSureDisabledAddons: "Erweiterungen deaktivieren"
makeSureDisabledAddons_description: "Einige Erweiterungen können das Verhalten des Clients stören und die Leistung beeinträchtigen. Deaktiviere die Browser-Erweiterungen und prüfe, ob sich die Situation dadurch verbessert."
_clip:
tip: "Clips sind eine Funktion, mit der du Notizen gruppieren kannst."
_userLists:
tip: "Es können Listen mit beliebigen Benutzern erstellt werden. Die erstellte Liste kann als eigene Chronik angezeigt werden."
watermark: "Wasserzeichen"
defaultPreset: "Standard-Voreinstellungen"
_watermarkEditor:
tip: "Dem Bild kann ein Wasserzeichen, z. B. eine Quellenangabe, hinzugefügt werden."
quitWithoutSaveConfirm: "Nicht gespeicherte Änderungen verwerfen?"
driveFileTypeWarn: "Diese Datei wird nicht unterstützt"
driveFileTypeWarnDescription: "Bilddatei auswählen"
title: "Wasserzeichen bearbeiten"
cover: "Alles bedecken"
opacity: "Transparenz"
scale: "Größe"
text: "Text"
position: "Position"
type: "Art"
image: "Bilder"
advanced: "Fortgeschritten"
stripe: "Streifen"
stripeWidth: "Linienbreite"
stripeFrequency: "Linienanzahl"
angle: "Winkel"
polkadot: "Punktmuster"
polkadotMainDotOpacity: "Deckkraft des Hauptpunktes"
polkadotMainDotRadius: "Größe des Hauptpunktes"
polkadotSubDotOpacity: "Deckkraft des Unterpunktes"
polkadotSubDotRadius: "Größe des Unterpunktes"
polkadotSubDotDivisions: "Anzahl der Unterpunkte"
_imageEffector:
title: "Effekte"
addEffect: "Effekte hinzufügen"
discardChangesConfirm: "Änderungen verwerfen und beenden?"
_fxs:
chromaticAberration: "Chromatische Abweichung"
glitch: "Glitch"
mirror: "Spiegeln"
invert: "Farben umkehren"
grayscale: "Schwarzweiß"
colorAdjust: "Farbkorrektur"
colorClamp: "Farbkomprimierung"
colorClampAdvanced: "Farbkomprimierung (erweitert)"
distort: "Verzerrung"
stripe: "Streifen"
polkadot: "Punktmuster"
drafts: "Entwurf"
_drafts:
select: "Entwurf auswählen"
cannotCreateDraftAnymore: "Die Anzahl der Entwürfe, die erstellt werden können, wurde überschritten."
cannotCreateDraft: "Mit diesem Inhalt kann kein Entwurf erstellt werden."
delete: "Entwurf löschen"
deleteAreYouSure: "Entwurf löschen?"
noDrafts: "Keine Entwürfe"
replyTo: "Antwort an {user}"
quoteOf: "Zitat von {user}s Notiz"
saveToDraft: "Als Entwurf speichern"
restoreFromDraft: "Aus Entwurf wiederherstellen"
restore: "Wiederherstellen"
listDrafts: "Liste der Entwürfe"

View File

@@ -403,3 +403,5 @@ _reversi:
total: "Σύνολο"
_search:
searchScopeLocal: "Τοπικό"
_watermarkEditor:
image: "Εικόνες"

View File

@@ -327,7 +327,7 @@ dark: "Dark"
lightThemes: "Light themes"
darkThemes: "Dark themes"
syncDeviceDarkMode: "Sync Dark Mode with your device settings"
switchDarkModeManuallyWhenSyncEnabledConfirm: "\"{x}\" is turned on, Would you like to turn off synchronization and switch modes manually?"
switchDarkModeManuallyWhenSyncEnabledConfirm: "\"{x}\" is turned on. Would you like to turn off synchronization and switch modes manually?"
drive: "Drive"
fileName: "Filename"
selectFile: "Select a file"
@@ -1313,6 +1313,7 @@ availableRoles: "Available roles"
acknowledgeNotesAndEnable: "Turn on after understanding the precautions."
federationSpecified: "This server is operated in a whitelist federation. Interacting with servers other than those designated by the administrator is not allowed."
federationDisabled: "Federation is disabled on this server. You cannot interact with users on other servers."
draft: "Drafts"
confirmOnReact: "Confirm when reacting"
reactAreYouSure: "Would you like to add a \"{emoji}\" reaction?"
markAsSensitiveConfirm: "Do you want to set this media as sensitive?"
@@ -1365,6 +1366,11 @@ abort: "Abort"
tip: "Tips & Tricks"
redisplayAllTips: "Show all “Tips & Tricks” again"
hideAllTips: "Hide all \"Tips & Tricks\""
defaultImageCompressionLevel: "Default image compression level"
defaultImageCompressionLevel_description: "Lower level preserves image quality but increases file size.<br>Higher level reduce file size, but reduce image quality."
_order:
newest: "Newest First"
oldest: "Oldest First"
_chat:
noMessagesYet: "No messages yet"
newMessage: "New message"
@@ -1452,6 +1458,7 @@ _settings:
contentsUpdateFrequency_description: "The higher the value the more the content updates but it lowers the performance and increases the traffic and memory consumption."
contentsUpdateFrequency_description2: "When real-time mode is on, content is updated in real time regardless of this setting."
showUrlPreview: "Show URL preview"
showAvailableReactionsFirstInNote: "Show available reactions at the top."
_chat:
showSenderName: "Show sender's name"
sendOnEnter: "Press Enter to send"
@@ -1990,6 +1997,8 @@ _role:
uploadableFileTypes: "Uploadable file types"
uploadableFileTypes_caption: "Specifies the allowed MIME/file types. Multiple MIME types can be specified by separating them with a new line, and wildcards can be specified with an asterisk (*). (e.g., image/*)"
uploadableFileTypes_caption2: "Some files types might fail to be detected. To allow such files, add {x} to the specification."
noteDraftLimit: "Number of possible drafts of server notes"
watermarkAvailable: "Availability of watermark function"
_condition:
roleAssignedTo: "Assigned to manual roles"
isLocal: "Local user"
@@ -2149,6 +2158,7 @@ _theme:
install: "Install a theme"
manage: "Manage themes"
code: "Theme code"
copyThemeCode: "Copy theme code"
description: "Description"
installed: "{name} has been installed"
installedThemes: "Installed themes"
@@ -2462,6 +2472,8 @@ _visibility:
disableFederation: "Defederate"
disableFederationDescription: "Don't transmit to other instances"
_postForm:
quitInspiteOfThereAreUnuploadedFilesConfirm: "There are files that have not been uploaded, do you want to discard them and close the form?"
uploaderTip: "The file has not yet been uploaded. From the file menu, you can rename, crop images, watermark and compress or uncompress the file. Files are automatically uploaded when you publish a note."
replyPlaceholder: "Reply to this note..."
quotePlaceholder: "Quote this note..."
channelPlaceholder: "Post to a channel..."
@@ -2795,6 +2807,7 @@ _fileViewer:
url: "URL"
uploadedAt: "Uploaded at"
attachedNotes: "Attached notes"
usage: "Used"
thisPageCanBeSeenFromTheAuthor: "This page can only be seen by the user who uploaded this file."
_externalResourceInstaller:
title: "Install from external site"
@@ -2968,7 +2981,7 @@ _customEmojisManager:
markAsDeleteTargetRanges: "Mark rows in the selection as a target to delete"
alertUpdateEmojisNothingDescription: "There are no updated Emojis."
alertDeleteEmojisNothingDescription: "There are no Emojis to be deleted."
confirmMovePage: ""
confirmMovePage: "Would you like to move pages?"
confirmChangeView: ""
confirmUpdateEmojisDescription: "Update {count} Emoji(s). Are you sure to continue?"
confirmDeleteEmojisDescription: "Delete checked {count} Emoji(s). Are you sure to continue?"
@@ -3098,6 +3111,7 @@ _serverSetupWizard:
text2: "We would appreciate your support so that we can continue to develop this software further into the future."
text3: "There are also special benefits for supporters!"
_uploader:
editImage: "Edit Image"
compressedToX: "Compressed to {x}"
savedXPercent: "Saving {x}%"
abortConfirm: "Some files have not been uploaded, do you want to abort?"
@@ -3117,3 +3131,67 @@ _clip:
tip: "Clip is a feature that allows you to organize your notes."
_userLists:
tip: "Lists can contain any user you specify when creating, the created list can then be displayed as a timeline showing only the specified users."
watermark: "Watermark"
defaultPreset: "Default Preset"
_watermarkEditor:
tip: "A watermark, such as credit information, can be added to the image."
quitWithoutSaveConfirm: "Discard unsaved changes?"
driveFileTypeWarn: "This file is not supported"
driveFileTypeWarnDescription: "Choose an image file"
title: "Edit Watermark"
cover: "Cover everything"
repeat: "spread all over"
opacity: "Opacity"
scale: "Size"
text: "Text"
position: "Position"
type: "Type"
image: "Images"
advanced: "Advanced"
stripe: "Stripes"
stripeWidth: "Line width"
stripeFrequency: "Lines count"
angle: "Angle"
polkadot: "Polkadot"
checker: "Checker"
polkadotMainDotOpacity: "Opacity of the main dot"
polkadotMainDotRadius: "Size of the main dot"
polkadotSubDotOpacity: "Opacity of the secondary dot"
polkadotSubDotRadius: "Size of the secondary dot"
polkadotSubDotDivisions: "Number of sub-dots."
_imageEffector:
title: "Effects"
addEffect: "Add Effects"
discardChangesConfirm: "Are you sure you want to leave? You have unsaved changes."
_fxs:
chromaticAberration: "Chromatic Aberration"
glitch: "Glitch"
mirror: "Mirror"
invert: "Invert Colors"
grayscale: "Grayscale"
colorAdjust: "Color Correction"
colorClamp: "Color Compression"
colorClampAdvanced: "Color Compression (Advanced)"
distort: "Distortion"
threshold: "Binarize"
zoomLines: "Saturated lines"
stripe: "Stripes"
polkadot: "Polkadot"
checker: "Checker"
blockNoise: "Block Noise"
tearing: "Tearing"
drafts: "Drafts"
_drafts:
select: "Select Draft"
cannotCreateDraftAnymore: "The number of drafts that can be created has been exceeded."
cannotCreateDraft: "You cannot create a draft with this content."
delete: "Delete Draft"
deleteAreYouSure: "Delete draft?"
noDrafts: "No drafts"
replyTo: "Reply to {user}"
quoteOf: "Citation to {user}'s note"
postTo: "Posting to {channel}"
saveToDraft: "Save to Draft"
restoreFromDraft: "Restore from Draft"
restore: "Restore"
listDrafts: "List of Drafts"

View File

@@ -61,11 +61,11 @@ copyRSS: "Copiar RSS"
copyUsername: "Copiar nombre de usuario"
copyUserId: "Copiar ID del usuario"
copyNoteId: "Copiar ID de la nota"
copyFileId: "Copiar ID del archivo"
copyFileId: "Copiar ID de archivo"
copyFolderId: "Copiar ID de carpeta"
copyProfileUrl: "Copiar la URL del perfil"
searchUser: "Buscar un usuario"
searchThisUsersNotes: ""
searchThisUsersNotes: "Buscar en las notas de este usuario"
reply: "Responder"
loadMore: "Ver más"
showMore: "Ver más"
@@ -83,10 +83,10 @@ files: "Archivos"
download: "Descargar"
driveFileDeleteConfirm: "¿Desea borrar el archivo \"{name}\"? Las notas que tengan este archivo como adjunto serán eliminadas"
unfollowConfirm: "¿Desea dejar de seguir a {name}?"
exportRequested: "Se ha solicitado la exportación. Puede tomar un tiempo. Cuando termine la exportación, se añadirá en el drive"
importRequested: "Se ha solicitado la importación. Puede tomar un tiempo."
exportRequested: "Has solicitado la exportación. Puede llevar un tiempo. Cuando termine la exportación, se añadirá al drive"
importRequested: "Has solicitado la importación. Puede llevar un tiempo."
lists: "Listas"
noLists: "No tiene listas"
noLists: "No tienes ninguna lista"
note: "Notas"
notes: "Notas"
following: "Siguiendo"
@@ -99,9 +99,9 @@ somethingHappened: "Ocurrió un error"
retry: "Reintentar"
pageLoadError: "Error al leer la página"
pageLoadErrorDescription: "Normalmente es debido a la red o al caché del navegador. Por favor limpie el caché o intente más tarde."
serverIsDead: "No hay respuesta del servidor. Espere un momento y vuelva a intentarlo."
youShouldUpgradeClient: "Para ver esta página, por favor refrezca el navegador y utiliza una versión más reciente del cliente."
enterListName: "Ingrese nombre de lista"
serverIsDead: "No hay respuesta del servidor. Espera un momento y vuelve a intentarlo."
youShouldUpgradeClient: "Para ver esta página, recarga el navegador para actualizar el cliente."
enterListName: "Introduce un nombre para la lista"
privacy: "Privacidad"
makeFollowManuallyApprove: "Aprobar manualmente las solicitudes de seguimiento"
defaultNoteVisibility: "Visibilidad por defecto"
@@ -125,7 +125,7 @@ renoteToOtherChannel: "Renotar a otro canal"
pinnedNote: "Nota fijada"
pinned: "Fijar al perfil"
you: "Tú"
clickToShow: "Click para ver"
clickToShow: "Haz clic para verlo"
sensitive: "Marcado como sensible"
add: "Agregar"
reaction: "Reacción"
@@ -134,28 +134,28 @@ emojiPicker: "Selector de emojis"
pinnedEmojisForReactionSettingDescription: "Puedes seleccionar reacciones para fijarlos en el selector"
pinnedEmojisSettingDescription: "Puedes seleccionar emojis para fijarlos en el selector"
emojiPickerDisplay: "Mostrar el selector de emojis"
overwriteFromPinnedEmojisForReaction: "Sobreescribir las reacciones fijadas"
overwriteFromPinnedEmojis: "Sobreescribir los emojis fijados"
reactionSettingDescription2: "Arrastre para reordenar, click para borrar, apriete la tecla + para añadir."
overwriteFromPinnedEmojisForReaction: "Sobreescribir los ajustes de reacciones"
overwriteFromPinnedEmojis: "Sobreescribir los ajustes generales"
reactionSettingDescription2: "Arrastra para reordenar, click para borrar, pulsa \"+\" para añadir."
rememberNoteVisibility: "Recordar visibilidad"
attachCancel: "Quitar adjunto"
deleteFile: "Archivo eliminado"
deleteFile: "Eliminar archivo"
markAsSensitive: "Marcar como sensible"
unmarkAsSensitive: "Desmarcar como sensible"
enterFileName: "Ingrese el nombre del archivo"
enterFileName: "Introduce el nombre del archivo"
mute: "Silenciar"
unmute: "Dejar de silenciar"
renoteMute: "Silenciar renota"
renoteUnmute: "Desilenciar renota"
block: "Bloquear"
unblock: "Dejar de bloquear"
unblock: "Desbloquear"
suspend: "Suspender"
unsuspend: "Dejar de suspender"
blockConfirm: "¿Quiere bloquear esta cuenta?"
unblockConfirm: "¿Quiere dejar de bloquear esta cuenta?"
suspendConfirm: "¿Quiere suspender esta cuenta?"
unsuspendConfirm: "¿Quiere dejar de suspender esta cuenta?"
selectList: "Seleccione una lista"
blockConfirm: "¿Quieres bloquear esta cuenta?"
unblockConfirm: "¿Quieres desbloquear esta cuenta?"
suspendConfirm: "¿Quieres suspender esta cuenta?"
unsuspendConfirm: "¿Quieres dejar de suspender esta cuenta?"
selectList: "Selecciona una lista"
editList: "Editar lista"
selectChannel: "Seleccionar canal"
selectAntenna: "Seleccionar antena"
@@ -163,55 +163,55 @@ editAntenna: "Editar antena"
createAntenna: "Crear una antena"
selectWidget: "Seleccionar widget"
editWidgets: "Editar widgets"
editWidgetsExit: "Terminar edición"
editWidgetsExit: "Hecho"
customEmojis: "Emojis personalizados"
emoji: "Emoji"
emojis: "Emoji"
emojis: "Emojis"
emojiName: "Nombre del emoji"
emojiUrl: "URL de la imágen del emoji"
addEmoji: "Agregar emoji"
settingGuide: "Configuración sugerida"
cacheRemoteFiles: "Mantener en cache los archivos remotos"
cacheRemoteFilesDescription: "Si desactiva esta configuración, Los archivos remotos se cargarán desde el link directo sin usar la caché. Con eso se puede ahorrar almacenamiento del servidor, pero eso aumentará el tráfico al no crear miniaturas."
emojiUrl: "URL del emoji"
addEmoji: "Añadir emoji"
settingGuide: "Configuración recomendada"
cacheRemoteFiles: "Mantener los archivos remotos en caché"
cacheRemoteFilesDescription: "Si desactivas esta configuración, los archivos remotos se cargarán directamente de los servidores remotos. Desactivar esto reducirá el uso de almacenamiento, pero incrementará el uso de tráfico, ya que no se generarán miniaturas."
youCanCleanRemoteFilesCache: "Puedes vaciar la caché pulsando en el botón 🗑️ en el administrador de archivos."
cacheRemoteSensitiveFiles: "Cachear archivos remotos sensibles"
cacheRemoteSensitiveFilesDescription: "Cuando esta opción está desactivada, los archivos remotos sensibles son cargador directamente de la instancia origen sin ser cacheados."
cacheRemoteSensitiveFiles: "Mantener los archivos remotos sensibles en caché"
cacheRemoteSensitiveFilesDescription: "Cuando esta opción está desactivada, los archivos remotos sensibles se cargarán directamente desde los servidores remotos."
flagAsBot: "Esta cuenta es un bot"
flagAsBotDescription: "En caso de que esta cuenta fuera usada por un programa, active esta opción. Al hacerlo, esta opción servirá para otros desarrolladores para evitar cadenas infinitas de reacciones, y ajustará los sistemas internos de Misskey para que trate a esta cuenta como un bot."
flagAsCat: "Esta cuenta es un gato"
flagAsCatDescription: "En caso de que declare que esta cuenta es de un gato, active esta opción."
flagShowTimelineReplies: "Mostrar respuestas a las notas en la biografía"
flagShowTimelineRepliesDescription: "Cuando se marca, la línea de tiempo muestra respuestas a otras notas además de las notas del usuario"
flagAsBotDescription: "Activa esta opción si la cuenta es utilizada por un programa. Si se activa, actuará como una etiqueta para otros desarrolladores para prevenir cadenas eternas de interacción con otros bots, y ajustará los sistemas internos de Misskey para tratar esta cuenta de manera acorde."
flagAsCat: "Marcar esta cuenta como gato"
flagAsCatDescription: "Activa esta opción para marcar esta cuenta como un gato."
flagShowTimelineReplies: "Mostrar respuestas en la línea de tiempo"
flagShowTimelineRepliesDescription: "Muestra respuestas de los usuarios a las notas de otros usuarios en la línea de tiempo al activar esta opción."
autoAcceptFollowed: "Aceptar automáticamente las solicitudes de seguimiento de los usuarios que sigues"
addAccount: "Agregar Cuenta"
addAccount: "Agregar cuenta"
reloadAccountsList: "Recargar lista de cuentas"
loginFailed: "Error al iniciar sesión."
showOnRemote: "Ver en una instancia remota"
continueOnRemote: "Ver en una instancia remota"
showOnRemote: "Ver en instancia remota"
continueOnRemote: "Continuar en una instancia remota"
chooseServerOnMisskeyHub: "Elegir un servidor en Misskey Hub"
specifyServerHost: "Especifica una instancia directamente"
inputHostName: "Introduzca el dominio"
inputHostName: "Introduce el dominio"
general: "General"
wallpaper: "Fondo de pantalla"
setWallpaper: "Establecer fondo de pantalla"
removeWallpaper: "Quitar fondo de pantalla"
searchWith: "Buscar: {q}"
youHaveNoLists: "No tienes listas"
followConfirm: "¿Desea seguir a {name}?"
youHaveNoLists: "No tienes ninguna lista"
followConfirm: "¿Quieres seguir a {name}?"
proxyAccount: "Cuenta proxy"
proxyAccountDescription: "Una cuenta proxy es una cuenta que actúa como un seguidor remoto de un usuario bajo ciertas condiciones. Por ejemplo, cuando un usuario añade un usuario remoto a una lista, si ningún usuario local sigue al usuario agregado a la lista, la instancia no puede obtener su actividad. Así que la cuenta proxy sigue al usuario añadido a la lista"
host: "Host"
proxyAccountDescription: "Una cuenta proxy es una cuenta que actúa como un seguidor remoto de un usuario bajo ciertas condiciones. Por ejemplo, cuando un usuario añade un usuario remoto a una lista, si ningún usuario local sigue al usuario agregado a la lista, la instancia no puede obtener su actividad, así que la cuenta proxy sigue al usuario añadido a la lista"
host: "Instancia"
selectSelf: "Elígete a ti mismo"
selectUser: "Elegir usuario"
recipient: "Recipiente"
recipient: "Receptor"
annotation: "Anotación"
federation: "Federación"
instances: "Instancia"
instances: "Instancias"
registeredAt: "Registrado en"
latestRequestReceivedAt: "Ultimo pedido recibido"
latestStatus: "Último status"
latestRequestReceivedAt: "Última petición recibida"
latestStatus: "Último estado"
storageUsage: "Almacenamiento usado"
charts: "Chat"
charts: "Métricas"
perHour: "por hora"
perDay: "por día"
stopActivityDelivery: "Dejar de enviar actividades"
@@ -226,40 +226,40 @@ metadata: "Metadatos"
withNFiles: "{n} archivos"
monitor: "Monitor"
jobQueue: "Cola de trabajos"
cpuAndMemory: "CPU y Memoria"
cpuAndMemory: "CPU y memoria"
network: "Red"
disk: "Disco"
instanceInfo: "información de la instancia"
instanceInfo: "Información de la instancia"
statistics: "Estadísticas"
clearQueue: "Limpiar cola"
clearQueueConfirmTitle: "¿Desea limpiar la cola?"
clearQueueConfirmTitle: "¿Quieres limpiar la cola?"
clearQueueConfirmText: "Las notas aún no entregadas no se federarán. Normalmente no se necesita ejecutar esta operación"
clearCachedFiles: "Limpiar caché"
clearCachedFilesConfirm: "¿Desea borrar todos los archivos remotos cacheados?"
clearCachedFilesConfirm: "¿Quieres borrar todos los archivos remotos en caché?"
blockedInstances: "Instancias bloqueadas"
blockedInstancesDescription: "Seleccione los hosts de las instancias que desea bloquear, separadas por una linea nueva. Las instancias bloqueadas no podrán comunicarse con esta instancia."
blockedInstancesDescription: "La lista de los dominios de las instancias que quieres bloquear, separadas por una linea nueva. Las instancias bloqueadas no podrán comunicarse con esta instancia."
silencedInstances: "Instancias silenciadas"
silencedInstancesDescription: "Listar los hostname de las instancias que quieres silenciar. Todas las cuentas de las instancias listadas serán tratadas como silenciadas, solo podrán hacer peticiones de seguimiento, y no podrán mencionar cuentas locales si no las siguen. Esto no afecta a las instancias bloqueadas."
mediaSilencedInstances: "Servidores silenciados (Multimedia)"
mediaSilencedInstancesDescription: "Listar las instancias que quieres silenciar. Todas las cuentas de las instancias listadas serán tratadas como silenciadas, solo podrán hacer peticiones de seguimiento, y no podrán mencionar cuentas locales si no las siguen. Esto no afecta a las instancias bloqueadas."
silencedInstancesDescription: "La lista de los dominios de las instancias que quieres silenciar. Todas las cuentas de las instancias listadas serán tratadas como silenciadas, solo podrán hacer peticiones de seguimiento, y no podrán mencionar cuentas locales si no las siguen. Esto no afecta a las instancias bloqueadas."
mediaSilencedInstances: "Servidores con multimedia silenciada"
mediaSilencedInstancesDescription: "La lista de los dominios de las instancias cuya multimedia quieres silenciar. Todas las cuentas que pertenezcan a estas instancias serán marcadas como sensibles, y no podrán usar sus emojis personalizados. Esto no afecta a las instancias bloqueadas"
federationAllowedHosts: "Servidores federados"
federationAllowedHostsDescription: "Establezca los nombres de los servidores que pueden federarse, separados por una nueva línea."
federationAllowedHostsDescription: "La lista de los dominios de las instancias cuya federación está permitida, separadas por saltos de línea."
muteAndBlock: "Silenciar y bloquear"
mutedUsers: "Usuarios silenciados"
blockedUsers: "Usuarios bloqueados"
noUsers: "No hay usuarios"
editProfile: "Editar perfil"
noteDeleteConfirm: "¿Desea borrar esta nota?"
pinLimitExceeded: "Ya no se pueden fijar más posts"
noteDeleteConfirm: "¿Quieres borrar esta nota?"
pinLimitExceeded: "Ya no se pueden fijar más notas"
done: "Terminado"
processing: "Procesando"
processing: "Procesando..."
preview: "Vista previa"
default: "Predeterminado"
defaultValueIs: "Por defecto: {value}"
noCustomEmojis: "No hay emojis personalizados"
noJobs: "No hay trabajos"
federating: "Federando"
blocked: "Bloqueando"
blocked: "Bloqueado"
suspended: "Suspendido"
all: "Todo"
subscribing: "Suscribiendo"
@@ -848,7 +848,7 @@ info: "Información"
userInfo: "Información del usuario"
unknown: "Desconocido"
onlineStatus: "En línea"
hideOnlineStatus: "mostrarse como desconectado"
hideOnlineStatus: "Mostrarse como desconectado"
hideOnlineStatusDescription: "Ocultar su estado en línea puede reducir la eficacia de algunas funciones, como la búsqueda"
online: "En línea"
active: "Activo"
@@ -1313,6 +1313,7 @@ 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"
draft: "Borrador"
confirmOnReact: "Confirmar la reacción"
reactAreYouSure: "¿Quieres añadir una reacción «{emoji}»?"
markAsSensitiveConfirm: "¿Desea establecer este medio multimedia(Imagen,vídeo...) como sensible?"
@@ -1365,6 +1366,11 @@ abort: "Abortar"
tip: "Consejos y trucos"
redisplayAllTips: "Volver a mostrar todos \"Trucos y consejos\""
hideAllTips: "Ocultar todos los \"Trucos y consejos\""
defaultImageCompressionLevel: "Nivel de compresión de la imagen por defecto"
defaultImageCompressionLevel_description: "Baja, conserva la calidad de la imagen pero la medida del archivo es más grande. <br>Alta, reduce la medida del archivo pero también la calidad de la imagen."
_order:
newest: "Los más recientes primero"
oldest: "Los más antiguos primero"
_chat:
noMessagesYet: "Aún no hay mensajes"
newMessage: "Mensajes nuevos"
@@ -1380,7 +1386,7 @@ _chat:
noInvitations: "No hay invitación."
history: "Historial"
noHistory: "No hay datos en el historial"
noRooms: "Sala no encontrada"
noRooms: "No te has unido a ninguna sala "
inviteUser: "Invitar usuarios"
sentInvitations: "Invitaciones enviadas"
join: "Unirse"
@@ -1452,6 +1458,7 @@ _settings:
contentsUpdateFrequency_description: "Cuanto mayor sea el valor, más se actualiza el contenido, pero disminuye el rendimiento y aumenta el tráfico y el consumo de memoria."
contentsUpdateFrequency_description2: "Cuando el modo en tiempo real está activado, el contenido se actualiza en tiempo real independientemente de esta configuración."
showUrlPreview: "Mostrar la vista previa de la URL"
showAvailableReactionsFirstInNote: "Mostrar las reacciones disponibles en la parte superior."
_chat:
showSenderName: "Mostrar el nombre del remitente"
sendOnEnter: "Intro para enviar"
@@ -1480,7 +1487,7 @@ _accountSettings:
makeNotesHiddenBeforeDescription: "Mientras esta función esté activada, las notas que hayan pasado la fecha y hora fijadas o hayan transcurrido el tiempo establecido sólo serán visibles para ti (se harán privadas). Si la desactivas, también se restablecerá el estado público de las notas."
mayNotEffectForFederatedNotes: "Notas federadas por un servidor remoto pueden no verse afectadas."
mayNotEffectSomeSituations: "Estas restricciones son simplificadas. Pueden no aplicarse en algunas situaciones, como cuando se visualiza en un servidor remoto o durante la moderación."
notesHavePassedSpecifiedPeriod: "Ten en cuenta que el tiempo especificado ha pasado"
notesHavePassedSpecifiedPeriod: "Notas publicadas durante el siguiente tiempo específico"
notesOlderThanSpecifiedDateAndTime: "Notas antes de la fecha y hora especificadas"
_abuseUserReport:
forward: "Reenviar"
@@ -1990,6 +1997,8 @@ _role:
uploadableFileTypes: "Tipos de archivos que se pueden cargar."
uploadableFileTypes_caption: "Especifica los tipos MIME/archivos permitidos. Se pueden especificar varios tipos MIME separándolos con una nueva línea, y se pueden especificar comodines con un asterisco (*). (por ejemplo, image/*)"
uploadableFileTypes_caption2: "Es posible que no se detecten algunos tipos de archivos. Para permitir estos archivos, añade {x} a la especificación."
noteDraftLimit: "Número de posibles borradores de notas del servidor"
watermarkAvailable: "Disponibilidad de la función de marca de agua"
_condition:
roleAssignedTo: "Asignado a roles manuales"
isLocal: "Usuario local"
@@ -2149,6 +2158,7 @@ _theme:
install: "Instalar tema"
manage: "Gestor de temas"
code: "Código del tema"
copyThemeCode: "Copiar el código del tema"
description: "Descripción"
installed: "{name} ha sido instalado"
installedThemes: "Temas instalados"
@@ -2259,7 +2269,7 @@ _2fa:
setupCompleted: "Configuración completada"
step4: "Ahora cuando inicie sesión, ingrese el mismo token"
securityKeyNotSupported: "Tu navegador no soporta claves de autenticación."
registerTOTPBeforeKey: "Please set up an authenticator app to register a security or pass key.\npor favor. configura una aplicación de autenticación para registrar una llave de seguridad."
registerTOTPBeforeKey: "Por favor. configura una aplicación de autenticación para registrar una llave de seguridad."
securityKeyInfo: "Se puede configurar el inicio de sesión usando una clave de seguridad de hardware que soporte FIDO2 o con un certificado de huella digital o con un PIN"
registerSecurityKey: "Registrar una llave de seguridad"
securityKeyName: "Ingresa un nombre para la clave"
@@ -2462,6 +2472,8 @@ _visibility:
disableFederation: "No federado"
disableFederationDescription: "No enviar a otras instancias"
_postForm:
quitInspiteOfThereAreUnuploadedFilesConfirm: "Hay archivos que no se han cargado, ¿deseas descartarlos y cerrar el formulario?"
uploaderTip: "El archivo aún no se ha cargado. Desde el menú Archivo, puedes cambiar el nombre, recortar imágenes, poner marcas de agua y comprimir o no el archivo. Los archivos se cargan automáticamente al publicar una nota."
replyPlaceholder: "Responder a esta nota"
quotePlaceholder: "Citar esta nota"
channelPlaceholder: "Publicar en el canal"
@@ -2627,6 +2639,7 @@ _notification:
flushNotification: "Limpiar notificaciones"
exportOfXCompleted: "La exportación de {x} ha sido completada."
login: "Alguien ha iniciado sesión"
createToken: "Token de acceso creado"
createTokenDescription: "Si no tienes ni idea, elimina el token de acceso a través de \"{text}\"."
_types:
all: "Todo"
@@ -2724,10 +2737,18 @@ _webhookSettings:
_abuseReport:
_notificationRecipient:
createRecipient: "Añadir destinatario a los informes"
modifyRecipient: "Editar un destinatario en el informe de moderación\n"
recipientType: "Tipo de notificación"
_recipientType:
mail: "Correo"
webhook: "Webhook"
_captions:
mail: "Enviar un correo electrónico a todos los moderadores cuando reciban un informe de moderación"
webhook: "Enviar una notificación al SystemWebhook cuando se reciba o se resuelva un informe de moderación"
keywords: "Palabras Clave"
notifiedUser: "Usuarios a notificar"
notifiedWebhook: "Webhook a utilizar"
deleteConfirm: "¿Estás seguro de que deseas borrar el destinatario del informe de moderación?"
_moderationLogTypes:
createRole: "Rol creado"
deleteRole: "Rol eliminado"
@@ -2752,9 +2773,12 @@ _moderationLogTypes:
resetPassword: "Resetear contraseña"
suspendRemoteInstance: "Instancia remota suspendida"
unsuspendRemoteInstance: "Suspensión de instancia remota retirada"
updateRemoteInstanceNote: "Nota de moderación de una instancia remota actualizada"
markSensitiveDriveFile: "Archivo marcado como sensible"
unmarkSensitiveDriveFile: "Archivo marcado como no sensible"
resolveAbuseReport: "Reporte resuelto"
forwardAbuseReport: "Informe reenviado"
updateAbuseReportNote: "Nota de moderación de un informe actualizada"
createInvitation: "Generar invitación"
createAd: "Anuncio creado"
deleteAd: "Anuncio eliminado"
@@ -2764,6 +2788,18 @@ _moderationLogTypes:
deleteAvatarDecoration: "Decoración de avatar eliminada"
unsetUserAvatar: "Quitar decoración de avatar de este usuario"
unsetUserBanner: "Quitar banner de este usuario"
createSystemWebhook: "Crear un SystemWebhook"
updateSystemWebhook: "Actualizar SystemWebhook "
deleteSystemWebhook: "Borrar SystemWebHook"
createAbuseReportNotificationRecipient: "Crear un destinatario para el informe de moderación"
updateAbuseReportNotificationRecipient: "Destinatario de los informes actualizados"
deleteAbuseReportNotificationRecipient: "Destinatario de los informes borrado"
deleteAccount: "Cuenta Borrada"
deletePage: "Página borrada"
deleteFlash: "Juego borrado"
deleteGalleryPost: "Publicación de la galería, eliminada"
deleteChatRoom: "Borrar sala del chat"
updateProxyAccountDescription: "Actualizar la descripción de la cuenta proxy"
_fileViewer:
title: "Detalles del archivo"
type: "Tipo de archivo"
@@ -2771,6 +2807,7 @@ _fileViewer:
url: "URL"
uploadedAt: "Subido el"
attachedNotes: "Notas adjuntas"
usage: "Utilizado"
thisPageCanBeSeenFromTheAuthor: "Esta página solo puede ser vista por el autor."
_externalResourceInstaller:
title: "Instalar desde sitio externo"
@@ -2818,17 +2855,46 @@ _dataSaver:
_avatar:
title: "Avatares animados"
description: "Desactiva la animación de los avatares. Las imágenes animadas pueden llegar a ser de mayor tamaño que las normales, por lo que al desactivarlas puedes reducir el consumo de datos."
_urlPreviewThumbnail:
title: "Ocultar las miniaturas de las vistas previas de URL"
description: "Las imágenes en miniatura de la vista previa de URL no se pueden cargar "
_disableUrlPreview:
title: "Desactivar la vista previa de las URL"
description: "Desactiva la función de previsualización de la URL. A diferencia de solo las imágenes en miniatura, esta función reduce la carga de la propia información vinculada."
_code:
title: "Resaltar código"
description: "Si se usa resaltado de código en MFM, etc., no se cargará hasta pulsar en ello. El resaltado de sintaxis requiere la descarga de archivos de definición para cada lenguaje de programación. Debido a esto, al deshabilitar la carga automática de estos archivos reducirás el consumo de datos."
_hemisphere:
N: "Hemisferio norte"
S: "Hemisferio sur"
caption: "Usado en algunos clientes para determinar la estación del año"
_reversi:
reversi: "Reversi"
gameSettings: "Configuración del juego"
chooseBoard: "Elegir tablero"
blackOrWhite: "Negras/Blancas"
blackIs: "{name} juega con negras"
rules: "Reglas"
thisGameIsStartedSoon: "El juego comenzará en breve"
waitingForOther: "Esperando el turno del adversario"
waitingForMe: "Esperando tu turno"
waitingBoth: "Prepárate"
ready: "Listo"
cancelReady: "No estoy listo"
opponentTurn: "Turno del oponente"
myTurn: "¡Tu turno!"
turnOf: "Le toca a {name}"
pastTurnOf: "Turno de {name}"
surrender: "Rendirse"
surrendered: "Te has rendido"
timeout: "Se acabó el tiempo"
drawn: "Empate"
won: "{name} ha ganado"
black: "Negras"
white: "Blancas"
total: "Total"
turnCount: "Turno {count}"
myGames: "Mis rondas"
allGames: "Todos los juegos"
ended: "Finalizado"
playing: "Jugando actualmente"
@@ -2844,7 +2910,7 @@ _reversi:
opponentHasSettingsChanged: "El oponente ha cambiado su configuración"
allowIrregularRules: "Reglas irregulares (completamente libre)"
disallowIrregularRules: "Sin reglas irregulares "
showBoardLabels: "Mostrar el número de línea y de columna en el tablero de juego."
showBoardLabels: "Mostrar el número de línea y la letra de columna en el tablero de juego."
useAvatarAsStone: "Usar los avatares de los usuarios como fichas\n"
_offlineScreen:
title: "Fuera de línea. No se puede conectar con el servidor"
@@ -2894,11 +2960,68 @@ _customEmojisManager:
sortOrder: "Ordenar"
registrationLogs: "Log de registros "
registrationLogsCaption: "Los registros se mostrarán al actualizar o borrar Emojis. Desaparecerán después de actualizarlos o eliminarlos, pasar a una nueva página o recargar."
alertEmojisRegisterFailedDescription: "No se ha podido actualizar o borrar el emoji. Por favor comprueba el log del registro para más detalles."
_logs:
showSuccessLogSwitch: "Mostrar registro de éxito"
failureLogNothing: "No hay log de fallos"
logNothing: "No hay logs"
_remote:
selectionRowDetail: "Detalle de la línea seleccionada"
importSelectionRows: "Importar las líneas seleccionadas"
importSelectionRangesRows: "Importar las filas seleccionadas"
importEmojisButton: "Importar los Emojis marcados"
confirmImportEmojisTitle: "Importar Emojis"
confirmImportEmojisDescription: "Importar {count} Emoji(s) recibidos del servidor remoto. Por favor, presta mucha atención a la licencia del Emoji. ¿Estás seguro de continuar?"
_local:
tabTitleList: "Lista de emojis registrados"
tabTitleRegister: "Registro de Emojis"
_list:
emojisNothing: "No hay Emojis registrados"
markAsDeleteTargetRows: "Marcar las filas seleccionadas como objetivo a eliminar"
markAsDeleteTargetRanges: "Selección de filas para su eliminación"
alertUpdateEmojisNothingDescription: "No hay Emojis actualizados"
alertDeleteEmojisNothingDescription: "No hay Emojis para borrar"
confirmMovePage: "¿Quieres cambiar de página?"
confirmChangeView: "¿De verdad quieres cambiar la vista?"
confirmUpdateEmojisDescription: "Actualizar {count} Emoji(s). ¿Deseas continuar?"
confirmDeleteEmojisDescription: "Borrar {count} Emoji(s) seleccionados. ¿Deseas continuar?"
confirmResetDescription: "Se restablecerán todos los cambios hechos hasta ahora."
confirmMovePageDesciption: "Se han realizado cambios en los Emojis de esta página.\nSi abandonas la página sin guardar, se descartarán todos los cambios realizados en esta página."
dialogSelectRoleTitle: "Buscar Emojis por rol"
_register:
uploadSettingTitle: "Ajustes de carga"
uploadSettingDescription: "En esta pantalla, puedes configurar el comportamiento al cargar Emojis."
directoryToCategoryLabel: "Introduce el nombre del directorio en el campo \"categoría\""
directoryToCategoryCaption: "Cuando arrastres y sueltes un directorio, introduce el nombre del directorio en el campo \"categoría\"."
confirmRegisterEmojisDescription: "Registra los Emojis de la lista como nuevos Emojis personalizados. ¿Estás seguro de continuar? (Para evitar sobrecargas, sólo {count} Emoji(s) en una sola operación)"
confirmClearEmojisDescription: "Descartar las ediciones y borrar los Emojis de la lista. ¿Estás seguro de continuar?"
confirmUploadEmojisDescription: "Cargar los {count} archivo(s) arrastrado(s) y soltado(s) en la unidad. ¿Estás seguro de continuar?"
_embedCodeGen:
title: "Personalizar el código de incrustación"
header: "Mostrar encabezados"
autoload: "Cargar más automáticamente (no recomendado)"
maxHeight: "Altura máxima"
maxHeightDescription: "0 desactiva el ajuste del valor máximo. Para evitar que el widget siga creciendo verticalmente, especifica algún valor."
maxHeightWarn: "El límite de altura máxima está desactivado (0). Si esto no estaba previsto, establece la altura máxima en algún valor."
previewIsNotActual: "La visualización difiere de la incrustación real porque excede el rango mostrado en la pantalla de vista previa."
rounded: "Bordes Redondeados"
border: "Añadir un borde al marco exterior"
applyToPreview: "Aplicar a la vista previa"
generateCode: "Crear el código para incrustar"
codeGenerated: "El código ha sido generado"
codeGeneratedDescription: "Pegue el código generado en su sitio web para incrustar el contenido."
_selfXssPrevention:
warning: "Advertencia"
title: "\"Pegar algo en esta pantalla\" es un timo."
description1: "Si pegas algo aquí, un usuario malintencionado podría secuestrar tu cuenta o robar tu información personal."
description2: "Si no entiendes que estás pegando exactamente, %cdetente ahora mismo y cierra esta ventana"
description3: "Para más información visita esto {link}"
_followRequest:
recieved: "Petición de seguimiento recibida"
sent: "Petición de seguimiento enviada"
_remoteLookupErrors:
_federationNotAllowed:
title: "Incapaz de comunicarse con este servidor."
description: "Es posible que se haya desactivado la comunicación con este servidor o que haya sido bloqueado.\nPonte en contacto con el administrador del servidor.."
_uriInvalid:
title: "La URI es inválida"
@@ -2927,9 +3050,148 @@ _captcha:
text: "Se ha producido un error inesperado."
_bootErrors:
title: "Fallo al cargar"
serverError: "Si el problema persiste después de esperar un momento y volver a cargar, póngase en contacto con el administrador del servidor con el siguiente ID de error."
solution: "Lo siguiente puede resolver el problema."
solution1: "Actualiza tu navegador web y el sistema operativo a la última versión"
solution2: "Desactiva el AdBlocker"
solution3: "Borra la memoria caché del navegador web "
solution4: "(Navegador Tor) configura dom.webaudio.enabled a true"
otherOption: "Otras opciones"
otherOption1: "Borra la configuración y la memoria caché del cliente"
otherOption2: "Iniciar el cliente simple"
otherOption3: "Iniciar la herramienta de reparación"
_search:
searchScopeAll: "Todo"
searchScopeLocal: "Local"
searchScopeServer: "Especifica el servidor (Instancia)"
searchScopeUser: "Especificar usuario"
pleaseEnterServerHost: "Introduce la dirección del servidor/Instancia"
pleaseSelectUser: "Selecciona un usuario, por favor"
serverHostPlaceholder: "Ejemplo: misskey.example.com"
_serverSetupWizard:
installCompleted: "¡La instalación de Misskey se ha completado!"
firstCreateAccount: "Para comenzar, crea una cuenta de administrador"
accountCreated: "¡La cuenta de administrador se ha creado! "
serverSetting: "Configuración del servidor"
youCanEasilyConfigureOptimalServerSettingsWithThisWizard: "Este asistente te facilita una configuración óptima del servidor."
settingsYouMakeHereCanBeChangedLater: "Los ajustes que han sido cambiados a través de este asistente pueden ser modificados más tarde."
howWillYouUseMisskey: "¿Cómo vas a usar Misskey?"
_use:
single: "Servidor para un único usuario."
single_description: "Utilízalo como tu propio servidor dedicado."
single_youCanCreateMultipleAccounts: "Se pueden crear múltiples cuentas según sea necesario, incluso cuando se opera como servidor unipersonal."
group: "Servidor de grupo"
group_description: "Invita otros usuarios de confianza y úsalo con más de una persona.\n"
open: "Servidor público"
open_description: "Permite a cualquiera registrarse"
openServerAdvice: "Aceptar un número no determinado de usuarios comporta algunos riesgos. Se recomienda operar con un sistema de moderación fiable para hacer frente a los problemas."
openServerAntiSpamAdvice: "Para evitar que su servidor se convierta en un trampolín para el spam, también debe prestar mucha atención a la seguridad habilitando funciones anti-bot como reCAPTCHA."
howManyUsersDoYouExpect: "¿Cuántas personas esperas?"
_scale:
small: "Menos de 100 (escala pequeña)"
medium: "Más de 100 y menos de 1000 (escala media)\n"
large: "Más de 1000(escala grande)"
largeScaleServerAdvice: "Los grandes servidores pueden requerir conocimientos avanzados de infraestructura, como equilibrio de carga y replicación de bases de datos."
doYouConnectToFediverse: "¿Quieres conectarte al Fediverso?"
doYouConnectToFediverse_description1: "Cuando se conecta a una red de servidores distribuidos (Fediverso), el contenido puede intercambiarse con otros servidores."
doYouConnectToFediverse_description2: "Conectarse con el Fediverso también se conoce como \"federación\"."
youCanConfigureMoreFederationSettingsLater: "Los ajustes avanzados, como la especificación de servidores federados, pueden configurarse más adelante."
adminInfo: "Información del administrador"
adminInfo_description: "Establece la información del administrador para recibir consultas."
adminInfo_mustBeFilled: "Esta información debe ser introducida en el caso de registros abiertos o la federación esté activada."
followingSettingsAreRecommended: "Se recomienda los siguientes ajustes"
applyTheseSettings: "Aplicar estos ajustes"
skipSettings: "Omitir configuración"
settingsCompleted: "¡Configuración inicial del servidor completada!"
settingsCompleted_description: "Gracias por tu tiempo. Ahora que está todo listo puedes empezar a utilizar el servidor inmediatamente."
settingsCompleted_description2: "La configuración avanzada del servidor pueden realizarse a través del \"Panel de control\"."
donationRequest: "Por favor Dona"
_donationRequest:
text1: "Misskey es un software libre desarrollado por voluntarios."
text2: "Agradeceríamos su apoyo para que podamos seguir desarrollando este software en el futuro."
text3: "También hay beneficios especiales para los donantes"
_uploader:
editImage: "Editar la imagen"
compressedToX: "Comprimir a {x}"
savedXPercent: "Guardando {x}%"
abortConfirm: "Algunos archivos no se han cargado, ¿deseas cancelar?"
doneConfirm: "Algunos archivos no se han cargado, ¿deseas continuar de todos modos?"
maxFileSizeIsX: "El tamaño máximo de archivo que se puede cargar es de {x}"
allowedTypes: "Tipos de archivos que se pueden cargar."
tip: "El archivo aún no se ha cargado, por lo que este cuadro de diálogo te permite confirmar, renombrar, comprimir y recortar el archivo antes de cargarlo. Cuando esté listo, puedes iniciar la carga pulsando el botón \"Cargar\"."
_clientPerformanceIssueTip:
title: "Si crees que el consumo de batería es demasiado alto"
makeSureDisabledAdBlocker: "Por favor, desactive el bloqueador de publicidad."
makeSureDisabledAdBlocker_description: "Los bloqueadores de anuncios pueden afectar al rendimiento. Asegúrate de que no están activados en tu sistema o en las funciones/extensiones de tu navegador."
makeSureDisabledCustomCss: "Desactiva el CSS personalizado"
makeSureDisabledCustomCss_description: "Anular estilos puede afectar al rendimiento. Asegúrate de que el CSS personalizado o las extensiones que sobrescriben estilos no están activados."
makeSureDisabledAddons: "Desactiva las extensiones "
makeSureDisabledAddons_description: "Algunas extensiones pueden interferir con el comportamiento del cliente y afectar al rendimiento. Por favor, deshabilita las extensiones de tu navegador y comprueba si esto mejora la situación."
_clip:
tip: "Clip es una función que permite organizar varias notas."
_userLists:
tip: "Las listas pueden contener cualquier usuario que especifiques al crearlas, la lista creada puede mostrarse entonces como una línea de tiempo mostrando solo los usuarios especificados."
watermark: "Marca de Agua"
defaultPreset: "Por defecto"
_watermarkEditor:
tip: "Se puede añadir a la imagen una marca de agua, como información crediticia."
quitWithoutSaveConfirm: "¿Descartar cambios no guardados?"
driveFileTypeWarn: "Este archivo es incompatible"
driveFileTypeWarnDescription: "Elegir una imagen"
title: "Editar la marca de agua"
cover: "Cubrir todo"
repeat: "Repetir"
opacity: "Opacidad"
scale: "Tamaño"
text: "Texto"
position: "Posición"
type: "Tipo"
image: "Imágenes"
advanced: "Avanzado"
stripe: "Rayas"
stripeWidth: "Anchura de línea"
stripeFrequency: "Número de líneas."
angle: "Ángulo"
polkadot: "Lunares"
checker: "verificador"
polkadotMainDotOpacity: "Opacidad del círculo principal"
polkadotMainDotRadius: "Tamaño del círculo principal."
polkadotSubDotOpacity: "Opacidad del círculo secundario"
polkadotSubDotRadius: "Tamaño del círculo secundario."
polkadotSubDotDivisions: "Número de subpuntos."
_imageEffector:
title: "Efecto"
addEffect: "Añadir Efecto"
discardChangesConfirm: "¿Ignorar cambios y salir?"
_fxs:
chromaticAberration: "Aberración Cromática"
glitch: "Glitch"
mirror: "Espejo"
invert: "Invertir colores"
grayscale: "Blanco y negro"
colorAdjust: "Corrección de Color"
colorClamp: "Compresión cromática"
colorClampAdvanced: "Compresión cromática avanzada"
distort: "Distorsión"
threshold: "umbral"
zoomLines: "Saturación de Líneas"
stripe: "Rayas"
polkadot: "Lunares"
checker: "Corrector"
blockNoise: "Bloquear Ruido"
tearing: "Rasgado de Imagen (Tearing)"
drafts: "Borrador"
_drafts:
select: "Seleccionar borradores"
cannotCreateDraftAnymore: "Se ha superado el número de borradores que se pueden crear."
cannotCreateDraft: "No se pueden crear borradores con este contenido."
delete: "Eliminar borrador"
deleteAreYouSure: "¿Quieres borrar el borrador?"
noDrafts: "No hay borradores disponibles."
replyTo: "Responder a {user}"
quoteOf: "Citar las notas de {user}"
postTo: "Destino a {channel}"
saveToDraft: "Guardar como borrador"
restoreFromDraft: "Restaurar desde los borradores"
restore: "Restaurar"
listDrafts: "Listar los borradores"

View File

@@ -2360,3 +2360,13 @@ _search:
searchScopeAll: "Tous"
searchScopeLocal: "Local"
searchScopeUser: "Spécifier l'utilisateur·rice"
_watermarkEditor:
driveFileTypeWarn: "Ce fichier n'est pas pris en charge"
opacity: "Transparence"
scale: "Taille"
text: "Texte"
position: "Position"
type: "Type"
image: "Images"
advanced: "Avancé"
angle: "Angle"

View File

@@ -5,9 +5,13 @@ introMisskey: "Selamat datang! Misskey adalah perangkat mikroblog tercatu bersif
poweredByMisskeyDescription: "{name} adalah sebuah layanan (instance) yang menggunakan platform sumber terbuka <b>Misskey</b>."
monthAndDay: "{day} {month}"
search: "Penelusuran"
reset: "Reset"
notifications: "Notifikasi"
username: "Nama Pengguna"
password: "Kata sandi"
initialPasswordForSetup: "Kata sandi untuk memulai konfigurasi awal"
initialPasswordIsIncorrect: "Kata sandi untuk memulai konfigurasi awal salah."
initialPasswordForSetupDescription: "Jika Anda menginstal Misskey sendiri, gunakan kata sandi yang Anda masukkan di berkas konfigurasi.\nJika Anda menggunakan layanan hosting Misskey, gunakan kata sandi yang diberikan.\nJika Anda belum mengatur kata sandi, biarkan kosong dan lanjutkan."
forgotPassword: "Lupa Kata Sandi"
fetchingAsApObject: "Mengambil data dari Fediverse..."
ok: "OK"
@@ -45,6 +49,7 @@ pin: "Sematkan ke profil"
unpin: "Lepas sematan dari profil"
copyContent: "Salin konten"
copyLink: "Salin tautan"
copyRemoteLink: "Salin tautan jarak jauh"
copyLinkRenote: "Salin tautan renote"
delete: "Hapus"
deleteAndEdit: "Hapus dan sunting"
@@ -212,8 +217,10 @@ perDay: "per Hari"
stopActivityDelivery: "Berhenti mengirim aktivitas"
blockThisInstance: "Blokir instansi ini"
silenceThisInstance: "Senyapkan instansi ini"
mediaSilenceThisInstance: "Server media senyap"
operations: "Tindakan"
software: "Perangkat lunak"
softwareName: "Nama Perangkat Lunak"
version: "Versi"
metadata: "Metadata"
withNFiles: "{n} berkas"
@@ -1040,7 +1047,7 @@ disableFederationConfirmWarn: "Mematikan federasi tidak membuat kiriman menjadi
disableFederationOk: "Matikan federasi"
invitationRequiredToRegister: "Instansi ini dalam mode undangan-saja. Kamu harus memasukkan kode undangan yang valid untuk mendaftar."
emailNotSupported: "Instansi ini tidak mendukung mengirim surel"
postToTheChannel: "Catat ke kanal"
postToTheChannel: "Buat Catatan ke Kanal"
cannotBeChangedLater: "Hal ini nantinya tidak dapat diubah lagi."
reactionAcceptance: "Penerimaan reaksi"
likeOnly: "Hanya suka"
@@ -2400,7 +2407,7 @@ _deck:
main: "Utama"
widgets: "Widget"
notifications: "Notifikasi"
tl: "Lini masa"
tl: "Beranda"
antenna: "Antena"
list: "Daftar"
channel: "Kanal"
@@ -2608,3 +2615,13 @@ _search:
searchScopeAll: "Semua"
searchScopeLocal: "Lokal"
searchScopeUser: "Pengguna spesifik"
_watermarkEditor:
driveFileTypeWarn: "Berkas ini tidak didukung"
opacity: "Opasitas"
scale: "Ukuran"
text: "Teks"
position: "Posisi"
type: "Tipe"
image: "Gambar"
advanced: "Tingkat lanjut"
angle: "Sudut"

122
locales/index.d.ts vendored
View File

@@ -5231,7 +5231,7 @@ export interface Locale extends ILocale {
*/
"prohibitedWordsForNameOfUser": string;
/**
* このリストに含まれる文字列がユーザーの名前に含まれる場合、ユーザーの名前の変更を拒否します。モデレーター権限を持つユーザーはこの制限の影響を受けません。
* このリストに含まれる文字列がユーザーの名前に含まれる場合、ユーザーの名前の変更を拒否します。モデレーター権限を持つユーザーはこの制限の影響を受けません。ユーザー名(username)に対しても全て小文字に置き換えて検査します。
*/
"prohibitedWordsForNameOfUserDescription": string;
/**
@@ -5270,6 +5270,10 @@ export interface Locale extends ILocale {
* このサーバーは連合が無効化されています。他のサーバーのユーザーとやり取りすることはできません。
*/
"federationDisabled": string;
/**
* 下書き
*/
"draft": string;
/**
* リアクションする際に確認する
*/
@@ -5489,6 +5493,16 @@ export interface Locale extends ILocale {
* 低くすると画質を保てますが、ファイルサイズは増加します。<br>高くするとファイルサイズを減らせますが、画質は低下します。
*/
"defaultImageCompressionLevel_description": string;
"_order": {
/**
* 新しい順
*/
"newest": string;
/**
* 古い順
*/
"oldest": string;
};
"_chat": {
/**
* まだメッセージはありません
@@ -7777,6 +7791,14 @@ export interface Locale extends ILocale {
* ファイルによっては種別を判定できないことがあります。そのようなファイルを許可する場合は {x} を指定に追加してください。
*/
"uploadableFileTypes_caption2": ParameterizedString<"x">;
/**
* サーバーサイドのノートの下書きの作成可能数
*/
"noteDraftLimit": string;
/**
* ウォーターマーク機能の使用可否
*/
"watermarkAvailable": string;
};
"_condition": {
/**
@@ -8366,6 +8388,10 @@ export interface Locale extends ILocale {
* テーマコード
*/
"code": string;
/**
* テーマコードをコピー
*/
"copyThemeCode": string;
/**
* 説明
*/
@@ -9584,6 +9610,14 @@ export interface Locale extends ILocale {
"disableFederationDescription": string;
};
"_postForm": {
/**
* アップロードされていないファイルがありますが、破棄してフォームを閉じますか?
*/
"quitInspiteOfThereAreUnuploadedFilesConfirm": string;
/**
* ファイルはまだアップロードされていません。ファイルのメニューから、リネームや画像のクロップ、ウォーターマークの付与、圧縮の有無などを設定できます。ファイルはノート投稿時に自動でアップロードされます。
*/
"uploaderTip": string;
/**
* このノートに返信...
*/
@@ -10860,6 +10894,10 @@ export interface Locale extends ILocale {
* 添付されているノート
*/
"attachedNotes": string;
/**
* 利用
*/
"usage": string;
/**
* このページは、このファイルをアップロードしたユーザーしか閲覧できません。
*/
@@ -11961,6 +11999,10 @@ export interface Locale extends ILocale {
};
};
"_uploader": {
/**
* 画像の編集
*/
"editImage": string;
/**
* {x}に圧縮
*/
@@ -12049,6 +12091,14 @@ export interface Locale extends ILocale {
* 保存せずに終了しますか?
*/
"quitWithoutSaveConfirm": string;
/**
* このファイルは対応していません
*/
"driveFileTypeWarn": string;
/**
* 画像ファイルを選択してください
*/
"driveFileTypeWarnDescription": string;
/**
* ウォーターマークの編集
*/
@@ -12168,6 +12218,10 @@ export interface Locale extends ILocale {
* 白黒
*/
"grayscale": string;
/**
* 色調補正
*/
"colorAdjust": string;
/**
* 色の圧縮
*/
@@ -12200,8 +12254,74 @@ export interface Locale extends ILocale {
* チェッカー
*/
"checker": string;
/**
* ブロックノイズ
*/
"blockNoise": string;
/**
* ティアリング
*/
"tearing": string;
};
};
/**
* 下書き
*/
"drafts": string;
"_drafts": {
/**
* 下書きを選択
*/
"select": string;
/**
* 下書きの作成可能数を超えています。
*/
"cannotCreateDraftAnymore": string;
/**
* この内容では下書きを作成できません。
*/
"cannotCreateDraft": string;
/**
* 下書きを削除
*/
"delete": string;
/**
* 下書きを削除しますか?
*/
"deleteAreYouSure": string;
/**
* 下書きはありません
*/
"noDrafts": string;
/**
* {user}への返信
*/
"replyTo": ParameterizedString<"user">;
/**
* {user}のノートへの引用
*/
"quoteOf": ParameterizedString<"user">;
/**
* {channel}への投稿
*/
"postTo": ParameterizedString<"channel">;
/**
* 下書きへ保存
*/
"saveToDraft": string;
/**
* 下書きから復元
*/
"restoreFromDraft": string;
/**
* 復元
*/
"restore": string;
/**
* 下書き一覧
*/
"listDrafts": string;
};
}
declare const locales: {
[lang: string]: Locale;

View File

@@ -327,6 +327,7 @@ dark: "Scuro"
lightThemes: "Tema Chiaro"
darkThemes: "Tema Scuro"
syncDeviceDarkMode: "Sincronizza il tema scuro con le impostazioni del dispositivo"
switchDarkModeManuallyWhenSyncEnabledConfirm: "({x}) è attiva. Vuoi disattivare la sincronizzazione e passare alla modalità manuale?"
drive: "Drive"
fileName: "Nome dell'allegato"
selectFile: "Scelta allegato"
@@ -581,7 +582,7 @@ sounds: "Impostazioni suoni"
sound: "Suono"
notificationSoundSettings: "Preferenze di notifica"
listen: "Ascolta"
none: "Nessuno"
none: "Nessuna"
showInPage: "Visualizza in pagina"
popout: "Finestra pop-out"
volume: "Volume"
@@ -1329,6 +1330,7 @@ restore: "Ripristina"
syncBetweenDevices: "Sincronizzazione tra i dispositivi"
preferenceSyncConflictTitle: "Sul server esiste già il valore impostato"
preferenceSyncConflictText: "Le impostazione sincronizzata salverà il valore sul server. Però, bada che esiste già un valore sul server. Quale vorresti sovrascrivere?"
preferenceSyncConflictChoiceMerge: "Integra"
preferenceSyncConflictChoiceServer: "Valore del server"
preferenceSyncConflictChoiceDevice: "Valore del dispositivo"
preferenceSyncConflictChoiceCancel: "Annulla la sincronizzazione"
@@ -1340,7 +1342,7 @@ information: "Informazioni"
chat: "Chat"
migrateOldSettings: "Migrare le vecchie impostazioni"
migrateOldSettings_description: "Di solito, viene fatto automaticamente. Se per qualche motivo non fossero migrate con successo, è possibile avviare il processo di migrazione manualmente, sovrascrivendo le configurazioni attuali."
compress: "Comprimi"
compress: "Compressione"
right: "Destra"
bottom: "Sotto"
top: "Sopra"
@@ -1349,6 +1351,7 @@ settingsMigrating: "Migrazione delle impostazioni. Attendere prego ... (Puoi anc
readonly: "Sola lettura"
goToDeck: "Torna al Deck"
federationJobs: "Coda di federazione"
driveAboutTip: "Il Drive mostra l'elenco di file caricati in passato. Puoi organizzarli in cartelle, riusarli allegandoli ad altre note, o caricarli in anticipo e poi pubblicarli in un secondo momento. Tieni presente che se elimini un file, non sarà più visibile in nessuno degli oggetti a cui è allegato (Note, pagine, avatar, banner, ecc.)"
scrollToClose: "Scorri per chiudere"
advice: "Consiglio"
realtimeMode: "Modalità in tempo reale"
@@ -1362,6 +1365,8 @@ abort: "Annulla"
tip: "Suggerimento"
redisplayAllTips: "Mostra tutti i suggerimenti"
hideAllTips: "Nascondi tutti i suggerimenti"
defaultImageCompressionLevel: "Livello predefinito di compressione immagini"
defaultImageCompressionLevel_description: "La compressione diminuisce la qualità dell'immagine, poca compressione mantiene alta qualità delle immagini. Aumentandola, si riducono le dimensioni del file, a discapito della qualità dell'immagine."
_chat:
noMessagesYet: "Ancora nessun messaggio"
newMessage: "Nuovo messaggio"
@@ -1449,6 +1454,7 @@ _settings:
contentsUpdateFrequency_description: "Se l'impostazione è alta, verranno aggiornati più frequentemente, consumando più dati e più batteria."
contentsUpdateFrequency_description2: "Quando la modalità è in tempo reale, arriveranno a prescindere."
showUrlPreview: "Mostra anteprima dell'URL"
showAvailableReactionsFirstInNote: "Mostra le reazioni disponibili in alto"
_chat:
showSenderName: "Mostra il nome del mittente"
sendOnEnter: "Invio spedisce"
@@ -2459,6 +2465,8 @@ _visibility:
disableFederation: "Senza federazione"
disableFederationDescription: "Non spedire attività alle altre istanze remote"
_postForm:
quitInspiteOfThereAreUnuploadedFilesConfirm: "Alcuni file non sono stati caricati. Vuoi annullare l'operazione?"
uploaderTip: "Il file non è ancora stato caricato. Nel menu file (tre puntini), puoi ritagliare l'immagine, mettere la filigrana, decidere la presenza o l'assenza di compressione... Il file verrà caricato automaticamente quando pubblichi la Nota."
replyPlaceholder: "Rispondi a questa nota..."
quotePlaceholder: "Cita questa nota..."
channelPlaceholder: "Pubblica sul canale..."
@@ -2902,6 +2910,8 @@ _offlineScreen:
_urlPreviewSetting:
title: "Impostazioni per l'anteprima delle URL"
enable: "Attiva l'anteprima delle URL"
allowRedirect: "Segui i reindirizzamenti per visualizzare le anteprime"
allowRedirectDescription: "Se la URL inserita contiene un reindirizzamento, decidi di seguire il reindirizzamento fino alla destinazione, visualizzandone l'anteprima. Disabilitando questa opzione si risparmiano risorse del server, ma il contenuto effettivo dal reindirizzamento, non verrà visualizzato."
timeout: "Timeout dell'anteprima in millisecondi"
timeoutDescription: "Impegna al massimo il tempo indicato, altrimenti ignora l'anteprima"
maximumContentLength: "Grandezza del contenuto (Content-Length in byte)"
@@ -3112,3 +3122,52 @@ _clip:
tip: "Le clip sono una funzionalità che consente di raggruppare le Note."
_userLists:
tip: "Puoi creare un elenco di Note create da qualsiasi profilo. L'elenco è visualizzato come una sequenza temporale."
watermark: "Filigrana"
defaultPreset: "Impostazioni predefinite"
_watermarkEditor:
tip: "Puoi aggiungere una filigrana, ad esempio con i crediti alle tue immagini."
quitWithoutSaveConfirm: "Uscire senza salvare?"
driveFileTypeWarn: "Formato file non supportato"
driveFileTypeWarnDescription: "Per favore seleziona un file immagine"
title: "Modifica la filigrana"
cover: "Coprire tutto"
repeat: "Disposizione"
opacity: "Opacità"
scale: "Dimensioni"
text: "Testo"
position: "Posizione"
type: "Tipo"
image: "Immagini"
advanced: "Avanzato"
stripe: "Strisce"
stripeWidth: "Larghezza della linea"
stripeFrequency: "Il numero di linee"
angle: "Angolo"
polkadot: "A pallini"
checker: "revisore"
polkadotMainDotOpacity: "Opacità del punto principale"
polkadotMainDotRadius: "Dimensione del punto principale"
polkadotSubDotOpacity: "Opacità del punto secondario"
polkadotSubDotRadius: "Dimensione del punto secondario"
polkadotSubDotDivisions: "Quantità di punti secondari"
_imageEffector:
title: "Effetto"
addEffect: "Aggiungi effetto"
discardChangesConfirm: "Scarta le modifiche ed esci?"
_fxs:
chromaticAberration: "Aberrazione cromatica"
glitch: "Glitch"
mirror: "Specchio"
invert: "Inversione colore"
grayscale: "Bianco e nero"
colorAdjust: "Correzione Colore"
colorClamp: "Compressione del colore"
colorClampAdvanced: "Compressione del colore (avanzata)"
distort: "Distorsione"
threshold: "Soglia"
zoomLines: "Linea di saturazione"
stripe: "Strisce"
polkadot: "A pallini"
checker: "revisore"
_drafts:
restore: "Ripristina"

View File

@@ -1303,7 +1303,7 @@ messageToFollower: "フォロワーへのメッセージ"
target: "対象"
testCaptchaWarning: "CAPTCHAのテストを目的とした機能です。<strong>本番環境で使用しないでください。</strong>"
prohibitedWordsForNameOfUser: "禁止ワード(ユーザーの名前)"
prohibitedWordsForNameOfUserDescription: "このリストに含まれる文字列がユーザーの名前に含まれる場合、ユーザーの名前の変更を拒否します。モデレーター権限を持つユーザーはこの制限の影響を受けません。"
prohibitedWordsForNameOfUserDescription: "このリストに含まれる文字列がユーザーの名前に含まれる場合、ユーザーの名前の変更を拒否します。モデレーター権限を持つユーザーはこの制限の影響を受けません。ユーザー名(username)に対しても全て小文字に置き換えて検査します。"
yourNameContainsProhibitedWords: "変更しようとした名前に禁止された文字列が含まれています"
yourNameContainsProhibitedWordsDescription: "名前に禁止されている文字列が含まれています。この名前を使用したい場合は、サーバー管理者にお問い合わせください。"
thisContentsAreMarkedAsSigninRequiredByAuthor: "投稿者により、表示にはログインが必要と設定されています"
@@ -1313,6 +1313,7 @@ availableRoles: "利用可能なロール"
acknowledgeNotesAndEnable: "注意事項を理解した上でオンにします。"
federationSpecified: "このサーバーはホワイトリスト連合で運用されています。管理者が指定したサーバー以外とやり取りすることはできません。"
federationDisabled: "このサーバーは連合が無効化されています。他のサーバーのユーザーとやり取りすることはできません。"
draft: "下書き"
confirmOnReact: "リアクションする際に確認する"
reactAreYouSure: "\" {emoji} \" をリアクションしますか?"
markAsSensitiveConfirm: "このメディアをセンシティブとして設定しますか?"
@@ -1368,6 +1369,10 @@ hideAllTips: "全ての「ヒントとコツ」を非表示"
defaultImageCompressionLevel: "デフォルトの画像圧縮度"
defaultImageCompressionLevel_description: "低くすると画質を保てますが、ファイルサイズは増加します。<br>高くするとファイルサイズを減らせますが、画質は低下します。"
_order:
newest: "新しい順"
oldest: "古い順"
_chat:
noMessagesYet: "まだメッセージはありません"
newMessage: "新しいメッセージ"
@@ -2013,6 +2018,8 @@ _role:
uploadableFileTypes: "アップロード可能なファイル種別"
uploadableFileTypes_caption: "MIMEタイプを指定します。改行で区切って複数指定できるほか、アスタリスク(*)でワイルドカード指定できます。(例: image/*)"
uploadableFileTypes_caption2: "ファイルによっては種別を判定できないことがあります。そのようなファイルを許可する場合は {x} を指定に追加してください。"
noteDraftLimit: "サーバーサイドのノートの下書きの作成可能数"
watermarkAvailable: "ウォーターマーク機能の使用可否"
_condition:
roleAssignedTo: "マニュアルロールにアサイン済み"
isLocal: "ローカルユーザー"
@@ -2193,6 +2200,7 @@ _theme:
install: "テーマのインストール"
manage: "テーマの管理"
code: "テーマコード"
copyThemeCode: "テーマコードをコピー"
description: "説明"
installed: "{name}をインストールしました"
installedThemes: "インストールされたテーマ"
@@ -2522,6 +2530,8 @@ _visibility:
disableFederationDescription: "他サーバーへの配信を行いません"
_postForm:
quitInspiteOfThereAreUnuploadedFilesConfirm: "アップロードされていないファイルがありますが、破棄してフォームを閉じますか?"
uploaderTip: "ファイルはまだアップロードされていません。ファイルのメニューから、リネームや画像のクロップ、ウォーターマークの付与、圧縮の有無などを設定できます。ファイルはノート投稿時に自動でアップロードされます。"
replyPlaceholder: "このノートに返信..."
quotePlaceholder: "このノートを引用..."
channelPlaceholder: "チャンネルに投稿..."
@@ -2876,6 +2886,7 @@ _fileViewer:
url: "URL"
uploadedAt: "追加日"
attachedNotes: "添付されているノート"
usage: "利用"
thisPageCanBeSeenFromTheAuthor: "このページは、このファイルをアップロードしたユーザーしか閲覧できません。"
_externalResourceInstaller:
@@ -3199,6 +3210,7 @@ _serverSetupWizard:
text3: "支援者向け特典もあります!"
_uploader:
editImage: "画像の編集"
compressedToX: "{x}に圧縮"
savedXPercent: "{x}%節約"
abortConfirm: "アップロードされていないファイルがありますが、中止しますか?"
@@ -3227,6 +3239,8 @@ defaultPreset: "デフォルトのプリセット"
_watermarkEditor:
tip: "画像にクレジット情報などのウォーターマークを追加することができます。"
quitWithoutSaveConfirm: "保存せずに終了しますか?"
driveFileTypeWarn: "このファイルは対応していません"
driveFileTypeWarnDescription: "画像ファイルを選択してください"
title: "ウォーターマークの編集"
cover: "全体に被せる"
repeat: "敷き詰める"
@@ -3260,6 +3274,7 @@ _imageEffector:
mirror: "ミラー"
invert: "色の反転"
grayscale: "白黒"
colorAdjust: "色調補正"
colorClamp: "色の圧縮"
colorClampAdvanced: "色の圧縮(高度)"
distort: "歪み"
@@ -3268,3 +3283,21 @@ _imageEffector:
stripe: "ストライプ"
polkadot: "ポルカドット"
checker: "チェッカー"
blockNoise: "ブロックノイズ"
tearing: "ティアリング"
drafts: "下書き"
_drafts:
select: "下書きを選択"
cannotCreateDraftAnymore: "下書きの作成可能数を超えています。"
cannotCreateDraft: "この内容では下書きを作成できません。"
delete: "下書きを削除"
deleteAreYouSure: "下書きを削除しますか?"
noDrafts: "下書きはありません"
replyTo: "{user}への返信"
quoteOf: "{user}のノートへの引用"
postTo: "{channel}への投稿"
saveToDraft: "下書きへ保存"
restoreFromDraft: "下書きから復元"
restore: "復元"
listDrafts: "下書き一覧"

View File

@@ -2848,3 +2848,13 @@ _search:
searchScopeAll: "みんな"
searchScopeLocal: "ローカル"
searchScopeUser: "ユーザー指定"
_watermarkEditor:
driveFileTypeWarn: "このファイルは対応しとらへん"
opacity: "不透明度"
scale: "大きさ"
text: "テキスト"
position: "位置"
type: "タイプ"
image: "画像"
advanced: "高度"
angle: "角度"

View File

@@ -848,3 +848,5 @@ _remoteLookupErrors:
_search:
searchScopeAll: "말캉"
searchScopeUser: "사용자 지정"
_watermarkEditor:
image: "이미지"

View File

@@ -1313,6 +1313,7 @@ availableRoles: "사용 가능한 역할"
acknowledgeNotesAndEnable: "활성화 하기 전에 주의 사항을 확인했습니다."
federationSpecified: "이 서버는 화이트 리스트 제도로 운영 중 입니다. 정해진 리모트 서버가 아닌 경우 연합되지 않습니다."
federationDisabled: "이 서버는 연합을 하지 않고 있습니다. 리모트 서버 유저와 통신을 할 수 없습니다."
draft: "초안"
confirmOnReact: "리액션할 때 확인"
reactAreYouSure: "\" {emoji} \"로 리액션하시겠습니까?"
markAsSensitiveConfirm: "이 미디어를 민감한 미디어로 설정하시겠습니까?"
@@ -1365,6 +1366,11 @@ abort: "중지"
tip: "팁과 유용한 정보"
redisplayAllTips: "모든 '팁과 유용한 정보'를 재표시"
hideAllTips: "모든 '팁과 유용한 정보'를 비표시"
defaultImageCompressionLevel: "기본 이미지 압축 정도"
defaultImageCompressionLevel_description: "낮추면 화질을 유지합니다만 파일 크기는 증가합니다. <br>높이면 파일 크기를 줄일 수 있습니다만 화질은 저하됩니다."
_order:
newest: "최신 순"
oldest: "오래된 순"
_chat:
noMessagesYet: "아직 메시지가 없습니다"
newMessage: "새로운 메시지"
@@ -1452,6 +1458,7 @@ _settings:
contentsUpdateFrequency_description: "높을수록 실시간으로 콘텐츠가 업데이트됩니다만, 성능이 저하되고 데이터 사용량과 배터리의 소비가 증가합니다."
contentsUpdateFrequency_description2: "실시간 모드가 켜져 있을 때는 이 설정과 상관없이 실시간으로 콘텐츠가 업데이트됩니다."
showUrlPreview: "URL 미리보기 표시"
showAvailableReactionsFirstInNote: "이용 가능한 리액션을 선두로 표시"
_chat:
showSenderName: "발신자 이름 표시"
sendOnEnter: "엔터로 보내기"
@@ -1990,6 +1997,8 @@ _role:
uploadableFileTypes: "업로드 가능한 파일 유형"
uploadableFileTypes_caption: "MIME 유형을 "
uploadableFileTypes_caption2: "파일에 따라서는 유형을 검사하지 못하는 경우가 있습니다. 그러한 파일을 허가하는 경우에는 {x}를 지정으로 추가해주십시오."
noteDraftLimit: "서버측 노트 초안 작성 가능 수"
watermarkAvailable: "워터마크 기능의 사용 여부"
_condition:
roleAssignedTo: "수동 역할에 이미 할당됨"
isLocal: "로컬 유저"
@@ -2149,6 +2158,7 @@ _theme:
install: "테마 설치"
manage: "테마 관리"
code: "테마 코드"
copyThemeCode: "테마 코드 복사"
description: "설명"
installed: "{name} 테마가 설치되었습니다"
installedThemes: "설치된 테마"
@@ -2462,6 +2472,8 @@ _visibility:
disableFederation: "연합에 보내지 않기"
disableFederationDescription: "다른 서버로 보내지 않습니다"
_postForm:
quitInspiteOfThereAreUnuploadedFilesConfirm: "업로드되지 않은 파일이 있습니다만, 없애고 폼을 닫겠습니까?"
uploaderTip: "파일이 아직 업로드돼있지 않습니다. 파일 메뉴에서 이름 바꾸기나 이미지의 자르기, 워터마크 넣기, 압축의 유무 등을 설정할 수 있습니다. 파일은 노트 게시 시 자동으로 업로드됩니다."
replyPlaceholder: "이 노트에 답글..."
quotePlaceholder: "이 노트를 인용..."
channelPlaceholder: "채널에 게시하기..."
@@ -2795,6 +2807,7 @@ _fileViewer:
url: "URL"
uploadedAt: "업로드 날짜"
attachedNotes: "첨부된 노트"
usage: "이용"
thisPageCanBeSeenFromTheAuthor: "이 페이지는 파일 소유자만 열람할 수 있습니다"
_externalResourceInstaller:
title: "외부 사이트로부터 설치"
@@ -3078,7 +3091,7 @@ _serverSetupWizard:
small: "100명 이하(소규모)"
medium: "100명 이상 1000명 이하(중간 규모)"
large: "1000명 이상(대규모)"
largeScaleServerAdvice: "대규모 서버에서는 부하분산이나 데이터베이스의 레플리케이션 등 높은 인프라스트럭처 지식이 필요할 수 있습니다."
largeScaleServerAdvice: "대규모 서버에서는 부하분산이나 데이터베이스의 복제 등 높은 인프라스트럭처 지식이 필요할 수 있습니다."
doYouConnectToFediverse: "Fediverse에 접속하시겠습니까?"
doYouConnectToFediverse_description1: "분산형 서버로 구성된 네트워크(Fediverse)에 접속하면 다른 서버와 서로 콘텐츠의 주고받기를 할 수 있습니다."
doYouConnectToFediverse_description2: "Fediverse에 접속하는 것을 '연합'이라고도 부릅니다."
@@ -3098,11 +3111,12 @@ _serverSetupWizard:
text2: "앞으로도 계속해서 개발을 할 수 있도록 괜찮으시다면 부디 기부를 부탁드립니다."
text3: "지원자 대상 특전도 있습니다!"
_uploader:
editImage: "이미지 편집"
compressedToX: "{x}로 압축"
savedXPercent: "{x}% 절약"
abortConfirm: "업로드되지 않은 파일이 있습니다만, 그만 두시겠습니까?"
doneConfirm: "업로드되지 않은 파일이 있습니다만, 완료하시겠습니까?"
maxFileSizeIsX: "업드 가능한 최대 파일 크기는 {x}입니다."
maxFileSizeIsX: "업드 가능한 최대 파일 크기는 {x}입니다."
allowedTypes: "업로드 가능한 파일 유형"
tip: "파일은 아직 업로드되지 않았습니다. 이 다이얼로그에서 업로드 전의 확인, 이름 바꾸기, 압축, 자르기 등을 하실 수 있습니다. 준비가 되셨다면 '업로드' 버튼을 클릭해 업로드를 시작하실 수 있습니다."
_clientPerformanceIssueTip:
@@ -3117,3 +3131,67 @@ _clip:
tip: "클립은 노트를 정리할 수 있는 기능입니다."
_userLists:
tip: "임의의 유저가 포함된 리스트를 작성할 수 있습니다. 작성한 리스트는 타임라인으로 표시가 가능합니다."
watermark: "워터마크"
defaultPreset: "기본 프리셋"
_watermarkEditor:
tip: "이미지에 크레딧 정보 등의 워터마크를 추가할 수 있습니다."
quitWithoutSaveConfirm: "보존하지 않고 종료하시겠습니까?"
driveFileTypeWarn: "이 파이"
driveFileTypeWarnDescription: "이미지 파일을 선택해주십시오."
title: "워터마크 편집"
cover: "전체에 붙이기"
repeat: "전면에 깔기"
opacity: "불투명도"
scale: "크기"
text: "텍스트"
position: "위치"
type: "종류"
image: "이미지"
advanced: "고급"
stripe: "줄무늬"
stripeWidth: "라인의 폭"
stripeFrequency: "라인의 수"
angle: "각도"
polkadot: "물방울 무늬"
checker: "체크 무늬"
polkadotMainDotOpacity: "주요 물방울의 불투명도"
polkadotMainDotRadius: "주요 물방울의 크기"
polkadotSubDotOpacity: "서브 물방울의 불투명도"
polkadotSubDotRadius: "서브 물방울의 크기"
polkadotSubDotDivisions: "서브 물방울의 수"
_imageEffector:
title: "이펙트"
addEffect: "이펙트를 추가"
discardChangesConfirm: "변경을 취소하고 종료하시겠습니까?"
_fxs:
chromaticAberration: "색수차"
glitch: "글리치"
mirror: "미러"
invert: "색 반전"
grayscale: "흑백"
colorAdjust: "색조 보정"
colorClamp: "색 압축"
colorClampAdvanced: "색 압축(고급)"
distort: "뒤틀림"
threshold: "이진화"
zoomLines: "집중선"
stripe: "줄무늬"
polkadot: "물방울 무늬"
checker: "체크 무늬"
blockNoise: "노이즈 방지"
tearing: "티어링"
drafts: "초안"
_drafts:
select: "초안 선택"
cannotCreateDraftAnymore: "초안 작성 가능 수를 초과했습니다."
cannotCreateDraft: "이 내용으로는 초안을 작성할 수 없습니다. "
delete: "초안 삭제\n"
deleteAreYouSure: "초안을 삭제하시겠습니까?"
noDrafts: "초안 없음\n"
replyTo: "{user}에 회신"
quoteOf: "{user} 노트에 인용"
postTo: "{channel}에 게시"
saveToDraft: "초안에 저장"
restoreFromDraft: "초안에서 복원\n"
restore: "복원"
listDrafts: "초안 목록"

View File

@@ -483,3 +483,5 @@ _remoteLookupErrors:
title: "ບໍ່ພົບ"
_search:
searchScopeAll: "ທັງໝົດ"
_watermarkEditor:
image: "ຮູບພາບ"

View File

@@ -1078,3 +1078,6 @@ _remoteLookupErrors:
title: "Niet gevonden"
_search:
searchScopeAll: "Alle"
_watermarkEditor:
image: "Afbeeldingen"
advanced: "Geavanceerd"

View File

@@ -735,3 +735,8 @@ _remoteLookupErrors:
title: "Ikke funnet"
_search:
searchScopeAll: "Alle"
_watermarkEditor:
scale: "Størrelse"
text: "Tekst"
type: "Type"
image: "Bilder"

View File

@@ -1584,3 +1584,10 @@ _remoteLookupErrors:
_search:
searchScopeAll: "Wszystkie"
searchScopeLocal: "Lokalne"
_watermarkEditor:
opacity: "Przezroczystość"
scale: "Rozmiar"
text: "Tekst"
type: "Typ"
image: "Zdjęcia"
advanced: "Zaawansowane"

View File

@@ -298,6 +298,7 @@ uploadFromUrl: "Enviar por URL"
uploadFromUrlDescription: "URL do arquivo que você deseja enviar"
uploadFromUrlRequested: "Upload solicitado"
uploadFromUrlMayTakeTime: "Pode levar algum tempo para que o upload seja concluído."
uploadNFiles: "Enviar {n} arquivos"
explore: "Explorar"
messageRead: "Lida"
noMoreHistory: "Não existe histórico anterior"
@@ -326,6 +327,7 @@ dark: "Escuro"
lightThemes: "Tema claro"
darkThemes: "Tema escuro"
syncDeviceDarkMode: "Sincronize com o modo escuro do dispositivo"
switchDarkModeManuallyWhenSyncEnabledConfirm: "\"{x}\" está ativado. Você gostaria de desligar a sincronização e alterar manualmente?"
drive: "Drive"
fileName: "Nome do Ficheiro"
selectFile: "Selecione os arquivos"
@@ -444,7 +446,7 @@ exploreUsersCount: "Há um utilizador de {count}"
exploreFediverse: "Explorar Fediverse"
popularTags: "Tags populares"
userList: "Listas"
about: "Informações"
about: "Sobre"
aboutMisskey: "Sobre Misskey"
administrator: "Administrador"
token: "Símbolo"
@@ -578,6 +580,7 @@ newNoteRecived: "Nova nota recebida"
newNote: "Nova Nota"
sounds: "Sons"
sound: "Sons"
notificationSoundSettings: "Configurações de som de notificações"
listen: "Ouvir"
none: "Nenhum"
showInPage: "Ver na página"
@@ -999,6 +1002,7 @@ failedToUpload: "Falha ao enviar"
cannotUploadBecauseInappropriate: "Esse arquivo não pôde ser enviado porque partes dele foram detectadas como potencialmente inapropriadas."
cannotUploadBecauseNoFreeSpace: "Envio falhou devido à falta de capacidade no Drive."
cannotUploadBecauseExceedsFileSizeLimit: "Não é possível realizar o upload deste arquivo porque ele excede o tamanho máximo permitido."
cannotUploadBecauseUnallowedFileType: "Não foi possível fazer o envio, pois o formato do arquivo não foi autorizado."
beta: "Beta"
enableAutoSensitive: "Marcar automaticamente como conteúdo sensível"
enableAutoSensitiveDescription: "Quando disponível, a marcação de mídia sensível será automaticamente atribuído ao conteúdo de mídia usando aprendizado de máquina. Mesmo que você desative essa função, em alguns servidores, isso pode ser configurado automaticamente."
@@ -1309,6 +1313,7 @@ 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."
draft: "Rascunhos"
confirmOnReact: "Confirmar ao reagir"
reactAreYouSure: "Você deseja adicionar uma reação \"{emoji}\"?"
markAsSensitiveConfirm: "Você deseja definir essa mídia como sensível?"
@@ -1326,6 +1331,7 @@ 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?"
preferenceSyncConflictChoiceMerge: "Combinar"
preferenceSyncConflictChoiceServer: "Valor configurado no servidor"
preferenceSyncConflictChoiceDevice: "Valor configurado no dispositivo"
preferenceSyncConflictChoiceCancel: "Cancelar a habilitação de sincronização"
@@ -1333,7 +1339,7 @@ paste: "Colar"
emojiPalette: "Paleta de emojis"
postForm: "Campo de postagem"
textCount: "Contagem de caracteres"
information: "Informações"
information: "Sobre"
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."
@@ -1356,6 +1362,15 @@ emojiMute: "Silenciar emoji"
emojiUnmute: "Reativar emoji"
muteX: "Silenciar {x}"
unmuteX: "Reativar {x}"
abort: "Abortar"
tip: "Dicas e Truques"
redisplayAllTips: "Mostrar todas as \"Dicas e Truques\" novamente"
hideAllTips: "Ocultas todas as \"Dicas e Truques\""
defaultImageCompressionLevel: "Nível de compressão de imagem padrão"
defaultImageCompressionLevel_description: "Alto, reduz o tamanho do arquivo mas, também, a qualidade da imagem.<br>Alto, reduz o tamanho do arquivo mas, também, a qualidade da imagem."
_order:
newest: "Priorizar Mais Novos"
oldest: "Priorizar Mais Antigos"
_chat:
noMessagesYet: "Ainda não há mensagens"
newMessage: "Nova mensagem"
@@ -1442,6 +1457,8 @@ _settings:
contentsUpdateFrequency: "Frequência da obtenção de conteúdo"
contentsUpdateFrequency_description: "Quanto maior o valor, mais o conteúdo atualiza. Porém, há uma diminuição do desempenho e aumento do tráfego e consumo de memória."
contentsUpdateFrequency_description2: "Quando o modo tempo-real está ativado, o conteúdo é atualizado em tempo real, ignorando essa opção."
showUrlPreview: "Exibir prévia de URL"
showAvailableReactionsFirstInNote: "Exibir reações disponíveis no topo."
_chat:
showSenderName: "Exibir nome de usuário do remetente"
sendOnEnter: "Pressionar Enter para enviar"
@@ -1977,6 +1994,11 @@ _role:
canImportMuting: "Permitir importação de silenciamentos"
canImportUserLists: "Permitir importação de listas"
chatAvailability: "Permitir Conversas"
uploadableFileTypes: "Tipos de arquivo enviáveis"
uploadableFileTypes_caption: "Especifica tipos MIME permitidos. Múltiplos tipos MIME podem ser especificados separando-os por linha. Curingas podem ser especificados com um asterisco (*). (exemplo, image/*)"
uploadableFileTypes_caption2: "Alguns tipos de arquivos podem não ser detectados. Para permiti-los, adicione {x} à especificação."
noteDraftLimit: "Limite de rascunhos possíveis"
watermarkAvailable: "Disponibilidade da função de marca d'água"
_condition:
roleAssignedTo: "Atribuído a cargos manuais"
isLocal: "Usuário local"
@@ -2136,6 +2158,7 @@ _theme:
install: "Instalar um tema"
manage: "Gerenciar temas"
code: "Código do tema"
copyThemeCode: "Copiar código do tema"
description: "Descrição"
installed: "{name} foi instalado"
installedThemes: "Temas instalados"
@@ -2449,6 +2472,8 @@ _visibility:
disableFederation: "Defederar"
disableFederationDescription: "Não transmitir às outras instâncias"
_postForm:
quitInspiteOfThereAreUnuploadedFilesConfirm: "Há arquivos que não foram enviados, gostaria de descartá-los e fechar o editor?"
uploaderTip: "O arquivo ainda não foi enviado. No menu do arquivo, você pode renomear, cortar, adicionar uma marca d'água, comprimir ou descomprimir um arquivo. Arquivos serão enviados automaticamente ao publicar a nota."
replyPlaceholder: "Responder a essa nota..."
quotePlaceholder: "Citar essa nota..."
channelPlaceholder: "Postar em canal..."
@@ -2782,6 +2807,7 @@ _fileViewer:
url: "URL"
uploadedAt: "Adicionado em"
attachedNotes: "Notas anexadas"
usage: "Usado"
thisPageCanBeSeenFromTheAuthor: "Essa página só pode ser vista pelo usuário que enviou esse arquivo."
_externalResourceInstaller:
title: "Instalar de site externo"
@@ -2829,6 +2855,12 @@ _dataSaver:
_avatar:
title: "Imagem do avatar"
description: "Parar animação de avatares. Imagens animadas podem ter um arquivo mais pesado do que imagens normais, potencialmente levando a reduções no tráfego de dados."
_urlPreviewThumbnail:
title: "Esconder miniaturas em prévias de URL"
description: "Miniaturas em prévias de URL não serão carregadas."
_disableUrlPreview:
title: "Desabilitar prévias de URL"
description: "Desabilita a função de prévias de URL. Diferente das miniaturas, essa função impede o carregamento de toda informação do link."
_code:
title: "Destaque de código"
description: "Se as notações de formatação de código forem utilizadas em MFM, elas não irão carregar até serem selecionadas. Destaque de código exige baixar arquivos de alta definição para cada linguagem de programação. Logo, desabilitar o carregamento automático desses arquivos diminui a quantidade de informação comunicada."
@@ -2886,6 +2918,8 @@ _offlineScreen:
_urlPreviewSetting:
title: "Configurações da prévia de URL"
enable: "Habilitar prévia de URL"
allowRedirect: "Permitir redirecionamentos de URL em prévias."
allowRedirectDescription: "Se um URL tem um redirecionamento, você pode habilitar essa função para segui-lo e exibir a prévia do conteúdo redirecionado. Desabilitar isso irá economizar recursos, mas o conteúdo não será exibido."
timeout: "Tempo máximo para obter a prévia (ms)"
timeoutDescription: "Se demorar mais que esse valor para obter uma prévia, ela não será gerada."
maximumContentLength: "Content-Length máximo (em bytes)"
@@ -3076,6 +3110,15 @@ _serverSetupWizard:
text1: "Misskey é software aberto desenvolvido por voluntários."
text2: "Nós apreciaríamos o seu apoio para podermos continuar o desenvolvimento desse software no futuro."
text3: "Também há benefícios especiais para apoiadores!"
_uploader:
editImage: "Editar Imagem"
compressedToX: "Comprimido para {x}"
savedXPercent: "Salvando {x}%"
abortConfirm: "Alguns arquivos não foram enviados, deseja abortar?"
doneConfirm: "Alguns arquivos não foram enviados, deseja continuar mesmo assim?"
maxFileSizeIsX: "O tamanho máximo de arquivos enviados é {x}"
allowedTypes: "Tipos de arquivo enviáveis"
tip: "O arquivo não foi enviado. Então, esse diálogo permite que você confirme, renomeie, comprima e recorte o arquivo antes de enviar. Quando estiver pronto, você pode enviar apertando o botão \"Enviar\"."
_clientPerformanceIssueTip:
title: "Dicas de desempenho"
makeSureDisabledAdBlocker: "Desative o seu bloqueador de anúncios"
@@ -3084,3 +3127,71 @@ _clientPerformanceIssueTip:
makeSureDisabledCustomCss_description: "Substituir o estilo da página pode afetar o desempenho. Certifique-se que o CSS personalizado ou extensões que modifiquem o estilo da página estejam desabilitados."
makeSureDisabledAddons: "Desabilite extensões"
makeSureDisabledAddons_description: "Algumas extensões podem afetar comportamentos do cliente e afetar o desempenho. Por favor, desative as extensões do seu navegador e veja se isso melhora a situação."
_clip:
tip: "Clip é uma função que permite organização das suas notas."
_userLists:
tip: "Listas podem conter qualquer usuário que você especificar em sua criação. A lista criada aparece como uma linha do tempo exibindo usuários selecionados."
watermark: "Marca d'água"
defaultPreset: "Predefinição Padrão"
_watermarkEditor:
tip: "Uma marca d'água, como informação de autoria, pode ser adicionada à imagem."
quitWithoutSaveConfirm: "Descartar mudanças?"
driveFileTypeWarn: "Esse arquivo não é compatível"
driveFileTypeWarnDescription: "Escolha um arquivo de imagem"
title: "Editar marca d'água"
cover: "Cobrir tudo"
repeat: "Espalhar pelo conteúdo"
opacity: "Opacidade"
scale: "Tamanho"
text: "Texto"
position: "Posição"
type: "Tipo"
image: "imagem"
advanced: "Avançado"
stripe: "Listras"
stripeWidth: "Largura da linha"
stripeFrequency: "Número de linhas"
angle: "Ângulo"
polkadot: "Bolinhas"
checker: "Xadrez"
polkadotMainDotOpacity: "Opacidade da bolinha principal"
polkadotMainDotRadius: "Raio da bolinha principal"
polkadotSubDotOpacity: "Opacidade da bolinha secundária"
polkadotSubDotRadius: "Raio das bolinhas adicionais"
polkadotSubDotDivisions: "Número de bolinhas adicionais"
_imageEffector:
title: "Efeitos"
addEffect: "Adicionar efeitos"
discardChangesConfirm: "Tem certeza que deseja sair? Há mudanças não salvas."
_fxs:
chromaticAberration: "Aberração cromática"
glitch: "Glitch"
mirror: "Espelho"
invert: "Inverter Cores"
grayscale: "Tons de Cinza"
colorAdjust: "Correção de Cores"
colorClamp: "Compressão de Cores"
colorClampAdvanced: "Compressão Avançada de Cores"
distort: "Distorção"
threshold: "Limiarização Binária"
zoomLines: "Linhas de Ação"
stripe: "Listras"
polkadot: "Bolinhas"
checker: "Xadrez"
blockNoise: "Bloquear Ruído"
tearing: "Descontinuidade"
drafts: "Rascunhos"
_drafts:
select: "Selecionar Rascunho"
cannotCreateDraftAnymore: "O número máximo de rascunhos foi excedido."
cannotCreateDraft: "Você não pode criar um rascunho com esse conteúdo."
delete: "Excluir Rascunho"
deleteAreYouSure: "Excluir rascunho?"
noDrafts: "Sem rascunhos"
replyTo: "Resposta a {user}"
quoteOf: "Citação à nota de {user}"
postTo: "Publicando em {channel}"
saveToDraft: "Salvar como Rascunho"
restoreFromDraft: "Restaurar de Rascunho"
restore: "Redefinir"
listDrafts: "Lista de Rascunhos"

View File

@@ -1391,3 +1391,10 @@ _search:
searchScopeLocal: "Local"
searchScopeUser: "Utilizator specific"
serverHostPlaceholder: "Exemplu: misskey.example.com"
_watermarkEditor:
scale: "Dimensiune"
text: "Text"
position: "Poziție"
type: "Tip"
image: "Imagini"
advanced: "Avansat"

View File

@@ -2191,3 +2191,12 @@ _search:
searchScopeAll: "Все"
searchScopeLocal: "Местная"
searchScopeUser: "Указанный пользователь"
_watermarkEditor:
opacity: "Непрозрачность"
scale: "Размер"
text: "Текст"
position: "Позиция"
type: "Тип"
image: "Изображения"
advanced: "Для продвинутых"
angle: "Угол"

View File

@@ -1450,3 +1450,10 @@ _remoteLookupErrors:
_search:
searchScopeAll: "Všetko"
searchScopeLocal: "Lokálne"
_watermarkEditor:
opacity: "Priehľadnosť"
scale: "Veľkosť"
text: "Text"
type: "Typ"
image: "Obrázky"
advanced: "Rozšírené"

View File

@@ -711,3 +711,6 @@ _selfXssPrevention:
warning: "VARNING"
_search:
searchScopeAll: "Allt"
_watermarkEditor:
scale: "Storlek"
image: "Bilder"

File diff suppressed because it is too large Load Diff

View File

@@ -460,3 +460,5 @@ _moderationLogTypes:
resetPassword: "Şifre sıfırlama"
_search:
searchScopeAll: "Tümü"
_watermarkEditor:
image: "Görseller"

View File

@@ -8,6 +8,9 @@ search: "Пошук"
notifications: "Сповіщення"
username: "Ім'я користувача"
password: "Пароль"
initialPasswordForSetup: "Початковий пароль для налаштування"
initialPasswordIsIncorrect: "Початковий пароль для налаштування неправильний"
initialPasswordForSetupDescription: "Використайте пароль, вказаний у конфігураційному файлі, якщо ви встановлювали Misskey власноруч.\nЯкщо використовуєте сервіси хостингу Misskey, використайте наданий пароль.\nЯкщо ви не маєте паролю, лишіть порожнім щоб продовжити. "
forgotPassword: "Я забув пароль"
fetchingAsApObject: "Отримуємо з федіверсу..."
ok: "OK"
@@ -45,6 +48,7 @@ pin: "Закріпити"
unpin: "Відкріпити"
copyContent: "Скопіювати контент"
copyLink: "Скопіювати посилання"
copyRemoteLink: "Копіювати віддалене посилання"
delete: "Видалити"
deleteAndEdit: "Видалити й редагувати"
deleteAndEditConfirm: "Ви впевнені, що хочете видалити цю нотатку та відредагувати її? Ви втратите всі реакції, поширення та відповіді на неї."
@@ -57,6 +61,7 @@ copyUserId: "Копіювати ID користувача"
copyNoteId: "блокнот ID користувача"
copyFileId: "Скопіювати ідентифікатор файлу."
searchUser: "Пошук користувачів"
searchThisUsersNotes: "Пошук нотаток користувача"
reply: "Відповісти"
loadMore: "Показати більше"
showMore: "Показати більше"
@@ -105,9 +110,11 @@ enterEmoji: "Введіть емодзі"
renote: "Поширити"
unrenote: "Відміна поширення"
renoted: "Поширити запис."
renotedToX: "Поширено до {name}"
cantRenote: "Неможливо поширити."
cantReRenote: "Поширення не можливо поширити."
quote: "Цитата"
inChannelRenote: "Поширено у канал"
pinnedNote: "Закріплений запис"
pinned: "Закріпити"
you: "Ви"
@@ -116,6 +123,7 @@ sensitive: "NSFW"
add: "Додати"
reaction: "Реакції"
reactions: "Реакції"
emojiPicker: "Вибір реакції"
reactionSettingDescription2: "Перемістити щоб змінити порядок, Клацнути мишою щоб видалити, Натиснути \"+\" щоб додати."
rememberNoteVisibility: "Пам’ятати параметри видимісті"
attachCancel: "Видалити вкладення"
@@ -289,7 +297,9 @@ folderName: "Ім'я теки"
createFolder: "Створити теку"
renameFolder: "Перейменувати теку"
deleteFolder: "Видалити теку"
folder: "Тека"
addFile: "Додати файл"
showFile: "Показати файл"
emptyDrive: "Диск порожній"
emptyFolder: "Тека порожня"
unableToDelete: "Видалення неможливе"
@@ -302,6 +312,7 @@ copyUrl: "Копіювати URL"
rename: "Перейменувати"
avatar: "Аватар"
banner: "Банер"
displayOfSensitiveMedia: "Показ чутливого медіа"
whenServerDisconnected: "Коли зв’язок із сервером втрачено"
disconnectedFromServer: "Зв’язок із сервером було перервано"
reload: "Оновити"
@@ -348,8 +359,11 @@ hcaptcha: "hCaptcha"
enableHcaptcha: "Увімкнути hCaptcha"
hcaptchaSiteKey: "Ключ сайту"
hcaptchaSecretKey: "Секретний ключ"
mcaptcha: "MCaptcha"
enableMcaptcha: "Увімкнути MCaptcha"
mcaptchaSiteKey: "Ключ сайту"
mcaptchaSecretKey: "Секретний ключ"
mcaptchaInstanceUrl: "Посилання на сервер MCaptcha"
recaptcha: "reCAPTCHA"
enableRecaptcha: "Увімкнути reCAPTCHA"
recaptchaSiteKey: "Ключ сайту"
@@ -1625,3 +1639,10 @@ _remoteLookupErrors:
_search:
searchScopeAll: "Всі"
searchScopeLocal: "Локальна"
_watermarkEditor:
opacity: "Непрозорість"
scale: "Розмір"
text: "Текст"
type: "Тип"
image: "Зображення"
advanced: "Розширені"

View File

@@ -1097,3 +1097,8 @@ _remoteLookupErrors:
_search:
searchScopeAll: "Barcha"
searchScopeLocal: "Mahalliy"
_watermarkEditor:
text: "Matn"
type: "turi"
image: "Rasmlar"
advanced: "Murakkab"

View File

@@ -220,6 +220,7 @@ silenceThisInstance: "Máy chủ im lặng"
mediaSilenceThisInstance: "Tắt nội dung đa phương tiện từ máy chủ này"
operations: "Vận hành"
software: "Phần mềm"
softwareName: "Tên phần mềm"
version: "Phiên bản"
metadata: "Metadata"
withNFiles: "{n} tập tin"
@@ -1211,6 +1212,9 @@ federationDisabled: "Liên kết bị vô hiệu hóa trên máy chủ này. B
reactAreYouSure: "Bạn có muốn phản hồi với \" {emoji} \" không?"
preferences: "Thiết lập môi trường"
accessibility: "Khả năng tiếp cận"
preferencesProfile: "Hồ sơ sở thích"
preferenceSyncConflictTitle: "Cài đặt tồn tại trên máy chủ"
preferenceSyncConflictText: "Các thiết lập đồng bộ hóa được bật sẽ lưu các giá trị của chúng vào máy chủ. Tuy nhiên, có những giá trị hiện có trên máy chủ. Bạn muốn ghi đè lên bộ giá trị nào?"
paste: "dán"
postForm: "Mẫu đăng"
information: "Giới thiệu"
@@ -1223,6 +1227,8 @@ _chat:
members: "Thành viên"
home: "Trang chính"
send: "Gửi"
_settings:
preferencesBanner: "Bạn có thể cấu hình hành vi chung của máy khách theo sở thích của mình."
_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."
@@ -2074,3 +2080,12 @@ _search:
searchScopeAll: "Tất cả"
searchScopeLocal: "Máy chủ này"
searchScopeUser: "Người dùng chỉ định"
_watermarkEditor:
opacity: "Độ trong suốt"
scale: "Kích thước"
text: "Văn bản"
position: "Vị trí"
type: "Loại"
image: "Hình ảnh"
advanced: "Nâng cao"
angle: "Góc"

View File

@@ -1313,6 +1313,7 @@ availableRoles: "可用角色"
acknowledgeNotesAndEnable: "理解注意事项后再开启。"
federationSpecified: "此服务器已开启联合白名单。只能与管理员指定的服务器通信。"
federationDisabled: "此服务器已禁用联合。无法与其它服务器上的用户通信。"
draft: "草稿"
confirmOnReact: "发送回应前需要确认"
reactAreYouSure: "要用「{emoji}」进行回应吗?"
markAsSensitiveConfirm: "要将此媒体标记为敏感吗?"
@@ -1365,6 +1366,11 @@ abort: "中止"
tip: "提示和技巧"
redisplayAllTips: "重新显示所有的提示和技巧"
hideAllTips: "隐藏所有的提示和技巧"
defaultImageCompressionLevel: "默认图像压缩等级"
defaultImageCompressionLevel_description: "较低的等级可以保持画质,但会增加文件大小。<br>较高的等级可以减少文件大小,但相对应的画质将会降低。"
_order:
newest: "从新到旧"
oldest: "从旧到新"
_chat:
noMessagesYet: "还没有消息"
newMessage: "新消息"
@@ -1452,6 +1458,7 @@ _settings:
contentsUpdateFrequency_description: "设置越高,内容更新越实时,但性能会降低,并且会消耗更多的流量和电池。"
contentsUpdateFrequency_description2: "当实时模式开启时,无论此设置如何,内容都会实时更新。"
showUrlPreview: "显示 URL 预览"
showAvailableReactionsFirstInNote: "在顶部显示可用的回应"
_chat:
showSenderName: "显示发送者的名字"
sendOnEnter: "回车键发送"
@@ -1628,7 +1635,7 @@ _serverSettings:
inquiryUrl: "联络地址"
inquiryUrlDescription: "用来指定诸如向服务运营商咨询的论坛地址,或记载了运营商联系方式之类的网页地址。"
openRegistration: "开放注册"
openRegistrationWarning: "开放注册有风险。建议仅当能够持续监控服务器并在出现问题时能够立即响应时才打开它。"
openRegistrationWarning: "开放注册有风险。建议仅当能够持续监控服务器并在出现问题时能够立即响应时才打开它。"
thisSettingWillAutomaticallyOffWhenModeratorsInactive: "若在一段时间内没有检测到管理活动,为防止垃圾信息,此设定将自动关闭。"
deliverSuspendedSoftware: "停止投递的软件"
deliverSuspendedSoftwareDescription: "可因安全漏洞之类的原因,停止向指定的服务器及服务器版本送信。版本信息由服务器提供,不保证可靠性。可使用 semver 范围来指定版本,但指定 >= 2024.3.1 将不包括如 2024.3.1-custom.0 等自定义版本,因此建议像 >= 2024.3.1-0 这样指定 prerelease 版本。"
@@ -1641,7 +1648,7 @@ _serverSettings:
allowExternalApRedirect: "允许通过 ActivityPub 重定向查询"
allowExternalApRedirect_description: "启用时,将允许其它服务器通过此服务器查询第三方内容,但有可能导致内容欺骗。"
userGeneratedContentsVisibilityForVisitor: "用户生成内容对非用户的可见性"
userGeneratedContentsVisibilityForVisitor_description: "对于防止诸如难以审核的不适当的远程内容通过自己的服务器无意中在互联网上公开等问题很有用。"
userGeneratedContentsVisibilityForVisitor_description: "对于防止难以审核的不适当的远程内容等,通过自己的服务器无意中在互联网上公开等问题很有用。"
userGeneratedContentsVisibilityForVisitor_description2: "包含服务器接收到的远程内容在内,无条件将服务器上的所有内容公开在互联网上存在风险。特别是对去中心化的特性不是很了解的访问者有可能将远程服务器上的内容误认为是在此服务器内生成的,需要特别留意。"
_userGeneratedContentsVisibilityForVisitor:
all: "全部公开"
@@ -1990,6 +1997,8 @@ _role:
uploadableFileTypes: "可上传的文件类型"
uploadableFileTypes_caption: "指定 MIME 类型。可用换行指定多个类型,也可以用星号(*)作为通配符。(如 image/*"
uploadableFileTypes_caption2: "文件根据文件的不同,可能无法判断其类型。若要允许此类文件,请在指定中添加 {x}。"
noteDraftLimit: "可在服务器上创建多少草稿"
watermarkAvailable: "能否使用水印功能"
_condition:
roleAssignedTo: "已分配给手动角色"
isLocal: "是本地用户"
@@ -2140,7 +2149,7 @@ _wordMute:
muteWordsDescription: "AND 条件用空格分隔OR 条件用换行符分隔。"
muteWordsDescription2: "正则表达式用斜线包裹"
_instanceMute:
instanceMuteDescription: "隐藏服务器中所有帖子和转帖,包括这些服务器上用户回复。"
instanceMuteDescription: "隐藏服务器中所有帖子和转帖,包括这些服务器上用户回复。"
instanceMuteDescription2: "一行一个"
title: "下面实例中的帖子将被隐藏。"
heading: "已隐藏的服务器"
@@ -2149,6 +2158,7 @@ _theme:
install: "安装主题"
manage: "主题管理"
code: "主题代码"
copyThemeCode: "复制主题代码"
description: "描述"
installed: "{name} 已安装"
installedThemes: "已安装的主题"
@@ -2462,6 +2472,8 @@ _visibility:
disableFederation: "不参与联合"
disableFederationDescription: "不发送到其他服务器"
_postForm:
quitInspiteOfThereAreUnuploadedFilesConfirm: "还有未上传的文件,要丢弃并关闭窗口吗?"
uploaderTip: "文件还未上传。可以在文件菜单中进行重命名、裁剪、添加水印、设置是否压缩等操作。文件将在发帖时自动上传。"
replyPlaceholder: "回复这个帖子..."
quotePlaceholder: "引用这个帖子..."
channelPlaceholder: "发布到频道…"
@@ -2488,7 +2500,7 @@ _profile:
avatarDecorationMax: "最多可添加 {max} 个挂件"
followedMessage: "被关注时显示的消息"
followedMessageDescription: "可以设置被关注时向对方显示的短消息。"
followedMessageDescriptionForLockedAccount: "需要批准才能关注的情况下,消息在请求被批准后显示。"
followedMessageDescriptionForLockedAccount: "需要批准才能关注的情况下,消息在请求被批准后显示。"
_exportOrImport:
allNotes: "所有帖子"
favoritedNotes: "收藏的帖子"
@@ -2795,6 +2807,7 @@ _fileViewer:
url: "URL"
uploadedAt: "添加日期"
attachedNotes: "附加到的帖子"
usage: "使用"
thisPageCanBeSeenFromTheAuthor: "此页只能被该文件的上传者查看。"
_externalResourceInstaller:
title: "从外部站点安装"
@@ -3098,6 +3111,7 @@ _serverSetupWizard:
text2: "为了今后也能继续开发,如果可以的话,请考虑一下捐助。"
text3: "也有面向支援者的特典!"
_uploader:
editImage: "编辑图像"
compressedToX: "压缩 {x}"
savedXPercent: "节省了 {x}% 的空间"
abortConfirm: "还有未上传的文件,要中止吗?"
@@ -3117,3 +3131,67 @@ _clip:
tip: "便签功能可以将帖子合并在一起。"
_userLists:
tip: "可创建包含任意用户的列表。已创建的列表可作为时间线查看。"
watermark: "水印"
defaultPreset: "默认预设"
_watermarkEditor:
tip: "可在图像内增加包含作者等信息的水印。"
quitWithoutSaveConfirm: "不保存就退出吗?"
driveFileTypeWarn: "不支持此文件"
driveFileTypeWarnDescription: "请选择图像文件"
title: "编辑水印"
cover: "覆盖全体"
repeat: "平铺"
opacity: "不透明度"
scale: "大小"
text: "文本"
position: "位置"
type: "类型"
image: "图片"
advanced: "高级"
stripe: "条纹"
stripeWidth: "线条宽度"
stripeFrequency: "线条数量"
angle: "角度"
polkadot: "波点"
checker: "检查"
polkadotMainDotOpacity: "主波点的不透明度"
polkadotMainDotRadius: "主波点的大小"
polkadotSubDotOpacity: "副波点的不透明度"
polkadotSubDotRadius: "副波点的大小"
polkadotSubDotDivisions: "副波点的数量"
_imageEffector:
title: "效果"
addEffect: "添加效果"
discardChangesConfirm: "丢弃当前设置并退出?"
_fxs:
chromaticAberration: "色差"
glitch: "故障"
mirror: "镜像"
invert: "反转颜色"
grayscale: "黑白"
colorAdjust: "色彩校正"
colorClamp: "颜色限制"
colorClampAdvanced: "颜色限制(高级)"
distort: "失真"
threshold: "二值化"
zoomLines: "集中线"
stripe: "条纹"
polkadot: "波点"
checker: "检查"
blockNoise: "块状噪点"
tearing: "撕裂"
drafts: "草稿"
_drafts:
select: "选择草稿"
cannotCreateDraftAnymore: "已超过可创建的草稿数量。"
cannotCreateDraft: "此内容无法创建草稿。"
delete: "删除草稿"
deleteAreYouSure: "要删除草稿吗?"
noDrafts: "没有草稿"
replyTo: "回复给 {user}"
quoteOf: "对 {user} 帖子的引用"
postTo: "向 {channel} 的投稿"
saveToDraft: "保存到草稿"
restoreFromDraft: "从草稿恢复"
restore: "恢复"
listDrafts: "草稿一览"

View File

@@ -1313,6 +1313,7 @@ availableRoles: "可用角色"
acknowledgeNotesAndEnable: "了解注意事項後再開啟。"
federationSpecified: "此伺服器以白名單聯邦的方式運作。除了管理員指定的伺服器外,它無法與其他伺服器互動。"
federationDisabled: "此伺服器未開啟站台聯邦。無法與其他伺服器上的使用者互動。"
draft: "草稿\n"
confirmOnReact: "在做出反應前先確認"
reactAreYouSure: "用「 {emoji} 」反應嗎?"
markAsSensitiveConfirm: "要將這個媒體設定為敏感嗎?"
@@ -1365,6 +1366,11 @@ abort: "取消"
tip: "提示與技巧"
redisplayAllTips: "重新顯示所有「提示與技巧」"
hideAllTips: "隱藏所有「提示與技巧」"
defaultImageCompressionLevel: "預設的影像壓縮程度"
defaultImageCompressionLevel_description: "低的話可以保留畫質,但是會增加檔案的大小。<br>高的話可以減少檔案大小,但是會降低畫質。"
_order:
newest: "最新的在前"
oldest: "最舊的在前"
_chat:
noMessagesYet: "尚無訊息"
newMessage: "新訊息"
@@ -1452,6 +1458,7 @@ _settings:
contentsUpdateFrequency_description: "頻率越高,內容更新越即時,但可能會降低效能,並增加資料傳輸量與電池消耗。\n"
contentsUpdateFrequency_description2: "當即時模式開啟時,不論此設定為何,內容都會即時更新。"
showUrlPreview: "顯示網址預覽"
showAvailableReactionsFirstInNote: "將可用的反應顯示在頂部"
_chat:
showSenderName: "顯示發送者的名稱"
sendOnEnter: "按下 Enter 發送訊息"
@@ -1990,6 +1997,8 @@ _role:
uploadableFileTypes: "可上傳的檔案類型"
uploadableFileTypes_caption: "請指定 MIME 類型。可以用換行區隔多個類型,也可以使用星號(*作為萬用字元進行指定。例如image/*\n"
uploadableFileTypes_caption2: "有些檔案可能無法判斷其類型。若要允許這類檔案,請在指定中加入 {x}。"
noteDraftLimit: "伺服器端可建立的貼文草稿數量上限\n"
watermarkAvailable: "浮水印功能是否可用"
_condition:
roleAssignedTo: "手動指派角色完成"
isLocal: "本地使用者"
@@ -2149,6 +2158,7 @@ _theme:
install: "安裝佈景主題"
manage: "管理佈景主題"
code: "佈景主題代碼"
copyThemeCode: "複製主題代碼"
description: "描述"
installed: "{name}已安裝"
installedThemes: "已經安裝的佈景主題"
@@ -2462,6 +2472,8 @@ _visibility:
disableFederation: "停用聯邦"
disableFederationDescription: "不發送到其他伺服器"
_postForm:
quitInspiteOfThereAreUnuploadedFilesConfirm: "尚有未上傳的檔案,確定要放棄並關閉表單嗎?"
uploaderTip: "檔案尚未上傳。您可以從檔案選單中設定重新命名、裁切圖片、加上浮水印、是否壓縮等選項。檔案會在發布貼文時自動上傳。\n"
replyPlaceholder: "回覆此貼文..."
quotePlaceholder: "引用此貼文..."
channelPlaceholder: "發佈到頻道"
@@ -2795,6 +2807,7 @@ _fileViewer:
url: "URL"
uploadedAt: "加入日期"
attachedNotes: "含有附件的貼文"
usage: "使用情況"
thisPageCanBeSeenFromTheAuthor: "本頁面僅限上傳了這個檔案的使用者可以檢視。"
_externalResourceInstaller:
title: "從外部網站安裝"
@@ -3098,6 +3111,7 @@ _serverSetupWizard:
text2: "為了能夠繼續開發,若您願意的話,請考慮進行捐款。\n"
text3: "也有提供支援者專屬的特典!\n"
_uploader:
editImage: "編輯圖片"
compressedToX: "壓縮為 {x}"
savedXPercent: "節省了 {x}%"
abortConfirm: "有些檔案尚未上傳,您要中止嗎?"
@@ -3117,3 +3131,67 @@ _clip:
tip: "摘錄是一項可以用來整理貼文的功能。"
_userLists:
tip: "您可以建立包含任意使用者的清單。建立後的清單可以作為時間軸顯示。\n"
watermark: "浮水印"
defaultPreset: "預設值"
_watermarkEditor:
tip: "可以在圖片中以浮水印加上出處等資訊。"
quitWithoutSaveConfirm: "不儲存就退出嗎?"
driveFileTypeWarn: "不支援此檔案"
driveFileTypeWarnDescription: "請選擇圖片檔案"
title: "編輯浮水印"
cover: "覆蓋整體"
repeat: "佈局"
opacity: "透明度"
scale: "大小"
text: "文字"
position: "位置"
type: "類型"
image: "圖片"
advanced: "進階"
stripe: "條紋"
stripeWidth: "線條寬度"
stripeFrequency: "線條數量"
angle: "角度"
polkadot: "波卡圓點"
checker: "棋盤格"
polkadotMainDotOpacity: "主圓點的不透明度"
polkadotMainDotRadius: "主圓點的尺寸"
polkadotSubDotOpacity: "子圓點的不透明度"
polkadotSubDotRadius: "子圓點的尺寸"
polkadotSubDotDivisions: "子圓點的數量"
_imageEffector:
title: "特效"
addEffect: "新增特效"
discardChangesConfirm: "捨棄更改並退出嗎?"
_fxs:
chromaticAberration: "色差"
glitch: "異常雜訊效果"
mirror: "鏡像"
invert: "反轉色彩"
grayscale: "黑白"
colorAdjust: "色彩校正"
colorClamp: "壓縮色彩"
colorClampAdvanced: "壓縮色彩(進階)"
distort: "變形"
threshold: "閾值"
zoomLines: "速度線"
stripe: "條紋"
polkadot: "波卡圓點"
checker: "棋盤格"
blockNoise: "阻擋雜訊"
tearing: "撕裂"
drafts: "草稿\n"
_drafts:
select: "選擇草槁"
cannotCreateDraftAnymore: "已超出可建立的草稿數量上限。\n"
cannotCreateDraft: "無法以此內容建立草稿。\n"
delete: "刪除草稿"
deleteAreYouSure: "確定要刪除草稿嗎?\n"
noDrafts: "沒有草稿。\n"
replyTo: "回覆給 {user}\n"
quoteOf: "引用自 {user} 的貼文\n"
postTo: "發佈到 {channel}\n"
saveToDraft: "儲存為草稿"
restoreFromDraft: "從草稿復原\n"
restore: "還原"
listDrafts: "草稿清單"

View File

@@ -1,12 +1,12 @@
{
"name": "misskey",
"version": "2025.6.1-alpha.0",
"version": "2025.7.0",
"codename": "nasubi",
"repository": {
"type": "git",
"url": "https://github.com/misskey-dev/misskey.git"
},
"packageManager": "pnpm@10.11.0",
"packageManager": "pnpm@10.13.1",
"workspaces": [
"packages/frontend-shared",
"packages/frontend",
@@ -52,29 +52,29 @@
"lodash": "4.17.21"
},
"dependencies": {
"cssnano": "7.0.7",
"esbuild": "0.25.4",
"execa": "9.5.3",
"cssnano": "7.1.0",
"esbuild": "0.25.6",
"execa": "9.6.0",
"fast-glob": "3.3.3",
"glob": "11.0.2",
"glob": "11.0.3",
"ignore-walk": "7.0.0",
"js-yaml": "4.1.0",
"postcss": "8.5.3",
"postcss": "8.5.6",
"tar": "7.4.3",
"terser": "5.39.2",
"terser": "5.43.1",
"typescript": "5.8.3"
},
"devDependencies": {
"@misskey-dev/eslint-plugin": "2.1.0",
"@types/node": "22.15.21",
"@typescript-eslint/eslint-plugin": "8.32.1",
"@typescript-eslint/parser": "8.32.1",
"@types/node": "22.16.4",
"@typescript-eslint/eslint-plugin": "8.37.0",
"@typescript-eslint/parser": "8.37.0",
"cross-env": "7.0.3",
"cypress": "14.4.0",
"eslint": "9.27.0",
"globals": "16.1.0",
"cypress": "14.5.2",
"eslint": "9.31.0",
"globals": "16.3.0",
"ncp": "2.0.0",
"pnpm": "10.11.0",
"pnpm": "10.13.1",
"start-server-and-test": "2.0.12"
},
"optionalDependencies": {
@@ -83,6 +83,9 @@
"pnpm": {
"overrides": {
"@aiscript-dev/aiscript-languageserver": "-"
},
"patchedDependencies": {
"typeorm": "patches/typeorm.patch"
}
}
}

View File

@@ -25,6 +25,7 @@ export default [
},
},
rules: {
'@typescript-eslint/no-unused-vars': 'off',
'import/order': ['warn', {
groups: [
'builtin',

View File

@@ -0,0 +1,91 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
export class CreateNoteDraft1736686850345 {
name = 'CreateNoteDraft1736686850345'
async up(queryRunner) {
await queryRunner.query(`
CREATE TABLE "note_draft" (
"id" varchar NOT NULL,
"replyId" varchar NULL,
"renoteId" varchar NULL,
"text" text NULL,
"cw" varchar(512) NULL,
"userId" varchar NOT NULL,
"localOnly" boolean DEFAULT false,
"reactionAcceptance" varchar(64) NULL,
"visibility" varchar NOT NULL,
"fileIds" varchar[] DEFAULT '{}',
"visibleUserIds" varchar[] DEFAULT '{}',
"hashtag" varchar(128) NULL,
"channelId" varchar NULL,
"hasPoll" boolean DEFAULT false,
"pollChoices" varchar(256)[] DEFAULT '{}',
"pollMultiple" boolean NULL,
"pollExpiresAt" TIMESTAMP WITH TIME ZONE NULL,
"pollExpiredAfter" bigint NULL,
PRIMARY KEY ("id")
)`);
await queryRunner.query(`
CREATE INDEX "IDX_NOTE_DRAFT_REPLY_ID" ON "note_draft" ("replyId")
`);
await queryRunner.query(`
CREATE INDEX "IDX_NOTE_DRAFT_RENOTE_ID" ON "note_draft" ("renoteId")
`);
await queryRunner.query(`
CREATE INDEX "IDX_NOTE_DRAFT_USER_ID" ON "note_draft" ("userId")
`);
await queryRunner.query(`
CREATE INDEX "IDX_NOTE_DRAFT_FILE_IDS" ON "note_draft" USING GIN ("fileIds")
`);
await queryRunner.query(`
CREATE INDEX "IDX_NOTE_DRAFT_VISIBLE_USER_IDS" ON "note_draft" USING GIN ("visibleUserIds")
`);
await queryRunner.query(`
CREATE INDEX "IDX_NOTE_DRAFT_CHANNEL_ID" ON "note_draft" ("channelId")
`);
await queryRunner.query(`
ALTER TABLE "note_draft"
ADD CONSTRAINT "FK_NOTE_DRAFT_REPLY_ID" FOREIGN KEY ("replyId") REFERENCES "note"("id") ON DELETE CASCADE
`);
await queryRunner.query(`
ALTER TABLE "note_draft"
ADD CONSTRAINT "FK_NOTE_DRAFT_RENOTE_ID" FOREIGN KEY ("renoteId") REFERENCES "note"("id") ON DELETE CASCADE
`);
await queryRunner.query(`
ALTER TABLE "note_draft"
ADD CONSTRAINT "FK_NOTE_DRAFT_USER_ID" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE
`);
await queryRunner.query(`
ALTER TABLE "note_draft"
ADD CONSTRAINT "FK_NOTE_DRAFT_CHANNEL_ID" FOREIGN KEY ("channelId") REFERENCES "channel"("id") ON DELETE CASCADE
`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "note_draft" DROP CONSTRAINT "FK_NOTE_DRAFT_CHANNEL_ID"`);
await queryRunner.query(`ALTER TABLE "note_draft" DROP CONSTRAINT "FK_NOTE_DRAFT_USER_ID"`);
await queryRunner.query(`ALTER TABLE "note_draft" DROP CONSTRAINT "FK_NOTE_DRAFT_RENOTE_ID"`);
await queryRunner.query(`ALTER TABLE "note_draft" DROP CONSTRAINT "FK_NOTE_DRAFT_REPLY_ID"`);
await queryRunner.query(`DROP INDEX "IDX_NOTE_DRAFT_CHANNEL_ID"`);
await queryRunner.query(`DROP INDEX "IDX_NOTE_DRAFT_VISIBLE_USER_IDS"`);
await queryRunner.query(`DROP INDEX "IDX_NOTE_DRAFT_FILE_IDS"`);
await queryRunner.query(`DROP INDEX "IDX_NOTE_DRAFT_USER_ID"`);
await queryRunner.query(`DROP INDEX "IDX_NOTE_DRAFT_RENOTE_ID"`);
await queryRunner.query(`DROP INDEX "IDX_NOTE_DRAFT_REPLY_ID"`);
await queryRunner.query(`DROP TABLE "note_draft"`);
}
}

View File

@@ -0,0 +1,15 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
export class FixAvatarUrl1750729939704 {
name = 'FixAvatarUrl1750729939704'
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "user" ALTER COLUMN "avatarUrl" TYPE character varying(1024)`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "user" ALTER COLUMN "avatarUrl" TYPE character varying(512)`);
}
}

View File

@@ -0,0 +1,24 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
export class NoActionOnDraftRelation1752502434151 {
name = 'NoActionOnDraftRelation1752502434151'
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "note_draft" DROP CONSTRAINT "FK_NOTE_DRAFT_CHANNEL_ID"`);
await queryRunner.query(`ALTER TABLE "note_draft" DROP CONSTRAINT "FK_NOTE_DRAFT_USER_ID"`);
await queryRunner.query(`ALTER TABLE "note_draft" DROP CONSTRAINT "FK_NOTE_DRAFT_RENOTE_ID"`);
await queryRunner.query(`ALTER TABLE "note_draft" DROP CONSTRAINT "FK_NOTE_DRAFT_REPLY_ID"`);
await queryRunner.query(`ALTER TABLE "note_draft" ADD CONSTRAINT "FK_e4983f28b4b18b03491536052f5" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "note_draft" DROP CONSTRAINT "FK_e4983f28b4b18b03491536052f5"`);
await queryRunner.query(`ALTER TABLE "note_draft" ADD CONSTRAINT "FK_NOTE_DRAFT_REPLY_ID" FOREIGN KEY ("replyId") REFERENCES "note"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "note_draft" ADD CONSTRAINT "FK_NOTE_DRAFT_RENOTE_ID" FOREIGN KEY ("renoteId") REFERENCES "note"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "note_draft" ADD CONSTRAINT "FK_NOTE_DRAFT_USER_ID" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "note_draft" ADD CONSTRAINT "FK_NOTE_DRAFT_CHANNEL_ID" FOREIGN KEY ("channelId") REFERENCES "channel"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
}
}

View File

@@ -0,0 +1,79 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
export class MigrationCleanup1752509043847 {
name = 'MigrationCleanup1752509043847'
async up(queryRunner) {
// 1745378064470-composite-note-index.js created a index ON "note" ("userId", "id" DESC) as IDX_724b311e6f883751f261ebe378 but should be named IDX_a6f649630f55af3888e5a42919
await queryRunner.query(`ALTER INDEX "IDX_724b311e6f883751f261ebe378" RENAME TO "IDX_a6f649630f55af3888e5a42919"`);
// 1713656541000-abuse-report-notification.js generated system_webhook with hand-written SQL with CURRENT_TIMESTAMP as the default value, but its representation in TypeORM is `now()`
// see https://github.com/typeorm/typeorm/blob/f351757a15b9d2bd9d4222c69dcfd2316f46b5d1/src/driver/postgres/PostgresDriver.ts#L1575
await queryRunner.query(`ALTER TABLE "system_webhook" ALTER COLUMN "updatedAt" SET DEFAULT now()`);
// 1702718871541-ffVisibility.js defined a enum type "user_profile_followersVisibility_enum" but it should be "user_profile_followersvisibility_enum" (lowercase 'v') in typeorm
await queryRunner.query(`ALTER TYPE "public"."user_profile_followersVisibility_enum" RENAME TO "user_profile_followersvisibility_enum"`);
// 1713656541000-abuse-report-notification.js generated abuse_report_notification_recipient with hand-written SQL with CURRENT_TIMESTAMP as the default value, but its representation in TypeORM is `now()`
await queryRunner.query(`ALTER TABLE "abuse_report_notification_recipient" ALTER COLUMN "updatedAt" SET DEFAULT now()`);
// 1690796169261-play-visibility.js added visibility column to flash table but it forgot to set NOT NULL constraint
await queryRunner.query(`ALTER TABLE "flash" ALTER COLUMN "visibility" SET NOT NULL`);
// 1736686850345-createNoteDraft.js created note_draft with hand-written SQL but several types and comments are not correctly defined
await queryRunner.query(`CREATE TYPE "public"."note_draft_visibility_enum" AS ENUM('public', 'home', 'followers', 'specified')`);
await queryRunner.query(`ALTER TABLE "note_draft" ALTER COLUMN "id" SET DATA TYPE character varying(32)`);
await queryRunner.query(`ALTER TABLE "note_draft" ALTER COLUMN "replyId" SET DATA TYPE character varying(32)`);
await queryRunner.query(`ALTER TABLE "note_draft" ALTER COLUMN "renoteId" SET DATA TYPE character varying(32)`);
await queryRunner.query(`ALTER TABLE "note_draft" ALTER COLUMN "userId" SET DATA TYPE character varying(32)`);
await queryRunner.query(`ALTER TABLE "note_draft" ALTER COLUMN "channelId" SET DATA TYPE character varying(32)`);
await queryRunner.query(`ALTER TABLE "note_draft" ALTER COLUMN "fileIds" SET DATA TYPE character varying(32) array`);
await queryRunner.query(`ALTER TABLE "note_draft" ALTER COLUMN "visibleUserIds" SET DATA TYPE character varying(32) array`);
await queryRunner.query(`ALTER TABLE "note_draft" ALTER COLUMN "visibility" SET DATA TYPE "public"."note_draft_visibility_enum" USING visibility::note_draft_visibility_enum`);
await queryRunner.query(`COMMENT ON COLUMN "note_draft"."replyId" IS 'The ID of reply target.'`);
await queryRunner.query(`COMMENT ON COLUMN "note_draft"."renoteId" IS 'The ID of renote target.'`);
await queryRunner.query(`COMMENT ON COLUMN "note_draft"."userId" IS 'The ID of author.'`);
await queryRunner.query(`COMMENT ON COLUMN "note_draft"."channelId" IS 'The ID of source channel.'`);
await queryRunner.query(`ALTER TABLE "note_draft" ALTER COLUMN "fileIds" SET NOT NULL`);
await queryRunner.query(`ALTER TABLE "note_draft" ALTER COLUMN "hasPoll" SET NOT NULL`);
await queryRunner.query(`ALTER TABLE "note_draft" ALTER COLUMN "pollChoices" SET NOT NULL`);
await queryRunner.query(`ALTER TABLE "note_draft" ALTER COLUMN "pollMultiple" SET NOT NULL`);
await queryRunner.query(`ALTER TABLE "note_draft" ALTER COLUMN "localOnly" SET NOT NULL`);
await queryRunner.query(`ALTER TABLE "note_draft" ALTER COLUMN "visibleUserIds" SET NOT NULL`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "note_draft" ALTER COLUMN "visibleUserIds" DROP NOT NULL`);
await queryRunner.query(`ALTER TABLE "note_draft" ALTER COLUMN "localOnly" DROP NOT NULL`);
await queryRunner.query(`ALTER TABLE "note_draft" ALTER COLUMN "pollMultiple" DROP NOT NULL`);
await queryRunner.query(`ALTER TABLE "note_draft" ALTER COLUMN "pollChoices" DROP NOT NULL`);
await queryRunner.query(`ALTER TABLE "note_draft" ALTER COLUMN "hasPoll" DROP NOT NULL`);
await queryRunner.query(`ALTER TABLE "note_draft" ALTER COLUMN "fileIds" DROP NOT NULL`);
await queryRunner.query(`COMMENT ON COLUMN "note_draft"."channelId" IS NULL`);
await queryRunner.query(`COMMENT ON COLUMN "note_draft"."userId" IS 'The ID of author.'`);
await queryRunner.query(`COMMENT ON COLUMN "note_draft"."renoteId" IS NULL`);
await queryRunner.query(`COMMENT ON COLUMN "note_draft"."replyId" IS NULL`);
await queryRunner.query(`ALTER TABLE "note_draft" ALTER COLUMN "visibility" SET DATA TYPE varchar`);
await queryRunner.query(`ALTER TABLE "note_draft" ALTER COLUMN "visibleUserIds" SET DATA TYPE varchar[]`);
await queryRunner.query(`ALTER TABLE "note_draft" ALTER COLUMN "fileIds" SET DATA TYPE varchar[]`);
await queryRunner.query(`ALTER TABLE "note_draft" ALTER COLUMN "channelId" SET DATA TYPE varchar`);
await queryRunner.query(`ALTER TABLE "note_draft" ALTER COLUMN "userId" SET DATA TYPE varchar`);
await queryRunner.query(`ALTER TABLE "note_draft" ALTER COLUMN "renoteId" SET DATA TYPE varchar`);
await queryRunner.query(`ALTER TABLE "note_draft" ALTER COLUMN "replyId" SET DATA TYPE varchar`);
await queryRunner.query(`ALTER TABLE "note_draft" ALTER COLUMN "id" SET DATA TYPE varchar`);
await queryRunner.query(`DROP TYPE "public"."note_draft_visibility_enum"`);
await queryRunner.query(`ALTER TABLE "flash" ALTER COLUMN "visibility" DROP NOT NULL`);
await queryRunner.query(`ALTER TABLE "abuse_report_notification_recipient" ALTER COLUMN "updatedAt" SET DEFAULT CURRENT_TIMESTAMP`);
await queryRunner.query(`ALTER TYPE "public"."user_profile_followersvisibility_enum" RENAME TO "user_profile_followersVisibility_enum"`);
await queryRunner.query(`ALTER TABLE "system_webhook" ALTER COLUMN "updatedAt" SET DEFAULT CURRENT_TIMESTAMP`);
await queryRunner.query(`ALTER INDEX "IDX_a6f649630f55af3888e5a42919" RENAME TO "IDX_724b311e6f883751f261ebe378"`);
}
}

View File

@@ -4,7 +4,7 @@
"private": true,
"type": "module",
"engines": {
"node": "^20.10.0 || ^22.0.0"
"node": "^20.18.1 || ^22.0.0"
},
"scripts": {
"start": "node ./built/boot/entry.js",
@@ -33,21 +33,22 @@
"test:fed": "pnpm jest:fed",
"test-and-coverage": "pnpm jest-and-coverage",
"test-and-coverage:e2e": "pnpm build && pnpm build:test && pnpm jest-and-coverage:e2e",
"check-migrations": "node scripts/check_migrations_clean.js",
"generate-api-json": "node ./scripts/generate_api_json.js"
},
"optionalDependencies": {
"@swc/core-android-arm64": "1.3.11",
"@swc/core-darwin-arm64": "1.11.29",
"@swc/core-darwin-x64": "1.11.29",
"@swc/core-darwin-arm64": "1.12.0",
"@swc/core-darwin-x64": "1.12.0",
"@swc/core-freebsd-x64": "1.3.11",
"@swc/core-linux-arm-gnueabihf": "1.11.29",
"@swc/core-linux-arm64-gnu": "1.11.29",
"@swc/core-linux-arm64-musl": "1.11.29",
"@swc/core-linux-x64-gnu": "1.11.29",
"@swc/core-linux-x64-musl": "1.11.29",
"@swc/core-win32-arm64-msvc": "1.11.29",
"@swc/core-win32-ia32-msvc": "1.11.29",
"@swc/core-win32-x64-msvc": "1.11.29",
"@swc/core-linux-arm-gnueabihf": "1.12.0",
"@swc/core-linux-arm64-gnu": "1.12.0",
"@swc/core-linux-arm64-musl": "1.12.0",
"@swc/core-linux-x64-gnu": "1.12.0",
"@swc/core-linux-x64-musl": "1.12.0",
"@swc/core-win32-arm64-msvc": "1.12.0",
"@swc/core-win32-ia32-msvc": "1.12.0",
"@swc/core-win32-x64-msvc": "1.12.0",
"@tensorflow/tfjs": "4.22.0",
"@tensorflow/tfjs-node": "4.22.0",
"bufferutil": "4.0.9",
@@ -67,8 +68,8 @@
"utf-8-validate": "6.0.5"
},
"dependencies": {
"@aws-sdk/client-s3": "3.817.0",
"@aws-sdk/lib-storage": "3.817.0",
"@aws-sdk/client-s3": "3.826.0",
"@aws-sdk/lib-storage": "3.826.0",
"@discordapp/twemoji": "15.1.0",
"@fastify/accepts": "5.0.2",
"@fastify/cookie": "11.0.2",
@@ -80,10 +81,10 @@
"@fastify/view": "10.0.2",
"@misskey-dev/sharp-read-bmp": "1.2.0",
"@misskey-dev/summaly": "5.2.1",
"@napi-rs/canvas": "0.1.70",
"@nestjs/common": "11.1.2",
"@nestjs/core": "11.1.2",
"@nestjs/testing": "11.1.2",
"@napi-rs/canvas": "0.1.71",
"@nestjs/common": "11.1.3",
"@nestjs/core": "11.1.3",
"@nestjs/testing": "11.1.3",
"@peertube/http-signature": "1.7.0",
"@sentry/node": "8.55.0",
"@sentry/profiling-node": "8.55.0",
@@ -91,7 +92,7 @@
"@sinonjs/fake-timers": "11.3.1",
"@smithy/node-http-handler": "2.5.0",
"@swc/cli": "0.7.7",
"@swc/core": "1.11.29",
"@swc/core": "1.12.0",
"@twemoji/parser": "15.1.1",
"@types/redis-info": "3.0.3",
"accepts": "1.3.8",
@@ -101,7 +102,7 @@
"bcryptjs": "2.4.3",
"blurhash": "2.0.5",
"body-parser": "1.20.3",
"bullmq": "5.53.0",
"bullmq": "5.53.2",
"cacheable-lookup": "7.0.0",
"cbor": "9.0.2",
"chalk": "5.4.1",
@@ -117,7 +118,7 @@
"feed": "4.2.2",
"file-type": "19.6.0",
"fluent-ffmpeg": "2.1.3",
"form-data": "4.0.2",
"form-data": "4.0.3",
"got": "14.4.7",
"happy-dom": "16.8.1",
"hpagent": "1.2.0",
@@ -133,9 +134,9 @@
"jsonld": "8.3.3",
"jsrsasign": "11.1.0",
"juice": "11.0.1",
"meilisearch": "0.50.0",
"meilisearch": "0.51.0",
"mfm-js": "0.24.0",
"microformats-parser": "2.0.2",
"microformats-parser": "2.0.3",
"mime-types": "2.1.35",
"misskey-js": "workspace:*",
"misskey-reversi": "workspace:*",
@@ -188,16 +189,16 @@
},
"devDependencies": {
"@jest/globals": "29.7.0",
"@nestjs/platform-express": "10.4.18",
"@sentry/vue": "9.22.0",
"@nestjs/platform-express": "10.4.19",
"@sentry/vue": "9.28.0",
"@simplewebauthn/types": "12.0.0",
"@swc/jest": "0.2.38",
"@types/accepts": "1.3.7",
"@types/archiver": "6.0.3",
"@types/bcryptjs": "2.4.6",
"@types/body-parser": "1.19.5",
"@types/body-parser": "1.19.6",
"@types/color-convert": "2.0.4",
"@types/content-disposition": "0.5.8",
"@types/content-disposition": "0.5.9",
"@types/fluent-ffmpeg": "2.1.27",
"@types/htmlescape": "1.1.3",
"@types/http-link-header": "1.0.7",
@@ -208,12 +209,12 @@
"@types/jsrsasign": "10.5.15",
"@types/mime-types": "2.1.4",
"@types/ms": "0.7.34",
"@types/node": "22.15.21",
"@types/node": "22.15.31",
"@types/nodemailer": "6.4.17",
"@types/oauth": "0.9.6",
"@types/oauth2orize": "1.11.5",
"@types/oauth2orize-pkce": "0.1.2",
"@types/pg": "8.15.2",
"@types/pg": "8.15.4",
"@types/pug": "2.0.10",
"@types/qrcode": "1.5.5",
"@types/random-seed": "0.3.5",
@@ -229,8 +230,8 @@
"@types/vary": "1.1.3",
"@types/web-push": "3.6.4",
"@types/ws": "8.18.1",
"@typescript-eslint/eslint-plugin": "8.32.1",
"@typescript-eslint/parser": "8.32.1",
"@typescript-eslint/eslint-plugin": "8.34.0",
"@typescript-eslint/parser": "8.34.0",
"aws-sdk-client-mock": "4.1.0",
"cross-env": "7.0.3",
"eslint-plugin-import": "2.31.0",

View File

@@ -0,0 +1,26 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
// This script checks if the database migrations has been generated correctly.
import dataSource from '../ormconfig.js';
await dataSource.initialize();
const sqlInMemory = await dataSource.driver.createSchemaBuilder().log();
if (sqlInMemory.upQueries.length > 0 || sqlInMemory.downQueries.length > 0) {
console.error('There are several pending migrations. Please make sure you have generated the migrations correctly, or configured entities class correctly.');
for (const query of sqlInMemory.upQueries) {
console.error(`- ${query.query}`);
}
for (const query of sqlInMemory.downQueries) {
console.error(`- ${query.query}`);
}
process.exit(1);
} else {
console.log('All migrations are clean.');
process.exit(0);
}

View File

@@ -331,6 +331,16 @@ export class ChatService {
await redisPipeline.exec();
}
@bindThis
public async readAllChatMessages(
readerId: MiUser['id'],
): Promise<void> {
const redisPipeline = this.redisClient.pipeline();
// TODO: newUserChatMessageExists とか newRoomChatMessageExists も消したい(けどキーの列挙が必要になって面倒)
redisPipeline.del(`newChatMessagesExists:${readerId}`);
await redisPipeline.exec();
}
@bindThis
public findMessageById(messageId: MiChatMessage['id']) {
return this.chatMessagesRepository.findOneBy({ id: messageId });

View File

@@ -44,6 +44,7 @@ import { ModerationLogService } from './ModerationLogService.js';
import { NoteCreateService } from './NoteCreateService.js';
import { NoteDeleteService } from './NoteDeleteService.js';
import { NotePiningService } from './NotePiningService.js';
import { NoteDraftService } from './NoteDraftService.js';
import { NotificationService } from './NotificationService.js';
import { PollService } from './PollService.js';
import { PushNotificationService } from './PushNotificationService.js';
@@ -118,6 +119,7 @@ import { RenoteMutingEntityService } from './entities/RenoteMutingEntityService.
import { NoteEntityService } from './entities/NoteEntityService.js';
import { NoteFavoriteEntityService } from './entities/NoteFavoriteEntityService.js';
import { NoteReactionEntityService } from './entities/NoteReactionEntityService.js';
import { NoteDraftEntityService } from './entities/NoteDraftEntityService.js';
import { NotificationEntityService } from './entities/NotificationEntityService.js';
import { PageEntityService } from './entities/PageEntityService.js';
import { PageLikeEntityService } from './entities/PageLikeEntityService.js';
@@ -185,6 +187,7 @@ const $ModerationLogService: Provider = { provide: 'ModerationLogService', useEx
const $NoteCreateService: Provider = { provide: 'NoteCreateService', useExisting: NoteCreateService };
const $NoteDeleteService: Provider = { provide: 'NoteDeleteService', useExisting: NoteDeleteService };
const $NotePiningService: Provider = { provide: 'NotePiningService', useExisting: NotePiningService };
const $NoteDraftService: Provider = { provide: 'NoteDraftService', useExisting: NoteDraftService };
const $NotificationService: Provider = { provide: 'NotificationService', useExisting: NotificationService };
const $PollService: Provider = { provide: 'PollService', useExisting: PollService };
const $SystemAccountService: Provider = { provide: 'SystemAccountService', useExisting: SystemAccountService };
@@ -266,6 +269,7 @@ const $RenoteMutingEntityService: Provider = { provide: 'RenoteMutingEntityServi
const $NoteEntityService: Provider = { provide: 'NoteEntityService', useExisting: NoteEntityService };
const $NoteFavoriteEntityService: Provider = { provide: 'NoteFavoriteEntityService', useExisting: NoteFavoriteEntityService };
const $NoteReactionEntityService: Provider = { provide: 'NoteReactionEntityService', useExisting: NoteReactionEntityService };
const $NoteDraftEntityService: Provider = { provide: 'NoteDraftEntityService', useExisting: NoteDraftEntityService };
const $NotificationEntityService: Provider = { provide: 'NotificationEntityService', useExisting: NotificationEntityService };
const $PageEntityService: Provider = { provide: 'PageEntityService', useExisting: PageEntityService };
const $PageLikeEntityService: Provider = { provide: 'PageLikeEntityService', useExisting: PageLikeEntityService };
@@ -335,6 +339,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
NoteCreateService,
NoteDeleteService,
NotePiningService,
NoteDraftService,
NotificationService,
PollService,
SystemAccountService,
@@ -416,6 +421,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
NoteEntityService,
NoteFavoriteEntityService,
NoteReactionEntityService,
NoteDraftEntityService,
NotificationEntityService,
PageEntityService,
PageLikeEntityService,
@@ -481,6 +487,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
$NoteCreateService,
$NoteDeleteService,
$NotePiningService,
$NoteDraftService,
$NotificationService,
$PollService,
$SystemAccountService,
@@ -562,6 +569,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
$NoteEntityService,
$NoteFavoriteEntityService,
$NoteReactionEntityService,
$NoteDraftEntityService,
$NotificationEntityService,
$PageEntityService,
$PageLikeEntityService,
@@ -628,6 +636,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
NoteCreateService,
NoteDeleteService,
NotePiningService,
NoteDraftService,
NotificationService,
PollService,
SystemAccountService,
@@ -708,6 +717,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
NoteEntityService,
NoteFavoriteEntityService,
NoteReactionEntityService,
NoteDraftEntityService,
NotificationEntityService,
PageEntityService,
PageLikeEntityService,
@@ -773,6 +783,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
$NoteCreateService,
$NoteDeleteService,
$NotePiningService,
$NoteDraftService,
$NotificationService,
$PollService,
$SystemAccountService,
@@ -852,6 +863,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
$NoteEntityService,
$NoteFavoriteEntityService,
$NoteReactionEntityService,
$NoteDraftEntityService,
$NotificationEntityService,
$PageEntityService,
$PageLikeEntityService,

View File

@@ -803,14 +803,14 @@ export class DriveService {
await Promise.all(promises);
}
this.deletePostProcess(file, isExpired, deleter);
await this.deletePostProcess(file, isExpired, deleter);
}
@bindThis
private async deletePostProcess(file: MiDriveFile, isExpired = false, deleter?: MiUser) {
// リモートファイル期限切れ削除後は直リンクにする
if (isExpired && file.userHost !== null && file.uri != null) {
this.driveFilesRepository.update(file.id, {
await this.driveFilesRepository.update(file.id, {
isLink: true,
url: file.uri,
thumbnailUrl: null,
@@ -822,7 +822,7 @@ export class DriveService {
webpublicAccessKey: 'webpublic-' + randomUUID(),
});
} else {
this.driveFilesRepository.delete(file.id);
await this.driveFilesRepository.delete(file.id);
}
this.driveChart.update(file, false);

View File

@@ -145,7 +145,10 @@ export class EmailService {
try {
// TODO: htmlサニタイズ
const info = await transporter.sendMail({
from: this.meta.email!,
from: this.meta.name ? {
name: this.meta.name,
address: this.meta.email!,
} : this.meta.email!,
to: to,
subject: subject,
text: text,

View File

@@ -4,8 +4,11 @@
*/
import { Inject, Injectable } from '@nestjs/common';
import { Brackets } from 'typeorm';
import { DI } from '@/di-symbols.js';
import { type FlashsRepository } from '@/models/_.js';
import { type FlashLikesRepository, MiUser, type FlashsRepository } from '@/models/_.js';
import { QueryService } from '@/core/QueryService.js';
import { sqlLikeEscape } from '@/misc/sql-like-escape.js';
/**
* MisskeyPlay関係のService
@@ -15,6 +18,11 @@ export class FlashService {
constructor(
@Inject(DI.flashsRepository)
private flashRepository: FlashsRepository,
@Inject(DI.flashLikesRepository)
private flashLikesRepository: FlashLikesRepository,
private queryService: QueryService,
) {
}
@@ -37,4 +45,43 @@ export class FlashService {
return await builder.getMany();
}
public async myLikes(meId: MiUser['id'], opts: { sinceId?: string, untilId?: string, sinceDate?: number, untilDate?: number, limit?: number, search?: string | null }) {
const query = this.queryService.makePaginationQuery(this.flashLikesRepository.createQueryBuilder('like'), opts.sinceId, opts.untilId, opts.sinceDate, opts.untilDate)
.andWhere('like.userId = :meId', { meId })
.leftJoinAndSelect('like.flash', 'flash');
if (opts.search != null) {
for (const word of opts.search.trim().split(' ')) {
query.andWhere(new Brackets(qb => {
qb.orWhere('flash.title ILIKE :search', { search: `%${sqlLikeEscape(word)}%` });
qb.orWhere('flash.summary ILIKE :search', { search: `%${sqlLikeEscape(word)}%` });
}));
}
}
const likes = await query
.limit(opts.limit)
.getMany();
return likes;
}
public async search(searchQuery: string, opts: { sinceId?: string, untilId?: string, sinceDate?: number, untilDate?: number, limit?: number }) {
const query = this.queryService.makePaginationQuery(this.flashRepository.createQueryBuilder('flash'), opts.sinceId, opts.untilId, opts.sinceDate, opts.untilDate)
.andWhere('flash.visibility = \'public\'');
for (const word of searchQuery.trim().split(' ')) {
query.andWhere(new Brackets(qb => {
qb.orWhere('flash.title ILIKE :search', { search: `%${sqlLikeEscape(word)}%` });
qb.orWhere('flash.summary ILIKE :search', { search: `%${sqlLikeEscape(word)}%` });
}));
}
const result = await query
.limit(opts.limit)
.getMany();
return result;
}
}

View File

@@ -0,0 +1,314 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { Inject, Injectable } from '@nestjs/common';
import { In } from 'typeorm';
import type { noteVisibilities, noteReactionAcceptances } from '@/types.js';
import { DI } from '@/di-symbols.js';
import type { MiNoteDraft, NoteDraftsRepository, MiNote, MiDriveFile, MiChannel, UsersRepository, DriveFilesRepository, NotesRepository, BlockingsRepository, ChannelsRepository } from '@/models/_.js';
import { bindThis } from '@/decorators.js';
import { RoleService } from '@/core/RoleService.js';
import { IdService } from '@/core/IdService.js';
import type { MiLocalUser, MiUser } from '@/models/User.js';
import { IPoll } from '@/models/Poll.js';
import { IdentifiableError } from '@/misc/identifiable-error.js';
import { isRenote, isQuote } from '@/misc/is-renote.js';
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
export type NoteDraftOptions = {
replyId?: MiNote['id'] | null;
renoteId?: MiNote['id'] | null;
text?: string | null;
cw?: string | null;
localOnly?: boolean | null;
reactionAcceptance?: typeof noteReactionAcceptances[number];
visibility?: typeof noteVisibilities[number];
fileIds?: MiDriveFile['id'][];
visibleUserIds?: MiUser['id'][];
hashtag?: string;
channelId?: MiChannel['id'] | null;
poll?: (IPoll & { expiredAfter?: number | null }) | null;
};
@Injectable()
export class NoteDraftService {
constructor(
@Inject(DI.blockingsRepository)
private blockingsRepository: BlockingsRepository,
@Inject(DI.noteDraftsRepository)
private noteDraftsRepository: NoteDraftsRepository,
@Inject(DI.notesRepository)
private notesRepository: NotesRepository,
@Inject(DI.usersRepository)
private usersRepository: UsersRepository,
@Inject(DI.driveFilesRepository)
private driveFilesRepository: DriveFilesRepository,
@Inject(DI.channelsRepository)
private channelsRepository: ChannelsRepository,
private roleService: RoleService,
private idService: IdService,
private noteEntityService: NoteEntityService,
) {
}
@bindThis
public async get(me: MiLocalUser, draftId: MiNoteDraft['id']): Promise<MiNoteDraft | null> {
const draft = await this.noteDraftsRepository.findOneBy({
id: draftId,
userId: me.id,
});
return draft;
}
@bindThis
public async create(me: MiLocalUser, data: NoteDraftOptions): Promise<MiNoteDraft> {
//#region check draft limit
const currentCount = await this.noteDraftsRepository.countBy({
userId: me.id,
});
if (currentCount >= (await this.roleService.getUserPolicies(me.id)).noteDraftLimit) {
throw new IdentifiableError('9ee33bbe-fde3-4c71-9b51-e50492c6b9c8', 'Too many drafts');
}
//#endregion
if (data.poll) {
if (typeof data.poll.expiresAt === 'number') {
if (data.poll.expiresAt < Date.now()) {
throw new IdentifiableError('04da457d-b083-4055-9082-955525eda5a5', 'Cannot create expired poll');
}
} else if (typeof data.poll.expiredAfter === 'number') {
data.poll.expiresAt = new Date(Date.now() + data.poll.expiredAfter);
}
}
const appliedDraft = await this.checkAndSetDraftNoteOptions(me, this.noteDraftsRepository.create(), data);
appliedDraft.id = this.idService.gen();
appliedDraft.userId = me.id;
const draft = this.noteDraftsRepository.save(appliedDraft);
return draft;
}
@bindThis
public async update(me: MiLocalUser, draftId: MiNoteDraft['id'], data: NoteDraftOptions): Promise<MiNoteDraft> {
const draft = await this.noteDraftsRepository.findOneBy({
id: draftId,
userId: me.id,
});
if (draft == null) {
throw new IdentifiableError('49cd6b9d-848e-41ee-b0b9-adaca711a6b1', 'No such note draft');
}
if (data.poll) {
if (typeof data.poll.expiresAt === 'number') {
if (data.poll.expiresAt < Date.now()) {
throw new IdentifiableError('04da457d-b083-4055-9082-955525eda5a5', 'Cannot create expired poll');
}
} else if (typeof data.poll.expiredAfter === 'number') {
data.poll.expiresAt = new Date(Date.now() + data.poll.expiredAfter);
}
}
const appliedDraft = await this.checkAndSetDraftNoteOptions(me, draft, data);
return await this.noteDraftsRepository.save(appliedDraft);
}
@bindThis
public async delete(me: MiLocalUser, draftId: MiNoteDraft['id']): Promise<void> {
const draft = await this.noteDraftsRepository.findOneBy({
id: draftId,
userId: me.id,
});
if (draft == null) {
throw new IdentifiableError('49cd6b9d-848e-41ee-b0b9-adaca711a6b1', 'No such note draft');
}
await this.noteDraftsRepository.delete(draft.id);
}
@bindThis
public async getDraft(me: MiLocalUser, draftId: MiNoteDraft['id']): Promise<MiNoteDraft> {
const draft = await this.noteDraftsRepository.findOneBy({
id: draftId,
userId: me.id,
});
if (draft == null) {
throw new IdentifiableError('49cd6b9d-848e-41ee-b0b9-adaca711a6b1', 'No such note draft');
}
return draft;
}
// 関連エンティティを取得し紐づける部分を共通化する
@bindThis
public async checkAndSetDraftNoteOptions(
me: MiLocalUser,
draft: MiNoteDraft,
data: NoteDraftOptions,
): Promise<MiNoteDraft> {
data.visibility ??= 'public';
data.localOnly ??= false;
if (data.reactionAcceptance === undefined) data.reactionAcceptance = null;
if (data.channelId != null) {
data.visibility = 'public';
data.visibleUserIds = [];
data.localOnly = true;
}
let appliedDraft = draft;
//#region visibleUsers
let visibleUsers: MiUser[] = [];
if (data.visibleUserIds != null) {
visibleUsers = await this.usersRepository.findBy({
id: In(data.visibleUserIds),
});
}
//#endregion
//#region files
let files: MiDriveFile[] = [];
const fileIds = data.fileIds ?? null;
if (fileIds != null) {
files = await this.driveFilesRepository.createQueryBuilder('file')
.where('file.userId = :userId AND file.id IN (:...fileIds)', {
userId: me.id,
fileIds: fileIds,
})
.orderBy('array_position(ARRAY[:...fileIds], "id"::text)')
.setParameters({ fileIds })
.getMany();
if (files.length !== fileIds.length) {
throw new IdentifiableError('b6992544-63e7-67f0-fa7f-32444b1b5306', 'No such drive file');
}
}
//#endregion
//#region renote
let renote: MiNote | null = null;
if (data.renoteId != null) {
renote = await this.notesRepository.findOneBy({ id: data.renoteId });
if (renote == null) {
throw new IdentifiableError('64929870-2540-4d11-af41-3b484d78c956', 'No such renote');
} else if (isRenote(renote) && !isQuote(renote)) {
throw new IdentifiableError('76cc5583-5a14-4ad3-8717-0298507e32db', 'Cannot renote');
}
// Check blocking
if (renote.userId !== me.id) {
const blockExist = await this.blockingsRepository.exists({
where: {
blockerId: renote.userId,
blockeeId: me.id,
},
});
if (blockExist) {
throw new IdentifiableError('075ca298-e6e7-485a-b570-51a128bb5168', 'You have been blocked by the user');
}
}
if (renote.visibility === 'followers' && renote.userId !== me.id) {
// 他人のfollowers noteはreject
throw new IdentifiableError('81eb8188-aea1-4e35-9a8f-3334a3be9855', 'Cannot Renote Due to Visibility');
} else if (renote.visibility === 'specified') {
// specified / direct noteはreject
throw new IdentifiableError('81eb8188-aea1-4e35-9a8f-3334a3be9855', 'Cannot Renote Due to Visibility');
}
if (renote.channelId && renote.channelId !== data.channelId) {
// チャンネルのノートに対しリノート要求がきたとき、チャンネル外へのリノート可否をチェック
// リートのユースケースのうち、チャンネル内→チャンネル外は少数だと考えられるため、JOINはせず必要な時に都度取得する
const renoteChannel = await this.channelsRepository.findOneBy({ id: renote.channelId });
if (renoteChannel == null) {
// リノートしたいノートが書き込まれているチャンネルがない
throw new IdentifiableError('6815399a-6f13-4069-b60d-ed5156249d12', 'No such channel');
} else if (!renoteChannel.allowRenoteToExternal) {
// リノート作成のリクエストだが、対象チャンネルがリノート禁止だった場合
throw new IdentifiableError('ed1952ac-2d26-4957-8b30-2deda76bedf7', 'Cannot Renote to External');
}
}
}
//#endregion
//#region reply
let reply: MiNote | null = null;
if (data.replyId != null) {
// Fetch reply
reply = await this.notesRepository.findOneBy({ id: data.replyId });
if (reply == null) {
throw new IdentifiableError('c4721841-22fc-4bb7-ad3d-897ef1d375b5', 'No such reply');
} else if (isRenote(reply) && !isQuote(reply)) {
throw new IdentifiableError('e6c10b57-2c09-4da3-bd4d-eda05d51d140', 'Cannot reply To Pure Renote');
} else if (!await this.noteEntityService.isVisibleForMe(reply, me.id)) {
throw new IdentifiableError('593c323c-6b6a-4501-a25c-2f36bd2a93d6', 'Cannot reply To Invisible Note');
} else if (reply.visibility === 'specified' && data.visibility !== 'specified') {
throw new IdentifiableError('215dbc76-336c-4d2a-9605-95766ba7dab0', 'Cannot reply To Specified Note With Extended Visibility');
}
// Check blocking
if (reply.userId !== me.id) {
const blockExist = await this.blockingsRepository.exists({
where: {
blockerId: reply.userId,
blockeeId: me.id,
},
});
if (blockExist) {
throw new IdentifiableError('075ca298-e6e7-485a-b570-51a128bb5168', 'You have been blocked by the user');
}
}
}
//#endregion
//#region channel
let channel: MiChannel | null = null;
if (data.channelId != null) {
channel = await this.channelsRepository.findOneBy({ id: data.channelId, isArchived: false });
if (channel == null) {
throw new IdentifiableError('6815399a-6f13-4069-b60d-ed5156249d12', 'No such channel');
}
}
//#endregion
appliedDraft = {
...appliedDraft,
visibility: data.visibility,
cw: data.cw ?? null,
fileIds: fileIds ?? [],
replyId: data.replyId ?? null,
renoteId: data.renoteId ?? null,
channelId: data.channelId ?? null,
text: data.text ?? null,
hashtag: data.hashtag ?? null,
hasPoll: data.poll != null,
pollChoices: data.poll ? data.poll.choices : [],
pollMultiple: data.poll ? data.poll.multiple : false,
pollExpiresAt: data.poll ? data.poll.expiresAt : null,
pollExpiredAfter: data.poll ? data.poll.expiredAfter ?? null : null,
visibleUserIds: data.visibleUserIds ?? [],
localOnly: data.localOnly,
reactionAcceptance: data.reactionAcceptance,
} satisfies MiNoteDraft;
return appliedDraft;
}
}

View File

@@ -66,6 +66,8 @@ export type RolePolicies = {
canImportUserLists: boolean;
chatAvailability: 'available' | 'readonly' | 'unavailable';
uploadableFileTypes: string[];
noteDraftLimit: number;
watermarkAvailable: boolean;
};
export const DEFAULT_POLICIES: RolePolicies = {
@@ -109,6 +111,8 @@ export const DEFAULT_POLICIES: RolePolicies = {
'video/*',
'audio/*',
],
noteDraftLimit: 10,
watermarkAvailable: true,
};
@Injectable()
@@ -430,6 +434,8 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
}
return [...set];
}),
noteDraftLimit: calc('noteDraftLimit', vs => Math.max(...vs)),
watermarkAvailable: calc('watermarkAvailable', vs => vs.some(v => v === true)),
};
}

View File

@@ -93,6 +93,11 @@ export class SignupService {
if (isPreserved) {
throw new Error('USED_USERNAME');
}
const hasProhibitedWords = this.utilityService.isKeyWordIncluded(username.toLowerCase(), this.meta.prohibitedWordsForNameOfUser);
if (hasProhibitedWords) {
throw new Error('USED_USERNAME');
}
}
const keyPair = await new Promise<string[]>((res, rej) =>

View File

@@ -0,0 +1,189 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { Inject, Injectable } from '@nestjs/common';
import { ModuleRef } from '@nestjs/core';
import { EntityNotFoundError } from 'typeorm';
import { DI } from '@/di-symbols.js';
import type { Packed } from '@/misc/json-schema.js';
import { awaitAll } from '@/misc/prelude/await-all.js';
import type { MiUser, MiNote, MiNoteDraft } from '@/models/_.js';
import type { NoteDraftsRepository, ChannelsRepository } from '@/models/_.js';
import { bindThis } from '@/decorators.js';
import { DebounceLoader } from '@/misc/loader.js';
import { IdService } from '@/core/IdService.js';
import type { OnModuleInit } from '@nestjs/common';
import type { UserEntityService } from './UserEntityService.js';
import type { DriveFileEntityService } from './DriveFileEntityService.js';
import type { NoteEntityService } from './NoteEntityService.js';
@Injectable()
export class NoteDraftEntityService implements OnModuleInit {
private userEntityService: UserEntityService;
private driveFileEntityService: DriveFileEntityService;
private idService: IdService;
private noteEntityService: NoteEntityService;
private noteDraftLoader = new DebounceLoader(this.findNoteDraftOrFail);
constructor(
private moduleRef: ModuleRef,
@Inject(DI.noteDraftsRepository)
private noteDraftsRepository: NoteDraftsRepository,
@Inject(DI.channelsRepository)
private channelsRepository: ChannelsRepository,
) {
}
onModuleInit() {
this.userEntityService = this.moduleRef.get('UserEntityService');
this.driveFileEntityService = this.moduleRef.get('DriveFileEntityService');
this.idService = this.moduleRef.get('IdService');
this.noteEntityService = this.moduleRef.get('NoteEntityService');
}
@bindThis
public async packAttachedFiles(fileIds: MiNote['fileIds'], packedFiles: Map<MiNote['fileIds'][number], Packed<'DriveFile'> | null>): Promise<Packed<'DriveFile'>[]> {
const missingIds = [];
for (const id of fileIds) {
if (!packedFiles.has(id)) missingIds.push(id);
}
if (missingIds.length) {
const additionalMap = await this.driveFileEntityService.packManyByIdsMap(missingIds);
for (const [k, v] of additionalMap) {
packedFiles.set(k, v);
}
}
return fileIds.map(id => packedFiles.get(id)).filter(x => x != null);
}
@bindThis
public async pack(
src: MiNoteDraft['id'] | MiNoteDraft,
me?: { id: MiUser['id'] } | null | undefined,
options?: {
detail?: boolean;
skipHide?: boolean;
withReactionAndUserPairCache?: boolean;
_hint_?: {
packedFiles: Map<MiNote['fileIds'][number], Packed<'DriveFile'> | null>;
packedUsers: Map<MiUser['id'], Packed<'UserLite'>>
};
},
): Promise<Packed<'NoteDraft'>> {
const opts = Object.assign({
detail: true,
}, options);
const noteDraft = typeof src === 'object' ? src : await this.noteDraftLoader.load(src);
const text = noteDraft.text;
const channel = noteDraft.channelId
? noteDraft.channel
? noteDraft.channel
: await this.channelsRepository.findOneBy({ id: noteDraft.channelId })
: null;
const packedFiles = options?._hint_?.packedFiles;
const packedUsers = options?._hint_?.packedUsers;
async function nullIfEntityNotFound<T>(promise: Promise<T>): Promise<T | null> {
try {
return await promise;
} catch (err) {
if (err instanceof EntityNotFoundError) {
return null;
}
throw err;
}
}
const packed: Packed<'NoteDraft'> = await awaitAll({
id: noteDraft.id,
createdAt: this.idService.parse(noteDraft.id).date.toISOString(),
userId: noteDraft.userId,
user: packedUsers?.get(noteDraft.userId) ?? this.userEntityService.pack(noteDraft.user ?? noteDraft.userId, me),
text: text,
cw: noteDraft.cw,
visibility: noteDraft.visibility,
localOnly: noteDraft.localOnly,
reactionAcceptance: noteDraft.reactionAcceptance,
visibleUserIds: noteDraft.visibility === 'specified' ? noteDraft.visibleUserIds : undefined,
hashtag: noteDraft.hashtag ?? undefined,
fileIds: noteDraft.fileIds,
files: packedFiles != null ? this.packAttachedFiles(noteDraft.fileIds, packedFiles) : this.driveFileEntityService.packManyByIds(noteDraft.fileIds),
replyId: noteDraft.replyId,
renoteId: noteDraft.renoteId,
channelId: noteDraft.channelId ?? undefined,
channel: channel ? {
id: channel.id,
name: channel.name,
color: channel.color,
isSensitive: channel.isSensitive,
allowRenoteToExternal: channel.allowRenoteToExternal,
userId: channel.userId,
} : undefined,
...(opts.detail ? {
reply: noteDraft.replyId ? nullIfEntityNotFound(this.noteEntityService.pack(noteDraft.replyId, me, {
detail: false,
skipHide: opts.skipHide,
})) : undefined,
renote: noteDraft.renoteId ? nullIfEntityNotFound(this.noteEntityService.pack(noteDraft.renoteId, me, {
detail: true,
skipHide: opts.skipHide,
})) : undefined,
poll: noteDraft.hasPoll ? {
choices: noteDraft.pollChoices,
multiple: noteDraft.pollMultiple,
expiresAt: noteDraft.pollExpiresAt?.toISOString(),
expiredAfter: noteDraft.pollExpiredAfter,
} : undefined,
} : {} ),
});
return packed;
}
@bindThis
public async packMany(
noteDrafts: MiNoteDraft[],
me?: { id: MiUser['id'] } | null | undefined,
options?: {
detail?: boolean;
},
) {
if (noteDrafts.length === 0) return [];
// TODO: 本当は renote とか reply がないのに renoteId とか replyId があったらここで解決しておく
const fileIds = noteDrafts.map(n => [n.fileIds, n.renote?.fileIds, n.reply?.fileIds]).flat(2).filter(x => x != null);
const packedFiles = fileIds.length > 0 ? await this.driveFileEntityService.packManyByIdsMap(fileIds) : new Map();
const users = [
...noteDrafts.map(({ user, userId }) => user ?? userId),
];
const packedUsers = await this.userEntityService.packMany(users, me)
.then(users => new Map(users.map(u => [u.id, u])));
return await Promise.all(noteDrafts.map(n => this.pack(n, me, {
...options,
_hint_: {
packedFiles,
packedUsers,
},
})));
}
@bindThis
private findNoteDraftOrFail(id: string): Promise<MiNoteDraft> {
return this.noteDraftsRepository.findOneOrFail({
where: { id },
relations: ['user'],
});
}
}

View File

@@ -89,5 +89,6 @@ export const DI = {
chatRoomInvitationsRepository: Symbol('chatRoomInvitationsRepository'),
bubbleGameRecordsRepository: Symbol('bubbleGameRecordsRepository'),
reversiGamesRepository: Symbol('reversiGamesRepository'),
noteDraftsRepository: Symbol('noteDraftsRepository'),
//#endregion
};

View File

@@ -72,6 +72,7 @@ import { packedChatRoomSchema } from '@/models/json-schema/chat-room.js';
import { packedChatRoomInvitationSchema } from '@/models/json-schema/chat-room-invitation.js';
import { packedChatRoomMembershipSchema } from '@/models/json-schema/chat-room-membership.js';
import { packedAchievementNameSchema, packedAchievementSchema } from '@/models/json-schema/achievement.js';
import { packedNoteDraftSchema } from '@/models/json-schema/note-draft.js';
export const refs = {
UserLite: packedUserLiteSchema,
@@ -89,6 +90,7 @@ export const refs = {
Announcement: packedAnnouncementSchema,
App: packedAppSchema,
Note: packedNoteSchema,
NoteDraft: packedNoteDraftSchema,
NoteReaction: packedNoteReactionSchema,
NoteFavorite: packedNoteFavoriteSchema,
Notification: packedNotificationSchema,

View File

@@ -22,7 +22,7 @@ export class MiAbuseReportNotificationRecipient {
/**
* 有効かどうか.
*/
@Index()
@Index('IDX_abuse_report_notification_recipient_isActive')
@Column('boolean', {
default: true,
})
@@ -47,7 +47,7 @@ export class MiAbuseReportNotificationRecipient {
/**
* 通知方法.
*/
@Index()
@Index('IDX_abuse_report_notification_recipient_method')
@Column('varchar', {
length: 64,
})
@@ -56,10 +56,11 @@ export class MiAbuseReportNotificationRecipient {
/**
* 通知先のユーザID.
*/
@Index()
@Index('IDX_abuse_report_notification_recipient_userId')
@Column({
...id(),
nullable: true,
default: null,
})
public userId: MiUser['id'] | null;
@@ -75,17 +76,20 @@ export class MiAbuseReportNotificationRecipient {
/**
* 通知先のユーザプロフィール.
*/
@ManyToOne(type => MiUserProfile, {})
@ManyToOne(type => MiUserProfile, {
onDelete: 'CASCADE',
})
@JoinColumn({ name: 'userId', referencedColumnName: 'userId', foreignKeyConstraintName: 'FK_abuse_report_notification_recipient_userId2' })
public userProfile: MiUserProfile | null;
/**
* 通知先のシステムWebhookId.
*/
@Index()
@Index('IDX_abuse_report_notification_recipient_systemWebhookId')
@Column({
...id(),
nullable: true,
default: null,
})
public systemWebhookId: string | null;
@@ -95,6 +99,6 @@ export class MiAbuseReportNotificationRecipient {
@ManyToOne(type => MiSystemWebhook, {
onDelete: 'CASCADE',
})
@JoinColumn()
@JoinColumn({ name: 'systemWebhookId', referencedColumnName: 'id', foreignKeyConstraintName: 'FK_abuse_report_notification_recipient_systemWebhookId' })
public systemWebhook: MiSystemWebhook | null;
}

View File

@@ -8,6 +8,7 @@ import { id } from './util/id.js';
@Entity('emoji')
@Index(['name', 'host'], { unique: true })
@Index('IDX_EMOJI_ROLE_IDS', { synchronize: false }) // GIN for roleIdsThatCanBeUsedThisEmojiAsReaction in production
export class MiEmoji {
@PrimaryColumn(id())
public id: string;
@@ -32,6 +33,7 @@ export class MiEmoji {
@Column('varchar', {
length: 128, nullable: true,
})
@Index('IDX_EMOJI_CATEGORY')
public category: string | null;
@Column('varchar', {

View File

@@ -59,7 +59,7 @@ export class MiMeta {
public maintainerEmail: string | null;
@Column('boolean', {
default: false,
default: true,
})
public disableRegistration: boolean;
@@ -570,7 +570,7 @@ export class MiMeta {
public bannedEmailDomains: string[];
@Column('varchar', {
length: 1024, array: true, default: '{ "admin", "administrator", "root", "system", "maintainer", "host", "mod", "moderator", "owner", "superuser", "staff", "auth", "i", "me", "everyone", "all", "mention", "mentions", "example", "user", "users", "account", "accounts", "official", "help", "helps", "support", "supports", "info", "information", "informations", "announce", "announces", "announcement", "announcements", "notice", "notification", "notifications", "dev", "developer", "developers", "tech", "misskey" }',
length: 1024, array: true, default: ['admin', 'administrator', 'root', 'system', 'maintainer', 'host', 'mod', 'moderator', 'owner', 'superuser', 'staff', 'auth', 'i', 'me', 'everyone', 'all', 'mention', 'mentions', 'example', 'user', 'users', 'account', 'accounts', 'official', 'help', 'helps', 'support', 'supports', 'info', 'information', 'informations', 'announce', 'announces', 'announcement', 'announcements', 'notice', 'notification', 'notifications', 'dev', 'developer', 'developers', 'tech', 'misskey'],
})
public preservedUsernames: string[];
@@ -635,7 +635,7 @@ export class MiMeta {
public urlPreviewMaximumContentLength: number;
@Column('boolean', {
default: true,
default: false,
})
public urlPreviewRequireContentLength: boolean;
@@ -648,6 +648,7 @@ export class MiMeta {
@Column('varchar', {
length: 1024,
nullable: true,
default: null,
})
public urlPreviewUserAgent: string | null;

View File

@@ -4,7 +4,7 @@
*/
import { Entity, Index, JoinColumn, Column, PrimaryColumn, ManyToOne } from 'typeorm';
import { noteVisibilities } from '@/types.js';
import { noteVisibilities, noteReactionAcceptances } from '@/types.js';
import { id } from './util/id.js';
import { MiUser } from './User.js';
import { MiChannel } from './Channel.js';
@@ -20,7 +20,8 @@ import type { MiDriveFile } from './DriveFile.js';
// You should not use `@Index({ concurrent: true })` decorator because database initialization for test will fail
// because it will always run CREATE INDEX in transaction based on decorators.
// Not appending `{ concurrent: true }` to `@Index` will not cause any problem in production,
@Index(['userId', 'id'])
@Index(['userId', 'id']) // Note: this index is ("userId", "id" DESC) in production, but not in test.
@Entity('note')
export class MiNote {
@PrimaryColumn(id())
@@ -96,7 +97,7 @@ export class MiNote {
@Column('varchar', {
length: 64, nullable: true,
})
public reactionAcceptance: 'likeOnly' | 'likeOnlyForRemote' | 'nonSensitiveOnly' | 'nonSensitiveOnlyForLocalLikeOnlyForRemote' | null;
public reactionAcceptance: typeof noteReactionAcceptances[number];
@Column('smallint', {
default: 0,

View File

@@ -0,0 +1,163 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { Entity, Index, JoinColumn, Column, PrimaryColumn, ManyToOne } from 'typeorm';
import { noteVisibilities, noteReactionAcceptances } from '@/types.js';
import { id } from './util/id.js';
import { MiUser } from './User.js';
import { MiChannel } from './Channel.js';
import { MiNote } from './Note.js';
import type { MiDriveFile } from './DriveFile.js';
@Entity('note_draft')
@Index('IDX_NOTE_DRAFT_FILE_IDS', { synchronize: false }) // GIN for fileIds in production
@Index('IDX_NOTE_DRAFT_VISIBLE_USER_IDS', { synchronize: false }) // GIN for visibleUserIds in production
export class MiNoteDraft {
@PrimaryColumn(id())
public id: string;
@Index('IDX_NOTE_DRAFT_REPLY_ID')
@Column({
...id(),
nullable: true,
comment: 'The ID of reply target.',
})
public replyId: MiNote['id'] | null;
// There is a possibility that replyId is not null but reply is null when the reply note is deleted.
@ManyToOne(type => MiNote, {
createForeignKeyConstraints: false,
})
@JoinColumn()
public reply: MiNote | null;
@Index('IDX_NOTE_DRAFT_RENOTE_ID')
@Column({
...id(),
nullable: true,
comment: 'The ID of renote target.',
})
public renoteId: MiNote['id'] | null;
// There is a possibility that renoteId is not null but renote is null when the renote note is deleted.
@ManyToOne(type => MiNote, {
createForeignKeyConstraints: false,
})
@JoinColumn()
public renote: MiNote | null;
// TODO: varcharにしたい(Note.tsと同じ)
@Column('text', {
nullable: true,
})
public text: string | null;
@Column('varchar', {
length: 512, nullable: true,
})
public cw: string | null;
@Index('IDX_NOTE_DRAFT_USER_ID')
@Column({
...id(),
comment: 'The ID of author.',
})
public userId: MiUser['id'];
@ManyToOne(type => MiUser, {
onDelete: 'CASCADE',
})
@JoinColumn()
public user: MiUser | null;
@Column('boolean', {
default: false,
})
public localOnly: boolean;
@Column('varchar', {
length: 64, nullable: true,
})
public reactionAcceptance: typeof noteReactionAcceptances[number];
/**
* public ... 公開
* home ... ホームタイムライン(ユーザーページのタイムライン含む)のみに流す
* followers ... フォロワーのみ
* specified ... visibleUserIds で指定したユーザーのみ
*/
@Column('enum', { enum: noteVisibilities })
public visibility: typeof noteVisibilities[number];
@Index('IDX_NOTE_DRAFT_FILE_IDS', { synchronize: false })
@Column({
...id(),
array: true, default: '{}',
})
public fileIds: MiDriveFile['id'][];
@Index('IDX_NOTE_DRAFT_VISIBLE_USER_IDS', { synchronize: false })
@Column({
...id(),
array: true, default: '{}',
})
public visibleUserIds: MiUser['id'][];
@Column('varchar', {
length: 128, nullable: true,
})
public hashtag: string | null;
@Index('IDX_NOTE_DRAFT_CHANNEL_ID')
@Column({
...id(),
nullable: true,
comment: 'The ID of source channel.',
})
public channelId: MiChannel['id'] | null;
// There is a possibility that channelId is not null but channel is null when the channel is deleted.
// (deleting channel is not implemented so it's not happening now but may happen in the future)
@ManyToOne(type => MiChannel, {
createForeignKeyConstraints: false,
})
@JoinColumn()
public channel: MiChannel | null;
// 以下、Pollについて追加
@Column('boolean', {
default: false,
})
public hasPoll: boolean;
@Column('varchar', {
length: 256, array: true, default: '{}',
})
public pollChoices: string[];
@Column('boolean')
public pollMultiple: boolean;
@Column('timestamp with time zone', {
nullable: true,
})
public pollExpiresAt: Date | null;
@Column('bigint', {
nullable: true,
})
public pollExpiredAfter: number | null;
// ここまで追加
constructor(data: Partial<MiNoteDraft>) {
if (data == null) return;
for (const [k, v] of Object.entries(data)) {
(this as any)[k] = v;
}
}
}

View File

@@ -42,6 +42,7 @@ import {
MiNoteFavorite,
MiNoteReaction,
MiNoteThreadMuting,
MiNoteDraft,
MiPage,
MiPageLike,
MiPasswordResetRequest,
@@ -140,6 +141,12 @@ const $noteReactionsRepository: Provider = {
inject: [DI.db],
};
const $noteDraftsRepository: Provider = {
provide: DI.noteDraftsRepository,
useFactory: (db: DataSource) => db.getRepository(MiNoteDraft).extend(miRepository as MiRepository<MiNoteDraft>),
inject: [DI.db],
};
const $pollsRepository: Provider = {
provide: DI.pollsRepository,
useFactory: (db: DataSource) => db.getRepository(MiPoll).extend(miRepository as MiRepository<MiPoll>),
@@ -542,6 +549,7 @@ const $reversiGamesRepository: Provider = {
$noteFavoritesRepository,
$noteThreadMutingsRepository,
$noteReactionsRepository,
$noteDraftsRepository,
$pollsRepository,
$pollVotesRepository,
$userProfilesRepository,
@@ -618,6 +626,7 @@ const $reversiGamesRepository: Provider = {
$noteFavoritesRepository,
$noteThreadMutingsRepository,
$noteReactionsRepository,
$noteDraftsRepository,
$pollsRepository,
$pollVotesRepository,
$userProfilesRepository,

View File

@@ -120,7 +120,7 @@ export class MiUser {
// avatarId が null になったとしてもこれが null でない可能性があるため、このフィールドを使うときは avatarId の non-null チェックをすること
@Column('varchar', {
length: 512, nullable: true,
length: 1024, nullable: true,
})
public avatarUrl: string | null;

View File

@@ -29,7 +29,7 @@ export class MiUserProfile {
})
public location: string | null;
@Index()
// Note: There's index named IDX_de22cd2b445eee31ae51cdbe99 for SUBSTR("birthday", 6, 5)
@Column('char', {
length: 10, nullable: true,
comment: 'The birthday (YYYY-MM-DD) of the User.',

View File

@@ -55,6 +55,7 @@ import { MiMeta } from '@/models/Meta.js';
import { MiModerationLog } from '@/models/ModerationLog.js';
import { MiMuting } from '@/models/Muting.js';
import { MiNote } from '@/models/Note.js';
import { MiNoteDraft } from '@/models/NoteDraft.js';
import { MiNoteFavorite } from '@/models/NoteFavorite.js';
import { MiNoteReaction } from '@/models/NoteReaction.js';
import { MiNoteThreadMuting } from '@/models/NoteThreadMuting.js';
@@ -188,6 +189,7 @@ export {
MiMuting,
MiRenoteMuting,
MiNote,
MiNoteDraft,
MiNoteFavorite,
MiNoteReaction,
MiNoteThreadMuting,
@@ -266,6 +268,7 @@ export type ModerationLogsRepository = Repository<MiModerationLog> & MiRepositor
export type MutingsRepository = Repository<MiMuting> & MiRepository<MiMuting>;
export type RenoteMutingsRepository = Repository<MiRenoteMuting> & MiRepository<MiRenoteMuting>;
export type NotesRepository = Repository<MiNote> & MiRepository<MiNote>;
export type NoteDraftsRepository = Repository<MiNoteDraft> & MiRepository<MiNoteDraft>;
export type NoteFavoritesRepository = Repository<MiNoteFavorite> & MiRepository<MiNoteFavorite>;
export type NoteReactionsRepository = Repository<MiNoteReaction> & MiRepository<MiNoteReaction>;
export type NoteThreadMutingsRepository = Repository<MiNoteThreadMuting> & MiRepository<MiNoteThreadMuting>;

View File

@@ -51,7 +51,7 @@ export const packedFlashSchema = {
},
likedCount: {
type: 'number',
optional: false, nullable: true,
optional: false, nullable: false,
},
isLiked: {
type: 'boolean',

View File

@@ -0,0 +1,171 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
export const packedNoteDraftSchema = {
type: 'object',
properties: {
id: {
type: 'string',
optional: false, nullable: false,
format: 'id',
example: 'xxxxxxxxxx',
},
createdAt: {
type: 'string',
optional: false, nullable: false,
format: 'date-time',
},
text: {
type: 'string',
optional: false, nullable: true,
},
cw: {
type: 'string',
optional: true, nullable: true,
},
userId: {
type: 'string',
optional: false, nullable: false,
format: 'id',
},
user: {
type: 'object',
ref: 'UserLite',
optional: false, nullable: false,
},
replyId: {
type: 'string',
optional: true, nullable: true,
format: 'id',
example: 'xxxxxxxxxx',
},
renoteId: {
type: 'string',
optional: true, nullable: true,
format: 'id',
example: 'xxxxxxxxxx',
},
reply: {
type: 'object',
optional: true, nullable: true,
ref: 'Note',
description: 'The reply target note contents if exists. If the reply target has been deleted since the draft was created, this will be null while replyId is not null.',
},
renote: {
type: 'object',
optional: true, nullable: true,
ref: 'Note',
description: 'The renote target note contents if exists. If the renote target has been deleted since the draft was created, this will be null while renoteId is not null.',
},
visibility: {
type: 'string',
optional: false, nullable: false,
enum: ['public', 'home', 'followers', 'specified'],
},
visibleUserIds: {
type: 'array',
optional: true, nullable: false,
items: {
type: 'string',
optional: false, nullable: false,
format: 'id',
},
},
fileIds: {
type: 'array',
optional: true, nullable: false,
items: {
type: 'string',
optional: false, nullable: false,
format: 'id',
},
},
files: {
type: 'array',
optional: true, nullable: false,
items: {
type: 'object',
optional: false, nullable: false,
ref: 'DriveFile',
},
},
hashtag: {
type: 'string',
optional: true, nullable: false,
},
poll: {
type: 'object',
optional: true, nullable: true,
properties: {
expiresAt: {
type: 'string',
optional: true, nullable: true,
format: 'date-time',
},
expiredAfter: {
type: 'number',
optional: true, nullable: true,
},
multiple: {
type: 'boolean',
optional: false, nullable: false,
},
choices: {
type: 'array',
optional: false, nullable: false,
items: {
type: 'string',
optional: false, nullable: false,
},
},
},
},
channelId: {
type: 'string',
optional: true, nullable: true,
format: 'id',
example: 'xxxxxxxxxx',
},
channel: {
type: 'object',
optional: true, nullable: true,
properties: {
id: {
type: 'string',
optional: false, nullable: false,
},
name: {
type: 'string',
optional: false, nullable: false,
},
color: {
type: 'string',
optional: false, nullable: false,
},
isSensitive: {
type: 'boolean',
optional: false, nullable: false,
},
allowRenoteToExternal: {
type: 'boolean',
optional: false, nullable: false,
},
userId: {
type: 'string',
optional: false, nullable: true,
},
},
},
localOnly: {
type: 'boolean',
optional: true, nullable: false,
},
reactionAcceptance: {
type: 'string',
optional: false, nullable: true,
enum: ['likeOnly', 'likeOnlyForRemote', 'nonSensitiveOnly', 'nonSensitiveOnlyForLocalLikeOnlyForRemote', null],
},
},
} as const;

View File

@@ -309,6 +309,14 @@ export const packedRolePoliciesSchema = {
optional: false, nullable: false,
enum: ['available', 'readonly', 'unavailable'],
},
noteDraftLimit: {
type: 'integer',
optional: false, nullable: false,
},
watermarkAvailable: {
type: 'boolean',
optional: false, nullable: false,
},
},
} as const;

View File

@@ -45,6 +45,7 @@ import { MiNote } from '@/models/Note.js';
import { MiNoteFavorite } from '@/models/NoteFavorite.js';
import { MiNoteReaction } from '@/models/NoteReaction.js';
import { MiNoteThreadMuting } from '@/models/NoteThreadMuting.js';
import { MiNoteDraft } from '@/models/NoteDraft.js';
import { MiPage } from '@/models/Page.js';
import { MiPageLike } from '@/models/PageLike.js';
import { MiPasswordResetRequest } from '@/models/PasswordResetRequest.js';
@@ -210,6 +211,7 @@ export const entities = [
MiNoteFavorite,
MiNoteReaction,
MiNoteThreadMuting,
MiNoteDraft,
MiPage,
MiPageLike,
MiGalleryPost,

View File

@@ -34,6 +34,11 @@ export class CleanRemoteFilesProcessorService {
let deletedCount = 0;
let cursor: MiDriveFile['id'] | null = null;
const total = await this.driveFilesRepository.countBy({
userHost: Not(IsNull()),
isLink: false,
});
while (true) {
const files = await this.driveFilesRepository.find({
where: {
@@ -58,12 +63,7 @@ export class CleanRemoteFilesProcessorService {
deletedCount += 8;
const total = await this.driveFilesRepository.countBy({
userHost: Not(IsNull()),
isLink: false,
});
job.updateProgress(100 / total * deletedCount);
job.updateProgress(deletedCount * total / 100);
}
this.logger.succ('All cached remote files has been deleted.');

View File

@@ -43,6 +43,10 @@ export class DeleteDriveFilesProcessorService {
let deletedCount = 0;
let cursor: MiDriveFile['id'] | null = null;
const total = await this.driveFilesRepository.countBy({
userId: user.id,
});
while (true) {
const files = await this.driveFilesRepository.find({
where: {
@@ -67,11 +71,7 @@ export class DeleteDriveFilesProcessorService {
deletedCount++;
}
const total = await this.driveFilesRepository.countBy({
userId: user.id,
});
job.updateProgress(deletedCount / total);
job.updateProgress(deletedCount / total * 100);
}
this.logger.succ(`All drive files (${deletedCount}) of ${user.id} has been deleted.`);

View File

@@ -58,6 +58,10 @@ export class ExportBlockingProcessorService {
let exportedCount = 0;
let cursor: MiBlocking['id'] | null = null;
const total = await this.blockingsRepository.countBy({
blockerId: user.id,
});
while (true) {
const blockings = await this.blockingsRepository.find({
where: {
@@ -97,11 +101,7 @@ export class ExportBlockingProcessorService {
exportedCount++;
}
const total = await this.blockingsRepository.countBy({
blockerId: user.id,
});
job.updateProgress(exportedCount / total);
job.updateProgress(exportedCount / total * 100);
}
stream.end();

View File

@@ -95,6 +95,10 @@ export class ExportClipsProcessorService {
let exportedClipsCount = 0;
let cursor: MiClip['id'] | null = null;
const total = await this.clipsRepository.countBy({
userId: user.id,
});
while (true) {
const clips = await this.clipsRepository.find({
where: {
@@ -126,11 +130,7 @@ export class ExportClipsProcessorService {
exportedClipsCount++;
}
const total = await this.clipsRepository.countBy({
userId: user.id,
});
job.updateProgress(exportedClipsCount / total);
job.updateProgress(exportedClipsCount / total * 100);
}
}

View File

@@ -78,6 +78,10 @@ export class ExportFavoritesProcessorService {
let exportedFavoritesCount = 0;
let cursor: MiNoteFavorite['id'] | null = null;
const total = await this.noteFavoritesRepository.countBy({
userId: user.id,
});
while (true) {
const favorites = await this.noteFavoritesRepository.find({
where: {
@@ -109,11 +113,7 @@ export class ExportFavoritesProcessorService {
exportedFavoritesCount++;
}
const total = await this.noteFavoritesRepository.countBy({
userId: user.id,
});
job.updateProgress(exportedFavoritesCount / total);
job.updateProgress(exportedFavoritesCount / total * 100);
}
await write(']');

View File

@@ -58,6 +58,10 @@ export class ExportMutingProcessorService {
let exportedCount = 0;
let cursor: MiMuting['id'] | null = null;
const total = await this.mutingsRepository.countBy({
muterId: user.id,
});
while (true) {
const mutes = await this.mutingsRepository.find({
where: {
@@ -98,11 +102,7 @@ export class ExportMutingProcessorService {
exportedCount++;
}
const total = await this.mutingsRepository.countBy({
muterId: user.id,
});
job.updateProgress(exportedCount / total);
job.updateProgress(exportedCount / total * 100);
}
stream.end();

View File

@@ -37,6 +37,8 @@ class NoteStream extends ReadableStream<Record<string, unknown>> {
let exportedNotesCount = 0;
let cursor: MiNote['id'] | null = null;
const totalPromise = notesRepository.countBy({ userId });
const serialize = (
note: MiNote,
poll: MiPoll | null,
@@ -88,8 +90,8 @@ class NoteStream extends ReadableStream<Record<string, unknown>> {
exportedNotesCount++;
}
const total = await notesRepository.countBy({ userId });
job.updateProgress(exportedNotesCount / total);
const total = await totalPromise;
job.updateProgress(exportedNotesCount / total * 100);
},
});
}

View File

@@ -482,9 +482,19 @@ export class ActivityPubServerService {
return true;
},
dbFallback: async (untilId, sinceId, limit) => {
return await this.getUserNotesFromDb(sinceId, untilId, limit, user.id);
return await this.getUserNotesFromDb({
untilId,
sinceId,
limit,
userId: user.id,
});
},
}) : await this.getUserNotesFromDb(sinceId ?? null, untilId ?? null, limit, user.id);
}) : await this.getUserNotesFromDb({
untilId: untilId ?? null,
sinceId: sinceId ?? null,
limit,
userId: user.id,
});
if (sinceId) notes.reverse();
@@ -523,16 +533,21 @@ 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 })
private async getUserNotesFromDb(ps: {
untilId: string | null,
sinceId: string | null,
limit: number,
userId: MiUser['id'],
}) {
return await this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), ps.sinceId, ps.untilId)
.andWhere('note.userId = :userId', { userId: ps.userId })
.andWhere(new Brackets(qb => {
qb
.where('note.visibility = \'public\'')
.orWhere('note.visibility = \'home\'');
}))
.andWhere('note.localOnly = FALSE')
.limit(limit)
.limit(ps.limit)
.getMany();
}

View File

@@ -129,7 +129,8 @@ export class SignupApiService {
let ticket: MiRegistrationTicket | null = null;
if (this.meta.disableRegistration) {
// テスト時はこの機構は障害となるため無効にする
if (process.env.NODE_ENV !== 'test' && this.meta.disableRegistration) {
if (invitationCode == null || typeof invitationCode !== 'string') {
reply.code(400);
return;

View File

@@ -168,6 +168,7 @@ export * as 'clips/update' from './endpoints/clips/update.js';
export * as 'drive' from './endpoints/drive.js';
export * as 'drive/files' from './endpoints/drive/files.js';
export * as 'drive/files/attached-notes' from './endpoints/drive/files/attached-notes.js';
export * as 'drive/files/attached-chat-messages' from './endpoints/drive/files/attached-chat-messages.js';
export * as 'drive/files/check-existence' from './endpoints/drive/files/check-existence.js';
export * as 'drive/files/create' from './endpoints/drive/files/create.js';
export * as 'drive/files/delete' from './endpoints/drive/files/delete.js';
@@ -208,6 +209,7 @@ export * as 'flash/my-likes' from './endpoints/flash/my-likes.js';
export * as 'flash/show' from './endpoints/flash/show.js';
export * as 'flash/unlike' from './endpoints/flash/unlike.js';
export * as 'flash/update' from './endpoints/flash/update.js';
export * as 'flash/search' from './endpoints/flash/search.js';
export * as 'following/create' from './endpoints/following/create.js';
export * as 'following/delete' from './endpoints/following/delete.js';
export * as 'following/invalidate' from './endpoints/following/invalidate.js';
@@ -307,6 +309,11 @@ export * as 'notes/clips' from './endpoints/notes/clips.js';
export * as 'notes/conversation' from './endpoints/notes/conversation.js';
export * as 'notes/create' from './endpoints/notes/create.js';
export * as 'notes/delete' from './endpoints/notes/delete.js';
export * as 'notes/drafts/list' from './endpoints/notes/drafts/list.js';
export * as 'notes/drafts/create' from './endpoints/notes/drafts/create.js';
export * as 'notes/drafts/delete' from './endpoints/notes/drafts/delete.js';
export * as 'notes/drafts/update' from './endpoints/notes/drafts/update.js';
export * as 'notes/drafts/count' from './endpoints/notes/drafts/count.js';
export * as 'notes/favorites/create' from './endpoints/notes/favorites/create.js';
export * as 'notes/favorites/delete' from './endpoints/notes/favorites/delete.js';
export * as 'notes/featured' from './endpoints/notes/featured.js';
@@ -428,4 +435,5 @@ export * as 'chat/rooms/invitations/ignore' from './endpoints/chat/rooms/invitat
export * as 'chat/rooms/invitations/inbox' from './endpoints/chat/rooms/invitations/inbox.js';
export * as 'chat/rooms/invitations/outbox' from './endpoints/chat/rooms/invitations/outbox.js';
export * as 'chat/history' from './endpoints/chat/history.js';
export * as 'chat/read-all' from './endpoints/chat/read-all.js';
export * as 'v2/admin/emoji/list' from './endpoints/v2/admin/emoji/list.js';

View File

@@ -98,6 +98,8 @@ export const paramDef = {
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
sinceId: { type: 'string', format: 'misskey:id' },
untilId: { type: 'string', format: 'misskey:id' },
sinceDate: { type: 'integer' },
untilDate: { type: 'integer' },
state: { type: 'string', nullable: true, default: null },
reporterOrigin: { type: 'string', enum: ['combined', 'local', 'remote'], default: 'combined' },
targetUserOrigin: { type: 'string', enum: ['combined', 'local', 'remote'], default: 'combined' },
@@ -115,7 +117,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
private queryService: QueryService,
) {
super(meta, paramDef, async (ps, me) => {
const query = this.queryService.makePaginationQuery(this.abuseUserReportsRepository.createQueryBuilder('report'), ps.sinceId, ps.untilId);
const query = this.queryService.makePaginationQuery(this.abuseUserReportsRepository.createQueryBuilder('report'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate);
switch (ps.state) {
case 'resolved': query.andWhere('report.resolved = TRUE'); break;

View File

@@ -34,6 +34,8 @@ export const paramDef = {
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
sinceId: { type: 'string', format: 'misskey:id' },
untilId: { type: 'string', format: 'misskey:id' },
sinceDate: { type: 'integer' },
untilDate: { type: 'integer' },
publishing: { type: 'boolean', default: null, nullable: true },
},
required: [],
@@ -48,7 +50,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
private queryService: QueryService,
) {
super(meta, paramDef, async (ps, me) => {
const query = this.queryService.makePaginationQuery(this.adsRepository.createQueryBuilder('ad'), ps.sinceId, ps.untilId);
const query = this.queryService.makePaginationQuery(this.adsRepository.createQueryBuilder('ad'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate);
if (ps.publishing === true) {
query.andWhere('ad.expiresAt > :now', { now: new Date() }).andWhere('ad.startsAt <= :now', { now: new Date() });
} else if (ps.publishing === false) {

View File

@@ -68,6 +68,8 @@ export const paramDef = {
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
sinceId: { type: 'string', format: 'misskey:id' },
untilId: { type: 'string', format: 'misskey:id' },
sinceDate: { type: 'integer' },
untilDate: { type: 'integer' },
userId: { type: 'string', format: 'misskey:id', nullable: true },
status: { type: 'string', enum: ['all', 'active', 'archived'], default: 'active' },
},
@@ -87,7 +89,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
private idService: IdService,
) {
super(meta, paramDef, async (ps, me) => {
const query = this.queryService.makePaginationQuery(this.announcementsRepository.createQueryBuilder('announcement'), ps.sinceId, ps.untilId);
const query = this.queryService.makePaginationQuery(this.announcementsRepository.createQueryBuilder('announcement'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate);
if (ps.status === 'archived') {
query.andWhere('announcement.isActive = false');

View File

@@ -71,6 +71,8 @@ export const paramDef = {
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
sinceId: { type: 'string', format: 'misskey:id' },
untilId: { type: 'string', format: 'misskey:id' },
sinceDate: { type: 'integer' },
untilDate: { type: 'integer' },
userId: { type: 'string', format: 'misskey:id', nullable: true },
},
required: [],

View File

@@ -34,6 +34,8 @@ export const paramDef = {
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
sinceId: { type: 'string', format: 'misskey:id' },
untilId: { type: 'string', format: 'misskey:id' },
sinceDate: { type: 'integer' },
untilDate: { type: 'integer' },
userId: { type: 'string', format: 'misskey:id', nullable: true },
type: { type: 'string', nullable: true, pattern: /^[a-zA-Z0-9\/\-*]+$/.toString().slice(1, -1) },
origin: { type: 'string', enum: ['combined', 'local', 'remote'], default: 'local' },
@@ -57,7 +59,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
private queryService: QueryService,
) {
super(meta, paramDef, async (ps, me) => {
const query = this.queryService.makePaginationQuery(this.driveFilesRepository.createQueryBuilder('file'), ps.sinceId, ps.untilId);
const query = this.queryService.makePaginationQuery(this.driveFilesRepository.createQueryBuilder('file'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate);
if (ps.userId) {
query.andWhere('file.userId = :userId', { userId: ps.userId });

View File

@@ -74,6 +74,8 @@ export const paramDef = {
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
sinceId: { type: 'string', format: 'misskey:id' },
untilId: { type: 'string', format: 'misskey:id' },
sinceDate: { type: 'integer' },
untilDate: { type: 'integer' },
},
required: [],
} as const;
@@ -89,7 +91,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
private emojiEntityService: EmojiEntityService,
) {
super(meta, paramDef, async (ps, me) => {
const q = this.queryService.makePaginationQuery(this.emojisRepository.createQueryBuilder('emoji'), ps.sinceId, ps.untilId);
const q = this.queryService.makePaginationQuery(this.emojisRepository.createQueryBuilder('emoji'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate);
if (ps.host == null) {
q.andWhere('emoji.host IS NOT NULL');

View File

@@ -68,6 +68,8 @@ export const paramDef = {
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
sinceId: { type: 'string', format: 'misskey:id' },
untilId: { type: 'string', format: 'misskey:id' },
sinceDate: { type: 'integer' },
untilDate: { type: 'integer' },
},
required: [],
} as const;
@@ -82,7 +84,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
private queryService: QueryService,
) {
super(meta, paramDef, async (ps, me) => {
const q = this.queryService.makePaginationQuery(this.emojisRepository.createQueryBuilder('emoji'), ps.sinceId, ps.untilId)
const q = this.queryService.makePaginationQuery(this.emojisRepository.createQueryBuilder('emoji'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
.andWhere('emoji.host IS NULL');
let emojis: MiEmoji[];

View File

@@ -49,6 +49,8 @@ export const paramDef = {
roleId: { type: 'string', format: 'misskey:id' },
sinceId: { type: 'string', format: 'misskey:id' },
untilId: { type: 'string', format: 'misskey:id' },
sinceDate: { type: 'integer' },
untilDate: { type: 'integer' },
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
},
required: ['roleId'],
@@ -76,7 +78,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
throw new ApiError(meta.errors.noSuchRole);
}
const query = this.queryService.makePaginationQuery(this.roleAssignmentsRepository.createQueryBuilder('assign'), ps.sinceId, ps.untilId)
const query = this.queryService.makePaginationQuery(this.roleAssignmentsRepository.createQueryBuilder('assign'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
.andWhere('assign.roleId = :roleId', { roleId: role.id })
.andWhere(new Brackets(qb => {
qb

View File

@@ -9,6 +9,7 @@ import type { ModerationLogsRepository } from '@/models/_.js';
import { QueryService } from '@/core/QueryService.js';
import { DI } from '@/di-symbols.js';
import { ModerationLogEntityService } from '@/core/entities/ModerationLogEntityService.js';
import { sqlLikeEscape } from '@/misc/sql-like-escape.js';
export const meta = {
tags: ['admin'],
@@ -63,8 +64,11 @@ export const paramDef = {
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
sinceId: { type: 'string', format: 'misskey:id' },
untilId: { type: 'string', format: 'misskey:id' },
sinceDate: { type: 'integer' },
untilDate: { type: 'integer' },
type: { type: 'string', nullable: true },
userId: { type: 'string', format: 'misskey:id', nullable: true },
search: { type: 'string', nullable: true },
},
required: [],
} as const;
@@ -79,19 +83,24 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
private queryService: QueryService,
) {
super(meta, paramDef, async (ps, me) => {
const query = this.queryService.makePaginationQuery(this.moderationLogsRepository.createQueryBuilder('report'), ps.sinceId, ps.untilId);
const query = this.queryService.makePaginationQuery(this.moderationLogsRepository.createQueryBuilder('log'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate);
if (ps.type != null) {
query.andWhere('report.type = :type', { type: ps.type });
query.andWhere('log.type = :type', { type: ps.type });
}
if (ps.userId != null) {
query.andWhere('report.userId = :userId', { userId: ps.userId });
query.andWhere('log.userId = :userId', { userId: ps.userId });
}
const reports = await query.limit(ps.limit).getMany();
if (ps.search != null) {
const escapedSearch = sqlLikeEscape(ps.search);
query.andWhere('log.info::text ILIKE :search', { search: `%${escapedSearch}%` });
}
return await this.moderationLogEntityService.packMany(reports);
const logs = await query.limit(ps.limit).getMany();
return await this.moderationLogEntityService.packMany(logs);
});
}
}

View File

@@ -33,6 +33,8 @@ export const paramDef = {
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
sinceId: { type: 'string', format: 'misskey:id' },
untilId: { type: 'string', format: 'misskey:id' },
sinceDate: { type: 'integer' },
untilDate: { type: 'integer' },
isActive: { type: 'boolean', default: true },
},
required: [],
@@ -48,7 +50,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
private announcementEntityService: AnnouncementEntityService,
) {
super(meta, paramDef, async (ps, me) => {
const query = this.queryService.makePaginationQuery(this.announcementsRepository.createQueryBuilder('announcement'), ps.sinceId, ps.untilId)
const query = this.queryService.makePaginationQuery(this.announcementsRepository.createQueryBuilder('announcement'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
.andWhere('announcement.isActive = :isActive', { isActive: ps.isActive })
.andWhere(new Brackets(qb => {
if (me) qb.orWhere('announcement.userId = :meId', { meId: me.id });

View File

@@ -34,6 +34,8 @@ export const paramDef = {
limit: { type: 'integer', minimum: 1, maximum: 100, default: 30 },
sinceId: { type: 'string', format: 'misskey:id' },
untilId: { type: 'string', format: 'misskey:id' },
sinceDate: { type: 'integer' },
untilDate: { type: 'integer' },
},
required: [],
} as const;
@@ -48,7 +50,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
private queryService: QueryService,
) {
super(meta, paramDef, async (ps, me) => {
const query = this.queryService.makePaginationQuery(this.blockingsRepository.createQueryBuilder('blocking'), ps.sinceId, ps.untilId)
const query = this.queryService.makePaginationQuery(this.blockingsRepository.createQueryBuilder('blocking'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
.andWhere('blocking.blockerId = :meId', { meId: me.id });
const blockings = await query

View File

@@ -33,6 +33,8 @@ export const paramDef = {
properties: {
sinceId: { type: 'string', format: 'misskey:id' },
untilId: { type: 'string', format: 'misskey:id' },
sinceDate: { type: 'integer' },
untilDate: { type: 'integer' },
limit: { type: 'integer', minimum: 1, maximum: 100, default: 5 },
},
required: [],
@@ -53,8 +55,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
this.channelFollowingsRepository.createQueryBuilder(),
ps.sinceId,
ps.untilId,
null,
null,
ps.sinceDate,
ps.untilDate,
'followeeId',
)
.andWhere({ followerId: me.id });

View File

@@ -33,6 +33,8 @@ export const paramDef = {
properties: {
sinceId: { type: 'string', format: 'misskey:id' },
untilId: { type: 'string', format: 'misskey:id' },
sinceDate: { type: 'integer' },
untilDate: { type: 'integer' },
limit: { type: 'integer', minimum: 1, maximum: 100, default: 5 },
},
required: [],
@@ -48,7 +50,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
private queryService: QueryService,
) {
super(meta, paramDef, async (ps, me) => {
const query = this.queryService.makePaginationQuery(this.channelsRepository.createQueryBuilder('channel'), ps.sinceId, ps.untilId)
const query = this.queryService.makePaginationQuery(this.channelsRepository.createQueryBuilder('channel'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
.andWhere('channel.isArchived = FALSE')
.andWhere({ userId: me.id });

View File

@@ -35,6 +35,8 @@ export const paramDef = {
type: { type: 'string', enum: ['nameAndDescription', 'nameOnly'], default: 'nameAndDescription' },
sinceId: { type: 'string', format: 'misskey:id' },
untilId: { type: 'string', format: 'misskey:id' },
sinceDate: { type: 'integer' },
untilDate: { type: 'integer' },
limit: { type: 'integer', minimum: 1, maximum: 100, default: 5 },
},
required: ['query'],
@@ -50,7 +52,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
private queryService: QueryService,
) {
super(meta, paramDef, async (ps, me) => {
const query = this.queryService.makePaginationQuery(this.channelsRepository.createQueryBuilder('channel'), ps.sinceId, ps.untilId)
const query = this.queryService.makePaginationQuery(this.channelsRepository.createQueryBuilder('channel'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
.andWhere('channel.isArchived = FALSE');
if (ps.query !== '') {

View File

@@ -9,6 +9,7 @@ import { DI } from '@/di-symbols.js';
import { ChatService } from '@/core/ChatService.js';
import { ChatEntityService } from '@/core/entities/ChatEntityService.js';
import { ApiError } from '@/server/api/error.js';
import { IdService } from '@/core/IdService.js';
export const meta = {
tags: ['chat'],
@@ -42,6 +43,8 @@ export const paramDef = {
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
sinceId: { type: 'string', format: 'misskey:id' },
untilId: { type: 'string', format: 'misskey:id' },
sinceDate: { type: 'integer' },
untilDate: { type: 'integer' },
roomId: { type: 'string', format: 'misskey:id' },
},
required: ['roomId'],
@@ -52,8 +55,12 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
constructor(
private chatEntityService: ChatEntityService,
private chatService: ChatService,
private idService: IdService,
) {
super(meta, paramDef, async (ps, me) => {
const untilId = ps.untilId ?? (ps.untilDate ? this.idService.gen(ps.untilDate!) : null);
const sinceId = ps.sinceId ?? (ps.sinceDate ? this.idService.gen(ps.sinceDate!) : null);
await this.chatService.checkChatAvailability(me.id, 'read');
const room = await this.chatService.findRoomById(ps.roomId);
@@ -65,7 +72,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
throw new ApiError(meta.errors.noSuchRoom);
}
const messages = await this.chatService.roomTimeline(room.id, ps.limit, ps.sinceId, ps.untilId);
const messages = await this.chatService.roomTimeline(room.id, ps.limit, sinceId, untilId);
this.chatService.readRoomChatMessage(me.id, room.id);

View File

@@ -10,6 +10,7 @@ import { GetterService } from '@/server/api/GetterService.js';
import { ChatService } from '@/core/ChatService.js';
import { ChatEntityService } from '@/core/entities/ChatEntityService.js';
import { ApiError } from '@/server/api/error.js';
import { IdService } from '@/core/IdService.js';
export const meta = {
tags: ['chat'],
@@ -43,6 +44,8 @@ export const paramDef = {
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
sinceId: { type: 'string', format: 'misskey:id' },
untilId: { type: 'string', format: 'misskey:id' },
sinceDate: { type: 'integer' },
untilDate: { type: 'integer' },
userId: { type: 'string', format: 'misskey:id' },
},
required: ['userId'],
@@ -54,8 +57,12 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
private chatEntityService: ChatEntityService,
private chatService: ChatService,
private getterService: GetterService,
private idService: IdService,
) {
super(meta, paramDef, async (ps, me) => {
const untilId = ps.untilId ?? (ps.untilDate ? this.idService.gen(ps.untilDate!) : null);
const sinceId = ps.sinceId ?? (ps.sinceDate ? this.idService.gen(ps.sinceDate!) : null);
await this.chatService.checkChatAvailability(me.id, 'read');
const other = await this.getterService.getUser(ps.userId).catch(err => {
@@ -63,7 +70,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
throw err;
});
const messages = await this.chatService.userTimeline(me.id, other.id, ps.limit, ps.sinceId, ps.untilId);
const messages = await this.chatService.userTimeline(me.id, other.id, ps.limit, sinceId, untilId);
this.chatService.readUserChatMessage(me.id, other.id);

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