Compare commits

..

290 Commits

Author SHA1 Message Date
syuilo
c20311b8a7 Merge branch 'develop' 2022-07-09 18:32:55 +09:00
syuilo
111d4d0149 12.112.3 2022-07-09 18:32:45 +09:00
syuilo
49012f8352 update summaly 2022-07-09 18:23:21 +09:00
MeiMei
53e54c22fa Fix Attempts to update all notifications (#8974)
* Fix massive update notification parameters

* CHANGELOG

* CHANGELOG
2022-07-09 18:18:39 +09:00
syuilo
75d516011b enhance: make active email validation configurable 2022-07-09 15:05:55 +09:00
syuilo
522ddba3d7 enhance(server): tweak identicon generation 2022-07-09 13:22:35 +09:00
syuilo
fb14ac50b8 Merge branch 'develop' 2022-07-08 17:34:53 +09:00
syuilo
4ac75243e5 12.112.2 2022-07-08 17:34:44 +09:00
MeiMei
417e75b470 DockerでAlpineではなくDebianを使用するように (#8966)
* Debian

* CHANGELOG

* Update CHANGELOG
2022-07-08 17:17:21 +09:00
syuilo
481783606f Update CHANGELOG.md 2022-07-08 11:27:49 +09:00
syuilo
3b71f985a5 Update CHANGELOG.md 2022-07-08 11:24:12 +09:00
syuilo
9a58b4160b Update CHANGELOG.md 2022-07-08 11:21:14 +09:00
syuilo
207d7e0478 fix test 2022-07-08 11:21:11 +09:00
syuilo
84d984bd31 Merge branch 'develop' 2022-07-07 21:23:03 +09:00
syuilo
4bff55231f 12.112.1 2022-07-07 21:22:43 +09:00
syuilo
0890253b4c 12.112.0 2022-07-07 21:21:36 +09:00
Johann150
a1b8587ab2 enhance: show recipients of notes with specified visibility (#8949)
* enhance: reusable visibility component

* rename renote tooltip component

The tooltip that is used for renotes can be used in other cases as well.

* add tooltip for specified recipients

* add changelog entry

* Update visibility.vue

Co-authored-by: syuilo <Syuilotan@yahoo.co.jp>
2022-07-07 21:17:47 +09:00
syuilo
e560601815 feat: auto nsfw detection (#8840)
* feat: auto nsfw detection

* ✌️

* Update ja-JP.yml

* Update ja-JP.yml

* ポルノ判定のしきい値を高めに

* エラーハンドリングちゃんとした

* Update ja-JP.yml

* 感度設定を強化

* refactor

* feat: add video support for auto nsfw detection

* rename: image -> media

* .js

* fix: add missing error handling

* fix: use valid pathname instead of using filename due to invalid usage

* perf(nsfw-detection): decode frames

* disable detection of video for some reasons

* perf(nsfw-detection): streamify detection process for video

* disable disallowUploadWhenPredictedAsPorn option

* fix(nsfw-detection): improve reliability

* fix(nsfw-detection): use Math.ceil instead of Math.round

* perf(nsfw-detection): delete tmp frames after used

* fix(nsfw-detection): FSWatcher does not emit ready event

* perf(nsfw-detection): skip black frames

* refactor: strip exists check

* Update package.json

* めっちゃ変えた

* lint

* Update COPYING

* オプションで動画解析できるように

* Update yarn.lock

* Update CHANGELOG.md

Co-authored-by: Acid Chicken (硫酸鶏) <root@acid-chicken.com>
2022-07-07 21:06:37 +09:00
syuilo
010db2515c New Crowdin updates (#8950)
* 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)
2022-07-07 21:01:45 +09:00
syuilo
a785f1f933 chore(client): tweak ui 2022-07-07 21:00:42 +09:00
syuilo
c0eba65527 chore(client): tweak ui 2022-07-07 20:19:50 +09:00
syuilo
15a9a4b119 Merge branch 'develop' of https://github.com/misskey-dev/misskey into develop 2022-07-07 19:08:21 +09:00
syuilo
da239b8362 chore(server): tweak api for admin 2022-07-07 19:08:18 +09:00
dependabot[bot]
10f7e976ee chore(deps): bump moment from 2.29.3 to 2.29.4 in /packages/backend (#8958)
Bumps [moment](https://github.com/moment/moment) from 2.29.3 to 2.29.4.
- [Release notes](https://github.com/moment/moment/releases)
- [Changelog](https://github.com/moment/moment/blob/develop/CHANGELOG.md)
- [Commits](https://github.com/moment/moment/compare/2.29.3...2.29.4)

---
updated-dependencies:
- dependency-name: moment
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-07-07 18:29:42 +09:00
syuilo
95b966474f 12.112.0-beta.21 2022-07-07 18:28:54 +09:00
syuilo
3ffe674e80 update deps 2022-07-07 18:28:43 +09:00
syuilo
423e7692db chore(server): tweak api for admin 2022-07-07 18:09:50 +09:00
syuilo
a279d50212 chore(client): tweak ui 2022-07-07 18:06:34 +09:00
syuilo
9426f37c3e chore(client): tweak ui 2022-07-07 17:55:47 +09:00
syuilo
37bc81595a Merge branch 'develop' of https://github.com/misskey-dev/misskey into develop 2022-07-07 17:36:45 +09:00
Kainoa Kanter
a23f59b996 enhance: Styled error screen (#8946)
* Styled error screen

* Make details margin auto

* Update boot.css

* Replace fontawesome with tabler svg

* Remove hr

* Add new style to flush screen

* Rename to `error.css`

* Fix

* Update base.pug

* Finally fix!

* Wrap details in `<code>`

* Add style to flush

* Fix

* BIOS -> Repair tool

* Fix

* Typo

* Adjust style

* Adjust text

* Flush -> Clear

* Revert flush changes

* Responsive

* Also hide splash
2022-07-07 17:35:56 +09:00
syuilo
f4fcb912e3 enhance(client): make widgets available on tablet again 2022-07-07 17:29:30 +09:00
syuilo
1c5f339d09 chore(client): tweak style 2022-07-07 17:28:21 +09:00
syuilo
7cf3218068 chore(client): tweak ui 2022-07-07 17:28:13 +09:00
Johann150
7775eb9641 refactor: use overflow-y to determine scroll container
By using `overflow-y` instead of `overflow` using `endsWith` can be
avoided and represents the data we are actually interested in here
more accurately.
2022-07-06 19:02:39 +02:00
Johann150
ac6b8f3480 refactor: use autofocus parameter
Using the `ref` seems to be broken but using the autofocus parameter
seems to fix it.
2022-07-06 18:23:05 +02:00
syuilo
41bef75d1a chore(client): tweak style 2022-07-06 18:20:32 +09:00
syuilo
14e32557d2 Update CHANGELOG.md 2022-07-06 08:42:04 +09:00
syuilo
6d7a29b2cb 12.112.0-beta.20 2022-07-06 07:54:35 +09:00
syuilo
7db4af5578 perf(client): trying improve perf of emoji-picker 2022-07-06 07:54:04 +09:00
syuilo
f7747af690 Revert "revert emoji picker changes"
This reverts commit 38d5303ccd.
2022-07-06 07:30:56 +09:00
Johann150
4940894324 fix prismjs import
fixes #8944
2022-07-06 00:29:51 +02:00
syuilo
2618d72f1f 12.112.0-beta.19 2022-07-06 07:27:09 +09:00
syuilo
38d5303ccd revert emoji picker changes 2022-07-06 07:26:58 +09:00
syuilo
efafc31c9b fix(client): テーマを作成するとクライアントが起動しなくなる 2022-07-06 07:08:45 +09:00
syuilo
b35c3114c8 revert: feat: styled error screen (#8930) 2022-07-06 06:36:14 +09:00
syuilo
b9f9fe2927 12.112.0-beta.18 2022-07-05 23:13:49 +09:00
syuilo
d393cabfe1 Merge branch 'develop' of https://github.com/misskey-dev/misskey into develop 2022-07-05 23:13:33 +09:00
syuilo
bf186de56c chore(client): rendering performance tweak a bit 2022-07-05 23:13:28 +09:00
syuilo
21279769c9 New Crowdin updates (#8841)
* New translations ja-JP.yml (French)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (Arabic)

* New translations ja-JP.yml (Slovak)

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

* New translations ja-JP.yml (Kabyle)

* New translations ja-JP.yml (Kannada)

* New translations ja-JP.yml (Bengali)

* New translations ja-JP.yml (Indonesian)

* New translations ja-JP.yml (English)

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

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Vietnamese)

* New translations ja-JP.yml (Romanian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Catalan)

* New translations ja-JP.yml (Czech)

* New translations ja-JP.yml (Spanish)

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

* New translations ja-JP.yml (Portuguese)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (Polish)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Italian)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Dutch)

* New translations ja-JP.yml (Swedish)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Indonesian)

* New translations ja-JP.yml (Slovak)

* New translations ja-JP.yml (Indonesian)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Portuguese)

* New translations ja-JP.yml (Portuguese)

* New translations ja-JP.yml (Portuguese)

* New translations ja-JP.yml (Portuguese)

* New translations ja-JP.yml (Portuguese)

* New translations ja-JP.yml (Portuguese)

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

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (English)

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

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

* New translations ja-JP.yml (Thai)

* New translations ja-JP.yml (Thai)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Slovak)

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

* New translations ja-JP.yml (Vietnamese)

* New translations ja-JP.yml (Vietnamese)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Thai)

* New translations ja-JP.yml (Thai)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Slovak)

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

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Vietnamese)

* New translations ja-JP.yml (Thai)

* New translations ja-JP.yml (Thai)

* New translations ja-JP.yml (Slovak)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Slovak)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Thai)

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

* New translations ja-JP.yml (Thai)

* New translations ja-JP.yml (Thai)

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

* New translations ja-JP.yml (Vietnamese)

* New translations ja-JP.yml (Thai)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (English)

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

* New translations ja-JP.yml (Thai)

* New translations ja-JP.yml (Thai)

* New translations ja-JP.yml (Vietnamese)

* New translations ja-JP.yml (Slovak)

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

* New translations ja-JP.yml (Thai)

* New translations ja-JP.yml (Thai)

* New translations ja-JP.yml (German)

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

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Slovak)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Vietnamese)

* New translations ja-JP.yml (Spanish)

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

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Slovak)

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

* New translations ja-JP.yml (Bengali)

* New translations ja-JP.yml (Indonesian)

* New translations ja-JP.yml (English)

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

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Vietnamese)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Spanish)

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

* New translations ja-JP.yml (Portuguese)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (Polish)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Italian)

* New translations ja-JP.yml (Korean)

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

* New translations ja-JP.yml (Vietnamese)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Slovak)

* New translations ja-JP.yml (Vietnamese)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Slovak)

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

* New translations ja-JP.yml (Vietnamese)
2022-07-05 23:08:24 +09:00
syuilo
bc73ad2e56 chore(client): rendering performance tweak a bit 2022-07-05 23:01:23 +09:00
syuilo
f882e0b6b6 chore(client): remove unused class 2022-07-05 22:40:53 +09:00
syuilo
bc012784ef chore(client): tweak ui 2022-07-05 22:40:15 +09:00
syuilo
f66235f066 chore(client): rendering performance tweak a bit 2022-07-05 22:35:57 +09:00
syuilo
60710805d5 chore(client): fix type 2022-07-05 22:25:34 +09:00
syuilo
62f8af4891 enhance(client): improve usability 2022-07-05 22:25:27 +09:00
syuilo
7dd9f93efb feat(client): メニューからページをリロードできるように 2022-07-05 19:29:44 +09:00
syuilo
972b03f842 perf: allow get for notes/reactions 2022-07-05 19:16:21 +09:00
syuilo
a1cbffd14f chore(client): tweak ui 2022-07-05 17:55:47 +09:00
syuilo
38c1867a8b 12.112.0-beta.17 2022-07-05 17:46:55 +09:00
syuilo
cb246d3459 rename: BIOS -> Repair Tool 2022-07-05 17:46:17 +09:00
Kainoa Kanter
40656e3ee2 feat: styled error screen (#8930)
* Styled error screen

* Make details margin auto

* Update boot.css

* Replace fontawesome with tabler svg

* Remove hr

* Add new style to flush screen

* Rename to `error.css`
2022-07-05 17:44:05 +09:00
Johann150
ef9fdb93d2 fix: pagination uses API correctly (#8925) 2022-07-05 17:42:54 +09:00
syuilo
02fafd5114 fix(client): user search of explore not working 2022-07-05 17:20:34 +09:00
syuilo
58b00e2f4c chore(client): tweak style 2022-07-05 16:19:52 +09:00
syuilo
0de176a2ba enhance(client): improve marquee 2022-07-05 16:16:13 +09:00
syuilo
1778269ea8 Merge branch 'develop' of https://github.com/misskey-dev/misskey into develop 2022-07-05 16:07:55 +09:00
syuilo
ccea04f391 chore(client): tweak deck 2022-07-05 16:07:53 +09:00
syuilo
135dfa8026 chore(client): tweak deck 2022-07-05 15:55:55 +09:00
Kainoa Kanter
25b7d02540 Update store.ts (#8937) 2022-07-05 15:21:46 +09:00
syuilo
4f0878e267 chore(client): tweak ui 2022-07-05 12:09:49 +09:00
Kainoa Kanter
1eb504a640 chore: fix client lint errors (#8934)
* Fix client lint

* Hide no-v-html

* Ignore banned type

* Update page-editor.vue
2022-07-05 11:21:59 +09:00
Usuyuki
ce9d29828d fix:typo 「有効する必要…」→「有効にする必要…」 (#8936) 2022-07-05 11:17:42 +09:00
tamaina
2fe4a51d26 Merge branch 'develop' of https://github.com/misskey-dev/misskey into develop 2022-07-04 15:26:21 +00:00
tamaina
452f2a07ac update CHANGELOG.md 2022-07-04 15:26:18 +00:00
CyberRex
cd07eb222e Add additional drive capacity change support (#8867)
* Add additional drive capacity change support

* Update packages/backend/src/server/api/endpoints/admin/drive-capacity-override.ts

Co-authored-by: Johann150 <johann@qwertqwefsday.eu>

* 🎨

* show instance default capacity in placeholder

* fix

* update api/drive

* fix

* remove :

* fix lint

Co-authored-by: Johann150 <johann@qwertqwefsday.eu>
Co-authored-by: tamaina <tamaina@hotmail.co.jp>
2022-07-05 00:21:01 +09:00
Johann150
a228d1ddaa fix lint @typescript-eslint/ban-types 2022-07-04 16:46:48 +02:00
Johann150
d748ba2c51 fix lint no-prototype-builtins 2022-07-04 16:39:04 +02:00
Johann150
a5c3fcea6e fix lint no-undef 2022-07-04 16:33:55 +02:00
Johann150
2bd4323b17 fix lint: use let instead of const for $ref
Fixes lint no-const-assign.
2022-07-04 16:22:21 +02:00
Johann150
935fce338a refactor: remove unnecessary computed
Fixes lint no-const-assign.
2022-07-04 16:17:07 +02:00
Johann150
366fae41ff fix lint vue/require-valid-default-prop 2022-07-04 16:06:46 +02:00
Johann150
0b9c961707 fix lint no-fallthrough 2022-07-04 16:05:41 +02:00
Johann150
f14d5886f2 fix lint padded-blocks 2022-07-04 15:59:24 +02:00
Johann150
ea9e32096b fix(lint): semicolong spacing 2022-07-04 15:56:16 +02:00
Johann150
121fa40621 fix: replace use of window 2022-07-04 15:27:21 +02:00
syuilo
f9444aa3d3 Merge branch 'develop' of https://github.com/misskey-dev/misskey into develop 2022-07-04 21:29:10 +09:00
syuilo
08c6ed04bf update vite 2022-07-04 21:29:07 +09:00
syuilo
65c12903e4 enhance(client): deckのウイジェットカラムが未設定の時に説明を表示するように 2022-07-04 21:28:59 +09:00
Johann150
e0e42a6425 fix: spellcheck is boolean not string 2022-07-04 10:35:27 +02:00
Johann150
b438a1935d update changelog 2022-07-03 21:41:10 +02:00
syuilo
4ab2f16ed3 enhance(client): tweak statusbar 2022-07-04 01:37:47 +09:00
syuilo
dc1a35c13c chore(client): tweak style 2022-07-04 01:12:36 +09:00
syuilo
1cb847aa80 enhance(client): tweak deck 2022-07-03 23:13:41 +09:00
MeiMei
034c5d792b fix: streamingテストおそい (#8912) 2022-07-03 20:54:54 +09:00
syuilo
0076797b15 12.112.0-beta.16 2022-07-03 20:32:34 +09:00
syuilo
ee0d3c6742 Update CHANGELOG.md 2022-07-03 20:32:21 +09:00
syuilo
1163c85db6 enhance(client): refine deck
Fix #7720
2022-07-03 20:30:58 +09:00
syuilo
af6dd4194f fix(client): contextmenu of deck not working 2022-07-03 19:11:10 +09:00
syuilo
26c89e053d fix typo 2022-07-03 19:01:08 +09:00
syuilo
751e655d72 12.112.0-beta.15 2022-07-03 17:04:44 +09:00
syuilo
57c6db6952 chore(client): rename marquee -> ticker 2022-07-03 16:50:51 +09:00
syuilo
66ffb253a2 chore(client): tweak style 2022-07-03 16:46:00 +09:00
syuilo
ab5cd1cb15 fix(client): fix wrong import 2022-07-03 16:36:23 +09:00
syuilo
4774bc1f47 chore(client): tweak style 2022-07-03 16:36:13 +09:00
syuilo
1cc8fd54c0 fix(client): fix wrong import 2022-07-03 16:19:47 +09:00
syuilo
e393ab6044 fix(client): style tweak for ios 2022-07-03 16:17:31 +09:00
syuilo
01688b543a 12.112.0-beta.14 2022-07-03 14:45:20 +09:00
syuilo
b2af1948a4 fix(client): フォロワー一覧がフォローににゃっているんだにゃあ 2022-07-03 14:44:18 +09:00
syuilo
0eb473198c chore(client): tweak style 2022-07-03 14:43:28 +09:00
syuilo
44c85aff86 feat(client): status bar (experimental) 2022-07-03 14:40:02 +09:00
syuilo
f8f3ecbf02 12.112.0-beta.13 2022-07-03 00:24:49 +09:00
syuilo
dd426735a0 feat: moderation note 2022-07-03 00:15:03 +09:00
syuilo
0de973d293 update eslint rules 2022-07-02 23:01:13 +09:00
syuilo
9c6a220810 chore(client): tweak ui 2022-07-02 22:07:04 +09:00
syuilo
ec41aefeea fix(client): fix typo 2022-07-02 22:06:53 +09:00
syuilo
66231c1669 fix(client): use unique class names for root to prevent conflicts of style 2022-07-02 21:29:48 +09:00
syuilo
f9ba35d928 enhance(client): better sticky-container component 2022-07-02 21:28:55 +09:00
syuilo
ef83670716 enhance(client): better marquee component 2022-07-02 21:28:04 +09:00
syuilo
949dbb3918 feat(server): add fetch-rss api to reduce dependency of external apis 2022-07-02 21:26:33 +09:00
syuilo
eb709508a4 12.112.0-beta.12 2022-07-02 15:17:09 +09:00
syuilo
eccc90c843 feat: Log user ips (#8872)
* wip

* store ip and headers

* Update admin-file.vue

* require admin for view ip/headers

* IP (recent) 消した

* admin必須

* opt in

* clean ips periodically

* respect logging setting in drive/files/create
2022-07-02 15:12:11 +09:00
syuilo
ded0f6f0df refactor(client): refactoring 2022-07-02 14:00:37 +09:00
syuilo
52a1ec9af1 enhance(server): アンケートを新しい順にソート 2022-07-02 12:34:22 +09:00
syuilo
b773d516d3 chore(client): tweak ui 2022-07-02 12:22:52 +09:00
syuilo
6bcd5cb310 enhance(client): cache pages in page-window 2022-07-02 12:12:10 +09:00
syuilo
01d5a97a4f feat(client): poll highlights in explore page 2022-07-01 23:42:03 +09:00
syuilo
afe0d9a266 enhance(client): ハイライトをみつけるに統合 2022-07-01 23:33:47 +09:00
syuilo
add6e9b14b chore(client): tweak ui 2022-07-01 18:55:45 +09:00
syuilo
80a033c1cf chore(client): tweak style 2022-07-01 17:08:45 +09:00
syuilo
c67c3b0360 chore(client): tweak style 2022-07-01 16:43:38 +09:00
syuilo
f635d5b864 chore(client): tweak style 2022-07-01 15:23:49 +09:00
syuilo
9205155fc9 12.112.0-beta.11 2022-07-01 15:11:39 +09:00
syuilo
65b0a002c7 chore(client): tweak ui 2022-07-01 15:06:17 +09:00
MeiMei
2f65d91ea8 migrate parse5 to 7.0.0 (#8916)
* migrate parse5 to 7.0.0

* fix
2022-07-01 13:48:03 +09:00
syuilo
b846ebeb97 use parse5 6.0.1
Fix #8914
2022-07-01 11:07:14 +09:00
Johann150
66b27bdc97 fix typo
Co-authored-by: mei23 <m@m544.net>
2022-06-30 22:03:04 +02:00
syuilo
649bb672df chore(client): fix pie rendering 2022-07-01 00:38:20 +09:00
syuilo
27fef64cf3 12.112.0-beta.10 2022-07-01 00:21:38 +09:00
syuilo
e3bf53ea84 update deps 2022-07-01 00:21:25 +09:00
syuilo
30aa1dcdcd chore(client): tweak rss-marquee 2022-06-30 23:53:58 +09:00
syuilo
7c7ce072c7 chore(client): tweak ui 2022-06-30 23:51:18 +09:00
syuilo
6ba888f476 feat(client): add rss-marquee widget 2022-06-30 23:45:11 +09:00
syuilo
bbdc52a7ea chore(client): tweak style 2022-06-30 23:07:45 +09:00
syuilo
cb697cf582 chore(client): tweak ui 2022-06-30 22:02:08 +09:00
syuilo
4c2cd3c8d5 chore(client): tweak ui 2022-06-30 21:38:34 +09:00
syuilo
1bec974fe6 12.112.0-beta.9 2022-06-30 20:15:47 +09:00
syuilo
1069ae6525 update vite 2022-06-30 20:15:40 +09:00
syuilo
ed41d542bb chore(client): tweak ui 2022-06-30 20:15:14 +09:00
syuilo
eac31eb323 chore(client): tweak ui 2022-06-30 19:19:54 +09:00
syuilo
324f5525b5 fix(server): cannot show users 2022-06-30 15:36:09 +09:00
syuilo
6f3e64f13e chore(client): tweak client 2022-06-30 15:32:11 +09:00
syuilo
6f2d2a71f9 enhance(client): show confirm dialog when logout 2022-06-30 15:09:10 +09:00
syuilo
47dcb1b41f refactor(client): use setup syntax 2022-06-30 12:48:42 +09:00
syuilo
fa6eb0e0f2 perf(client): improve range control performance 2022-06-30 12:42:35 +09:00
syuilo
bffe6fb9bf tweak client 2022-06-30 10:53:40 +09:00
syuilo
9ac526b6b6 tweak client 2022-06-30 10:13:27 +09:00
Johann150
ca6afd40ad fix client router catchall
fixes #8903
2022-06-29 22:09:44 +02:00
Johann150
8b7dcf4dba fix 'assignment to const' error 2022-06-29 17:44:03 +02:00
syuilo
99dcd7bb27 feat(client): add instance-cloud widget 2022-06-29 23:28:52 +09:00
syuilo
6a7dff1c82 Update .eslintrc.js 2022-06-29 23:06:03 +09:00
syuilo
82e9658ac3 12.112.0-beta.8 2022-06-29 21:22:47 +09:00
syuilo
3f6e04697a Merge branch 'develop' of https://github.com/misskey-dev/misskey into develop 2022-06-29 21:22:18 +09:00
syuilo
c9b3ab80ca feat(client): add tag cloud component 2022-06-29 21:22:15 +09:00
Johann150
7f111f4474 Prevent access to user pages when not logged in [v2] (#8904)
* do not throw error when navigating

* enhance: add loginRequired to router

This allows client pages to require logging in before displaying the
page, useful for example for user settings pages.

* add login requirements

Co-authored-by: Andreas Nedbal <git@pixelde.su>
2022-06-29 18:26:06 +09:00
syuilo
f997b7dff2 chore(client): fix type def 2022-06-29 16:07:38 +09:00
syuilo
a107dff4d6 perf(client): remove needless reactivity 2022-06-29 16:06:13 +09:00
syuilo
bb68cfaa81 enhance(client): improve router
Fix #8902
2022-06-29 16:00:00 +09:00
syuilo
4fd386c3dc chore(client): tweak client 2022-06-29 15:41:06 +09:00
syuilo
8648308823 chore(client): tweak style 2022-06-29 14:19:40 +09:00
syuilo
2b1e03cc64 enhance(client): add users tab to instance-info 2022-06-29 14:14:27 +09:00
syuilo
0f1c0a42a2 enhance(client): メニュー整理
Resolve #6389
Fix #8035
2022-06-29 11:13:32 +09:00
syuilo
1a698111a4 refactor(client): remove invalid computed 2022-06-29 00:36:06 +09:00
syuilo
9f7c9b122f fix(client): 非モデレーターがインスタンス情報ページを表示できない問題を修正 2022-06-28 22:56:18 +09:00
syuilo
9a4198293a chore(client): tweak style 2022-06-28 22:32:01 +09:00
syuilo
ac162f9996 chore(client): tweak style 2022-06-28 18:41:37 +09:00
syuilo
d7e7152bd3 chore(client): tweak style 2022-06-28 18:09:42 +09:00
syuilo
a50b1d69a1 chore(client): fix #8858 2022-06-28 17:59:23 +09:00
syuilo
30bdfde4cc 12.112.0-beta.7 2022-06-28 16:06:23 +09:00
syuilo
ea3d391df9 chore(client): tweak style 2022-06-28 16:02:39 +09:00
syuilo
270e1212ac chore(client): refactor and style tweaks 2022-06-28 15:59:49 +09:00
syuilo
57bb6e611f refactor(client): use setup syntax 2022-06-28 14:34:44 +09:00
syuilo
31d73f4659 chore(client): fix type def 2022-06-28 13:06:31 +09:00
syuilo
5c3e782d29 improve instance doughnut charts 2022-06-28 13:05:20 +09:00
syuilo
553d644781 chore(client): tweak style 2022-06-28 12:16:20 +09:00
syuilo
7d8a70f99e fix(api): fix instance schema 2022-06-28 12:16:11 +09:00
syuilo
0f550d568d 12.112.0-beta.6 2022-06-28 10:43:18 +09:00
syuilo
0657995b42 chore(client): tweak style 2022-06-28 10:42:54 +09:00
syuilo
fe460c022c feat(client): add instances doughnuts charts for dashboard 2022-06-28 10:42:26 +09:00
syuilo
d7c6e2e61c fix(client): fix chart tooltip rendering 2022-06-28 10:41:38 +09:00
syuilo
c04d3d22af feat(api): add federation/stats endpoint 2022-06-28 10:41:22 +09:00
syuilo
164d4a9825 fix(api): add missing themeColor property of instance 2022-06-28 10:40:49 +09:00
syuilo
596a61ce18 lint fix 2022-06-28 00:27:24 +09:00
syuilo
40cd5c5a49 chore(client): tweak style 2022-06-28 00:20:51 +09:00
syuilo
329f055a97 feat: make possible to delete an account by admin
Resolve #8830
2022-06-27 23:49:16 +09:00
Johann150
bc3ae901cc refactor: remove duplicate code (#8895) 2022-06-27 21:48:10 +09:00
syuilo
0ec266abf7 chore(client): tweak client 2022-06-26 19:41:21 +09:00
MeiMei
f834d6a813 fix: mocha テストが動かないのを修正 v2 (#8892)
* on push

* Fix mute test

* fix note test

* api

* inc timeout

* uploadUrl

* Revert "on push"

This reverts commit 778a58df61.

* lint

* waitFire

* Wrap connectStream

* return
2022-06-26 19:16:32 +09:00
syuilo
4634920866 fix #8894 2022-06-26 17:38:50 +09:00
syuilo
744db4b5ed chore(client): tweak ui 🎨 2022-06-26 16:57:12 +09:00
syuilo
bd3c6f4157 chore(client): tweak ui 🎨 2022-06-26 16:38:27 +09:00
syuilo
4329d9e76d chore(client): fix type 2022-06-26 15:55:51 +09:00
syuilo
311478e725 chore(client): tweak client 2022-06-26 15:54:07 +09:00
syuilo
c27d9e11b4 chore(client): tweak client 2022-06-26 14:17:55 +09:00
syuilo
de43b47ca8 12.112.0-beta.5 2022-06-26 13:29:14 +09:00
syuilo
3183a02824 Merge branch 'develop' of https://github.com/misskey-dev/misskey into develop 2022-06-26 13:28:49 +09:00
syuilo
0cae0a49e2 chore(client): tweak ui 2022-06-26 13:28:47 +09:00
tamaina
2366f568b9 enhance(client): Enhance boot error display (#8879)
* Change boot error message

* fix

* ✌️

* fix
2022-06-26 12:47:43 +09:00
syuilo
5e95a1f7af refactor(client): extract interval logic to a composable function
あと`onUnmounted`を`onMounted`内で呼んでいたりしたのを修正したりとか
2022-06-26 03:12:58 +09:00
syuilo
6a4574b612 enhance(client): tweak control panel dashboard 2022-06-26 01:45:33 +09:00
syuilo
f071ea4902 fix(client): remove needless requestLog call 2022-06-25 23:16:02 +09:00
syuilo
0af581f2e6 12.112.0-beta.4 2022-06-25 23:01:48 +09:00
syuilo
0248a2a989 enhance(client): improve control panel 2022-06-25 23:01:40 +09:00
tamaina
c67c0df762 fix notification-setting-window.vue 2022-06-25 09:29:42 +00:00
syuilo
929dc076ec Merge branch 'develop' of https://github.com/misskey-dev/misskey into develop 2022-06-25 18:26:34 +09:00
syuilo
58e83f8e4f feat: allow GET for some endpoints
Resolve #8263
2022-06-25 18:26:31 +09:00
syuilo
7be4b2145b refactor(client): extract tooltip logic of chart 2022-06-25 18:05:35 +09:00
Johann150
d5ef68336a refactor: notification setting window composition API (#8860)
* refactor: notification setting window composition API

* fix lint vue/require-valid-default-prop

* fix type
2022-06-25 17:14:13 +09:00
dependabot[bot]
126011c1a7 chore(deps): bump jsrsasign from 10.5.24 to 10.5.25 in /packages/backend (#8889)
Bumps [jsrsasign](https://github.com/kjur/jsrsasign) from 10.5.24 to 10.5.25.
- [Release notes](https://github.com/kjur/jsrsasign/releases)
- [Changelog](https://github.com/kjur/jsrsasign/blob/master/ChangeLog.txt)
- [Commits](https://github.com/kjur/jsrsasign/compare/10.5.24...10.5.25)

---
updated-dependencies:
- dependency-name: jsrsasign
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-06-25 16:28:36 +09:00
Andreas Nedbal
36f09b6cdc fix(client): only enable hotkeys for logged in users (#8793)
* fix(client): only enable hotkeys for logged in users

* fix(client): keep theme and search hotkeys for logged out users
2022-06-25 14:25:22 +09:00
Johann150
5728350267 fix: always respect instance mutes (#8854)
* fix: muted user query also checks instances

This way it can be ensured that the instance mute is used everywhere it
is required without checking the whole codebase again. Muted users and
muted instances should be used together anyways.

* fix lint
2022-06-25 14:23:59 +09:00
dependabot[bot]
e3461f1b58 chore(deps): bump jpeg-js from 0.4.1 to 0.4.4 in /packages/backend (#8843)
Bumps [jpeg-js](https://github.com/eugeneware/jpeg-js) from 0.4.1 to 0.4.4.
- [Release notes](https://github.com/eugeneware/jpeg-js/releases)
- [Commits](https://github.com/eugeneware/jpeg-js/compare/v0.4.1...v0.4.4)

---
updated-dependencies:
- dependency-name: jpeg-js
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-06-25 13:50:15 +09:00
dependabot[bot]
ca5200d1f1 chore(deps): bump undici from 5.4.0 to 5.5.1 in /packages/backend (#8842)
Bumps [undici](https://github.com/nodejs/undici) from 5.4.0 to 5.5.1.
- [Release notes](https://github.com/nodejs/undici/releases)
- [Commits](https://github.com/nodejs/undici/compare/v5.4.0...v5.5.1)

---
updated-dependencies:
- dependency-name: undici
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-06-25 13:50:06 +09:00
syuilo
16fda89738 chore(client): tweak MkKeyValue component 2022-06-25 11:50:19 +09:00
syuilo
b2caf821ef 12.112.0-beta.3 2022-06-25 00:06:13 +09:00
syuilo
734fe9fd9d chore(client): tweak ui 2022-06-25 00:03:59 +09:00
syuilo
03973654b5 chore(client): improve usability 2022-06-24 23:49:47 +09:00
syuilo
1b2bd89383 fix bug 2022-06-24 21:48:54 +09:00
syuilo
1e8d84dbfa refactor: remove unused import 2022-06-24 21:46:49 +09:00
syuilo
696e8add00 feat: 管理者が特定ユーザーのアップロードしたファイル一覧を見れるように 2022-06-24 21:43:28 +09:00
syuilo
905d8625f8 fix(client): アカウント作成フォームでエラーが出る問題を修正 2022-06-24 21:19:38 +09:00
syuilo
bf4726f91d fix(client): ログアウトできない問題を修正 2022-06-24 21:16:05 +09:00
syuilo
274352beab Merge branch 'develop' of https://github.com/misskey-dev/misskey into develop 2022-06-24 19:47:48 +09:00
syuilo
a1449455a2 chore(client): tweak mini-chart rendering 2022-06-24 19:47:38 +09:00
Johann150
a5241379af fix lints 2022-06-24 12:44:22 +02:00
MeiMei
6f8e3fe366 enhance: Redisをioredisに統一してIPv6サポート (#8869)
* Use ioredis, Supports IPv6 host

https://github.com/misskey-dev/misskey/issues/8862

* Fix import

* order

* a

* i

* fix

* flushdb

* family

* CHANGELOG

* redis_version

Co-authored-by: syuilo <Syuilotan@yahoo.co.jp>
2022-06-24 19:22:19 +09:00
Johann150
1c2e2c4b06 fix(client): ask to log in for poll vote (#8883) 2022-06-24 19:03:41 +09:00
syuilo
55c22eec8b chore(client): tweak ui 2022-06-24 10:52:34 +09:00
syuilo
4a5d5fe20c refactor(client): use composition api 2022-06-24 10:52:28 +09:00
tamaina
12374bd6a3 fix(nirax): Normalize path (#8877) 2022-06-24 01:26:15 +09:00
syuilo
c9e9129373 fix #8861 2022-06-24 00:47:55 +09:00
syuilo
5ee53c222b chore(client): tweak ui 2022-06-23 23:45:22 +09:00
syuilo
3e1248ff35 lint fixes 2022-06-23 21:46:15 +09:00
Johann150
4f4d2b7c53 refactor: simplify ap/show with DbResolver (#8838)
Using the existing code in DbResolver we can avoid separate code for
parsing the URIs in this endpoint.

Co-authored-by: syuilo <Syuilotan@yahoo.co.jp>
2022-06-23 21:32:17 +09:00
Johann150
ecdaeea94f enhance: word mute checks CW (#8873) 2022-06-23 20:26:47 +09:00
syuilo
d1e151172b chore(client): tweak client design 2022-06-23 13:39:28 +09:00
syuilo
2a2020b797 chore(dev): improve eslint config 2022-06-23 13:19:17 +09:00
syuilo
43b9a9e618 enhance(client): tweak ui 2022-06-22 23:40:53 +09:00
syuilo
aabf12038c 12.112.0-beta.2 2022-06-22 20:51:04 +09:00
syuilo
d3f25fa290 tweak client 2022-06-22 20:47:53 +09:00
syuilo
be383aa5b2 refactor(client): use composition api 2022-06-22 16:30:55 +09:00
syuilo
85365da69e refactor(client): refactor header tab handling 2022-06-22 16:30:45 +09:00
syuilo
e44cb42de4 🎨 2022-06-22 00:48:16 +09:00
syuilo
ad123b3cce tweak client 2022-06-22 00:10:34 +09:00
syuilo
1e85a3025c Merge branch 'develop' of https://github.com/misskey-dev/misskey into develop 2022-06-21 23:22:20 +09:00
syuilo
c9d4c00708 fix(client): moderators cannot view instance-info page 2022-06-21 23:22:18 +09:00
Johann150
e0c6688709 update changelog 2022-06-21 15:56:47 +02:00
syuilo
2d181ba5af enhance(client): show warning in control panel when there is an unresolved abuse report 2022-06-21 19:48:28 +09:00
syuilo
f880d0631c tweak client 2022-06-21 17:55:38 +09:00
syuilo
a6fff86099 refactor(client): use composition api 2022-06-21 14:39:23 +09:00
syuilo
4efee455b1 fix(server): faviconUrl of federated instance is missing 2022-06-21 14:28:43 +09:00
syuilo
14cc341cc9 chore: add comments 2022-06-21 14:18:06 +09:00
syuilo
ce6cc21bcd tweak client
Fix #8856
2022-06-21 14:12:39 +09:00
Johann150
3796a3edea fix: block button in federation panel (#8855) 2022-06-20 23:48:38 +09:00
syuilo
f995172c5d tweak client 2022-06-20 21:05:18 +09:00
syuilo
8e20e27ff9 fix client 2022-06-20 19:49:51 +09:00
syuilo
699f24f3dc refactor(client): Refine routing (#8846) 2022-06-20 17:38:49 +09:00
tamaina
30a39a296d refactor: チャットルームをComposition API化 (#8850)
* pick form

* pick message

* pick room

* fix lint

* fix scroll?

* fix scroll.ts

* fix directives/sticky-container

* update global/sticky-container.vue

* fix, 🎨

* test.1
2022-06-20 13:20:28 +09:00
tamaina
b70473ed60 feat: Add Badge Image to Push Notification (#8012)
* fix

* nanka iroiro

* wip

* wip

* fix lint

* fix loginId

* fix

* refactor

* refactor

* remove follow action

* clean up

* Revert "remove follow action"

This reverts commit defbb41648.

* Revert "clean up"

This reverts commit f94919cb9c.

* remove fetch specification

* renoteの条件追加

* apiFetch => cli

* bypass fetch?

* fix

* refactor: use path alias

* temp: add submodule

* remove submodule

* enhane: unison-reloadに指定したパスに移動できるように

* null

* null

* feat: ログインするアカウントのIDをクエリ文字列で指定する機能

* null

* await?

* rename

* rename

* Update read.ts

* merge

* get-note-summary

* fix

* swパッケージに

* add missing packages

* fix getNoteSummary

* add webpack-cli

* ✌️

* remove plugins

* sw-inject分離したがテストしてない

* fix notification.vue

* remove a blank line

* disconnect intersection observer

* disconnect2

* fix notification.vue

* remove a blank line

* disconnect intersection observer

* disconnect2

* fix

* ✌️

* clean up config

* typesを戻した

* backend/src/web/index.ts

* notification-badges

* add scripts

* change create-notification.ts

* Update packages/client/src/components/notification.vue

Co-authored-by: Acid Chicken (硫酸鶏) <root@acid-chicken.com>

* disconnect

* oops

* Failed to load the script unexpectedly回避
sw.jsとlib.tsを分離してみた

* truncate notification

* Update packages/client/src/ui/_common_/common.vue

Co-authored-by: syuilo <Syuilotan@yahoo.co.jp>

* clean up

* clean up

* refactor

* キャッシュ対策

* Truncate push notification message

* fix

* クライアントがあったらストリームに接続しているということなので通知しない判定の位置を修正

* components/drive-file-thumbnail.vue

* components/drive-select-dialog.vue

* components/drive-window.vue

* merge

* fix

* Service Workerのビルドにesbuildを使うようにする

* return createEmptyNotification()

* fix

* fix

* i18n.ts

* update

* ✌️

* remove ts-loader

* fix

* fix

* enhance: Service Workerを常に登録するように

* pollEnded

* pollEnded

* URLをsw.jsに戻す

* clean up

* fix lint

* changelog

* alpha-test

* also with twemoji

* add isMimeImage function

* catch

* Colour => Color

* char2file => char2filePath

* Update autocomplete.vue

* remove clone?

Co-authored-by: Acid Chicken (硫酸鶏) <root@acid-chicken.com>
Co-authored-by: syuilo <Syuilotan@yahoo.co.jp>
2022-06-20 00:33:46 +09:00
Andreas Nedbal
54465d36a7 Refactor page-editor elements to use Composition API (#8721)
* refactor(client): refactor page-editor elements to use Composition API

* Apply review suggestions from @Johann150

Co-authored-by: Johann150 <johann@qwertqwefsday.eu>

Co-authored-by: Johann150 <johann@qwertqwefsday.eu>
2022-06-18 18:39:04 +09:00
syuilo
802a35d4b6 fix typo 2022-06-18 18:27:47 +09:00
futchitwo
5b7595d9d7 Improve: unclip (#8823)
* Refactor clip page to use Composition API

* Refactor clip page

* Refactor clip page

* Refactor clip page

* Improve: unclip

* Fix unclip

* Fix unclip

* chore: better type and name

* Fix

* Fix clipPage vue provider

Co-authored-by: syuilo <Syuilotan@yahoo.co.jp>
2022-06-18 18:27:09 +09:00
futchitwo
d7bab7cf0b Refactor clip page to Composition API (#8822)
* Refactor clip page to use Composition API

* Refactor clip page

* Refactor clip page

* Refactor clip page
2022-06-18 18:23:54 +09:00
MeiMei
6422cde5f2 enhance: Improve player detection in URL preview (#8849)
* enhance: Improve player detection in URL preview

* CHANGELOG
2022-06-18 16:02:31 +09:00
syuilo
8df2f19b5b enhance(client): improve file moderation ui 2022-06-17 15:03:02 +09:00
syuilo
e29a310f7d Merge branch 'develop' of https://github.com/misskey-dev/misskey into develop 2022-06-17 14:31:31 +09:00
syuilo
70450fe6b4 Update ROADMAP.md 2022-06-17 13:56:39 +09:00
syuilo
7faa75d483 chore(client): tweak range control design 2022-06-17 13:20:33 +09:00
syuilo
836ecff785 Update CONTRIBUTING.md 2022-06-17 11:02:47 +09:00
Johann150
6078c986d3 fix: render empty note content correctly
Instead of coercing to `null`, coercing to an empty string should simplify handling.
2022-06-16 12:51:44 +02:00
Johann150
b54f906605 fix: correctly render note text
Fix a regression from #8787 that was previously fixed in #8440.
2022-06-16 12:32:09 +02:00
syuilo
4a55425fdb enhance(client): improve files page of control panel 2022-06-16 16:05:43 +09:00
syuilo
fdba255b9a Update CHANGELOG.md 2022-06-14 23:05:11 +09:00
MeiMei
1d8ec102f1 fix: GenerateVideoThumbnail (#8825)
* fix: GenerateVideoThumbnail

* CHANGELOG

* fix cleanup

* Revert "fix cleanup"

This reverts commit d54cf8262a.
2022-06-14 23:02:14 +09:00
Johann150
3a42fe50c6 fix: tmpdir cleanup removes contained files (#8826) 2022-06-14 23:00:10 +09:00
syuilo
e4dc25dd5c enhance(server): モデレーターであってもレートリミットを有効に 2022-06-14 22:59:19 +09:00
tamaina
f1e6fa8ee2 fix: add limit to i/notifications (#8836)
* fix: add limit to i/notifications

* ms

* remove ms
2022-06-14 22:55:58 +09:00
Johann150
10d979bd65 fix(docs): use correct description property 2022-06-14 11:55:58 +02:00
Johann150
b5390c0922 fix: remove unused parameter 2022-06-14 11:54:55 +02:00
syuilo
963f538728 lint fixes 2022-06-14 18:01:23 +09:00
578 changed files with 19831 additions and 14169 deletions

View File

@@ -57,6 +57,7 @@ db:
redis: redis:
host: localhost host: localhost
port: 6379 port: 6379
#family: 0 # 0=Both, 4=IPv4, 6=IPv6
#pass: example-pass #pass: example-pass
#prefix: example-prefix #prefix: example-prefix
#db: 1 #db: 1

View File

@@ -9,6 +9,74 @@
You should also include the user name that made the change. You should also include the user name that made the change.
--> -->
## 12.112.3 (2022/07/09)
### Improvements
- Make active email validation configurable
### Bugfixes
- Server: Fix Attempts to update all notifications @mei23
## 12.112.2 (2022/07/08)
### Bugfixes
- Fix Docker doesn't work @mei23
Still not working on arm64 environment. (See 12.112.0)
## 12.112.1 (2022/07/07)
same as 12.112.0
## 12.112.0 (2022/07/07)
### Known issues
- 現在arm64環境ではインストールに失敗します。これは次のバージョンで修正される予定です。
### Changes
- ハイライトがみつけるに統合されました
- カスタム絵文字ページはインスタンス情報ページに統合されました
- 連合ページはインスタンス情報ページに統合されました
- メンション一覧ページは通知一覧ページに統合されました
- ダイレクト投稿一覧ページは通知一覧ページに統合されました
- メニューからアンテナタイムラインを表示する方法は廃止され、タイムライン上部のアイコンからアクセスするようになりました
- メニューからリストタイムラインを表示する方法は廃止され、タイムライン上部のアイコンからアクセスするようになりました
### Improvements
- Server: Allow GET method for some endpoints @syuilo
- Server: Auto NSFW detection @syuilo
- Server: Add rate limit to i/notifications @tamaina
- Client: Improve control panel @syuilo
- Client: Show warning in control panel when there is an unresolved abuse report @syuilo
- Client: Statusbars @syuilo
- Client: Add instance-cloud widget @syuilo
- Client: Add rss-ticker widget @syuilo
- Client: Removing entries from a clip @futchitwo
- Client: Poll highlights in explore page @syuilo
- Client: Improve deck UI @syuilo
- Client: Word mute also checks content warnings @Johann150
- Client: メニューからページをリロードできるように @syuilo
- Client: Improve emoji picker performance @syuilo
- Client: For notes with specified visibility, show recipients when hovering over visibility symbol. @Johann150
- Client: Make widgets available again on a tablet @syuilo
- ユーザーにモデレーションメモを残せる機能 @syuilo
- Make possible to delete an account by admin @syuilo
- Improve player detection in URL preview @mei23
- Add Badge Image to Push Notification #8012 @tamaina
- Server: Improve performance
- Server: Supports IPv6 on Redis transport. @mei23
IPv4/IPv6 is used by default. You can tune this behavior via `redis.family`.
- Server: Add possibility to log IP addresses of users @syuilo
- Add additional drive capacity change support @CyberRex0
### Bugfixes
- Server: Fix GenerateVideoThumbnail failed @mei23
- Server: Ensure temp directory cleanup @Johann150
- favicons of federated instances not showing @syuilo
- Admin: The checkbox for blocking an instance works again @Johann150
- Client: Prevent access to user pages when not logged in @pixeldesu @Johann150
- Client: Disable some hotkeys (e.g. for creating a post) for not logged in users @pixeldesu
- Client: Ask users that are not logged in to log in when trying to vote in a poll @Johann150
- Instance mutes also apply in antennas etc. @Johann150
## 12.111.1 (2022/06/13) ## 12.111.1 (2022/06/13)
### Bugfixes ### Bugfixes

View File

@@ -74,8 +74,6 @@ The `/deploy` command by issue comment can be used to deploy the contents of a P
An actual domain will be assigned so you can test the federation. An actual domain will be assigned so you can test the federation.
## Merge ## Merge
For now, basically only @syuilo has the authority to merge PRs into develop because he is most familiar with the codebase.
However, minor fixes, refactoring, and urgent changes may be merged at the discretion of a contributor.
## Release ## Release
### Release Instructions ### Release Instructions

View File

@@ -1,5 +1,5 @@
Unless otherwise stated this repository is Unless otherwise stated this repository is
Copyright © 2014-2020 syuilo and contributers Copyright © 2014-2022 syuilo and contributers
And is distributed under The GNU Affero General Public License Version 3, you should have received a copy of the license file as LICENSE. And is distributed under The GNU Affero General Public License Version 3, you should have received a copy of the license file as LICENSE.
@@ -13,3 +13,7 @@ https://github.com/muan/emojilib/blob/master/LICENSE
RsaSignature2017 implementation by Transmute Industries Inc RsaSignature2017 implementation by Transmute Industries Inc
License: MIT License: MIT
https://github.com/transmute-industries/RsaSignature2017/blob/master/LICENSE https://github.com/transmute-industries/RsaSignature2017/blob/master/LICENSE
Machine learning model for sensitive images by Infinite Red, Inc.
License: MIT
https://github.com/infinitered/nsfwjs/blob/master/LICENSE

View File

@@ -1,28 +1,24 @@
FROM node:18.0.0-alpine3.15 AS base FROM node:16.15.1-bullseye AS builder
ARG NODE_ENV=production ARG NODE_ENV=production
WORKDIR /misskey WORKDIR /misskey
ENV BUILD_DEPS autoconf automake file g++ gcc libc-dev libtool make nasm pkgconfig python3 zlib-dev git
FROM base AS builder
COPY . ./ COPY . ./
RUN apk add --no-cache $BUILD_DEPS && \ RUN apt-get update
git submodule update --init && \ RUN apt-get install -y build-essential
yarn install && \ RUN git submodule update --init
yarn build && \ RUN yarn install
rm -rf .git RUN yarn build
RUN rm -rf .git
FROM base AS runner FROM node:16.15.1-bullseye-slim AS runner
RUN apk add --no-cache \ WORKDIR /misskey
ffmpeg \
tini
ENTRYPOINT ["/sbin/tini", "--"] RUN apt-get update
RUN apt-get install -y ffmpeg tini
COPY --from=builder /misskey/node_modules ./node_modules COPY --from=builder /misskey/node_modules ./node_modules
COPY --from=builder /misskey/built ./built COPY --from=builder /misskey/built ./built
@@ -32,5 +28,5 @@ COPY --from=builder /misskey/packages/client/node_modules ./packages/client/node
COPY . ./ COPY . ./
ENV NODE_ENV=production ENV NODE_ENV=production
ENTRYPOINT ["/usr/bin/tini", "--"]
CMD ["npm", "run", "migrateandstart"] CMD ["npm", "run", "migrateandstart"]

View File

@@ -19,6 +19,7 @@ This is the phase we are at now. We need to make a high-maintenance environment
## (2) Improve functionality ## (2) Improve functionality
Once Phase 1 is complete and an environment conducive to the development of a stable system is in place, the implementation of new functions can begin gradually. Once Phase 1 is complete and an environment conducive to the development of a stable system is in place, the implementation of new functions can begin gradually.
- Improve features for moderation
- OAuth2 support https://github.com/misskey-dev/misskey/issues/8262 - OAuth2 support https://github.com/misskey-dev/misskey/issues/8262
- GraphQL support? - GraphQL support?

View File

@@ -803,6 +803,7 @@ oneHour: "ساعة"
oneDay: "يوم" oneDay: "يوم"
oneWeek: "أسبوع" oneWeek: "أسبوع"
failedToFetchAccountInformation: "تعذر جلب معلومات الحساب" failedToFetchAccountInformation: "تعذر جلب معلومات الحساب"
file: "الملفات"
_emailUnavailable: _emailUnavailable:
used: "هذا البريد الإلكتروني مستخدم" used: "هذا البريد الإلكتروني مستخدم"
format: "صيغة البريد الإلكتروني غير صالحة" format: "صيغة البريد الإلكتروني غير صالحة"

View File

@@ -843,6 +843,7 @@ oneWeek: "এক সপ্তাহ"
reflectMayTakeTime: "এটির কাজ দেখা যেতে কিছুটা সময় লাগতে পারে।" reflectMayTakeTime: "এটির কাজ দেখা যেতে কিছুটা সময় লাগতে পারে।"
failedToFetchAccountInformation: "অ্যাকাউন্টের তথ্য উদ্ধার করা যায়নি" failedToFetchAccountInformation: "অ্যাকাউন্টের তথ্য উদ্ধার করা যায়নি"
rateLimitExceeded: "রেট লিমিট ছাড়িয়ে গেছে " rateLimitExceeded: "রেট লিমিট ছাড়িয়ে গেছে "
file: "ফাইলগুলি"
_emailUnavailable: _emailUnavailable:
used: "এই ইমেইল ঠিকানাটি ইতোমধ্যে ব্যবহৃত হয়েছে" used: "এই ইমেইল ঠিকানাটি ইতোমধ্যে ব্যবহৃত হয়েছে"
format: "এই ইমেল ঠিকানাটি সঠিকভাবে লিখা হয়নি" format: "এই ইমেল ঠিকানাটি সঠিকভাবে লিখা হয়নি"
@@ -1638,8 +1639,6 @@ _notification:
_deck: _deck:
alwaysShowMainColumn: "সর্বদা মেইন কলাম দেখান" alwaysShowMainColumn: "সর্বদা মেইন কলাম দেখান"
columnAlign: "কলাম সাজান" columnAlign: "কলাম সাজান"
columnMargin: "কলামের মধ্যবর্তী মার্জিন"
columnHeaderHeight: "কলামের হেডারের উচ্চতা"
addColumn: "কলাম যুক্ত করুন" addColumn: "কলাম যুক্ত করুন"
swapLeft: "বামে সরান" swapLeft: "বামে সরান"
swapRight: "ডানে সরান" swapRight: "ডানে সরান"

View File

@@ -120,6 +120,7 @@ smtpUser: "Nom d'usuari"
smtpPass: "Contrasenya" smtpPass: "Contrasenya"
user: "Usuaris" user: "Usuaris"
searchByGoogle: "Cercar" searchByGoogle: "Cercar"
file: "Fitxers"
_email: _email:
_follow: _follow:
title: "t'ha seguit" title: "t'ha seguit"

View File

@@ -474,6 +474,7 @@ info: "Informace"
user: "Uživatelé" user: "Uživatelé"
administration: "Administrace" administration: "Administrace"
searchByGoogle: "Vyhledávání" searchByGoogle: "Vyhledávání"
file: "Soubor(ů)"
_email: _email:
_follow: _follow:
title: "Máte nového následovníka" title: "Máte nového následovníka"

View File

@@ -203,6 +203,7 @@ done: "Fertig"
processing: "In Bearbeitung …" processing: "In Bearbeitung …"
preview: "Vorschau" preview: "Vorschau"
default: "Standard" default: "Standard"
defaultValueIs: "Standardwert: {value}"
noCustomEmojis: "Keine benutzerdefinierten Emojis gefunden" noCustomEmojis: "Keine benutzerdefinierten Emojis gefunden"
noJobs: "Keine Jobs vorhanden" noJobs: "Keine Jobs vorhanden"
federating: "Wird föderiert" federating: "Wird föderiert"
@@ -356,7 +357,7 @@ antennaExcludeKeywords: "Zu ignorierende Schlüsselwörter"
antennaKeywordsDescription: "Zum Nutzen einer \"UND\"-Verknüpfung Einträge mit Leerzeichen trennen, zum Nutzen einer \"ODER\"-Verknüpfung Einträge mit einem Zeilenumbruch trennen" antennaKeywordsDescription: "Zum Nutzen einer \"UND\"-Verknüpfung Einträge mit Leerzeichen trennen, zum Nutzen einer \"ODER\"-Verknüpfung Einträge mit einem Zeilenumbruch trennen"
notifyAntenna: "Über neue Notizen benachrichtigen" notifyAntenna: "Über neue Notizen benachrichtigen"
withFileAntenna: "Nur Notizen mit Dateien" withFileAntenna: "Nur Notizen mit Dateien"
enableServiceworker: "ServiceWorker aktivieren" enableServiceworker: "Push-Benachrichtigungen im Browser aktivieren"
antennaUsersDescription: "Benutzernamen getrennt durch Zeilenumbrüche angeben" antennaUsersDescription: "Benutzernamen getrennt durch Zeilenumbrüche angeben"
caseSensitive: "Groß-/Kleinschreibung unterscheiden" caseSensitive: "Groß-/Kleinschreibung unterscheiden"
withReplies: "Antworten beinhalten" withReplies: "Antworten beinhalten"
@@ -381,6 +382,7 @@ administrator: "Administrator"
token: "Token" token: "Token"
twoStepAuthentication: "Zwei-Faktor-Authentifizierung" twoStepAuthentication: "Zwei-Faktor-Authentifizierung"
moderator: "Moderator" moderator: "Moderator"
moderation: "Moderation"
nUsersMentioned: "Von {n} Benutzern erwähnt" nUsersMentioned: "Von {n} Benutzern erwähnt"
securityKey: "Sicherheitsschlüssel" securityKey: "Sicherheitsschlüssel"
securityKeyName: "Schlüsselname" securityKeyName: "Schlüsselname"
@@ -425,7 +427,7 @@ quoteQuestion: "Als Zitat anhängen?"
noMessagesYet: "Noch keine Nachrichten vorhanden" noMessagesYet: "Noch keine Nachrichten vorhanden"
newMessageExists: "Du hast eine neue Nachricht" newMessageExists: "Du hast eine neue Nachricht"
onlyOneFileCanBeAttached: "Es kann pro Nachricht nur eine Datei angehängt werden" onlyOneFileCanBeAttached: "Es kann pro Nachricht nur eine Datei angehängt werden"
signinRequired: "Bitte melde dich an" signinRequired: "Bitte registriere oder melde dich an, um fortzufahren"
invitations: "Einladungen" invitations: "Einladungen"
invitationCode: "Einladungscode" invitationCode: "Einladungscode"
checking: "Wird überprüft …" checking: "Wird überprüft …"
@@ -643,6 +645,8 @@ clip: "Clip erstellen"
createNew: "Neu erstellen" createNew: "Neu erstellen"
optional: "Optional" optional: "Optional"
createNewClip: "Neuen Clip erstellen" createNewClip: "Neuen Clip erstellen"
unclip: "Aus Clip entfernen"
confirmToUnclipAlreadyClippedNote: "Diese Notiz ist bereits im \"{name}\" Clip enthalten. Möchtest du sie aus diesem Clip entfernen?"
public: "Öffentlich" public: "Öffentlich"
i18nInfo: "Misskey wird durch freiwillige Helfer in viele verschiedene Sprachen übersetzt. Auf {link} kannst du mithelfen." i18nInfo: "Misskey wird durch freiwillige Helfer in viele verschiedene Sprachen übersetzt. Auf {link} kannst du mithelfen."
manageAccessTokens: "Zugriffstokens verwalten" manageAccessTokens: "Zugriffstokens verwalten"
@@ -830,7 +834,7 @@ auto: "Automatisch"
themeColor: "Farbe der Instanz-Information" themeColor: "Farbe der Instanz-Information"
size: "Größe" size: "Größe"
numberOfColumn: "Spaltenanzahl" numberOfColumn: "Spaltenanzahl"
searchByGoogle: "Googlen" searchByGoogle: "Suchen"
instanceDefaultLightTheme: "Instanzweites Standardfarbschema (Hell)" instanceDefaultLightTheme: "Instanzweites Standardfarbschema (Hell)"
instanceDefaultDarkTheme: "Instanzweites Standardfarbschema (Dunkel)" instanceDefaultDarkTheme: "Instanzweites Standardfarbschema (Dunkel)"
instanceDefaultThemeDescription: "Gib den Farbschemencode im Objektformat ein." instanceDefaultThemeDescription: "Gib den Farbschemencode im Objektformat ein."
@@ -845,6 +849,26 @@ failedToFetchAccountInformation: "Benutzerkontoinformationen konnten nicht abgef
rateLimitExceeded: "Versuchsanzahl überschritten" rateLimitExceeded: "Versuchsanzahl überschritten"
cropImage: "Bild zuschneiden" cropImage: "Bild zuschneiden"
cropImageAsk: "Möchtest du das Bild zuschneiden?" cropImageAsk: "Möchtest du das Bild zuschneiden?"
file: "Datei"
recentNHours: "Letzten {n} Stunden"
recentNDays: "Letzten {n} Tage"
noEmailServerWarning: "Es ist kein Email-Server konfiguriert."
thereIsUnresolvedAbuseReportWarning: "Es liegen ungelöste Meldungen vor."
recommended: "Empfehlung"
check: "Check"
driveCapOverrideLabel: "Die Drive-Kapazität dieses Nutzers verändern"
driveCapOverrideCaption: "Gib einen Wert von 0 oder weniger ein, um die Kapazität auf den Standard zurückzusetzen."
requireAdminForView: "Melde dich mit einem Administratorkonto an, um dies einzusehen."
isSystemAccount: "Ein Benutzerkonto, dass durch das System erstellt und automatisch kontrolliert wird."
typeToConfirm: "Bitte gib zur Bestätigung {x} ein"
deleteAccount: "Benutzerkonto löschen"
document: "Dokument"
numberOfPageCache: "Seitencachegröße"
numberOfPageCacheDescription: "Das Erhöhen dieses Caches führt zu einer angenehmerern Benutzererfahrung, erhöht aber Serverlast und Arbeitsspeicherauslastung."
logoutConfirm: "Wirklich abmelden?"
lastActiveDate: "Zuletzt verwendet am"
statusbar: "Statusleiste"
pleaseSelect: "Wähle eine Option"
_emailUnavailable: _emailUnavailable:
used: "Diese Email-Adresse wird bereits verwendet" used: "Diese Email-Adresse wird bereits verwendet"
format: "Das Format dieser Email-Adresse ist ungültig" format: "Das Format dieser Email-Adresse ist ungültig"
@@ -1199,10 +1223,12 @@ _widgets:
trends: "Trends" trends: "Trends"
clock: "Uhr" clock: "Uhr"
rss: "RSS-Reader" rss: "RSS-Reader"
rssTicker: "RSS-Ticker"
activity: "Aktivität" activity: "Aktivität"
photos: "Fotos" photos: "Fotos"
digitalClock: "Digitaluhr" digitalClock: "Digitaluhr"
federation: "Föderation" federation: "Föderation"
instanceCloud: "Instanzwolke"
postForm: "Notizfenster" postForm: "Notizfenster"
slideshow: "Diashow" slideshow: "Diashow"
button: "Knopf" button: "Knopf"
@@ -1640,8 +1666,6 @@ _notification:
_deck: _deck:
alwaysShowMainColumn: "Hauptspalte immer zeigen" alwaysShowMainColumn: "Hauptspalte immer zeigen"
columnAlign: "Spaltenausrichtung" columnAlign: "Spaltenausrichtung"
columnMargin: "Spaltenabstand"
columnHeaderHeight: "Spaltenkopfhöhe"
addColumn: "Spalte hinzufügen" addColumn: "Spalte hinzufügen"
swapLeft: "Mit linker Spalte tauschen" swapLeft: "Mit linker Spalte tauschen"
swapRight: "Mit rechter Spalte tauschen" swapRight: "Mit rechter Spalte tauschen"
@@ -1650,6 +1674,9 @@ _deck:
stackLeft: "Auf linke Spalte stapeln" stackLeft: "Auf linke Spalte stapeln"
popRight: "Nach rechts vom Stapel nehmen" popRight: "Nach rechts vom Stapel nehmen"
profile: "Profil" profile: "Profil"
introduction: "Erstelle eine auf dich zugeschneiderte Benutzeroberfläche durch das Aneinanderreihen von Spalten!"
introduction2: "Klicke auf das + rechts um wann immer du möchtest neue Spalten hinzuzufügen."
widgetsIntroduction: "Drücke bitte \"Widgets bearbeiten\" im Spaltenmenü und füge ein Widget hinzu."
_columns: _columns:
main: "Hauptspalte" main: "Hauptspalte"
widgets: "Widgets" widgets: "Widgets"

View File

@@ -203,6 +203,7 @@ done: "Done"
processing: "Processing..." processing: "Processing..."
preview: "Preview" preview: "Preview"
default: "Default" default: "Default"
defaultValueIs: "Default: {value}"
noCustomEmojis: "There are no emoji" noCustomEmojis: "There are no emoji"
noJobs: "There are no jobs" noJobs: "There are no jobs"
federating: "Federating" federating: "Federating"
@@ -356,7 +357,7 @@ antennaExcludeKeywords: "Keywords to exclude"
antennaKeywordsDescription: "Separate with spaces for an AND condition or with line breaks for an OR condition." antennaKeywordsDescription: "Separate with spaces for an AND condition or with line breaks for an OR condition."
notifyAntenna: "Notify about new notes" notifyAntenna: "Notify about new notes"
withFileAntenna: "Only notes with files" withFileAntenna: "Only notes with files"
enableServiceworker: "Enable ServiceWorker" enableServiceworker: "Enable Push-Notifications for your Browser"
antennaUsersDescription: "List one username per line" antennaUsersDescription: "List one username per line"
caseSensitive: "Case sensitive" caseSensitive: "Case sensitive"
withReplies: "Include replies" withReplies: "Include replies"
@@ -381,6 +382,7 @@ administrator: "Administrator"
token: "Token" token: "Token"
twoStepAuthentication: "Two-factor authentication" twoStepAuthentication: "Two-factor authentication"
moderator: "Moderator" moderator: "Moderator"
moderation: "Moderation"
nUsersMentioned: "Mentioned by {n} users" nUsersMentioned: "Mentioned by {n} users"
securityKey: "Security key" securityKey: "Security key"
securityKeyName: "Key name" securityKeyName: "Key name"
@@ -425,7 +427,7 @@ quoteQuestion: "Append as quote?"
noMessagesYet: "No messages yet" noMessagesYet: "No messages yet"
newMessageExists: "There are new messages" newMessageExists: "There are new messages"
onlyOneFileCanBeAttached: "You can only attach one file to a message" onlyOneFileCanBeAttached: "You can only attach one file to a message"
signinRequired: "Please sign in" signinRequired: "Please register or sign in before continuing"
invitations: "Invites" invitations: "Invites"
invitationCode: "Invitation code" invitationCode: "Invitation code"
checking: "Checking..." checking: "Checking..."
@@ -643,6 +645,8 @@ clip: "Clip"
createNew: "Create new" createNew: "Create new"
optional: "Optional" optional: "Optional"
createNewClip: "Create new clip" createNewClip: "Create new clip"
unclip: "Unclip"
confirmToUnclipAlreadyClippedNote: "This note is already part of the \"{name}\" clip. Do you want to remove it from this clip instead?"
public: "Public" public: "Public"
i18nInfo: "Misskey is being translated into various languages by volunteers. You can help at {link}." i18nInfo: "Misskey is being translated into various languages by volunteers. You can help at {link}."
manageAccessTokens: "Manage access tokens" manageAccessTokens: "Manage access tokens"
@@ -830,7 +834,7 @@ auto: "Auto"
themeColor: "Instance Ticker Color" themeColor: "Instance Ticker Color"
size: "Size" size: "Size"
numberOfColumn: "Number of columns" numberOfColumn: "Number of columns"
searchByGoogle: "Google" searchByGoogle: "Search"
instanceDefaultLightTheme: "Instance-wide default light theme" instanceDefaultLightTheme: "Instance-wide default light theme"
instanceDefaultDarkTheme: "Instance-wide default dark theme" instanceDefaultDarkTheme: "Instance-wide default dark theme"
instanceDefaultThemeDescription: "Enter the theme code in object format." instanceDefaultThemeDescription: "Enter the theme code in object format."
@@ -845,6 +849,26 @@ failedToFetchAccountInformation: "Could not fetch account information"
rateLimitExceeded: "Rate limit exceeded" rateLimitExceeded: "Rate limit exceeded"
cropImage: "Crop image" cropImage: "Crop image"
cropImageAsk: "Do you want to crop this image?" cropImageAsk: "Do you want to crop this image?"
file: "File"
recentNHours: "Last {n} hours"
recentNDays: "Last {n} days"
noEmailServerWarning: "Email server not configured."
thereIsUnresolvedAbuseReportWarning: "There are unsolved reports."
recommended: "Recommended"
check: "Check"
driveCapOverrideLabel: "Change the drive capacity for this user"
driveCapOverrideCaption: "Reset the capacity to default by inputting a value of 0 or lower."
requireAdminForView: "You must log in with an administrator account to view this."
isSystemAccount: "An account created and automatically operated by the system."
typeToConfirm: "Please enter {x} to confirm"
deleteAccount: "Delete account"
document: "Document"
numberOfPageCache: "Number of cached pages"
numberOfPageCacheDescription: "Increasing this number will improve convenience for users but cause more server load as well as more memory to be used."
logoutConfirm: "Really log out?"
lastActiveDate: "Last used at"
statusbar: "Status bar"
pleaseSelect: "Select an option"
_emailUnavailable: _emailUnavailable:
used: "This email address is already being used" used: "This email address is already being used"
format: "The format of this email address is invalid" format: "The format of this email address is invalid"
@@ -1199,10 +1223,12 @@ _widgets:
trends: "Trending" trends: "Trending"
clock: "Clock" clock: "Clock"
rss: "RSS reader" rss: "RSS reader"
rssTicker: "RSS-Ticker"
activity: "Activity" activity: "Activity"
photos: "Photos" photos: "Photos"
digitalClock: "Digital clock" digitalClock: "Digital clock"
federation: "Federation" federation: "Federation"
instanceCloud: "Instance cloud"
postForm: "Posting form" postForm: "Posting form"
slideshow: "Slideshow" slideshow: "Slideshow"
button: "Button" button: "Button"
@@ -1640,8 +1666,6 @@ _notification:
_deck: _deck:
alwaysShowMainColumn: "Always show main column" alwaysShowMainColumn: "Always show main column"
columnAlign: "Align columns" columnAlign: "Align columns"
columnMargin: "Margin between columns"
columnHeaderHeight: "Column header height"
addColumn: "Add column" addColumn: "Add column"
swapLeft: "Swap with the left column" swapLeft: "Swap with the left column"
swapRight: "Swap with the right column" swapRight: "Swap with the right column"
@@ -1650,6 +1674,9 @@ _deck:
stackLeft: "Stack with the left column" stackLeft: "Stack with the left column"
popRight: "Pop column to the right" popRight: "Pop column to the right"
profile: "Profile" profile: "Profile"
introduction: "Create the perfect interface for you by arranging columns freely!"
introduction2: "Click on the + on the right of the screen to add new colums whenever you want."
widgetsIntroduction: "Please select \"Edit widgets\" in the column menu and add a widget."
_columns: _columns:
main: "Main" main: "Main"
widgets: "Widgets" widgets: "Widgets"

View File

@@ -592,6 +592,8 @@ smtpSecure: "Usar SSL/TLS implícito en la conexión SMTP"
smtpSecureInfo: "Apagar cuando se use STARTTLS" smtpSecureInfo: "Apagar cuando se use STARTTLS"
testEmail: "Prueba de envío" testEmail: "Prueba de envío"
wordMute: "Silenciar palabras" wordMute: "Silenciar palabras"
regexpError: "Error de la expresión regular"
regexpErrorDescription: "Ocurrió un error en la expresión regular en la linea {line} de las palabras muteadas {tab}"
instanceMute: "Instancias silenciadas" instanceMute: "Instancias silenciadas"
userSaysSomething: "{name} dijo algo" userSaysSomething: "{name} dijo algo"
makeActive: "Activar" makeActive: "Activar"
@@ -620,8 +622,9 @@ reportAbuse: "Reportar"
reportAbuseOf: "Reportar a {name}" reportAbuseOf: "Reportar a {name}"
fillAbuseReportDescription: "Ingrese los detalles del reporte. Si hay una nota en particular, ingrese la URL de esta." fillAbuseReportDescription: "Ingrese los detalles del reporte. Si hay una nota en particular, ingrese la URL de esta."
abuseReported: "Se ha enviado el reporte. Muchas gracias." abuseReported: "Se ha enviado el reporte. Muchas gracias."
reporteeOrigin: "Informar a" reporter: "Reportador"
reporterOrigin: "Origen del informe" reporteeOrigin: "Reportar a"
reporterOrigin: "Origen del reporte"
forwardReport: "Transferir un informe a una instancia remota" forwardReport: "Transferir un informe a una instancia remota"
forwardReportIsAnonymous: "No puede ver su información de la instancia remota y aparecerá como una cuenta anónima del sistema" forwardReportIsAnonymous: "No puede ver su información de la instancia remota y aparecerá como una cuenta anónima del sistema"
send: "Enviar" send: "Enviar"
@@ -640,6 +643,8 @@ clip: "Clip"
createNew: "Crear" createNew: "Crear"
optional: "Opcional" optional: "Opcional"
createNewClip: "Crear clip nuevo" createNewClip: "Crear clip nuevo"
unclip: "Quitar clip"
confirmToUnclipAlreadyClippedNote: "Esta nota ya está incluida en el clip \"{name}\". ¿Quiere quitar la nota del clip?"
public: "Público" public: "Público"
i18nInfo: "Misskey está siendo traducido a varios idiomas gracias a voluntarios. Se puede colaborar traduciendo en {link}" i18nInfo: "Misskey está siendo traducido a varios idiomas gracias a voluntarios. Se puede colaborar traduciendo en {link}"
manageAccessTokens: "Administrar tokens de acceso" manageAccessTokens: "Administrar tokens de acceso"
@@ -727,6 +732,7 @@ showingPastTimeline: "Mostrar líneas de tiempo antiguas"
clear: "Limpiar" clear: "Limpiar"
markAllAsRead: "Marcar todo como leído" markAllAsRead: "Marcar todo como leído"
goBack: "Deseleccionar" goBack: "Deseleccionar"
unlikeConfirm: "¿Quitar como favorito?"
fullView: "Vista completa" fullView: "Vista completa"
quitFullView: "quitar vista completa" quitFullView: "quitar vista completa"
addDescription: "Agregar descripción" addDescription: "Agregar descripción"
@@ -794,6 +800,7 @@ pubSub: "Cuentas Pub/Sub"
lastCommunication: "Última comunicación" lastCommunication: "Última comunicación"
resolved: "Resuelto" resolved: "Resuelto"
unresolved: "Sin resolver" unresolved: "Sin resolver"
breakFollow: "Dejar de seguir"
itsOn: "¡Está encendido!" itsOn: "¡Está encendido!"
itsOff: "¡Está apagado!" itsOff: "¡Está apagado!"
emailRequiredForSignup: "Se requere una dirección de correo electrónico para el registro de la cuenta" emailRequiredForSignup: "Se requere una dirección de correo electrónico para el registro de la cuenta"
@@ -807,16 +814,80 @@ classic: "Clásico"
muteThread: "Ocultar hilo" muteThread: "Ocultar hilo"
unmuteThread: "Mostrar hilo" unmuteThread: "Mostrar hilo"
ffVisibility: "Visibilidad de seguidores y seguidos" ffVisibility: "Visibilidad de seguidores y seguidos"
ffVisibilityDescription: "Puedes configurar quien puede ver a quienes sigues y quienes te siguen"
continueThread: "Ver la continuación del hilo"
deleteAccountConfirm: "La cuenta será borrada. ¿Está seguro?"
incorrectPassword: "La contraseña es incorrecta"
voteConfirm: "¿Confirma su voto a {choice}?"
hide: "Ocultar" hide: "Ocultar"
leaveGroup: "Dejar el grupo"
leaveGroupConfirm: "¿Desea salir de {name}?"
useDrawerReactionPickerForMobile: "Mostrar panel de reacciones en móviles"
welcomeBackWithName: "Bienvenido otra vez, {name}"
clickToFinishEmailVerification: "Cliquée {ok} y verifique su correo"
overridedDeviceKind: "Tipo de dispositivo"
smartphone: "Teléfono smartphone"
tablet: "Tablet"
auto: "Automático"
themeColor: "Color del tema"
size: "Tamaño"
numberOfColumn: "Cantidad de columnas"
searchByGoogle: "Buscar" searchByGoogle: "Buscar"
instanceDefaultLightTheme: "Tema claro por defecto de la instancia"
instanceDefaultDarkTheme: "Tema oscuro por defecto de la instancia"
instanceDefaultThemeDescription: "Ingrese el código del tema en formato objeto"
mutePeriod: "Período de silenciamiento"
indefinitely: "Sin límite de tiempo" indefinitely: "Sin límite de tiempo"
tenMinutes: "10 minutos"
oneHour: "1 hora"
oneDay: "1 día"
oneWeek: "1 semana"
reflectMayTakeTime: "Puede pasar un tiempo hasta que se reflejen los cambios"
failedToFetchAccountInformation: "No se pudo obtener información de la cuenta"
rateLimitExceeded: "Se excedió el límite de peticiones"
cropImage: "Recortar imágen"
cropImageAsk: "¿Desea recortar la imagen?"
file: "Archivos"
recentNHours: "Últimas {n} horas"
recentNDays: "Últimos {n} días"
noEmailServerWarning: "No se ha configurado un servidor de correo electrónico."
thereIsUnresolvedAbuseReportWarning: "Hay reportes sin resolver"
recommended: "Recomendado"
check: "Verificar"
isSystemAccount: "Cuenta creada y operada automáticamente por el sistema"
typeToConfirm: "Ingrese {x} para confirmar"
deleteAccount: "Borrar cuenta"
document: "Documento"
numberOfPageCache: "Cantidad de páginas cacheadas"
numberOfPageCacheDescription: "Al aumentar el número mejora la conveniencia pero tambien puede aumentar la carga y la memoria a usarse"
logoutConfirm: "¿Cerrar sesión?"
_emailUnavailable:
used: "Ya fue usado"
format: "Formato no válido."
disposable: "No es un correo reutilizable"
mx: "Servidor de correo inválido"
smtp: "Servidor de correo no disponible"
_ffVisibility: _ffVisibility:
public: "Publicar" public: "Publicar"
followers: "Visible solo para seguidores"
private: "Privado"
_signup:
almostThere: "Ya falta poco"
emailAddressInfo: "Ingrese el correo electrónico que usa. Este no se hará público."
emailSent: "Se envió un correo de verificación a la dirección {email}. Acceda al link enviado en el correo para completar el ingreso."
_accountDelete: _accountDelete:
accountDelete: "Eliminar Cuenta" accountDelete: "Eliminar Cuenta"
mayTakeTime: "La eliminación de la cuenta es un proceso que precisa de carga. Puede pasar un tiempo hasta que se complete si es mucho el contenido creado y los archivos subidos."
sendEmail: "Cuando se termine de borrar la cuenta, se enviará un correo a la dirección usada para el registro."
requestAccountDelete: "Pedir la eliminación de la cuenta."
started: "El proceso de eliminación ha comenzado."
inProgress: "La eliminación está en proceso."
_ad: _ad:
back: "Deseleccionar" back: "Deseleccionar"
reduceFrequencyOfThisAd: "Mostrar menos este anuncio."
_forgotPassword: _forgotPassword:
enterEmail: "Ingrese el correo usado para registrar la cuenta. Se enviará un link para resetear la contraseña."
ifNoEmail: "Si no utilizó un correo para crear la cuenta, contáctese con el administrador."
contactAdmin: "Esta instancia no admite el uso de direcciones de correo electrónico, póngase en contacto con el administrador de la instancia para restablecer su contraseña" contactAdmin: "Esta instancia no admite el uso de direcciones de correo electrónico, póngase en contacto con el administrador de la instancia para restablecer su contraseña"
_gallery: _gallery:
my: "Mi galería" my: "Mi galería"
@@ -858,20 +929,63 @@ _mfm:
mention: "Menciones" mention: "Menciones"
mentionDescription: "El signo @ seguido de un nombre de usuario se puede utilizar para notificar a un usuario en particular." mentionDescription: "El signo @ seguido de un nombre de usuario se puede utilizar para notificar a un usuario en particular."
hashtag: "Hashtag" hashtag: "Hashtag"
hashtagDescription: "Puede especificar un hashtag con un numeral y el texto."
url: "URL" url: "URL"
urlDescription: "Se pueden mostrar las URL" urlDescription: "Se pueden mostrar las URL"
link: "Vínculo" link: "Vínculo"
linkDescription: "Se pueden asociar partes de texto a la URL"
bold: "Negrita" bold: "Negrita"
boldDescription: "Muestra el texto con las letras más gruesas"
small: "Pequeño"
smallDescription: "Muestra el texto más pequeño y delgado"
center: "Centrar" center: "Centrar"
centerDescription: "Muestra el texto centrado"
inlineCode: "Código (insertado)"
inlineCodeDescription: "Muestra el código de un programa resaltando su sintaxis"
blockCode: "Código (bloque)" blockCode: "Código (bloque)"
blockCodeDescription: "Código de resaltado de sintaxis, como programas de varias líneas con bloques." blockCodeDescription: "Código de resaltado de sintaxis, como programas de varias líneas con bloques."
inlineMath: "Fórmula (insertado)"
inlineMathDescription: "Muestra fórmulas (KaTeX) insertadas"
blockMath: "Fórmula (bloque)"
blockMathDescription: "Muestra fórmulas (KaTeX) de varias líneas en un bloque"
quote: "Citar" quote: "Citar"
quoteDescription: "Muestra el contenido como una cita"
emoji: "Emojis personalizados" emoji: "Emojis personalizados"
emojiDescription: "Muestra los emojis personalizados encerrados entre dos puntos."
search: "Buscar" search: "Buscar"
searchDescription: "Muestra una caja de búsqueda con texto pre-escrito"
flip: "Echar de un capirotazo" flip: "Echar de un capirotazo"
flipDescription: "Voltea el contenido hacia arriba / abajo o hacia la izquierda / derecha." flipDescription: "Voltea el contenido hacia arriba / abajo o hacia la izquierda / derecha."
jelly: "Animación (gelatina)"
jellyDescription: "Aplica un efecto de animación tipo gelatina"
tada: "Animación (tadá)"
tadaDescription: "Aplica un efecto de animación al estilo \"Tadá\""
jump: "Animación (saltar)"
jumpDescription: "Aplica un efecto de animación tipo salto"
bounce: "Animación (rebotar)"
bounceDescription: "Aplica un efecto de animación tipo rebote"
shake: "Animación (temblor)"
shakeDescription: "Aplica un efecto de animación tipo temblor"
twitch: "Animación (sacudida)"
twitchDescription: "Aplica un efecto de animación tipo sacudida"
spin: "Animación (giro)"
spinDescription: "Aplica un efecto de animación tipo rotación"
x2: "Grande"
x2Description: "Muestra el contenido más grande"
x3: "Muy grande"
x3Description: "Muestra el contenido mucho más grande"
x4: "Totalmente grande"
x4Description: "Muestra el contenido totalmente grande"
blur: "Desenfoque"
blurDescription: "Para desenfocar el contenido. Se muestra claramente al colocar el puntero encima."
font: "Fuente" font: "Fuente"
fontDescription: "Elegir la fuente del contenido"
rainbow: "Arcoíris"
rainbowDescription: "Muestra el contenido con los colores del arcoíris"
sparkle: "Parpadeante"
sparkleDescription: "Aplica un efecto de partículas parpadeantes"
rotate: "Rotar" rotate: "Rotar"
rotateDescription: "Rota el contenido a un ángulo especificado."
_instanceTicker: _instanceTicker:
none: "No mostrar" none: "No mostrar"
remote: "Mostrar a usuarios remotos" remote: "Mostrar a usuarios remotos"
@@ -893,6 +1007,7 @@ _channel:
_menuDisplay: _menuDisplay:
sideFull: "Horizontal" sideFull: "Horizontal"
sideIcon: "Horizontal (ícono)" sideIcon: "Horizontal (ícono)"
top: "Arriba"
hide: "Ocultar" hide: "Ocultar"
_wordMute: _wordMute:
muteWords: "Palabras que silenciar" muteWords: "Palabras que silenciar"
@@ -915,6 +1030,8 @@ _theme:
code: "Código del tema" code: "Código del tema"
description: "Descripción" description: "Descripción"
installed: "{name} ha sido instalado" installed: "{name} ha sido instalado"
installedThemes: "Temas instalados"
builtinThemes: "Temas integrados"
alreadyInstalled: "Este tema ya está instalado" alreadyInstalled: "Este tema ya está instalado"
invalid: "El formato del tema no es válido" invalid: "El formato del tema no es válido"
make: "Crear tema" make: "Crear tema"
@@ -1032,6 +1149,7 @@ _2fa:
registerKey: "Registrar clave" registerKey: "Registrar clave"
step1: "Primero, instale en su dispositivo la aplicación de autenticación {a} o {b} u otra." step1: "Primero, instale en su dispositivo la aplicación de autenticación {a} o {b} u otra."
step2: "Luego, escanee con la aplicación el código QR mostrado en pantalla." step2: "Luego, escanee con la aplicación el código QR mostrado en pantalla."
step2Url: "En una aplicación de escritorio se puede ingresar la siguiente URL:"
step3: "Para terminar, ingrese el token mostrado en la aplicación." step3: "Para terminar, ingrese el token mostrado en la aplicación."
step4: "Ahora cuando inicie sesión, ingrese el mismo token" step4: "Ahora cuando inicie sesión, ingrese el mismo token"
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" 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"
@@ -1064,6 +1182,10 @@ _permissions:
"write:user-groups": "Administrar grupos de usuarios" "write:user-groups": "Administrar grupos de usuarios"
"read:channels": "Ver canal" "read:channels": "Ver canal"
"write:channels": "Modificar canal" "write:channels": "Modificar canal"
"read:gallery": "Ver galería"
"write:gallery": "Editar galería"
"read:gallery-likes": "Ver favoritos de la galería"
"write:gallery-likes": "Editar favoritos de la galería"
_auth: _auth:
shareAccess: "¿Desea permitir el acceso a la cuenta \"{name}\"?" shareAccess: "¿Desea permitir el acceso a la cuenta \"{name}\"?"
shareAccessAsk: "¿Está seguro de que desea autorizar esta aplicación para acceder a su cuenta?" shareAccessAsk: "¿Está seguro de que desea autorizar esta aplicación para acceder a su cuenta?"
@@ -1097,9 +1219,15 @@ _widgets:
photos: "Fotos" photos: "Fotos"
digitalClock: "Reloj digital" digitalClock: "Reloj digital"
federation: "Federación" federation: "Federación"
instanceCloud: "Nube de palabras de la instancia"
postForm: "Formulario" postForm: "Formulario"
slideshow: "Diapositivas"
button: "Botón" button: "Botón"
onlineUsers: "Usuarios en linea"
jobQueue: "Cola de trabajos" jobQueue: "Cola de trabajos"
serverMetric: "Estadísticas del servidor"
aiscript: "Consola de AiScript"
aichan: "indigo"
_cw: _cw:
hide: "Ocultar" hide: "Ocultar"
show: "Ver más" show: "Ver más"
@@ -1154,14 +1282,21 @@ _profile:
username: "Nombre de usuario" username: "Nombre de usuario"
description: "Descripción" description: "Descripción"
youCanIncludeHashtags: "Puedes añadir hashtags" youCanIncludeHashtags: "Puedes añadir hashtags"
metadata: "información adicional"
metadataEdit: "Editar información adicional"
metadataDescription: "Muestra la información adicional en el perfil"
metadataLabel: "Etiqueta" metadataLabel: "Etiqueta"
metadataContent: "Contenido" metadataContent: "Contenido"
changeAvatar: "Cambiar avatar"
changeBanner: "Cambiar banner"
_exportOrImport: _exportOrImport:
allNotes: "Todas las notas" allNotes: "Todas las notas"
followingList: "Siguiendo" followingList: "Siguiendo"
muteList: "Silenciados" muteList: "Silenciados"
blockingList: "Bloqueados" blockingList: "Bloqueados"
userLists: "Listas" userLists: "Listas"
excludeMutingUsers: "Excluir usuarios silenciados"
excludeInactiveUsers: "Excluir usuarios inactivos"
_charts: _charts:
federation: "Federación" federation: "Federación"
apRequest: "Pedidos" apRequest: "Pedidos"
@@ -1200,6 +1335,7 @@ _pages:
created: "La página fue creada" created: "La página fue creada"
updated: "La página fue actualizada" updated: "La página fue actualizada"
deleted: "La página borrada" deleted: "La página borrada"
pageSetting: "Configurar página"
nameAlreadyExists: "La URL de la página especificada ya existe" nameAlreadyExists: "La URL de la página especificada ya existe"
invalidNameTitle: "URL inválida" invalidNameTitle: "URL inválida"
invalidNameText: "Verifique que no tenga espacios en blanco" invalidNameText: "Verifique que no tenga espacios en blanco"
@@ -1210,6 +1346,7 @@ _pages:
unlike: "Quitar me gusta" unlike: "Quitar me gusta"
my: "Mis páginas" my: "Mis páginas"
liked: "Páginas que me gustan" liked: "Páginas que me gustan"
featured: "Popular"
inspector: "Inspector" inspector: "Inspector"
contents: "Contenido" contents: "Contenido"
content: "Bloque de página" content: "Bloque de página"
@@ -1265,6 +1402,11 @@ _pages:
id: "Lienzo ID" id: "Lienzo ID"
width: "Ancho" width: "Ancho"
height: "Altura" height: "Altura"
note: "Nota embebida"
_note:
id: "Id de la nota"
idDescription: "Pega la URL de la nota para configurarla"
detailed: "Ver Detalles"
switch: "Interruptor" switch: "Interruptor"
_switch: _switch:
name: "Nombre de variable" name: "Nombre de variable"
@@ -1492,6 +1634,8 @@ _notification:
youReceivedFollowRequest: "Has mandado una solicitud de seguimiento" youReceivedFollowRequest: "Has mandado una solicitud de seguimiento"
yourFollowRequestAccepted: "Tu solicitud de seguimiento fue aceptada" yourFollowRequestAccepted: "Tu solicitud de seguimiento fue aceptada"
youWereInvitedToGroup: "Invitado al grupo" youWereInvitedToGroup: "Invitado al grupo"
pollEnded: "Estan disponibles los resultados de la encuesta"
emptyPushNotificationMessage: "Se han actualizado las notificaciones push"
_types: _types:
all: "Todo" all: "Todo"
follow: "Siguiendo" follow: "Siguiendo"
@@ -1501,11 +1645,13 @@ _notification:
quote: "Citar" quote: "Citar"
reaction: "Reacción" reaction: "Reacción"
pollVote: "Votado en la encuesta" pollVote: "Votado en la encuesta"
pollEnded: "La encuesta terminó"
receiveFollowRequest: "Recibió una solicitud de seguimiento" receiveFollowRequest: "Recibió una solicitud de seguimiento"
followRequestAccepted: "El seguimiento fue aceptado" followRequestAccepted: "El seguimiento fue aceptado"
groupInvited: "Invitado al grupo" groupInvited: "Invitado al grupo"
app: "Notificaciones desde aplicaciones" app: "Notificaciones desde aplicaciones"
_actions: _actions:
followBack: "Te sigue de vuelta"
reply: "Responder" reply: "Responder"
renote: "Renotar" renote: "Renotar"
_deck: _deck:
@@ -1518,7 +1664,9 @@ _deck:
swapDown: "Mover abajo" swapDown: "Mover abajo"
stackLeft: "Apilar a la izquierda" stackLeft: "Apilar a la izquierda"
popRight: "Sacar a la derecha" popRight: "Sacar a la derecha"
profile: "Perfil"
_columns: _columns:
main: "Principal"
widgets: "Widgets" widgets: "Widgets"
notifications: "Notificaciones" notifications: "Notificaciones"
tl: "Linea de tiempo" tl: "Linea de tiempo"

View File

@@ -815,6 +815,7 @@ voteConfirm: "Confirmez-vous votre vote pour « {choice} » ?"
hide: "Masquer" hide: "Masquer"
leaveGroup: "Quitter le groupe" leaveGroup: "Quitter le groupe"
leaveGroupConfirm: "Êtes vous sûr de vouloir quitter \"{name}\" ?" leaveGroupConfirm: "Êtes vous sûr de vouloir quitter \"{name}\" ?"
useDrawerReactionPickerForMobile: "Afficher le sélecteur de réactions en tant que panneau sur mobile"
welcomeBackWithName: "Heureux de vous revoir, {name}" welcomeBackWithName: "Heureux de vous revoir, {name}"
clickToFinishEmailVerification: "Veuillez cliquer sur [{ok}] afin de compléter la vérification par courriel." clickToFinishEmailVerification: "Veuillez cliquer sur [{ok}] afin de compléter la vérification par courriel."
overridedDeviceKind: "Type dappareil" overridedDeviceKind: "Type dappareil"
@@ -827,15 +828,21 @@ numberOfColumn: "Nombre de colonnes"
searchByGoogle: "Google" searchByGoogle: "Google"
instanceDefaultLightTheme: "Thème clair par défaut sur toute linstance" instanceDefaultLightTheme: "Thème clair par défaut sur toute linstance"
instanceDefaultDarkTheme: "Thème sombre par défaut sur toute linstance" instanceDefaultDarkTheme: "Thème sombre par défaut sur toute linstance"
instanceDefaultThemeDescription: "Saisissez le code du thème en format objet."
mutePeriod: "Durée de mise en sourdine" mutePeriod: "Durée de mise en sourdine"
indefinitely: "Illimité" indefinitely: "Illimité"
tenMinutes: "10 minutes" tenMinutes: "10 minutes"
oneHour: "1 heure" oneHour: "1 heure"
oneDay: "1 jour" oneDay: "1 jour"
oneWeek: "1 semaine" oneWeek: "1 semaine"
rateLimitExceeded: "Limite de taux dépassée"
cropImage: "Recadrer l'image"
cropImageAsk: "Voulez-vous recadrer cette image ?"
file: "Fichiers"
_emailUnavailable: _emailUnavailable:
used: "Non disponible" used: "Non disponible"
format: "Le format de cette adresse de courriel est invalide" format: "Le format de cette adresse de courriel est invalide"
disposable: "Les adresses e-mail jetables ne peuvent pas être utilisées"
mx: "Ce serveur de courriels est invalide" mx: "Ce serveur de courriels est invalide"
smtp: "Ce serveur de courriels ne répond pas" smtp: "Ce serveur de courriels ne répond pas"
_ffVisibility: _ffVisibility:
@@ -1118,6 +1125,7 @@ _2fa:
registerKey: "Enregistrer une clef" registerKey: "Enregistrer une clef"
step1: "Tout d'abord, installez une application d'authentification, telle que {a} ou {b}, sur votre appareil." step1: "Tout d'abord, installez une application d'authentification, telle que {a} ou {b}, sur votre appareil."
step2: "Ensuite, scannez le code QR affiché sur lécran." step2: "Ensuite, scannez le code QR affiché sur lécran."
step2Url: "Vous pouvez également saisir cette URL si vous utilisez un programme de bureau :"
step3: "Entrez le jeton affiché sur votre application pour compléter la configuration." step3: "Entrez le jeton affiché sur votre application pour compléter la configuration."
step4: "À partir de maintenant, ce même jeton vous sera demandé à chacune de vos connexions." step4: "À partir de maintenant, ce même jeton vous sera demandé à chacune de vos connexions."
securityKeyInfo: "Vous pouvez configurer l'authentification WebAuthN pour sécuriser davantage le processus de connexion grâce à une clé de sécurité matérielle qui prend en charge FIDO2, ou bien en configurant l'authentification par empreinte digitale ou par code PIN sur votre appareil." securityKeyInfo: "Vous pouvez configurer l'authentification WebAuthN pour sécuriser davantage le processus de connexion grâce à une clé de sécurité matérielle qui prend en charge FIDO2, ou bien en configurant l'authentification par empreinte digitale ou par code PIN sur votre appareil."
@@ -1601,6 +1609,8 @@ _notification:
youReceivedFollowRequest: "Vous avez reçu une demande dabonnement" youReceivedFollowRequest: "Vous avez reçu une demande dabonnement"
yourFollowRequestAccepted: "Votre demande dabonnement a été accepté" yourFollowRequestAccepted: "Votre demande dabonnement a été accepté"
youWereInvitedToGroup: "Invité·e au groupe" youWereInvitedToGroup: "Invité·e au groupe"
pollEnded: "Les résultats du sondage sont disponibles"
emptyPushNotificationMessage: "Les notifications push ont été mises à jour"
_types: _types:
all: "Toutes" all: "Toutes"
follow: "Nouvel·le abonné·e" follow: "Nouvel·le abonné·e"
@@ -1615,13 +1625,12 @@ _notification:
groupInvited: "Invitation à un groupe" groupInvited: "Invitation à un groupe"
app: "Notifications provenant des apps" app: "Notifications provenant des apps"
_actions: _actions:
followBack: "Suivre"
reply: "Répondre" reply: "Répondre"
renote: "Renoter" renote: "Renoter"
_deck: _deck:
alwaysShowMainColumn: "Toujours afficher la colonne principale" alwaysShowMainColumn: "Toujours afficher la colonne principale"
columnAlign: "Aligner les colonnes" columnAlign: "Aligner les colonnes"
columnMargin: "Marge entre les colonnes"
columnHeaderHeight: "Taille de l'en-tête de colonne"
addColumn: "Ajouter une colonne" addColumn: "Ajouter une colonne"
swapLeft: "Déplacer à gauche" swapLeft: "Déplacer à gauche"
swapRight: "Déplacer à droite" swapRight: "Déplacer à droite"

View File

@@ -81,7 +81,7 @@ somethingHappened: "Terjadi kesalahan"
retry: "Coba lagi" retry: "Coba lagi"
pageLoadError: "Gagal memuat halaman." pageLoadError: "Gagal memuat halaman."
pageLoadErrorDescription: "Umumnya disebabkan jaringan atau tembolok perambah. Cobalah bersihkan tembolok peramban lalu tunggu sesaat sebelum mencoba kembali." pageLoadErrorDescription: "Umumnya disebabkan jaringan atau tembolok perambah. Cobalah bersihkan tembolok peramban lalu tunggu sesaat sebelum mencoba kembali."
serverIsDead: "Tidak ada respon dari server. Mohon tunggu dan coba beberapa saat lagi." serverIsDead: "Tidak ada respon dari peladen. Mohon tunggu dan coba beberapa saat lagi."
youShouldUpgradeClient: "Untuk melihat halaman ini, mohon muat ulang untuk memutakhirkan klienmu." youShouldUpgradeClient: "Untuk melihat halaman ini, mohon muat ulang untuk memutakhirkan klienmu."
enterListName: "Masukkan nama daftar" enterListName: "Masukkan nama daftar"
privacy: "Privasi" privacy: "Privasi"
@@ -294,8 +294,8 @@ rename: "Ubah nama"
avatar: "Avatar" avatar: "Avatar"
banner: "Banner" banner: "Banner"
nsfw: "Konten sensitif" nsfw: "Konten sensitif"
whenServerDisconnected: "Ketika kehilangan koneksi dengan server" whenServerDisconnected: "Ketika kehilangan koneksi dengan peladen"
disconnectedFromServer: "Terputus koneksi dari server" disconnectedFromServer: "Terputus koneksi dari peladen"
reload: "Muat ulang" reload: "Muat ulang"
doNothing: "Abaikan" doNothing: "Abaikan"
reloadConfirm: "Apakah kamu ingin memuat ulang linimasa?" reloadConfirm: "Apakah kamu ingin memuat ulang linimasa?"
@@ -495,7 +495,7 @@ objectStorageUseSSLDesc: "Matikan ini jika kamu tidak akan menggunakan HTTPS unt
objectStorageUseProxy: "Hubungkan melalui Proxy" objectStorageUseProxy: "Hubungkan melalui Proxy"
objectStorageUseProxyDesc: "Matikan ini jika kamu tidak akan menggunakan Proxy untuk koneksi ObjectStorage" objectStorageUseProxyDesc: "Matikan ini jika kamu tidak akan menggunakan Proxy untuk koneksi ObjectStorage"
objectStorageSetPublicRead: "Setel \"public-read\" disaat mengunggah" objectStorageSetPublicRead: "Setel \"public-read\" disaat mengunggah"
serverLogs: "Log Server" serverLogs: "Log Peladen"
deleteAll: "Hapus semua" deleteAll: "Hapus semua"
showFixedPostForm: "Tampilkan form posting di atas linimasa." showFixedPostForm: "Tampilkan form posting di atas linimasa."
newNoteRecived: "Kamu mendapat catatan baru" newNoteRecived: "Kamu mendapat catatan baru"
@@ -533,7 +533,7 @@ removeAllFollowingDescription: "Batal mengikuti semua akun dari {host}. Mohon ja
userSuspended: "Pengguna ini telah dibekukan." userSuspended: "Pengguna ini telah dibekukan."
userSilenced: "Pengguna ini telah dibungkam." userSilenced: "Pengguna ini telah dibungkam."
yourAccountSuspendedTitle: "Akun ini dibekukan" yourAccountSuspendedTitle: "Akun ini dibekukan"
yourAccountSuspendedDescription: "Akun ini dibekukan karena melanggar ketentuan penggunaan layanan server atau semacamnya. Hubungi admin apabila ingin tahu alasan lebih lanjut. Mohon untuk tidak membuat akun baru." yourAccountSuspendedDescription: "Akun ini dibekukan karena melanggar ketentuan penggunaan layanan peladen atau semacamnya. Hubungi admin apabila ingin tahu alasan lebih lanjut. Mohon untuk tidak membuat akun baru."
menu: "Menu" menu: "Menu"
divider: "Pembagi" divider: "Pembagi"
addItem: "Tambahkan item" addItem: "Tambahkan item"
@@ -577,12 +577,12 @@ pluginTokenRequestedDescription: "Plugin ini dapat menggunakan setelan ijin disi
notificationType: "Jenis pemberitahuan" notificationType: "Jenis pemberitahuan"
edit: "Sunting" edit: "Sunting"
useStarForReactionFallback: "Gunakan ★ sebagai fallback jika reaksi emoji tidak diketahui" useStarForReactionFallback: "Gunakan ★ sebagai fallback jika reaksi emoji tidak diketahui"
emailServer: "Server surel" emailServer: "Peladen surel"
enableEmail: "Nyalakan distribusi surel" enableEmail: "Nyalakan distribusi surel"
emailConfigInfo: "Digunakan untuk mengonfirmasi surel kamu disaat mendaftar dan lupa kata sandi" emailConfigInfo: "Digunakan untuk mengonfirmasi surel kamu disaat mendaftar dan lupa kata sandi"
email: "Surel" email: "Surel"
emailAddress: "Alamat surel" emailAddress: "Alamat surel"
smtpConfig: "Konfigurasi server SMTP" smtpConfig: "Konfigurasi peladen SMTP"
smtpHost: "Host" smtpHost: "Host"
smtpPort: "Port" smtpPort: "Port"
smtpUser: "Nama Pengguna" smtpUser: "Nama Pengguna"
@@ -643,6 +643,8 @@ clip: "Klip"
createNew: "Buat baru" createNew: "Buat baru"
optional: "Opsional" optional: "Opsional"
createNewClip: "Buat klip baru" createNewClip: "Buat klip baru"
unclip: "Batalkan klip"
confirmToUnclipAlreadyClippedNote: "Catatan ini sudah disertakan di klip \"{name}\". Yakin ingin membatalkan catatan dari klip ini?"
public: "Publik" public: "Publik"
i18nInfo: "Misskey diterjemahkan ke dalam banyak bahasa oleh sukarelawan. Kamu dapat ikut membantu di {link}." i18nInfo: "Misskey diterjemahkan ke dalam banyak bahasa oleh sukarelawan. Kamu dapat ikut membantu di {link}."
manageAccessTokens: "Kelola access token" manageAccessTokens: "Kelola access token"
@@ -791,7 +793,7 @@ whatIsNew: "Lihat perubahan pemutakhiran"
translate: "Terjemahkan" translate: "Terjemahkan"
translatedFrom: "Terjemahkan dari {x}" translatedFrom: "Terjemahkan dari {x}"
accountDeletionInProgress: "Penghapusan akun sedang dalam proses" accountDeletionInProgress: "Penghapusan akun sedang dalam proses"
usernameInfo: "Nama yang mengidentifikasikan akun kamu dari yang lain pada server ini. Kamu dapat menggunakan alfabet (a~z, A~Z), digit (0~9) atau garis bawah (_). Username tidak dapat diubah setelahnya." usernameInfo: "Nama yang mengidentifikasikan akun kamu dari yang lain pada peladen ini. Kamu dapat menggunakan alfabet (a~z, A~Z), digit (0~9) atau garis bawah (_). Username tidak dapat diubah setelahnya."
aiChanMode: "Mode Ai" aiChanMode: "Mode Ai"
keepCw: "Biarkan Peringatan Konten" keepCw: "Biarkan Peringatan Konten"
pubSub: "Akun Pub/Sub" pubSub: "Akun Pub/Sub"
@@ -804,7 +806,7 @@ itsOff: "Nonaktif"
emailRequiredForSignup: "Membutuhkan alamat surel untuk mendaftar" emailRequiredForSignup: "Membutuhkan alamat surel untuk mendaftar"
unread: "Belum dibaca" unread: "Belum dibaca"
filter: "Saring" filter: "Saring"
controlPanel: "Panel kontrol" controlPanel: "Panel kendali"
manageAccounts: "Kelola Akun" manageAccounts: "Kelola Akun"
makeReactionsPublic: "Tampilkan riwayat reaksi ke publik" makeReactionsPublic: "Tampilkan riwayat reaksi ke publik"
makeReactionsPublicDescription: "Pengaturan ini akan membuat daftar dari semua reaksi masa lalu kamu ditampilkan secara publik." makeReactionsPublicDescription: "Pengaturan ini akan membuat daftar dari semua reaksi masa lalu kamu ditampilkan secara publik."
@@ -845,12 +847,13 @@ failedToFetchAccountInformation: "Gagal untuk mendapatkan informasi akun"
rateLimitExceeded: "Batas sudah terlampaui" rateLimitExceeded: "Batas sudah terlampaui"
cropImage: "potong gambar" cropImage: "potong gambar"
cropImageAsk: "Ingin memotong gambar?" cropImageAsk: "Ingin memotong gambar?"
file: "Berkas"
_emailUnavailable: _emailUnavailable:
used: "Alamat surel ini telah digunakan" used: "Alamat surel ini telah digunakan"
format: "Format tidak valid." format: "Format tidak valid."
disposable: "Alamat surel temporer tidak dapat digunakan" disposable: "Alamat surel temporer tidak dapat digunakan"
mx: "Server alamat surel ini tidak valid" mx: "Peladen alamat surel ini tidak valid"
smtp: "Server alamat surel ini tidak merespon" smtp: "Peladen alamat surel ini tidak merespon"
_ffVisibility: _ffVisibility:
public: "Terbitkan" public: "Terbitkan"
followers: "Tampil untuk pengikut saja" followers: "Tampil untuk pengikut saja"
@@ -1208,7 +1211,7 @@ _widgets:
button: "Tombol" button: "Tombol"
onlineUsers: "Pengguna online" onlineUsers: "Pengguna online"
jobQueue: "Antrian kerja" jobQueue: "Antrian kerja"
serverMetric: "Statistik server" serverMetric: "Statistik peladen"
aiscript: "Konsol AiScript" aiscript: "Konsol AiScript"
aichan: "Ai" aichan: "Ai"
_cw: _cw:
@@ -1640,8 +1643,6 @@ _notification:
_deck: _deck:
alwaysShowMainColumn: "Selalu tampilkan kolom utama" alwaysShowMainColumn: "Selalu tampilkan kolom utama"
columnAlign: "Luruskan kolom" columnAlign: "Luruskan kolom"
columnMargin: "Batas antar kolom"
columnHeaderHeight: "Tinggi kolom header"
addColumn: "Tambahkan kolom" addColumn: "Tambahkan kolom"
swapLeft: "Pindah ke kiri" swapLeft: "Pindah ke kiri"
swapRight: "Pindah ke kanan" swapRight: "Pindah ke kanan"

View File

@@ -809,6 +809,7 @@ tenMinutes: "10 minuti"
oneHour: "1 ora" oneHour: "1 ora"
oneDay: "1 giorno" oneDay: "1 giorno"
oneWeek: "1 settimana" oneWeek: "1 settimana"
file: "Allegati"
_emailUnavailable: _emailUnavailable:
used: "Email già in uso" used: "Email già in uso"
format: "Formato email non valido" format: "Formato email non valido"
@@ -1443,8 +1444,6 @@ _notification:
_deck: _deck:
alwaysShowMainColumn: "Mostra sempre la colonna principale" alwaysShowMainColumn: "Mostra sempre la colonna principale"
columnAlign: "Allineare colonne" columnAlign: "Allineare colonne"
columnMargin: "Margine tra le colonne"
columnHeaderHeight: "Dimensioni dell'intestazione della colonna"
addColumn: "Aggiungi colonna" addColumn: "Aggiungi colonna"
swapLeft: "Sposta a sinistra" swapLeft: "Sposta a sinistra"
swapRight: "Sposta a destra" swapRight: "Sposta a destra"

View File

@@ -203,6 +203,7 @@ done: "完了"
processing: "処理中" processing: "処理中"
preview: "プレビュー" preview: "プレビュー"
default: "デフォルト" default: "デフォルト"
defaultValueIs: "デフォルト: {value}"
noCustomEmojis: "絵文字はありません" noCustomEmojis: "絵文字はありません"
noJobs: "ジョブはありません" noJobs: "ジョブはありません"
federating: "連合中" federating: "連合中"
@@ -381,6 +382,7 @@ administrator: "管理者"
token: "トークン" token: "トークン"
twoStepAuthentication: "二段階認証" twoStepAuthentication: "二段階認証"
moderator: "モデレーター" moderator: "モデレーター"
moderation: "モデレーション"
nUsersMentioned: "{n}人が投稿" nUsersMentioned: "{n}人が投稿"
securityKey: "セキュリティキー" securityKey: "セキュリティキー"
securityKeyName: "キーの名前" securityKeyName: "キーの名前"
@@ -541,7 +543,7 @@ relays: "リレー"
addRelay: "リレーの追加" addRelay: "リレーの追加"
inboxUrl: "inboxのURL" inboxUrl: "inboxのURL"
addedRelays: "追加済みのリレー" addedRelays: "追加済みのリレー"
serviceworkerInfo: "プッシュ通知を行うには有効する必要があります。" serviceworkerInfo: "プッシュ通知を行うには有効する必要があります。"
deletedNote: "削除された投稿" deletedNote: "削除された投稿"
invisibleNote: "非公開の投稿" invisibleNote: "非公開の投稿"
enableInfiniteScroll: "自動でもっと見る" enableInfiniteScroll: "自動でもっと見る"
@@ -643,6 +645,8 @@ clip: "クリップ"
createNew: "新規作成" createNew: "新規作成"
optional: "任意" optional: "任意"
createNewClip: "新しいクリップを作成" createNewClip: "新しいクリップを作成"
unclip: "クリップ解除"
confirmToUnclipAlreadyClippedNote: "このノートはすでにクリップ「{name}」に含まれています。ノートをこのクリップから除外しますか?"
public: "パブリック" public: "パブリック"
i18nInfo: "Misskeyは有志によって様々な言語に翻訳されています。{link}で翻訳に協力できます。" i18nInfo: "Misskeyは有志によって様々な言語に翻訳されています。{link}で翻訳に協力できます。"
manageAccessTokens: "アクセストークンの管理" manageAccessTokens: "アクセストークンの管理"
@@ -845,6 +849,53 @@ failedToFetchAccountInformation: "アカウント情報の取得に失敗しま
rateLimitExceeded: "レート制限を超えました" rateLimitExceeded: "レート制限を超えました"
cropImage: "画像のクロップ" cropImage: "画像のクロップ"
cropImageAsk: "画像をクロップしますか?" cropImageAsk: "画像をクロップしますか?"
file: "ファイル"
recentNHours: "直近{n}時間"
recentNDays: "直近{n}日"
noEmailServerWarning: "メールサーバーの設定がされていません。"
thereIsUnresolvedAbuseReportWarning: "未対応の通報があります。"
recommended: "推奨"
check: "チェック"
driveCapOverrideLabel: "このユーザーのドライブ容量上限を変更"
driveCapOverrideCaption: "0以下を指定すると解除されます。"
requireAdminForView: "閲覧するには管理者アカウントでログインしている必要があります。"
isSystemAccount: "システムにより自動で作成・管理されているアカウントです。"
typeToConfirm: "この操作を行うには {x} と入力してください"
deleteAccount: "アカウント削除"
document: "ドキュメント"
numberOfPageCache: "ページキャッシュ数"
numberOfPageCacheDescription: "多くすると利便性が向上しますが、負荷とメモリ使用量が増えます。"
logoutConfirm: "ログアウトしますか?"
lastActiveDate: "最終利用日時"
statusbar: "ステータスバー"
pleaseSelect: "選択してください"
reverse: "反転"
colored: "色付き"
refreshInterval: "更新間隔"
label: "ラベル"
type: "タイプ"
speed: "速度"
slow: "遅い"
fast: "速い"
sensitiveMediaDetection: "センシティブなメディアの検出"
localOnly: "ローカルのみ"
remoteOnly: "リモートのみ"
failedToUpload: "アップロード失敗"
cannotUploadBecauseInappropriate: "不適切な内容を含む可能性があると判定されたためアップロードできません。"
cannotUploadBecauseNoFreeSpace: "ドライブの空き容量が無いためアップロードできません。"
beta: "ベータ"
enableAutoSensitive: "自動NSFW判定"
enableAutoSensitiveDescription: "利用可能な場合は、機械学習を利用して自動でメディアにNSFWフラグを設定します。この機能をオフにしても、インスタンスによっては自動で設定されることがあります。"
activeEmailValidationDescription: "ユーザーのメールアドレスのバリデーションを、捨てアドかどうかや実際に通信可能かどうかなどを判定しより積極的に行います。オフにすると単に文字列として正しいかどうかのみチェックされます。"
_sensitiveMediaDetection:
description: "機械学習を使って自動でセンシティブなメディアを検出し、モデレーションに役立てることができます。サーバーの負荷が少し増えます。"
sensitivity: "検出感度"
sensitivityDescription: "感度を低くすると、誤検知(偽陽性)が減ります。感度を高くすると、検知漏れ(偽陰性)が減ります。"
setSensitiveFlagAutomatically: "NSFWフラグを設定する"
setSensitiveFlagAutomaticallyDescription: "この設定をオフにしても内部的に判定結果は保持されます。"
analyzeVideos: "動画の解析を有効化"
analyzeVideosDescription: "静止画に加えて動画も解析するようにします。サーバーの負荷が少し増えます。"
_emailUnavailable: _emailUnavailable:
used: "既に使用されています" used: "既に使用されています"
@@ -1230,10 +1281,12 @@ _widgets:
trends: "トレンド" trends: "トレンド"
clock: "時計" clock: "時計"
rss: "RSSリーダー" rss: "RSSリーダー"
rssTicker: "RSSティッカー"
activity: "アクティビティ" activity: "アクティビティ"
photos: "フォト" photos: "フォト"
digitalClock: "デジタル時計" digitalClock: "デジタル時計"
federation: "連合" federation: "連合"
instanceCloud: "インスタンスクラウド"
postForm: "投稿フォーム" postForm: "投稿フォーム"
slideshow: "スライドショー" slideshow: "スライドショー"
button: "ボタン" button: "ボタン"
@@ -1698,8 +1751,6 @@ _notification:
_deck: _deck:
alwaysShowMainColumn: "常にメインカラムを表示" alwaysShowMainColumn: "常にメインカラムを表示"
columnAlign: "カラムの寄せ" columnAlign: "カラムの寄せ"
columnMargin: "カラム間のマージン"
columnHeaderHeight: "カラムのヘッダー幅"
addColumn: "カラムを追加" addColumn: "カラムを追加"
swapLeft: "左に移動" swapLeft: "左に移動"
swapRight: "右に移動" swapRight: "右に移動"
@@ -1708,6 +1759,9 @@ _deck:
stackLeft: "左に重ねる" stackLeft: "左に重ねる"
popRight: "右に出す" popRight: "右に出す"
profile: "プロファイル" profile: "プロファイル"
introduction: "カラムを組み合わせて自分だけのインターフェイスを作りましょう!"
introduction2: "画面の右にある + を押して、いつでもカラムを追加できます。"
widgetsIntroduction: "カラムのメニューから、「ウィジェットの編集」を選択してウィジェットを追加してください"
_columns: _columns:
main: "メイン" main: "メイン"

View File

@@ -657,6 +657,7 @@ hashtags: "ハッシュタグ"
hide: "隠す" hide: "隠す"
searchByGoogle: "探す" searchByGoogle: "探す"
indefinitely: "無期限" indefinitely: "無期限"
file: "ファイル"
_ad: _ad:
back: "戻る" back: "戻る"
_gallery: _gallery:
@@ -1207,8 +1208,6 @@ _notification:
_deck: _deck:
alwaysShowMainColumn: "いつもメインカラムを表示" alwaysShowMainColumn: "いつもメインカラムを表示"
columnAlign: "カラムの寄せ" columnAlign: "カラムの寄せ"
columnMargin: "カラム間のマージン"
columnHeaderHeight: "カラムのヘッダー幅"
addColumn: "カラムを追加" addColumn: "カラムを追加"
swapLeft: "左に移動" swapLeft: "左に移動"
swapRight: "右に移動" swapRight: "右に移動"

View File

@@ -56,6 +56,7 @@ emailNotification: "Ilɣa imayl"
selectAccount: "Fren amiḍan" selectAccount: "Fren amiḍan"
accounts: "Imiḍan" accounts: "Imiḍan"
searchByGoogle: "Nadi" searchByGoogle: "Nadi"
file: "Ifuyla"
_email: _email:
_follow: _follow:
title: "Yeṭṭafaṛ-ik·em-id" title: "Yeṭṭafaṛ-ik·em-id"

View File

@@ -60,6 +60,7 @@ smtpUser: "ಬಳಕೆಹೆಸರು"
smtpPass: "ಗುಪ್ತಪದ" smtpPass: "ಗುಪ್ತಪದ"
user: "ಬಳಕೆದಾರ" user: "ಬಳಕೆದಾರ"
searchByGoogle: "ಹುಡುಕು" searchByGoogle: "ಹುಡುಕು"
file: "ಕಡತಗಳು"
_email: _email:
_follow: _follow:
title: "ಹಿಂಬಾಲಿಸಿದರು" title: "ಹಿಂಬಾಲಿಸಿದರು"

View File

@@ -643,6 +643,8 @@ clip: "클립"
createNew: "새로 만들기" createNew: "새로 만들기"
optional: "옵션" optional: "옵션"
createNewClip: "새 클립 만들기" createNewClip: "새 클립 만들기"
unclip: "클립 해제"
confirmToUnclipAlreadyClippedNote: "이 노트는 이미 \"{name}\" 클립에 포함되어 있습니다. 클립을 해제하시겠습니까?"
public: "공개" public: "공개"
i18nInfo: "Misskey는 자원봉사자들에 의해 다양한 언어로 번역되고 있습니다. {link}에서 번역에 참가할 수 있습니다." i18nInfo: "Misskey는 자원봉사자들에 의해 다양한 언어로 번역되고 있습니다. {link}에서 번역에 참가할 수 있습니다."
manageAccessTokens: "액세스 토큰 관리" manageAccessTokens: "액세스 토큰 관리"
@@ -845,6 +847,16 @@ failedToFetchAccountInformation: "계정 정보를 가져오지 못했습니다"
rateLimitExceeded: "요청 제한 횟수를 초과하였습니다" rateLimitExceeded: "요청 제한 횟수를 초과하였습니다"
cropImage: "이미지 자르기" cropImage: "이미지 자르기"
cropImageAsk: "이미지를 자르시겠습니까?" cropImageAsk: "이미지를 자르시겠습니까?"
file: "파일"
recentNHours: "최근 {n}시간"
recentNDays: "최근 {n}일"
noEmailServerWarning: "메일 서버가 설정되어 있지 않습니다."
thereIsUnresolvedAbuseReportWarning: "해결되지 않은 신고가 있습니다."
recommended: "추천"
check: "체크"
isSystemAccount: "시스템에 의해 자동으로 생성되어 관리되는 계정입니다."
typeToConfirm: "계속하시려면 {x} 을 입력하세요"
deleteAccount: "계정 삭제"
_emailUnavailable: _emailUnavailable:
used: "이 메일 주소는 사용중입니다" used: "이 메일 주소는 사용중입니다"
format: "형식이 올바르지 않습니다" format: "형식이 올바르지 않습니다"
@@ -1640,8 +1652,6 @@ _notification:
_deck: _deck:
alwaysShowMainColumn: "메인 칼럼 항상 표시" alwaysShowMainColumn: "메인 칼럼 항상 표시"
columnAlign: "칼럼 정렬" columnAlign: "칼럼 정렬"
columnMargin: "칼럼 간 여백"
columnHeaderHeight: "칼럼 헤더 폭"
addColumn: "칼럼 추가" addColumn: "칼럼 추가"
swapLeft: "왼쪽으로 이동" swapLeft: "왼쪽으로 이동"
swapRight: "오른쪽으로 이동" swapRight: "오른쪽으로 이동"

View File

@@ -305,6 +305,7 @@ hide: "Verbergen"
searchByGoogle: "Zoeken" searchByGoogle: "Zoeken"
cropImage: "Afbeelding bijsnijden" cropImage: "Afbeelding bijsnijden"
cropImageAsk: "Bijsnijdengevraagd" cropImageAsk: "Bijsnijdengevraagd"
file: "Bestanden"
_email: _email:
_follow: _follow:
title: "volgde jou" title: "volgde jou"

View File

@@ -760,6 +760,7 @@ pubSub: "Konta Pub/Sub"
hide: "Ukryj" hide: "Ukryj"
searchByGoogle: "Szukaj" searchByGoogle: "Szukaj"
indefinitely: "Nigdy" indefinitely: "Nigdy"
file: "Pliki"
_ffVisibility: _ffVisibility:
public: "Publikuj" public: "Publikuj"
_ad: _ad:
@@ -1406,8 +1407,6 @@ _notification:
_deck: _deck:
alwaysShowMainColumn: "Zawsze pokazuj główną kolumnę" alwaysShowMainColumn: "Zawsze pokazuj główną kolumnę"
columnAlign: "Wyrównaj kolumny" columnAlign: "Wyrównaj kolumny"
columnMargin: "Odstęp między kolumnami"
columnHeaderHeight: "Wysokość nagłówka kolumny"
addColumn: "Dodaj kolumnę" addColumn: "Dodaj kolumnę"
swapLeft: "Przesuń w lewo" swapLeft: "Przesuń w lewo"
swapRight: "Przesuń w prawo" swapRight: "Przesuń w prawo"

View File

@@ -1,9 +1,9 @@
--- ---
_lang_: "Português" _lang_: "Português"
headlineMisskey: "Rede conectada por notas" headlineMisskey: "Uma rede ligada por notas"
introMisskey: "Bem-vindo! Misskey é um serviço de microblogue descentralizado de código aberto.\nCria \"notas\" e partilha o que te ocorre com todos à tua volta. 📡\nCom \"reações\" podes também expressar logo o que sentes às notas de todos. 👍\nExploremos um novo mundo! 🚀" introMisskey: "Bem-vindo! Misskey é um serviço de microblogue descentralizado de código aberto.\nCria \"notas\" e partilha o que te ocorre com todos à tua volta. 📡\nCom \"reações\" podes também expressar logo o que sentes às notas de todos. 👍\nExploremos um novo mundo! 🚀"
monthAndDay: "{day}/{month}" monthAndDay: "{day}/{month}"
search: "Pesquisar" search: "Buscar"
notifications: "Notificações" notifications: "Notificações"
username: "Nome de usuário" username: "Nome de usuário"
password: "Senha" password: "Senha"
@@ -94,6 +94,7 @@ unfollow: "Deixar de seguir"
followRequestPending: "Pedido de seguimento pendente" followRequestPending: "Pedido de seguimento pendente"
enterEmoji: "Inserir emoji" enterEmoji: "Inserir emoji"
renote: "Repostar" renote: "Repostar"
unrenote: "Desmarcar"
renoted: "Repostado" renoted: "Repostado"
cantRenote: "Não pode repostar" cantRenote: "Não pode repostar"
cantReRenote: "Não pode repostar este repost" cantReRenote: "Não pode repostar este repost"
@@ -106,6 +107,7 @@ sensitive: "Conteúdo sensível"
add: "Adicionar" add: "Adicionar"
reaction: "Reações" reaction: "Reações"
reactionSetting: "Quais reações a mostrar no selecionador de reações" reactionSetting: "Quais reações a mostrar no selecionador de reações"
reactionSettingDescription2: "Arraste para reordenar, clique para excluir, pressione + para adicionar."
rememberNoteVisibility: "Lembrar das configurações de visibilidade de notas" rememberNoteVisibility: "Lembrar das configurações de visibilidade de notas"
attachCancel: "Remover anexo" attachCancel: "Remover anexo"
markAsSensitive: "Marcar como sensível" markAsSensitive: "Marcar como sensível"
@@ -133,35 +135,339 @@ emojiName: "Nome do Emoji"
emojiUrl: "URL do Emoji" emojiUrl: "URL do Emoji"
addEmoji: "Adicionar um Emoji" addEmoji: "Adicionar um Emoji"
settingGuide: "Guia de configuração" settingGuide: "Guia de configuração"
cacheRemoteFiles: "Memória transitória de arquivos remotos"
cacheRemoteFilesDescription: "Se você desabilitar essa configuração, os arquivos remotos não serão armazenados em memória transitória e serão vinculados diretamente. Economiza o armazenamento do servidor, mas não gera miniaturas, o que aumenta o tráfego."
flagAsBot: "Marcar conta como robô" flagAsBot: "Marcar conta como robô"
flagAsBotDescription: "Se esta conta for operada por um programa, ative este sinalizador. Quando ativado, serve como um sinalizador para evitar o encadeamento de reações para outros programadores, e o manuseio do sistema do Misskey é adequado para bots."
flagAsCat: "Marcar conta como gato" flagAsCat: "Marcar conta como gato"
flagAsCatDescription: "Ative essa opção para marcar essa conta como gato." flagAsCatDescription: "Ative essa opção para marcar essa conta como gato."
flagShowTimelineReplies: "Mostrar respostas na linha de tempo" flagShowTimelineReplies: "Mostrar respostas na linha de tempo"
flagShowTimelineRepliesDescription: "Quando ativado, a linha do tempo mostra as respostas às outras notas do utilizador, além da nota do utilizador."
autoAcceptFollowed: "Aprove automaticamente os seguidores dos seguintes utilizadores"
addAccount: "Adicionar Conta"
loginFailed: "Não consegui logar"
showOnRemote: "Exibir remotamente"
general: "Geral" general: "Geral"
wallpaper: "Papel de parede" wallpaper: "Papel de parede"
setWallpaper: "Definir papel de parede"
removeWallpaper: "Remover papel de parede"
searchWith: "Buscar: {q}" searchWith: "Buscar: {q}"
youHaveNoLists: "Não tem nenhuma lista" youHaveNoLists: "Não tem nenhuma lista"
followConfirm: "Tem certeza que quer deixar de seguir {name}?" followConfirm: "Tem certeza que quer deixar de seguir {name}?"
proxyAccount: "Conta proxy"
proxyAccountDescription: "Uma conta proxy é uma conta que atua como seguidora remota para utilizadores sob determinadas condições. Por exemplo, quando um utilizador lista um utilizador remoto, a atividade não será entregue à instância, a menos que alguém esteja seguindo o utilizador listado, portanto, a conta proxy deve seguir."
host: "hospedeiro"
selectUser: "Selecionar utilizador"
recipient: "Morada"
annotation: "Anotação"
federation: "União"
instances: "Instância" instances: "Instância"
registeredAt: "Registrado em" registeredAt: "Registrado em"
latestRequestSentAt: "Enviar a solicitação mais recente"
latestRequestReceivedAt: "Recebeu a última solicitação"
latestStatus: "Status mais recente"
storageUsage: "Uso de armazenamento"
charts: "gráfico"
perHour: "por hora" perHour: "por hora"
perDay: "por dia" perDay: "por dia"
stopActivityDelivery: "Parar a entrega de atividades"
blockThisInstance: "Bloquear esta instância"
operations: "operar"
software: "Programas"
version: "versão"
metadata: "Metadados"
withNFiles: "{n} Um arquivo"
monitor: "monitor"
jobQueue: "Fila de trabalhos"
cpuAndMemory: "CPU e memória"
network: "rede"
disk: "disco"
instanceInfo: "Informações da instância"
statistics: "Estatisticas"
clearQueue: "Limpar a fila"
clearQueueConfirmTitle: "Quer limpar a fila?"
clearQueueConfirmText: "Postagens não entregues não serão mais entregues. Normalmente você não precisa fazer isso."
clearCachedFiles: "Limpar memória transitória"
clearCachedFilesConfirm: "Tem certeza de que deseja excluir todos os arquivos remotos armazenados em memória transitória?"
blockedInstances: "Instância bloqueada"
blockedInstancesDescription: "Defina os anfitriões das instâncias que deseja bloquear, separados por quebras de linha. Uma instância bloqueada não poderá interagir com esta instância."
muteAndBlock: "Silenciar e bloquear"
mutedUsers: "Silenciar utilizador"
blockedUsers: "Utilizadores bloqueados"
noUsers: "Sem usuários" noUsers: "Sem usuários"
editProfile: "Editar Perfil"
noteDeleteConfirm: "Deseja excluir esta nota?"
pinLimitExceeded: "Não consigo mais fixar"
intro: "A instalação do Misskey está completa! Crie uma conta de administrador."
done: "Concluído"
processing: "Em Progresso"
preview: "Pré-visualizar"
default: "Padrão"
noCustomEmojis: "Não há emojis"
noJobs: "Sem trabalho"
federating: "federar"
blocked: "Bloqueado"
suspended: "Cancelar subscrição"
all: "Todos"
subscribing: "Subscrito"
publishing: "Executando"
notResponding: "Sem resposta"
instanceFollowing: "Seguir a instância"
instanceFollowers: "Seguidores da instância"
instanceUsers: "Utilizador da instância"
changePassword: "Mudar senha"
security: "Segurança"
retypedNotMatch: "As entradas não coincidem."
currentPassword: "Palavra-passe atual"
newPassword: "Nova palavra-passe"
newPasswordRetype: "Nova senha (redigite)"
attachFile: "Anexar arquivo"
more: "Mais!"
featured: "Destaques"
usernameOrUserId: "Nome de utilizador ou ID de utilizador"
noSuchUser: "Utilizador não encontrado"
lookup: "Buscando"
announcements: "Notícia"
imageUrl: "URL da imagem"
remove: "Eliminar" remove: "Eliminar"
removed: "Foi deletado"
removeAreYouSure: "Deseja excluir \"{x}\"?"
deleteAreYouSure: "Deseja excluir \"{x}\"?"
resetAreYouSure: "Redefinir agora?"
saved: "Salvo"
messaging: "Chat"
upload: "Enviando"
keepOriginalUploading: "Manter a imagem original"
keepOriginalUploadingDescription: "Mantenha a versão original ao carregar a imagem. Quando desligado, a imagem para publicação na web será gerada no navegador no momento do upload."
fromDrive: "\nDa unidade"
fromUrl: "Da URL"
uploadFromUrl: "Carregamento de URL"
uploadFromUrlDescription: "URL do arquivo que você deseja enviar"
uploadFromUrlRequested: "Upload solicitado"
uploadFromUrlMayTakeTime: "Pode levar algum tempo para que o upload seja concluído."
explore: "Explorar"
messageRead: "Lida" messageRead: "Lida"
noMoreHistory: "Sem mais história"
startMessaging: "Iniciar conversação"
nUsersRead: "{n} Pessoas leem"
agreeTo: "Eu concordo com {0}"
tos: "Termos de serviço"
start: "começar"
home: "casa"
remoteUserCaution: "As informações estão incompletas porque é um utilizador remoto."
activity: "atividade"
images: "imagem"
birthday: "aniversário"
yearsOld: "{age} anos"
registeredDate: "Data de registro"
location: "Lugar, colocar"
theme: "tema"
themeForLightMode: "Temas usados no modo de luz"
themeForDarkMode: "Temas usados no modo escuro"
light: "Claro"
dark: "Escuro"
lightThemes: "Tema claro" lightThemes: "Tema claro"
darkThemes: "Tema escuro" darkThemes: "Tema escuro"
syncDeviceDarkMode: "Sincronize com o modo escuro do dispositivo"
drive: "Unidades"
fileName: "Nome do Ficheiro"
selectFile: "Selecione os arquivos"
selectFiles: "Selecione os arquivos"
selectFolder: "Selecionar uma pasta"
selectFolders: "Selecionar uma pasta"
renameFile: "Renomear ficheiro"
folderName: "Nome da pasta"
createFolder: "Criar pasta"
renameFolder: "Renomear Pasta"
deleteFolder: "Eliminar Pasta"
addFile: "Adicionar arquivo" addFile: "Adicionar arquivo"
emptyDrive: "A unidade está vazia"
emptyFolder: "A pasta está vazia"
unableToDelete: "Não é possível eliminar"
inputNewFileName: "Por favor, digite um novo nome para a pasta!"
inputNewDescription: "Insira uma nova legenda"
inputNewFolderName: "Por favor, digite um novo nome para a pasta!"
circularReferenceFolder: "A pasta de destino é uma subpasta da pasta que você deseja mover."
hasChildFilesOrFolders: "Esta pasta não está vazia e não pode ser excluída."
copyUrl: "Copiar URL"
rename: "Renomear"
avatar: "Avatar"
banner: "Capa"
nsfw: "Conteúdo sensível" nsfw: "Conteúdo sensível"
whenServerDisconnected: "Quando a conexão com o servidor é perdida"
disconnectedFromServer: "Desconectado do servidor"
reload: "Recarregar"
doNothing: "Nenhuma ação adicional"
reloadConfirm: "Quer recarregar?"
watch: "ver"
unwatch: "Não observar"
accept: "Aceitar"
reject: "Rejeitar"
normal: "Normal"
instanceName: "Nome da instância"
instanceDescription: "Descrição da instância"
maintainerName: "Nome do administrador"
maintainerEmail: "E-mail do Administrador:"
tosUrl: "URL dos Termos de Uso"
thisYear: "Este ano"
thisMonth: "Este mês"
today: "Hoje"
dayX: " Dia {day}"
monthX: "mês de {month}" monthX: "mês de {month}"
yearX: "Ano {year}"
pages: "Páginas"
integration: "Integração"
connectService: "Conectar"
disconnectService: "Desconectar"
enableLocalTimeline: "Ativar linha do tempo local"
enableGlobalTimeline: "Ativar linha do tempo global"
disablingTimelinesInfo: "Se você desabilitar essas linhas do tempo, administradores e moderadores ainda poderão usá-las por conveniência."
registration: "Registar"
enableRegistration: "Permitir que qualquer pessoa se registre"
invite: "Convidar"
driveCapacityPerLocalAccount: "Capacidade da unidade por utilizador local"
driveCapacityPerRemoteAccount: "Capacidade da unidade por utilizador remoto"
inMb: "Em megabytes"
iconUrl: "URL da imagem do ícone (favicon, etc.)"
bannerUrl: "URL da imagem do banner"
backgroundImageUrl: "URL da imagem de fundo"
basicInfo: "Informações básicas"
pinnedUsers: "Utilizador fixado"
pinnedUsersDescription: "Descreva os utilizadores que você deseja fixar na página \"Localizar\", etc., separados por quebras de linha."
pinnedPages: "Página fixada"
pinnedPagesDescription: "Descreva o caminho da página que você deseja fixar na página superior da instância, separada por quebras de linha."
pinnedClipId: "ID do clipe a ser fixado"
pinnedNotes: "Post fixado" pinnedNotes: "Post fixado"
hcaptcha: "hCaptcha"
enableHcaptcha: "Ativar hCaptcha"
hcaptchaSiteKey: "Chave do sítio web"
hcaptchaSecretKey: "Chave secreta"
recaptcha: "reCAPTCHA"
enableRecaptcha: "Habilitar reCAPTCHA"
recaptchaSiteKey: "Chave do sítio web"
recaptchaSecretKey: "Chave secreta"
avoidMultiCaptchaConfirm: "O uso de vários captchas pode causar interferência. Deseja desativar outros captchas? Você também pode cancelar e deixar vários captchas ativados."
antennas: "Antenas"
manageAntennas: "Gestão de antena"
name: "Nome"
antennaSource: "Origem de entrada"
antennaKeywords: "Palavras-chave recebidas"
antennaExcludeKeywords: "Palavras-chave negativas"
antennaKeywordsDescription: "Se você separá-lo com um espaço, será uma especificação AND, e se você separá-lo com uma quebra de linha, será uma especificação OR."
notifyAntenna: "Notificar novas notas"
withFileAntenna: "Apenas notas com arquivos anexados"
enableServiceworker: "Ative as notificações push para o seu navegador"
antennaUsersDescription: "Especificar nomes de utilizador separados por quebras de linha"
caseSensitive: "Maiúsculas e minúsculas"
withReplies: "Incluindo resposta"
connectedTo: "Você está conectado à seguinte conta"
notesAndReplies: "Publicações e respostas"
withFiles: "Com arquivo"
silence: "Silenciado"
silenceConfirm: "Quer silenciar?"
unsilence: "Liberar silenciar"
unsilenceConfirm: "Quer liberar o silêncio?"
popularUsers: "Utilizadores populares"
recentlyUpdatedUsers: "Utilizadores postados recentemente"
recentlyRegisteredUsers: "Utilizadores registrados recentemente"
recentlyDiscoveredUsers: "Utilizadores descobertos recentemente"
exploreUsersCount: "Há um utilizador de {count}"
exploreFediverse: "Explorar Fediverse"
popularTags: "Tags populares"
userList: "Listas" userList: "Listas"
about: "Informações"
aboutMisskey: "Sobre Misskey"
administrator: "Administrador"
token: "Símbolo"
twoStepAuthentication: "Verificação em duas etapas"
moderator: "Moderador"
nUsersMentioned: "Postado por {n} pessoas"
securityKey: "Chave de segurança"
securityKeyName: "Nome chave"
registerSecurityKey: "Registre a chave de segurança"
lastUsed: "Último uso"
unregister: "Cancelar registro"
passwordLessLogin: "Entrar sem senha"
resetPassword: "Redefinir senha"
newPasswordIs: "A nova senha é \"{password}\""
reduceUiAnimation: "Reduzir a animação da interface do utilizador"
share: "Compartilhar"
notFound: "Não encontrado"
notFoundDescription: "Não havia página correspondente ao URL especificado."
uploadFolder: "Destino de upload padrão"
cacheClear: "Excluir memória transitória"
markAsReadAllNotifications: "Marcar todas as notificações como lidas"
markAsReadAllUnreadNotes: "Marcar todas as postagens como lidas"
markAsReadAllTalkMessages: "Marcar todas as conversas como lidas"
help: "Ajuda"
inputMessageHere: "Escrever mensagem aqui"
close: "Fechar"
group: "Grupos"
groups: "Grupos"
createGroup: "Criar grupo"
ownedGroups: "Grupo próprio"
invites: "Convidar"
invitations: "Convidar"
tags: "Etiquetas"
docSource: "Fonte deste documento"
createAccount: "Criar conta"
existingAccount: "Contas existentes"
regenerate: "Gerar novamente"
fontSize: "Tamanho do texto"
noFollowRequests: "Não há aplicação de acompanhamento"
openImageInNewTab: "Abrir a imagem numa nova aba"
dashboard: "Painel de controle"
local: "Local"
remote: "Remoto"
total: "Total"
weekOverWeekChanges: "Em comparação com a semana anterior"
dayOverDayChanges: "Dia anterior"
appearance: "Aparência"
clientSettings: "Configurações do cliente"
accountSettings: "Configurações da conta"
promotion: "Promoção"
promote: "Promover"
numberOfDays: "Dias"
hideThisNote: "Ocultar esta nota"
showFeaturedNotesInTimeline: "Mostrar notas recomendadas na linha do tempo"
objectStorage: "Armazenamento de objetos"
useObjectStorage: "Usar armazenamento de objetos"
objectStorageBaseUrl: "URL base"
objectStorageBaseUrlDesc: "O URL usado para referência. Se você estiver usando um CDN ou Proxy, seu URL, S3:'https: // <bucket> .s3.amazonaws.com', GCS, etc .:'https://storage.googleapis.com/ <bucket>' ."
objectStorageBucket: "Bucket"
objectStorageBucketDesc: "Especifique o nome do bucket do serviço a ser usado."
objectStoragePrefix: "Prefixo"
objectStoragePrefixDesc: "Ele é armazenado neste diretório de prefixo."
objectStorageEndpoint: "Ponto final"
objectStorageEndpointDesc: "Especifique vazio para S3, caso contrário, especifique o ponto final para cada serviço. Especifique como'<host>'ou'<host>: <port>'."
objectStorageRegion: "Região"
objectStorageRegionDesc: "Especifique uma região como 'xx-east-1'. Caso seu serviço não tenha o conceito de região, ele deve estar vazio ou 'us-east-1'."
objectStorageUseSSL: "Usar SSL"
objectStorageUseSSLDesc: "Desative-o se não quiser usar https para conexões de API"
objectStorageUseProxy: "Usar proxy"
objectStorageUseProxyDesc: "Se você não usa proxy para conexão de API, desative-o."
objectStorageSetPublicRead: "Definir 'public-read' ao fazer o upload"
serverLogs: "Registro do servidor"
deleteAll: "Apagar Tudo"
showFixedPostForm: "Exibir o formulário de postagem na parte superior da linha do tempo"
newNoteRecived: "Nova nota recebida"
sounds: "Sons"
listen: "Ouvir"
none: "Nenhum" none: "Nenhum"
showInPage: "Ver na página"
popout: "Sair"
volume: "Volume"
masterVolume: "volume principal"
details: "Detalhes"
output: "Resultado" output: "Resultado"
smtpHost: "hospedeiro"
smtpUser: "Nome de usuário" smtpUser: "Nome de usuário"
smtpPass: "Senha" smtpPass: "Senha"
clearCache: "Limpar memória transitória"
info: "Informações"
user: "Usuários" user: "Usuários"
searchByGoogle: "Pesquisar" searchByGoogle: "Buscar"
file: "Ficheiros"
_email: _email:
_follow: _follow:
title: "Você tem um novo seguidor" title: "Você tem um novo seguidor"
@@ -169,7 +475,7 @@ _mfm:
mention: "Menção" mention: "Menção"
quote: "Citar" quote: "Citar"
emoji: "Emoji personalizado" emoji: "Emoji personalizado"
search: "Pesquisar" search: "Buscar"
_theme: _theme:
keys: keys:
mention: "Menção" mention: "Menção"
@@ -177,22 +483,33 @@ _theme:
_sfx: _sfx:
note: "Posts" note: "Posts"
notification: "Notificações" notification: "Notificações"
chat: "Chat"
_widgets: _widgets:
notifications: "Notificações" notifications: "Notificações"
timeline: "Timeline" timeline: "Timeline"
activity: "atividade"
federation: "União"
jobQueue: "Fila de trabalhos"
_cw: _cw:
show: "Carregar mais" show: "Carregar mais"
_visibility: _visibility:
home: "casa"
followers: "Seguidores" followers: "Seguidores"
_profile: _profile:
name: "Nome"
username: "Nome de usuário" username: "Nome de usuário"
_exportOrImport: _exportOrImport:
followingList: "Seguindo" followingList: "Seguindo"
muteList: "Silenciar" muteList: "Silenciar"
blockingList: "Bloquear" blockingList: "Bloquear"
userLists: "Listas" userLists: "Listas"
_charts:
federation: "União"
_timelines:
home: "casa"
_pages: _pages:
blocks: blocks:
image: "imagem"
_button: _button:
_action: _action:
_pushEvent: _pushEvent:
@@ -397,8 +714,6 @@ _notification:
_deck: _deck:
alwaysShowMainColumn: "Sempre mostrar a coluna principal" alwaysShowMainColumn: "Sempre mostrar a coluna principal"
columnAlign: "Alinhar colunas" columnAlign: "Alinhar colunas"
columnMargin: "Margem entre colunas"
columnHeaderHeight: "Altura do cabeçalho de coluna"
addColumn: "Adicionar coluna" addColumn: "Adicionar coluna"
swapLeft: "Trocar de posição com a coluna à esquerda" swapLeft: "Trocar de posição com a coluna à esquerda"
swapRight: "Trocar de posição com a coluna à direita" swapRight: "Trocar de posição com a coluna à direita"

View File

@@ -644,6 +644,7 @@ administration: "Gestionare"
middle: "Mediu" middle: "Mediu"
sent: "Trimite" sent: "Trimite"
searchByGoogle: "Caută" searchByGoogle: "Caută"
file: "Fișiere"
_email: _email:
_follow: _follow:
title: "te-a urmărit" title: "te-a urmărit"

View File

@@ -381,6 +381,7 @@ administrator: "Администратор"
token: "Токен" token: "Токен"
twoStepAuthentication: "Двухфакторная аутентификация" twoStepAuthentication: "Двухфакторная аутентификация"
moderator: "Модератор" moderator: "Модератор"
moderation: "Модерация"
nUsersMentioned: "Упомянуло пользователей: {n}" nUsersMentioned: "Упомянуло пользователей: {n}"
securityKey: "Ключ безопасности" securityKey: "Ключ безопасности"
securityKeyName: "Имя ключа" securityKeyName: "Имя ключа"
@@ -636,7 +637,7 @@ waitingFor: "Ждём, когда {x} ответит"
random: "Случайные" random: "Случайные"
system: "Система" system: "Система"
switchUi: "Выбор вида" switchUi: "Выбор вида"
desktop: "Стол" desktop: "Компьютер"
clip: "Подборка" clip: "Подборка"
createNew: "Новый документ" createNew: "Новый документ"
optional: "Необязательно" optional: "Необязательно"
@@ -832,6 +833,7 @@ searchByGoogle: "Поиск"
instanceDefaultLightTheme: "Светлая тема по умолчанию" instanceDefaultLightTheme: "Светлая тема по умолчанию"
instanceDefaultDarkTheme: "Темная тема по умолчанию" instanceDefaultDarkTheme: "Темная тема по умолчанию"
indefinitely: "вечно" indefinitely: "вечно"
file: "Файлы"
_emailUnavailable: _emailUnavailable:
used: "Уже используется" used: "Уже используется"
format: "Неверный формат" format: "Неверный формат"
@@ -1619,8 +1621,6 @@ _notification:
_deck: _deck:
alwaysShowMainColumn: "Всегда показывать главную колонку" alwaysShowMainColumn: "Всегда показывать главную колонку"
columnAlign: "Выравнивание колонок" columnAlign: "Выравнивание колонок"
columnMargin: "Расстояние между колонками"
columnHeaderHeight: "Высота заголовка колонки"
addColumn: "Добавить колонку" addColumn: "Добавить колонку"
swapLeft: "Переставить левее" swapLeft: "Переставить левее"
swapRight: "Переставить правее" swapRight: "Переставить правее"

View File

@@ -203,6 +203,7 @@ done: "Hotovo"
processing: "Pracujem..." processing: "Pracujem..."
preview: "Náhľad" preview: "Náhľad"
default: "Predvolené" default: "Predvolené"
defaultValueIs: "Predvolené: {value}"
noCustomEmojis: "Žiadne emoji" noCustomEmojis: "Žiadne emoji"
noJobs: "Žiadne úlohy" noJobs: "Žiadne úlohy"
federating: "Federácia" federating: "Federácia"
@@ -381,6 +382,7 @@ administrator: "Administrátor"
token: "Token" token: "Token"
twoStepAuthentication: "Dvojfaktorová autentifikácia" twoStepAuthentication: "Dvojfaktorová autentifikácia"
moderator: "Moderátor" moderator: "Moderátor"
moderation: "Moderovanie"
nUsersMentioned: "{n} používateľov spomenulo" nUsersMentioned: "{n} používateľov spomenulo"
securityKey: "Bezpečnostný kľúč" securityKey: "Bezpečnostný kľúč"
securityKeyName: "Názov kľúča" securityKeyName: "Názov kľúča"
@@ -642,6 +644,8 @@ clip: "Klip"
createNew: "Vytvoriť nový" createNew: "Vytvoriť nový"
optional: "Voliteľné" optional: "Voliteľné"
createNewClip: "Vytvoriť nový klip" createNewClip: "Vytvoriť nový klip"
unclip: "Odopnúť"
confirmToUnclipAlreadyClippedNote: "Táto poznámka je už pripnutá ako \"{name}\". Naozaj ju chcete odopnúť?"
public: "Verejné" public: "Verejné"
i18nInfo: "Misskey je prekladaný do rôznych jazykov dobrovoľníkmi. Pomôcť môžete na {link}." i18nInfo: "Misskey je prekladaný do rôznych jazykov dobrovoľníkmi. Pomôcť môžete na {link}."
manageAccessTokens: "Spravovať prístupové tokeny" manageAccessTokens: "Spravovať prístupové tokeny"
@@ -842,6 +846,25 @@ oneWeek: "1 týždeň"
reflectMayTakeTime: "Zmeny môžu chvíľu trvať kým sa prejavia." reflectMayTakeTime: "Zmeny môžu chvíľu trvať kým sa prejavia."
failedToFetchAccountInformation: "Nepodarilo sa načítať informácie o účte." failedToFetchAccountInformation: "Nepodarilo sa načítať informácie o účte."
rateLimitExceeded: "Prekročený limit rýchlosti" rateLimitExceeded: "Prekročený limit rýchlosti"
cropImage: "Orezanie obrázku"
cropImageAsk: "Chcete orezať obrázok?"
file: "Súbor/y"
recentNHours: "Posledných {n} hodín"
recentNDays: "Posledných {n} dní"
noEmailServerWarning: "Nie je nastavený emailový server."
thereIsUnresolvedAbuseReportWarning: "Existuje nevyriešené nahlásenie zneužitia."
recommended: "Odporúčané"
driveCapOverrideLabel: "Zmena limitu úložiska pre tohoto používateľa"
driveCapOverrideCaption: "Ak je zadaná hodnota menšia alebo rovná 0, zruší sa."
isSystemAccount: "Tieto účty automaticky vytvoril a spravuje systém."
typeToConfirm: "Ak chcete vykonať túto operáciu, napíšte {x}"
deleteAccount: "Vymazať účet"
document: "Dokument"
numberOfPageCache: "Počet cachí pre stránky"
numberOfPageCacheDescription: "Zvýši rýchlosť ale tiež nároky na pamäť."
logoutConfirm: "Naozaj sa chcete odhlásiť?"
statusbar: "Stavový riadok"
pleaseSelect: "Prosím vyberte"
_emailUnavailable: _emailUnavailable:
used: "Táto emailová adresa sa už používa" used: "Táto emailová adresa sa už používa"
format: "Formát emailovej adresy je nesprávny" format: "Formát emailovej adresy je nesprávny"
@@ -1196,10 +1219,12 @@ _widgets:
trends: "Trendy" trends: "Trendy"
clock: "Hodiny" clock: "Hodiny"
rss: "RSS čítačka" rss: "RSS čítačka"
rssTicker: "RSS Ticker"
activity: "Aktivita" activity: "Aktivita"
photos: "Fotky" photos: "Fotky"
digitalClock: "Digitálne hodiny" digitalClock: "Digitálne hodiny"
federation: "Federácia" federation: "Federácia"
instanceCloud: "Cloud serverov"
postForm: "Napísať poznámku" postForm: "Napísať poznámku"
slideshow: "Prezentácia" slideshow: "Prezentácia"
button: "Tlačidlo" button: "Tlačidlo"
@@ -1615,6 +1640,7 @@ _notification:
yourFollowRequestAccepted: "Vaša žiadosť o sledovanie bola prijatá" yourFollowRequestAccepted: "Vaša žiadosť o sledovanie bola prijatá"
youWereInvitedToGroup: "Pozvať do skupiny" youWereInvitedToGroup: "Pozvať do skupiny"
pollEnded: "Výsledky hlasovania sú k dispozícii." pollEnded: "Výsledky hlasovania sú k dispozícii."
emptyPushNotificationMessage: "Push notifikácie aktualizované"
_types: _types:
all: "Všetky" all: "Všetky"
follow: "Sledujete" follow: "Sledujete"
@@ -1636,8 +1662,6 @@ _notification:
_deck: _deck:
alwaysShowMainColumn: "Vždy zobraziť v hlavnom stĺpci" alwaysShowMainColumn: "Vždy zobraziť v hlavnom stĺpci"
columnAlign: "Zarovnať stĺpce" columnAlign: "Zarovnať stĺpce"
columnMargin: "Rozostup medzi stĺpcami"
columnHeaderHeight: "Výška hlavičky stĺpca"
addColumn: "Pridať stĺpec" addColumn: "Pridať stĺpec"
swapLeft: "Vymeniť vľavo" swapLeft: "Vymeniť vľavo"
swapRight: "Vymeniť vpravo" swapRight: "Vymeniť vpravo"
@@ -1646,6 +1670,9 @@ _deck:
stackLeft: "Priložiť do ľavého stĺpca" stackLeft: "Priložiť do ľavého stĺpca"
popRight: "Vybrať napravo" popRight: "Vybrať napravo"
profile: "Profil" profile: "Profil"
introduction: "Kombinujte stĺpce a vytvorte si svoje vlastné rozhranie!"
introduction2: "Stlačením tlačidla + v pravej časti obrazovky môžete kedykoľvek pridať stĺpce."
widgetsIntroduction: "V ponuke stĺpca vyberte možnosť \"Upraviť widget\" a pridajte widget"
_columns: _columns:
main: "Hlavný" main: "Hlavný"
widgets: "Widgety" widgets: "Widgety"

View File

@@ -247,6 +247,7 @@ smtpPass: "Lösenord"
clearCache: "Rensa cache" clearCache: "Rensa cache"
user: "Användare" user: "Användare"
searchByGoogle: "Sök" searchByGoogle: "Sök"
file: "Filer"
_email: _email:
_follow: _follow:
title: "följde dig" title: "följde dig"

View File

@@ -1 +1,883 @@
--- ---
_lang_: "ภาษาไทย"
headlineMisskey: "เชื่อมต่อเครือข่ายโดยโน้ต"
introMisskey: "ยินดีต้อนรับจ้าาา! Misskey เป็นบริการไมโครบล็อกโอเพ่นซอร์ส แบบการกระจายอำนาจ\nสร้าง \"โน้ต\" เพื่อแบ่งปันความคิดของคุณกับทุกคนรอบตัวคุณกันเถอะ 📡\nด้วยการ \"รีแอคชั่นผู้คน\" คุณยังสามารถแสดงความรู้สึกของคุณเกี่ยวกับบันทึกของทุกคนได้อย่างรวดเร็ว 👍\n\nแล้วมาท่องสำรวจโลกใบใหม่กันเถอะ! 🚀"
monthAndDay: "{เดือน}/{วัน}"
search: "ค้นหา"
notifications: "การเเจ้งเตือน"
username: "ชื่อผู้ใช้"
password: "รหัสผ่าน"
forgotPassword: "ลืมรหัสผ่าน?"
fetchingAsApObject: "กำลังดึงข้อมูล จาก เฟดิเวิร์ส..."
ok: "ตกลง"
gotIt: "เข้าใจแล้ว !"
cancel: "ยกเลิก"
enterUsername: "ใส่ชื่อผู้ใช้"
renotedBy: "รีโน้ตโดย {ผู้ใช้}"
noNotes: "ไม่มีโน้ต"
noNotifications: "ไม่มีการแจ้งเตือน"
instance: "ตัวอย่าง"
settings: "การตั้งค่า"
basicSettings: "การตั้งค่าพื้นฐาน"
otherSettings: "การตั้งค่าอื่นๆ"
openInWindow: "เปิดในหน้าต่าง"
profile: "โปรไฟล์"
timeline: "ไทม์ไลน์"
noAccountDescription: "ผู้ใช้รายนี้ยังไม่ได้เขียนลงประวัติของพวกเขา"
login: "เข้าสู่ระบบ"
loggingIn: "กำลังเข้าสู่ระบบ"
logout: "ออกจากระบบ"
signup: "สร้างบัญชีผู้ใช้"
uploading: "กำลังอัพโหลด..."
save: "บันทึก"
users: "ผู้ใช้งาน"
addUser: "เพิ่มผู้ใช้"
favorite: "รายการโปรด"
favorites: "รายการโปรด"
unfavorite: "ลบออกจากรายการโปรด"
favorited: "เพิ่มแล้วในรายการโปรด"
alreadyFavorited: "เพิ่มในรายการโปรดอยู่แล้ว"
cantFavorite: "ไม่สามารถเพิ่มในรายการโปรดได้"
pin: "ปักหมุดไปยังโปรไฟล์"
unpin: "เลิกปักหมุดจากโปรไฟล์"
copyContent: "คัดลอกเนื้อหา"
copyLink: "คัดลอกลิงก์"
delete: "ลบ"
deleteAndEdit: "ลบและแก้ไข"
deleteAndEditConfirm: "นายแน่ใจแล้วเหรอ? ว่าต้องการลบโน้ตนี้และแก้ไข คุณอาจจะสูญเสียการโต้ตอบ, โน้ต, และการตอบกลับทั้งหมดได้นะ"
addToList: "เพิ่มในลิสต์"
sendMessage: "ส่งข้อความ"
copyUsername: "คัดลอกชื่อผู้ใช้"
searchUser: "ค้นหาผู้ใช้งาน"
reply: "ตอบกลับ"
loadMore: "โหลดเพิ่มเติม"
showMore: "แสดงเพิ่มเติม"
youGotNewFollower: "ได้ติดตามคุณ"
receiveFollowRequest: "คำขอผู้ติดตามที่ได้รับ"
followRequestAccepted: "ผู้ติดตามได้ตอบรับคำขอร้องของคุณแล้ว"
mention: "กล่าวถึง"
mentions: "พูดถึง"
directNotes: "ไดเร็คโน้ต"
importAndExport: "นำเข้า / ส่งออก"
import: "การนำเข้า"
export: "การนำออก"
files: "ไฟล์"
download: "ดาวน์โหลด"
driveFileDeleteConfirm: "นายแน่ใจแล้วหรอ? ว่าต้องการลบไฟล์ \"{name}\" โน้ตย่อที่แนบมากับไฟล์นี้ก็จะถูกลบด้วยนะ"
unfollowConfirm: "นายแน่ใจแล้วหรอว่าต้องการเลิกติดตาม {name}?"
exportRequested: "เมื่อคุณได้ร้องขอการส่งออก อาจจะต้องใช้เวลาสักครู่ และจะถูกเพิ่มในไดรฟ์ของคุณเมื่อเสร็จสิ้นแล้ว"
importRequested: "เมื่อคุณได้ร้องขอการนำเข้า อาจจะต้องใช้เวลาสักครู่นะ"
lists: "รายการ"
noLists: "คุณไม่มีลิสต์ใดๆนะ"
note: "ตัวโน้ต"
notes: "หมายเหตุ"
following: "กำลังติดตาม"
followers: "ผู้ติดตาม"
followsYou: "ติดตามคุณ"
createList: "สร้างลิสต์"
manageLists: "จัดการลิสต์"
error: "ผิดพลาด!"
somethingHappened: "อุ๊ย ! มีอะไรบางอย่างผิดพลาด"
retry: "ลองใหม่อีกครั้ง"
pageLoadError: "เกิดข้อผิดพลาดในการโหลดหน้านี้"
pageLoadErrorDescription: "โดยปกติแล้วมักจะเกิดจากข้อผิดพลาดของเครือข่ายหรือแคชของเบราว์เซอร์ ลองล้างแคชแล้วลองใหม่อีกครั้งหลังจากรอสักครู่ "
serverIsDead: "เซิร์ฟเวอร์นี้ไม่มีการตอบสนอง ได้โปรดกรุณารอสักครู่แล้วลองใหม่อีกครั้งนะ"
youShouldUpgradeClient: "หากต้องการดูหน้านี้ได้โปรดกรุณา รีเซ็ตเพื่ออัปเดตไคลเอ็นต์ของคุณนะ"
enterListName: "ใส่ชื่อสำหรับรายการลิสต์"
privacy: "ความเป็นส่วนตัว"
makeFollowManuallyApprove: "ติดตามคำขอที่ต้องได้รับการอนุมัติ"
defaultNoteVisibility: "การมองเห็นที่เป็นค่าเริ่มต้น"
follow: "กำลังติดตาม"
followRequest: "ส่งคำขอติดตาม"
followRequests: "ติดตามการร้องขอ"
unfollow: "เลิกติดตาม"
followRequestPending: "กำลังรอดำเนินการร้องขอติดตาม"
enterEmoji: "ใส่อีโมจิ"
renote: "รีโน้ต"
unrenote: "เลิกรีโน้ต"
renoted: "รีโน้ตเอาไว้"
cantRenote: "โพสต์นี้ไม่สามารถรีโน้ตไว้ใหม่ได้นะ"
cantReRenote: "ไม่สามารถรีโน้ตเอาไว้ใหม่ได้นะ"
quote: "อ้างคำพูด"
pinnedNote: "โน้ตที่ปักหมุดเอาไว้"
pinned: "ปักหมุดไปยังโปรไฟล์"
you: "ตัวเอง"
clickToShow: "คลิกเพื่อแสดง"
sensitive: "เนื้อหาที่ละเอียดอ่อน NSFW"
add: "เพิ่ม"
reaction: "รีแอคชั่น"
reactionSetting: "รีแอคชั่นไปยังแสดงผลในตัวเลือกการรีแอคชั่น"
reactionSettingDescription2: "กดลากเพื่อจัดลำดับใหม่ กดคลิกเพื่อลบ กด \"+\" เพื่อเพิ่ม"
rememberNoteVisibility: "จดจำการตั้งค่าการมองเห็นตัวโน้ต"
attachCancel: "ลบไฟล์ออกที่แนบมา"
markAsSensitive: "ทำเครื่องหมายว่าละเอียดอ่อน"
unmarkAsSensitive: "ยกเลิกทำเครื่องหมายเป็น NSFW"
enterFileName: "พิมพ์ชื่อไฟล์"
mute: "ปิดเสียง"
unmute: "ไม่ปิดเสียง"
block: "บล็อค"
unblock: "เลิกปิดกั้น"
suspend: "ถูกระงับ"
unsuspend: "ยกเลิกระงับ"
blockConfirm: "คุณแน่ใจแล้วเหรอ? ว่าต้องการบล็อกบัญชีนี้"
unblockConfirm: "คุณแน่ใจแล้วเหรอ? ว่าต้องการปลดบล็อคบัญชีนี้"
suspendConfirm: "นายแน่ใจแล้วเหรอว่าต้องการระงับบัญชีนี้อ่ะ?"
unsuspendConfirm: "นายแน่ใจแล้วหรอ? ว่าต้องการยกเลิกการระงับบัญชีนี้"
selectList: "เลือกรายการ (Automatic Translation)"
selectAntenna: "เลือกเสาอากาศ"
selectWidget: "เลือกวิดเจ็ต"
editWidgets: "แก้ไขวิดเจ็ต"
editWidgetsExit: "เรียบร้อย"
customEmojis: "กำหนดอีโมจิเอง"
emoji: "อีโมจิ"
emojis: "อีโมจิ"
emojiName: "ชื่ออิโมจิ"
emojiUrl: "อิโมจิ URL"
addEmoji: "แทรกอีโมจิ"
settingGuide: "การตั้งค่าที่แนะนำ"
cacheRemoteFiles: "แคชไฟล์ระยะไกล"
cacheRemoteFilesDescription: "เมื่อปิดใช้งานการตั้งค่านี้ ไฟล์ระยะไกลนั้นจะถูกโหลดโดยตรงจากอินสแตนซ์ระยะไกล แต่กรณีการปิดใช้งานนี้จะช่วยลดปริมาณการใช้พื้นที่จัดเก็บข้อมูล แต่เพิ่มปริมาณการใช้งาน เพราะเนื่องจากจะไม่มีการสร้างภาพขนาดย่อ"
flagAsBot: "ทำเครื่องหมายบอกว่าบัญชีนี้เป็นบอท"
flagAsBotDescription: "การเปิดใช้งานตัวเลือกนี้หากบัญชีนี้ถูกควบคุมโดยนักเขียนโปรแกรม หรือ ถ้าหากเปิดใช้งาน มันจะทำหน้าที่เป็นแฟล็กสำหรับนักพัฒนารายอื่นๆ และเพื่อป้องกันการโต้ตอบแบบไม่มีที่สิ้นสุดกับบอทตัวอื่นๆ และยังสามารถปรับเปลี่ยนระบบภายในของ Misskey เพื่อปฏิบัติต่อบัญชีนี้เป็นบอท"
flagAsCat: "ทำเครื่องหมายบอกว่าบัญชีนี้เป็นแมว"
flagAsCatDescription: "การเปิดใช้งานตัวเลือกนี้เพื่อทำเครื่องหมายบอกว่าบัญชีนี้เป็นแมว"
flagShowTimelineReplies: "แสดงตอบกลับ ในไทม์ไลน์"
flagShowTimelineRepliesDescription: "แสดงการตอบกลับของผู้ใช้งานไปยังโน้ตของผู้ใช้งานรายอื่นๆในไทม์ไลน์หากได้เปิดเอาไว้"
autoAcceptFollowed: "อนุมัติคำขอติดตามโดยอัตโนมัติทันที จากผู้ใช้งานที่คุณกำลังติดตาม"
addAccount: "เพิ่มบัญชี"
loginFailed: "การเข้าสู่ระบบไม่สำเร็จ"
showOnRemote: "ดูบนอินสแตนซ์ระยะไกล"
general: "ทั่วไป"
wallpaper: "วอลล์เปเปอร์"
setWallpaper: "ตั้งวอลเปเปอร์"
removeWallpaper: "นำวอลเปเปอร์ออก"
searchWith: "ค้นหา: {q}"
youHaveNoLists: "รายการนี้ว่างเปล่า"
followConfirm: "คุณแน่ใจแล้วหรอว่าต้องการที่จะติดตาม {name}?"
proxyAccount: "บัญชี พร็อกซี่"
proxyAccountDescription: "บัญชีพร็อกซี่ คือ บัญชีที่จะทำหน้าที่เป็นผู้ติดตามระยะไกลสำหรับผู้ใช้งานที่อยู่ภายใต้ด้วยเงื่อนไขบางอย่าง ยกตัวอย่าง เช่น เมื่อมีผู้ใช้งานนั้นได้เพิ่มผู้ใช้งานจากระยะไกลลงในรายการ แต่กิจกรรมของผู้ใช้ในระยะไกลนั้นจะไม่ถูกส่งไปยังอินสแตนซ์หากไม่มีผู้ใช้งานในพื้นที่ติดตามผู้ใช้รายนั้น ดังนั้นบัญชีพร็อกซีนี้จะติดตามแทน"
host: "โฮสต์"
selectUser: "เลือกผู้ใช้งาน"
recipient: "ผู้รับ"
annotation: "ความคิดเห็น"
federation: "สหพันธ์"
instances: "ตัวอย่าง"
registeredAt: "จดทะเบียนที่"
latestRequestSentAt: "ส่งคำขอล่าสุดไปแล้ว"
latestRequestReceivedAt: "ได้รับคำขอล่าสุดไปแล้ว"
latestStatus: "สถานะล่าสุด"
storageUsage: "พื้นที่จัดเก็บข้อมูลที่ใช้ไป"
charts: "โดดเด่น"
perHour: "ทุกชั่วโมง"
perDay: "ต่อวัน"
stopActivityDelivery: "หยุดส่งกิจกรรม"
blockThisInstance: "บล็อกอินสแตนซ์นี้"
operations: "ดำเนินการ"
software: "ซอฟต์แวร์"
version: "เวอร์ชั่น"
metadata: "ข้อมูลเมตา"
withNFiles: "{n} ไฟล์(s)"
monitor: "มอนิเตอร์"
jobQueue: "คิวงาน"
cpuAndMemory: "ซีพียู และ หน่วยความจำ"
network: "เน็ตเวิร์ก"
disk: "ดิสก์"
instanceInfo: "ข้อมูล อินสแตนซ์"
statistics: "สถิติการใช้งาน"
clearQueue: "ล้างคิว"
clearQueueConfirmTitle: "คุณแน่ใจแล้วหรอว่าต้องการที่จะล้างคิว?"
clearQueueConfirmText: "บันทึกย่อที่ยังไม่ได้ส่งที่เหลืออยู่ในคิวนั้นมักจะ ไม่ถูกรวมเข้าด้วยกัน โดยปกติแล้วไม่จำเป็นต้องดำเนินการนี้"
clearCachedFiles: "ล้างแคช"
clearCachedFilesConfirm: "นายแน่ใจแล้วหรอว่าต้องการที่จะลบไฟล์ระยะไกลที่แคชไว้ทั้งหมด?"
blockedInstances: "อินสแตนซ์ที่ ถูกบล็อก"
blockedInstancesDescription: "ระบุชื่อโฮสต์ของอินสแตนซ์ที่คุณต้องการบล็อก อินสแตนซ์ที่อยู่ในรายการนั้นจะไม่สามารถพูดคุยกับอินสแตนซ์นี้ได้อีกต่อไป"
muteAndBlock: "ปิดเสียงและบล็อก"
mutedUsers: "ผู้ใช้ที่ถูกปิดเสียง"
blockedUsers: "ผู้ใช้ที่ถูกบล็อก"
noUsers: "ไม่พบผู้ใช้งาน"
editProfile: "แก้ไขโปรไฟล์"
noteDeleteConfirm: "นายแน่ใจแล้วหรอว่าต้องการลบโน้ตนี้นะ?"
pinLimitExceeded: "คุณไม่สามารถปักหมุดโน้ตเพิ่มเติมใดๆได้อีก"
intro: "การติดตั้ง Misskey เสร็จสิ้นแล้วนะ! โปรดสร้างผู้ใช้งานที่เป็นผู้ดูแลระบบ"
done: "เสร็จสิ้น"
processing: "กำลังประมวลผล..."
preview: "แสดงตัวอย่าง"
default: "ค่าตั้งต้น"
defaultValueIs: "ค่าเริ่มต้น: {value}"
noCustomEmojis: "ไม่มีอีโมจิ"
noJobs: "ไม่มีชิ้นงาน"
federating: "สหพันธ์"
blocked: "ถูกบล็อก"
suspended: "ถูกระงับ"
all: "ทั้งหมด"
subscribing: "สมัครแล้ว"
publishing: "กำลังเผยแพร่"
notResponding: "ไม่มีการตอบสนอง"
instanceFollowing: "กำลังติดตาม บน อินสแตนซ์"
instanceFollowers: "ผู้ติดตามของอินสแตนซ์"
instanceUsers: "ผู้ใช้งานของอินสแตนซ์นี้"
changePassword: "เปลี่ยนรหัสผ่าน"
security: "ความปลอดภัย"
retypedNotMatch: "อินพุตไม่ตรงกันนะ"
currentPassword: "รหัสผ่านปัจจุบัน"
newPassword: "รหัสผ่านใหม่"
newPasswordRetype: "ใส่รหัสผ่านใหม่อีกครั้ง"
attachFile: "แนบไฟล์"
more: "เพิ่มเติม!"
featured: "เป็นจุดเด่น"
usernameOrUserId: "ชื่อผู้ใช้หรือรหัสผู้ใช้งาน"
noSuchUser: "ไม่มีผู้ใช้นี้อยู่ในระบบ"
lookup: "ค้นหา"
announcements: "ประกาศ"
imageUrl: "url รูปภาพ"
remove: "ลบ"
removed: "ถูกลบไปแล้ว"
removeAreYouSure: "นายแน่ใจจริงหรอว่าต้องการที่จะลบออก \"{x}\""
deleteAreYouSure: "นายแน่ใจจริงหรอว่าต้องการที่จะลบออก \"{x}\""
resetAreYouSure: "รีเซ็ตเลยไหม"
saved: "บันทึกแล้ว"
messaging: "แชท"
upload: "อัพโหลด"
keepOriginalUploading: "เก็บภาพต้นฉบับ"
keepOriginalUploadingDescription: "บันทึกรูปภาพที่อัพโหลดต้นฉบับตามที่เป็นอยู่ ถ้าหากปิดอยู่ ระบบจะสร้างเวอร์ชั่นที่จะแสดงบนเว็บเมื่ออัพโหลดนะ"
fromDrive: "จากไดรฟ์"
fromUrl: "จาก URL"
uploadFromUrl: "อัพโหลดจาก URL"
uploadFromUrlDescription: "URL ของไฟล์ที่คุณต้องการอัปโหลด"
uploadFromUrlRequested: "อัพโหลดที่ร้องขอ"
uploadFromUrlMayTakeTime: "มันอาจจะต้องใช้เวลาสักครู่จนกว่าการอัพโหลดจะเสร็จสมบูรณ์นะ"
explore: "สำรวจ"
messageRead: "อ่านแล้ว"
noMoreHistory: "ในนั้นไม่มีประวัติอีกต่อไปแล้วนะ"
startMessaging: "เริ่มการสนทนา"
nUsersRead: "อ่านโดย {n}"
agreeTo: "ฉันยอมรับที่จะ {0}"
tos: "ข้อกำหนดและเงื่อนไข"
start: "เริ่มต้น​ใช้งาน​"
home: "หน้าแรก"
remoteUserCaution: "เนื่องจากผู้ใช้งานรายนี้นั้น มาจากอินสแตนซ์ระยะไกล ข้อมูลที่แสดงดังกล่าวนั้นอาจจะไม่สมบูรณ์ก็ได้นะ"
activity: "กิจกรรม"
images: "รูปภาพ"
birthday: "วันเกิด"
yearsOld: "{อายุ} ปี"
registeredDate: "วันที่สมัครสมาชิก"
location: "ตำแหน่งที่ตั้ง"
theme: "ธีม"
themeForLightMode: "ธีมที่จะใช้ในโหมดแสง"
themeForDarkMode: "ธีมที่จะใช้ในโหมดมืด"
light: "สว่าง"
dark: "มืด"
lightThemes: "ธีมสีสว่าง"
darkThemes: "ธีมมืด"
syncDeviceDarkMode: "ซิงค์โหมดมืดด้วยการตั้งค่ากับอุปกรณ์"
drive: "ไดรฟ์"
fileName: "ชื่อไฟล์"
selectFile: "เลือกไฟล์"
selectFiles: "เลือกไฟล์"
selectFolder: "เลือกโฟลเดอร์"
selectFolders: "เลือกโฟลเดอร์"
renameFile: "เปลี่ยนชื่อไฟล์"
folderName: "ชื่อแฟ้ม"
createFolder: "สร้างโฟลเดอร์"
renameFolder: "เปลี่ยนชื่อโฟลเดอร์"
deleteFolder: "ลบโฟลเดอร์"
addFile: "เพิ่มไฟล์"
emptyDrive: "ไดรฟ์ของคุณว่างเปล่านะ"
emptyFolder: "โฟลเดอร์นี้น่าจะว่างเปล่านะ"
unableToDelete: "ไม่สามารถลบออกได้นะ"
inputNewFileName: "ป้อนชื่อไฟล์ใหม่นะ"
inputNewDescription: "กรุณาใส่แคปชั่นใหม่"
inputNewFolderName: "กรุณาใส่ชื่อโฟลเดอร์ใหม่นะ\n"
circularReferenceFolder: "โฟลเดอร์ปลายทาง คือ โฟลเดอร์ย่อยของโฟลเดอร์ที่คุณต้องการที่จะย้ายล่ะนะ"
hasChildFilesOrFolders: "เนื่องจากโฟลเดอร์นี้ไม่ว่างเปล่า จึงไม่สามารถลบได้นะ"
copyUrl: "คัดลอก URL"
rename: "เปลี่ยนชื่อ"
avatar: "ไอคอน"
banner: "แบนเนอร์"
nsfw: "เนื้อหาที่ละเอียดอ่อน NSFW"
whenServerDisconnected: "สูญเสียการเชื่อมต่อกับเซิร์ฟเวอร์"
disconnectedFromServer: "ถูกตัดการเชื่อมต่อออกจากเซิร์ฟเวอร์"
reload: "รีโหลด"
doNothing: "เมิน"
reloadConfirm: "นายต้องการรีเฟรชไทม์ไลน์หรือป่าว?"
watch: "ดู"
unwatch: "หยุดดู"
accept: "ยอมรับ"
reject: "ปฏิเสธ"
normal: "โหมดปกติ"
instanceName: "ชื่อ อินสแตนซ์"
instanceDescription: "คำอธิบายอินสแตนซ์"
maintainerName: "ผู้ดูแล"
maintainerEmail: "อีเมล์แอดมิน"
tosUrl: "เงื่อนไขการให้บริการ URL"
thisYear: "ปีนี้"
thisMonth: "เดือนนี้"
today: "วันนี้"
dayX: "{วัน}"
monthX: "{เดือน}"
yearX: "{ปี}"
pages: "หน้า"
integration: "รวบรวม"
connectService: "เชื่อมต่อ"
disconnectService: "ตัดการเชื่อมต่อ"
enableLocalTimeline: "เปิดใช้งานไทม์ไลน์ในพื้นที่"
enableGlobalTimeline: "เปิดใช้งานไทม์ไลน์ทั่วโลก"
disablingTimelinesInfo: "ผู้ดูแลระบบและผู้ควบคุมจะสามารถเข้าถึงไทม์ไลน์ทั้งหมด ถึงแม้ว่าจะไม่ได้เปิดใช้งานก็ตาม"
registration: "ลงทะเบียน"
enableRegistration: "เปิดใช้งานการลงทะเบียนผู้ใช้ใหม่"
invite: "เชิญชวน"
driveCapacityPerLocalAccount: "ความจุของไดรฟ์ต่อผู้ใช้ภายในเครื่อง"
driveCapacityPerRemoteAccount: "ความจุของไดรฟ์ต่อผู้ใช้ระยะไกล"
inMb: "เป็นเมกะไบต์"
iconUrl: "ไอคอน URL"
bannerUrl: "URL รูปภาพแบนเนอร์"
backgroundImageUrl: "URL ภาพพื้นหลัง"
basicInfo: "ข้อมูลเบื้องต้น"
pinnedUsers: "ผู้ใช้งานที่ได้รับการปักหมุด"
pinnedUsersDescription: "ลิสต์ชื่อผู้ใช้โดยคั่นด้วยการขึ้นบรรทัดใหม่เพื่อปักหมุดในแท็บ \"สำรวจ\""
pinnedPages: "หน้าที่ปักหมุด"
pinnedPagesDescription: "ป้อนเส้นทางของหน้าที่คุณต้องการตรึงไว้ที่หน้าแรกของอินสแตนซ์นี้ โดยคั่นด้วยตัวแบ่งบรรทัด"
pinnedClipId: "ID ของคลิปที่จะปักหมุด"
pinnedNotes: "โน้ตที่ปักหมุดเอาไว้"
hcaptcha: "hCaptcha"
enableHcaptcha: "เปิดใช้ hCaptcha"
hcaptchaSiteKey: "คีย์ไซต์"
hcaptchaSecretKey: "คีย์ลับ"
recaptcha: "reCAPTCHA"
enableRecaptcha: "เปิดใช้ reCAPTCHA"
recaptchaSiteKey: "คีย์ไซต์"
recaptchaSecretKey: "คีย์ลับ"
avoidMultiCaptchaConfirm: "การใช้ระบบ Captcha หลายระบบอาจทำให้เกิดการรบกวนหรืออาจจะเกิดข้อผิดพลาดได้ หากต้องการที่จะปิดการใช้งานระบบ Captcha อื่น ๆ แนะนำให้ปิดตัวอื่นๆก่อน ถ้าหากคุณต้องการให้เปิดใช้งานต่อไป ให้ กด ยกเลิก"
antennas: "เสาอากาศ"
manageAntennas: "จัดการเสาอากาศ"
name: "ชื่อ"
antennaSource: "แหล่งเสาอากาศ"
antennaKeywords: "คีย์เวิร์ดที่ควรฟัง"
antennaExcludeKeywords: "คีย์เวิร์ดที่จะยกเว้น"
antennaKeywordsDescription: "คั่นด้วยช่องว่างสำหรับเงื่อนไข AND หรือด้วยการขึ้นบรรทัดใหม่สำหรับเงื่อนไข OR นะ"
notifyAntenna: "แจ้งเตือนเกี่ยวกับโน้ตใหม่"
withFileAntenna: "เฉพาะโน้ตที่มีไฟล์"
enableServiceworker: "เปิดใช้งาน การแจ้งเตือนแบบพุชสำหรับเบราว์เซอร์ของคุณ"
antennaUsersDescription: "ระบุหนึ่งชื่อผู้ใช้ต่อบรรทัด"
caseSensitive: "กรณีที่สำคัญ"
withReplies: "รวมตอบกลับ"
connectedTo: "บัญชีดังต่อไปนี้มีการเชื่อมต่อกัน"
notesAndReplies: "โพสต์และการตอบกลับ"
withFiles: "รวบรวมไฟล์"
silence: "ถูกปิดปาก"
silenceConfirm: "นายแน่ใจแล้วหรอว่าต้องการที่จะ ปิดปาก ผู้ใช้งานรายนี้?"
unsilence: "ยกเลิกการปิดปาก"
unsilenceConfirm: "นายแน่ใจแล้วหรอว่าต้องการที่จะยกเลิกปิดปากผู้ใช้งานรายนี้?"
popularUsers: "ผู้ใช้ที่เป็นที่นิยม"
recentlyUpdatedUsers: "ผู้ใช้ที่เพิ่งใช้งานล่าสุด"
recentlyRegisteredUsers: "ผู้ใช้ที่เข้าร่วมใหม่"
recentlyDiscoveredUsers: "ผู้ใช้ที่เพิ่งค้นพบใหม่"
exploreUsersCount: "มีผู้ใช้ {จำนวน} ราย"
exploreFediverse: "สำรวจเฟดดิเวิร์ส"
popularTags: "แท็กยอดนิยม"
userList: "รายการ"
about: "เกี่ยวกับ"
aboutMisskey: "เกี่ยวกับ Misskey"
administrator: "ผู้ดูแลระบบ"
token: "โทเค็น"
twoStepAuthentication: "ยืนยันตัวตน 2 ชั้น"
moderator: "ผู้ควบคุม"
moderation: "การกลั่นกรอง"
nUsersMentioned: "กล่าวถึงโดยผู้ใช้ {n} รายนี้"
securityKey: "กุญแจความปลอดภัย"
securityKeyName: "ชื่อคีย์"
registerSecurityKey: "ลงทะเบียนรหัสความปลอดภัยคีย์"
lastUsed: "ใช้ล่าสุด"
unregister: "เลิกติดตาม"
passwordLessLogin: "เข้าสู่ระบบแบบไม่ใช้รหัสผ่าน"
resetPassword: "รีเซ็ตรหัสผ่าน"
newPasswordIs: "รหัสผ่านใหม่คือ \"{password}\""
reduceUiAnimation: "ลดภาพเคลื่อนไหว UI"
share: "แชร์"
notFound: "ไม่พบหน้าที่ต้องการ"
notFoundDescription: "ไม่พบหน้าที่สอดคล้องตรงกันกับ URL นี้นะ"
uploadFolder: "โฟลเดอร์เริ่มต้นสำหรับอัพโหลด"
cacheClear: "ล้างแคช"
markAsReadAllNotifications: "ทำเครื่องหมายการแจ้งเตือนทั้งหมดว่าอ่านแล้ว"
markAsReadAllUnreadNotes: "ทำเครื่องหมายโน้ตทั้งหมดว่าอ่านแล้ว"
markAsReadAllTalkMessages: "ทำเครื่องหมายข้อความทั้งหมดว่าอ่านแล้ว"
help: "ช่วยเหลือ"
inputMessageHere: "พิมพ์ข้อความที่นี่"
close: "ปิด"
group: "กลุ่ม"
groups: "กลุ่ม"
createGroup: "สร้างกลุ่ม"
ownedGroups: "กลุ่มที่เป็นเจ้าของ"
joinedGroups: "เข้าร่วมกลุ่ม"
invites: "เชิญชวน"
groupName: "ชื่อกลุ่ม"
members: "สมาชิก"
transfer: "ถ่ายโอน"
messagingWithUser: "แชทส่วนตัว"
messagingWithGroup: "แชทกลุ่ม"
title: "หัวข้อ"
text: "ข้อความ"
enable: "เปิดใช้งาน"
next: "ถัด​ไป"
retype: "พิมพ์รหัสอีกครั้ง"
noteOf: "โน้ต โดย {ผู้ใช้งาน}"
inviteToGroup: "ชวนเข้ากลุ่ม"
quoteAttached: "อ้างอิง"
quoteQuestion: "นายต้องการที่จะอ้างอิงหรอ?"
noMessagesYet: "ยังไม่มีข้อความนะ"
newMessageExists: "คุณมีข้อความใหม่"
onlyOneFileCanBeAttached: "คุณสามารถแนบไฟล์กับข้อความได้เพียงไฟล์เดียวเท่านั้นนะ"
signinRequired: "กรุณาลงทะเบียนหรือลงชื่อเข้าใช้ก่อนดำเนินการต่อนะ"
invitations: "เชิญชวน"
invitationCode: "รหัสคำเชิญ"
checking: "Checking"
available: "พร้อมใช้งาน"
unavailable: "ไม่พร้อมใช้"
usernameInvalidFormat: "คุณสามารถใช้อักษรตัวพิมพ์ใหญ่และตัวพิมพ์เล็ก ตัวเลข และขีดล่างได้นะ ( a-z , A-Z , 0-9 , รวมไปถึงอักษรพิเศษเช่น + * / , . - อื่นๆเป็นต้น )"
tooShort: "สั้นเกินไปนะ"
tooLong: "ยาวเกินไปนะ"
weakPassword: "รหัสผ่าน แย่มาก"
normalPassword: "รหัสผ่านปกติ"
strongPassword: "รหัสผ่านรัดกุมมาก"
passwordMatched: "ถูกต้อง!"
passwordNotMatched: "ไม่ถูกต้อง"
signinWith: "ลงชื่อเข้าใช้ด้วย {x}"
signinFailed: "ไม่สามารถลงชื่อผู้เข้าใช้ได้ เนื่องจาก ชื่อผู้ใช้หรือรหัสผ่านที่คุณป้อนนั้นไม่ถูกต้องนะ"
tapSecurityKey: "แตะคีย์ความปลอดภัย"
or: "หรือ"
language: "ภาษา"
uiLanguage: "ภาษาอินเทอร์เฟซผู้ใช้งาน"
groupInvited: "คุณได้รับเชิญให้เข้าร่วมกลุ่ม"
aboutX: "เกี่ยวกับ {x}"
useOsNativeEmojis: "ใช้อีโมจิ OS แบบดั้งเดิม"
disableDrawer: "อย่าใช้ลิ้นชักสไตล์เมนู"
youHaveNoGroups: "คุณยังไม่มีกลุ่ม"
joinOrCreateGroup: "รับเชิญเข้าร่วมกลุ่มหรือสร้างกลุ่มของคุณเองเลยนะ"
noHistory: "ไม่มีรายการ"
signinHistory: "ประวัติการเข้าสู่ระบบ"
disableAnimatedMfm: "ปิดการใช้งาน MFM ด้วยแอนิเมชั่น"
doing: "กำลังประมวลผล......"
category: "หมวดหมู่"
tags: "แท็ก"
docSource: "ที่มาของเอกสารนี้"
createAccount: "สร้างบัญชี"
existingAccount: "บัญชีที่มีอยู่"
regenerate: "สร้างอีกครั้ง"
fontSize: "ขนาดตัวอักษร"
noFollowRequests: "คุณไม่มีคำขอติดตามที่รอดำเนินการ"
openImageInNewTab: "เปิดรูปภาพในแท็บใหม่"
dashboard: "หน้ากระดานหลัก"
local: "ในพื้นที่"
remote: "ระยะไกล"
total: "รวมทั้งหมด"
weekOverWeekChanges: "เปลี่ยนแปลงไปเมื่อสัปดาห์ที่แล้ว"
dayOverDayChanges: "เปลี่ยนแปลงไปเมื่อวานนี้"
appearance: "ภาพลักษณ์"
clientSettings: "การตั้งค่าไคลเอนต์"
accountSettings: "ตั้งค่าบัญชี"
promotion: "โฆษณา"
promote: "โปรโมท"
numberOfDays: "จำนวนวัน"
hideThisNote: "ซ่อนโน้ตนี้"
showFeaturedNotesInTimeline: "แสดงโน้ตเด่นในไทม์ไลน์"
objectStorage: "อ็อบเจ็กต์ ที่จัดเก็บ"
useObjectStorage: "ใช้ อ็อบเจ็กต์ ที่จัดเก็บ"
objectStorageBaseUrl: "URL ฐาน"
objectStorageBaseUrlDesc: "URL ที่ใช้เป็นข้อมูลอ้างอิง ระบุ URL ของ CDN หรือ Proxy ถ้าหากคุณใช้อย่างใดอย่างหนึ่ง\n สำหรับการใช้งาน S3 'https://<bucket>.s3.amazonaws.com' และสำหรับ GCS หรือบริการที่เทียบเท่าใช้ 'https://storage.googleapis.com/<bucket>', เป็นต้น"
objectStorageBucket: "Bucket"
objectStorageBucketDesc: "โปรดระบุชื่อที่เก็บข้อมูลที่ใช้กับผู้ให้บริการของคุณ"
objectStoragePrefix: "คำนำหน้า"
objectStoragePrefixDesc: "ไฟล์ทั้งหมดจะถูกเก็บไว้ภายใต้ไดเร็กทอรีที่มีคำนำหน้านี้นะ"
objectStorageEndpoint: "ปลายทาง"
objectStorageEndpointDesc: "เว้นว่างไว้หากคุณใช้ AWS S3 หรือระบุปลายทางเป็น '<host>' หรือ '<host>:<port>' ทั้งนี้ขึ้นอยู่กับผู้ให้บริการที่คุณใช้อยู่ด้วย"
objectStorageRegion: "ภูมิภาค"
objectStorageRegionDesc: "ระบุภูมิภาค เช่น 'xx-east-1' ถ้าหากบริการของคุณไม่ได้แยกความแตกต่างระหว่างภูมิภาคก็ให้ เว้นว่างไว้หรือป้อน 'us-east-1'"
objectStorageUseSSL: "ใช้ SSL"
objectStorageUseSSLDesc: "ปิดการทำงานนี้ไว้ ถ้าหากคุณจะไม่ใช้ HTTPS สำหรับการเชื่อมต่อ API"
objectStorageUseProxy: "เชื่อมต่อผ่านพร็อกซี"
objectStorageUseProxyDesc: "ปิดสิ่งนี้ไว้ถ้าหากคุณจะไม่ใช้ Proxy สำหรับการเชื่อมต่อ API"
objectStorageSetPublicRead: "ตั้งค่า \"public-read\" ในการอัปโหลด"
serverLogs: "บันทึกของเซิร์ฟเวอร์"
deleteAll: "ลบทั้งหมด"
showFixedPostForm: "แสดงแบบฟอร์มการโพสต์ที่ด้านบนสุดของไทม์ไลน์"
newNoteRecived: "มีโน้ตใหม่"
sounds: "เสียง"
listen: "ฟัง"
none: "ไม่มี"
showInPage: "แสดงในเพจ"
popout: "ป๊อปเอาต์"
volume: "ความดัง"
masterVolume: "มาสเตอร์วอลุ่ม"
details: "รายละเอียด"
chooseEmoji: "เลือกโมจิของเธอ"
unableToProcess: "ไม่สามารถดำเนินการให้เสร็จสิ้นได้"
recentUsed: "ใช้ล่าสุด"
install: "ติดตั้ง"
uninstall: "ถอนการติดตั้ง"
installedApps: "แอปที่ติดตั้งแล้ว"
nothing: "ไม่พบผลลัพธ์"
installedDate: "วันที่ติดตั้ง"
lastUsedDate: "ใช้งานครั้งล่าสุด"
state: "สถานะ"
sort: "เรียงลำดับ"
ascendingOrder: "เรียงจากน้อยไปมาก"
descendingOrder: "เรียงจากมากไปน้อย"
scratchpad: "กระดานทดลอง"
scratchpadDescription: "Scratchpad เป็นการจัดเตรียมสภาพแวดล้อมสำหรับการทดลอง AiScript แต่คุณสามารถเขียน ดำเนินการ และตรวจสอบผลลัพธ์ของการโต้ตอบกับ Misskey มันได้ด้วยนะ"
output: "เอาท์พุต"
script: "สคริปต์"
disablePagesScript: "ปิดการใช้งาน AiScript บนเพจ"
updateRemoteUser: "อัปเดตข้อมูลผู้ใช้งานระยะไกล"
deleteAllFiles: "ลบไฟล์ทั้งหมด"
deleteAllFilesConfirm: "นายแน่ใจแล้วหรอว่าต้องการที่จะลบไฟล์ทั้งหมด?"
removeAllFollowing: "เลิกติดตามผู้ใช้ที่ติดตามทั้งหมด"
removeAllFollowingDescription: "การที่คุณดำเนินการนี้จะเลิกติดตามบัญชีทั้งหมดจาก {host} โปรดเรียกใช้คำสั่งสิ่งนี้หากต้องการยกเลิกอินสแตนซ์ เช่น ไม่มีอยู่แล้ว"
userSuspended: "ผู้ใช้รายนี้ถูกระงับการใช้งาน"
userSilenced: "ผู้ใช้รายนี้กำลังถูกปิดกั้น"
yourAccountSuspendedTitle: "บัญชีนี้นั้นถูกระงับ"
yourAccountSuspendedDescription: "บัญชีนี้ถูกระงับ เนื่องจากละเมิดข้อกำหนดในการให้บริการของเซิร์ฟเวอร์หรืออาจจะละเมิดหลักเกณฑ์ชุมชน หรือ อาจจะโดนร้องเรียนเรื่องการละเมิดลิขสิทธิ์และอื่นๆอย่างต่อเนื่องซ้ำๆ หากคุณคิดว่าไม่ได้ทำผิดจริงๆหรือตัดสินผิดพลาด ได้โปรดกรุณาติดต่อผู้ดูแลระบบหากคุณต้องการทราบเหตุผลโดยละเอียดเพิ่มเติม และขอความกรุณาอย่าสร้างบัญชีใหม่"
menu: "เมนู"
divider: "ตัวแบ่ง"
addItem: "เพิ่มรายการ"
relays: "รีเลย์"
addRelay: "เพิ่มรีเลย์"
inboxUrl: "อินบ็อกซ์ URL"
addedRelays: "เพิ่มรีเลย์แล้ว"
serviceworkerInfo: "ต้องเปิดใช้งานสำหรับการแจ้งเตือนแบบพุช"
deletedNote: "โน้ตที่ถูกลบ"
invisibleNote: "โน้ตที่มองไม่เห็น"
enableInfiniteScroll: "โหลดเพิ่มเติมโดยอัตโนมัติ"
visibility: "การมองเห็น"
poll: "โพล"
useCw: "ซ่อนเนื้อหา"
enablePlayer: "เปิดเครื่องเล่นวิดีโอ"
disablePlayer: "ปิดเครื่องเล่นวิดีโอ"
expandTweet: "ขยายทวีต"
themeEditor: "ตัวแก้ไขธีม"
description: "รายละเอียด"
describeFile: "เพิ่มแคปชั่น"
enterFileDescription: "ใส่แคปชั่น"
author: "ผู้เขียน"
leaveConfirm: "คุณมีการเปลี่ยนแปลงที่ไม่ได้บันทึกนะ นายต้องการทิ้งการเปลี่ยนแปลงเหล่านั้นหรอ?"
manage: "การจัดการ"
plugins: "ปลั๊กอิน"
deck: "เด็ค"
undeck: "ออกจากเด็ค"
useBlurEffectForModal: "ใช้เอฟเฟกต์เบลอสำหรับโมดอล"
useFullReactionPicker: "ใช้เครื่องมือเลือกปฏิกิริยาขนาดเต็ม"
width: "ความกว้าง"
height: "ความสูง"
large: "ใหญ่"
medium: "ปานกลาง"
small: "เล็ก"
generateAccessToken: "สร้างการเข้าถึงโทเค็น"
permission: "การอนุญาต"
enableAll: "เปิดใช้งานทั้งหมด"
disableAll: "ปิดการใช้งานทั้งหมด"
tokenRequested: "ให้สิทธิ์การเข้าถึงบัญชี"
pluginTokenRequestedDescription: "ปลั๊กอินนี้จะสามารถใช้การอนุญาตที่ตั้งค่าไว้ที่นี่นะ"
notificationType: "ประเภทการแจ้งเตือน"
edit: "แก้ไข"
useStarForReactionFallback: "ใช้ ★ เป็นทางเลือกแทนถ้าหากไม่ทราบอิโมจิ"
emailServer: "อีเมล์เซิร์ฟเวอร์"
enableEmail: "เปิดใช้งานการกระจายอีเมล"
emailConfigInfo: "ใช้เพื่อยืนยันอีเมลของคุณระหว่างการสมัครหรือถ้าหากคุณลืมรหัสผ่าน"
email: "อีเมล์"
emailAddress: "ที่อยู่อีเมล์"
smtpConfig: "กำหนดค่าเซิร์ฟเวอร์ SMTP"
smtpHost: "โฮสต์"
smtpPort: "พอร์ต"
smtpUser: "ชื่อผู้ใช้"
smtpPass: "รหัสผ่าน"
emptyToDisableSmtpAuth: "ปล่อยชื่อผู้ใช้และรหัสผ่านว่างไว้เพื่อปิดใช้งานการยืนยัน SMTP"
smtpSecure: "ใช้โดยนัย SSL/TLS สำหรับการเชื่อมต่อ SMTP"
smtpSecureInfo: "ปิดสิ่งนี้เมื่อใช้ STARTTLS"
testEmail: "ทดสอบการส่งอีเมล"
wordMute: "ปิดเสียงคำ"
regexpError: "ข้อผิดพลาดของนิพจน์ทั่วไป"
regexpErrorDescription: "เกิดข้อผิดพลาดในนิพจน์ทั่วไปในบรรทัดที่ {line} ของการปิดเสียงคำ {tab} ของคุณ:"
instanceMute: "ปิดเสียง อินสแตนซ์"
userSaysSomething: "{ชื่อ} พูดอะไรบางอย่าง"
makeActive: "เปิดใช้งาน"
display: "แสดงผล"
copy: "คัดลอก"
metrics: "เมตริก"
overview: "ภาพรวม"
logs: "บันทึกข้อมูลระบบ"
delayed: "ดีเลย์"
database: "ฐานข้อมูล"
channel: "แชนแนล"
create: "สร้าง"
notificationSetting: "ตั้งค่าการแจ้งเตือน"
notificationSettingDesc: "เลือกประเภทการแจ้งเตือนที่ต้องการจะแสดง"
useGlobalSetting: "ใช้การตั้งค่าส่วนกลาง"
useGlobalSettingDesc: "หากเปิดไว้ ระบบจะใช้การตั้งค่าการแจ้งเตือนของบัญชีของคุณ หากปิดอยู่ สามารถทำการกำหนดค่าแต่ละรายการได้นะ"
other: "อื่น ๆ"
regenerateLoginToken: "สร้างโทเค็นการเข้าสู่ระบบอีกครั้ง"
regenerateLoginTokenDescription: "สร้างโทเค็นใหม่ที่ใช้ภายในระหว่างการเข้าสู่ระบบ โดยตามหลักปกติแล้วการดำเนินการนี้ไม่จำเป็น หากสร้างใหม่ อุปกรณ์ทั้งหมดจะถูกออกจากระบบนะ"
setMultipleBySeparatingWithSpace: "คั่นหลายรายการด้วยช่องว่าง"
fileIdOrUrl: "ไฟล์ ID หรือ URL"
behavior: "พฤติกรรม"
sample: "ตัวอย่าง"
abuseReports: "รายงาน"
reportAbuse: "รายงาน"
reportAbuseOf: "รายงาน {ชื่อ}"
fillAbuseReportDescription: "กรุณากรอกรายละเอียดเกี่ยวกับรายงานนี้ หากเป็นเรื่องเกี่ยวกับโน้ตโดยเฉพาะ ได้โปรดระบุ URL"
abuseReported: "เราได้ส่งรายงานของคุณไปแล้ว ขอบคุณมากๆนะ"
reporter: "นักข่าว"
reporteeOrigin: "รายงานต้นทาง"
reporterOrigin: "นักข่าวต้นทาง"
forwardReport: "ส่งต่อรายงานไปยังอินสแตนซ์ระยะไกล"
forwardReportIsAnonymous: "แทนที่จะเป็นบัญชีของคุณ บัญชีระบบที่ไม่ระบุตัวตนจะแสดงเป็นนักข่าวที่อินสแตนซ์ระยะไกล"
send: "ส่ง"
abuseMarkAsResolved: "ทำเครื่องหมายรายงานว่าแก้ไขแล้ว"
openInNewTab: "เปิดในแท็บใหม่"
openInSideView: "เปิดในมุมมองด้านข้าง"
defaultNavigationBehaviour: "พฤติกรรมการนำทางที่เป็นค่าเริ่มต้น"
editTheseSettingsMayBreakAccount: "การแก้ไขการตั้งค่าเหล่านี้อาจทำให้บัญชีของคุณเสียหายนะ"
instanceTicker: "ข้อมูลอินสแตนซ์ของบันทึกย่อ"
waitingFor: "กำลังรอคอย {x}"
random: "สุ่มค่า"
system: "ระบบ"
switchUi: "สลับ UI"
desktop: "เดสก์ท็อป"
clip: "คลิป"
createNew: "สร้างใหม่"
optional: "ไม่บังคับ"
createNewClip: "สร้างคลิปใหม่"
unclip: "ลบคลิป"
confirmToUnclipAlreadyClippedNote: "โน้ตนี้เป็นส่วนหนึ่งของคลิป \"{name}\" แล้ว คุณต้องการลบออกจากคลิปนี้แทนอย่างงั้นหรอ?"
public: "สาธารณะ"
i18nInfo: "Misskey กำลังได้รับการแปลเป็นภาษาต่างๆ โดยอาสาสมัคร คุณสามารถช่วยเหลือได้ที่ {link}"
manageAccessTokens: "การจัดการโทเค็นการเข้าถึง"
accountInfo: "ข้อมูลบัญชี"
notesCount: "จำนวนของโน้ต"
repliesCount: "จำนวนการตอบกลับที่ส่ง"
renotesCount: "จำนวนรีโน้ตที่ส่ง"
repliedCount: "จำนวนของการตอบกลับที่ได้รับ"
renotedCount: "จำนวนรีโน้ตที่ได้รับ"
followingCount: "จำนวนบัญชีที่ติดตาม"
followersCount: "จำนวนผู้ติดตาม"
sentReactionsCount: "จำนวนปฏิกิริยาที่ส่ง"
receivedReactionsCount: "จำนวนปฏิกิริยาที่ได้รับ"
pollVotesCount: "จำนวนโหวตที่ส่งไป"
pollVotedCount: "จำนวนโหวตที่ได้รับ"
yes: "ใช่"
no: "ไม่"
driveFilesCount: "จำนวนไฟล์ไดรฟ์"
driveUsage: "การใช้พื้นที่ไดรฟ์"
noCrawle: "ปฏิเสธการจัดทำดัชนีของโปรแกรมรวบรวมข้อมูล"
noCrawleDescription: "ขอให้เครื่องมือค้นหาไม่จัดทำดัชนีหน้าโปรไฟล์ บันทึกย่อ หน้า ฯลฯ"
lockedAccountInfo: "เว้นแต่ว่าคุณจะต้องตั้งค่าการเปิดเผยโน้ตเป็น \"ผู้ติดตามเท่านั้น\" โน้ตย่อของคุณจะปรากฏแก่ทุกคน ถึงแม้ว่าคุณจะเป็นกำหนดให้ผู้ติดตามต้องได้รับการอนุมัติด้วยตนเองก็ตาม"
alwaysMarkSensitive: "ทำเครื่องหมายเป็น NSFW เป็นค่าเริ่มต้น"
loadRawImages: "โหลดภาพต้นฉบับแทนการแสดงภาพขนาดย่อ"
disableShowingAnimatedImages: "ไม่ต้องเล่นภาพเคลื่อนไหว"
verificationEmailSent: "ส่งอีเมลยืนยันแล้วนะ ได้โปรดกรุณาไปที่ลิงก์ที่รวมไว้เพื่อทำการตรวจสอบให้เสร็จสิ้น"
notSet: "ไม่ได้ตั้งค่า"
emailVerified: "อีเมลได้รับการยืนยันแล้ว"
noteFavoritesCount: "จำนวนโน้ตที่ชื่นชอบ"
pageLikesCount: "จำนวนเพจที่ชอบ"
pageLikedCount: "จำนวนการกดถูกใจเพจที่ได้รับแล้ว"
contact: "ติดต่อ"
useSystemFont: "ใช้ฟอนต์เริ่มต้นของระบบ"
clips: "คลิป"
experimentalFeatures: "ฟังก์ชั่นทดสอบ"
developer: "สำหรับนักพัฒนา"
makeExplorable: "ทำให้บัญชีมองเห็นใน \"สำรวจ\""
makeExplorableDescription: "ถ้าหากคุณปิดการทำงานนี้ บัญชีของคุณนั้นจะไม่แสดงในส่วน \"สำรวจ\" นะ"
showGapBetweenNotesInTimeline: "แสดงช่องว่างระหว่างโพสต์บนไทม์ไลน์"
duplicate: "ทำซ้ำ"
left: "ซ้าย"
center: "ศูนย์กลาง"
wide: "กว้าง"
narrow: "ชิด"
reloadToApplySetting: "การตั้งค่านี้จะมีผลหลังจากโหลดหน้าซ้ำเท่านั้น ต้องการที่จะโหลดใหม่เลยมั้ย"
needReloadToApply: "จำเป็นต้องโหลดซ้ำถึงจะมีผลนะ"
showTitlebar: "แสดงแถบชื่อ"
clearCache: "ล้างแคช"
onlineUsersCount: "{n} ผู้ใช้คนนี้กำลังออนไลน์"
nUsers: "{n} ผู้ใช้งาน"
nNotes: "{n} โน้ต"
sendErrorReports: "ส่งรายงานว่าข้อผิดพลาด"
sendErrorReportsDescription: "เมื่อเปิดใช้งาน ข้อมูลข้อผิดพลาดโดยรายละเอียดนั้นจะถูกแชร์ให้กับ Misskey เมื่อเกิดปัญหา ซึ่งช่วยปรับปรุงคุณภาพของ Misskey\nซึ่งจะรวมถึงข้อมูล เช่น เวอร์ชั่นของระบบปฏิบัติการ เบราว์เซอร์ที่คุณใช้ กิจกรรมของคุณใน Misskey เป็นต้น"
myTheme: "ธีมของฉัน"
backgroundColor: "ภาพพื้นหลัง"
accentColor: "รูปแบบสี"
textColor: "สีข้อความ"
saveAs: "บันทึกเป็น..."
advanced: "ขั้นสูง"
value: "ค่า"
createdAt: "สร้างเมื่อ"
updatedAt: "อัพเดทล่าสุด"
saveConfirm: "บันทึกเปลี่ยนแปลงมั้ย?"
deleteConfirm: "ลบจริงๆเหรอ?"
invalidValue: "ค่านี้ไม่ถูกต้อง"
registry: "ทะเบียน"
closeAccount: "ปิด บัญชี"
currentVersion: "เวอร์ชั่นปัจจุบัน"
latestVersion: "รุ่นปัจจุบัน"
youAreRunningUpToDateClient: "คุณกำลังใช้ไคลเอ็นต์เวอร์ชันใหม่ล่าสุดนะ"
newVersionOfClientAvailable: "มีไคลเอ็นต์เวอร์ชันใหม่กว่าของคุณพร้อมใช้งานนะ"
usageAmount: "การใช้งาน"
capacity: "ความจุ"
inUse: "ใช้แล้ว"
editCode: "แก้ไขโค้ด"
apply: "ตกลง"
receiveAnnouncementFromInstance: "รับการแจ้งเตือนจากอินสแตนซ์นี้"
emailNotification: "การแจ้งเตือนทางอีเมล์"
publish: "เผยแพร่"
inChannelSearch: "ค้นหาในช่อง"
useReactionPickerForContextMenu: "เปิดตัวเลือกปฏิกิริยาเมื่อคลิกขวา"
typingUsers: "{users} กำลัง/กำลังพิมพ์..."
jumpToSpecifiedDate: "ข้ามไปยังวันที่เฉพาะเจาะจง"
showingPastTimeline: "กำลังแสดงผลไทม์ไลน์เก่า"
clear: "ล้าง"
markAllAsRead: "ทำเครื่องหมายทั้งหมดว่าอ่านแล้ว"
goBack: "ย้อนกลับ"
unlikeConfirm: "ลบไลค์ของคุณออกจริงๆหรอ"
fullView: "มุมมองแบบเต็ม"
quitFullView: "ออกจากมุมมองแบบเต็ม"
addDescription: "เพิ่มคำอธิบาย"
userPagePinTip: "คุณสามารถแสดงผลโน้ตย่อได้ที่นี่โดยเลือก \"ปักหมุดที่โปรไฟล์\" จากเมนูของโน้ตย่อแต่ละรายการนะ"
notSpecifiedMentionWarning: "โน้ตนี้มีการกล่าวถึงผู้ใช้งานที่ไม่รวมอยู่ในผู้รับ"
info: "เกี่ยวกับ"
userInfo: "ข้อมูลผู้ใช้"
unknown: "ไม่ทราบสถานะ"
onlineStatus: "สถานะออนไลน์"
hideOnlineStatus: "ซ่อนสถานะออนไลน์"
hideOnlineStatusDescription: "การซ่อนสถานะออนไลน์ของคุณช่วยลดความสะดวกของคุณสมบัติบางอย่าง เช่น การค้นหา อ่ะนะ"
online: "ออนไลน์"
active: "ใช้งานอยู่"
offline: "ออฟไลน์"
notRecommended: "ไม่ใช้งาน"
botProtection: "การป้องกัน Bot (or AI)"
instanceBlocking: "อินสแตนซ์ที่ถูกบล็อก"
selectAccount: "เลือกบัญชี"
switchAccount: "สลับบัญชีผู้ใช้"
enabled: "เปิดใช้งาน"
disabled: "ปิดการใช้งาน"
quickAction: "ปุ่มลัด"
user: "ผู้ใช้งาน"
administration: "การจัดการ"
accounts: "บัญชีผู้ใช้"
switch: "สลับ"
noMaintainerInformationWarning: "ข้อมูลผู้ดูแลไม่ได้รับการกำหนดค่านะ"
noBotProtectionWarning: "ไม่ได้กำหนดค่าการป้องกันบอทนะ"
configure: "กำหนดค่า"
postToGallery: "สร้างโพสต์แกลเลอรี่ใหม่"
gallery: "แกลเลอรี่"
recentPosts: "โพสต์ล่าสุด"
popularPosts: "โพสต์ติดอันดับ"
shareWithNote: "แบ่งปันด้วยโน้ต"
ads: "โฆษณา"
expiration: "กำหนดเวลา"
memo: "ข้อควรจำ"
priority: "ลำดับความสำคัญ"
high: "สูง"
middle: "ปานกลาง"
low: "ต่ำ"
emailNotConfiguredWarning: "ไม่ได้ตั้งค่าที่อยู่อีเมลนะ"
ratio: "อัตราส่วน"
previewNoteText: "แสดงตัวอย่าง"
customCss: "CSS ที่กำหนดเอง"
customCssWarn: "ควรใช้การตั้งค่านี้เฉพาะต่อเมื่อคุณรู้ว่าการตั้งค่านี้ใช้ทำอะไร การป้อนค่าที่ไม่เหมาะสมอาจทำให้ไคลเอ็นต์หยุดทำงานตามปกติได้นะ"
global: "ทั่วโลก"
squareAvatars: "แสดงผลอวตารสี่เหลี่ยม"
sent: "ส่ง"
received: "ได้รับแล้ว"
searchResult: "ผลการค้นหา"
hashtags: "แฮชแท็ก"
troubleshooting: "แก้ปัญหา"
useBlurEffect: "ใช้เอฟเฟกต์เบลอใน UI"
learnMore: "แสดงให้ดูหน่อย"
misskeyUpdated: "Misskey ได้รับการอัปเดตแล้ว!"
whatIsNew: "แสดงการเปลี่ยนแปลง"
translate: "แปลภาษา"
translatedFrom: "แปลมาจาก {x}"
accountDeletionInProgress: "กำลังดำเนินการลบบัญชีอยู่"
searchByGoogle: "ค้นหา"
file: "ไฟล์"
_ffVisibility:
public: "เผยแพร่"
_ad:
back: "ย้อนกลับ"
_email:
_follow:
title: "ได้ติดตามคุณ"
_mfm:
mention: "กล่าวถึง"
quote: "อ้างคำพูด"
emoji: "กำหนดอีโมจิเอง"
search: "ค้นหา"
_theme:
description: "รายละเอียด"
keys:
mention: "กล่าวถึง"
renote: "รีโน้ต"
divider: "ตัวแบ่ง"
_sfx:
note: "หมายเหตุ"
notification: "การเเจ้งเตือน"
chat: "แชท"
_widgets:
notifications: "การเเจ้งเตือน"
timeline: "ไทม์ไลน์"
activity: "กิจกรรม"
federation: "สหพันธ์"
jobQueue: "คิวงาน"
_cw:
show: "โหลดเพิ่มเติม"
_visibility:
home: "หน้าแรก"
followers: "ผู้ติดตาม"
_profile:
name: "ชื่อ"
username: "ชื่อผู้ใช้"
_exportOrImport:
followingList: "กำลังติดตาม"
muteList: "ปิดเสียง"
blockingList: "บล็อค"
userLists: "รายการ"
_charts:
federation: "สหพันธ์"
_timelines:
home: "หน้าแรก"
_pages:
blocks:
image: "รูปภาพ"
script:
categories:
list: "รายการ"
blocks:
_join:
arg1: "รายการ"
_randomPick:
arg1: "รายการ"
_dailyRandomPick:
arg1: "รายการ"
_seedRandomPick:
arg2: "รายการ"
_pick:
arg1: "รายการ"
_listLen:
arg1: "รายการ"
types:
array: "รายการ"
_notification:
youWereFollowed: "ได้ติดตามคุณ"
_types:
follow: "กำลังติดตาม"
mention: "กล่าวถึง"
renote: "รีโน้ต"
quote: "อ้างคำพูด"
reaction: "รีแอคชั่น"
_actions:
reply: "ตอบกลับ"
renote: "รีโน้ต"
_deck:
_columns:
notifications: "การเเจ้งเตือน"
tl: "ไทม์ไลน์"
antenna: "เสาอากาศ"
list: "รายการ"
mentions: "พูดถึง"

View File

@@ -737,6 +737,7 @@ hashtags: "Хештеґ"
hide: "Сховати" hide: "Сховати"
searchByGoogle: "Пошук" searchByGoogle: "Пошук"
indefinitely: "Ніколи" indefinitely: "Ніколи"
file: "Файли"
_ffVisibility: _ffVisibility:
public: "Опублікувати" public: "Опублікувати"
_ad: _ad:
@@ -1434,8 +1435,6 @@ _notification:
_deck: _deck:
alwaysShowMainColumn: "Завжди показувати головну колонку" alwaysShowMainColumn: "Завжди показувати головну колонку"
columnAlign: "Вирівняти стовпці" columnAlign: "Вирівняти стовпці"
columnMargin: "Відступ між стовпцями"
columnHeaderHeight: "Висота заголовку колони"
addColumn: "Додати стовпець" addColumn: "Додати стовпець"
swapLeft: "Пересунути ліворуч" swapLeft: "Пересунути ліворуч"
swapRight: "Пересунути праворуч" swapRight: "Пересунути праворуч"

View File

@@ -203,6 +203,7 @@ done: "Xong"
processing: "Đang xử lý" processing: "Đang xử lý"
preview: "Xem trước" preview: "Xem trước"
default: "Mặc định" default: "Mặc định"
defaultValueIs: "Mặc định: {value}"
noCustomEmojis: "Không có emoji" noCustomEmojis: "Không có emoji"
noJobs: "Không có công việc" noJobs: "Không có công việc"
federating: "Đang liên hợp" federating: "Đang liên hợp"
@@ -381,6 +382,7 @@ administrator: "Quản trị viên"
token: "Token" token: "Token"
twoStepAuthentication: "Xác minh 2 bước" twoStepAuthentication: "Xác minh 2 bước"
moderator: "Kiểm duyệt viên" moderator: "Kiểm duyệt viên"
moderation: "Kiểm duyệt"
nUsersMentioned: "Dùng bởi {n} người" nUsersMentioned: "Dùng bởi {n} người"
securityKey: "Khóa bảo mật" securityKey: "Khóa bảo mật"
securityKeyName: "Tên khoá" securityKeyName: "Tên khoá"
@@ -643,6 +645,8 @@ clip: "Ghim"
createNew: "Tạo mới" createNew: "Tạo mới"
optional: "Không bắt buộc" optional: "Không bắt buộc"
createNewClip: "Tạo một ghim mới" createNewClip: "Tạo một ghim mới"
unclip: "Bỏ ghim"
confirmToUnclipAlreadyClippedNote: "Bài đăng này là một phần của \"{name}\" ghim. Bạn có muốn bỏ khỏi ghim?"
public: "Công khai" public: "Công khai"
i18nInfo: "Misskey đang được các tình nguyện viên dịch sang nhiều thứ tiếng khác nhau. Bạn có thể hỗ trợ tại {link}." i18nInfo: "Misskey đang được các tình nguyện viên dịch sang nhiều thứ tiếng khác nhau. Bạn có thể hỗ trợ tại {link}."
manageAccessTokens: "Tạo mã truy cập" manageAccessTokens: "Tạo mã truy cập"
@@ -843,6 +847,28 @@ oneWeek: "1 tuần"
reflectMayTakeTime: "Có thể mất một thời gian để điều này được áp dụng." reflectMayTakeTime: "Có thể mất một thời gian để điều này được áp dụng."
failedToFetchAccountInformation: "Không thể lấy thông tin tài khoản" failedToFetchAccountInformation: "Không thể lấy thông tin tài khoản"
rateLimitExceeded: "Giới hạn quá mức" rateLimitExceeded: "Giới hạn quá mức"
cropImage: "Cắt hình ảnh"
cropImageAsk: "Bạn có muốn cắt ảnh này?"
file: "Tập tin"
recentNHours: "{n}h trước"
recentNDays: "{n} ngày trước"
noEmailServerWarning: "Chưa đặt máy chủ email."
thereIsUnresolvedAbuseReportWarning: "Có báo cáo chưa xử lí."
recommended: "Được đề xuất"
check: "Kiểm tra"
driveCapOverrideLabel: "Thay đổi dung lượng drive cho người này"
driveCapOverrideCaption: "Đặt dung lượng drive về mặc định bằng cách nhập 0 hoặc số âm."
requireAdminForView: "Bạn phải đăng nhập như là quản trị viên mới xem được."
isSystemAccount: "Đã tạo một tài khoản và tự động vận hành bởi hệ thống."
typeToConfirm: "Nhấn {x} để xác nhận"
deleteAccount: "Xóa tài khoản"
document: "Tài liệu"
numberOfPageCache: "Số lượng trang bộ nhớ đệm"
numberOfPageCacheDescription: "Việc tăng con số này sẽ cải thiện sự thuận tiện cho người dùng nhưng gây ra nhiều áp lực hơn cho máy chủ cũng như sử dụng nhiều bộ nhớ hơn."
logoutConfirm: "Bạn có chắc muốn đăng xuất?"
lastActiveDate: "Lần cuối vào"
statusbar: "Thanh trạng thái"
pleaseSelect: "Chọn một lựa chọn"
_emailUnavailable: _emailUnavailable:
used: "Địa chỉ email đã được sử dụng" used: "Địa chỉ email đã được sử dụng"
format: "Địa chỉ email không hợp lệ" format: "Địa chỉ email không hợp lệ"
@@ -1197,10 +1223,12 @@ _widgets:
trends: "Xu hướng" trends: "Xu hướng"
clock: "Đồng hồ" clock: "Đồng hồ"
rss: "Trình đọc RSS" rss: "Trình đọc RSS"
rssTicker: "RSS-Ticker"
activity: "Hoạt động" activity: "Hoạt động"
photos: "Kho ảnh" photos: "Kho ảnh"
digitalClock: "Đồng hồ số" digitalClock: "Đồng hồ số"
federation: "Liên hợp" federation: "Liên hợp"
instanceCloud: "Instance cloud"
postForm: "Mẫu đăng" postForm: "Mẫu đăng"
slideshow: "Trình chiếu" slideshow: "Trình chiếu"
button: "Nút" button: "Nút"
@@ -1638,8 +1666,6 @@ _notification:
_deck: _deck:
alwaysShowMainColumn: "Luôn hiện cột chính" alwaysShowMainColumn: "Luôn hiện cột chính"
columnAlign: "Căn cột" columnAlign: "Căn cột"
columnMargin: "Căn lề giữa các cột"
columnHeaderHeight: "Chiều rộng cột ảnh bìa"
addColumn: "Thêm cột" addColumn: "Thêm cột"
swapLeft: "Hoán đổi với cột bên trái" swapLeft: "Hoán đổi với cột bên trái"
swapRight: "Hoán đổi với cột bên phải" swapRight: "Hoán đổi với cột bên phải"
@@ -1648,6 +1674,9 @@ _deck:
stackLeft: "Xếp chồng với cột bên trái" stackLeft: "Xếp chồng với cột bên trái"
popRight: "Xếp chồng với cột bên trái" popRight: "Xếp chồng với cột bên trái"
profile: "Hồ sơ" profile: "Hồ sơ"
introduction: "Kết hợp các cột để tạo giao diện của riêng bạn!"
introduction2: "Bạn có thể thêm cột bất kỳ lúc nào bằng cách nhấn + ở bên phải màn hình."
widgetsIntroduction: "Chọn \"Sửa widget\" trong menu cột và thêm một widget."
_columns: _columns:
main: "Chính" main: "Chính"
widgets: "Tiện ích" widgets: "Tiện ích"

View File

@@ -842,6 +842,16 @@ oneDay: "1天"
oneWeek: "1周" oneWeek: "1周"
reflectMayTakeTime: "可能需要一些时间才能体现出效果。" reflectMayTakeTime: "可能需要一些时间才能体现出效果。"
failedToFetchAccountInformation: "获取账户信息失败" failedToFetchAccountInformation: "获取账户信息失败"
cropImage: "剪裁图像"
cropImageAsk: "是否要裁剪图像?"
file: "文件"
recentNHours: "最近{n}小时"
recentNDays: "最近{n}天"
noEmailServerWarning: "电子邮件服务器未设置。"
thereIsUnresolvedAbuseReportWarning: "有未解决的报告"
recommended: "推荐"
check: "检查"
isSystemAccount: "该账号由系统自动创建和管理。"
_emailUnavailable: _emailUnavailable:
used: "已经被使用过" used: "已经被使用过"
format: "无效的格式" format: "无效的格式"
@@ -1637,8 +1647,6 @@ _notification:
_deck: _deck:
alwaysShowMainColumn: "总是显示主列" alwaysShowMainColumn: "总是显示主列"
columnAlign: "列对齐" columnAlign: "列对齐"
columnMargin: "列间距"
columnHeaderHeight: "列标题高度"
addColumn: "添加列" addColumn: "添加列"
swapLeft: "向左移动" swapLeft: "向左移动"
swapRight: "向右移动" swapRight: "向右移动"

View File

@@ -203,6 +203,7 @@ done: "完成"
processing: "處理中" processing: "處理中"
preview: "預覽" preview: "預覽"
default: "預設" default: "預設"
defaultValueIs: "預設值:{value}"
noCustomEmojis: "沒有自訂的表情符號" noCustomEmojis: "沒有自訂的表情符號"
noJobs: "沒有任務" noJobs: "沒有任務"
federating: "整合搜索中" federating: "整合搜索中"
@@ -381,6 +382,7 @@ administrator: "管理員"
token: "權杖" token: "權杖"
twoStepAuthentication: "兩階段驗證" twoStepAuthentication: "兩階段驗證"
moderator: "板主" moderator: "板主"
moderation: "言論調節"
nUsersMentioned: "提到了{n}" nUsersMentioned: "提到了{n}"
securityKey: "安全金鑰" securityKey: "安全金鑰"
securityKeyName: "金鑰名稱" securityKeyName: "金鑰名稱"
@@ -643,6 +645,8 @@ clip: "摘錄"
createNew: "新建" createNew: "新建"
optional: "可選" optional: "可選"
createNewClip: "建立新摘錄" createNewClip: "建立新摘錄"
unclip: "解除摘錄"
confirmToUnclipAlreadyClippedNote: "此貼文已包含在摘錄「{name}」中。 你想將貼文從這個摘錄中排除嗎?"
public: "公開" public: "公開"
i18nInfo: "Misskey已經被志願者們翻譯成各種語言版本如果想要幫忙的話可以進入{link}幫助翻譯。" i18nInfo: "Misskey已經被志願者們翻譯成各種語言版本如果想要幫忙的話可以進入{link}幫助翻譯。"
manageAccessTokens: "管理存取權杖" manageAccessTokens: "管理存取權杖"
@@ -842,6 +846,29 @@ oneDay: "1天"
oneWeek: "1週" oneWeek: "1週"
reflectMayTakeTime: "可能需要一些時間才會出現效果。" reflectMayTakeTime: "可能需要一些時間才會出現效果。"
failedToFetchAccountInformation: "取得帳戶資訊失敗" failedToFetchAccountInformation: "取得帳戶資訊失敗"
rateLimitExceeded: "已超過速率限制"
cropImage: "圖片裁剪"
cropImageAsk: "要剪裁圖片嗎?"
file: "檔案"
recentNHours: "過去{n}小時"
recentNDays: "過去{n}天"
noEmailServerWarning: "尚未設定電子郵件伺服器。"
thereIsUnresolvedAbuseReportWarning: "有尚未處理的檢舉。"
recommended: "推薦"
check: "檢查"
driveCapOverrideLabel: "更改這個使用者的雲端硬碟容量上限"
driveCapOverrideCaption: "如果指定0以下的值就會被取消。"
requireAdminForView: "必須以管理者帳號登入才可以檢視。"
isSystemAccount: "由系統自動建立與管理的帳號。"
typeToConfirm: "要執行這項操作,請輸入 {x} "
deleteAccount: "刪除帳號"
document: "文件"
numberOfPageCache: "快取頁面數"
numberOfPageCacheDescription: "增加數量會提高便利性,但也會增加負荷與記憶體使用量。"
logoutConfirm: "確定要登出嗎?"
lastActiveDate: "上次使用日期及時間"
statusbar: "狀態列"
pleaseSelect: "請選擇"
_emailUnavailable: _emailUnavailable:
used: "已經在使用中" used: "已經在使用中"
format: "格式無效" format: "格式無效"
@@ -1196,10 +1223,12 @@ _widgets:
trends: "發燒貼文" trends: "發燒貼文"
clock: "時鐘" clock: "時鐘"
rss: "RSS閱讀器" rss: "RSS閱讀器"
rssTicker: "RSS跑馬燈"
activity: "動態" activity: "動態"
photos: "照片" photos: "照片"
digitalClock: "電子時鐘" digitalClock: "電子時鐘"
federation: "聯邦宇宙" federation: "聯邦宇宙"
instanceCloud: "實例雲"
postForm: "發佈窗口" postForm: "發佈窗口"
slideshow: "幻燈片" slideshow: "幻燈片"
button: "按鈕" button: "按鈕"
@@ -1637,8 +1666,6 @@ _notification:
_deck: _deck:
alwaysShowMainColumn: "總是顯示主欄" alwaysShowMainColumn: "總是顯示主欄"
columnAlign: "對齊欄位" columnAlign: "對齊欄位"
columnMargin: "列之間的邊距"
columnHeaderHeight: "欄位標題高度"
addColumn: "新增欄位" addColumn: "新增欄位"
swapLeft: "向左移動" swapLeft: "向左移動"
swapRight: "向右移動" swapRight: "向右移動"
@@ -1647,6 +1674,9 @@ _deck:
stackLeft: "向左折疊" stackLeft: "向左折疊"
popRight: "向右彈出" popRight: "向右彈出"
profile: "個人檔案" profile: "個人檔案"
introduction: "組合欄位來製作屬於自己的介面吧!"
introduction2: "您可以隨時透過按畫面右方的 + 來添加欄位。"
widgetsIntroduction: "請從欄位的選單中,選擇「編輯小工具」來添加小工具"
_columns: _columns:
main: "主列" main: "主列"
widgets: "小工具" widgets: "小工具"

View File

@@ -1,6 +1,6 @@
{ {
"name": "misskey", "name": "misskey",
"version": "12.111.1", "version": "12.112.3",
"codename": "indigo", "codename": "indigo",
"repository": { "repository": {
"type": "git", "type": "git",
@@ -41,10 +41,10 @@
"devDependencies": { "devDependencies": {
"@types/gulp": "4.0.9", "@types/gulp": "4.0.9",
"@types/gulp-rename": "2.0.1", "@types/gulp-rename": "2.0.1",
"@typescript-eslint/parser": "5.27.1", "@typescript-eslint/parser": "5.30.0",
"cross-env": "7.0.3", "cross-env": "7.0.3",
"cypress": "10.0.3", "cypress": "10.3.0",
"start-server-and-test": "1.14.0", "start-server-and-test": "1.14.0",
"typescript": "4.7.3" "typescript": "4.7.4"
} }
} }

View File

@@ -5,6 +5,6 @@
"loader=./test/loader.js" "loader=./test/loader.js"
], ],
"slow": 1000, "slow": 1000,
"timeout": 10000, "timeout": 30000,
"exit": true "exit": true
} }

View File

@@ -0,0 +1,5 @@
Font Awesome Icons
-------------------------
Ⓒ Font Awesome
CC BY 4.0 (https://creativecommons.org/licenses/by/4.0/)

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 577 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 844 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 507 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 689 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 772 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 930 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 798 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 991 B

View File

@@ -0,0 +1,23 @@
export class nsfwDetection1655368940105 {
name = 'nsfwDetection1655368940105'
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "drive_file" ADD "forceIsSensitive" boolean NOT NULL DEFAULT false`);
await queryRunner.query(`ALTER TABLE "drive_file" ADD "predictedIsSensitive" boolean NOT NULL DEFAULT false`);
await queryRunner.query(`COMMENT ON COLUMN "drive_file"."predictedIsSensitive" IS 'Whether the DriveFile is NSFW. (predict)'`);
await queryRunner.query(`CREATE TYPE "public"."meta_sensitiveimagedetection_enum" AS ENUM('none', 'all', 'local', 'remote')`);
await queryRunner.query(`ALTER TABLE "meta" ADD "sensitiveImageDetection" "public"."meta_sensitiveimagedetection_enum" NOT NULL DEFAULT 'none'`);
await queryRunner.query(`ALTER TABLE "meta" ADD "forceIsSensitiveWhenPredicted" boolean NOT NULL DEFAULT true`);
await queryRunner.query(`CREATE INDEX "IDX_fc2d74a6d7d8b11292a851d8f8" ON "drive_file" ("predictedIsSensitive") `);
}
async down(queryRunner) {
await queryRunner.query(`DROP INDEX "public"."IDX_fc2d74a6d7d8b11292a851d8f8"`);
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "forceIsSensitiveWhenPredicted"`);
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "sensitiveImageDetection"`);
await queryRunner.query(`DROP TYPE "public"."meta_sensitiveimagedetection_enum"`);
await queryRunner.query(`COMMENT ON COLUMN "drive_file"."predictedIsSensitive" IS 'Whether the DriveFile is NSFW. (predict)'`);
await queryRunner.query(`ALTER TABLE "drive_file" DROP COLUMN "predictedIsSensitive"`);
await queryRunner.query(`ALTER TABLE "drive_file" DROP COLUMN "forceIsSensitive"`);
}
}

View File

@@ -0,0 +1,15 @@
export class nsfwDetection21655371960534 {
name = 'nsfwDetection21655371960534'
async up(queryRunner) {
await queryRunner.query(`CREATE TYPE "public"."meta_sensitiveimagedetectionsensitivity_enum" AS ENUM('medium', 'low', 'high')`);
await queryRunner.query(`ALTER TABLE "meta" ADD "sensitiveImageDetectionSensitivity" "public"."meta_sensitiveimagedetectionsensitivity_enum" NOT NULL DEFAULT 'medium'`);
await queryRunner.query(`ALTER TABLE "meta" ADD "disallowUploadWhenPredictedAsPorn" boolean NOT NULL DEFAULT false`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "disallowUploadWhenPredictedAsPorn"`);
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "sensitiveImageDetectionSensitivity"`);
await queryRunner.query(`DROP TYPE "public"."meta_sensitiveimagedetectionsensitivity_enum"`);
}
}

View File

@@ -0,0 +1,21 @@
export class nsfwDetection31655388169582 {
name = 'nsfwDetection31655388169582'
async up(queryRunner) {
await queryRunner.query(`ALTER TYPE "public"."meta_sensitiveimagedetectionsensitivity_enum" RENAME TO "meta_sensitiveimagedetectionsensitivity_enum_old"`);
await queryRunner.query(`CREATE TYPE "public"."meta_sensitiveimagedetectionsensitivity_enum" AS ENUM('medium', 'low', 'high', 'veryLow', 'veryHigh')`);
await queryRunner.query(`ALTER TABLE "meta" ALTER COLUMN "sensitiveImageDetectionSensitivity" DROP DEFAULT`);
await queryRunner.query(`ALTER TABLE "meta" ALTER COLUMN "sensitiveImageDetectionSensitivity" TYPE "public"."meta_sensitiveimagedetectionsensitivity_enum" USING "sensitiveImageDetectionSensitivity"::"text"::"public"."meta_sensitiveimagedetectionsensitivity_enum"`);
await queryRunner.query(`ALTER TABLE "meta" ALTER COLUMN "sensitiveImageDetectionSensitivity" SET DEFAULT 'medium'`);
await queryRunner.query(`DROP TYPE "public"."meta_sensitiveimagedetectionsensitivity_enum_old"`);
}
async down(queryRunner) {
await queryRunner.query(`CREATE TYPE "public"."meta_sensitiveimagedetectionsensitivity_enum_old" AS ENUM('medium', 'low', 'high')`);
await queryRunner.query(`ALTER TABLE "meta" ALTER COLUMN "sensitiveImageDetectionSensitivity" DROP DEFAULT`);
await queryRunner.query(`ALTER TABLE "meta" ALTER COLUMN "sensitiveImageDetectionSensitivity" TYPE "public"."meta_sensitiveimagedetectionsensitivity_enum_old" USING "sensitiveImageDetectionSensitivity"::"text"::"public"."meta_sensitiveimagedetectionsensitivity_enum_old"`);
await queryRunner.query(`ALTER TABLE "meta" ALTER COLUMN "sensitiveImageDetectionSensitivity" SET DEFAULT 'medium'`);
await queryRunner.query(`DROP TYPE "public"."meta_sensitiveimagedetectionsensitivity_enum"`);
await queryRunner.query(`ALTER TYPE "public"."meta_sensitiveimagedetectionsensitivity_enum_old" RENAME TO "meta_sensitiveimagedetectionsensitivity_enum"`);
}
}

View File

@@ -0,0 +1,25 @@
export class nsfwDetection41655393015659 {
name = 'nsfwDetection41655393015659'
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "sensitiveImageDetection"`);
await queryRunner.query(`DROP TYPE "public"."meta_sensitiveimagedetection_enum"`);
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "sensitiveImageDetectionSensitivity"`);
await queryRunner.query(`DROP TYPE "public"."meta_sensitiveimagedetectionsensitivity_enum"`);
await queryRunner.query(`CREATE TYPE "public"."meta_sensitivemediadetection_enum" AS ENUM('none', 'all', 'local', 'remote')`);
await queryRunner.query(`ALTER TABLE "meta" ADD "sensitiveMediaDetection" "public"."meta_sensitivemediadetection_enum" NOT NULL DEFAULT 'none'`);
await queryRunner.query(`CREATE TYPE "public"."meta_sensitivemediadetectionsensitivity_enum" AS ENUM('medium', 'low', 'high', 'veryLow', 'veryHigh')`);
await queryRunner.query(`ALTER TABLE "meta" ADD "sensitiveMediaDetectionSensitivity" "public"."meta_sensitivemediadetectionsensitivity_enum" NOT NULL DEFAULT 'medium'`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "sensitiveMediaDetectionSensitivity"`);
await queryRunner.query(`DROP TYPE "public"."meta_sensitivemediadetectionsensitivity_enum"`);
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "sensitiveMediaDetection"`);
await queryRunner.query(`DROP TYPE "public"."meta_sensitivemediadetection_enum"`);
await queryRunner.query(`CREATE TYPE "public"."meta_sensitiveimagedetectionsensitivity_enum" AS ENUM('medium', 'low', 'high', 'veryLow', 'veryHigh')`);
await queryRunner.query(`ALTER TABLE "meta" ADD "sensitiveImageDetectionSensitivity" "public"."meta_sensitiveimagedetectionsensitivity_enum" NOT NULL DEFAULT 'medium'`);
await queryRunner.query(`CREATE TYPE "public"."meta_sensitiveimagedetection_enum" AS ENUM('none', 'all', 'local', 'remote')`);
await queryRunner.query(`ALTER TABLE "meta" ADD "sensitiveImageDetection" "public"."meta_sensitiveimagedetection_enum" NOT NULL DEFAULT 'none'`);
}
}

View File

@@ -0,0 +1,13 @@
export class driveCapacityOverrideMb1655813815729 {
name = 'driveCapacityOverrideMb1655813815729'
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "user" ADD "driveCapacityOverrideMb" integer`);
await queryRunner.query(`COMMENT ON COLUMN "user"."driveCapacityOverrideMb" IS 'Overrides user drive capacity limit'`);
}
async down(queryRunner) {
await queryRunner.query(`COMMENT ON COLUMN "user"."driveCapacityOverrideMb" IS 'Overrides user drive capacity limit'`);
await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "driveCapacityOverrideMb"`);
}
}

View File

@@ -0,0 +1,17 @@
export class userIp1655918165614 {
name = 'userIp1655918165614'
async up(queryRunner) {
await queryRunner.query(`CREATE TABLE "user_ip" ("id" SERIAL NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "userId" character varying(32) NOT NULL, "ip" character varying(128) NOT NULL, CONSTRAINT "PK_2c44ddfbf7c0464d028dcef325e" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE INDEX "IDX_7f7f1c66f48e9a8e18a33bc515" ON "user_ip" ("userId") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_361b500e06721013c124b7b6c5" ON "user_ip" ("userId", "ip") `);
await queryRunner.query(`ALTER TABLE "user_ip" ADD CONSTRAINT "FK_7f7f1c66f48e9a8e18a33bc5150" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "user_ip" DROP CONSTRAINT "FK_7f7f1c66f48e9a8e18a33bc5150"`);
await queryRunner.query(`DROP INDEX "public"."IDX_361b500e06721013c124b7b6c5"`);
await queryRunner.query(`DROP INDEX "public"."IDX_7f7f1c66f48e9a8e18a33bc515"`);
await queryRunner.query(`DROP TABLE "user_ip"`);
}
}

View File

@@ -0,0 +1,13 @@
export class fileIp1656122560740 {
name = 'fileIp1656122560740'
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "drive_file" ADD "requestHeaders" jsonb DEFAULT '{}'`);
await queryRunner.query(`ALTER TABLE "drive_file" ADD "requestIp" character varying(128)`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "drive_file" DROP COLUMN "requestIp"`);
await queryRunner.query(`ALTER TABLE "drive_file" DROP COLUMN "requestHeaders"`);
}
}

View File

@@ -0,0 +1,33 @@
export class nsfwDetection51656251734807 {
name = 'nsfwDetection51656251734807'
async up(queryRunner) {
await queryRunner.query(`DROP INDEX "public"."IDX_fc2d74a6d7d8b11292a851d8f8"`);
await queryRunner.query(`ALTER TABLE "drive_file" DROP COLUMN "forceIsSensitive"`);
await queryRunner.query(`ALTER TABLE "drive_file" DROP COLUMN "predictedIsSensitive"`);
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "forceIsSensitiveWhenPredicted"`);
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "disallowUploadWhenPredictedAsPorn"`);
await queryRunner.query(`ALTER TABLE "drive_file" ADD "maybeSensitive" boolean NOT NULL DEFAULT false`);
await queryRunner.query(`COMMENT ON COLUMN "drive_file"."maybeSensitive" IS 'Whether the DriveFile is NSFW. (predict)'`);
await queryRunner.query(`ALTER TABLE "drive_file" ADD "maybePorn" boolean NOT NULL DEFAULT false`);
await queryRunner.query(`ALTER TABLE "meta" ADD "setSensitiveFlagAutomatically" boolean NOT NULL DEFAULT false`);
await queryRunner.query(`ALTER TABLE "user_profile" ADD "autoSensitive" boolean NOT NULL DEFAULT false`);
await queryRunner.query(`CREATE INDEX "IDX_3b33dff77bb64b23c88151d23e" ON "drive_file" ("maybeSensitive") `);
await queryRunner.query(`CREATE INDEX "IDX_8bdcd3dd2bddb78014999a16ce" ON "drive_file" ("maybePorn") `);
}
async down(queryRunner) {
await queryRunner.query(`DROP INDEX "public"."IDX_8bdcd3dd2bddb78014999a16ce"`);
await queryRunner.query(`DROP INDEX "public"."IDX_3b33dff77bb64b23c88151d23e"`);
await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "autoSensitive"`);
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "setSensitiveFlagAutomatically"`);
await queryRunner.query(`ALTER TABLE "drive_file" DROP COLUMN "maybePorn"`);
await queryRunner.query(`COMMENT ON COLUMN "drive_file"."maybeSensitive" IS 'Whether the DriveFile is NSFW. (predict)'`);
await queryRunner.query(`ALTER TABLE "drive_file" DROP COLUMN "maybeSensitive"`);
await queryRunner.query(`ALTER TABLE "meta" ADD "disallowUploadWhenPredictedAsPorn" boolean NOT NULL DEFAULT false`);
await queryRunner.query(`ALTER TABLE "meta" ADD "forceIsSensitiveWhenPredicted" boolean NOT NULL DEFAULT true`);
await queryRunner.query(`ALTER TABLE "drive_file" ADD "predictedIsSensitive" boolean NOT NULL DEFAULT false`);
await queryRunner.query(`ALTER TABLE "drive_file" ADD "forceIsSensitive" boolean NOT NULL DEFAULT false`);
await queryRunner.query(`CREATE INDEX "IDX_fc2d74a6d7d8b11292a851d8f8" ON "drive_file" ("predictedIsSensitive") `);
}
}

View File

@@ -0,0 +1,13 @@
export class ip21656328812281 {
name = 'ip21656328812281'
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "user_ip" DROP CONSTRAINT "FK_7f7f1c66f48e9a8e18a33bc5150"`);
await queryRunner.query(`ALTER TABLE "meta" ADD "enableIpLogging" boolean NOT NULL DEFAULT false`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "enableIpLogging"`);
await queryRunner.query(`ALTER TABLE "user_ip" ADD CONSTRAINT "FK_7f7f1c66f48e9a8e18a33bc5150" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
}
}

View File

@@ -0,0 +1,11 @@
export class nsfwDetection61656408772602 {
name = 'nsfwDetection61656408772602'
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "meta" ADD "enableSensitiveMediaDetectionForVideos" boolean NOT NULL DEFAULT false`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "enableSensitiveMediaDetectionForVideos"`);
}
}

View File

@@ -0,0 +1,11 @@
export class userModerationNote1656772790599 {
name = 'userModerationNote1656772790599'
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "user_profile" ADD "moderationNote" character varying(8192) NOT NULL DEFAULT ''`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "moderationNote"`);
}
}

View File

@@ -0,0 +1,11 @@
export class activeEmailValidation1657346559800 {
name = 'activeEmailValidation1657346559800'
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "meta" ADD "enableActiveEmailValidation" boolean NOT NULL DEFAULT true`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "enableActiveEmailValidation"`);
}
}

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -14,7 +14,7 @@
"lodash": "^4.17.21" "lodash": "^4.17.21"
}, },
"dependencies": { "dependencies": {
"@bull-board/koa": "3.11.1", "@bull-board/koa": "4.0.0",
"@discordapp/twemoji": "14.0.2", "@discordapp/twemoji": "14.0.2",
"@elastic/elasticsearch": "7.11.0", "@elastic/elasticsearch": "7.11.0",
"@koa/cors": "3.1.0", "@koa/cors": "3.1.0",
@@ -23,19 +23,21 @@
"@peertube/http-signature": "1.6.0", "@peertube/http-signature": "1.6.0",
"@sinonjs/fake-timers": "9.1.2", "@sinonjs/fake-timers": "9.1.2",
"@syuilo/aiscript": "0.11.1", "@syuilo/aiscript": "0.11.1",
"@tensorflow/tfjs-node": "3.18.0",
"abort-controller": "3.0.0", "abort-controller": "3.0.0",
"ajv": "8.11.0", "ajv": "8.11.0",
"archiver": "5.3.1", "archiver": "5.3.1",
"autobind-decorator": "2.4.0", "autobind-decorator": "2.4.0",
"autwh": "0.1.0", "autwh": "0.1.0",
"aws-sdk": "2.1152.0", "aws-sdk": "2.1165.0",
"bcryptjs": "2.4.3", "bcryptjs": "2.4.3",
"blurhash": "1.1.5", "blurhash": "1.1.5",
"bull": "4.8.3", "bull": "4.8.4",
"cacheable-lookup": "6.0.4", "cacheable-lookup": "6.0.4",
"cbor": "8.1.0", "cbor": "8.1.0",
"chalk": "5.0.1", "chalk": "5.0.1",
"chalk-template": "0.4.0", "chalk-template": "0.4.0",
"chokidar": "3.3.1",
"cli-highlight": "2.1.11", "cli-highlight": "2.1.11",
"color-convert": "2.0.1", "color-convert": "2.0.1",
"content-disposition": "0.5.4", "content-disposition": "0.5.4",
@@ -47,14 +49,15 @@
"fluent-ffmpeg": "2.1.2", "fluent-ffmpeg": "2.1.2",
"got": "12.1.0", "got": "12.1.0",
"hpagent": "0.1.2", "hpagent": "0.1.2",
"ioredis": "4.28.5",
"ip-cidr": "3.0.10", "ip-cidr": "3.0.10",
"is-svg": "4.3.2", "is-svg": "4.3.2",
"js-yaml": "4.1.0", "js-yaml": "4.1.0",
"jsdom": "19.0.0", "jsdom": "20.0.0",
"json5": "2.2.1", "json5": "2.2.1",
"json5-loader": "4.0.1", "json5-loader": "4.0.1",
"jsonld": "6.0.0", "jsonld": "6.0.0",
"jsrsasign": "10.5.24", "jsrsasign": "10.5.25",
"koa": "2.13.4", "koa": "2.13.4",
"koa-bodyparser": "4.3.0", "koa-bodyparser": "4.3.0",
"koa-favicon": "2.1.0", "koa-favicon": "2.1.0",
@@ -72,26 +75,27 @@
"multer": "1.4.4", "multer": "1.4.4",
"nested-property": "4.0.0", "nested-property": "4.0.0",
"node-fetch": "3.2.6", "node-fetch": "3.2.6",
"nodemailer": "6.7.5", "nodemailer": "6.7.6",
"nsfwjs": "2.4.1",
"os-utils": "0.0.14", "os-utils": "0.0.14",
"parse5": "6.0.1", "parse5": "7.0.0",
"pg": "8.7.3", "pg": "8.7.3",
"private-ip": "2.3.3", "private-ip": "2.3.3",
"probe-image-size": "7.2.3", "probe-image-size": "7.2.3",
"promise-limit": "2.7.0", "promise-limit": "2.7.0",
"pug": "3.0.2", "pug": "3.0.2",
"punycode": "2.1.1", "punycode": "2.1.1",
"pureimage": "0.3.8", "pureimage": "0.3.14",
"qrcode": "1.5.0", "qrcode": "1.5.0",
"random-seed": "0.3.0", "random-seed": "0.3.0",
"ratelimiter": "3.4.1", "ratelimiter": "3.4.1",
"re2": "1.17.4", "re2": "1.17.7",
"redis": "3.1.2",
"redis-lock": "0.1.4", "redis-lock": "0.1.4",
"reflect-metadata": "0.1.13", "reflect-metadata": "0.1.13",
"rename": "1.0.4", "rename": "1.0.4",
"require-all": "3.0.0", "require-all": "3.0.0",
"rndstr": "1.0.0", "rndstr": "1.0.0",
"rss-parser": "3.12.0",
"s-age": "1.1.2", "s-age": "1.1.2",
"sanitize-html": "2.7.0", "sanitize-html": "2.7.0",
"semver": "7.3.7", "semver": "7.3.7",
@@ -100,17 +104,17 @@
"strict-event-emitter-types": "2.0.0", "strict-event-emitter-types": "2.0.0",
"stringz": "2.1.0", "stringz": "2.1.0",
"style-loader": "3.3.1", "style-loader": "3.3.1",
"summaly": "2.5.1", "summaly": "2.7.0",
"syslog-pro": "1.0.0", "syslog-pro": "1.0.0",
"systeminformation": "5.11.16", "systeminformation": "5.11.22",
"tinycolor2": "1.4.2", "tinycolor2": "1.4.2",
"tmp": "0.2.1", "tmp": "0.2.1",
"ts-loader": "9.3.0", "ts-loader": "9.3.1",
"ts-node": "10.8.1", "ts-node": "10.8.1",
"tsc-alias": "1.6.9", "tsc-alias": "1.6.11",
"tsconfig-paths": "4.0.0", "tsconfig-paths": "4.0.0",
"twemoji-parser": "14.0.0", "twemoji-parser": "14.0.0",
"typeorm": "0.3.6", "typeorm": "0.3.7",
"ulid": "2.3.0", "ulid": "2.3.0",
"unzipper": "0.10.11", "unzipper": "0.10.11",
"uuid": "8.3.2", "uuid": "8.3.2",
@@ -121,7 +125,6 @@
}, },
"devDependencies": { "devDependencies": {
"@redocly/openapi-core": "1.0.0-beta.97", "@redocly/openapi-core": "1.0.0-beta.97",
"@types/semver": "7.3.9",
"@types/bcryptjs": "2.4.2", "@types/bcryptjs": "2.4.2",
"@types/bull": "3.15.8", "@types/bull": "3.15.8",
"@types/cbor": "6.0.0", "@types/cbor": "6.0.0",
@@ -144,11 +147,10 @@
"@types/koa__multer": "2.0.4", "@types/koa__multer": "2.0.4",
"@types/koa__router": "8.0.11", "@types/koa__router": "8.0.11",
"@types/mocha": "9.1.1", "@types/mocha": "9.1.1",
"@types/node": "17.0.41", "@types/node": "18.0.0",
"@types/node-fetch": "3.0.3", "@types/node-fetch": "3.0.3",
"@types/nodemailer": "6.4.4", "@types/nodemailer": "6.4.4",
"@types/oauth": "0.9.1", "@types/oauth": "0.9.1",
"@types/parse5": "6.0.3",
"@types/pug": "2.0.6", "@types/pug": "2.0.6",
"@types/punycode": "2.1.0", "@types/punycode": "2.1.0",
"@types/qrcode": "1.4.2", "@types/qrcode": "1.4.2",
@@ -157,7 +159,8 @@
"@types/redis": "4.0.11", "@types/redis": "4.0.11",
"@types/rename": "1.0.4", "@types/rename": "1.0.4",
"@types/sanitize-html": "2.6.2", "@types/sanitize-html": "2.6.2",
"@types/sharp": "0.30.2", "@types/semver": "7.3.10",
"@types/sharp": "0.30.4",
"@types/sinonjs__fake-timers": "8.1.2", "@types/sinonjs__fake-timers": "8.1.2",
"@types/speakeasy": "2.0.7", "@types/speakeasy": "2.0.7",
"@types/tinycolor2": "1.4.3", "@types/tinycolor2": "1.4.3",
@@ -166,12 +169,12 @@
"@types/web-push": "3.3.2", "@types/web-push": "3.3.2",
"@types/websocket": "1.0.5", "@types/websocket": "1.0.5",
"@types/ws": "8.5.3", "@types/ws": "8.5.3",
"@typescript-eslint/eslint-plugin": "5.27.1", "@typescript-eslint/eslint-plugin": "5.30.0",
"@typescript-eslint/parser": "5.27.1", "@typescript-eslint/parser": "5.30.0",
"typescript": "4.7.3",
"eslint": "8.17.0",
"eslint-plugin-import": "2.26.0",
"cross-env": "7.0.3", "cross-env": "7.0.3",
"execa": "6.1.0" "eslint": "8.18.0",
"eslint-plugin-import": "2.26.0",
"execa": "6.1.0",
"typescript": "4.7.4"
} }
} }

View File

@@ -19,6 +19,7 @@ export type Source = {
redis: { redis: {
host: string; host: string;
port: number; port: number;
family?: number;
pass: string; pass: string;
db?: number; db?: number;
prefix?: string; prefix?: string;

View File

@@ -68,9 +68,10 @@ import { RegistryItem } from '@/models/entities/registry-item.js';
import { Ad } from '@/models/entities/ad.js'; import { Ad } from '@/models/entities/ad.js';
import { PasswordResetRequest } from '@/models/entities/password-reset-request.js'; import { PasswordResetRequest } from '@/models/entities/password-reset-request.js';
import { UserPending } from '@/models/entities/user-pending.js'; import { UserPending } from '@/models/entities/user-pending.js';
import { Webhook } from '@/models/entities/webhook.js';
import { UserIp } from '@/models/entities/user-ip.js';
import { entities as charts } from '@/services/chart/entities.js'; import { entities as charts } from '@/services/chart/entities.js';
import { Webhook } from '@/models/entities/webhook.js';
import { envOption } from '../env.js'; import { envOption } from '../env.js';
import { dbLogger } from './logger.js'; import { dbLogger } from './logger.js';
import { redisClient } from './redis.js'; import { redisClient } from './redis.js';
@@ -173,6 +174,7 @@ export const entities = [
PasswordResetRequest, PasswordResetRequest,
UserPending, UserPending,
Webhook, Webhook,
UserIp,
...charts, ...charts,
]; ];
@@ -192,12 +194,13 @@ export const db = new DataSource({
synchronize: process.env.NODE_ENV === 'test', synchronize: process.env.NODE_ENV === 'test',
dropSchema: process.env.NODE_ENV === 'test', dropSchema: process.env.NODE_ENV === 'test',
cache: !config.db.disableCache ? { cache: !config.db.disableCache ? {
type: 'redis', type: 'ioredis',
options: { options: {
host: config.redis.host, host: config.redis.host,
port: config.redis.port, port: config.redis.port,
family: config.redis.family == null ? 0 : config.redis.family,
password: config.redis.pass, password: config.redis.pass,
prefix: `${config.redis.prefix}:query:`, keyPrefix: `${config.redis.prefix}:query:`,
db: config.redis.db || 0, db: config.redis.db || 0,
}, },
} : false, } : false,
@@ -226,7 +229,7 @@ export async function initDb(force = false) {
export async function resetDb() { export async function resetDb() {
const reset = async () => { const reset = async () => {
await redisClient.FLUSHDB(); await redisClient.flushdb();
const tables = await db.query(`SELECT relname AS "table" const tables = await db.query(`SELECT relname AS "table"
FROM pg_class C LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace) FROM pg_class C LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace)
WHERE nspname NOT IN ('pg_catalog', 'information_schema') WHERE nspname NOT IN ('pg_catalog', 'information_schema')

View File

@@ -1,16 +1,15 @@
import * as redis from 'redis'; import Redis from 'ioredis';
import config from '@/config/index.js'; import config from '@/config/index.js';
export function createConnection() { export function createConnection() {
return redis.createClient( return new Redis({
config.redis.port, port: config.redis.port,
config.redis.host, host: config.redis.host,
{ family: config.redis.family == null ? 0 : config.redis.family,
password: config.redis.pass, password: config.redis.pass,
prefix: config.redis.prefix, keyPrefix: `${config.redis.prefix}:`,
db: config.redis.db || 0, db: config.redis.db || 0,
} });
);
} }
export const subsdcriber = createConnection(); export const subsdcriber = createConnection();

View File

@@ -1,8 +1,10 @@
import * as parse5 from 'parse5';
import treeAdapter from 'parse5/lib/tree-adapters/default.js';
import { URL } from 'node:url'; import { URL } from 'node:url';
import * as parse5 from 'parse5';
import * as TreeAdapter from '../../node_modules/parse5/dist/tree-adapters/default.js';
const urlRegex = /^https?:\/\/[\w\/:%#@$&?!()\[\]~.,=+\-]+/; const treeAdapter = TreeAdapter.defaultTreeAdapter;
const urlRegex = /^https?:\/\/[\w\/:%#@$&?!()\[\]~.,=+\-]+/;
const urlRegexFull = /^https?:\/\/[\w\/:%#@$&?!()\[\]~.,=+\-]+$/; const urlRegexFull = /^https?:\/\/[\w\/:%#@$&?!()\[\]~.,=+\-]+$/;
export function fromHtml(html: string, hashtagNames?: string[]): string { export function fromHtml(html: string, hashtagNames?: string[]): string {
@@ -19,7 +21,7 @@ export function fromHtml(html: string, hashtagNames?: string[]): string {
return text.trim(); return text.trim();
function getText(node: parse5.Node): string { function getText(node: TreeAdapter.Node): string {
if (treeAdapter.isTextNode(node)) return node.value; if (treeAdapter.isTextNode(node)) return node.value;
if (!treeAdapter.isElementNode(node)) return ''; if (!treeAdapter.isElementNode(node)) return '';
if (node.nodeName === 'br') return '\n'; if (node.nodeName === 'br') return '\n';
@@ -31,7 +33,7 @@ export function fromHtml(html: string, hashtagNames?: string[]): string {
return ''; return '';
} }
function appendChildren(childNodes: parse5.ChildNode[]): void { function appendChildren(childNodes: TreeAdapter.ChildNode[]): void {
if (childNodes) { if (childNodes) {
for (const n of childNodes) { for (const n of childNodes) {
analyze(n); analyze(n);
@@ -39,7 +41,7 @@ export function fromHtml(html: string, hashtagNames?: string[]): string {
} }
} }
function analyze(node: parse5.Node) { function analyze(node: TreeAdapter.Node) {
if (treeAdapter.isTextNode(node)) { if (treeAdapter.isTextNode(node)) {
text += node.value; text += node.value;
return; return;
@@ -170,7 +172,7 @@ export function fromHtml(html: string, hashtagNames?: string[]): string {
const t = getText(node); const t = getText(node);
if (t) { if (t) {
text += '\n> '; text += '\n> ';
text += t.split('\n').join(`\n> `); text += t.split('\n').join('\n> ');
} }
break; break;
} }

View File

@@ -16,11 +16,13 @@ export async function checkWordMute(note: NoteLike, me: UserLike | null | undefi
if (me && (note.userId === me.id)) return false; if (me && (note.userId === me.id)) return false;
if (mutedWords.length > 0) { if (mutedWords.length > 0) {
if (note.text == null) return false; const text = ((note.cw ?? '') + '\n' + (note.text ?? '')).trim();
if (text === '') return false;
const matched = mutedWords.some(filter => { const matched = mutedWords.some(filter => {
if (Array.isArray(filter)) { if (Array.isArray(filter)) {
return filter.every(keyword => note.text!.includes(keyword)); return filter.every(keyword => text.includes(keyword));
} else { } else {
// represents RegExp // represents RegExp
const regexp = filter.match(/^\/(.+)\/(.*)$/); const regexp = filter.match(/^\/(.+)\/(.*)$/);
@@ -29,7 +31,7 @@ export async function checkWordMute(note: NoteLike, me: UserLike | null | undefi
if (!regexp) return false; if (!regexp) return false;
try { try {
return new RE2(regexp[1], regexp[2]).test(note.text!); return new RE2(regexp[1], regexp[2]).test(text);
} catch (err) { } catch (err) {
// This should never happen due to input sanitisation. // This should never happen due to input sanitisation.
return false; return false;

View File

@@ -11,9 +11,14 @@ export function createTemp(): Promise<[string, () => void]> {
export function createTempDir(): Promise<[string, () => void]> { export function createTempDir(): Promise<[string, () => void]> {
return new Promise<[string, () => void]>((res, rej) => { return new Promise<[string, () => void]>((res, rej) => {
tmp.dir((e, path, cleanup) => { tmp.dir(
if (e) return rej(e); {
res([path, cleanup]); unsafeCleanup: true,
}); },
(e, path, cleanup) => {
if (e) return rej(e);
res([path, cleanup]);
}
);
}); });
} }

View File

@@ -7,28 +7,31 @@ import { WriteStream } from 'node:fs';
import * as p from 'pureimage'; import * as p from 'pureimage';
import gen from 'random-seed'; import gen from 'random-seed';
const size = 256; // px const size = 128; // px
const n = 5; // resolution const n = 5; // resolution
const margin = (size / n); const margin = (size / 4);
const colors = [ const colors = [
'#e57373', ['#FF512F', '#DD2476'],
'#F06292', ['#FF61D2', '#FE9090'],
'#BA68C8', ['#72FFB6', '#10D164'],
'#9575CD', ['#FD8451', '#FFBD6F'],
'#7986CB', ['#305170', '#6DFC6B'],
'#64B5F6', ['#00C0FF', '#4218B8'],
'#4FC3F7', ['#009245', '#FCEE21'],
'#4DD0E1', ['#0100EC', '#FB36F4'],
'#4DB6AC', ['#FDABDD', '#374A5A'],
'#81C784', ['#38A2D7', '#561139'],
'#8BC34A', ['#121C84', '#8278DA'],
'#AFB42B', ['#5761B2', '#1FC5A8'],
'#F57F17', ['#FFDB01', '#0E197D'],
'#FF5722', ['#FF3E9D', '#0E1F40'],
'#795548', ['#766eff', '#00d4ff'],
'#455A64', ['#9bff6e', '#00d4ff'],
['#ff6e94', '#00d4ff'],
['#ffa96e', '#00d4ff'],
['#ffa96e', '#ff009d'],
['#ffdd6e', '#ff009d'],
]; ];
const bg = '#e9e9e9';
const actualSize = size - (margin * 2); const actualSize = size - (margin * 2);
const cellSize = actualSize / n; const cellSize = actualSize / n;
@@ -42,11 +45,17 @@ export function genIdenticon(seed: string, stream: WriteStream): Promise<void> {
const canvas = p.make(size, size, undefined); const canvas = p.make(size, size, undefined);
const ctx = canvas.getContext('2d'); const ctx = canvas.getContext('2d');
const bgColors = colors[rand(colors.length)];
const bg = ctx.createLinearGradient(0, 0, size, size);
bg.addColorStop(0, bgColors[0]);
bg.addColorStop(1, bgColors[1]);
ctx.fillStyle = bg; ctx.fillStyle = bg;
ctx.beginPath(); ctx.beginPath();
ctx.fillRect(0, 0, size, size); ctx.fillRect(0, 0, size, size);
ctx.fillStyle = colors[rand(colors.length)]; ctx.fillStyle = '#ffffff';
// side bitmap (filled by false) // side bitmap (filled by false)
const side: boolean[][] = new Array(sideN); const side: boolean[][] = new Array(sideN);

View File

@@ -1,12 +1,18 @@
import * as fs from 'node:fs'; import * as fs from 'node:fs';
import * as crypto from 'node:crypto'; import * as crypto from 'node:crypto';
import { join } from 'node:path';
import * as stream from 'node:stream'; import * as stream from 'node:stream';
import * as util from 'node:util'; import * as util from 'node:util';
import { FSWatcher } from 'chokidar';
import { fileTypeFromFile } from 'file-type'; import { fileTypeFromFile } from 'file-type';
import FFmpeg from 'fluent-ffmpeg';
import isSvg from 'is-svg'; import isSvg from 'is-svg';
import probeImageSize from 'probe-image-size'; import probeImageSize from 'probe-image-size';
import { type predictionType } from 'nsfwjs';
import sharp from 'sharp'; import sharp from 'sharp';
import { encode } from 'blurhash'; import { encode } from 'blurhash';
import { detectSensitive } from '@/services/detect-sensitive.js';
import { createTempDir } from './create-temp.js';
const pipeline = util.promisify(stream.pipeline); const pipeline = util.promisify(stream.pipeline);
@@ -21,6 +27,8 @@ export type FileInfo = {
height?: number; height?: number;
orientation?: number; orientation?: number;
blurhash?: string; blurhash?: string;
sensitive: boolean;
porn: boolean;
warnings: string[]; warnings: string[];
}; };
@@ -37,7 +45,12 @@ const TYPE_SVG = {
/** /**
* Get file information * Get file information
*/ */
export async function getFileInfo(path: string): Promise<FileInfo> { export async function getFileInfo(path: string, opts: {
skipSensitiveDetection: boolean;
sensitiveThreshold?: number;
sensitiveThresholdForPorn?: number;
enableSensitiveMediaDetectionForVideos?: boolean;
}): Promise<FileInfo> {
const warnings = [] as string[]; const warnings = [] as string[];
const size = await getFileSize(path); const size = await getFileSize(path);
@@ -58,7 +71,7 @@ export async function getFileInfo(path: string): Promise<FileInfo> {
// うまく判定できない画像は octet-stream にする // うまく判定できない画像は octet-stream にする
if (!imageSize) { if (!imageSize) {
warnings.push(`cannot detect image dimensions`); warnings.push('cannot detect image dimensions');
type = TYPE_OCTET_STREAM; type = TYPE_OCTET_STREAM;
} else if (imageSize.wUnits === 'px') { } else if (imageSize.wUnits === 'px') {
width = imageSize.width; width = imageSize.width;
@@ -67,7 +80,7 @@ export async function getFileInfo(path: string): Promise<FileInfo> {
// 制限を超えている画像は octet-stream にする // 制限を超えている画像は octet-stream にする
if (imageSize.width > 16383 || imageSize.height > 16383) { if (imageSize.width > 16383 || imageSize.height > 16383) {
warnings.push(`image dimensions exceeds limits`); warnings.push('image dimensions exceeds limits');
type = TYPE_OCTET_STREAM; type = TYPE_OCTET_STREAM;
} }
} else { } else {
@@ -84,6 +97,19 @@ export async function getFileInfo(path: string): Promise<FileInfo> {
}); });
} }
let sensitive = false;
let porn = false;
if (!opts.skipSensitiveDetection) {
[sensitive, porn] = await detectSensitivity(
path,
type.mime,
opts.sensitiveThreshold ?? 0.5,
opts.sensitiveThresholdForPorn ?? 0.75,
opts.enableSensitiveMediaDetectionForVideos ?? false,
);
}
return { return {
size, size,
md5, md5,
@@ -92,10 +118,150 @@ export async function getFileInfo(path: string): Promise<FileInfo> {
height, height,
orientation, orientation,
blurhash, blurhash,
sensitive,
porn,
warnings, warnings,
}; };
} }
async function detectSensitivity(source: string, mime: string, sensitiveThreshold: number, sensitiveThresholdForPorn: number, analyzeVideo: boolean): Promise<[sensitive: boolean, porn: boolean]> {
let sensitive = false;
let porn = false;
function judgePrediction(result: readonly predictionType[]): [sensitive: boolean, porn: boolean] {
let sensitive = false;
let porn = false;
if ((result.find(x => x.className === 'Sexy')?.probability ?? 0) > sensitiveThreshold) sensitive = true;
if ((result.find(x => x.className === 'Hentai')?.probability ?? 0) > sensitiveThreshold) sensitive = true;
if ((result.find(x => x.className === 'Porn')?.probability ?? 0) > sensitiveThreshold) sensitive = true;
if ((result.find(x => x.className === 'Porn')?.probability ?? 0) > sensitiveThresholdForPorn) porn = true;
return [sensitive, porn];
}
if (['image/jpeg', 'image/png', 'image/webp'].includes(mime)) {
const result = await detectSensitive(source);
if (result) {
[sensitive, porn] = judgePrediction(result);
}
} else if (analyzeVideo && (mime === 'image/apng' || mime.startsWith('video/'))) {
const [outDir, disposeOutDir] = await createTempDir();
try {
const command = FFmpeg()
.input(source)
.inputOptions([
'-skip_frame', 'nokey', // 可能ならキーフレームのみを取得してほしいとする(そうなるとは限らない)
'-lowres', '3', // 元の画質でデコードする必要はないので 1/8 画質でデコードしてもよいとする(そうなるとは限らない)
])
.noAudio()
.videoFilters([
{
filter: 'select', // フレームのフィルタリング
options: {
e: 'eq(pict_type,PICT_TYPE_I)', // I-Frame のみをフィルタするVP9 とかはデコードしてみないとわからないっぽい)
},
},
{
filter: 'blackframe', // 暗いフレームの検出
options: {
amount: '0', // 暗さに関わらず全てのフレームで測定値を取る
},
},
{
filter: 'metadata',
options: {
mode: 'select', // フレーム選択モード
key: 'lavfi.blackframe.pblack', // フレームにおける暗部の百分率(前のフィルタからのメタデータを参照する)
value: '50',
function: 'less', // 50% 未満のフレームを選択する50% 以上暗部があるフレームだと誤検知を招くかもしれないので)
},
},
{
filter: 'scale',
options: {
w: 299,
h: 299,
},
},
])
.format('image2')
.output(join(outDir, '%d.png'))
.outputOptions(['-vsync', '0']); // 可変フレームレートにすることで穴埋めをさせない
const results: ReturnType<typeof judgePrediction>[] = [];
let frameIndex = 0;
let targetIndex = 0;
let nextIndex = 1;
for await (const path of asyncIterateFrames(outDir, command)) {
try {
const index = frameIndex++;
if (index !== targetIndex) {
continue;
}
targetIndex = nextIndex;
nextIndex += index; // fibonacci sequence によってフレーム数制限を掛ける
const result = await detectSensitive(path);
if (result) {
results.push(judgePrediction(result));
}
} finally {
fs.promises.unlink(path);
}
}
sensitive = results.filter(x => x[0]).length >= Math.ceil(results.length * sensitiveThreshold);
porn = results.filter(x => x[1]).length >= Math.ceil(results.length * sensitiveThresholdForPorn);
} finally {
disposeOutDir();
}
}
return [sensitive, porn];
}
async function* asyncIterateFrames(cwd: string, command: FFmpeg.FfmpegCommand): AsyncGenerator<string, void> {
const watcher = new FSWatcher({
cwd,
disableGlobbing: true,
});
let finished = false;
command.once('end', () => {
finished = true;
watcher.close();
});
command.run();
for (let i = 1; true; i++) { // eslint-disable-line @typescript-eslint/no-unnecessary-condition
const current = `${i}.png`;
const next = `${i + 1}.png`;
const framePath = join(cwd, current);
if (await exists(join(cwd, next))) {
yield framePath;
} else if (!finished) { // eslint-disable-line @typescript-eslint/no-unnecessary-condition
watcher.add(next);
await new Promise<void>((resolve, reject) => {
watcher.on('add', function onAdd(path) {
if (path === next) { // 次フレームの書き出しが始まっているなら、現在フレームの書き出しは終わっている
watcher.unwatch(current);
watcher.off('add', onAdd);
resolve();
}
});
command.once('end', resolve); // 全てのフレームを処理し終わったなら、最終フレームである現在フレームの書き出しは終わっている
command.once('error', reject);
});
yield framePath;
} else if (await exists(framePath)) {
yield framePath;
} else {
return;
}
}
}
function exists(path: string): Promise<boolean> {
return fs.promises.access(path).then(() => true, () => false);
}
/** /**
* Detect MIME Type and extension * Detect MIME Type and extension
*/ */

View File

@@ -1,15 +0,0 @@
export function isBlockerUserRelated(note: any, blockerUserIds: Set<string>): boolean {
if (blockerUserIds.has(note.userId)) {
return true;
}
if (note.reply != null && blockerUserIds.has(note.reply.userId)) {
return true;
}
if (note.renote != null && blockerUserIds.has(note.renote.userId)) {
return true;
}
return false;
}

View File

@@ -0,0 +1,8 @@
import { FILE_TYPE_BROWSERSAFE } from '@/const.js';
const dictionary = {
'safe-file': FILE_TYPE_BROWSERSAFE,
'sharp-convertible-image': ['image/jpeg', 'image/png', 'image/gif', 'image/apng', 'image/vnd.mozilla.apng', 'image/webp', 'image/svg+xml'],
};
export const isMimeImage = (mime: string, type: keyof typeof dictionary): boolean => dictionary[type].includes(mime);

View File

@@ -1,15 +0,0 @@
export function isMutedUserRelated(note: any, mutedUserIds: Set<string>): boolean {
if (mutedUserIds.has(note.userId)) {
return true;
}
if (note.reply != null && mutedUserIds.has(note.reply.userId)) {
return true;
}
if (note.renote != null && mutedUserIds.has(note.renote.userId)) {
return true;
}
return false;
}

View File

@@ -0,0 +1,15 @@
export function isUserRelated(note: any, userIds: Set<string>): boolean {
if (userIds.has(note.userId)) {
return true;
}
if (note.reply != null && userIds.has(note.reply.userId)) {
return true;
}
if (note.renote != null && userIds.has(note.renote.userId)) {
return true;
}
return false;
}

View File

@@ -1,7 +1,7 @@
import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm';
import { id } from '../id.js';
import { User } from './user.js'; import { User } from './user.js';
import { DriveFolder } from './drive-folder.js'; import { DriveFolder } from './drive-folder.js';
import { id } from '../id.js';
@Entity() @Entity()
@Index(['userId', 'folderId', 'id']) @Index(['userId', 'folderId', 'id'])
@@ -156,6 +156,19 @@ export class DriveFile {
}) })
public isSensitive: boolean; public isSensitive: boolean;
@Index()
@Column('boolean', {
default: false,
comment: 'Whether the DriveFile is NSFW. (predict)',
})
public maybeSensitive: boolean;
@Index()
@Column('boolean', {
default: false,
})
public maybePorn: boolean;
/** /**
* 外部の(信頼されていない)URLへの直リンクか否か * 外部の(信頼されていない)URLへの直リンクか否か
*/ */
@@ -165,4 +178,15 @@ export class DriveFile {
comment: 'Whether the DriveFile is direct link to remote server.', comment: 'Whether the DriveFile is direct link to remote server.',
}) })
public isLink: boolean; public isLink: boolean;
@Column('jsonb', {
default: {},
nullable: true,
})
public requestHeaders: Record<string, string> | null;
@Column('varchar', {
length: 128, nullable: true,
})
public requestIp: string | null;
} }

View File

@@ -1,6 +1,6 @@
import { Entity, Column, PrimaryColumn, ManyToOne, JoinColumn } from 'typeorm'; import { Entity, Column, PrimaryColumn, ManyToOne, JoinColumn } from 'typeorm';
import { User } from './user.js';
import { id } from '../id.js'; import { id } from '../id.js';
import { User } from './user.js';
import { Clip } from './clip.js'; import { Clip } from './clip.js';
@Entity() @Entity()
@@ -188,6 +188,28 @@ export class Meta {
}) })
public recaptchaSecretKey: string | null; public recaptchaSecretKey: string | null;
@Column('enum', {
enum: ['none', 'all', 'local', 'remote'],
default: 'none',
})
public sensitiveMediaDetection: 'none' | 'all' | 'local' | 'remote';
@Column('enum', {
enum: ['medium', 'low', 'high', 'veryLow', 'veryHigh'],
default: 'medium',
})
public sensitiveMediaDetectionSensitivity: 'medium' | 'low' | 'high' | 'veryLow' | 'veryHigh';
@Column('boolean', {
default: false,
})
public setSensitiveFlagAutomatically: boolean;
@Column('boolean', {
default: false,
})
public enableSensitiveMediaDetectionForVideos: boolean;
@Column('integer', { @Column('integer', {
default: 1024, default: 1024,
comment: 'Drive capacity of a local user (MB)', comment: 'Drive capacity of a local user (MB)',
@@ -427,4 +449,14 @@ export class Meta {
default: true, default: true,
}) })
public objectStorageS3ForcePathStyle: boolean; public objectStorageS3ForcePathStyle: boolean;
@Column('boolean', {
default: false,
})
public enableIpLogging: boolean;
@Column('boolean', {
default: true,
})
public enableActiveEmailValidation: boolean;
} }

View File

@@ -0,0 +1,24 @@
import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne, PrimaryGeneratedColumn } from 'typeorm';
import { id } from '../id.js';
import { Note } from './note.js';
import { User } from './user.js';
@Entity()
@Index(['userId', 'ip'], { unique: true })
export class UserIp {
@PrimaryGeneratedColumn()
public id: string;
@Column('timestamp with time zone', {
})
public createdAt: Date;
@Index()
@Column(id())
public userId: User['id'];
@Column('varchar', {
length: 128,
})
public ip: string;
}

View File

@@ -1,8 +1,8 @@
import { Entity, Column, Index, OneToOne, JoinColumn, PrimaryColumn } from 'typeorm'; import { Entity, Column, Index, OneToOne, JoinColumn, PrimaryColumn } from 'typeorm';
import { ffVisibility, notificationTypes } from '@/types.js';
import { id } from '../id.js'; import { id } from '../id.js';
import { User } from './user.js'; import { User } from './user.js';
import { Page } from './page.js'; import { Page } from './page.js';
import { ffVisibility, notificationTypes } from '@/types.js';
// TODO: このテーブルで管理している情報すべてレジストリで管理するようにしても良いかも // TODO: このテーブルで管理している情報すべてレジストリで管理するようにしても良いかも
// ただ、「emailVerified が true なユーザーを find する」のようなクエリは書けなくなるからウーン // ただ、「emailVerified が true なユーザーを find する」のようなクエリは書けなくなるからウーン
@@ -117,6 +117,11 @@ export class UserProfile {
}) })
public password: string | null; public password: string | null;
@Column('varchar', {
length: 8192, default: '',
})
public moderationNote: string | null;
// TODO: そのうち消す // TODO: そのうち消す
@Column('jsonb', { @Column('jsonb', {
default: {}, default: {},
@@ -147,6 +152,11 @@ export class UserProfile {
}) })
public alwaysMarkNsfw: boolean; public alwaysMarkNsfw: boolean;
@Column('boolean', {
default: false,
})
public autoSensitive: boolean;
@Column('boolean', { @Column('boolean', {
default: false, default: false,
}) })

View File

@@ -218,6 +218,12 @@ export class User {
}) })
public token: string | null; public token: string | null;
@Column('integer', {
nullable: true,
comment: 'Overrides user drive capacity limit',
})
public driveCapacityOverrideMb: number | null;
constructor(data: Partial<User>) { constructor(data: Partial<User>) {
if (data == null) return; if (data == null) return;

View File

@@ -65,6 +65,7 @@ import { PasswordResetRequest } from './entities/password-reset-request.js';
import { UserPending } from './entities/user-pending.js'; import { UserPending } from './entities/user-pending.js';
import { InstanceRepository } from './repositories/instance.js'; import { InstanceRepository } from './repositories/instance.js';
import { Webhook } from './entities/webhook.js'; import { Webhook } from './entities/webhook.js';
import { UserIp } from './entities/user-ip.js';
export const Announcements = db.getRepository(Announcement); export const Announcements = db.getRepository(Announcement);
export const AnnouncementReads = db.getRepository(AnnouncementRead); export const AnnouncementReads = db.getRepository(AnnouncementRead);
@@ -90,6 +91,7 @@ export const UserGroups = (UserGroupRepository);
export const UserGroupJoinings = db.getRepository(UserGroupJoining); export const UserGroupJoinings = db.getRepository(UserGroupJoining);
export const UserGroupInvitations = (UserGroupInvitationRepository); export const UserGroupInvitations = (UserGroupInvitationRepository);
export const UserNotePinings = db.getRepository(UserNotePining); export const UserNotePinings = db.getRepository(UserNotePining);
export const UserIps = db.getRepository(UserIp);
export const UsedUsernames = db.getRepository(UsedUsername); export const UsedUsernames = db.getRepository(UsedUsername);
export const Followings = (FollowingRepository); export const Followings = (FollowingRepository);
export const FollowRequests = (FollowRequestRepository); export const FollowRequests = (FollowRequestRepository);

View File

@@ -1,11 +1,13 @@
import { db } from '@/db/postgre.js'; import { db } from '@/db/postgre.js';
import { Instance } from '@/models/entities/instance.js'; import { Instance } from '@/models/entities/instance.js';
import { Packed } from '@/misc/schema.js'; import { Packed } from '@/misc/schema.js';
import { fetchMeta } from '@/misc/fetch-meta.js';
export const InstanceRepository = db.getRepository(Instance).extend({ export const InstanceRepository = db.getRepository(Instance).extend({
async pack( async pack(
instance: Instance, instance: Instance,
): Promise<Packed<'FederationInstance'>> { ): Promise<Packed<'FederationInstance'>> {
const meta = await fetchMeta();
return { return {
id: instance.id, id: instance.id,
caughtAt: instance.caughtAt.toISOString(), caughtAt: instance.caughtAt.toISOString(),
@@ -18,6 +20,7 @@ export const InstanceRepository = db.getRepository(Instance).extend({
lastCommunicatedAt: instance.lastCommunicatedAt.toISOString(), lastCommunicatedAt: instance.lastCommunicatedAt.toISOString(),
isNotResponding: instance.isNotResponding, isNotResponding: instance.isNotResponding,
isSuspended: instance.isSuspended, isSuspended: instance.isSuspended,
isBlocked: meta.blockedHosts.includes(instance.host),
softwareName: instance.softwareName, softwareName: instance.softwareName,
softwareVersion: instance.softwareVersion, softwareVersion: instance.softwareVersion,
openRegistrations: instance.openRegistrations, openRegistrations: instance.openRegistrations,
@@ -26,6 +29,8 @@ export const InstanceRepository = db.getRepository(Instance).extend({
maintainerName: instance.maintainerName, maintainerName: instance.maintainerName,
maintainerEmail: instance.maintainerEmail, maintainerEmail: instance.maintainerEmail,
iconUrl: instance.iconUrl, iconUrl: instance.iconUrl,
faviconUrl: instance.faviconUrl,
themeColor: instance.themeColor,
infoUpdatedAt: instance.infoUpdatedAt ? instance.infoUpdatedAt.toISOString() : null, infoUpdatedAt: instance.infoUpdatedAt ? instance.infoUpdatedAt.toISOString() : null,
}; };
}, },

View File

@@ -315,6 +315,7 @@ export const UserRepository = db.getRepository(User).extend({
} : undefined) : undefined, } : undefined) : undefined,
emojis: populateEmojis(user.emojis, user.host), emojis: populateEmojis(user.emojis, user.host),
onlineStatus: this.getOnlineStatus(user), onlineStatus: this.getOnlineStatus(user),
driveCapacityOverrideMb: user.driveCapacityOverrideMb,
...(opts.detail ? { ...(opts.detail ? {
url: profile!.url, url: profile!.url,
@@ -359,6 +360,7 @@ export const UserRepository = db.getRepository(User).extend({
injectFeaturedNote: profile!.injectFeaturedNote, injectFeaturedNote: profile!.injectFeaturedNote,
receiveAnnouncementEmail: profile!.receiveAnnouncementEmail, receiveAnnouncementEmail: profile!.receiveAnnouncementEmail,
alwaysMarkNsfw: profile!.alwaysMarkNsfw, alwaysMarkNsfw: profile!.alwaysMarkNsfw,
autoSensitive: profile!.autoSensitive,
carefulBot: profile!.carefulBot, carefulBot: profile!.carefulBot,
autoAcceptFollowed: profile!.autoAcceptFollowed, autoAcceptFollowed: profile!.autoAcceptFollowed,
noCrawle: profile!.noCrawle, noCrawle: profile!.noCrawle,

View File

@@ -52,6 +52,10 @@ export const packedFederationInstanceSchema = {
type: 'boolean', type: 'boolean',
optional: false, nullable: false, optional: false, nullable: false,
}, },
isBlocked: {
type: 'boolean',
optional: false, nullable: false,
},
softwareName: { softwareName: {
type: 'string', type: 'string',
optional: false, nullable: true, optional: false, nullable: true,
@@ -88,6 +92,15 @@ export const packedFederationInstanceSchema = {
optional: false, nullable: true, optional: false, nullable: true,
format: 'url', format: 'url',
}, },
faviconUrl: {
type: 'string',
optional: false, nullable: true,
format: 'url',
},
themeColor: {
type: 'string',
optional: false, nullable: true,
},
infoUpdatedAt: { infoUpdatedAt: {
type: 'string', type: 'string',
optional: false, nullable: true, optional: false, nullable: true,

View File

@@ -161,19 +161,19 @@ export const packedUserDetailedNotMeOnlySchema = {
type: 'array', type: 'array',
nullable: false, optional: false, nullable: false, optional: false,
items: { items: {
type: 'object', type: 'object',
nullable: false, optional: false, nullable: false, optional: false,
properties: { properties: {
name: { name: {
type: 'string', type: 'string',
nullable: false, optional: false, nullable: false, optional: false,
},
value: {
type: 'string',
nullable: false, optional: false,
},
}, },
maxLength: 4, value: {
type: 'string',
nullable: false, optional: false,
},
},
maxLength: 4,
}, },
}, },
followersCount: { followersCount: {
@@ -292,6 +292,10 @@ export const packedMeDetailedOnlySchema = {
type: 'boolean', type: 'boolean',
nullable: true, optional: false, nullable: true, optional: false,
}, },
autoSensitive: {
type: 'boolean',
nullable: true, optional: false,
},
carefulBot: { carefulBot: {
type: 'boolean', type: 'boolean',
nullable: true, optional: false, nullable: true, optional: false,

View File

@@ -2,6 +2,9 @@ import httpSignature from '@peertube/http-signature';
import { v4 as uuid } from 'uuid'; import { v4 as uuid } from 'uuid';
import config from '@/config/index.js'; import config from '@/config/index.js';
import { DriveFile } from '@/models/entities/drive-file.js';
import { IActivity } from '@/remote/activitypub/type.js';
import { Webhook, webhookEventTypes } from '@/models/entities/webhook.js';
import { envOption } from '../env.js'; import { envOption } from '../env.js';
import processDeliver from './processors/deliver.js'; import processDeliver from './processors/deliver.js';
@@ -12,18 +15,15 @@ import processSystemQueue from './processors/system/index.js';
import processWebhookDeliver from './processors/webhook-deliver.js'; import processWebhookDeliver from './processors/webhook-deliver.js';
import { endedPollNotification } from './processors/ended-poll-notification.js'; import { endedPollNotification } from './processors/ended-poll-notification.js';
import { queueLogger } from './logger.js'; import { queueLogger } from './logger.js';
import { DriveFile } from '@/models/entities/drive-file.js';
import { getJobInfo } from './get-job-info.js'; import { getJobInfo } from './get-job-info.js';
import { systemQueue, dbQueue, deliverQueue, inboxQueue, objectStorageQueue, endedPollNotificationQueue, webhookDeliverQueue } from './queues.js'; import { systemQueue, dbQueue, deliverQueue, inboxQueue, objectStorageQueue, endedPollNotificationQueue, webhookDeliverQueue } from './queues.js';
import { ThinUser } from './types.js'; import { ThinUser } from './types.js';
import { IActivity } from '@/remote/activitypub/type.js';
import { Webhook, webhookEventTypes } from '@/models/entities/webhook.js';
function renderError(e: Error): any { function renderError(e: Error): any {
return { return {
stack: e?.stack, stack: e.stack,
message: e?.message, message: e.message,
name: e?.name, name: e.name,
}; };
} }
@@ -314,6 +314,12 @@ export default function() {
removeOnComplete: true, removeOnComplete: true,
}); });
systemQueue.add('clean', {
}, {
repeat: { cron: '0 0 * * *' },
removeOnComplete: true,
});
systemQueue.add('checkExpiredMutings', { systemQueue.add('checkExpiredMutings', {
}, { }, {
repeat: { cron: '*/5 * * * *' }, repeat: { cron: '*/5 * * * *' },

View File

@@ -6,6 +6,7 @@ export function initialize<T>(name: string, limitPerSec = -1) {
redis: { redis: {
port: config.redis.port, port: config.redis.port,
host: config.redis.host, host: config.redis.host,
family: config.redis.family == null ? 0 : config.redis.family,
password: config.redis.pass, password: config.redis.pass,
db: config.redis.db || 0, db: config.redis.db || 0,
}, },

View File

@@ -0,0 +1,18 @@
import Bull from 'bull';
import { LessThan } from 'typeorm';
import { UserIps } from '@/models/index.js';
import { queueLogger } from '../../logger.js';
const logger = queueLogger.createSubLogger('clean');
export async function clean(job: Bull.Job<Record<string, unknown>>, done: any): Promise<void> {
logger.info('Cleaning...');
UserIps.delete({
createdAt: LessThan(new Date(Date.now() - (1000 * 60 * 60 * 24 * 90))),
});
logger.succ('Cleaned.');
done();
}

View File

@@ -3,12 +3,14 @@ import { tickCharts } from './tick-charts.js';
import { resyncCharts } from './resync-charts.js'; import { resyncCharts } from './resync-charts.js';
import { cleanCharts } from './clean-charts.js'; import { cleanCharts } from './clean-charts.js';
import { checkExpiredMutings } from './check-expired-mutings.js'; import { checkExpiredMutings } from './check-expired-mutings.js';
import { clean } from './clean.js';
const jobs = { const jobs = {
tickCharts, tickCharts,
resyncCharts, resyncCharts,
cleanCharts, cleanCharts,
checkExpiredMutings, checkExpiredMutings,
clean,
} as Record<string, Bull.ProcessCallbackFunction<Record<string, unknown>> | Bull.ProcessPromiseFunction<Record<string, unknown>>>; } as Record<string, Bull.ProcessCallbackFunction<Record<string, unknown>> | Bull.ProcessPromiseFunction<Record<string, unknown>>>;
export default function(dbQueue: Bull.Queue<Record<string, unknown>>) { export default function(dbQueue: Bull.Queue<Record<string, unknown>>) {

View File

@@ -200,7 +200,7 @@ export async function createNote(value: string | IObject, resolver?: Resolver, s
let text: string | null = null; let text: string | null = null;
if (note.source?.mediaType === 'text/x.misskeymarkdown' && typeof note.source?.content === 'string') { if (note.source?.mediaType === 'text/x.misskeymarkdown' && typeof note.source?.content === 'string') {
text = note.source.content; text = note.source.content;
} else if (typeof note._misskey_content === 'string') { } else if (typeof note._misskey_content !== 'undefined') {
text = note._misskey_content; text = note._misskey_content;
} else if (typeof note.content === 'string') { } else if (typeof note.content === 'string') {
text = htmlToMfm(note.content, note.tag); text = htmlToMfm(note.content, note.tag);

View File

@@ -82,15 +82,14 @@ export default async function renderNote(note: Note, dive = true, isTalk = false
const files = await getPromisedFiles(note.fileIds); const files = await getPromisedFiles(note.fileIds);
// text should never be undefined const text = note.text ?? '';
const text = note.text ?? null;
let poll: Poll | null = null; let poll: Poll | null = null;
if (note.hasPoll) { if (note.hasPoll) {
poll = await Polls.findOneBy({ noteId: note.id }); poll = await Polls.findOneBy({ noteId: note.id });
} }
let apText = text ?? ''; let apText = text;
if (quote) { if (quote) {
apText += `\n\nRE: ${quote}`; apText += `\n\nRE: ${quote}`;

View File

@@ -201,7 +201,7 @@ export interface IApMention extends IObject {
href: string; href: string;
} }
export const isMention = (object: IObject): object is IApMention=> export const isMention = (object: IObject): object is IApMention =>
getApType(object) === 'Mention' && getApType(object) === 'Mention' &&
typeof object.href === 'string'; typeof object.href === 'string';

View File

@@ -1,12 +1,25 @@
import Koa from 'koa'; import Koa from 'koa';
import { User } from '@/models/entities/user.js';
import { UserIps } from '@/models/index.js';
import { fetchMeta } from '@/misc/fetch-meta.js';
import { IEndpoint } from './endpoints.js'; import { IEndpoint } from './endpoints.js';
import authenticate, { AuthenticationError } from './authenticate.js'; import authenticate, { AuthenticationError } from './authenticate.js';
import call from './call.js'; import call from './call.js';
import { ApiError } from './error.js'; import { ApiError } from './error.js';
const userIpHistories = new Map<User['id'], Set<string>>();
setInterval(() => {
userIpHistories.clear();
}, 1000 * 60 * 60);
export default (endpoint: IEndpoint, ctx: Koa.Context) => new Promise<void>((res) => { export default (endpoint: IEndpoint, ctx: Koa.Context) => new Promise<void>((res) => {
const body = ctx.request.body; const body = ctx.is('multipart/form-data')
? (ctx.request as any).body
: ctx.method === 'GET'
? ctx.query
: ctx.request.body;
const reply = (x?: any, y?: ApiError) => { const reply = (x?: any, y?: ApiError) => {
if (x == null) { if (x == null) {
@@ -33,10 +46,38 @@ export default (endpoint: IEndpoint, ctx: Koa.Context) => new Promise<void>((res
authenticate(body['i']).then(([user, app]) => { authenticate(body['i']).then(([user, app]) => {
// API invoking // API invoking
call(endpoint.name, user, app, body, ctx).then((res: any) => { call(endpoint.name, user, app, body, ctx).then((res: any) => {
if (ctx.method === 'GET' && endpoint.meta.cacheSec && !body['i'] && !user) {
ctx.set('Cache-Control', `public, max-age=${endpoint.meta.cacheSec}`);
}
reply(res); reply(res);
}).catch((e: ApiError) => { }).catch((e: ApiError) => {
reply(e.httpStatusCode ? e.httpStatusCode : e.kind === 'client' ? 400 : 500, e); reply(e.httpStatusCode ? e.httpStatusCode : e.kind === 'client' ? 400 : 500, e);
}); });
// Log IP
if (user) {
fetchMeta().then(meta => {
if (!meta.enableIpLogging) return;
const ip = ctx.ip;
const ips = userIpHistories.get(user.id);
if (ips == null || !ips.has(ip)) {
if (ips == null) {
userIpHistories.set(user.id, new Set([ip]));
} else {
ips.add(ip);
}
try {
UserIps.insert({
createdAt: new Date(),
userId: user.id,
ip: ip,
});
} catch {
}
}
});
}
}).catch(e => { }).catch(e => {
if (e instanceof AuthenticationError) { if (e instanceof AuthenticationError) {
reply(403, new ApiError({ reply(403, new ApiError({

View File

@@ -1,12 +1,12 @@
import Koa from 'koa';
import { performance } from 'perf_hooks'; import { performance } from 'perf_hooks';
import { limiter } from './limiter.js'; import Koa from 'koa';
import { CacheableLocalUser, User } from '@/models/entities/user.js'; import { CacheableLocalUser, User } from '@/models/entities/user.js';
import { AccessToken } from '@/models/entities/access-token.js';
import { getIpHash } from '@/misc/get-ip-hash.js';
import { limiter } from './limiter.js';
import endpoints, { IEndpointMeta } from './endpoints.js'; import endpoints, { IEndpointMeta } from './endpoints.js';
import { ApiError } from './error.js'; import { ApiError } from './error.js';
import { apiLogger } from './logger.js'; import { apiLogger } from './logger.js';
import { AccessToken } from '@/models/entities/access-token.js';
import { getIpHash } from '@/misc/get-ip-hash.js';
const accessDenied = { const accessDenied = {
message: 'Access denied.', message: 'Access denied.',
@@ -33,7 +33,7 @@ export default async (endpoint: string, user: CacheableLocalUser | null | undefi
throw new ApiError(accessDenied); throw new ApiError(accessDenied);
} }
if (ep.meta.limit && !isModerator) { if (ep.meta.limit) {
// koa will automatically load the `X-Forwarded-For` header if `proxy: true` is configured in the app. // koa will automatically load the `X-Forwarded-For` header if `proxy: true` is configured in the app.
let limitActor: string; let limitActor: string;
if (user) { if (user) {
@@ -94,7 +94,7 @@ export default async (endpoint: string, user: CacheableLocalUser | null | undefi
} }
// Cast non JSON input // Cast non JSON input
if (ep.meta.requireFile && ep.params.properties) { if ((ep.meta.requireFile || ctx?.method === 'GET') && ep.params.properties) {
for (const k of Object.keys(ep.params.properties)) { for (const k of Object.keys(ep.params.properties)) {
const param = ep.params.properties![k]; const param = ep.params.properties![k];
if (['boolean', 'number', 'integer'].includes(param.type ?? '') && typeof data[k] === 'string') { if (['boolean', 'number', 'integer'].includes(param.type ?? '') && typeof data[k] === 'string') {
@@ -116,24 +116,24 @@ export default async (endpoint: string, user: CacheableLocalUser | null | undefi
// API invoking // API invoking
const before = performance.now(); const before = performance.now();
return await ep.exec(data, user, token, ctx?.file).catch((e: Error) => { return await ep.exec(data, user, token, ctx?.file, ctx?.ip, ctx?.headers).catch((e: Error) => {
if (e instanceof ApiError) { if (e instanceof ApiError) {
throw e; throw e;
} else { } else {
apiLogger.error(`Internal error occurred in ${ep.name}: ${e?.message}`, { apiLogger.error(`Internal error occurred in ${ep.name}: ${e.message}`, {
ep: ep.name, ep: ep.name,
ps: data, ps: data,
e: { e: {
message: e?.message, message: e.message,
code: e?.name, code: e.name,
stack: e?.stack, stack: e.stack,
}, },
}); });
throw new ApiError(null, { throw new ApiError(null, {
e: { e: {
message: e?.message, message: e.message,
code: e?.name, code: e.name,
stack: e?.stack, stack: e.stack,
}, },
}); });
} }

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