Compare commits

..

194 Commits

Author SHA1 Message Date
60e10d4efa 10.57.2 2018-11-24 17:31:08 +09:00
95ba7e43b1 Fix bug: リモートユーザーのアイコンとバナーの色が取得されていない問題を修正 2018-11-24 17:29:32 +09:00
9e5a2e5b17 Fix lint 2018-11-24 17:19:51 +09:00
dbbc416095 [MFM] Fix hashtag detection 2018-11-24 17:18:11 +09:00
a479ad357c Update dependency 🚀 2018-11-24 17:13:25 +09:00
b1c12abb7c Refactor 2018-11-24 17:10:12 +09:00
ba50156a83 10.57.1 2018-11-24 07:35:29 +09:00
eb83ab41c0 Revert "10.57.1"
This reverts commit 8c4f0d4589.
2018-11-24 07:34:51 +09:00
4e6a917dab Merge branch 'develop' of https://github.com/syuilo/misskey into develop 2018-11-24 07:34:23 +09:00
8c4f0d4589 10.57.1 2018-11-24 07:33:53 +09:00
3f7738204e Merge pull request #3391 from syuilo/l10n_develop
New Crowdin translations
2018-11-24 07:31:36 +09:00
e251a9b9fe New translations ja-JP.yml (English) 2018-11-24 07:22:10 +09:00
01d43b9683 New translations ja-JP.yml (Norwegian) 2018-11-24 07:13:03 +09:00
4d4a0c89a8 New translations ja-JP.yml (Dutch) 2018-11-24 07:12:58 +09:00
0a5524e9c8 New translations ja-JP.yml (Japanese, Kansai) 2018-11-24 07:12:53 +09:00
c8fb5746b3 New translations ja-JP.yml (Spanish) 2018-11-24 07:12:49 +09:00
bbcc132978 New translations ja-JP.yml (Russian) 2018-11-24 07:12:44 +09:00
d3e4f84285 New translations ja-JP.yml (Portuguese) 2018-11-24 07:12:38 +09:00
62c470cf75 New translations ja-JP.yml (Polish) 2018-11-24 07:12:34 +09:00
8ab31d3765 New translations ja-JP.yml (Korean) 2018-11-24 07:12:28 +09:00
55fe1cf0a8 New translations ja-JP.yml (Italian) 2018-11-24 07:12:23 +09:00
00cff51ff7 New translations ja-JP.yml (German) 2018-11-24 07:12:18 +09:00
d6bc4a7aa1 New translations ja-JP.yml (French) 2018-11-24 07:12:14 +09:00
4e57d12aea New translations ja-JP.yml (English) 2018-11-24 07:12:09 +09:00
4a2d99c43f New translations ja-JP.yml (Chinese Simplified) 2018-11-24 07:12:03 +09:00
217c27df86 New translations ja-JP.yml (Catalan) 2018-11-24 07:11:59 +09:00
e6dcd438b4 Update ja-JP.yml 2018-11-24 07:05:41 +09:00
de2b0224d6 Resolve #3158 2018-11-24 07:04:29 +09:00
3f8a72eb88 🎨 2018-11-24 07:03:03 +09:00
0387176e8c 🎨 2018-11-24 07:01:40 +09:00
aa34e332f4 Update reversi.room.vue 2018-11-24 07:01:12 +09:00
d13999d689 🎨 2018-11-24 06:56:30 +09:00
22c4e92728 Resolve #3389 2018-11-24 06:47:51 +09:00
df8128c0b1 Update url-preview.ts 2018-11-24 06:41:22 +09:00
ec534a3704 New translations ja-JP.yml (Korean) 2018-11-24 00:53:34 +09:00
366d4cd3e2 New translations ja-JP.yml (Korean) 2018-11-24 00:43:26 +09:00
4841926df1 Update README.md [AUTOGEN] (#3393) 2018-11-23 23:12:54 +09:00
f2f7bdc5a9 Do not use _replyIds (#3392) 2018-11-23 23:12:28 +09:00
fd811eb325 New translations ja-JP.yml (English) 2018-11-23 19:44:09 +09:00
915d352505 Resolve #3366 2018-11-23 16:39:51 +09:00
1d1024c57a [MFM] Improve hashtag detection
Resolve #3387
2018-11-23 16:02:17 +09:00
73df6e0347 Update manage.ja.md 2018-11-23 09:26:14 +09:00
e6d62c5a7b Update manage.en.md 2018-11-23 09:25:32 +09:00
470e48c0a5 Delete suspend.js 2018-11-23 09:24:00 +09:00
9235f72a2e Update manage.ja.md 2018-11-23 09:23:40 +09:00
9fe6da79b2 Update manage.en.md 2018-11-23 09:23:19 +09:00
1858437eb1 Delete reset-password.js 2018-11-23 09:22:45 +09:00
c3ba0dcd32 Update @types/systeminformation requirement from 3.23.0 to 3.23.1 (#3370)
Updates the requirements on [@types/systeminformation](https://github.com/DefinitelyTyped/DefinitelyTyped) to permit the latest version.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-11-23 09:12:36 +09:00
70f4b13089 Update @types/node requirement from 10.12.2 to 10.12.10 (#3369)
Updates the requirements on [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped) to permit the latest version.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-11-23 09:12:29 +09:00
cc57a4b671 Update @types/koa requirement from 2.0.46 to 2.0.47 (#3354)
Updates the requirements on [@types/koa](https://github.com/DefinitelyTyped/DefinitelyTyped) to permit the latest version.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-11-23 09:12:21 +09:00
6902700458 Update @types/redis requirement from 2.8.7 to 2.8.8 (#3353)
Updates the requirements on [@types/redis](https://github.com/DefinitelyTyped/DefinitelyTyped) to permit the latest version.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-11-23 09:12:13 +09:00
b772041547 Update @types/koa-router requirement from 7.0.33 to 7.0.35 (#3352)
Updates the requirements on [@types/koa-router](https://github.com/DefinitelyTyped/DefinitelyTyped) to permit the latest version.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-11-23 09:12:01 +09:00
79174c1a19 10.57.0 2018-11-23 08:20:12 +09:00
898850027a Merge pull request #3335 from syuilo/l10n_develop
New Crowdin translations
2018-11-23 08:19:32 +09:00
0d272b1fb0 Resolve #3376 2018-11-23 08:13:17 +09:00
7993a9eb90 New translations ja-JP.yml (English) 2018-11-23 08:12:53 +09:00
42d419970d New translations ja-JP.yml (Norwegian) 2018-11-23 08:05:03 +09:00
ad49268d8b New translations ja-JP.yml (Dutch) 2018-11-23 08:04:53 +09:00
76c345396a New translations ja-JP.yml (Japanese, Kansai) 2018-11-23 08:04:44 +09:00
5690ef1ebc New translations ja-JP.yml (Spanish) 2018-11-23 08:04:35 +09:00
5616404b4d New translations ja-JP.yml (Russian) 2018-11-23 08:04:31 +09:00
f92137f6c2 New translations ja-JP.yml (Portuguese) 2018-11-23 08:04:21 +09:00
ca3373ba4e New translations ja-JP.yml (Polish) 2018-11-23 08:04:12 +09:00
4e6115b414 New translations ja-JP.yml (Korean) 2018-11-23 08:04:03 +09:00
ddf47051c9 New translations ja-JP.yml (Italian) 2018-11-23 08:03:54 +09:00
d45478510c New translations ja-JP.yml (German) 2018-11-23 08:03:45 +09:00
2641f89349 New translations ja-JP.yml (French) 2018-11-23 08:03:35 +09:00
9d46d03c37 New translations ja-JP.yml (English) 2018-11-23 08:03:26 +09:00
25b6de88a9 New translations ja-JP.yml (Chinese Simplified) 2018-11-23 08:03:18 +09:00
a24046e46a New translations ja-JP.yml (Catalan) 2018-11-23 08:03:09 +09:00
7e803ff9a9 Merge branch 'develop' of https://github.com/syuilo/misskey into develop 2018-11-23 08:01:29 +09:00
246cead2b1 Improve user operations
Resolve #2197
Resolve #3367
2018-11-23 08:01:14 +09:00
214f7f06bb Update koa requirement from 2.6.1 to 2.6.2 (#3386)
Updates the requirements on [koa](https://github.com/koajs/koa) to permit the latest version.
- [Release notes](https://github.com/koajs/koa/releases)
- [Changelog](https://github.com/koajs/koa/blob/master/History.md)
- [Commits](https://github.com/koajs/koa/commits/2.6.2)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-11-23 06:06:03 +09:00
6878f73a9f Update ws requirement from 6.1.0 to 6.1.2 (#3385)
Updates the requirements on [ws](https://github.com/websockets/ws) to permit the latest version.
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/commits/6.1.2)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-11-23 05:23:05 +09:00
336b45b6f7 AP quote (#3384) 2018-11-23 02:10:07 +09:00
2a0b62d26d Fix #3343 (#3383)
Setting "X-Forwarded-Proto: https" in the SSL proxy is the correct way to do this
2018-11-23 02:09:04 +09:00
653ec0cbb0 No cache /notes/:note (#3382) 2018-11-22 23:17:58 +09:00
120ab3f0a3 New translations ja-JP.yml (French) 2018-11-22 18:53:16 +09:00
8bcbbbc1a3 New translations ja-JP.yml (English) 2018-11-22 09:22:41 +09:00
13a75abc91 Update systeminformation requirement from 3.47.0 to 3.49.3 (#3374)
Updates the requirements on [systeminformation](https://github.com/sebhildebrandt/systeminformation) to permit the latest version.
- [Release notes](https://github.com/sebhildebrandt/systeminformation/releases)
- [Changelog](https://github.com/sebhildebrandt/systeminformation/blob/master/CHANGELOG.md)
- [Commits](https://github.com/sebhildebrandt/systeminformation/commits)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-11-22 05:31:46 +09:00
eace740c63 Update emojilib requirement from 2.3.0 to 2.4.0 (#3375)
Updates the requirements on [emojilib](https://github.com/muan/emojilib) to permit the latest version.
- [Release notes](https://github.com/muan/emojilib/releases)
- [Commits](https://github.com/muan/emojilib/commits/v2.4.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-11-22 05:31:09 +09:00
cb3a54de00 Update apexcharts requirement from 2.2.2 to 2.2.3 (#3373)
Updates the requirements on [apexcharts](https://github.com/apexcharts/apexcharts.js) to permit the latest version.
- [Release notes](https://github.com/apexcharts/apexcharts.js/releases)
- [Changelog](https://github.com/apexcharts/apexcharts.js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/apexcharts/apexcharts.js/commits/v2.2.3)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-11-22 05:29:47 +09:00
5fbc77795d Update webpack requirement from 4.25.1 to 4.26.0 (#3371)
Updates the requirements on [webpack](https://github.com/webpack/webpack) to permit the latest version.
- [Release notes](https://github.com/webpack/webpack/releases)
- [Commits](https://github.com/webpack/webpack/commits/v4.26.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-11-22 05:29:02 +09:00
ce4feae731 Update vue-i18n requirement from 8.3.1 to 8.3.2 (#3372)
Updates the requirements on [vue-i18n](https://github.com/kazupon/vue-i18n) to permit the latest version.
- [Release notes](https://github.com/kazupon/vue-i18n/releases)
- [Changelog](https://github.com/kazupon/vue-i18n/blob/dev/CHANGELOG.md)
- [Commits](https://github.com/kazupon/vue-i18n/commits/v8.3.2)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-11-22 05:28:39 +09:00
08f00d4990 Remove unneccesary cast (#3355) 2018-11-22 05:07:25 +09:00
6951f7e74a Fix #3361 (#3362)
* Update create.ts

* Update api.ts
2018-11-22 05:06:51 +09:00
2b4d63b1bb Add some tests 2018-11-22 05:04:45 +09:00
8cbb961493 [MFM] Improve URL parsing
Fix #3368
2018-11-22 05:02:38 +09:00
64c795938d New translations ja-JP.yml (French) 2018-11-22 02:03:40 +09:00
67df681a48 Refactoring 2018-11-22 01:51:26 +09:00
9285bcf8bb New translations ja-JP.yml (Norwegian) 2018-11-21 23:55:53 +09:00
b9b23a4b54 New translations ja-JP.yml (Dutch) 2018-11-21 23:55:48 +09:00
2f6371b085 New translations ja-JP.yml (Japanese, Kansai) 2018-11-21 23:55:38 +09:00
2a5c3475a7 New translations ja-JP.yml (Spanish) 2018-11-21 23:55:29 +09:00
8a2698a5db New translations ja-JP.yml (Russian) 2018-11-21 23:55:19 +09:00
f6919a171a New translations ja-JP.yml (Portuguese) 2018-11-21 23:55:09 +09:00
82ebf67456 New translations ja-JP.yml (Polish) 2018-11-21 23:55:02 +09:00
a60c8b2ee8 New translations ja-JP.yml (Korean) 2018-11-21 23:54:58 +09:00
0a2b8ccfb6 New translations ja-JP.yml (Italian) 2018-11-21 23:54:53 +09:00
698094b787 New translations ja-JP.yml (German) 2018-11-21 23:54:48 +09:00
b57e111ea8 New translations ja-JP.yml (French) 2018-11-21 23:54:41 +09:00
aa6bf2b54e New translations ja-JP.yml (English) 2018-11-21 23:54:31 +09:00
454910d295 New translations ja-JP.yml (Chinese Simplified) 2018-11-21 23:54:21 +09:00
d44e620769 New translations ja-JP.yml (Catalan) 2018-11-21 23:54:12 +09:00
ac14adfd3e Feature / user recommendation config in admin ui (#3357)
* add config for external user recommendation into admin ui

* debug

* correct admin ui

* switch external user recommendation to admin ui config

* debug

* debug

* debug

* Revert "debug"

This reverts commit f4a0460e5bde21cd1f39a735f496a2d74233ef3f.

* explicit parseInt radix

* add Japanese message

* change default engine to https

* remove unused settings

* debug

* nullable externalUserRecommendationTimeout
2018-11-21 23:44:59 +09:00
928d30ee1e New translations ja-JP.yml (Norwegian) 2018-11-21 14:53:16 +09:00
3dd9b0f347 New translations ja-JP.yml (Dutch) 2018-11-21 14:53:10 +09:00
c57dd083c5 New translations ja-JP.yml (Japanese, Kansai) 2018-11-21 14:53:06 +09:00
2a1d6c5406 New translations ja-JP.yml (Spanish) 2018-11-21 14:52:59 +09:00
112e9f69bd New translations ja-JP.yml (Russian) 2018-11-21 14:52:55 +09:00
d50e537888 New translations ja-JP.yml (Portuguese) 2018-11-21 14:52:50 +09:00
86d14d30fa New translations ja-JP.yml (Polish) 2018-11-21 14:52:46 +09:00
710d3689d3 New translations ja-JP.yml (Korean) 2018-11-21 14:52:39 +09:00
3fee011369 New translations ja-JP.yml (Italian) 2018-11-21 14:52:33 +09:00
7cd4b8ba4f New translations ja-JP.yml (German) 2018-11-21 14:52:28 +09:00
31132de18b New translations ja-JP.yml (French) 2018-11-21 14:52:23 +09:00
c6cb271f6f New translations ja-JP.yml (English) 2018-11-21 14:52:18 +09:00
b7c4afd20c New translations ja-JP.yml (Chinese Simplified) 2018-11-21 14:52:14 +09:00
70395d200a New translations ja-JP.yml (Catalan) 2018-11-21 14:52:07 +09:00
562a5f66fc Improve usability 2018-11-21 14:44:49 +09:00
b2f8003602 [MFM] Better inline code parse 2018-11-21 12:55:15 +09:00
b7b36973f7 Fix: stop in DB check (#3356) 2018-11-21 12:45:40 +09:00
f7d5f597f3 10.56.2 2018-11-21 08:33:02 +09:00
79c7712241 Improve MFM 2018-11-21 08:32:40 +09:00
8f5f3985f4 [MFM] Fix hashtag parsing 2018-11-21 08:30:29 +09:00
ef30f36f55 10.56.1 2018-11-21 06:27:11 +09:00
4198497237 Improve test page 2018-11-21 06:25:58 +09:00
9b1612574e [Client] Fix #3114 2018-11-21 06:24:46 +09:00
ca8a218144 10.56.0 2018-11-21 05:47:40 +09:00
db9c2913cf Update index.vue 2018-11-21 05:36:55 +09:00
286674c2bb Fix bug 2018-11-21 05:27:06 +09:00
7c259185bc Fix bug 2018-11-21 05:26:48 +09:00
79ffbf95db Improve MFM parser (#3337)
* wip

* wip

* Refactor

* Refactor

* wip

* wip

* wip

* wip

* Refactor

* Refactor

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* Clean up

* Update misskey-flavored-markdown.ts

* wip

* wip

* wip

* wip

* Update parser.ts

* wip

* Add new test

* wip

* Add new test

* Add new test

* wip

* Refactor

* Update parse.ts

* Refactor

* Update parser.ts

* wip
2018-11-21 05:11:00 +09:00
6e347e4221 Refactor checkMongoDb (#3339) 2018-11-20 21:19:14 +09:00
28ccb14166 Create backup.fr.md (#3342)
* Create backup.fr.md

Create backup.fr.md

* Fix typo

Fix typo
2018-11-20 21:18:39 +09:00
389315e000 Fix: ap/show (#3350) 2018-11-20 21:18:14 +09:00
af00464f5b New translations ja-JP.yml (French) 2018-11-20 17:38:45 +09:00
f522b3df91 New translations ja-JP.yml (French) 2018-11-20 17:22:49 +09:00
168db6891f Refactor spawnWorkers (#3338) 2018-11-20 12:25:58 +09:00
4a77548672 Refactor port checking (#3336) 2018-11-20 11:23:32 +09:00
e9ec4a3b84 New translations ja-JP.yml (English) 2018-11-20 06:51:54 +09:00
375b2bb284 Merge pull request #3324 from syuilo/l10n_develop
New Crowdin translations
2018-11-20 05:35:03 +09:00
b922277896 Update typescript-eslint-parser requirement from 21.0.0 to 21.0.1 (#3333)
Updates the requirements on [typescript-eslint-parser](https://github.com/eslint/typescript-eslint-parser) to permit the latest version.
- [Release notes](https://github.com/eslint/typescript-eslint-parser/releases)
- [Changelog](https://github.com/eslint/typescript-eslint-parser/blob/master/CHANGELOG.md)
- [Commits](https://github.com/eslint/typescript-eslint-parser/commits/v21.0.1)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-11-20 05:34:40 +09:00
8f6f810dbd Update apexcharts requirement from 2.2.0 to 2.2.2 (#3334)
Updates the requirements on [apexcharts](https://github.com/apexcharts/apexcharts.js) to permit the latest version.
- [Release notes](https://github.com/apexcharts/apexcharts.js/releases)
- [Changelog](https://github.com/apexcharts/apexcharts.js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/apexcharts/apexcharts.js/commits/v2.2.2)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-11-20 05:34:18 +09:00
8f0c433e05 Cores => Logical cores (#3332) 2018-11-20 05:30:22 +09:00
e332e3c248 Explicitly set max-age (#3330) 2018-11-20 05:29:51 +09:00
2f90c38604 New translations ja-JP.yml (German) 2018-11-20 01:12:33 +09:00
fa33d12bd7 New translations ja-JP.yml (German) 2018-11-20 00:16:06 +09:00
86ab496fd6 New translations ja-JP.yml (Chinese Simplified) 2018-11-19 23:54:55 +09:00
ca0cb6fd42 Merge environmentInfo and machineInfo into index.ts (#3319) 2018-11-19 13:39:10 +09:00
be52779bbc Use descriptive variables to improve readability (#3318) 2018-11-19 13:27:38 +09:00
23b64794a4 Call main at the end (#3317) 2018-11-19 12:58:58 +09:00
d5fed29df3 Merge pull request #3311 from syuilo/l10n_develop
New Crowdin translations
2018-11-19 09:18:45 +09:00
644bc985e7 Fix some image processing (#3313)
* Improve thunmbnail generation

* Respect orientation in Firefox
2018-11-19 09:17:16 +09:00
5c1dc31131 New translations ja-JP.yml (English) 2018-11-19 02:31:46 +09:00
31fae1caa6 New translations ja-JP.yml (French) 2018-11-19 02:22:05 +09:00
9bc85ac511 New translations ja-JP.yml (Norwegian) 2018-11-19 02:13:15 +09:00
69d6dc22b9 New translations ja-JP.yml (Dutch) 2018-11-19 02:13:10 +09:00
c4f81fc1a7 New translations ja-JP.yml (Japanese, Kansai) 2018-11-19 02:13:06 +09:00
9a866766e0 New translations ja-JP.yml (Spanish) 2018-11-19 02:13:02 +09:00
eb7153acee New translations ja-JP.yml (Russian) 2018-11-19 02:12:57 +09:00
f3d98da329 New translations ja-JP.yml (Portuguese) 2018-11-19 02:12:51 +09:00
aac1c50a77 New translations ja-JP.yml (Polish) 2018-11-19 02:12:47 +09:00
0619a27916 New translations ja-JP.yml (Korean) 2018-11-19 02:12:43 +09:00
49ba56493f New translations ja-JP.yml (Italian) 2018-11-19 02:12:38 +09:00
bf0dae8cc3 New translations ja-JP.yml (German) 2018-11-19 02:12:33 +09:00
fbf77afde1 New translations ja-JP.yml (French) 2018-11-19 02:12:27 +09:00
5159caa9ff New translations ja-JP.yml (English) 2018-11-19 02:12:21 +09:00
5aef35f0b7 New translations ja-JP.yml (Chinese Simplified) 2018-11-19 02:12:16 +09:00
4db2843e7b New translations ja-JP.yml (Catalan) 2018-11-19 02:12:10 +09:00
a390e57dff [Client] Improve UI 2018-11-19 02:09:27 +09:00
8d70587814 Refactoring 2018-11-19 02:04:12 +09:00
6f3775de9d New translations ja-JP.yml (French) 2018-11-19 02:01:57 +09:00
5a0a3050ae New translations ja-JP.yml (French) 2018-11-19 01:53:15 +09:00
cbbf141846 New translations ja-JP.yml (French) 2018-11-19 01:42:15 +09:00
43c2b00cf8 Show visibility in note-detail (#3308)
* Show visibility in note-detail

* fix
2018-11-18 22:47:21 +09:00
046ccd49ca Merge pull request #3305 from syuilo/l10n_develop
New Crowdin translations
2018-11-18 22:46:28 +09:00
e7df6f5c0e New translations ja-JP.yml (English) 2018-11-18 21:31:51 +09:00
c67110835c New translations ja-JP.yml (Chinese Simplified) 2018-11-18 15:11:49 +09:00
4c97b847e7 10.55.0 2018-11-18 12:00:07 +09:00
cfa4f0fe0b Add zh-CN 2018-11-18 11:59:26 +09:00
9672343360 New Crowdin translations (#3255)
* New translations ja-JP.yml (Catalan)

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

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Italian)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Polish)

* New translations ja-JP.yml (Portuguese)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Spanish)

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

* New translations ja-JP.yml (Dutch)

* New translations ja-JP.yml (Norwegian)

* New translations ja-JP.yml (Catalan)

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

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Italian)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Polish)

* New translations ja-JP.yml (Portuguese)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Spanish)

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

* New translations ja-JP.yml (Dutch)

* New translations ja-JP.yml (Norwegian)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (Catalan)

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

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Italian)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Polish)

* New translations ja-JP.yml (Portuguese)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Spanish)

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

* New translations ja-JP.yml (Dutch)

* New translations ja-JP.yml (Norwegian)

* New translations ja-JP.yml (Catalan)

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

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Italian)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Polish)

* New translations ja-JP.yml (Portuguese)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Spanish)

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

* New translations ja-JP.yml (Dutch)

* New translations ja-JP.yml (Norwegian)

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

* New translations ja-JP.yml (Norwegian)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (Catalan)

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

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Italian)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Polish)

* New translations ja-JP.yml (Portuguese)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Spanish)

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

* New translations ja-JP.yml (Dutch)

* New translations ja-JP.yml (Norwegian)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (French)

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

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

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

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

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

* New translations ja-JP.yml (Catalan)

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

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Italian)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Polish)

* New translations ja-JP.yml (Portuguese)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Spanish)

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

* New translations ja-JP.yml (Dutch)

* New translations ja-JP.yml (Norwegian)

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

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

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

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

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

* New translations ja-JP.yml (Italian)

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

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

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

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

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

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

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

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

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

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

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

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

* New translations ja-JP.yml (French)

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

* New translations ja-JP.yml (French)

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

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

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

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

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

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Chinese Simplified)
2018-11-18 10:56:51 +09:00
80fdfe54c4 Add faUserClock icon for follow requests (#3303) 2018-11-18 01:10:57 +09:00
7fcbe87591 Improve relative time detection (#3302) 2018-11-17 20:57:23 +09:00
e401ba9e25 Update visibility text (#3299) 2018-11-17 18:21:05 +09:00
35db61f1b4 To able to store local only visibilities (#3298) 2018-11-17 13:21:40 +09:00
6c72545fc8 [Test] Add a test and some updtes 2018-11-17 12:52:20 +09:00
70385ca670 Update @types/webpack requirement from 4.4.18 to 4.4.19 (#3295)
Updates the requirements on [@types/webpack](https://github.com/DefinitelyTyped/DefinitelyTyped) to permit the latest version.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-11-17 05:30:30 +09:00
a8e72d39f7 Update vue-svg-inline-loader requirement from 1.2.1 to 1.2.2 (#3294)
Updates the requirements on [vue-svg-inline-loader](https://github.com/oliverfindl/vue-svg-inline-loader) to permit the latest version.
- [Release notes](https://github.com/oliverfindl/vue-svg-inline-loader/releases)
- [Commits](https://github.com/oliverfindl/vue-svg-inline-loader/commits/v1.2.2)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-11-17 05:30:18 +09:00
0bf54b3ff6 Renote visibility (#3290) 2018-11-17 03:25:48 +09:00
db657c2a62 Hide unused login method (#3285) 2018-11-17 02:13:01 +09:00
01964f3926 Add missing Robot icon (used on user profiles) (#3284) 2018-11-17 01:55:37 +09:00
bfd6bb0fda Add missing Map Marker icon (used on user profiles) (#3283) 2018-11-17 01:50:39 +09:00
3fc70996e2 Change math syntax (#3280) 2018-11-17 00:31:49 +09:00
132 changed files with 4114 additions and 3084 deletions

View File

@ -118,12 +118,3 @@ autoAdmin: true
# Clustering
#clusterLimit: 1
# Summaly proxy
#summalyProxy: "http://example.com"
# User recommendation
#user_recommendation:
# external: true
# engine: http://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-misskey-api.cgi?{{host}}+{{user}}+{{limit}}+{{offset}}
# timeout: 300000

View File

@ -96,7 +96,6 @@ Please see [Contribution guide](./CONTRIBUTING.md).
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/4503830/ccf2cc867ea64de0b524bb2e24b9a1cb/1?token-time=2145916800&token-hash=S1zP0QyLU52Dqq6dtc9qNYyWfW86XrYHiR4NMbeOrnA%3D" alt="dansup"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/619786/32cf01444db24e578cd1982c197f6fc6/1?token-time=2145916800&token-hash=tB1e_r8RlZ5sFL0KV_e8dugapxatNBRK1Z3h67TO1g8%3D" alt="Gargron"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/5731881/4b6038e6cda34c04b83a5fcce3806a93/1?token-time=2145916800&token-hash=VZUtwrjQa8Jml4twCjHYQQZ64wHEY4oIlGl7Kc-VYUQ%3D" alt="Nokotaro Takeda"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12531784/93a45137841849329ba692da92ac7c60/1?token-time=2145916800&token-hash=tMosUojzUYJCH_3t--tvYA-SMCyrS__hzSndyaRSnbo%3D" alt="Takashi Shibuya"></td>
</tr><tr>
<td><a href="https://www.patreon.com/user?u=13039004">nemu</a></td>
<td><a href="https://www.patreon.com/yukimochi">YUKIMOCHI</a></td>
@ -106,13 +105,14 @@ Please see [Contribution guide](./CONTRIBUTING.md).
<td><a href="https://www.patreon.com/dansup">dansup</a></td>
<td><a href="https://www.patreon.com/mastodon">Gargron</a></td>
<td><a href="https://www.patreon.com/takenoko">Nokotaro Takeda</a></td>
<td><a href="https://www.patreon.com/user?u=12531784">Takashi Shibuya</a></td>
</tr></table>
<table><tr>
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12531784/93a45137841849329ba692da92ac7c60/1?token-time=2145916800&token-hash=tMosUojzUYJCH_3t--tvYA-SMCyrS__hzSndyaRSnbo%3D" alt="Takashi Shibuya"></td>
</tr><tr>
<td><a href="https://www.patreon.com/user?u=12531784">Takashi Shibuya</a></td>
</tr></table>
**Last updated:** Wed, 31 Oct 2018 23:21:06 UTC
**Last updated:** Fri, 23 Nov 2018 14:09:04 UTC
<!-- PATREON_END -->
:four_leaf_clover: Copyright

View File

@ -1,29 +0,0 @@
const mongo = require('mongodb');
const bcrypt = require('bcryptjs');
const User = require('../built/models/user').default;
const args = process.argv.slice(2);
const user = args[0];
const q = user.startsWith('@') ? {
username: user.split('@')[1],
host: user.split('@')[2] || null
} : { _id: new mongo.ObjectID(user) };
console.log(`Resetting password for ${user}...`);
const passwd = 'yo';
// Generate hash of password
const hash = bcrypt.hashSync(passwd);
User.update(q, {
$set: {
password: hash
}
}).then(() => {
console.log(`Password of ${user} is now '${passwd}'`);
}, e => {
console.error(e);
});

View File

@ -1,23 +0,0 @@
const mongo = require('mongodb');
const User = require('../built/models/user').default;
const args = process.argv.slice(2);
const user = args[0];
const q = user.startsWith('@') ? {
username: user.split('@')[1],
host: user.split('@')[2] || null
} : { _id: new mongo.ObjectID(user) };
console.log(`Suspending ${user}...`);
User.update(q, {
$set: {
isSuspended: true
}
}).then(() => {
console.log(`Suspended ${user}`);
}, e => {
console.error(e);
});

22
docs/backup.fr.md Normal file
View File

@ -0,0 +1,22 @@
Comment faire une sauvegarde de votre Misskey ?
==========================
Assurez-vous d'avoir installé **mongodb-tools**.
---
Dans votre terminal :
``` shell
$ mongodump --archive=db-backup -u <VotreNomdUtilisateur> -p <VotreMotDePasse>
```
Pour plus de détails, merci de consulter [la documentation de mongodump](https://docs.mongodb.com/manual/reference/program/mongodump/).
Restauration
-------
``` shell
$ mongorestore --archive=db-backup
```
Pour plus de détails, merci de consulter [la documentation de mongorestore](https://docs.mongodb.com/manual/reference/program/mongorestore/).

View File

@ -10,7 +10,7 @@ In your shell:
$ mongodump --archive=db-backup -u <YourUserName> -p <YourPassword>
```
For details, plese see [mongodump docs](https://docs.mongodb.com/manual/reference/program/mongodump/).
For details, please see [mongodump docs](https://docs.mongodb.com/manual/reference/program/mongodump/).
Restore
-------

View File

@ -8,28 +8,11 @@ coming soon
node cli/mark-admin (User-ID or Username)
```
## Mark as 'verified' user
``` shell
node cli/mark-verified (User-ID or Username)
```
## Suspend users
``` shell
node cli/suspend (User-ID or Username)
```
e.g.
``` shell
# Use id
node cli/suspend 57d01a501fdf2d07be417afe
# By id
node cli/mark-admin 57d01a501fdf2d07be417afe
# Use username
# By username
node cli/suspend @syuilo
# Use username (remote)
node cli/suspend @syuilo@misskey.xyz
```
## Reset password
``` shell
node cli/reset-password (User-ID or Username)
```

View File

@ -8,28 +8,11 @@ coming soon
node cli/mark-admin (ユーザーID または ユーザー名)
```
## 'verified'ユーザーを設定する
``` shell
node cli/mark-verified (ユーザーID または ユーザー名)
```
## ユーザーを凍結する
``` shell
node cli/suspend (ユーザーID または ユーザー名)
```
例:
``` shell
# ユーザーID
node cli/suspend 57d01a501fdf2d07be417afe
node cli/mark-admin 57d01a501fdf2d07be417afe
# ユーザー名
node cli/suspend @syuilo
# ユーザー名 (リモート)
node cli/suspend @syuilo@misskey.xyz
```
## ユーザーのパスワードをリセットする
``` shell
node cli/reset-password (ユーザーID または ユーザー名)
node cli/mark-admin @syuilo
```

View File

@ -90,6 +90,9 @@ common:
specified: "ダイレクト"
specified-desc: "指定したユーザーにのみ公開"
private: "非公開"
local-public: "公開 (ローカルのみ)"
local-home: "ホーム (ローカルのみ)"
local-followers: "フォロワー (ローカルのみ)"
note-placeholders:
a: "今どうしてる?"
b: "何かありましたか?"
@ -120,6 +123,7 @@ common:
is-remote-user: "このユーザー情報はコピーです。"
is-remote-post: "この投稿情報はコピーです。"
view-on-remote: "正確な情報を見る"
renoted-by: "{user}がRenote"
error:
title: '問題が発生しました'
retry: 'やり直す'
@ -427,6 +431,10 @@ common/views/components/visibility-chooser.vue:
specified: "ダイレクト"
specified-desc: "指定したユーザーにのみ公開"
private: "非公開"
local-public: "公開 (ローカルのみ)"
local-public-desc: "リモートへは公開しない"
local-home: "ホーム (ローカルのみ)"
local-followers: "フォロワー (ローカルのみ)"
common/views/components/trends.vue:
count: "{}人が投稿"
empty: "トレンドなし"
@ -636,12 +644,10 @@ desktop/views/components/messaging-window.vue:
desktop/views/components/note-detail.vue:
private: "この投稿は非公開です"
deleted: "この投稿は削除されました"
reposted-by: "{}がRenote"
location: "位置情報"
renote: "Renote"
add-reaction: "リアクション"
desktop/views/components/note.vue:
reposted-by: "{}がRenote"
reply: "返信"
renote: "Renote"
add-reaction: "リアクション"
@ -676,6 +682,7 @@ desktop/views/components/post-form.vue:
create-poll: "アンケートを作成"
text-remain: "残り{}文字"
recent-tags: "最近"
local-only-message: "この投稿はローカルにのみ公開されます"
click-to-tagging: "クリックでタグ付け"
visibility: "公開範囲"
geolocation-alert: "お使いの端末は位置情報に対応していません"
@ -693,6 +700,7 @@ desktop/views/components/renote-form.vue:
quote: "引用する..."
cancel: "キャンセル"
renote: "Renote"
renote-home: "Renote (Home)"
reposting: "しています..."
success: "Renoteしました"
failure: "Renoteに失敗しました"
@ -707,6 +715,7 @@ desktop/views/components/settings.vue:
profile: "プロフィール"
notification: "通知"
apps: "アプリ"
tags: "ハッシュタグ"
mute-and-block: "ミュート/ブロック"
blocking: "ブロック"
security: "セキュリティ"
@ -749,6 +758,7 @@ desktop/views/components/settings.vue:
show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する"
show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する"
show-maps: "マップの自動展開"
remain-deleted-note: "削除された投稿を表示し続ける"
deck-column-align: "デッキのカラムの位置"
deck-column-align-center: "中央"
deck-column-align-left: "左"
@ -921,7 +931,7 @@ admin/views/index.vue:
emoji: "カスタム絵文字"
moderators: "モデレーター"
users: "ユーザー"
update: "更新"
federation: "連合"
announcements: "お知らせ"
hashtags: "ハッシュタグ"
back-to-misskey: "Misskeyに戻る"
@ -981,6 +991,12 @@ admin/views/instance.vue:
invite: "招待"
save: "保存"
saved: "保存しました"
user-recommendation-config: "おすすめユーザー"
enable-external-user-recommendation: "外部ユーザーレコメンデーションを有効にする"
external-user-recommendation-engine: "エンジン"
external-user-recommendation-engine-desc: "例: https://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-misskey-api.cgi?{{host}}+{{user}}+{{limit}}+{{offset}}"
external-user-recommendation-timeout: "タイムアウト"
external-user-recommendation-timeout-desc: "ミリ秒単位 (例: 300000)"
admin/views/charts.vue:
title: "チャート"
per-day: "1日ごと"
@ -1007,18 +1023,35 @@ admin/views/charts.vue:
network-time: "応答時間"
network-usage: "通信量"
admin/views/users.vue:
suspend-user: "ユーザーの凍結"
operation: "操作"
username-or-userid: "ユーザー名またはユーザーID"
user-not-found: "ユーザーが見つかりません"
lookup: "照会"
reset-password: "パスワードをリセット"
password-updated: "パスワードは現在「{password}」です"
suspend: "凍結"
suspended: "凍結しました"
unsuspend-user: "ユーザーの凍結の解除"
unsuspend: "凍結の解除"
unsuspended: "凍結を解除しました"
verify-user: "ユーザーの公式アカウント設定"
verify: "公式アカウントにする"
verified: "公式アカウントにしました"
unverify-user: "ユーザーの公式アカウント解除"
unverify: "公式アカウントを解除する"
unverified: "公式アカウントを解除しました"
users:
title: "ユーザー"
sort:
title: "ソート"
createdAtAsc: "登録日時が古い順"
createdAtDesc: "登録日時が新しい順"
updatedAtAsc: "更新日時が古い順"
updatedAtDesc: "更新日時が新しい順"
origin:
title: "オリジン"
combined: "ローカル+リモート"
local: "ローカル"
remote: "リモート"
createdAt: "登録日時"
updatedAt: "更新日時"
admin/views/moderators.vue:
add-moderator:
title: "モデレーターの登録"
@ -1201,14 +1234,12 @@ mobile/views/components/friends-maker.vue:
refresh: "もっと見る"
close: "閉じる"
mobile/views/components/note.vue:
reposted-by: "{}がRenote"
private: "この投稿は非公開です"
deleted: "この投稿は削除されました"
location: "位置情報"
mobile/views/components/note-detail.vue:
reply: "返信"
reaction: "リアクション"
reposted-by: "{}がRenote"
private: "この投稿は非公開です"
deleted: "この投稿は削除されました"
location: "位置情報"

View File

@ -43,13 +43,13 @@ common:
unknown: "Unbekannt"
future: "Zukunft"
just_now: "Gerade eben"
seconds_ago: "vor {0} Sekunde{0:n}"
minutes_ago: "vor {0} Minuten"
hours_ago: "vor {0} Stunden"
days_ago: "vor {0} Tag{0:en}"
weeks_ago: "vor {0} Woche{0:n}"
months_ago: "vor {0} Monat{0:en}"
years_ago: "vor {} Jahr{0:en}"
seconds_ago: "vor {} Sekunde(n)"
minutes_ago: "vor {} Minute(n)"
hours_ago: "vor {} Stunde(n)"
days_ago: "vor {} Tag(en)"
weeks_ago: "vor {} Woche(n)"
months_ago: "vor {} Monat(en)"
years_ago: "vor {} Jahr(en)"
month-and-day: "{day}/{month}"
trash: "Papierkorb"
drive: "ドライブ"
@ -90,6 +90,9 @@ common:
specified: "Direkt"
specified-desc: "Nur für bestimmte Benutzer posten"
private: "Privat"
local-public: "公開 (ローカルのみ)"
local-home: "ホーム (ローカルのみ)"
local-followers: "フォロワー (ローカルのみ)"
note-placeholders:
a: "Was machst du gerade?"
b: "Was ist so passiert?"
@ -120,6 +123,7 @@ common:
is-remote-user: "このユーザー情報はコピーです。"
is-remote-post: "この投稿情報はコピーです。"
view-on-remote: "正確な情報を見る"
renoted-by: "{user}がRenote"
error:
title: '問題が発生しました'
retry: 'Erneut versuchen'
@ -427,6 +431,10 @@ common/views/components/visibility-chooser.vue:
specified: "Direkt"
specified-desc: "Poste nur für bestimmte Benutzer"
private: "Privat"
local-public: "公開 (ローカルのみ)"
local-public-desc: "リモートへは公開しない"
local-home: "ホーム (ローカルのみ)"
local-followers: "フォロワー (ローカルのみ)"
common/views/components/trends.vue:
count: "{}人が投稿"
empty: "トレンドなし"
@ -636,12 +644,10 @@ desktop/views/components/messaging-window.vue:
desktop/views/components/note-detail.vue:
private: "Dieser Post ist privat"
deleted: "Dieser Beitrag wurde entfernt"
reposted-by: "Repostet von {}"
location: "Ort"
renote: "Anmerkung"
add-reaction: "Reaktion hinzufügen"
desktop/views/components/note.vue:
reposted-by: "{}がRenote"
reply: "返信"
renote: "Renote"
add-reaction: "リアクション"
@ -676,6 +682,7 @@ desktop/views/components/post-form.vue:
create-poll: "Eine Abstimmung erstellen"
text-remain: "{} Zeichen verbleibend"
recent-tags: "最近"
local-only-message: "この投稿はローカルにのみ公開されます"
click-to-tagging: "クリックでタグ付け"
visibility: "Sichtbarkeit"
geolocation-alert: "お使いの端末は位置情報に対応していません"
@ -693,6 +700,7 @@ desktop/views/components/renote-form.vue:
quote: "Zitieren..."
cancel: "Abbrechen"
renote: "Anmerkung"
renote-home: "Renote (Home)"
reposting: "Weitersagen..."
success: "Weitergesagt!"
failure: "Weitersagen fehlgeschlagen"
@ -707,6 +715,7 @@ desktop/views/components/settings.vue:
profile: "Profil"
notification: "Mitteilungen"
apps: "In App öffnen"
tags: "ハッシュタグ"
mute-and-block: "ミュート/ブロック"
blocking: "ブロック"
security: "Sicherheit"
@ -749,6 +758,7 @@ desktop/views/components/settings.vue:
show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する"
show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する"
show-maps: "Karte anzeigen"
remain-deleted-note: "削除された投稿を表示し続ける"
deck-column-align: "デッキのカラムの位置"
deck-column-align-center: "中央"
deck-column-align-left: "左"
@ -921,7 +931,7 @@ admin/views/index.vue:
emoji: "カスタム絵文字"
moderators: "モデレーター"
users: "ユーザー"
update: "更新"
federation: "連合"
announcements: "お知らせ"
hashtags: "ハッシュタグ"
back-to-misskey: "Misskeyに戻る"
@ -981,6 +991,12 @@ admin/views/instance.vue:
invite: "招待"
save: "保存"
saved: "保存しました"
user-recommendation-config: "おすすめユーザー"
enable-external-user-recommendation: "外部ユーザーレコメンデーションを有効にする"
external-user-recommendation-engine: "エンジン"
external-user-recommendation-engine-desc: "例: https://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-misskey-api.cgi?{{host}}+{{user}}+{{limit}}+{{offset}}"
external-user-recommendation-timeout: "タイムアウト"
external-user-recommendation-timeout-desc: "ミリ秒単位 (例: 300000)"
admin/views/charts.vue:
title: "チャート"
per-day: "1日ごと"
@ -1007,18 +1023,35 @@ admin/views/charts.vue:
network-time: "応答時間"
network-usage: "通信量"
admin/views/users.vue:
suspend-user: "ユーザーの凍結"
operation: "操作"
username-or-userid: "ユーザー名またはユーザーID"
user-not-found: "ユーザーが見つかりません"
lookup: "照会"
reset-password: "パスワードをリセット"
password-updated: "パスワードは現在「{password}」です"
suspend: "凍結"
suspended: "凍結しました"
unsuspend-user: "ユーザーの凍結の解除"
unsuspend: "凍結の解除"
unsuspended: "凍結を解除しました"
verify-user: "ユーザーの公式アカウント設定"
verify: "公式アカウントにする"
verified: "公式アカウントにしました"
unverify-user: "ユーザーの公式アカウント解除"
unverify: "公式アカウントを解除する"
unverified: "公式アカウントを解除しました"
users:
title: "ユーザー"
sort:
title: "ソート"
createdAtAsc: "登録日時が古い順"
createdAtDesc: "登録日時が新しい順"
updatedAtAsc: "更新日時が古い順"
updatedAtDesc: "更新日時が新しい順"
origin:
title: "オリジン"
combined: "ローカル+リモート"
local: "ローカル"
remote: "リモート"
createdAt: "登録日時"
updatedAt: "更新日時"
admin/views/moderators.vue:
add-moderator:
title: "モデレーターの登録"
@ -1201,14 +1234,12 @@ mobile/views/components/friends-maker.vue:
refresh: "もっと見る"
close: "閉じる"
mobile/views/components/note.vue:
reposted-by: "{}がRenote"
private: "この投稿は非公開です"
deleted: "この投稿は削除されました"
location: "位置情報"
mobile/views/components/note-detail.vue:
reply: "返信"
reaction: "リアクション"
reposted-by: "{}がRenote"
private: "この投稿は非公開です"
deleted: "この投稿は削除されました"
location: "位置情報"

View File

@ -29,7 +29,7 @@ common:
got-it: "Got it!"
customization-tips:
title: "Customization tips"
paragraph: "<p>Home customization allows you to add/delete, drag and drop and rearrange widgets.</p><p>You can change the display by <strong><strong>right</strong> clicking</strong> on some widgets.</p><p>To delete a widget, drag and drop the widget onto <strong>the area labeled \"Trash\"</strong> in the header.</p><p>To finish the customization, click \"Finish\" on the upper right.</p>"
paragraph: "<p>Home customization allows you to add/delete, drag and drop and rearrange widgets.</p><p>You can change the display by <strong><strong>right</strong> clicking</strong> on some widgets.</p><p>To delete a widget, drag and drop the widget onto <strong>the area labeled \"Trash\"</strong> in the header.</p><p>To finish the customization, click \"Done\" on the upper right.</p>"
gotit: "Got it!"
notification:
file-uploaded: "File uploaded!"
@ -90,6 +90,9 @@ common:
specified: "Direct"
specified-desc: "Post to specified users only"
private: "Private"
local-public: "Local (Public)"
local-home: "Local (Home)"
local-followers: "Local (Followers)"
note-placeholders:
a: "What are you doing?"
b: "What's happening?"
@ -116,10 +119,11 @@ common:
reduce-motion: "Reduce motion in UI"
this-setting-is-this-device-only: "Only for this device"
use-os-default-emojis: "Use the OS default Emojis"
do-not-use-in-production: 'As this is for development, do not use this in production.'
do-not-use-in-production: 'This is a development build. Do not use in production.'
is-remote-user: "This user information is copied."
is-remote-post: "This post information is a copy."
view-on-remote: "View it on remote"
renoted-by: "Renoted by {user}"
error:
title: 'Something happened :('
retry: 'Retry'
@ -362,8 +366,8 @@ common/views/components/signin.vue:
signin: "Sign in"
or: "Or"
signin-with-twitter: "Log in with Twitter"
signin-with-github: "Log in with GitHub"
signin-with-discord: "Login with Discord"
signin-with-github: "Sign in with GitHub"
signin-with-discord: "Sign in with Discord"
login-failed: "Log in failed. Make sure you have entered your correct username and password."
common/views/components/signup.vue:
invitation-code: "Invitation code"
@ -427,6 +431,10 @@ common/views/components/visibility-chooser.vue:
specified: "Direct"
specified-desc: "Post to specified users only"
private: "Private"
local-public: "Local (Public)"
local-public-desc: "Do not publish to remote"
local-home: "Local (Home)"
local-followers: "Local (Followers)"
common/views/components/trends.vue:
count: "{} users mentioned"
empty: "No popular hashtag trends"
@ -636,12 +644,10 @@ desktop/views/components/messaging-window.vue:
desktop/views/components/note-detail.vue:
private: "Post is private"
deleted: "Post has been removed"
reposted-by: "Reposted by {}"
location: "Location"
renote: "Repost"
add-reaction: "Add a reaction"
desktop/views/components/note.vue:
reposted-by: "Reposted by {}"
reply: "Reply"
renote: "Renote"
add-reaction: "Add a reaction"
@ -676,6 +682,7 @@ desktop/views/components/post-form.vue:
create-poll: "Create a poll"
text-remain: "{} characters remaining"
recent-tags: "Recent"
local-only-message: "This post will only be published locally"
click-to-tagging: "Click to tagging"
visibility: "Visibility"
geolocation-alert: "Your device does not provide location services."
@ -693,6 +700,7 @@ desktop/views/components/renote-form.vue:
quote: "Quote..."
cancel: "Cancel"
renote: "Repost"
renote-home: "Renote (Home)"
reposting: "Reposting..."
success: "Reposted!"
failure: "Failed to Repost"
@ -707,6 +715,7 @@ desktop/views/components/settings.vue:
profile: "Profile"
notification: "Notification"
apps: "Apps"
tags: "Hashtags"
mute-and-block: "Mute / Block"
blocking: "Blocking"
security: "Security"
@ -749,6 +758,7 @@ desktop/views/components/settings.vue:
show-renoted-my-notes: "Show renoted posts of mine in timelines"
show-local-renotes: "Show renoted local posts in timelines"
show-maps: "Display a map to show the location"
remain-deleted-note: "Continue to show deleted posts"
deck-column-align: "Deck column alignment"
deck-column-align-center: "Center"
deck-column-align-left: "Left"
@ -919,9 +929,9 @@ admin/views/index.vue:
dashboard: "Dashboard"
instance: "Instance"
emoji: "Emoji"
moderators: "Moderator"
moderators: "Moderators"
users: "Users"
update: "Update"
federation: "Federation"
announcements: "Announcements"
hashtags: "Hashtags"
back-to-misskey: "Back to Misskey"
@ -976,11 +986,17 @@ admin/views/instance.vue:
proxy-account-username-desc: "Specify the user name of the account that is used as a proxy."
proxy-account-warn: "You must make an account having this username before this action."
max-note-text-length: "Maximum numbers of post characters"
disable-registration: "Stop user registration"
disable-local-timeline: "Make Local Timeline disabled"
disable-registration: "Disable new user registration"
disable-local-timeline: "Disable the Local Timeline"
invite: "Invite"
save: "Save"
saved: "Saved"
user-recommendation-config: "Recommended users"
enable-external-user-recommendation: "Enable to external user recommendation"
external-user-recommendation-engine: "Engine"
external-user-recommendation-engine-desc: "Example: https://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-misskey-api.cgi?{{host}}+{{user}}+{{limit}}+{{offset}}"
external-user-recommendation-timeout: "Timeout"
external-user-recommendation-timeout-desc: "Number of milliseconds (ex. 300,000)"
admin/views/charts.vue:
title: "Chart"
per-day: "per Day"
@ -1007,18 +1023,35 @@ admin/views/charts.vue:
network-time: "Response time"
network-usage: "Traffic"
admin/views/users.vue:
suspend-user: "Suspend a user"
operation: "Operations"
username-or-userid: "Username or user ID"
user-not-found: "User not found"
lookup: "Look up"
reset-password: "Reset password"
password-updated: "The password is now \"{password}\""
suspend: "Suspend"
suspended: "Successfully suspended."
unsuspend-user: "Unsuspend users"
unsuspend: "Unsuspend"
unsuspended: "The user has successfully unsuspended."
verify-user: "User account verification settings"
verify: "Verify account"
verified: "The account is now being verified"
unverify-user: "User account unverification settings"
unverify: "Unverify account"
unverified: "The account is now being unverified"
users:
title: "Users"
sort:
title: "Sort"
createdAtAsc: "Date Registered (Ascending)"
createdAtDesc: "Date Registered (Descending)"
updatedAtAsc: "Last Updated (Ascending)"
updatedAtDesc: "Last Updated (Descending)"
origin:
title: "Origin"
combined: "Local + Remote"
local: "Local"
remote: "Remote"
createdAt: "Created at"
updatedAt: "Updated at"
admin/views/moderators.vue:
add-moderator:
title: "Register Moderator"
@ -1041,7 +1074,7 @@ admin/views/emoji.vue:
remove: "Remove"
updated: "Updated"
remove-emoji:
are-you-sure: "Delete \"%1$s\"?"
are-you-sure: "Delete \"$1\"?"
removed: "Deleted"
admin/views/announcements.vue:
announcements: "Announcements"
@ -1052,7 +1085,7 @@ admin/views/announcements.vue:
text: "Content"
saved: "Saved"
_remove:
are-you-sure: "Delete \"%1$s\"?"
are-you-sure: "Delete \"$1\"?"
removed: "Deleted"
admin/views/hashtags.vue:
hided-tags: "Hidden Tags"
@ -1201,14 +1234,12 @@ mobile/views/components/friends-maker.vue:
refresh: "See more"
close: "Close"
mobile/views/components/note.vue:
reposted-by: "Reposted by {}"
private: "This post is private"
deleted: "This post has been deleted"
location: "Location"
mobile/views/components/note-detail.vue:
reply: "Reply"
reaction: "Reaction"
reposted-by: "Reposted by {}"
private: "This post is private"
deleted: "This post has been deleted"
location: "Location"
@ -1424,7 +1455,7 @@ deck:
deck/deck.tl-column.vue:
is-media-only: "Only media posts"
is-media-view: "Media view"
edit: "Option"
edit: "Options"
deck/deck.user-column.vue:
posts: "Posts"
following: "Following"

View File

@ -90,6 +90,9 @@ common:
specified: "ダイレクト"
specified-desc: "指定したユーザーにのみ公開"
private: "非公開"
local-public: "公開 (ローカルのみ)"
local-home: "ホーム (ローカルのみ)"
local-followers: "フォロワー (ローカルのみ)"
note-placeholders:
a: "¿Qué haces?"
b: "¿Qué está pasando?"
@ -120,6 +123,7 @@ common:
is-remote-user: "このユーザー情報はコピーです。"
is-remote-post: "この投稿情報はコピーです。"
view-on-remote: "正確な情報を見る"
renoted-by: "{user}がRenote"
error:
title: '問題が発生しました'
retry: 'やり直す'
@ -427,6 +431,10 @@ common/views/components/visibility-chooser.vue:
specified: "Directo"
specified-desc: "Publica solo para los seguidores que quieras"
private: "Privada"
local-public: "公開 (ローカルのみ)"
local-public-desc: "リモートへは公開しない"
local-home: "ホーム (ローカルのみ)"
local-followers: "フォロワー (ローカルのみ)"
common/views/components/trends.vue:
count: "{}人が投稿"
empty: "トレンドなし"
@ -636,12 +644,10 @@ desktop/views/components/messaging-window.vue:
desktop/views/components/note-detail.vue:
private: "Esta publicación es privada"
deleted: "Esta publicación ha sido removida"
reposted-by: "Republicado por {}"
location: "Localización"
renote: "Republicar"
add-reaction: "Agregar una reacción"
desktop/views/components/note.vue:
reposted-by: "{}がRenote"
reply: "返信"
renote: "Renote"
add-reaction: "リアクション"
@ -676,6 +682,7 @@ desktop/views/components/post-form.vue:
create-poll: "Crea una encuesta"
text-remain: "quedan {} caracteres"
recent-tags: "Reciente"
local-only-message: "この投稿はローカルにのみ公開されます"
click-to-tagging: "Click para etiquetar"
visibility: "Visibilidad"
geolocation-alert: "Tu dispositivo no tiene soporte de geolocalización."
@ -693,6 +700,7 @@ desktop/views/components/renote-form.vue:
quote: "Cita..."
cancel: "Cancelar"
renote: "Volver a publicar"
renote-home: "Renote (Home)"
reposting: "Publicando de nuevo..."
success: "¡Publicado!"
failure: "La publicación ha fallado"
@ -707,6 +715,7 @@ desktop/views/components/settings.vue:
profile: "Perfil"
notification: "Notificación"
apps: "Aplicaciones"
tags: "ハッシュタグ"
mute-and-block: "ミュート/ブロック"
blocking: "ブロック"
security: "Seguridad"
@ -749,6 +758,7 @@ desktop/views/components/settings.vue:
show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する"
show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する"
show-maps: "マップの自動展開"
remain-deleted-note: "削除された投稿を表示し続ける"
deck-column-align: "デッキのカラムの位置"
deck-column-align-center: "中央"
deck-column-align-left: "左"
@ -921,7 +931,7 @@ admin/views/index.vue:
emoji: "カスタム絵文字"
moderators: "モデレーター"
users: "ユーザー"
update: "更新"
federation: "連合"
announcements: "お知らせ"
hashtags: "ハッシュタグ"
back-to-misskey: "Misskeyに戻る"
@ -981,6 +991,12 @@ admin/views/instance.vue:
invite: "招待"
save: "保存"
saved: "保存しました"
user-recommendation-config: "おすすめユーザー"
enable-external-user-recommendation: "外部ユーザーレコメンデーションを有効にする"
external-user-recommendation-engine: "エンジン"
external-user-recommendation-engine-desc: "例: https://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-misskey-api.cgi?{{host}}+{{user}}+{{limit}}+{{offset}}"
external-user-recommendation-timeout: "タイムアウト"
external-user-recommendation-timeout-desc: "ミリ秒単位 (例: 300000)"
admin/views/charts.vue:
title: "チャート"
per-day: "1日ごと"
@ -1007,18 +1023,35 @@ admin/views/charts.vue:
network-time: "応答時間"
network-usage: "通信量"
admin/views/users.vue:
suspend-user: "ユーザーの凍結"
operation: "操作"
username-or-userid: "ユーザー名またはユーザーID"
user-not-found: "ユーザーが見つかりません"
lookup: "照会"
reset-password: "パスワードをリセット"
password-updated: "パスワードは現在「{password}」です"
suspend: "凍結"
suspended: "凍結しました"
unsuspend-user: "ユーザーの凍結の解除"
unsuspend: "凍結の解除"
unsuspended: "凍結を解除しました"
verify-user: "ユーザーの公式アカウント設定"
verify: "公式アカウントにする"
verified: "公式アカウントにしました"
unverify-user: "ユーザーの公式アカウント解除"
unverify: "公式アカウントを解除する"
unverified: "公式アカウントを解除しました"
users:
title: "ユーザー"
sort:
title: "ソート"
createdAtAsc: "登録日時が古い順"
createdAtDesc: "登録日時が新しい順"
updatedAtAsc: "更新日時が古い順"
updatedAtDesc: "更新日時が新しい順"
origin:
title: "オリジン"
combined: "ローカル+リモート"
local: "ローカル"
remote: "リモート"
createdAt: "登録日時"
updatedAt: "更新日時"
admin/views/moderators.vue:
add-moderator:
title: "モデレーターの登録"
@ -1201,14 +1234,12 @@ mobile/views/components/friends-maker.vue:
refresh: "もっと見る"
close: "閉じる"
mobile/views/components/note.vue:
reposted-by: "{}がRenote"
private: "この投稿は非公開です"
deleted: "この投稿は削除されました"
location: "位置情報"
mobile/views/components/note-detail.vue:
reply: "返信"
reaction: "リアクション"
reposted-by: "{}がRenote"
private: "この投稿は非公開です"
deleted: "この投稿は削除されました"
location: "位置情報"

View File

@ -4,16 +4,16 @@ meta:
divider: ""
common:
misskey: "Une ⭐ du fédiverse"
about-title: "Une ⭐ du fédivers."
about: "Merci davoir choisis Misskey. Misskey est une <b>plateforme de micro-blogging distribuée</b> née sur Terre et fait partie du Fédiverse (un univers composé de diverses plateformes de réseaux sociaux organisées), elle est connectée mutuellement avec dautres plateformes de réseaux sociaux. Désirez-vous prendre une pause, un court instant, loin de lagitation de la ville et plonger dans un Internet dun nouveau genre ?"
about-title: "Une ⭐ du fédiverse."
about: "Merci davoir choisis Misskey. Misskey est une <b>plateforme de microblogage distribuée</b> née sur Terre et fait partie du Fédiverse (un univers composé de diverses plateformes de réseaux sociaux organisées), elle est connectée mutuellement avec dautres plateformes de réseaux sociaux. Désirez-vous prendre une pause, un court instant, loin de lagitation de la ville et plonger dans un Internet dun nouveau genre ?"
intro:
title: "Cest quoi Misskey ?"
about: "Misskeyはオープンソースの<b>分散型マイクロブログSNS</b>です。リッチで高度にカスタマイズできるUI、投稿へのリアクション、ファイルを一元管理できるドライブなど、先進的な機能を揃えています。また、Fediverseと呼ばれるネットワークに接続できるため、他のSNSともやり取りできます。例えば、あなたが何か投稿すると、その投稿はMisskeyだけでなく他のSNSにも伝わります。ちょうどある惑星から他の惑星に電波を発信している様子をイメージしてください。"
about: "Misskey est un <b>réseau social de Microblogage</b> open source. Il offre une interface utilisateur riche et hautement personnalisable, une variété de réactions aux publications et un lecteur pour la gestion centralisée de fichiers. De plus, comme il est possible de se connecter au reste du du Fédiverse, vous pouvez interagir avec d'autres plateformes fédérées. Par exemple, si vous publiez quelque chose, la note sera transmise non seulement aux utilisateurs de Misskey, mais aussi à d'autres plateformes de réseaux sociaux dans le Fédiverse. Imaginez que vous puissiez transmettre des ondes radio d'une planète vers l'autre."
features: "Options"
rich-contents: "Notes"
rich-contents-desc: "自分の考え、話題の出来事、皆と共有したいことについて発信してください。必要であれば、様々な構文を使って投稿を装飾したり、好きな画像、動画などのファイルやアンケートを添付することもできます。"
rich-contents-desc: "Partagez vos idées, les événements et les sujets qui vous tiennent à cœur ainsi que tout autre chose que vous souhaitez partager avec les autres. Si vous le désirez, vous pouvez décorer vos messages en utilisant une syntaxe différente ou en y joignant des sondages et des fichiers, tels que les photos ou les vidéos que vous aimez."
reaction: "Réactions"
reaction-desc: "あなたの気持ちを伝える最も簡単な方法です。Misskeyは、他のユーザーの投稿に様々なリアクションを付けることができます。いちどMisskeyのリアクション機能を体験してしまうと、もう「いいね」の概念しか存在しないSNSには戻れなくなるかもしれません。"
reaction-desc: "Une manière simple d'exprimer vos émotions. Misskey peut attacher diverses réactions aux publications des autres utilisateurs. Si vous goûtez aux réactions sur Misskey une fois, vous ne pourrez plus être en mesure de retourner vers une autre plateforme de réseaux sociaux n'offrant que des \"J'aime\"."
ui: "Interface utilisateur"
ui-desc: "どのようなUIが使いやすいかは人それぞれです。だから、Misskeyは自由度の高いUIを持っています。レイアウトやデザインを調整したり、カスタマイズ可能な様々なウィジェットを配置したりして、自分だけのホームを作ってください。"
drive: "Drive"
@ -21,12 +21,12 @@ common:
outro: "他にもMisskeyにしかない機能はまだまだあるので、ぜひあなた自身の目で確かめてください。Misskeyは分散型SNSなので、このインスタンスが気に入らなければ他のインスタンスを試すこともできます。それでは、GLHF!"
adblock:
detected: "Veuillez désactiver votre bloqueur de publicités"
warning: "<strong>Misskey n'utilise pas de publicités</strong>, mais quelques options peuvent être non disponibles ou fonctionneraient mal si un bloqueur de publicités est activé."
application-authorization: "Permissions de l'application"
warning: "<strong>Misskey nutilise pas de publicités</strong>, mais quelques options peuvent être non disponibles ou fonctionneraient mal si un bloqueur de publicités est activé."
application-authorization: "Autorisations de lapplication"
close: "Fermer"
do-not-copy-paste: "Veuillez ne pas entrer ou coller le code ici. Le compte peut être compromis."
load-more: "Charger plus"
got-it: "J'ai compris !"
got-it: "Jai compris !"
customization-tips:
title: "Conseils de personnalisation"
paragraph: "<p>ホームのカスタマイズでは、ウィジェットを追加/削除したり、ドラッグ&ドロップして並べ替えたりすることができます。</p><p>一部のウィジェットは、<strong><strong>右</strong>クリック</strong>することで表示を変更することができます。</p><p>ウィジェットを削除するには、ヘッダーの<strong>「ゴミ箱」</strong>と書かれたエリアにウィジェットをドラッグ&ドロップします。</p><p>カスタマイズを終了するには、右上の「完了」をクリックします。</p>"
@ -44,8 +44,8 @@ common:
future: "à linstant"
just_now: "à l'instant"
seconds_ago: "Il y a {} seconde·s"
minutes_ago: "Il y a {} minute·s"
hours_ago: "Il y a {} heure·s"
minutes_ago: "Il y a {} min"
hours_ago: "Il y a {} h"
days_ago: "Il y a {} jours"
weeks_ago: "Il y a {} semaines·s"
months_ago: "Il y a {} mois"
@ -90,6 +90,9 @@ common:
specified: "Direct"
specified-desc: "Publier uniquement aux utilisateurs·rices mentionnés·es"
private: "Privé"
local-public: "Local (Public)"
local-home: "Accueil (local uniquement)"
local-followers: "Local (Abonnés)"
note-placeholders:
a: "Que faites-vous maintenant ?"
b: "Quoi de neuf ?"
@ -119,7 +122,8 @@ common:
do-not-use-in-production: 'Il sagit dune version de développement. Ne pas utiliser dans un environnement de production.'
is-remote-user: "Ces informations appartiennent à un·e utilisateur·rice distant·e."
is-remote-post: "Ceci est une publication distante."
view-on-remote: "Consulter le profil complet"
view-on-remote: " Consulter le profil complet"
renoted-by: "Renoté par {user}"
error:
title: 'Une erreur est survenue'
retry: 'Réessayer'
@ -158,15 +162,15 @@ common:
tips: "Conseils"
hashtags: "Hashtags"
dev: "Échec lors de la création de lapplication. Veuillez réessayer."
ai-chan-kawaii: "Ai-Chan est mignone !"
ai-chan-kawaii: "Ai-Chan est mignonne !"
auth/views/form.vue:
share-access: "Désirez-vous autoriser <i>{name}</i> à avoir accès à votre compte?"
permission-ask: "Cette application nécessite les autorisations suivantes :"
account-read: "Afficher les informations du compte :"
account-write: "Modifications des informations du compte :"
account-read: "Afficher les informations du compte."
account-write: "Modifications des informations du compte."
note-write: "Publier."
like-write: "Réagir aux publications."
following-write: "Sabonner et se désabonner."
following-write: "Suivre des comptes et se désabonner."
drive-read: "Lire votre Drive"
drive-write: "Téléverser/supprimer des fichiers dans votre Drive."
notification-read: "Lire vos notifications."
@ -175,13 +179,13 @@ auth/views/form.vue:
accept: "Autoriser laccès"
auth/views/index.vue:
loading: "Chargement en cours"
denied: "L'autorisation de l'application a été refusée."
denied: "Lautorisation de lapplication a été refusée."
denied-paragraph: "Cette application ne va pas accéder à votre compte."
already-authorized: "Cette application est déjà autorisée"
already-authorized: "Cette application est déjà autorisée."
allowed: "Permissions autorisées de lapplication."
callback-url: "Retour vers l'application"
callback-url: "Retour vers lapplication."
please-go-back: "Veillez retourner à l'application."
error: "La session n'existe pas."
error: "La session nexiste pas."
sign-in: "Veuillez vous connecter"
common/views/components/games/reversi/reversi.vue:
matching:
@ -198,7 +202,7 @@ common/views/components/games/reversi/reversi.index.vue:
sub-title: "Jouer à Reversi avec vos ami·e·s !"
invite: "Inviter"
rule: "Comment jouer ?"
rule-desc: "リバーシは、相手と交互に石をボードに置いて、相手の石を挟んで自分の色に変えてゆき、最終的に残った石が多い方が勝ちというボードゲームです。"
rule-desc: "Reversi est un jeu qui se joue sur un tablier et dans lequel les joueurs placent des pions sur ce dernier, à tour de rôle avec l'adversaire. Le but du jeu est d'avoir plus de pions de sa couleur que l'adversaire à la fin de la partie, celle-ci s'achevant lorsque aucun des deux joueurs ne peut plus jouer de coup légal, généralement lorsque les 64 cases sont occupées."
mode-invite: "Inviter"
mode-invite-desc: "Inviter un·e joueur·se."
invitations: "Vous avez reçu une invitation !"
@ -229,7 +233,7 @@ common/views/components/games/reversi/reversi.room.vue:
common/views/components/connect-failed.vue:
title: "Échec de connexion au serveur"
description: "Il se peut quil y est un problème avec votre connexion internet, ou le serveur est hors-ligne ou en maintenance. Veuillez {réessayer} plus tard."
thanks: "On vous remercie d'utiliser Misskey."
thanks: "On vous remercie davoir choisi dutiliser Misskey."
troubleshoot: "Dépanner"
common/views/components/connect-failed.troubleshooter.vue:
title: "Dépannage"
@ -254,8 +258,8 @@ common/views/components/media-banner.vue:
sensitive: "Contenu sensible"
click-to-show: "Cliquer pour afficher"
common/views/components/theme.vue:
light-theme: "Thème durant le mode clair"
dark-theme: "Thème durant le mode sombre"
light-theme: "Thème en mode jour"
dark-theme: "Thème en mode nuit"
light-themes: "Thème clair"
dark-themes: "Thème sombre"
install-a-theme: "Installer un thème"
@ -297,7 +301,7 @@ common/views/components/messaging.vue:
no-history: "Pas d'historique"
common/views/components/messaging-room.vue:
empty: "Pas de conversations"
no-history: "Il n'y a pas plus d'historique"
no-history: "Aucun historique"
resize-form: "Faites glisser pour redimensionner"
new-message: "Nouveau message"
only-one-file-attached: "Un seul fichier peut être joint au message"
@ -357,14 +361,14 @@ common/views/components/emoji-picker.vue:
common/views/components/signin.vue:
username: "Nom d'utilisateur·rice"
password: "Mot de passe"
token: "Token"
token: "Jeton"
signing-in: "Connexion…"
signin: "Se connecter"
or: "Ou"
signin-with-twitter: "Se connecter via Twitter"
signin-with-github: "Se connecter avec GitHub"
signin-with-discord: "Discordでログイン"
login-failed: "Échec d'authentification. Veuillez vérifier que votre nom d'utilisateur et mot de passe sont corrects."
signin-with-discord: "Se connecter avec Discord"
login-failed: "Échec dauthentification. Veuillez vérifier que votre nom dutilisateur et mot de passe sont corrects."
common/views/components/signup.vue:
invitation-code: "Code dinvitation"
invitation-info: "Si vous navez pas de code dinvitation, contactez un·e <a href=\"{}\">administrateur·rice</a>."
@ -410,12 +414,12 @@ common/views/components/github-setting.vue:
connect: "Se connecter avec GitHub"
disconnect: "Déconnecter"
common/views/components/discord-setting.vue:
description: "お使いのDiscordアカウントをお使いのMisskeyアカウントに接続しておくと、プロフィールでDiscordアカウント情報が表示されるようになったり、Discordを用いた便利なサインインを利用できるようになります。"
connected-to: "次のDiscordアカウントに接続されています"
detail: "詳細..."
reconnect: "再接続する"
connect: "Discordと接続する"
disconnect: "切断する"
description: "Si vous liez votre compte Discord à votre compte Misskey, vous serez en mesure de voir votre compte Twitter s'afficher sur votre profil, vous aurez aussi la possibilité de vous connecter à Misskey en utilisant votre compte Discord."
connected-to: "Vous êtes connecté à votre compte Discord"
detail: "Détails …"
reconnect: "Reconnecter"
connect: "Lier votre compte Discord"
disconnect: "Déconnecter"
common/views/components/uploader.vue:
waiting: "Veuillez patienter"
common/views/components/visibility-chooser.vue:
@ -427,6 +431,10 @@ common/views/components/visibility-chooser.vue:
specified: "Direct"
specified-desc: "Publier uniquement aux utilisateurs·rices mentionné·e·s"
private: "Privé"
local-public: "Local (Public)"
local-public-desc: "Ne pas publier pour les distants"
local-home: "Accueil (local uniquement)"
local-followers: "Local (Abonnés)"
common/views/components/trends.vue:
count: "{} utilisateurs·rices mentionnés·es"
empty: "Aucune tendance"
@ -456,9 +464,9 @@ common/views/widgets/broadcast.vue:
next: "Suivant"
common/views/widgets/calendar.vue:
year: "Année {}"
month: "{},"
day: "Jour {}"
today: "Aujourd'hui :"
month: "Mois {}"
day: "{}"
today: "Aujourdhui:"
this-month: "Ce mois-ci :"
this-year: "Cette année :"
common/views/widgets/donation.vue:
@ -501,9 +509,9 @@ common/views/widgets/tips.vue:
tips-line19: "Plusieurs fenêtres peuvent être détachées en dehors du navigateur."
tips-line20: "Pourcentage sur le widget calendrier qui indique le pourcentage de temps passé"
tips-line21: "Vous pouvez aussi utiliser l'API pour développer des Bots."
tips-line23: "Mayu est mignone avec ses sourcils."
tips-line24: "Misskey a vu le jour en 2014"
tips-line25: "対応ブラウザではMisskeyを開いていなくても通知を受け取れます"
tips-line23: "Mayu est mignonne avec ses sourcils."
tips-line24: "Misskey est fonctionnel depuis 2014"
tips-line25: "Vous pouvez recevoir les notifications de Misskey dans un navigateur web compatible"
common/views/pages/follow.vue:
signed-in-as: "Connecté·e en tant que {}"
following: "Suit"
@ -515,12 +523,12 @@ desktop:
banner-crop-title: "Découpez la partie qui apparaitra comme bannière"
banner: "Bannière"
uploading-banner: "Téléversement d'une nouvelle bannière"
banner-updated: "La bannière est mise à jour"
banner-updated: "Mise à jour de la bannière avec succès"
choose-banner: "Choisir une bannière"
avatar-crop-title: "Découpez la partie qui apparaitra comme avatar"
avatar: "Avatar"
uploading-avatar: "Téléversement du nouvel avatar"
avatar-updated: "L'avatar est mis à jour"
avatar-updated: "Mise à jour de lavatar avec succès"
choose-avatar: "Choisir un avatar"
invalid-filetype: "Ce format de fichier nest pas pris en charge"
desktop/views/components/activity.chart.vue:
@ -532,9 +540,9 @@ desktop/views/components/activity.vue:
title: "Activité"
toggle: "Afficher les vues"
desktop/views/components/calendar.vue:
title: "{year} / {month}"
prev: "Mois dernier"
next: "Mois prochain"
title: "{month} / {year}"
prev: "Mois précédent"
next: "Mois suivant"
go: "Cliquez pour naviguer"
desktop/views/components/choose-file-from-drive-window.vue:
chosen-files: "{count} fichier·s sélectionné·s"
@ -560,7 +568,7 @@ desktop/views/components/drive.file.vue:
rename: "Renommer"
mark-as-sensitive: "Marquer comme sensible"
unmark-as-sensitive: "Ne pas marquer comme sensible"
copy-url: "Copier l'URL"
copy-url: "Copier lURL"
download: "Télécharger"
else-files: "Autres..."
set-as-avatar: "Utiliser en tant qu'avatar"
@ -615,7 +623,7 @@ desktop/views/components/following-window.vue:
desktop/views/components/following.vue:
empty: "Vous ne suivez aucun compte."
desktop/views/components/friends-maker.vue:
title: "Utilisateurs recommandés :"
title: "Utilisateurs·rices recommandé·e·s :"
empty: "Impossible de trouver des utilisateurs·trices à recommander."
fetching: "Chargement"
refresh: "Plus"
@ -636,12 +644,10 @@ desktop/views/components/messaging-window.vue:
desktop/views/components/note-detail.vue:
private: "cette publication est privée"
deleted: "cette publication a été supprimée"
reposted-by: "Republié par {}"
location: "Géolocalisation"
renote: "Republier"
add-reaction: "Ajouter votre reaction"
desktop/views/components/note.vue:
reposted-by: "Partagé par {}"
reply: "Répondre"
renote: "Partager"
add-reaction: "Ajouter votre réaction"
@ -666,7 +672,7 @@ desktop/views/components/post-form.vue:
replied: "Répondu !"
reposted: "Reposté !"
note-failed: "La note à échoué"
reply-failed: "La réponse à échoué"
reply-failed: "La réponse a échoué"
renote-failed: "Échec lors de la republication"
posting: "Publication …"
attach-media-from-local: "Joindre un média depuis votre appareil"
@ -674,8 +680,9 @@ desktop/views/components/post-form.vue:
attach-cancel: "Annuler le fichier attaché"
insert-a-kao: "v('ω')v"
create-poll: "Créer un sondage"
text-remain: "{} charactères restants"
text-remain: "{} caractères restants"
recent-tags: "Récent"
local-only-message: "Ce message sera publié uniquement sur le fil local"
click-to-tagging: "Cliquer pour tagguer"
visibility: "Visibilité"
geolocation-alert: "Votre appareil ne prend pas en charge les services de localisation"
@ -693,6 +700,7 @@ desktop/views/components/renote-form.vue:
quote: "Citer..."
cancel: "Annuler"
renote: "Republier"
renote-home: "Renote (Home)"
reposting: "Republication en cours …"
success: "Republié !"
failure: "La renote a échoué"
@ -707,6 +715,7 @@ desktop/views/components/settings.vue:
profile: "Profil"
notification: "Notification"
apps: "Applications"
tags: "Hashtags"
mute-and-block: "Silencé·e·s / Bloqué·e·s"
blocking: "En cours de blocage"
security: "Sécurité"
@ -714,7 +723,7 @@ desktop/views/components/settings.vue:
password: "Mot de Passe"
2fa: "Vérification en deux étapes"
other: "Autres"
license: "License"
license: "Licence"
theme: "Thèmes"
behaviour: "Comportement"
fetch-on-scroll: "Chargement lors du défilement"
@ -726,7 +735,7 @@ desktop/views/components/settings.vue:
auto-popout-desc: "ウィンドウが開かれるとき、ポップアウト(ブラウザ外に切り離す)可能なら自動でポップアウトします。この設定はブラウザに記憶されます。"
advanced: "Paramètres avancés"
api-via-stream: "Requête API via le flux"
api-via-stream-desc: "この設定をオンにすると、websocket接続を経由してAPIリクエストが行われます(パフォーマンス向上が期待できます)。オフにすると、ネイティブの fetch APIが利用されます。この設定はこのデバイスのみ有効です。"
api-via-stream-desc: "Lorsque ce paramètre est activé, une demande d'API est effectuée via une connexion WebSocket (pour une meilleure performance). Lorsqu'il est désactivé, l'API de récupération native est utilisée. Ce paramètre n'est valide que sur cet appareil."
deck-nav: "デッキ内ナビゲーション"
deck-nav-desc: "デッキを使用しているとき、ナビゲーションが発生する際にページ遷移を行わずに一時的なカラムで受けるようにします。"
deck-default: "Utiliser le Deck comme IU par défaut"
@ -749,6 +758,7 @@ desktop/views/components/settings.vue:
show-renoted-my-notes: "Afficher mes republications dans les fils"
show-local-renotes: "Afficher les partages locaux sur les fils"
show-maps: "Afficher la carte"
remain-deleted-note: "Continuer à afficher les messages supprimés"
deck-column-align: "Alignement des colonnes du Deck"
deck-column-align-center: "Centrer"
deck-column-align-left: "À gauche"
@ -765,23 +775,23 @@ desktop/views/components/settings.vue:
language-desc: "Le rechargement de la page est requis afin d'appliquer les modifications."
cache: "Cache"
clean-cache: "Nettoyage"
cache-warn: "クリーンアップを行うと、ブラウザに記憶されたアカウント情報のキャッシュ、書きかけの投稿・返信・メッセージ、およびその他のデータ(設定情報含む)が削除されます。クリーンアップを行った後はページを再度読み込みする必要があります。"
cache-warn: "Le nettoyage du cache du compte supprime les informations stockées dans le navigateur comme les messages, les réponses ainsi que dautres données (y compris les paramètres de configuration). Après le nettoyage, vous devez recharger la page."
cache-cleared: "Cache nettoyé"
cache-cleared-desc: "Veuillez recharger la page."
auto-watch: "Montre automatique"
auto-watch-desc: "リアクションしたり返信したりした投稿に関する通知を自動的に受け取るようにします。"
auto-watch-desc: "Recevez automatiquement les notifications de publications, réponses et réactions."
about: "À propose de Misskey"
operator: "L'admin de cette instance"
update: "Mise à jour de Misskey"
version: "Version :"
latest-version: "Dernière version :"
update-checking: "Recherche de mises à jour"
update-checking: "Vérification des mises à jour en cours …"
do-update: "Rechercher des mises à jour"
update-settings: "Paramètres avancés"
prevent-update: "Reporter les mises à jour (non recommandé)"
prevent-update-desc: "この設定をオンにしてもアップデートが反映される場合があります。この設定はこのデバイスのみ有効です。"
prevent-update-desc: "Même si ce paramètre est activé, la mise à jour pourrait être appliquée. Ce paramètre n'est valide que sur cet appareil."
no-updates: "Aucune mise à jour disponible"
no-updates-desc: "Votre Misskey est à jour."
no-updates-desc: "Votre client Misskey est à jour."
update-available: "Nouvelle version disponible !"
update-available-desc: "Les mises à jour seront appliquées une fois la page est rechargée."
advanced-settings: "Réglages avancés"
@ -800,23 +810,23 @@ desktop/views/components/settings.2fa.vue:
intro: "Si vous configurez la vérication en deux étapes vous aurez non seulement besoin de votre mot de passe mais aussi un appareil déjà pré-enregistré(tel que votre smartphone) ce qui ameliora grandement la sécurité de votre compte."
detail: "Voir les détails..."
url: "https://www.google.com/landing/2step/"
caution: "Activer la vérification en deux étapes vient aussi avec des contraintes, si vous perdez votre appareil ou ne pouvez tout simplement plus y accèder vous ne serez plus en mesure de vous connecter à Misskey."
caution: "Activer la vérification en deux étapes vient aussi avec des contraintes, si vous perdez votre appareil ou ne pouvez tout simplement plus y accéder vous ne serez plus en mesure de vous connecter à Misskey."
register: "Enregistrer un appareil"
already-registered: "Cette étape à déjà été complétée"
unregister: "Désactiver"
unregistered: "La vérication en deux étapes a été desactivée"
unregistered: "L'authentification à deux facteurs a été désactivée."
enter-password: "Entrez un mot de passe"
authenticator: "Tout d'abord vous devez installer Google Authenticator sur votre appareil"
authenticator: "Vous devez au préalable installer Google Authenticator sur votre appareil:"
howtoinstall: "Comment installer"
scan: "Ensuite scannez le QR code afficher sur votre écran:"
done: "Veuillez entrer le token qui s'affiche sur votre appareil:"
submit: "Envoyer"
success: "L'operation a été complétée avec succès!"
failed: "L'operation a échoué. Veuillez vous assurer que le token a été entrer correctement."
info: "À partir de maintenant, à chaque fois que vous vous connecter entrez votre mot de passe ainsi que le token généré sur votre appareil."
success: "Sauvegarde des paramètres avec succès !"
failed: "Lopération a échoué. Veuillez vous assurer que le jeton a été saisi correctement."
info: "À partir de maintenant, à chaque fois que vous vous connectez entrez votre mot de passe ainsi que le jeton généré sur votre appareil."
common/views/components/api-settings.vue:
intro: "APIを利用するには、上記のトークンを「i」というキーでパラメータに付加してリクエストします。"
caution: "アカウントを不正利用される可能性があるため、このトークンは第三者に教えないでください(アプリなどにも入力しないでください)。"
intro: "Pour accéder à l'API, définissez ce jeton comme la clé de \"i\" dans les paramètres de requête."
caution: "Merci de ne pas introduire ce jeton dans aucune application ou le divulguer à quiconque. Ceci risque de compromettre votre compte."
regeneration-of-token: "Si votre jeton est compromis, vous pouvez le régénérer."
regenerate-token: "Régénérer le jeton"
token: "Jeton :"
@ -825,7 +835,7 @@ common/views/components/api-settings.vue:
title: 'Console API'
endpoint: 'Point de terminaison'
parameter: 'Paramètres'
credential-info: "「i」パラメータは自動で付与されます。"
credential-info: "Le paramètre \"i\" est requis dans la console."
send: 'Envoyer'
sending: 'Envoi en cours'
response: 'Résultat'
@ -836,7 +846,7 @@ common/views/components/drive-settings.vue:
in-use: "utilisé"
stats: "Statistiques"
common/views/components/mute-and-block.vue:
mute-and-block: "Silencer / Bloquer"
mute-and-block: "Silencés / Bloqués"
mute: "Mettre en sourdine"
block: "En cours blocage"
no-muted-users: "Aucun utilisateur·rice nest mis·e en sourdine"
@ -913,15 +923,15 @@ desktop/views/components/users-list.vue:
desktop/views/components/users-list-item.vue:
followed: "vous suit"
desktop/views/components/window.vue:
popout: "ポップアウト"
popout: "Fenêtre contextuelle"
close: "Fermer"
admin/views/index.vue:
dashboard: "Tableau de bord"
instance: "Instance"
emoji: "Emoji"
moderators: "モデレーター"
emoji: "Émoji"
moderators: "Modérateurs"
users: "Utilisateur·rice·s"
update: "Mise à jour"
federation: "Fédération"
announcements: "Annonces"
hashtags: "Hashtags"
back-to-misskey: "Retour vers Misskey"
@ -964,23 +974,29 @@ admin/views/instance.vue:
github-integration-info: "LURL callback est définit sur /api/gh/cb"
enable-github-integration: "Activer lauthentification avec Github"
github-integration-client-id: "ID client"
github-integration-client-secret: "Client Secret"
discord-integration-config: "Discord連携の設定"
discord-integration-info: "コールバックURLは /api/dc/cb に設定します。"
enable-discord-integration: "Discord連携を有効にする"
discord-integration-client-id: "Client ID"
discord-integration-client-secret: "Client Secret"
github-integration-client-secret: "Secret client"
discord-integration-config: "Paramètres dauthentification Discord"
discord-integration-info: "LURL callback est définit sur /api/dc/cb"
enable-discord-integration: "Activer lauthentification avec Discord"
discord-integration-client-id: "ID client"
discord-integration-client-secret: "Secret client"
proxy-account-config: "Compte proxy"
proxy-account-info: "プロキシアカウントは、特定の条件下でユーザーのリモートフォローを代行するアカウントです。例えば、ユーザーがリモートユーザーをリストに入れたとき、リストに入れられたユーザーを誰もフォローしていないとアクティビティがサーバーに配達されないため、代わりにプロキシアカウントがフォローするようにします。"
proxy-account-username: "Nom dutilisateur du compte proxy"
proxy-account-username-desc: "Spécifiez le nom dutilisateur du compte utilisé comme proxy."
proxy-account-warn: "Avant dentammer cette action, vous devez au préalable avoir créé un compte avec ce nom dutilisateur."
proxy-account-warn: "Avant dentamer cette action, vous devez au préalable avoir créé un compte avec ce nom dutilisateur."
max-note-text-length: "Nombre maximal de caractères pour les messages"
disable-registration: "Désactiver les inscriptions"
disable-local-timeline: "Désactiver lheure locale"
disable-local-timeline: "Désactiver le fil local"
invite: "Inviter"
save: "Sauvegarder"
saved: "Enregistré"
user-recommendation-config: "Utilisateur·rice·s"
enable-external-user-recommendation: "外部ユーザーレコメンデーションを有効にする"
external-user-recommendation-engine: "Moteur"
external-user-recommendation-engine-desc: "Exemple: https://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-misskey-api.cgi?{{host}}+{{user}}+{{limit}}+{{offset}}"
external-user-recommendation-timeout: "Délai dexpiration"
external-user-recommendation-timeout-desc: "En millisecondes (par exemple : 300000)"
admin/views/charts.vue:
title: "Graph"
per-day: "par jour"
@ -993,37 +1009,54 @@ admin/views/charts.vue:
charts:
federation-instances: "Nombre dinstances : augmentation/diminution"
federation-instances-total: "Nombre total dinstances"
notes: "投稿の増減 (統合)"
local-notes: "投稿の増減 (ローカル)"
remote-notes: "投稿の増減 (リモート)"
notes: "Nombre de publications : augmentation/diminution (combinés)"
local-notes: "Nombre des publications : augmentation/diminution (Local)"
remote-notes: "Nombre de publications : augmentation/diminution (distants)"
notes-total: "Total des publications"
users: "Nombre dutilisateur·rice·s : augmentation/diminution"
users-total: "Nombre total des utilisateur·rice·s"
drive: "ドライブ使用量の増減"
drive: "Capacité utilisée comme stockage : augmentation/diminution"
drive-total: "Utilisation totale du lecteur"
drive-files: "ドライブのファイル数の増減"
drive-files: "Le nombre de fichiers sur l'espace de stockage : augmentation/diminution"
drive-files-total: "Nombre total de fichiers sur le lecteur"
network-requests: "Requêtes"
network-time: "Temps de réponse"
network-usage: "Traffic"
admin/views/users.vue:
suspend-user: "Suspendre un·e utilisateur·rice"
operation: "操作"
username-or-userid: "ユーザー名またはユーザーID"
user-not-found: "ユーザーが見つかりません"
lookup: "照会"
reset-password: "パスワードをリセット"
password-updated: "パスワードは現在「{password}」です"
suspend: "Suspendre"
suspended: "Suspendu·e avec succès."
unsuspend-user: "Lever la suspension dutilisateur·rice·s"
unsuspend: "Suspension levée"
unsuspended: "La suspension de lutilisateur·rice a été levée avec succès"
verify-user: "Paramètres de vérification du compte utilisateur"
verify: "Vérification du compte"
verified: "Le compte a été vérifié"
unverify-user: "ユーザーの公式アカウント解除"
unverify: "Ôter la vérification du compte"
unverified: "Ce compte n'est plus vérifié"
users:
title: "ユーザー"
sort:
title: "ソート"
createdAtAsc: "登録日時が古い順"
createdAtDesc: "登録日時が新しい順"
updatedAtAsc: "更新日時が古い順"
updatedAtDesc: "更新日時が新しい順"
origin:
title: "オリジン"
combined: "ローカル+リモート"
local: "ローカル"
remote: "リモート"
createdAt: "登録日時"
updatedAt: "更新日時"
admin/views/moderators.vue:
add-moderator:
title: "モデレーターの登録"
add: "登録"
added: "モデレーターを登録しました"
title: "Ajout dun modérateur"
add: "Ajouter"
added: "Ajouté en tant que modérateur"
admin/views/emoji.vue:
add-emoji:
title: "Ajouter un émoji"
@ -1088,7 +1121,7 @@ desktop/views/pages/share.vue:
desktop/views/pages/tag.vue:
no-posts-found: "Aucune publication contenant « {q} » na été trouvée."
desktop/views/pages/user-list.users.vue:
users: "Utilisateurs"
users: "Utilisateurs·rices"
add-user: "Ajouter un utilisateur"
username: "Nom d'utilisateur"
desktop/views/pages/user/user.followers-you-know.vue:
@ -1098,7 +1131,7 @@ desktop/views/pages/user/user.followers-you-know.vue:
desktop/views/pages/user/user.friends.vue:
title: "Mentions fréquentes"
loading: "Chargement en cours"
no-users: "Pas d'utilisateurs"
no-users: "Aucune mention fréquente"
desktop/views/pages/user/user.photos.vue:
title: "Photos"
loading: "Chargement en cours"
@ -1122,9 +1155,9 @@ desktop/views/pages/user/user.header.vue:
followers: "Abonné·e·s"
is-bot: "Ce compte est un Bot"
years-old: "{age} ans"
year: "Année"
year: "/"
month: "/"
day: "-"
day: "/"
desktop/views/pages/user/user.timeline.vue:
default: "Publications"
with-replies: "Publications et réponses"
@ -1150,14 +1183,14 @@ desktop/views/widgets/trends.vue:
refresh: "Afficher d'autres"
nothing: "Rien"
desktop/views/widgets/users.vue:
title: "Utilisateurs"
title: "Utilisateurs·rices"
refresh: "Afficher d'autres"
no-one: "Personne"
mobile/views/components/drive.vue:
used: "utilisé"
folder-count: "Dossier(s)"
folder-count: "Dossier·s"
count-separator: ", "
file-count: "Fichiers(s)"
file-count: "Fichier·s"
nothing-in-drive: "Rien"
folder-is-empty: "Ce dossier est vide"
prompt: "Que veux-tu faire ? (Entrez un nombre): <1 → Télécharger le fichier | 2 → Télécharger le fichier avec l'URL | 3 → Créer le dossier | 4 → Modifier le nom du dossier | 5 → Déplacer ce dossier | 6 → Supprimer ce dossier >"
@ -1166,7 +1199,7 @@ mobile/views/components/drive.vue:
root-rename-alert: "L'emplacement actuel est la racine, pas le dossier, vous ne pouvez donc pas le renommer. Veuillez vous déplacer dans le dossier dont vous souhaitez modifier le nom."
root-move-alert: "L'emplacement actuel est la racine, ce n'est pas un dossier et il ne peut pas être déplacé. Veuillez vous déplacer dans le dossier que vous souhaitez déplacer."
url-prompt: "URL du fichier que vous souhaitez téléverser"
uploading: "アップロードをリクエストしました。アップロードが完了するまで時間がかかる場合があります。"
uploading: "Envoi demandé. Le téléversement pourrait prendre un certain temps avant de s'achever."
mobile/views/components/drive-file-chooser.vue:
select-file: "Choisissez un fichier"
mobile/views/components/drive-folder-chooser.vue:
@ -1195,20 +1228,18 @@ common/views/components/follow-button.vue:
follow-processing: "En cours dabonnement"
follow-request: "Demande dabonnement"
mobile/views/components/friends-maker.vue:
title: "Abonnez-vous aux utilisateurs"
title: "Abonnez-vous à"
empty: "Impossible de trouver des utilisateurs·trices à recommander."
fetching: "Chargement"
refresh: "Voir plus"
close: "Fermer"
mobile/views/components/note.vue:
reposted-by: "Republié par {}"
private: "cette publication est privée"
deleted: "cette publication a été supprimée"
location: "Géolocalisation"
mobile/views/components/note-detail.vue:
reply: "Répondre"
reaction: "Réaction"
reposted-by: "Republié par {}"
private: "cette publication est privée"
deleted: "cette publication a été supprimée"
location: "Lieu"
@ -1255,9 +1286,9 @@ mobile/views/components/ui.nav.vue:
darkmode: "Mode nuit"
settings: "Réglages"
admin: "Admin"
about: "À propose de Misskey"
about: "À propos de Misskey"
mobile/views/components/user-timeline.vue:
no-notes: "Cette utilisateur semble n'avoir rien poster pour le moment"
no-notes: "Il semble que cet·te utilisateur·rice na rien publié pour le moment."
no-notes-with-media: "Aucune notes avec des médias"
mobile/views/components/users-list.vue:
all: "Tout"
@ -1299,7 +1330,7 @@ mobile/views/pages/received-follow-requests.vue:
reject: "Refuser"
mobile/views/pages/note.vue:
title: "Post"
prev: "Note précedante"
prev: "Note précédente"
next: "Note suivante"
mobile/views/pages/notifications.vue:
notifications: "Notifications"
@ -1317,7 +1348,7 @@ mobile/views/pages/settings.vue:
lang-tip: "Le rechargement de la page est requis afin d'appliquer les modifications."
recommended: "Recommandé"
auto: "Automatique"
specify-language: "Spécifier la langue"
specify-language: "Sélectionnez votre langue"
design: "Affichage et design"
dark-mode: "Mode nuit"
i-am-under-limited-internet: "J'ai un accès Internet limité"
@ -1325,7 +1356,7 @@ mobile/views/pages/settings.vue:
contrasted-acct: "Nom dutilisateur contrasté"
timeline: "Fil d'actualité"
show-reply-target: "Afficher les réponses"
show-my-renotes: "Afficher mes republications"
show-my-renotes: "Afficher mes partages"
show-renoted-my-notes: "Afficher mes publications partagées"
show-local-renotes: "Afficher les publications partagées localement"
post-style: "Style de la publication"
@ -1351,10 +1382,10 @@ mobile/views/pages/settings.vue:
github-connect: "Se connecter à votre compte GitHub"
github-reconnect: "Reconnecter"
github-disconnect: "Déconnecter"
discord: "Discord連携"
discord-connect: "Discordアカウントに接続する"
discord-reconnect: "再接続する"
discord-disconnect: "切断する"
discord: "Intégration avec Discord"
discord-connect: "Connecter votre compte Discord"
discord-reconnect: "Reconnecter"
discord-disconnect: "Déconnecter"
update: "Mise à jour de Misskey"
version: "Version :"
latest-version: "Dernière version :"
@ -1377,7 +1408,7 @@ mobile/views/pages/user.vue:
notes: "Notes"
overview: "Aperçu"
timeline: "Fil d'actualité"
media: "Media"
media: "Média"
is-suspended: "This account has been suspended."
mute: "Mettre en sourdine"
unmute: "Enlever la sourdine"
@ -1390,13 +1421,13 @@ mobile/views/pages/user/home.vue:
activity: "Activité"
keywords: "Mot clés"
domains: "Domaines"
frequently-replied-users: "Utilisateurs qui interagissent souvent"
frequently-replied-users: "Utilisateurs·rices mentionné·e·s souvent"
followers-you-know: "Abonné·e·s que vous connaissez"
last-used-at: "Dernière connexion il y a"
mobile/views/pages/user/home.followers-you-know.vue:
no-users: "Aucun utilisateur·rice connu·e"
mobile/views/pages/user/home.friends.vue:
no-users: "Pass d'utilisateurs"
no-users: "Aucun utilisateur·rice connu·e"
mobile/views/pages/user/home.notes.vue:
no-notes: "Pas de notes"
mobile/views/pages/user/home.photos.vue:
@ -1448,7 +1479,7 @@ docs:
require-permission: "Ce point de communication nécessite la permission {permission}."
has-limit: "Il ya un taux limite."
duration-limit: "直近{duration}ミリ秒の間のこのエンドポイントへのリクエスト数の合計が{max}を超える場合はリクエストできません。"
min-interval-limit: "前回のリクエストから{interval}ミリ秒経っていない場合はリクエストできません。"
min-interval-limit: "Vous ne pourrez pas effectuer une nouvelle requête si {interval} millisecondes ne se sont pas écoulées depuis la dernière demande."
show-src: "Vous pouvez voir le code source ce point de communication."
show-src-link: "Consulter le code sur GitHub"
generated: "Ce document est généré à partir de la définition de lAPI."
@ -1474,7 +1505,7 @@ dev/views/new-app.vue:
callback-url-desc: "Vous pouvez définir lURL de redirection lorsque lutilisateur sest authentifié via formulaire dauthentification."
authority: "Autorisations "
authority-desc: "Sont accessibles via lAPI, uniquement les fonctionnalités demandées ici."
authority-warning: "アプリ作成後も変更できますが、新たな権限を付与する場合、その時点で関連付けられているユーザーキーはすべて無効になります。"
authority-warning: "Vous pouvez le changer même après avoir créé l'application, mais si vous attribuez une nouvelle permission, toutes les clés utilisateur associées seront dès lors invalides."
account-read: "Afficher les informations du compte"
account-write: "Modifications des informations du compte"
note-write: "Publications."

View File

@ -5,7 +5,7 @@
const fs = require('fs');
const yaml = require('js-yaml');
const langs = ['de-DE', 'en-US', 'fr-FR', 'ja-JP', 'ja-KS', 'pl-PL', 'es-ES', 'nl-NL'];
const langs = ['de-DE', 'en-US', 'fr-FR', 'ja-JP', 'ja-KS', 'pl-PL', 'es-ES', 'nl-NL', 'zh-CN'];
const loadLocale = lang => yaml.safeLoad(fs.readFileSync(`${__dirname}/${lang}.yml`, 'utf-8'));
const locales = langs.map(lang => ({ [lang]: loadLocale(lang) }));

View File

@ -1,10 +1,10 @@
---
meta:
lang: "日本語"
lang: "In Italiano"
divider: ""
common:
misskey: "A ⭐ of fediverse"
about-title: "A ⭐ of fediverse."
misskey: "A ⭐ of the fediverse"
about-title: "A ⭐ of the fediverse."
about: "Misskeyを見つけていただき、ありがとうございます。Misskeyは、地球で生まれた<b>分散マイクロブログSNS</b>です。Fediverse(様々なSNSで構成される宇宙)の中に存在するため、他のSNSと相互に繋がっています。暫し都会の喧騒から離れて、新しいインターネットにダイブしてみませんか。"
intro:
title: "Misskeyって"
@ -90,6 +90,9 @@ common:
specified: "ダイレクト"
specified-desc: "指定したユーザーにのみ公開"
private: "非公開"
local-public: "公開 (ローカルのみ)"
local-home: "ホーム (ローカルのみ)"
local-followers: "フォロワー (ローカルのみ)"
note-placeholders:
a: "今どうしてる?"
b: "何かありましたか?"
@ -120,6 +123,7 @@ common:
is-remote-user: "このユーザー情報はコピーです。"
is-remote-post: "この投稿情報はコピーです。"
view-on-remote: "正確な情報を見る"
renoted-by: "{user}がRenote"
error:
title: '問題が発生しました'
retry: 'やり直す'
@ -427,6 +431,10 @@ common/views/components/visibility-chooser.vue:
specified: "ダイレクト"
specified-desc: "指定したユーザーにのみ公開"
private: "非公開"
local-public: "公開 (ローカルのみ)"
local-public-desc: "リモートへは公開しない"
local-home: "ホーム (ローカルのみ)"
local-followers: "フォロワー (ローカルのみ)"
common/views/components/trends.vue:
count: "{}人が投稿"
empty: "トレンドなし"
@ -636,12 +644,10 @@ desktop/views/components/messaging-window.vue:
desktop/views/components/note-detail.vue:
private: "この投稿は非公開です"
deleted: "この投稿は削除されました"
reposted-by: "{}がRenote"
location: "位置情報"
renote: "Renote"
add-reaction: "リアクション"
desktop/views/components/note.vue:
reposted-by: "{}がRenote"
reply: "返信"
renote: "Renote"
add-reaction: "リアクション"
@ -676,6 +682,7 @@ desktop/views/components/post-form.vue:
create-poll: "アンケートを作成"
text-remain: "残り{}文字"
recent-tags: "最近"
local-only-message: "この投稿はローカルにのみ公開されます"
click-to-tagging: "クリックでタグ付け"
visibility: "公開範囲"
geolocation-alert: "お使いの端末は位置情報に対応していません"
@ -693,6 +700,7 @@ desktop/views/components/renote-form.vue:
quote: "引用する..."
cancel: "キャンセル"
renote: "Renote"
renote-home: "Renote (Home)"
reposting: "しています..."
success: "Renoteしました"
failure: "Renoteに失敗しました"
@ -707,6 +715,7 @@ desktop/views/components/settings.vue:
profile: "プロフィール"
notification: "通知"
apps: "アプリ"
tags: "ハッシュタグ"
mute-and-block: "ミュート/ブロック"
blocking: "ブロック"
security: "セキュリティ"
@ -749,6 +758,7 @@ desktop/views/components/settings.vue:
show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する"
show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する"
show-maps: "マップの自動展開"
remain-deleted-note: "削除された投稿を表示し続ける"
deck-column-align: "デッキのカラムの位置"
deck-column-align-center: "中央"
deck-column-align-left: "左"
@ -921,7 +931,7 @@ admin/views/index.vue:
emoji: "カスタム絵文字"
moderators: "モデレーター"
users: "ユーザー"
update: "更新"
federation: "連合"
announcements: "お知らせ"
hashtags: "ハッシュタグ"
back-to-misskey: "Misskeyに戻る"
@ -981,6 +991,12 @@ admin/views/instance.vue:
invite: "招待"
save: "保存"
saved: "保存しました"
user-recommendation-config: "おすすめユーザー"
enable-external-user-recommendation: "外部ユーザーレコメンデーションを有効にする"
external-user-recommendation-engine: "エンジン"
external-user-recommendation-engine-desc: "例: https://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-misskey-api.cgi?{{host}}+{{user}}+{{limit}}+{{offset}}"
external-user-recommendation-timeout: "タイムアウト"
external-user-recommendation-timeout-desc: "ミリ秒単位 (例: 300000)"
admin/views/charts.vue:
title: "チャート"
per-day: "1日ごと"
@ -1007,18 +1023,35 @@ admin/views/charts.vue:
network-time: "応答時間"
network-usage: "通信量"
admin/views/users.vue:
suspend-user: "ユーザーの凍結"
operation: "操作"
username-or-userid: "ユーザー名またはユーザーID"
user-not-found: "ユーザーが見つかりません"
lookup: "照会"
reset-password: "パスワードをリセット"
password-updated: "パスワードは現在「{password}」です"
suspend: "凍結"
suspended: "凍結しました"
unsuspend-user: "ユーザーの凍結の解除"
unsuspend: "凍結の解除"
unsuspended: "凍結を解除しました"
verify-user: "ユーザーの公式アカウント設定"
verify: "公式アカウントにする"
verified: "公式アカウントにしました"
unverify-user: "ユーザーの公式アカウント解除"
unverify: "公式アカウントを解除する"
unverified: "公式アカウントを解除しました"
users:
title: "ユーザー"
sort:
title: "ソート"
createdAtAsc: "登録日時が古い順"
createdAtDesc: "登録日時が新しい順"
updatedAtAsc: "更新日時が古い順"
updatedAtDesc: "更新日時が新しい順"
origin:
title: "オリジン"
combined: "ローカル+リモート"
local: "ローカル"
remote: "リモート"
createdAt: "登録日時"
updatedAt: "更新日時"
admin/views/moderators.vue:
add-moderator:
title: "モデレーターの登録"
@ -1201,14 +1234,12 @@ mobile/views/components/friends-maker.vue:
refresh: "もっと見る"
close: "閉じる"
mobile/views/components/note.vue:
reposted-by: "{}がRenote"
private: "この投稿は非公開です"
deleted: "この投稿は削除されました"
location: "位置情報"
mobile/views/components/note-detail.vue:
reply: "返信"
reaction: "リアクション"
reposted-by: "{}がRenote"
private: "この投稿は非公開です"
deleted: "この投稿は削除されました"
location: "位置情報"

View File

@ -96,9 +96,9 @@ common:
specified: "ダイレクト"
specified-desc: "指定したユーザーにのみ公開"
private: "非公開"
local-public: "公開(ローカルのみ)"
local-home: "ホーム(ローカルのみ)"
local-followers: "フォロワー(ローカルのみ)"
local-public: "公開 (ローカルのみ)"
local-home: "ホーム (ローカルのみ)"
local-followers: "フォロワー (ローカルのみ)"
note-placeholders:
a: "今どうしてる?"
@ -133,6 +133,7 @@ common:
is-remote-user: "このユーザー情報はコピーです。"
is-remote-post: "この投稿情報はコピーです。"
view-on-remote: "正確な情報を見る"
renoted-by: "{user}がRenote"
error:
title: '問題が発生しました'
@ -474,9 +475,10 @@ common/views/components/visibility-chooser.vue:
specified: "ダイレクト"
specified-desc: "指定したユーザーにのみ公開"
private: "非公開"
local-public: "公開(ローカルのみ)"
local-home: "ホーム(ローカルのみ)"
local-followers: "フォロワー(ローカルのみ)"
local-public: "公開 (ローカルのみ)"
local-public-desc: "リモートへは公開しない"
local-home: "ホーム (ローカルのみ)"
local-followers: "フォロワー (ローカルのみ)"
common/views/components/trends.vue:
count: "{}人が投稿"
@ -723,13 +725,11 @@ desktop/views/components/messaging-window.vue:
desktop/views/components/note-detail.vue:
private: "この投稿は非公開です"
deleted: "この投稿は削除されました"
reposted-by: "{}がRenote"
location: "位置情報"
renote: "Renote"
add-reaction: "リアクション"
desktop/views/components/note.vue:
reposted-by: "{}がRenote"
reply: "返信"
renote: "Renote"
add-reaction: "リアクション"
@ -788,6 +788,7 @@ desktop/views/components/renote-form.vue:
quote: "引用する..."
cancel: "キャンセル"
renote: "Renote"
renote-home: "Renote (Home)"
reposting: "しています..."
success: "Renoteしました"
failure: "Renoteに失敗しました"
@ -1116,6 +1117,12 @@ admin/views/instance.vue:
invite: "招待"
save: "保存"
saved: "保存しました"
user-recommendation-config: "おすすめユーザー"
enable-external-user-recommendation: "外部ユーザーレコメンデーションを有効にする"
external-user-recommendation-engine: "エンジン"
external-user-recommendation-engine-desc: "例: https://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-misskey-api.cgi?{{host}}+{{user}}+{{limit}}+{{offset}}"
external-user-recommendation-timeout: "タイムアウト"
external-user-recommendation-timeout-desc: "ミリ秒単位 (例: 300000)"
admin/views/charts.vue:
title: "チャート"
@ -1144,18 +1151,35 @@ admin/views/charts.vue:
network-usage: "通信量"
admin/views/users.vue:
suspend-user: "ユーザーの凍結"
operation: "操作"
username-or-userid: "ユーザー名またはユーザーID"
user-not-found: "ユーザーが見つかりません"
lookup: "照会"
reset-password: "パスワードをリセット"
password-updated: "パスワードは現在「{password}」です"
suspend: "凍結"
suspended: "凍結しました"
unsuspend-user: "ユーザーの凍結の解除"
unsuspend: "凍結の解除"
unsuspended: "凍結を解除しました"
verify-user: "ユーザーの公式アカウント設定"
verify: "公式アカウントにする"
verified: "公式アカウントにしました"
unverify-user: "ユーザーの公式アカウント解除"
unverify: "公式アカウントを解除する"
unverified: "公式アカウントを解除しました"
users:
title: "ユーザー"
sort:
title: "ソート"
createdAtAsc: "登録日時が古い順"
createdAtDesc: "登録日時が新しい順"
updatedAtAsc: "更新日時が古い順"
updatedAtDesc: "更新日時が新しい順"
origin:
title: "オリジン"
combined: "ローカル+リモート"
local: "ローカル"
remote: "リモート"
createdAt: "登録日時"
updatedAt: "更新日時"
admin/views/moderators.vue:
add-moderator:
@ -1374,7 +1398,6 @@ mobile/views/components/friends-maker.vue:
close: "閉じる"
mobile/views/components/note.vue:
reposted-by: "{}がRenote"
private: "この投稿は非公開です"
deleted: "この投稿は削除されました"
location: "位置情報"
@ -1382,7 +1405,6 @@ mobile/views/components/note.vue:
mobile/views/components/note-detail.vue:
reply: "返信"
reaction: "リアクション"
reposted-by: "{}がRenote"
private: "この投稿は非公開です"
deleted: "この投稿は削除されました"
location: "位置情報"

View File

@ -90,6 +90,9 @@ common:
specified: "ダイレクト"
specified-desc: "今から言うユーザー以外に見せんとってや"
private: "非公開"
local-public: "公開 (ローカルのみ)"
local-home: "ホーム (ローカルのみ)"
local-followers: "フォロワー (ローカルのみ)"
note-placeholders:
a: "今なにしてん?"
b: "何かあったんか?"
@ -120,6 +123,7 @@ common:
is-remote-user: "このユーザー情報はコピーです。"
is-remote-post: "この投稿情報はコピーです。"
view-on-remote: "ちゃんとした情報見せてや!"
renoted-by: "{user}がRenote"
error:
title: '問題が起こったわ'
retry: 'もっぺん'
@ -427,6 +431,10 @@ common/views/components/visibility-chooser.vue:
specified: "ダイレクト"
specified-desc: "今から言うユーザー以外に見せんとってや"
private: "非公開"
local-public: "公開 (ローカルのみ)"
local-public-desc: "リモートへは公開しない"
local-home: "ホーム (ローカルのみ)"
local-followers: "フォロワー (ローカルのみ)"
common/views/components/trends.vue:
count: "{}人が投稿"
empty: "流行は自分で作るんや"
@ -636,12 +644,10 @@ desktop/views/components/messaging-window.vue:
desktop/views/components/note-detail.vue:
private: "この投稿は見せられへんわ"
deleted: "この投稿なんか無くなってもうたわ"
reposted-by: "{}がRenote"
location: "ここおるで:"
renote: "Renote"
add-reaction: "リアクション"
desktop/views/components/note.vue:
reposted-by: "{}がRenote"
reply: "返す"
renote: "Renote"
add-reaction: "リアクション"
@ -676,6 +682,7 @@ desktop/views/components/post-form.vue:
create-poll: "アンケートを作成"
text-remain: "残り{}文字"
recent-tags: "最近のタグ"
local-only-message: "この投稿はローカルにのみ公開されます"
click-to-tagging: "クリックでタグ付け"
visibility: "公開範囲"
geolocation-alert: "あんさんのつことる端末は位置情報に対応しとらんみたいやわ、知らんけど。"
@ -693,6 +700,7 @@ desktop/views/components/renote-form.vue:
quote: "取ってくる……"
cancel: "やめとくわ"
renote: "Renote"
renote-home: "Renote (Home)"
reposting: "やっとります..."
success: "Renoteしたで"
failure: "Renoteでけへん"
@ -707,6 +715,7 @@ desktop/views/components/settings.vue:
profile: "プロフィール"
notification: "通知"
apps: "アプリ"
tags: "ハッシュタグ"
mute-and-block: "ミュート/ブロック"
blocking: "ブロック"
security: "セキュリティ"
@ -749,6 +758,7 @@ desktop/views/components/settings.vue:
show-renoted-my-notes: "わしのRenoteもタイムライン載せてくれや"
show-local-renotes: "ローカル投稿のRenoteも見たいんや"
show-maps: "地図勝手にバァーって開いてくれ"
remain-deleted-note: "削除された投稿を表示し続ける"
deck-column-align: "デッキのカラムの位置"
deck-column-align-center: "真ん中"
deck-column-align-left: "左"
@ -921,7 +931,7 @@ admin/views/index.vue:
emoji: "カスタム絵文字"
moderators: "モデレーター"
users: "ユーザー"
update: "更新"
federation: "連合"
announcements: "知っといてや"
hashtags: "ハッシュタグ"
back-to-misskey: "Misskeyに戻る"
@ -981,6 +991,12 @@ admin/views/instance.vue:
invite: "招待"
save: "保存"
saved: "保存しました"
user-recommendation-config: "おすすめユーザー"
enable-external-user-recommendation: "外部ユーザーレコメンデーションを有効にする"
external-user-recommendation-engine: "エンジン"
external-user-recommendation-engine-desc: "例: https://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-misskey-api.cgi?{{host}}+{{user}}+{{limit}}+{{offset}}"
external-user-recommendation-timeout: "タイムアウト"
external-user-recommendation-timeout-desc: "ミリ秒単位 (例: 300000)"
admin/views/charts.vue:
title: "チャート"
per-day: "1日ごと"
@ -1007,18 +1023,35 @@ admin/views/charts.vue:
network-time: "応答時間"
network-usage: "通信量"
admin/views/users.vue:
suspend-user: "ユーザーの凍結"
operation: "操作"
username-or-userid: "ユーザー名またはユーザーID"
user-not-found: "ユーザーが見つかりません"
lookup: "照会"
reset-password: "パスワードをリセット"
password-updated: "パスワードは現在「{password}」です"
suspend: "凍結"
suspended: "凍結しました"
unsuspend-user: "ユーザーの凍結の解除"
unsuspend: "凍結の解除"
unsuspended: "凍結を解除しました"
verify-user: "ユーザーの公式アカウント設定"
verify: "公式アカウントにする"
verified: "公式アカウントにしました"
unverify-user: "ユーザーの公式アカウント解除"
unverify: "公式アカウントを解除する"
unverified: "公式アカウントを解除しました"
users:
title: "ユーザー"
sort:
title: "ソート"
createdAtAsc: "登録日時が古い順"
createdAtDesc: "登録日時が新しい順"
updatedAtAsc: "更新日時が古い順"
updatedAtDesc: "更新日時が新しい順"
origin:
title: "オリジン"
combined: "ローカル+リモート"
local: "ローカル"
remote: "リモート"
createdAt: "登録日時"
updatedAt: "更新日時"
admin/views/moderators.vue:
add-moderator:
title: "モデレーターの登録"
@ -1201,14 +1234,12 @@ mobile/views/components/friends-maker.vue:
refresh: "もっとあるやろ!"
close: "さいなら"
mobile/views/components/note.vue:
reposted-by: "{}がRenote"
private: "この投稿は見せられへんわ"
deleted: "この投稿なんか無くなってもうたわ"
location: "ここおるで:"
mobile/views/components/note-detail.vue:
reply: "返す"
reaction: "リアクション"
reposted-by: "{}がRenote"
private: "この投稿は見せられへんわ"
deleted: "この投稿なんか無くなってもうたわ"
location: "ここおるで:"

View File

@ -5,12 +5,12 @@ meta:
common:
misskey: "연합우주의 ⭐"
about-title: "연합우주의 ⭐."
about: "Misskey를 찾아 주셔서 감사합니다. Misskey 지구에서 태어난 <b>분산 마이크로 블로그 SNS </b> 입니다. Fediverse (다양한 SNS로 구성되는 우주)에 존재하는 다른 SNS와 상호 연결되어 있습니다. 잠시 도시의 번잡함에서 벗어나 새로운 인터넷에 다이브 해 보지 않겠습니까."
about: "Misskey를 찾아주셔서 감사합니다. Misskey 지구에서 태어난 <b>분산 마이크로 블로그 SNS </b> 입니다. Fediverse(다양한 SNS로 구성되는 우주)에 존재하는 다른 SNS와 상호 연결되어 있습니다. 잠시 도시의 번잡함에서 벗어나 새로운 인터넷에 다이브 해 보지 않겠습니까."
intro:
title: "Misskey란?"
about: "Misskeyはオープンソースの<b>分散型マイクロブログSNS</b>です。リッチで高度にカスタマイズできるUI、投稿へのリアクション、ファイルを一元管理できるドライブなど、先進的な機能を揃えています。また、Fediverseと呼ばれるネットワークに接続できるため、他のSNSともやり取りできます。例えば、あなたが何か投稿すると、その投稿はMisskeyだけでなく他のSNSにも伝わります。ちょうどある惑星から他の惑星に電波を発信している様子をイメージしてください。"
about: "Misskey는 오픈소스 <b>분산형 마이크로블로그 SNS</b>입니다. 다양하고 폭넓게 커스터마이징할 수 있는 UI, 게시물에 대한 반응, 파일을 관리할 수 있는 드라이브 등의 선진적인 기능을 갖추고 있습니다. 더하여 Fediverse라고 부르는 네트워크에 연결할 수 있어 다른 SNS와도 주고받을 수 있습니다. 예를 들자면, 당신이 무언가를 게시하면, 해당 게시물은 Misskey 뿐만 아니라 다른 SNS에도 전해집니다. 살짝 어떤 행성에서 다른 행성으로 전파를 발신하고 있는 모습을 상상해주세요."
features: "특징"
rich-contents: "게시"
rich-contents: "글 쓰기"
rich-contents-desc: "自分の考え、話題の出来事、皆と共有したいことについて発信してください。必要であれば、様々な構文を使って投稿を装飾したり、好きな画像、動画などのファイルやアンケートを添付することもできます。"
reaction: "반응"
reaction-desc: "あなたの気持ちを伝える最も簡単な方法です。Misskeyは、他のユーザーの投稿に様々なリアクションを付けることができます。いちどMisskeyのリアクション機能を体験してしまうと、もう「いいね」の概念しか存在しないSNSには戻れなくなるかもしれません。"
@ -90,6 +90,9 @@ common:
specified: "다이렉트"
specified-desc: "지정한 사용자에게만 공개"
private: "비공개"
local-public: "公開 (ローカルのみ)"
local-home: "ホーム (ローカルのみ)"
local-followers: "フォロワー (ローカルのみ)"
note-placeholders:
a: "지금 어떻게하고있어?"
b: "뭔가 있었습니까?"
@ -120,6 +123,7 @@ common:
is-remote-user: "このユーザー情報はコピーです。"
is-remote-post: "この投稿情報はコピーです。"
view-on-remote: "正確な情報を見る"
renoted-by: "{user}がRenote"
error:
title: '問題が発生しました'
retry: 'やり直す'
@ -427,6 +431,10 @@ common/views/components/visibility-chooser.vue:
specified: "ダイレクト"
specified-desc: "指定したユーザーにのみ公開"
private: "非公開"
local-public: "公開 (ローカルのみ)"
local-public-desc: "リモートへは公開しない"
local-home: "ホーム (ローカルのみ)"
local-followers: "フォロワー (ローカルのみ)"
common/views/components/trends.vue:
count: "{}人が投稿"
empty: "トレンドなし"
@ -636,12 +644,10 @@ desktop/views/components/messaging-window.vue:
desktop/views/components/note-detail.vue:
private: "この投稿は非公開です"
deleted: "この投稿は削除されました"
reposted-by: "{}がRenote"
location: "位置情報"
renote: "Renote"
add-reaction: "リアクション"
desktop/views/components/note.vue:
reposted-by: "{}がRenote"
reply: "返信"
renote: "Renote"
add-reaction: "リアクション"
@ -676,6 +682,7 @@ desktop/views/components/post-form.vue:
create-poll: "アンケートを作成"
text-remain: "残り{}文字"
recent-tags: "最近"
local-only-message: "この投稿はローカルにのみ公開されます"
click-to-tagging: "クリックでタグ付け"
visibility: "公開範囲"
geolocation-alert: "お使いの端末は位置情報に対応していません"
@ -693,6 +700,7 @@ desktop/views/components/renote-form.vue:
quote: "引用する..."
cancel: "キャンセル"
renote: "Renote"
renote-home: "Renote (Home)"
reposting: "しています..."
success: "Renoteしました"
failure: "Renoteに失敗しました"
@ -707,6 +715,7 @@ desktop/views/components/settings.vue:
profile: "プロフィール"
notification: "通知"
apps: "アプリ"
tags: "ハッシュタグ"
mute-and-block: "ミュート/ブロック"
blocking: "ブロック"
security: "セキュリティ"
@ -749,6 +758,7 @@ desktop/views/components/settings.vue:
show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する"
show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する"
show-maps: "マップの自動展開"
remain-deleted-note: "削除された投稿を表示し続ける"
deck-column-align: "デッキのカラムの位置"
deck-column-align-center: "中央"
deck-column-align-left: "左"
@ -921,7 +931,7 @@ admin/views/index.vue:
emoji: "カスタム絵文字"
moderators: "モデレーター"
users: "ユーザー"
update: "更新"
federation: "連合"
announcements: "お知らせ"
hashtags: "ハッシュタグ"
back-to-misskey: "Misskeyに戻る"
@ -981,6 +991,12 @@ admin/views/instance.vue:
invite: "招待"
save: "保存"
saved: "保存しました"
user-recommendation-config: "おすすめユーザー"
enable-external-user-recommendation: "外部ユーザーレコメンデーションを有効にする"
external-user-recommendation-engine: "エンジン"
external-user-recommendation-engine-desc: "例: https://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-misskey-api.cgi?{{host}}+{{user}}+{{limit}}+{{offset}}"
external-user-recommendation-timeout: "タイムアウト"
external-user-recommendation-timeout-desc: "ミリ秒単位 (例: 300000)"
admin/views/charts.vue:
title: "チャート"
per-day: "1日ごと"
@ -1007,18 +1023,35 @@ admin/views/charts.vue:
network-time: "応答時間"
network-usage: "通信量"
admin/views/users.vue:
suspend-user: "ユーザーの凍結"
operation: "操作"
username-or-userid: "ユーザー名またはユーザーID"
user-not-found: "ユーザーが見つかりません"
lookup: "照会"
reset-password: "パスワードをリセット"
password-updated: "パスワードは現在「{password}」です"
suspend: "凍結"
suspended: "凍結しました"
unsuspend-user: "ユーザーの凍結の解除"
unsuspend: "凍結の解除"
unsuspended: "凍結を解除しました"
verify-user: "ユーザーの公式アカウント設定"
verify: "公式アカウントにする"
verified: "公式アカウントにしました"
unverify-user: "ユーザーの公式アカウント解除"
unverify: "公式アカウントを解除する"
unverified: "公式アカウントを解除しました"
users:
title: "ユーザー"
sort:
title: "ソート"
createdAtAsc: "登録日時が古い順"
createdAtDesc: "登録日時が新しい順"
updatedAtAsc: "更新日時が古い順"
updatedAtDesc: "更新日時が新しい順"
origin:
title: "オリジン"
combined: "ローカル+リモート"
local: "ローカル"
remote: "リモート"
createdAt: "登録日時"
updatedAt: "更新日時"
admin/views/moderators.vue:
add-moderator:
title: "モデレーターの登録"
@ -1201,14 +1234,12 @@ mobile/views/components/friends-maker.vue:
refresh: "もっと見る"
close: "閉じる"
mobile/views/components/note.vue:
reposted-by: "{}がRenote"
private: "この投稿は非公開です"
deleted: "この投稿は削除されました"
location: "位置情報"
mobile/views/components/note-detail.vue:
reply: "返信"
reaction: "リアクション"
reposted-by: "{}がRenote"
private: "この投稿は非公開です"
deleted: "この投稿は削除されました"
location: "位置情報"

View File

@ -90,6 +90,9 @@ common:
specified: "ダイレクト"
specified-desc: "指定したユーザーにのみ公開"
private: "非公開"
local-public: "公開 (ローカルのみ)"
local-home: "ホーム (ローカルのみ)"
local-followers: "フォロワー (ローカルのみ)"
note-placeholders:
a: "今どうしてる?"
b: "何かありましたか?"
@ -120,6 +123,7 @@ common:
is-remote-user: "このユーザー情報はコピーです。"
is-remote-post: "この投稿情報はコピーです。"
view-on-remote: "正確な情報を見る"
renoted-by: "{user}がRenote"
error:
title: '問題が発生しました'
retry: 'やり直す'
@ -427,6 +431,10 @@ common/views/components/visibility-chooser.vue:
specified: "ダイレクト"
specified-desc: "指定したユーザーにのみ公開"
private: "非公開"
local-public: "公開 (ローカルのみ)"
local-public-desc: "リモートへは公開しない"
local-home: "ホーム (ローカルのみ)"
local-followers: "フォロワー (ローカルのみ)"
common/views/components/trends.vue:
count: "{}人が投稿"
empty: "トレンドなし"
@ -636,12 +644,10 @@ desktop/views/components/messaging-window.vue:
desktop/views/components/note-detail.vue:
private: "(dit bericht is privé)"
deleted: "この投稿は削除されました"
reposted-by: "{}がRenote"
location: "Locatie"
renote: "Renote"
add-reaction: "リアクション"
desktop/views/components/note.vue:
reposted-by: "{}がRenote"
reply: "返信"
renote: "Renote"
add-reaction: "リアクション"
@ -676,6 +682,7 @@ desktop/views/components/post-form.vue:
create-poll: "Peiling creëren"
text-remain: "{} resterende tekens"
recent-tags: "最近"
local-only-message: "この投稿はローカルにのみ公開されます"
click-to-tagging: "クリックでタグ付け"
visibility: "公開範囲"
geolocation-alert: "お使いの端末は位置情報に対応していません"
@ -693,6 +700,7 @@ desktop/views/components/renote-form.vue:
quote: "Citeren..."
cancel: "Annuleren"
renote: "Renote"
renote-home: "Renote (Home)"
reposting: "Bezig met herplaatsen..."
success: "Hergeplaatst!"
failure: "Renote mislukt"
@ -707,6 +715,7 @@ desktop/views/components/settings.vue:
profile: "Profiel"
notification: "Melding"
apps: "Apps"
tags: "ハッシュタグ"
mute-and-block: "ミュート/ブロック"
blocking: "ブロック"
security: "Beveiliging"
@ -749,6 +758,7 @@ desktop/views/components/settings.vue:
show-renoted-my-notes: "Mijn gerenote bericht tonen op de tijdlijn"
show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する"
show-maps: "Kaart tonen"
remain-deleted-note: "削除された投稿を表示し続ける"
deck-column-align: "デッキのカラムの位置"
deck-column-align-center: "中央"
deck-column-align-left: "左"
@ -921,7 +931,7 @@ admin/views/index.vue:
emoji: "カスタム絵文字"
moderators: "モデレーター"
users: "ユーザー"
update: "更新"
federation: "連合"
announcements: "お知らせ"
hashtags: "ハッシュタグ"
back-to-misskey: "Misskeyに戻る"
@ -981,6 +991,12 @@ admin/views/instance.vue:
invite: "招待"
save: "保存"
saved: "保存しました"
user-recommendation-config: "おすすめユーザー"
enable-external-user-recommendation: "外部ユーザーレコメンデーションを有効にする"
external-user-recommendation-engine: "エンジン"
external-user-recommendation-engine-desc: "例: https://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-misskey-api.cgi?{{host}}+{{user}}+{{limit}}+{{offset}}"
external-user-recommendation-timeout: "タイムアウト"
external-user-recommendation-timeout-desc: "ミリ秒単位 (例: 300000)"
admin/views/charts.vue:
title: "チャート"
per-day: "1日ごと"
@ -1007,18 +1023,35 @@ admin/views/charts.vue:
network-time: "応答時間"
network-usage: "通信量"
admin/views/users.vue:
suspend-user: "ユーザーの凍結"
operation: "操作"
username-or-userid: "ユーザー名またはユーザーID"
user-not-found: "ユーザーが見つかりません"
lookup: "照会"
reset-password: "パスワードをリセット"
password-updated: "パスワードは現在「{password}」です"
suspend: "凍結"
suspended: "凍結しました"
unsuspend-user: "ユーザーの凍結の解除"
unsuspend: "凍結の解除"
unsuspended: "凍結を解除しました"
verify-user: "ユーザーの公式アカウント設定"
verify: "公式アカウントにする"
verified: "公式アカウントにしました"
unverify-user: "ユーザーの公式アカウント解除"
unverify: "公式アカウントを解除する"
unverified: "公式アカウントを解除しました"
users:
title: "ユーザー"
sort:
title: "ソート"
createdAtAsc: "登録日時が古い順"
createdAtDesc: "登録日時が新しい順"
updatedAtAsc: "更新日時が古い順"
updatedAtDesc: "更新日時が新しい順"
origin:
title: "オリジン"
combined: "ローカル+リモート"
local: "ローカル"
remote: "リモート"
createdAt: "登録日時"
updatedAt: "更新日時"
admin/views/moderators.vue:
add-moderator:
title: "モデレーターの登録"
@ -1201,14 +1234,12 @@ mobile/views/components/friends-maker.vue:
refresh: "もっと見る"
close: "閉じる"
mobile/views/components/note.vue:
reposted-by: "Renote door {}"
private: "この投稿は非公開です"
deleted: "この投稿は削除されました"
location: "位置情報"
mobile/views/components/note-detail.vue:
reply: "Beantwoorden"
reaction: "Reactie"
reposted-by: "{}がRenote"
private: "この投稿は非公開です"
deleted: "この投稿は削除されました"
location: "位置情報"

View File

@ -1,6 +1,6 @@
---
meta:
lang: "norsk"
lang: "Norsk Bokmål"
divider: ""
common:
misskey: "En ⭐ av fediverse"
@ -90,6 +90,9 @@ common:
specified: "ダイレクト"
specified-desc: "指定したユーザーにのみ公開"
private: "Privat"
local-public: "公開 (ローカルのみ)"
local-home: "ホーム (ローカルのみ)"
local-followers: "フォロワー (ローカルのみ)"
note-placeholders:
a: "今どうしてる?"
b: "何かありましたか?"
@ -120,6 +123,7 @@ common:
is-remote-user: "このユーザー情報はコピーです。"
is-remote-post: "この投稿情報はコピーです。"
view-on-remote: "正確な情報を見る"
renoted-by: "{user}がRenote"
error:
title: '問題が発生しました'
retry: 'やり直す'
@ -427,6 +431,10 @@ common/views/components/visibility-chooser.vue:
specified: "Direkte"
specified-desc: "指定したユーザーにのみ公開"
private: "Privat"
local-public: "公開 (ローカルのみ)"
local-public-desc: "リモートへは公開しない"
local-home: "ホーム (ローカルのみ)"
local-followers: "フォロワー (ローカルのみ)"
common/views/components/trends.vue:
count: "{}人が投稿"
empty: "トレンドなし"
@ -636,12 +644,10 @@ desktop/views/components/messaging-window.vue:
desktop/views/components/note-detail.vue:
private: "この投稿は非公開です"
deleted: "この投稿は削除されました"
reposted-by: "{}がRenote"
location: "Lokasjon"
renote: "Renote"
add-reaction: "リアクション"
desktop/views/components/note.vue:
reposted-by: "{}がRenote"
reply: "返信"
renote: "Renote"
add-reaction: "リアクション"
@ -676,6 +682,7 @@ desktop/views/components/post-form.vue:
create-poll: "アンケートを作成"
text-remain: "残り{}文字"
recent-tags: "Nylig"
local-only-message: "この投稿はローカルにのみ公開されます"
click-to-tagging: "クリックでタグ付け"
visibility: "Synlighet"
geolocation-alert: "お使いの端末は位置情報に対応していません"
@ -693,6 +700,7 @@ desktop/views/components/renote-form.vue:
quote: "引用する..."
cancel: "Avbryt"
renote: "Renote"
renote-home: "Renote (Home)"
reposting: "しています..."
success: "Renoteしました"
failure: "Renoteに失敗しました"
@ -707,6 +715,7 @@ desktop/views/components/settings.vue:
profile: "プロフィール"
notification: "Notifikasjon"
apps: "Apper"
tags: "ハッシュタグ"
mute-and-block: "ミュート/ブロック"
blocking: "ブロック"
security: "セキュリティ"
@ -749,6 +758,7 @@ desktop/views/components/settings.vue:
show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する"
show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する"
show-maps: "マップの自動展開"
remain-deleted-note: "削除された投稿を表示し続ける"
deck-column-align: "デッキのカラムの位置"
deck-column-align-center: "中央"
deck-column-align-left: "左"
@ -921,7 +931,7 @@ admin/views/index.vue:
emoji: "カスタム絵文字"
moderators: "モデレーター"
users: "ユーザー"
update: "更新"
federation: "連合"
announcements: "お知らせ"
hashtags: "ハッシュタグ"
back-to-misskey: "Misskeyに戻る"
@ -981,6 +991,12 @@ admin/views/instance.vue:
invite: "招待"
save: "保存"
saved: "保存しました"
user-recommendation-config: "おすすめユーザー"
enable-external-user-recommendation: "外部ユーザーレコメンデーションを有効にする"
external-user-recommendation-engine: "エンジン"
external-user-recommendation-engine-desc: "例: https://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-misskey-api.cgi?{{host}}+{{user}}+{{limit}}+{{offset}}"
external-user-recommendation-timeout: "タイムアウト"
external-user-recommendation-timeout-desc: "ミリ秒単位 (例: 300000)"
admin/views/charts.vue:
title: "チャート"
per-day: "1日ごと"
@ -1007,18 +1023,35 @@ admin/views/charts.vue:
network-time: "応答時間"
network-usage: "通信量"
admin/views/users.vue:
suspend-user: "ユーザーの凍結"
operation: "操作"
username-or-userid: "ユーザー名またはユーザーID"
user-not-found: "ユーザーが見つかりません"
lookup: "照会"
reset-password: "パスワードをリセット"
password-updated: "パスワードは現在「{password}」です"
suspend: "凍結"
suspended: "凍結しました"
unsuspend-user: "ユーザーの凍結の解除"
unsuspend: "凍結の解除"
unsuspended: "凍結を解除しました"
verify-user: "ユーザーの公式アカウント設定"
verify: "公式アカウントにする"
verified: "公式アカウントにしました"
unverify-user: "ユーザーの公式アカウント解除"
unverify: "公式アカウントを解除する"
unverified: "公式アカウントを解除しました"
users:
title: "ユーザー"
sort:
title: "ソート"
createdAtAsc: "登録日時が古い順"
createdAtDesc: "登録日時が新しい順"
updatedAtAsc: "更新日時が古い順"
updatedAtDesc: "更新日時が新しい順"
origin:
title: "オリジン"
combined: "ローカル+リモート"
local: "ローカル"
remote: "リモート"
createdAt: "登録日時"
updatedAt: "更新日時"
admin/views/moderators.vue:
add-moderator:
title: "モデレーターの登録"
@ -1201,14 +1234,12 @@ mobile/views/components/friends-maker.vue:
refresh: "Se mer"
close: "Lukk"
mobile/views/components/note.vue:
reposted-by: "{}がRenote"
private: "この投稿は非公開です"
deleted: "この投稿は削除されました"
location: "Lokasjon"
mobile/views/components/note-detail.vue:
reply: "Svar"
reaction: "リアクション"
reposted-by: "{}がRenote"
private: "この投稿は非公開です"
deleted: "この投稿は削除されました"
location: "Lokasjon"

View File

@ -90,6 +90,9 @@ common:
specified: "ダイレクト"
specified-desc: "指定したユーザーにのみ公開"
private: "非公開"
local-public: "公開 (ローカルのみ)"
local-home: "ホーム (ローカルのみ)"
local-followers: "フォロワー (ローカルのみ)"
note-placeholders:
a: "Co robisz?"
b: "Co się wydarzyło?"
@ -120,6 +123,7 @@ common:
is-remote-user: "このユーザー情報はコピーです。"
is-remote-post: "この投稿情報はコピーです。"
view-on-remote: "正確な情報を見る"
renoted-by: "{user}がRenote"
error:
title: '問題が発生しました'
retry: 'やり直す'
@ -427,6 +431,10 @@ common/views/components/visibility-chooser.vue:
specified: "Bezpośredni"
specified-desc: "Tylko dla określonych użytkowników"
private: "Prywatny"
local-public: "公開 (ローカルのみ)"
local-public-desc: "リモートへは公開しない"
local-home: "ホーム (ローカルのみ)"
local-followers: "フォロワー (ローカルのみ)"
common/views/components/trends.vue:
count: "{}人が投稿"
empty: "トレンドなし"
@ -636,12 +644,10 @@ desktop/views/components/messaging-window.vue:
desktop/views/components/note-detail.vue:
private: "ten wpis jest prywatny"
deleted: "ten wpis został usunięty"
reposted-by: "Udostępniono przez {}"
location: "Informacje o lokalizacji"
renote: "Udostępnienie"
add-reaction: "Dodaj reakcję"
desktop/views/components/note.vue:
reposted-by: "{}がRenote"
reply: "返信"
renote: "Renote"
add-reaction: "リアクション"
@ -676,6 +682,7 @@ desktop/views/components/post-form.vue:
create-poll: "Utwórz ankietę"
text-remain: "pozostałe znaki: {}"
recent-tags: "Ostatnie"
local-only-message: "この投稿はローカルにのみ公開されます"
click-to-tagging: "Naciśnij aby oznaczyć"
visibility: "Widoczność"
geolocation-alert: "Twoje urządzenie nie obsługuje geolokalizacji."
@ -693,6 +700,7 @@ desktop/views/components/renote-form.vue:
quote: "Cytuj…"
cancel: "Anuluj"
renote: "Udostępnij"
renote-home: "Renote (Home)"
reposting: "Udostępnianie…"
success: "Udostępniono!"
failure: "Nie udało się udostępnić"
@ -707,6 +715,7 @@ desktop/views/components/settings.vue:
profile: "Profil"
notification: "Powiadomienia"
apps: "Aplikacje"
tags: "ハッシュタグ"
mute-and-block: "ミュート/ブロック"
blocking: "ブロック"
security: "Bezpieczeństwo"
@ -749,6 +758,7 @@ desktop/views/components/settings.vue:
show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する"
show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する"
show-maps: "Automatycznie pokazuj mapę"
remain-deleted-note: "削除された投稿を表示し続ける"
deck-column-align: "デッキのカラムの位置"
deck-column-align-center: "中央"
deck-column-align-left: "左"
@ -921,7 +931,7 @@ admin/views/index.vue:
emoji: "カスタム絵文字"
moderators: "モデレーター"
users: "ユーザー"
update: "更新"
federation: "連合"
announcements: "お知らせ"
hashtags: "ハッシュタグ"
back-to-misskey: "Misskeyに戻る"
@ -981,6 +991,12 @@ admin/views/instance.vue:
invite: "招待"
save: "保存"
saved: "保存しました"
user-recommendation-config: "おすすめユーザー"
enable-external-user-recommendation: "外部ユーザーレコメンデーションを有効にする"
external-user-recommendation-engine: "エンジン"
external-user-recommendation-engine-desc: "例: https://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-misskey-api.cgi?{{host}}+{{user}}+{{limit}}+{{offset}}"
external-user-recommendation-timeout: "タイムアウト"
external-user-recommendation-timeout-desc: "ミリ秒単位 (例: 300000)"
admin/views/charts.vue:
title: "チャート"
per-day: "1日ごと"
@ -1007,18 +1023,35 @@ admin/views/charts.vue:
network-time: "応答時間"
network-usage: "通信量"
admin/views/users.vue:
suspend-user: "ユーザーの凍結"
operation: "操作"
username-or-userid: "ユーザー名またはユーザーID"
user-not-found: "ユーザーが見つかりません"
lookup: "照会"
reset-password: "パスワードをリセット"
password-updated: "パスワードは現在「{password}」です"
suspend: "凍結"
suspended: "凍結しました"
unsuspend-user: "ユーザーの凍結の解除"
unsuspend: "凍結の解除"
unsuspended: "凍結を解除しました"
verify-user: "ユーザーの公式アカウント設定"
verify: "公式アカウントにする"
verified: "公式アカウントにしました"
unverify-user: "ユーザーの公式アカウント解除"
unverify: "公式アカウントを解除する"
unverified: "公式アカウントを解除しました"
users:
title: "ユーザー"
sort:
title: "ソート"
createdAtAsc: "登録日時が古い順"
createdAtDesc: "登録日時が新しい順"
updatedAtAsc: "更新日時が古い順"
updatedAtDesc: "更新日時が新しい順"
origin:
title: "オリジン"
combined: "ローカル+リモート"
local: "ローカル"
remote: "リモート"
createdAt: "登録日時"
updatedAt: "更新日時"
admin/views/moderators.vue:
add-moderator:
title: "モデレーターの登録"
@ -1201,14 +1234,12 @@ mobile/views/components/friends-maker.vue:
refresh: "Więcej"
close: "Zamknij"
mobile/views/components/note.vue:
reposted-by: "Udostępniono przez {}"
private: "ten wpis jest prywatny"
deleted: "ten wpis został usunięty"
location: "Informacje o lokalizacji"
mobile/views/components/note-detail.vue:
reply: "Odpowiedz"
reaction: "Reakcja"
reposted-by: "Udostępniono przez {}"
private: "ten wpis jest prywatny"
deleted: "ten wpis został usunięty"
location: "Informacje o lokalizacji"

View File

@ -90,6 +90,9 @@ common:
specified: "ダイレクト"
specified-desc: "指定したユーザーにのみ公開"
private: "非公開"
local-public: "公開 (ローカルのみ)"
local-home: "ホーム (ローカルのみ)"
local-followers: "フォロワー (ローカルのみ)"
note-placeholders:
a: "O que está fazendo?"
b: "O que está acontecendo?"
@ -120,6 +123,7 @@ common:
is-remote-user: "このユーザー情報はコピーです。"
is-remote-post: "この投稿情報はコピーです。"
view-on-remote: "正確な情報を見る"
renoted-by: "{user}がRenote"
error:
title: '問題が発生しました'
retry: 'やり直す'
@ -427,6 +431,10 @@ common/views/components/visibility-chooser.vue:
specified: "ダイレクト"
specified-desc: "指定したユーザーにのみ公開"
private: "非公開"
local-public: "公開 (ローカルのみ)"
local-public-desc: "リモートへは公開しない"
local-home: "ホーム (ローカルのみ)"
local-followers: "フォロワー (ローカルのみ)"
common/views/components/trends.vue:
count: "{}人が投稿"
empty: "トレンドなし"
@ -636,12 +644,10 @@ desktop/views/components/messaging-window.vue:
desktop/views/components/note-detail.vue:
private: "この投稿は非公開です"
deleted: "この投稿は削除されました"
reposted-by: "{}がRenote"
location: "位置情報"
renote: "Renote"
add-reaction: "リアクション"
desktop/views/components/note.vue:
reposted-by: "{}がRenote"
reply: "返信"
renote: "Renote"
add-reaction: "リアクション"
@ -676,6 +682,7 @@ desktop/views/components/post-form.vue:
create-poll: "アンケートを作成"
text-remain: "残り{}文字"
recent-tags: "最近"
local-only-message: "この投稿はローカルにのみ公開されます"
click-to-tagging: "クリックでタグ付け"
visibility: "公開範囲"
geolocation-alert: "お使いの端末は位置情報に対応していません"
@ -693,6 +700,7 @@ desktop/views/components/renote-form.vue:
quote: "引用する..."
cancel: "キャンセル"
renote: "Renote"
renote-home: "Renote (Home)"
reposting: "しています..."
success: "Renoteしました"
failure: "Renoteに失敗しました"
@ -707,6 +715,7 @@ desktop/views/components/settings.vue:
profile: "プロフィール"
notification: "通知"
apps: "アプリ"
tags: "ハッシュタグ"
mute-and-block: "ミュート/ブロック"
blocking: "ブロック"
security: "セキュリティ"
@ -749,6 +758,7 @@ desktop/views/components/settings.vue:
show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する"
show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する"
show-maps: "マップの自動展開"
remain-deleted-note: "削除された投稿を表示し続ける"
deck-column-align: "デッキのカラムの位置"
deck-column-align-center: "中央"
deck-column-align-left: "左"
@ -921,7 +931,7 @@ admin/views/index.vue:
emoji: "カスタム絵文字"
moderators: "モデレーター"
users: "ユーザー"
update: "更新"
federation: "連合"
announcements: "お知らせ"
hashtags: "ハッシュタグ"
back-to-misskey: "Misskeyに戻る"
@ -981,6 +991,12 @@ admin/views/instance.vue:
invite: "招待"
save: "保存"
saved: "保存しました"
user-recommendation-config: "おすすめユーザー"
enable-external-user-recommendation: "外部ユーザーレコメンデーションを有効にする"
external-user-recommendation-engine: "エンジン"
external-user-recommendation-engine-desc: "例: https://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-misskey-api.cgi?{{host}}+{{user}}+{{limit}}+{{offset}}"
external-user-recommendation-timeout: "タイムアウト"
external-user-recommendation-timeout-desc: "ミリ秒単位 (例: 300000)"
admin/views/charts.vue:
title: "チャート"
per-day: "1日ごと"
@ -1007,18 +1023,35 @@ admin/views/charts.vue:
network-time: "応答時間"
network-usage: "通信量"
admin/views/users.vue:
suspend-user: "ユーザーの凍結"
operation: "操作"
username-or-userid: "ユーザー名またはユーザーID"
user-not-found: "ユーザーが見つかりません"
lookup: "照会"
reset-password: "パスワードをリセット"
password-updated: "パスワードは現在「{password}」です"
suspend: "凍結"
suspended: "凍結しました"
unsuspend-user: "ユーザーの凍結の解除"
unsuspend: "凍結の解除"
unsuspended: "凍結を解除しました"
verify-user: "ユーザーの公式アカウント設定"
verify: "公式アカウントにする"
verified: "公式アカウントにしました"
unverify-user: "ユーザーの公式アカウント解除"
unverify: "公式アカウントを解除する"
unverified: "公式アカウントを解除しました"
users:
title: "ユーザー"
sort:
title: "ソート"
createdAtAsc: "登録日時が古い順"
createdAtDesc: "登録日時が新しい順"
updatedAtAsc: "更新日時が古い順"
updatedAtDesc: "更新日時が新しい順"
origin:
title: "オリジン"
combined: "ローカル+リモート"
local: "ローカル"
remote: "リモート"
createdAt: "登録日時"
updatedAt: "更新日時"
admin/views/moderators.vue:
add-moderator:
title: "モデレーターの登録"
@ -1201,14 +1234,12 @@ mobile/views/components/friends-maker.vue:
refresh: "もっと見る"
close: "閉じる"
mobile/views/components/note.vue:
reposted-by: "{}がRenote"
private: "この投稿は非公開です"
deleted: "この投稿は削除されました"
location: "位置情報"
mobile/views/components/note-detail.vue:
reply: "返信"
reaction: "リアクション"
reposted-by: "{}がRenote"
private: "この投稿は非公開です"
deleted: "この投稿は削除されました"
location: "位置情報"

View File

@ -90,6 +90,9 @@ common:
specified: "ダイレクト"
specified-desc: "指定したユーザーにのみ公開"
private: "非公開"
local-public: "公開 (ローカルのみ)"
local-home: "ホーム (ローカルのみ)"
local-followers: "フォロワー (ローカルのみ)"
note-placeholders:
a: "今どうしてる?"
b: "何かありましたか?"
@ -120,6 +123,7 @@ common:
is-remote-user: "このユーザー情報はコピーです。"
is-remote-post: "この投稿情報はコピーです。"
view-on-remote: "正確な情報を見る"
renoted-by: "{user}がRenote"
error:
title: '問題が発生しました'
retry: 'やり直す'
@ -427,6 +431,10 @@ common/views/components/visibility-chooser.vue:
specified: "ダイレクト"
specified-desc: "指定したユーザーにのみ公開"
private: "非公開"
local-public: "公開 (ローカルのみ)"
local-public-desc: "リモートへは公開しない"
local-home: "ホーム (ローカルのみ)"
local-followers: "フォロワー (ローカルのみ)"
common/views/components/trends.vue:
count: "{}人が投稿"
empty: "トレンドなし"
@ -636,12 +644,10 @@ desktop/views/components/messaging-window.vue:
desktop/views/components/note-detail.vue:
private: "この投稿は非公開です"
deleted: "この投稿は削除されました"
reposted-by: "{}がRenote"
location: "位置情報"
renote: "Renote"
add-reaction: "リアクション"
desktop/views/components/note.vue:
reposted-by: "{}がRenote"
reply: "返信"
renote: "Renote"
add-reaction: "リアクション"
@ -676,6 +682,7 @@ desktop/views/components/post-form.vue:
create-poll: "アンケートを作成"
text-remain: "残り{}文字"
recent-tags: "最近"
local-only-message: "この投稿はローカルにのみ公開されます"
click-to-tagging: "クリックでタグ付け"
visibility: "公開範囲"
geolocation-alert: "お使いの端末は位置情報に対応していません"
@ -693,6 +700,7 @@ desktop/views/components/renote-form.vue:
quote: "引用する..."
cancel: "キャンセル"
renote: "Renote"
renote-home: "Renote (Home)"
reposting: "しています..."
success: "Renoteしました"
failure: "Renoteに失敗しました"
@ -707,6 +715,7 @@ desktop/views/components/settings.vue:
profile: "プロフィール"
notification: "通知"
apps: "アプリ"
tags: "ハッシュタグ"
mute-and-block: "ミュート/ブロック"
blocking: "ブロック"
security: "セキュリティ"
@ -749,6 +758,7 @@ desktop/views/components/settings.vue:
show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する"
show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する"
show-maps: "マップの自動展開"
remain-deleted-note: "削除された投稿を表示し続ける"
deck-column-align: "デッキのカラムの位置"
deck-column-align-center: "中央"
deck-column-align-left: "左"
@ -921,7 +931,7 @@ admin/views/index.vue:
emoji: "カスタム絵文字"
moderators: "モデレーター"
users: "ユーザー"
update: "更新"
federation: "連合"
announcements: "お知らせ"
hashtags: "ハッシュタグ"
back-to-misskey: "Misskeyに戻る"
@ -981,6 +991,12 @@ admin/views/instance.vue:
invite: "招待"
save: "保存"
saved: "保存しました"
user-recommendation-config: "おすすめユーザー"
enable-external-user-recommendation: "外部ユーザーレコメンデーションを有効にする"
external-user-recommendation-engine: "エンジン"
external-user-recommendation-engine-desc: "例: https://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-misskey-api.cgi?{{host}}+{{user}}+{{limit}}+{{offset}}"
external-user-recommendation-timeout: "タイムアウト"
external-user-recommendation-timeout-desc: "ミリ秒単位 (例: 300000)"
admin/views/charts.vue:
title: "チャート"
per-day: "1日ごと"
@ -1007,18 +1023,35 @@ admin/views/charts.vue:
network-time: "応答時間"
network-usage: "通信量"
admin/views/users.vue:
suspend-user: "ユーザーの凍結"
operation: "操作"
username-or-userid: "ユーザー名またはユーザーID"
user-not-found: "ユーザーが見つかりません"
lookup: "照会"
reset-password: "パスワードをリセット"
password-updated: "パスワードは現在「{password}」です"
suspend: "凍結"
suspended: "凍結しました"
unsuspend-user: "ユーザーの凍結の解除"
unsuspend: "凍結の解除"
unsuspended: "凍結を解除しました"
verify-user: "ユーザーの公式アカウント設定"
verify: "公式アカウントにする"
verified: "公式アカウントにしました"
unverify-user: "ユーザーの公式アカウント解除"
unverify: "公式アカウントを解除する"
unverified: "公式アカウントを解除しました"
users:
title: "ユーザー"
sort:
title: "ソート"
createdAtAsc: "登録日時が古い順"
createdAtDesc: "登録日時が新しい順"
updatedAtAsc: "更新日時が古い順"
updatedAtDesc: "更新日時が新しい順"
origin:
title: "オリジン"
combined: "ローカル+リモート"
local: "ローカル"
remote: "リモート"
createdAt: "登録日時"
updatedAt: "更新日時"
admin/views/moderators.vue:
add-moderator:
title: "モデレーターの登録"
@ -1201,14 +1234,12 @@ mobile/views/components/friends-maker.vue:
refresh: "もっと見る"
close: "閉じる"
mobile/views/components/note.vue:
reposted-by: "{}がRenote"
private: "この投稿は非公開です"
deleted: "この投稿は削除されました"
location: "位置情報"
mobile/views/components/note-detail.vue:
reply: "返信"
reaction: "リアクション"
reposted-by: "{}がRenote"
private: "この投稿は非公開です"
deleted: "この投稿は削除されました"
location: "位置情報"

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,8 @@
{
"name": "misskey",
"author": "syuilo <i@syuilo.com>",
"version": "10.54.0",
"clientVersion": "2.0.11894",
"version": "10.57.2",
"clientVersion": "2.0.12088",
"codename": "nighthike",
"main": "./built/index.js",
"private": true,
@ -47,14 +47,14 @@
"@types/is-url": "1.2.28",
"@types/js-yaml": "3.11.2",
"@types/katex": "0.5.0",
"@types/koa": "2.0.46",
"@types/koa": "2.0.47",
"@types/koa-bodyparser": "5.0.1",
"@types/koa-compress": "2.0.8",
"@types/koa-favicon": "2.0.19",
"@types/koa-logger": "3.1.1",
"@types/koa-mount": "3.0.1",
"@types/koa-multer": "1.0.0",
"@types/koa-router": "7.0.33",
"@types/koa-router": "7.0.35",
"@types/koa-send": "4.1.1",
"@types/koa-views": "2.0.3",
"@types/koa__cors": "2.2.3",
@ -63,13 +63,14 @@
"@types/mocha": "5.2.5",
"@types/mongodb": "3.1.14",
"@types/ms": "0.7.30",
"@types/node": "10.12.2",
"@types/node": "10.12.10",
"@types/oauth": "0.9.1",
"@types/parsimmon": "1.10.0",
"@types/portscanner": "2.1.0",
"@types/pug": "2.0.4",
"@types/qrcode": "1.3.0",
"@types/ratelimiter": "2.1.28",
"@types/redis": "2.8.7",
"@types/redis": "2.8.8",
"@types/request": "2.48.1",
"@types/request-promise-native": "1.0.15",
"@types/rimraf": "2.0.2",
@ -77,16 +78,16 @@
"@types/sharp": "0.21.0",
"@types/showdown": "1.7.5",
"@types/speakeasy": "2.0.3",
"@types/systeminformation": "3.23.0",
"@types/systeminformation": "3.23.1",
"@types/tinycolor2": "1.4.1",
"@types/tmp": "0.0.33",
"@types/uuid": "3.4.4",
"@types/webpack": "4.4.18",
"@types/webpack": "4.4.19",
"@types/webpack-stream": "3.2.10",
"@types/websocket": "0.0.40",
"@types/ws": "6.0.1",
"animejs": "2.2.0",
"apexcharts": "2.2.0",
"apexcharts": "2.2.3",
"autobind-decorator": "2.2.1",
"autosize": "4.0.2",
"autwh": "0.1.0",
@ -108,7 +109,7 @@
"diskusage": "0.2.5",
"double-ended-queue": "2.1.0-0",
"elasticsearch": "15.2.0",
"emojilib": "2.3.0",
"emojilib": "2.4.0",
"escape-regexp": "0.0.1",
"eslint": "5.8.0",
"eslint-plugin-vue": "4.7.1",
@ -142,7 +143,7 @@
"json5": "2.1.0",
"json5-loader": "1.0.1",
"katex": "0.10.0",
"koa": "2.6.1",
"koa": "2.6.2",
"koa-bodyparser": "4.2.1",
"koa-compress": "3.0.0",
"koa-favicon": "2.0.1",
@ -170,6 +171,7 @@
"on-build-webpack": "0.1.0",
"os-utils": "0.0.14",
"parse5": "5.1.0",
"parsimmon": "1.12.0",
"portscanner": "2.2.0",
"postcss-loader": "3.0.0",
"progress-bar-webpack-plugin": "1.11.0",
@ -199,7 +201,7 @@
"stylus": "0.54.5",
"stylus-loader": "3.0.2",
"summaly": "2.2.0",
"systeminformation": "3.47.0",
"systeminformation": "3.49.3",
"syuilo-password-strength": "0.0.1",
"terser-webpack-plugin": "1.1.0",
"textarea-caret": "3.1.0",
@ -209,7 +211,7 @@
"ts-node": "7.0.1",
"tslint": "5.10.0",
"typescript": "3.1.6",
"typescript-eslint-parser": "21.0.0",
"typescript-eslint-parser": "21.0.1",
"uglify-es": "3.3.9",
"url-loader": "1.1.2",
"uuid": "3.3.2",
@ -218,13 +220,13 @@
"vue-color": "2.7.0",
"vue-content-loading": "1.5.3",
"vue-cropperjs": "2.2.2",
"vue-i18n": "8.3.1",
"vue-i18n": "8.3.2",
"vue-js-modal": "1.3.26",
"vue-loader": "15.4.2",
"vue-marquee-text-component": "1.1.0",
"vue-router": "3.0.1",
"vue-router": "3.0.2",
"vue-style-loader": "4.1.2",
"vue-svg-inline-loader": "1.2.1",
"vue-svg-inline-loader": "1.2.2",
"vue-template-compiler": "2.5.17",
"vuedraggable": "2.16.0",
"vuewordcloud": "18.7.11",
@ -232,10 +234,10 @@
"vuex-persistedstate": "2.5.4",
"web-push": "3.3.3",
"webfinger.js": "2.6.6",
"webpack": "4.25.1",
"webpack": "4.26.0",
"webpack-cli": "3.1.2",
"websocket": "1.0.28",
"ws": "6.1.0",
"ws": "6.1.2",
"xev": "2.0.1"
}
}

View File

@ -9,7 +9,7 @@
<ui-textarea v-model="announcement.text">
<span>{{ $t('text') }}</span>
</ui-textarea>
<ui-horizon-group>
<ui-horizon-group class="fit-bottom">
<ui-button @click="save()"><fa :icon="['far', 'save']"/> {{ $t('save') }}</ui-button>
<ui-button @click="remove(i)"><fa :icon="['far', 'trash-alt']"/> {{ $t('remove') }}</ui-button>
</ui-horizon-group>

View File

@ -38,7 +38,7 @@
<i slot="icon"><fa icon="link"/></i>
<span>{{ $t('add-emoji.url') }}</span>
</ui-input>
<ui-horizon-group>
<ui-horizon-group class="fit-bottom">
<ui-button @click="updateEmoji(emoji)"><fa :icon="['far', 'save']"/> {{ $t('emojis.update') }}</ui-button>
<ui-button @click="removeEmoji(emoji)"><fa :icon="['far', 'trash-alt']"/> {{ $t('emojis.remove') }}</ui-button>
</ui-horizon-group>

View File

@ -42,6 +42,16 @@
<section>
<ui-switch v-model="disableLocalTimeline">{{ $t('disable-local-timeline') }}</ui-switch>
</section>
<section>
<header>summaly Proxy</header>
<ui-input v-model="summalyProxy">URL</ui-input>
</section>
<section>
<header><fa :icon="faUserPlus"/> {{ $t('user-recommendation-config') }}</header>
<ui-switch v-model="enableExternalUserRecommendation">{{ $t('enable-external-user-recommendation') }}</ui-switch>
<ui-input v-model="externalUserRecommendationEngine" :disabled="!enableExternalUserRecommendation">{{ $t('external-user-recommendation-engine') }}<span slot="desc">{{ $t('external-user-recommendation-engine-desc') }}</span></ui-input>
<ui-input v-model="externalUserRecommendationTimeout" type="number" :disabled="!enableExternalUserRecommendation">{{ $t('external-user-recommendation-timeout') }}<span slot="suffix">ms</span><span slot="desc">{{ $t('external-user-recommendation-timeout-desc') }}</span></ui-input>
</section>
<section>
<ui-button @click="updateMeta">{{ $t('save') }}</ui-button>
</section>
@ -95,7 +105,7 @@ import Vue from 'vue';
import i18n from '../../i18n';
import { host } from '../../config';
import { toUnicode } from 'punycode';
import { faHeadset, faShieldAlt, faGhost } from '@fortawesome/free-solid-svg-icons';
import { faHeadset, faShieldAlt, faGhost, faUserPlus } from '@fortawesome/free-solid-svg-icons';
export default Vue.extend({
i18n: i18n('admin/views/instance.vue'),
@ -129,7 +139,11 @@ export default Vue.extend({
discordClientSecret: null,
proxyAccount: null,
inviteCode: null,
faHeadset, faShieldAlt, faGhost
enableExternalUserRecommendation: false,
externalUserRecommendationEngine: null,
externalUserRecommendationTimeout: null,
summalyProxy: null,
faHeadset, faShieldAlt, faGhost, faUserPlus
};
},
@ -158,6 +172,10 @@ export default Vue.extend({
this.enableDiscordIntegration = meta.enableDiscordIntegration;
this.discordClientId = meta.discordClientId;
this.discordClientSecret = meta.discordClientSecret;
this.enableExternalUserRecommendation = meta.enableExternalUserRecommendation;
this.externalUserRecommendationEngine = meta.externalUserRecommendationEngine;
this.externalUserRecommendationTimeout = meta.externalUserRecommendationTimeout;
this.summalyProxy = meta.summalyProxy;
});
},
@ -199,7 +217,11 @@ export default Vue.extend({
githubClientSecret: this.githubClientSecret,
enableDiscordIntegration: this.enableDiscordIntegration,
discordClientId: this.discordClientId,
discordClientSecret: this.discordClientSecret
discordClientSecret: this.discordClientSecret,
enableExternalUserRecommendation: this.enableExternalUserRecommendation,
externalUserRecommendationEngine: this.externalUserRecommendationEngine,
externalUserRecommendationTimeout: parseInt(this.externalUserRecommendationTimeout, 10),
summalyProxy: this.summalyProxy
}).then(() => {
this.$root.alert({
type: 'success',

View File

@ -1,42 +1,63 @@
<template>
<div class="ucnffhbtogqgscfmqcymwmmupoknpfsw">
<ui-card>
<div slot="title">{{ $t('verify-user') }}</div>
<div slot="title"><fa :icon="faTerminal"/> {{ $t('operation') }}</div>
<section class="fit-top">
<ui-input v-model="verifyUsername" type="text">
<span slot="prefix">@</span>
<ui-input v-model="target" type="text">
<span>{{ $t('username-or-userid') }}</span>
</ui-input>
<ui-button @click="verifyUser" :disabled="verifying">{{ $t('verify') }}</ui-button>
<ui-button @click="resetPassword"><fa :icon="faKey"/> {{ $t('reset-password') }}</ui-button>
<ui-horizon-group>
<ui-button @click="verifyUser" :disabled="verifying"><fa :icon="faCertificate"/> {{ $t('verify') }}</ui-button>
<ui-button @click="unverifyUser" :disabled="unverifying">{{ $t('unverify') }}</ui-button>
</ui-horizon-group>
<ui-horizon-group>
<ui-button @click="suspendUser" :disabled="suspending"><fa :icon="faSnowflake"/> {{ $t('suspend') }}</ui-button>
<ui-button @click="unsuspendUser" :disabled="unsuspending">{{ $t('unsuspend') }}</ui-button>
</ui-horizon-group>
<ui-button @click="showUser"><fa :icon="faSearch"/> {{ $t('lookup') }}</ui-button>
<ui-textarea v-if="user" :value="user | json5" readonly tall style="margin-top:16px;"></ui-textarea>
</section>
</ui-card>
<ui-card>
<div slot="title">{{ $t('unverify-user') }}</div>
<div slot="title"><fa :icon="faUsers"/> {{ $t('users.title') }}</div>
<section class="fit-top">
<ui-input v-model="unverifyUsername" type="text">
<span slot="prefix">@</span>
</ui-input>
<ui-button @click="unverifyUser" :disabled="unverifying">{{ $t('unverify') }}</ui-button>
</section>
</ui-card>
<ui-card>
<div slot="title">{{ $t('suspend-user') }}</div>
<section class="fit-top">
<ui-input v-model="suspendUsername" type="text">
<span slot="prefix">@</span>
</ui-input>
<ui-button @click="suspendUser" :disabled="suspending">{{ $t('suspend') }}</ui-button>
</section>
</ui-card>
<ui-card>
<div slot="title">{{ $t('unsuspend-user') }}</div>
<section class="fit-top">
<ui-input v-model="unsuspendUsername" type="text">
<span slot="prefix">@</span>
</ui-input>
<ui-button @click="unsuspendUser" :disabled="unsuspending">{{ $t('unsuspend') }}</ui-button>
<ui-horizon-group inputs>
<ui-select v-model="sort">
<span slot="label">{{ $t('users.sort.title') }}</span>
<option value="-createdAt">{{ $t('users.sort.createdAtAsc') }}</option>
<option value="+createdAt">{{ $t('users.sort.createdAtDesc') }}</option>
<option value="-updatedAt">{{ $t('users.sort.updatedAtAsc') }}</option>
<option value="+updatedAt">{{ $t('users.sort.updatedAtDesc') }}</option>
</ui-select>
<ui-select v-model="origin">
<span slot="label">{{ $t('users.origin.title') }}</span>
<option value="combined">{{ $t('users.origin.combined') }}</option>
<option value="local">{{ $t('users.origin.local') }}</option>
<option value="remote">{{ $t('users.origin.remote') }}</option>
</ui-select>
</ui-horizon-group>
<div class="kofvwchc" v-for="user in users">
<div>
<a :href="user | userPage(null, true)">
<mk-avatar class="avatar" :user="user" :disable-link="true"/>
</a>
</div>
<div>
<header>
<b>{{ user | userName }}</b>
<span class="username">@{{ user | acct }}</span>
</header>
<div>
<span>{{ $t('users.updatedAt') }}: <mk-time :time="user.updatedAt" mode="detail"/></span>
</div>
<div>
<span>{{ $t('users.createdAt') }}: <mk-time :time="user.createdAt" mode="detail"/></span>
</div>
</div>
</div>
<ui-button v-if="existMore" @click="fetchUsers">{{ $t('@.load-more') }}</ui-button>
</section>
</ui-card>
</div>
@ -46,29 +67,89 @@
import Vue from 'vue';
import i18n from '../../i18n';
import parseAcct from "../../../../misc/acct/parse";
import { faCertificate, faUsers, faTerminal, faSearch, faKey } from '@fortawesome/free-solid-svg-icons';
import { faSnowflake } from '@fortawesome/free-regular-svg-icons';
export default Vue.extend({
i18n: i18n('admin/views/users.vue'),
data() {
return {
verifyUsername: null,
user: null,
target: null,
verifying: false,
unverifyUsername: null,
unverifying: false,
suspendUsername: null,
suspending: false,
unsuspendUsername: null,
unsuspending: false
unsuspending: false,
sort: '+createdAt',
origin: 'combined',
limit: 10,
offset: 0,
users: [],
existMore: false,
faTerminal, faCertificate, faUsers, faSnowflake, faSearch, faKey
};
},
watch: {
sort() {
this.users = [];
this.offset = 0;
this.fetchUsers();
},
origin() {
this.users = [];
this.offset = 0;
this.fetchUsers();
}
},
mounted() {
this.fetchUsers();
},
methods: {
async fetchUser() {
try {
return await this.$root.api('users/show', this.target.startsWith('@') ? parseAcct(this.target) : { userId: this.target });
} catch (e) {
if (e == 'user not found') {
this.$root.alert({
type: 'error',
text: this.$t('user-not-found')
});
} else {
this.$root.alert({
type: 'error',
text: e.toString()
});
}
}
},
async showUser() {
const user = await this.fetchUser();
this.$root.api('admin/show-user', { userId: user.id }).then(info => {
this.user = info;
});
},
async resetPassword() {
const user = await this.fetchUser();
this.$root.api('admin/reset-password', { userId: user.id }).then(res => {
this.$root.alert({
type: 'success',
text: this.$t('password-updated', { password: res.password })
});
});
},
async verifyUser() {
this.verifying = true;
const process = async () => {
const user = await this.$root.api('users/show', parseAcct(this.verifyUsername));
const user = await this.fetchUser();
await this.$root.api('admin/verify-user', { userId: user.id });
this.$root.alert({
type: 'success',
@ -90,7 +171,7 @@ export default Vue.extend({
this.unverifying = true;
const process = async () => {
const user = await this.$root.api('users/show', parseAcct(this.unverifyUsername));
const user = await this.fetchUser();
await this.$root.api('admin/unverify-user', { userId: user.id });
this.$root.alert({
type: 'success',
@ -112,7 +193,7 @@ export default Vue.extend({
this.suspending = true;
const process = async () => {
const user = await this.$root.api('users/show', parseAcct(this.suspendUsername));
const user = await this.fetchUser();
await this.$root.api('admin/suspend-user', { userId: user.id });
this.$root.alert({
type: 'success',
@ -134,7 +215,7 @@ export default Vue.extend({
this.unsuspending = true;
const process = async () => {
const user = await this.$root.api('users/show', parseAcct(this.unsuspendUsername));
const user = await this.fetchUser();
await this.$root.api('admin/unsuspend-user', { userId: user.id });
this.$root.alert({
type: 'success',
@ -150,6 +231,24 @@ export default Vue.extend({
});
this.unsuspending = false;
},
fetchUsers() {
this.$root.api('users', {
origin: this.origin,
sort: this.sort,
offset: this.offset,
limit: this.limit + 1
}).then(users => {
if (users.length == this.limit + 1) {
users.pop();
this.existMore = true;
} else {
this.existMore = false;
}
this.users = this.users.concat(users);
this.offset += this.limit;
});
}
}
});
@ -160,4 +259,24 @@ export default Vue.extend({
@media (min-width 500px)
padding 16px
.kofvwchc
display flex
padding 16px 0
border-top solid 1px var(--faceDivider)
> div:first-child
> a
> .avatar
width 64px
height 64px
> div:last-child
flex 1
padding-left 16px
> header
> .username
margin-left 8px
opacity 0.7
</style>

View File

@ -41,6 +41,7 @@
if (`${url.pathname}/`.startsWith('/dev/')) app = 'dev';
if (`${url.pathname}/`.startsWith('/auth/')) app = 'auth';
if (`${url.pathname}/`.startsWith('/admin/')) app = 'admin';
if (`${url.pathname}/`.startsWith('/test/')) app = 'test';
//#endregion
// Script version

View File

@ -5,7 +5,7 @@
<div class="icon" :class="type"><fa :icon="icon"/></div>
<header v-if="title" v-html="title"></header>
<div class="body" v-if="text" v-html="text"></div>
<ui-horizon-group no-grow class="buttons" v-if="!splash">
<ui-horizon-group no-grow class="buttons fit-bottom" v-if="!splash">
<ui-button @click="ok" primary autofocus>OK</ui-button>
<ui-button @click="cancel" v-if="showCancelButton">Cancel</ui-button>
</ui-horizon-group>

View File

@ -22,8 +22,8 @@
<div v-for="(x, i) in game.settings.map.join('')"
:data-none="x == ' '"
@click="onPixelClick(i, x)">
<template v-if="x == 'b'"><template v-if="$store.state.device.darkmode"><fa :icon="['far', 'circle']"/></template><template v-else><fa icon="circle"/></template></template>
<template v-if="x == 'w'"><template v-if="$store.state.device.darkmode"><fa :icon="['far', 'circle']"/></template><template v-else><fa icon="circle"/></template></template>
<fa v-if="x == 'b'" :icon="fasCircle"/>
<fa v-if="x == 'w'" :icon="farCircle"/>
</div>
</div>
</div>
@ -117,6 +117,8 @@
import Vue from 'vue';
import i18n from '../../../../../i18n';
import * as maps from '../../../../../../../games/reversi/maps';
import { faCircle as fasCircle } from '@fortawesome/free-solid-svg-icons';
import { faCircle as farCircle } from '@fortawesome/free-regular-svg-icons';
export default Vue.extend({
i18n: i18n('common/views/components/games/reversi/reversi.room.vue'),
@ -129,7 +131,8 @@ export default Vue.extend({
mapName: maps.eighteight.name,
maps: maps,
form: null,
messages: []
messages: [],
fasCircle, farCircle
};
},

View File

@ -65,5 +65,6 @@ export default Vue.extend({
max-height 100%
margin auto
cursor zoom-out
image-orientation from-image
</style>

View File

@ -10,13 +10,14 @@ import trends from './trends.vue';
import analogClock from './analog-clock.vue';
import menu from './menu.vue';
import noteHeader from './note-header.vue';
import renote from './renote.vue';
import signin from './signin.vue';
import signup from './signup.vue';
import forkit from './forkit.vue';
import acct from './acct.vue';
import avatar from './avatar.vue';
import nav from './nav.vue';
import misskeyFlavoredMarkdown from './misskey-flavored-markdown';
import misskeyFlavoredMarkdown from './misskey-flavored-markdown.vue';
import poll from './poll.vue';
import pollEditor from './poll-editor.vue';
import reactionIcon from './reaction-icon.vue';
@ -53,6 +54,7 @@ Vue.component('mk-trends', trends);
Vue.component('mk-analog-clock', analogClock);
Vue.component('mk-menu', menu);
Vue.component('mk-note-header', noteHeader);
Vue.component('mk-renote', renote);
Vue.component('mk-signin', signin);
Vue.component('mk-signup', signup);
Vue.component('mk-forkit', forkit);

View File

@ -1,11 +1,39 @@
import Vue, { VNode } from 'vue';
import { length } from 'stringz';
import { Node } from '../../../../../mfm/parser';
import parse from '../../../../../mfm/parse';
import getAcct from '../../../../../misc/acct/render';
import MkUrl from './url.vue';
import { concat } from '../../../../../prelude/array';
import MkFormula from './formula.vue';
import MkGoogle from './google.vue';
import { toUnicode } from 'punycode';
import syntaxHighlight from '../../../../../mfm/syntax-highlight';
function getTextCount(tokens: Node[]): number {
let count = 0;
const extract = (tokens: Node[]) => {
tokens.filter(x => x.name === 'text').forEach(x => {
count += length(x.props.text);
});
tokens.filter(x => x.children).forEach(x => {
extract(x.children);
});
};
extract(tokens);
return count;
}
function getChildrenCount(tokens: Node[]): number {
let count = 0;
const extract = (tokens: Node[]) => {
tokens.filter(x => x.children).forEach(x => {
count++;
extract(x.children);
});
};
extract(tokens);
return count;
}
export default Vue.component('misskey-flavored-markdown', {
props: {
@ -21,6 +49,10 @@ export default Vue.component('misskey-flavored-markdown', {
type: Boolean,
default: true
},
author: {
type: Object,
default: null
},
i: {
type: Object,
default: null
@ -31,23 +63,24 @@ export default Vue.component('misskey-flavored-markdown', {
},
render(createElement) {
let ast: any[];
if (this.text == null || this.text == '') return;
let ast: Node[];
if (this.ast == null) {
// Parse text to ast
ast = parse(this.text);
} else {
ast = this.ast as any[];
ast = this.ast as Node[];
}
let bigCount = 0;
let motionCount = 0;
// Parse ast to DOM
const els = concat(ast.map((token): VNode[] => {
switch (token.type) {
const genEl = (ast: Node[]) => concat(ast.map((token): VNode[] => {
switch (token.name) {
case 'text': {
const text = token.content.replace(/(\r\n|\n|\r)/g, '\n');
const text = token.props.text.replace(/(\r\n|\n|\r)/g, '\n');
if (this.shouldBreak) {
const x = text.split('\n')
@ -60,12 +93,12 @@ export default Vue.component('misskey-flavored-markdown', {
}
case 'bold': {
return [createElement('b', token.bold)];
return [createElement('b', genEl(token.children))];
}
case 'big': {
bigCount++;
const isLong = length(token.big) > 10;
const isLong = getTextCount(token.children) > 10 || getChildrenCount(token.children) > 5;
const isMany = bigCount > 3;
return (createElement as any)('strong', {
attrs: {
@ -75,12 +108,12 @@ export default Vue.component('misskey-flavored-markdown', {
name: 'animate-css',
value: { classes: 'tada', iteration: 'infinite' }
}]
}, token.big);
}, genEl(token.children));
}
case 'motion': {
motionCount++;
const isLong = length(token.motion) > 10;
const isLong = getTextCount(token.children) > 10 || getChildrenCount(token.children) > 5;
const isMany = motionCount > 3;
return (createElement as any)('span', {
attrs: {
@ -90,13 +123,14 @@ export default Vue.component('misskey-flavored-markdown', {
name: 'animate-css',
value: { classes: 'rubberBand', iteration: 'infinite' }
}]
}, token.motion);
}, genEl(token.children));
}
case 'url': {
return [createElement(MkUrl, {
key: Math.random(),
props: {
url: token.content,
url: token.props.url,
target: '_blank',
style: 'color:var(--mfmLink);'
}
@ -107,75 +141,75 @@ export default Vue.component('misskey-flavored-markdown', {
return [createElement('a', {
attrs: {
class: 'link',
href: token.url,
href: token.props.url,
target: '_blank',
title: token.url,
title: token.props.url,
style: 'color:var(--mfmLink);'
}
}, token.title)];
}, genEl(token.children))];
}
case 'mention': {
const host = token.props.host == null && this.author && this.author.host != null ? this.author.host : token.props.host;
const canonical = host != null ? `@${token.props.username}@${toUnicode(host)}` : `@${token.props.username}`;
return (createElement as any)('router-link', {
key: Math.random(),
attrs: {
to: `/${token.canonical}`,
dataIsMe: (this as any).i && getAcct((this as any).i) == getAcct(token),
to: `/${canonical}`,
// TODO
//dataIsMe: (this as any).i && getAcct((this as any).i) == getAcct(token),
style: 'color:var(--mfmMention);'
},
directives: [{
name: 'user-preview',
value: token.canonical
value: canonical
}]
}, token.canonical);
}, canonical);
}
case 'hashtag': {
return [createElement('router-link', {
key: Math.random(),
attrs: {
to: `/tags/${encodeURIComponent(token.hashtag)}`,
to: `/tags/${encodeURIComponent(token.props.hashtag)}`,
style: 'color:var(--mfmHashtag);'
}
}, token.content)];
}, `#${token.props.hashtag}`)];
}
case 'code': {
case 'blockCode': {
return [createElement('pre', {
class: 'code'
}, [
createElement('code', {
domProps: {
innerHTML: token.html
innerHTML: syntaxHighlight(token.props.code)
}
})
])];
}
case 'inline-code': {
case 'inlineCode': {
return [createElement('code', {
domProps: {
innerHTML: token.html
innerHTML: syntaxHighlight(token.props.code)
}
})];
}
case 'quote': {
const text2 = token.quote.replace(/(\r\n|\n|\r)/g, '\n');
if (this.shouldBreak) {
const x = text2.split('\n')
.map(t => [createElement('span', t), createElement('br')]);
x[x.length - 1].pop();
return [createElement('div', {
attrs: {
class: 'quote'
}
}, x)];
}, genEl(token.children))];
} else {
return [createElement('span', {
attrs: {
class: 'quote'
}
}, text2.replace(/\n/g, ' '))];
}, genEl(token.children))];
}
}
@ -184,15 +218,16 @@ export default Vue.component('misskey-flavored-markdown', {
attrs: {
class: 'title'
}
}, token.title)];
}, genEl(token.children))];
}
case 'emoji': {
const customEmojis = (this.$root.getMetaSync() || { emojis: [] }).emojis || [];
return [createElement('mk-emoji', {
key: Math.random(),
attrs: {
emoji: token.emoji,
name: token.name
emoji: token.props.emoji,
name: token.props.name
},
props: {
customEmojis: this.customEmojis || customEmojis
@ -203,8 +238,9 @@ export default Vue.component('misskey-flavored-markdown', {
case 'math': {
//const MkFormula = () => import('./formula.vue').then(m => m.default);
return [createElement(MkFormula, {
key: Math.random(),
props: {
formula: token.formula
formula: token.props.formula
}
})];
}
@ -212,22 +248,22 @@ export default Vue.component('misskey-flavored-markdown', {
case 'search': {
//const MkGoogle = () => import('./google.vue').then(m => m.default);
return [createElement(MkGoogle, {
key: Math.random(),
props: {
q: token.query
q: token.props.query
}
})];
}
default: {
console.log('unknown ast type:', token.type);
console.log('unknown ast type:', token.name);
return [];
}
}
}));
// el.tag === 'br' のとき i !== 0 が保証されるため、短絡評価により els[i - 1] は配列外参照しない
const _els = els.filter((el, i) => !(el.tag === 'br' && ['div', 'pre'].includes(els[i - 1].tag)));
return createElement('span', _els);
// Parse ast to DOM
return createElement('span', genEl(ast));
}
});

View File

@ -0,0 +1,57 @@
<template>
<mfm v-bind="$attrs" class="havbbuyv"/>
</template>
<script lang="ts">
import Vue from 'vue';
import Mfm from './mfm';
export default Vue.extend({
components: {
Mfm
}
});
</script>
<style lang="stylus" scoped>
.havbbuyv
>>> .title
display block
margin-bottom 4px
padding 4px
font-size 90%
text-align center
background var(--mfmTitleBg)
border-radius 4px
>>> .code
margin 8px 0
>>> .quote
margin 8px
padding 6px 12px
color var(--mfmQuote)
border-left solid 3px var(--mfmQuoteLine)
>>> code
padding 4px 8px
margin 0 0.5em
font-size 80%
color #525252
background #f8f8f8
border-radius 2px
>>> pre > code
padding 16px
margin 0
>>> [data-is-me]:after
content "you"
padding 0 4px
margin-left 4px
font-size 80%
color var(--primaryForeground)
background var(--primary)
border-radius 4px
</style>

View File

@ -0,0 +1,108 @@
<template>
<div class="puqkfets" :class="{ mini }">
<mk-avatar class="avatar" :user="note.user"/>
<fa icon="retweet"/>
<i18n path="@.renoted-by" tag="span">
<router-link class="name" :to="note.user | userPage" v-user-preview="note.userId" place="user">{{ note.user | userName }}</router-link>
</i18n>
<div class="info">
<span class="mobile" v-if="note.viaMobile"><fa icon="mobile-alt"/></span>
<mk-time :time="note.createdAt"/>
<span class="visibility" v-if="note.visibility != 'public'">
<fa v-if="note.visibility == 'home'" icon="home"/>
<fa v-if="note.visibility == 'followers'" icon="unlock"/>
<fa v-if="note.visibility == 'specified'" icon="envelope"/>
<fa v-if="note.visibility == 'private'" icon="lock"/>
</span>
<span class="localOnly" v-if="note.localOnly == true"><fa icon="heart"/></span>
</div>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import i18n from '../../../i18n';
export default Vue.extend({
i18n: i18n(),
props: {
note: {
type: Object,
required: true
},
mini: {
type: Boolean,
required: false,
default: false
}
}
});
</script>
<style lang="stylus" scoped>
.puqkfets
display flex
align-items center
padding 16px 32px 8px 32px
line-height 28px
white-space pre
color var(--renoteText)
background linear-gradient(to bottom, var(--renoteGradient) 0%, var(--face) 100%)
&.mini
padding 8px 16px
@media (min-width 500px)
padding 16px
@media (min-width 600px)
padding 16px 32px
> .avatar
@media (min-width 500px)
width 28px
height 28px
> .avatar
flex-shrink 0
display inline-block
width 28px
height 28px
margin 0 8px 0 0
border-radius 6px
> [data-icon]
margin-right 4px
> span
overflow hidden
flex-shrink 1
text-overflow ellipsis
white-space nowrap
> .name
font-weight bold
> .info
margin-left auto
font-size 0.9em
> .mobile
margin-right 8px
> .mk-time
flex-shrink 0
> .visibility
margin-left 8px
[data-icon]
margin-right 0
> .localOnly
margin-left 4px
[data-icon]
margin-right 0
</style>

View File

@ -12,9 +12,9 @@
</ui-input>
<ui-input v-if="user && user.twoFactorEnabled" v-model="token" type="number" required styl="fill"/>
<ui-button type="submit" :disabled="signing">{{ signing ? $t('signing-in') : $t('signin') }}</ui-button>
<p style="margin: 8px 0;"><a :href="`${apiUrl}/signin/twitter`">{{ $t('signin-with-twitter') }}</a></p>
<p style="margin: 8px 0;"><a :href="`${apiUrl}/signin/github`">{{ $t('signin-with-github') }}</a></p>
<p style="margin: 8px 0;"><a :href="`${apiUrl}/signin/discord`">{{ $t('signin-with-discord') /* TODO: Make these layouts better */ }}</a></p>
<p v-if="meta && meta.enableTwitterIntegration" style="margin: 8px 0;"><a :href="`${apiUrl}/signin/twitter`">{{ $t('signin-with-twitter') }}</a></p>
<p v-if="meta && meta.enableGithubIntegration" style="margin: 8px 0;"><a :href="`${apiUrl}/signin/github`">{{ $t('signin-with-github') }}</a></p>
<p v-if="meta && meta.enableDiscordIntegration" style="margin: 8px 0;"><a :href="`${apiUrl}/signin/discord`">{{ $t('signin-with-discord') /* TODO: Make these layouts better */ }}</a></p>
</form>
</template>
@ -41,9 +41,15 @@ export default Vue.extend({
password: '',
token: '',
apiUrl,
host: toUnicode(host)
host: toUnicode(host),
meta: null
};
},
created() {
this.$root.getMeta().then(meta => {
this.meta = meta;
});
},
methods: {
onUsernameChange() {
this.$root.api('users/show', {

View File

@ -53,8 +53,8 @@ export default Vue.extend({
ago >= 3600 ? this.$t('@.time.hours_ago') .replace('{}', (~~(ago / 3600)).toString()) :
ago >= 60 ? this.$t('@.time.minutes_ago').replace('{}', (~~(ago / 60)).toString()) :
ago >= 10 ? this.$t('@.time.seconds_ago').replace('{}', (~~(ago % 60)).toString()) :
ago >= 0 ? this.$t('@.time.just_now') :
ago < 0 ? this.$t('@.time.future') :
ago >= -1 ? this.$t('@.time.just_now') :
ago < -1 ? this.$t('@.time.future') :
this.$t('@.time.unknown'));
}
},

View File

@ -27,9 +27,17 @@ export default Vue.extend({
<style lang="stylus" scoped>
.vnxwkwuf
margin 16px 0
&.inputs
margin 32px 0
&.fit-top
margin-top 0
&.fit-bottom
margin-bottom 0
&:not(.noGrow)
display flex
@ -37,5 +45,6 @@ export default Vue.extend({
flex 1
> *:not(:last-child)
margin-right 16px
margin-right 16px !important
</style>

View File

@ -9,27 +9,30 @@
<div class="prefix" ref="prefix"><slot name="prefix"></slot></div>
<template v-if="type != 'file'">
<input ref="input"
:type="type"
v-model="v"
:disabled="disabled"
:required="required"
:readonly="readonly"
:pattern="pattern"
:autocomplete="autocomplete"
:spellcheck="spellcheck"
@focus="focused = true"
@blur="focused = false">
:type="type"
v-model="v"
:disabled="disabled"
:required="required"
:readonly="readonly"
:pattern="pattern"
:autocomplete="autocomplete"
:spellcheck="spellcheck"
@focus="focused = true"
@blur="focused = false"
>
</template>
<template v-else>
<input ref="input"
type="text"
:value="placeholder"
readonly
@click="chooseFile">
type="text"
:value="placeholder"
readonly
@click="chooseFile"
>
<input ref="file"
type="file"
:value="value"
@change="onChangeFile">
type="file"
:value="value"
@change="onChangeFile"
>
</template>
<div class="suffix" ref="suffix"><slot name="suffix"></slot></div>
</div>
@ -325,6 +328,9 @@ root(fill)
margin 6px 0
font-size 13px
&:empty
display none
*
margin 0

View File

@ -1,15 +1,17 @@
<template>
<div class="ui-select" :class="[{ focused, filled }, styl]">
<div class="ui-select" :class="[{ focused, disabled, filled, inline }, styl]">
<div class="icon" ref="icon"><slot name="icon"></slot></div>
<div class="input" @click="focus">
<span class="label" ref="label"><slot name="label"></slot></span>
<div class="prefix" ref="prefix"><slot name="prefix"></slot></div>
<select ref="input"
:value="v"
:required="required"
@input="$emit('input', $event.target.value)"
@focus="focused = true"
@blur="focused = false">
:value="v"
:required="required"
:disabled="disabled"
@input="$emit('input', $event.target.value)"
@focus="focused = true"
@blur="focused = false"
>
<slot></slot>
</select>
<div class="suffix"><slot name="suffix"></slot></div>
@ -22,6 +24,11 @@
import Vue from 'vue';
export default Vue.extend({
inject: {
horizonGrouped: {
default: false
}
},
props: {
value: {
required: false
@ -30,11 +37,22 @@ export default Vue.extend({
type: Boolean,
required: false
},
disabled: {
type: Boolean,
required: false
},
styl: {
type: String,
required: false,
default: 'line'
}
},
inline: {
type: Boolean,
required: false,
default(): boolean {
return this.horizonGrouped;
}
},
},
data() {
return {
@ -122,7 +140,7 @@ root(fill)
transition-duration 0.3s
font-size 16px
line-height 32px
color rgba(#000, 0.54)
color var(--inputLabel)
pointer-events none
//will-change transform
transform-origin top left
@ -171,6 +189,9 @@ root(fill)
margin 6px 0
font-size 13px
&:empty
display none
*
margin 0
@ -200,4 +221,14 @@ root(fill)
&:not(.fill)
root(false)
&.inline
display inline-block
margin 0
&.disabled
opacity 0.7
&, *
cursor not-allowed !important
</style>

View File

@ -126,6 +126,8 @@ root(fill)
> textarea
display block
width 100%
min-width 100%
max-width 100%
min-height 100px
padding 0
font inherit
@ -143,6 +145,9 @@ root(fill)
font-size 13px
opacity 0.7
&:empty
display none
*
margin 0

View File

@ -39,6 +39,7 @@
<div><fa icon="globe"/></div>
<div>
<span>{{ $t('local-public') }}</span>
<span>{{ $t('local-public-desc') }}</span>
</div>
</div>
<div @click="choose('local-home')" :class="{ active: v == 'local-home' }">

View File

@ -14,7 +14,7 @@
</div>
</header>
<div class="text">
<misskey-flavored-markdown v-if="note.text" :text="note.text" :customEmojis="note.emojis"/>
<misskey-flavored-markdown v-if="note.text" :text="note.text" :author="note.user" :custom-emojis="note.emojis"/>
</div>
</div>
</div>

View File

@ -1,3 +1,10 @@
import Vue from 'vue';
import * as JSON5 from 'json5';
Vue.filter('json5', x => {
return JSON5.stringify(x, null, 2);
});
require('./bytes');
require('./number');
require('./user');

View File

@ -1,6 +1,7 @@
import Vue from 'vue';
import getAcct from '../../../../../misc/acct/render';
import getUserName from '../../../../../misc/get-user-name';
import { url } from '../../../config';
Vue.filter('acct', user => {
return getAcct(user);
@ -10,6 +11,6 @@ Vue.filter('userName', user => {
return getUserName(user);
});
Vue.filter('userPage', (user, path?) => {
return `/@${Vue.filter('acct')(user)}${(path ? `/${path}` : '')}`;
Vue.filter('userPage', (user, path?, absolute = false) => {
return `${absolute ? url : ''}/@${Vue.filter('acct')(user)}${(path ? `/${path}` : '')}`;
});

View File

@ -9,7 +9,7 @@
<router-link :to="user | userPage" class="name">{{ user | userName }}</router-link>
<span class="username">@{{ user | acct }}</span>
<div class="description">
<misskey-flavored-markdown v-if="user.description" :text="user.description" :i="$store.state.i"/>
<misskey-flavored-markdown v-if="user.description" :text="user.description" :author="user" :i="$store.state.i"/>
</div>
</div>
</main>

View File

@ -3,7 +3,7 @@
<x-pie class="pie" :value="usage"/>
<div>
<p><fa icon="microchip"/>CPU</p>
<p>{{ meta.cpu.cores }} Cores</p>
<p>{{ meta.cpu.cores }} Logical cores</p>
<p>{{ meta.cpu.model }}</p>
</div>
</div>

View File

@ -2,7 +2,7 @@
<div class="mk-note-detail" :title="title">
<button
class="read-more"
v-if="p.reply && p.reply.replyId && conversation.length == 0"
v-if="appearNote.reply && appearNote.reply.replyId && conversation.length == 0"
:title="$t('title')"
@click="fetchConversation"
:disabled="conversationFetching"
@ -13,65 +13,66 @@
<div class="conversation">
<x-sub v-for="note in conversation" :key="note.id" :note="note"/>
</div>
<div class="reply-to" v-if="p.reply">
<x-sub :note="p.reply"/>
</div>
<div class="renote" v-if="isRenote">
<p>
<mk-avatar class="avatar" :user="note.user"/>
<fa icon="retweet"/>
<router-link class="name" :href="note.user | userPage">{{ note.user | userName }}</router-link>
<span>{{ this.$t('reposted-by').substr(0, this.$t('reposted-by').indexOf('{')) }}</span>
<a class="name" :href="note.user | userPage" v-user-preview="note.userId">{{ note.user | userName }}</a>
<span>{{ this.$t('reposted-by').substr(this.$t('reposted-by').indexOf('}') + 1) }}</span>
<mk-time :time="note.createdAt"/>
</p>
<div class="reply-to" v-if="appearNote.reply">
<x-sub :note="appearNote.reply"/>
</div>
<mk-renote class="renote" v-if="isRenote" :note="note"/>
<article>
<mk-avatar class="avatar" :user="p.user"/>
<mk-avatar class="avatar" :user="appearNote.user"/>
<header>
<router-link class="name" :to="p.user | userPage" v-user-preview="p.user.id">{{ p.user | userName }}</router-link>
<span class="username"><mk-acct :user="p.user"/></span>
<router-link class="time" :to="p | notePage">
<mk-time :time="p.createdAt"/>
</router-link>
<router-link class="name" :to="appearNote.user | userPage" v-user-preview="appearNote.user.id">{{ appearNote.user | userName }}</router-link>
<span class="username"><mk-acct :user="appearNote.user"/></span>
<div class="info">
<router-link class="time" :to="appearNote | notePage">
<mk-time :time="appearNote.createdAt"/>
</router-link>
<div class="visibility-info">
<span class="visibility" v-if="appearNote.visibility != 'public'">
<fa v-if="appearNote.visibility == 'home'" icon="home"/>
<fa v-if="appearNote.visibility == 'followers'" icon="unlock"/>
<fa v-if="appearNote.visibility == 'specified'" icon="envelope"/>
<fa v-if="appearNote.visibility == 'private'" icon="lock"/>
</span>
<span class="localOnly" v-if="appearNote.localOnly == true"><fa icon="heart"/></span>
</div>
</div>
</header>
<div class="body">
<p v-if="p.cw != null" class="cw">
<span class="text" v-if="p.cw != ''">{{ p.cw }}</span>
<p v-if="appearNote.cw != null" class="cw">
<span class="text" v-if="appearNote.cw != ''">{{ appearNote.cw }}</span>
<mk-cw-button v-model="showContent"/>
</p>
<div class="content" v-show="p.cw == null || showContent">
<div class="content" v-show="appearNote.cw == null || showContent">
<div class="text">
<span v-if="p.isHidden" style="opacity: 0.5">{{ $t('private') }}</span>
<span v-if="p.deletedAt" style="opacity: 0.5">{{ $t('deleted') }}</span>
<misskey-flavored-markdown v-if="p.text" :text="p.text" :i="$store.state.i" :customEmojis="p.emojis" />
<span v-if="appearNote.isHidden" style="opacity: 0.5">{{ $t('private') }}</span>
<span v-if="appearNote.deletedAt" style="opacity: 0.5">{{ $t('deleted') }}</span>
<misskey-flavored-markdown v-if="appearNote.text" :text="appearNote.text" :author="appearNote.user" :i="$store.state.i" :custom-emojis="appearNote.emojis" />
</div>
<div class="files" v-if="p.files.length > 0">
<mk-media-list :media-list="p.files" :raw="true"/>
<div class="files" v-if="appearNote.files.length > 0">
<mk-media-list :media-list="appearNote.files" :raw="true"/>
</div>
<mk-poll v-if="p.poll" :note="p"/>
<mk-poll v-if="appearNote.poll" :note="appearNote"/>
<mk-url-preview v-for="url in urls" :url="url" :key="url" :detail="true"/>
<a class="location" v-if="p.geo" :href="`https://maps.google.com/maps?q=${p.geo.coordinates[1]},${p.geo.coordinates[0]}`" target="_blank"><fa icon="map-marker-alt"/> {{ $t('location') }}</a>
<div class="map" v-if="p.geo" ref="map"></div>
<div class="renote" v-if="p.renote">
<mk-note-preview :note="p.renote"/>
<a class="location" v-if="appearNote.geo" :href="`https://maps.google.com/maps?q=${appearNote.geo.coordinates[1]},${appearNote.geo.coordinates[0]}`" target="_blank"><fa icon="map-marker-alt"/> {{ $t('location') }}</a>
<div class="map" v-if="appearNote.geo" ref="map"></div>
<div class="renote" v-if="appearNote.renote">
<mk-note-preview :note="appearNote.renote"/>
</div>
</div>
</div>
<footer>
<span class="app" v-if="note.app && $store.state.settings.showVia">via <b>{{ note.app.name }}</b></span>
<mk-reactions-viewer :note="p"/>
<mk-reactions-viewer :note="appearNote"/>
<button class="replyButton" @click="reply" :title="$t('reply')">
<template v-if="p.reply"><fa icon="reply-all"/></template>
<template v-if="appearNote.reply"><fa icon="reply-all"/></template>
<template v-else><fa icon="reply"/></template>
<p class="count" v-if="p.repliesCount > 0">{{ p.repliesCount }}</p>
<p class="count" v-if="appearNote.repliesCount > 0">{{ appearNote.repliesCount }}</p>
</button>
<button class="renoteButton" @click="renote" :title="$t('renote')">
<fa icon="retweet"/><p class="count" v-if="p.renoteCount > 0">{{ p.renoteCount }}</p>
<fa icon="retweet"/><p class="count" v-if="appearNote.renoteCount > 0">{{ appearNote.renoteCount }}</p>
</button>
<button class="reactionButton" :class="{ reacted: p.myReaction != null }" @click="react" ref="reactButton" :title="$t('add-reaction')">
<fa icon="plus"/><p class="count" v-if="p.reactions_count > 0">{{ p.reactions_count }}</p>
<button class="reactionButton" :class="{ reacted: appearNote.myReaction != null }" @click="react" ref="reactButton" :title="$t('add-reaction')">
<fa icon="plus"/><p class="count" v-if="appearNote.reactions_count > 0">{{ appearNote.reactions_count }}</p>
</button>
<button @click="menu" ref="menuButton">
<fa icon="ellipsis-h"/>
@ -132,23 +133,23 @@ export default Vue.extend({
this.note.poll == null);
},
p(): any {
appearNote(): any {
return this.isRenote ? this.note.renote : this.note;
},
reactionsCount(): number {
return this.p.reactionCounts
? sum(Object.values(this.p.reactionCounts))
return this.appearNote.reactionCounts
? sum(Object.values(this.appearNote.reactionCounts))
: 0;
},
title(): string {
return new Date(this.p.createdAt).toLocaleString();
return new Date(this.appearNote.createdAt).toLocaleString();
},
urls(): string[] {
if (this.p.text) {
const ast = parse(this.p.text);
if (this.appearNote.text) {
const ast = parse(this.appearNote.text);
return unique(ast
.filter(t => (t.type == 'url' || t.type == 'link') && !t.silent)
.map(t => t.url));
@ -162,7 +163,7 @@ export default Vue.extend({
// Get replies
if (!this.compact) {
this.$root.api('notes/replies', {
noteId: this.p.id,
noteId: this.appearNote.id,
limit: 8
}).then(replies => {
this.replies = replies;
@ -170,11 +171,11 @@ export default Vue.extend({
}
// Draw map
if (this.p.geo) {
if (this.appearNote.geo) {
const shouldShowMap = this.$store.getters.isSignedIn ? this.$store.state.settings.showMaps : true;
if (shouldShowMap) {
this.$root.os.getGoogleMaps().then(maps => {
const uluru = new maps.LatLng(this.p.geo.coordinates[1], this.p.geo.coordinates[0]);
const uluru = new maps.LatLng(this.appearNote.geo.coordinates[1], this.appearNote.geo.coordinates[0]);
const map = new maps.Map(this.$refs.map, {
center: uluru,
zoom: 15
@ -194,7 +195,7 @@ export default Vue.extend({
// Fetch conversation
this.$root.api('notes/conversation', {
noteId: this.p.replyId
noteId: this.appearNote.replyId
}).then(conversation => {
this.conversationFetching = false;
this.conversation = conversation.reverse();
@ -203,27 +204,27 @@ export default Vue.extend({
reply() {
this.$root.new(MkPostFormWindow, {
reply: this.p
reply: this.appearNote
});
},
renote() {
this.$root.new(MkRenoteFormWindow, {
note: this.p
note: this.appearNote
});
},
react() {
this.$root.new(MkReactionPicker, {
source: this.$refs.reactButton,
note: this.p
note: this.appearNote
});
},
menu() {
this.$root.new(MkNoteMenu, {
source: this.$refs.menuButton,
note: this.p
note: this.appearNote
});
}
}
@ -266,29 +267,8 @@ export default Vue.extend({
> *
border-bottom 1px solid var(--faceDivider)
> .renote
color var(--renoteText)
background linear-gradient(to bottom, var(--renoteGradient) 0%, var(--face) 100%)
> p
margin 0
padding 16px 32px
.avatar
display inline-block
width 28px
height 28px
margin 0 8px 0 0
border-radius 6px
[data-icon]
margin-right 4px
.name
font-weight bold
& + article
padding-top 8px
> .renote + article
padding-top 8px
> .reply-to
border-bottom 1px solid var(--faceDivider)
@ -335,12 +315,21 @@ export default Vue.extend({
margin 0
color var(--noteHeaderAcct)
> .time
> .info
position absolute
top 0
right 32px
font-size 1em
color var(--noteHeaderInfo)
> .time
color var(--noteHeaderInfo)
> .visibility-info
text-align: right
color var(--noteHeaderInfo)
> .localOnly
margin-left 4px
> .body
padding 8px 0

View File

@ -13,21 +13,7 @@
<div class="reply-to" v-if="appearNote.reply && (!$store.getters.isSignedIn || $store.state.settings.showReplyTarget)">
<x-sub :note="appearNote.reply" :mini="mini"/>
</div>
<div class="renote" v-if="isRenote">
<mk-avatar class="avatar" :user="note.user"/>
<fa icon="retweet"/>
<span>{{ this.$t('reposted-by').substr(0, this.$t('reposted-by').indexOf('{')) }}</span>
<router-link class="name" :to="note.user | userPage" v-user-preview="note.userId">{{ note.user | userName }}</router-link>
<span>{{ this.$t('reposted-by').substr(this.$t('reposted-by').indexOf('}') + 1) }}</span>
<mk-time :time="note.createdAt"/>
<span class="visibility" v-if="note.visibility != 'public'">
<fa v-if="note.visibility == 'home'" icon="home"/>
<fa v-if="note.visibility == 'followers'" icon="unlock"/>
<fa v-if="note.visibility == 'specified'" icon="envelope"/>
<fa v-if="note.visibility == 'private'" icon="lock"/>
</span>
<span class="localOnly" v-if="note.localOnly == true"><fa icon="heart"/></span>
</div>
<mk-renote class="renote" v-if="isRenote" :note="note"/>
<article>
<mk-avatar class="avatar" :user="appearNote.user"/>
<div class="main">
@ -41,7 +27,7 @@
<div class="text">
<span v-if="appearNote.isHidden" style="opacity: 0.5">{{ $t('private') }}</span>
<a class="reply" v-if="appearNote.reply"><fa icon="reply"/></a>
<misskey-flavored-markdown v-if="appearNote.text" :text="appearNote.text" :i="$store.state.i" :class="$style.text" :customEmojis="appearNote.emojis"/>
<misskey-flavored-markdown v-if="appearNote.text" :text="appearNote.text" :author="appearNote.user" :i="$store.state.i" :custom-emojis="appearNote.emojis"/>
<a class="rp" v-if="appearNote.renote">RN:</a>
</div>
<div class="files" v-if="appearNote.files.length > 0">
@ -185,56 +171,8 @@ export default Vue.extend({
border 2px solid var(--primaryAlpha03)
border-radius 4px
> .renote
display flex
align-items center
padding 16px 32px 8px 32px
line-height 28px
white-space pre
color var(--renoteText)
background linear-gradient(to bottom, var(--renoteGradient) 0%, var(--face) 100%)
.avatar
flex-shrink 0
display inline-block
width 28px
height 28px
margin 0 8px 0 0
border-radius 6px
[data-icon]
margin-right 4px
> span
flex-shrink 0
.name
overflow hidden
flex-shrink 1
text-overflow ellipsis
white-space nowrap
font-weight bold
> .mk-time
display block
margin-left auto
flex-shrink 0
font-size 0.9em
> .visibility
margin-left 8px
[data-icon]
margin-right 0
> .localOnly
margin-left 4px
[data-icon]
margin-right 0
& + article
padding-top 8px
> .renote + article
padding-top 8px
> article
display flex
@ -285,24 +223,6 @@ export default Vue.extend({
overflow-wrap break-word
color var(--noteText)
>>> .title
display block
margin-bottom 4px
padding 4px
font-size 90%
text-align center
background var(--mfmTitleBg)
border-radius 4px
>>> .code
margin 8px 0
>>> .quote
margin 8px
padding 6px 12px
color var(--mfmQuote)
border-left solid 3px var(--mfmQuoteLine)
> .reply
margin-right 8px
color var(--text)
@ -384,28 +304,3 @@ export default Vue.extend({
opacity 0.7
</style>
<style lang="stylus" module>
.text
code
padding 4px 8px
margin 0 0.5em
font-size 80%
color #525252
background #f8f8f8
border-radius 2px
pre > code
padding 16px
margin 0
[data-is-me]:after
content "you"
padding 0 4px
margin-left 4px
font-size 80%
color var(--primaryForeground)
background var(--primary)
border-radius 4px
</style>

View File

@ -111,7 +111,7 @@ export default Vue.extend({
useCw: false,
cw: null,
geo: null,
visibility: this.$store.state.settings.rememberNoteVisibility ? (this.$store.state.device.visibility || this.$store.state.settings.defaultNoteVisibility) : this.$store.state.settings.defaultNoteVisibility,
visibility: 'public',
visibleUsers: [],
localOnly: false,
autocomplete: null,
@ -195,6 +195,9 @@ export default Vue.extend({
});
}
// デフォルト公開範囲
this.applyVisibility(this.$store.state.settings.rememberNoteVisibility ? (this.$store.state.device.visibility || this.$store.state.settings.defaultNoteVisibility) : this.$store.state.settings.defaultNoteVisibility);
// 公開以外へのリプライ時は元の公開範囲を引き継ぐ
if (this.reply && ['home', 'followers', 'specified', 'private'].includes(this.reply.visibility)) {
this.visibility = this.reply.visibility;
@ -365,17 +368,21 @@ export default Vue.extend({
source: this.$refs.visibilityButton
});
w.$once('chosen', v => {
const m = v.match(/^local-(.+)/);
if (m) {
this.localOnly = true;
this.visibility = m[1];
} else {
this.localOnly = false;
this.visibility = v;
}
this.applyVisibility(v);
});
},
applyVisibility(v :string) {
const m = v.match(/^local-(.+)/);
if (m) {
this.localOnly = true;
this.visibility = m[1];
} else {
this.localOnly = false;
this.visibility = v;
}
},
addVisibleUser() {
this.$input({
title: this.$t('enter-username')

View File

@ -5,7 +5,8 @@
<footer>
<a class="quote" v-if="!quote" @click="onQuote">{{ $t('quote') }}</a>
<ui-button class="button cancel" inline @click="cancel">{{ $t('cancel') }}</ui-button>
<ui-button class="button ok" inline primary @click="ok" :disabled="wait">{{ wait ? this.$t('reposting') : this.$t('renote') }}</ui-button>
<ui-button class="button home" inline :primary="visibility != 'public'" @click="ok('home')" :disabled="wait">{{ wait ? this.$t('reposting') : this.$t('renote-home') }}</ui-button>
<ui-button class="button ok" inline :primary="visibility == 'public'" @click="ok('public')" :disabled="wait">{{ wait ? this.$t('reposting') : this.$t('renote') }}</ui-button>
</footer>
</template>
<template v-if="quote">
@ -24,14 +25,16 @@ export default Vue.extend({
data() {
return {
wait: false,
quote: false
quote: false,
visibility: this.$store.state.settings.defaultNoteVisibility
};
},
methods: {
ok() {
ok(v: string) {
this.wait = true;
this.$root.api('notes/create', {
renoteId: this.note.id
renoteId: this.note.id,
visibility: v || this.visibility
}).then(data => {
this.$emit('posted');
this.$notify(this.$t('success'));
@ -81,7 +84,11 @@ export default Vue.extend({
height 40px
&.cancel
right 280px
&.home
right 148px
font-size 13px
&.ok
right 16px

View File

@ -85,6 +85,9 @@
<option value="followers">{{ $t('@.note-visibility.followers') }}</option>
<option value="specified">{{ $t('@.note-visibility.specified') }}</option>
<option value="private">{{ $t('@.note-visibility.private') }}</option>
<option value="local-public">{{ $t('@.note-visibility.local-public') }}</option>
<option value="local-home">{{ $t('@.note-visibility.local-home') }}</option>
<option value="local-followers">{{ $t('@.note-visibility.local-followers') }}</option>
</ui-select>
</section>
</section>

View File

@ -4,7 +4,7 @@
<span v-if="note.isHidden" style="opacity: 0.5">{{ $t('private') }}</span>
<span v-if="note.deletedAt" style="opacity: 0.5">{{ $t('deleted') }}</span>
<a class="reply" v-if="note.replyId"><fa icon="reply"/></a>
<misskey-flavored-markdown v-if="note.text" :text="note.text" :i="$store.state.i" :custom-emojis="note.emojis"/>
<misskey-flavored-markdown v-if="note.text" :text="note.text" :author="note.user" :i="$store.state.i" :custom-emojis="note.emojis"/>
<a class="rp" v-if="note.renoteId" :href="`/notes/${note.renoteId}`">RN: ...</a>
</div>
<details v-if="note.files.length > 0">

View File

@ -7,7 +7,7 @@
<router-link :to="user | userPage" class="name">{{ user | userName }}</router-link>
<span class="username">@{{ user | acct }}</span>
<div class="description">
<misskey-flavored-markdown v-if="user.description" :text="user.description" :i="$store.state.i"/>
<misskey-flavored-markdown v-if="user.description" :text="user.description" :author="user" :i="$store.state.i"/>
</div>
</div>
</div>

View File

@ -22,7 +22,7 @@
</header>
<div class="info">
<div class="description">
<misskey-flavored-markdown v-if="user.description" :text="user.description" :i="$store.state.i"/>
<misskey-flavored-markdown v-if="user.description" :text="user.description" :author="user" :i="$store.state.i"/>
</div>
<div class="counts">
<div>

View File

@ -14,7 +14,7 @@
<mk-avatar class="avatar" :user="user" :disable-preview="true"/>
<div class="body">
<div class="description">
<misskey-flavored-markdown v-if="user.description" :text="user.description" :i="$store.state.i"/>
<misskey-flavored-markdown v-if="user.description" :text="user.description" :author="user" :i="$store.state.i"/>
</div>
<div class="info">
<span class="location" v-if="user.host === null && user.profile.location"><fa icon="map-marker"/> {{ user.profile.location }}</span>

View File

@ -115,10 +115,13 @@ import {
faChartLine,
faEllipsisV,
faStickyNote,
faUserClock,
faUserPlus,
faExternalLinkSquareAlt,
faSync,
faArrowLeft,
faMapMarker,
faRobot,
} from '@fortawesome/free-solid-svg-icons';
import {
@ -239,10 +242,13 @@ library.add(
faChartLine,
faEllipsisV,
faStickyNote,
faUserClock,
faUserPlus,
faExternalLinkSquareAlt,
faSync,
faArrowLeft,
faMapMarker,
faRobot,
farBell,
farEnvelope,

View File

@ -2,7 +2,7 @@
<div class="mk-note-detail">
<button
class="more"
v-if="p.reply && p.reply.replyId && conversation.length == 0"
v-if="appearNote.reply && appearNote.reply.replyId && conversation.length == 0"
@click="fetchConversation"
:disabled="conversationFetching"
>
@ -12,66 +12,65 @@
<div class="conversation">
<x-sub v-for="note in conversation" :key="note.id" :note="note"/>
</div>
<div class="reply-to" v-if="p.reply">
<x-sub :note="p.reply"/>
</div>
<div class="renote" v-if="isRenote">
<p>
<mk-avatar class="avatar" :user="note.user"/>
<fa icon="retweet"/>
<router-link class="name" :href="note.user | userPage">{{ note.user | userName }}</router-link>
<span>{{ this.$t('reposted-by').substr(0, this.$t('reposted-by').indexOf('{')) }}</span>
<a class="name" :href="note.user | userPage" v-user-preview="note.userId">{{ note.user | userName }}</a>
<span>{{ this.$t('reposted-by').substr(this.$t('reposted-by').indexOf('}') + 1) }}</span>
<mk-time :time="note.createdAt"/>
</p>
<div class="reply-to" v-if="appearNote.reply">
<x-sub :note="appearNote.reply"/>
</div>
<mk-renote class="renote" v-if="isRenote" :note="note" mini/>
<article>
<header>
<mk-avatar class="avatar" :user="p.user"/>
<mk-avatar class="avatar" :user="appearNote.user"/>
<div>
<router-link class="name" :to="p.user | userPage">{{ p.user | userName }}</router-link>
<span class="username"><mk-acct :user="p.user"/></span>
<router-link class="name" :to="appearNote.user | userPage">{{ appearNote.user | userName }}</router-link>
<span class="username"><mk-acct :user="appearNote.user"/></span>
</div>
</header>
<div class="body">
<p v-if="p.cw != null" class="cw">
<span class="text" v-if="p.cw != ''">{{ p.cw }}</span>
<p v-if="appearNote.cw != null" class="cw">
<span class="text" v-if="appearNote.cw != ''">{{ appearNote.cw }}</span>
<mk-cw-button v-model="showContent"/>
</p>
<div class="content" v-show="p.cw == null || showContent">
<div class="content" v-show="appearNote.cw == null || showContent">
<div class="text">
<span v-if="p.isHidden" style="opacity: 0.5">({{ $t('private') }})</span>
<span v-if="p.deletedAt" style="opacity: 0.5">({{ $t('deleted') }})</span>
<misskey-flavored-markdown v-if="p.text" :text="p.text" :i="$store.state.i" :customEmojis="p.emojis"/>
<span v-if="appearNote.isHidden" style="opacity: 0.5">({{ $t('private') }})</span>
<span v-if="appearNote.deletedAt" style="opacity: 0.5">({{ $t('deleted') }})</span>
<misskey-flavored-markdown v-if="appearNote.text" :text="appearNote.text" :author="appearNote.user" :i="$store.state.i" :custom-emojis="appearNote.emojis"/>
</div>
<div class="files" v-if="p.files.length > 0">
<mk-media-list :media-list="p.files" :raw="true"/>
<div class="files" v-if="appearNote.files.length > 0">
<mk-media-list :media-list="appearNote.files" :raw="true"/>
</div>
<mk-poll v-if="p.poll" :note="p"/>
<mk-poll v-if="appearNote.poll" :note="appearNote"/>
<mk-url-preview v-for="url in urls" :url="url" :key="url" :detail="true"/>
<a class="location" v-if="p.geo" :href="`https://maps.google.com/maps?q=${p.geo.coordinates[1]},${p.geo.coordinates[0]}`" target="_blank"><fa icon="map-marker-alt"/> {{ $t('location') }}</a>
<div class="map" v-if="p.geo" ref="map"></div>
<div class="renote" v-if="p.renote">
<mk-note-preview :note="p.renote"/>
<a class="location" v-if="appearNote.geo" :href="`https://maps.google.com/maps?q=${appearNote.geo.coordinates[1]},${appearNote.geo.coordinates[0]}`" target="_blank"><fa icon="map-marker-alt"/> {{ $t('location') }}</a>
<div class="map" v-if="appearNote.geo" ref="map"></div>
<div class="renote" v-if="appearNote.renote">
<mk-note-preview :note="appearNote.renote"/>
</div>
</div>
</div>
<router-link class="time" :to="p | notePage">
<mk-time :time="p.createdAt" mode="detail"/>
<router-link class="time" :to="appearNote | notePage">
<mk-time :time="appearNote.createdAt" mode="detail"/>
</router-link>
<div class="visibility-info">
<span class="visibility" v-if="appearNote.visibility != 'public'">
<fa v-if="appearNote.visibility == 'home'" icon="home"/>
<fa v-if="appearNote.visibility == 'followers'" icon="unlock"/>
<fa v-if="appearNote.visibility == 'specified'" icon="envelope"/>
<fa v-if="appearNote.visibility == 'private'" icon="lock"/>
</span>
<span class="localOnly" v-if="appearNote.localOnly == true"><fa icon="heart"/></span>
</div>
<footer>
<mk-reactions-viewer :note="p"/>
<mk-reactions-viewer :note="appearNote"/>
<button @click="reply" :title="$t('title')">
<template v-if="p.reply"><fa icon="reply-all"/></template>
<template v-if="appearNote.reply"><fa icon="reply-all"/></template>
<template v-else><fa icon="reply"/></template>
<p class="count" v-if="p.repliesCount > 0">{{ p.repliesCount }}</p>
<p class="count" v-if="appearNote.repliesCount > 0">{{ appearNote.repliesCount }}</p>
</button>
<button @click="renote" title="Renote">
<fa icon="retweet"/><p class="count" v-if="p.renoteCount > 0">{{ p.renoteCount }}</p>
<fa icon="retweet"/><p class="count" v-if="appearNote.renoteCount > 0">{{ appearNote.renoteCount }}</p>
</button>
<button :class="{ reacted: p.myReaction != null }" @click="react" ref="reactButton" :title="$t('title')">
<fa icon="plus"/><p class="count" v-if="p.reactions_count > 0">{{ p.reactions_count }}</p>
<button :class="{ reacted: appearNote.myReaction != null }" @click="react" ref="reactButton" :title="$t('title')">
<fa icon="plus"/><p class="count" v-if="appearNote.reactions_count > 0">{{ appearNote.reactions_count }}</p>
</button>
<button @click="menu" ref="menuButton">
<fa icon="ellipsis-h"/>
@ -130,19 +129,19 @@ export default Vue.extend({
this.note.poll == null);
},
p(): any {
appearNote(): any {
return this.isRenote ? this.note.renote : this.note;
},
reactionsCount(): number {
return this.p.reactionCounts
? sum(Object.values(this.p.reactionCounts))
return this.appearNote.reactionCounts
? sum(Object.values(this.appearNote.reactionCounts))
: 0;
},
urls(): string[] {
if (this.p.text) {
const ast = parse(this.p.text);
if (this.appearNote.text) {
const ast = parse(this.appearNote.text);
return unique(ast
.filter(t => (t.type == 'url' || t.type == 'link') && !t.silent)
.map(t => t.url));
@ -156,7 +155,7 @@ export default Vue.extend({
// Get replies
if (!this.compact) {
this.$root.api('notes/replies', {
noteId: this.p.id,
noteId: this.appearNote.id,
limit: 8
}).then(replies => {
this.replies = replies;
@ -164,11 +163,11 @@ export default Vue.extend({
}
// Draw map
if (this.p.geo) {
if (this.appearNote.geo) {
const shouldShowMap = this.$store.getters.isSignedIn ? this.$store.state.settings.showMaps : true;
if (shouldShowMap) {
this.$root.os.getGoogleMaps().then(maps => {
const uluru = new maps.LatLng(this.p.geo.coordinates[1], this.p.geo.coordinates[0]);
const uluru = new maps.LatLng(this.appearNote.geo.coordinates[1], this.appearNote.geo.coordinates[0]);
const map = new maps.Map(this.$refs.map, {
center: uluru,
zoom: 15
@ -188,7 +187,7 @@ export default Vue.extend({
// Fetch conversation
this.$root.api('notes/conversation', {
noteId: this.p.replyId
noteId: this.appearNote.replyId
}).then(conversation => {
this.conversationFetching = false;
this.conversation = conversation.reverse();
@ -197,20 +196,20 @@ export default Vue.extend({
reply() {
this.$post({
reply: this.p
reply: this.appearNote
});
},
renote() {
this.$post({
renote: this.p
renote: this.appearNote
});
},
react() {
this.$root.new(MkReactionPicker, {
source: this.$refs.reactButton,
note: this.p,
note: this.appearNote,
compact: true,
big: true
});
@ -219,7 +218,7 @@ export default Vue.extend({
menu() {
this.$root.new(MkNoteMenu, {
source: this.$refs.menuButton,
note: this.p,
note: this.appearNote,
compact: true
});
}
@ -268,29 +267,8 @@ export default Vue.extend({
> *
border-bottom 1px solid var(--faceDivider)
> .renote
color var(--renoteText)
background linear-gradient(to bottom, var(--renoteGradient) 0%, var(--face) 100%)
> p
margin 0
padding 16px 32px
.avatar
display inline-block
width 28px
height 28px
margin 0 8px 0 0
border-radius 6px
[data-icon]
margin-right 4px
.name
font-weight bold
& + article
padding-top 8px
> .renote + article
padding-top 8px
> .reply-to
border-bottom 1px solid var(--faceDivider)
@ -400,6 +378,12 @@ export default Vue.extend({
font-size 16px
color var(--noteHeaderInfo)
> .visibility-info
color var(--noteHeaderInfo)
> .localOnly
margin-left 4px
> footer
font-size 1.2em

View File

@ -9,21 +9,7 @@
<div class="reply-to" v-if="appearNote.reply && (!$store.getters.isSignedIn || $store.state.settings.showReplyTarget)">
<x-sub :note="appearNote.reply"/>
</div>
<div class="renote" v-if="isRenote">
<mk-avatar class="avatar" :user="note.user"/>
<fa icon="retweet"/>
<span>{{ this.$t('reposted-by').substr(0, this.$t('reposted-by').indexOf('{')) }}</span>
<router-link class="name" :to="note.user | userPage">{{ note.user | userName }}</router-link>
<span>{{ this.$t('reposted-by').substr(this.$t('reposted-by').indexOf('}') + 1) }}</span>
<mk-time :time="note.createdAt"/>
<span class="visibility" v-if="note.visibility != 'public'">
<fa v-if="note.visibility == 'home'" icon="home"/>
<fa v-if="note.visibility == 'followers'" icon="unlock"/>
<fa v-if="note.visibility == 'specified'" icon="envelope"/>
<fa v-if="note.visibility == 'private'" icon="lock"/>
</span>
<span class="localOnly" v-if="note.localOnly == true"><fa icon="heart"/></span>
</div>
<mk-renote class="renote" v-if="isRenote" :note="note" mini/>
<article>
<mk-avatar class="avatar" :user="appearNote.user" v-if="$store.state.device.postStyle != 'smart'"/>
<div class="main">
@ -37,7 +23,7 @@
<div class="text">
<span v-if="appearNote.isHidden" style="opacity: 0.5">({{ $t('private') }})</span>
<a class="reply" v-if="appearNote.reply"><fa icon="reply"/></a>
<misskey-flavored-markdown v-if="appearNote.text" :text="appearNote.text" :i="$store.state.i" :class="$style.text" :custom-emojis="appearNote.emojis"/>
<misskey-flavored-markdown v-if="appearNote.text" :text="appearNote.text" :author="appearNote.user" :i="$store.state.i" :custom-emojis="appearNote.emojis"/>
<a class="rp" v-if="appearNote.renote != null">RN:</a>
</div>
<div class="files" v-if="appearNote.files.length > 0">
@ -138,66 +124,8 @@ export default Vue.extend({
align-items center
margin-bottom 4px
> .renote
display flex
align-items center
padding 8px 16px
line-height 28px
white-space pre
color var(--renoteText)
background linear-gradient(to bottom, var(--renoteGradient) 0%, var(--face) 100%)
@media (min-width 500px)
padding 16px
@media (min-width 600px)
padding 16px 32px
.avatar
flex-shrink 0
display inline-block
width 20px
height 20px
margin 0 8px 0 0
border-radius 6px
@media (min-width 500px)
width 28px
height 28px
[data-icon]
margin-right 4px
> span
flex-shrink 0
.name
overflow hidden
flex-shrink 1
text-overflow ellipsis
white-space nowrap
font-weight bold
> .mk-time
display block
margin-left auto
flex-shrink 0
font-size 0.9em
> .visibility
margin-left 8px
[data-icon]
margin-right 0
> .localOnly
margin-left 4px
[data-icon]
margin-right 0
& + article
padding-top 8px
> .renote + article
padding-top 8px
> article
display flex
@ -260,24 +188,6 @@ export default Vue.extend({
overflow-wrap break-word
color var(--noteText)
>>> .title
display block
margin-bottom 4px
padding 4px
font-size 90%
text-align center
background var(--mfmTitleBg)
border-radius 4px
>>> .code
margin 8px 0
>>> .quote
margin 8px
padding 6px 12px
color var(--mfmQuote)
border-left solid 3px var(--mfmQuoteLine)
> .reply
margin-right 8px
color var(--noteText)
@ -287,15 +197,6 @@ export default Vue.extend({
font-style oblique
color var(--renoteText)
[data-is-me]:after
content "you"
padding 0 4px
margin-left 4px
font-size 80%
color var(--primaryForeground)
background var(--primary)
border-radius 4px
.mk-url-preview
margin-top 8px
@ -361,18 +262,3 @@ export default Vue.extend({
opacity 0.7
</style>
<style lang="stylus" module>
.text
code
padding 4px 8px
margin 0 0.5em
font-size 80%
color #525252
background #f8f8f8
border-radius 2px
pre > code
padding 16px
margin 0
</style>

View File

@ -100,7 +100,7 @@ export default Vue.extend({
files: [],
poll: false,
geo: null,
visibility: this.$store.state.settings.rememberNoteVisibility ? (this.$store.state.device.visibility || this.$store.state.settings.defaultNoteVisibility) : this.$store.state.settings.defaultNoteVisibility,
visibility: 'public',
visibleUsers: [],
localOnly: false,
useCw: false,
@ -184,6 +184,9 @@ export default Vue.extend({
});
}
// デフォルト公開範囲
this.applyVisibility(this.$store.state.settings.rememberNoteVisibility ? (this.$store.state.device.visibility || this.$store.state.settings.defaultNoteVisibility) : this.$store.state.settings.defaultNoteVisibility);
// 公開以外へのリプライ時は元の公開範囲を引き継ぐ
if (this.reply && ['home', 'followers', 'specified', 'private'].includes(this.reply.visibility)) {
this.visibility = this.reply.visibility;
@ -275,26 +278,19 @@ export default Vue.extend({
compact: true
});
w.$once('chosen', v => {
const m = v.match(/^local-(.+)/);
if (m) {
this.localOnly = true;
this.visibility = m[1];
} else {
this.localOnly = false;
this.visibility = v;
}
this.applyVisibility(v);
});
},
addVisibleUser() {
this.$input({
title: this.$t('username-prompt')
}).then(acct => {
if (acct.startsWith('@')) acct = acct.substr(1);
this.$root.api('users/show', parseAcct(acct)).then(user => {
this.visibleUsers.push(user);
});
});
applyVisibility(v :string) {
const m = v.match(/^local-(.+)/);
if (m) {
this.localOnly = true;
this.visibility = m[1];
} else {
this.localOnly = false;
this.visibility = v;
}
},
removeVisibleUser(user) {

View File

@ -4,7 +4,7 @@
<span v-if="note.isHidden" style="opacity: 0.5">({{ $t('private') }})</span>
<span v-if="note.deletedAt" style="opacity: 0.5">({{ $t('deleted') }})</span>
<a class="reply" v-if="note.replyId"><fa icon="reply"/></a>
<misskey-flavored-markdown v-if="note.text" :text="note.text" :i="$store.state.i" :custom-emojis="note.emojis"/>
<misskey-flavored-markdown v-if="note.text" :text="note.text" :author="note.user" :i="$store.state.i" :custom-emojis="note.emojis"/>
<a class="rp" v-if="note.renoteId">RN: ...</a>
</div>
<details v-if="note.files.length > 0">

View File

@ -15,23 +15,23 @@
</router-link>
<div class="links">
<ul>
<li><router-link to="/" :data-active="$route.name == 'index'"><i><fa icon="home"/></i>{{ $t('timeline') }}<i><fa icon="angle-right"/></i></router-link></li>
<li><router-link to="/i/notifications" :data-active="$route.name == 'notifications'"><i><fa :icon="['far', 'bell']"/></i>{{ $t('notifications') }}<i v-if="hasUnreadNotification" class="circle"><fa icon="circle"/></i><i><fa icon="angle-right"/></i></router-link></li>
<li><router-link to="/i/messaging" :data-active="$route.name == 'messaging'"><i><fa :icon="['far', 'comments']"/></i>{{ $t('@.messaging') }}<i v-if="hasUnreadMessagingMessage" class="circle"><fa icon="circle"/></i><i><fa icon="angle-right"/></i></router-link></li>
<li v-if="$store.getters.isSignedIn && ($store.state.i.isLocked || $store.state.i.carefulBot)"><router-link to="/i/received-follow-requests" :data-active="$route.name == 'received-follow-requests'"><i><fa :icon="['far', 'envelope']"/></i>{{ $t('follow-requests') }}<i v-if="$store.getters.isSignedIn && $store.state.i.pendingReceivedFollowRequestsCount" class="circle"><fa icon="circle"/></i><i><fa icon="angle-right"/></i></router-link></li>
<li><router-link to="/reversi" :data-active="$route.name == 'reversi'"><i><fa icon="gamepad"/></i>{{ $t('game') }}<i v-if="hasGameInvitation" class="circle"><fa icon="circle"/></i><i><fa icon="angle-right"/></i></router-link></li>
<li><router-link to="/" :data-active="$route.name == 'index'"><i><fa icon="home" fixed-width/></i>{{ $t('timeline') }}<i><fa icon="angle-right"/></i></router-link></li>
<li><router-link to="/i/notifications" :data-active="$route.name == 'notifications'"><i><fa :icon="['far', 'bell']" fixed-width/></i>{{ $t('notifications') }}<i v-if="hasUnreadNotification" class="circle"><fa icon="circle"/></i><i><fa icon="angle-right"/></i></router-link></li>
<li><router-link to="/i/messaging" :data-active="$route.name == 'messaging'"><i><fa :icon="['far', 'comments']" fixed-width/></i>{{ $t('@.messaging') }}<i v-if="hasUnreadMessagingMessage" class="circle"><fa icon="circle"/></i><i><fa icon="angle-right"/></i></router-link></li>
<li v-if="$store.getters.isSignedIn && ($store.state.i.isLocked || $store.state.i.carefulBot)"><router-link to="/i/received-follow-requests" :data-active="$route.name == 'received-follow-requests'"><i><fa :icon="['far', 'envelope']" fixed-width/></i>{{ $t('follow-requests') }}<i v-if="$store.getters.isSignedIn && $store.state.i.pendingReceivedFollowRequestsCount" class="circle"><fa icon="circle"/></i><i><fa icon="angle-right"/></i></router-link></li>
<li><router-link to="/reversi" :data-active="$route.name == 'reversi'"><i><fa icon="gamepad" fixed-width/></i>{{ $t('game') }}<i v-if="hasGameInvitation" class="circle"><fa icon="circle"/></i><i><fa icon="angle-right"/></i></router-link></li>
</ul>
<ul>
<li><router-link to="/i/widgets" :data-active="$route.name == 'widgets'"><i><fa :icon="['far', 'calendar-alt']"/></i>{{ $t('widgets') }}<i><fa icon="angle-right"/></i></router-link></li>
<li><router-link to="/i/favorites" :data-active="$route.name == 'favorites'"><i><fa icon="star"/></i>{{ $t('favorites') }}<i><fa icon="angle-right"/></i></router-link></li>
<li><router-link to="/i/lists" :data-active="$route.name == 'user-lists'"><i><fa icon="list"/></i>{{ $t('user-lists') }}<i><fa icon="angle-right"/></i></router-link></li>
<li><router-link to="/i/drive" :data-active="$route.name == 'drive'"><i><fa icon="cloud"/></i>{{ $t('@.drive') }}<i><fa icon="angle-right"/></i></router-link></li>
<li><router-link to="/i/widgets" :data-active="$route.name == 'widgets'"><i><fa :icon="['far', 'calendar-alt']" fixed-width/></i>{{ $t('widgets') }}<i><fa icon="angle-right"/></i></router-link></li>
<li><router-link to="/i/favorites" :data-active="$route.name == 'favorites'"><i><fa icon="star" fixed-width/></i>{{ $t('favorites') }}<i><fa icon="angle-right"/></i></router-link></li>
<li><router-link to="/i/lists" :data-active="$route.name == 'user-lists'"><i><fa icon="list" fixed-width/></i>{{ $t('user-lists') }}<i><fa icon="angle-right"/></i></router-link></li>
<li><router-link to="/i/drive" :data-active="$route.name == 'drive'"><i><fa icon="cloud" fixed-width/></i>{{ $t('@.drive') }}<i><fa icon="angle-right"/></i></router-link></li>
</ul>
<ul>
<li><a @click="search"><i><fa icon="search"/></i>{{ $t('search') }}<i><fa icon="angle-right"/></i></a></li>
<li><router-link to="/i/settings" :data-active="$route.name == 'settings'"><i><fa icon="cog"/></i>{{ $t('settings') }}<i><fa icon="angle-right"/></i></router-link></li>
<li v-if="$store.getters.isSignedIn && ($store.state.i.isAdmin || $store.state.i.isModerator)"><a href="/admin"><i><fa icon="terminal"/></i><span>{{ $t('admin') }}</span><i><fa icon="angle-right"/></i></a></li>
<li @click="dark"><p><template v-if="$store.state.device.darkmode"><i><fa icon="moon"/></i></template><template v-else><i><fa :icon="['far', 'moon']"/></i></template><span>{{ $t('darkmode') }}</span></p></li>
<li><a @click="search"><i><fa icon="search" fixed-width/></i>{{ $t('search') }}<i><fa icon="angle-right"/></i></a></li>
<li><router-link to="/i/settings" :data-active="$route.name == 'settings'"><i><fa icon="cog" fixed-width/></i>{{ $t('settings') }}<i><fa icon="angle-right"/></i></router-link></li>
<li v-if="$store.getters.isSignedIn && ($store.state.i.isAdmin || $store.state.i.isModerator)"><a href="/admin"><i><fa icon="terminal" fixed-width/></i><span>{{ $t('admin') }}</span><i><fa icon="angle-right"/></i></a></li>
<li @click="dark"><p><template v-if="$store.state.device.darkmode"><i><fa icon="moon" fixed-width/></i></template><template v-else><i><fa :icon="['far', 'moon']"/></i></template><span>{{ $t('darkmode') }}</span></p></li>
</ul>
</div>
<div class="announcements" v-if="announcements && announcements.length > 0">

View File

@ -80,6 +80,9 @@
<option value="followers">{{ $t('@.note-visibility.followers') }}</option>
<option value="specified">{{ $t('@.note-visibility.specified') }}</option>
<option value="private">{{ $t('@.note-visibility.private') }}</option>
<option value="local-public">{{ $t('@.note-visibility.local-public') }}</option>
<option value="local-home">{{ $t('@.note-visibility.local-home') }}</option>
<option value="local-followers">{{ $t('@.note-visibility.local-followers') }}</option>
</ui-select>
</section>
</section>

View File

@ -20,7 +20,7 @@
<span class="followed" v-if="user.isFollowed">{{ $t('follows-you') }}</span>
</div>
<div class="description">
<misskey-flavored-markdown v-if="user.description" :text="user.description" :i="$store.state.i"/>
<misskey-flavored-markdown v-if="user.description" :text="user.description" :author="user" :i="$store.state.i"/>
</div>
<div class="info">
<p class="location" v-if="user.host === null && user.profile.location">

View File

@ -31,7 +31,6 @@
<x-followers-you-know :user="user"/>
</div>
</section>
<p v-if="user.host === null">{{ $t('last-used-at') }}: <b><mk-time :time="user.lastUsedAt"/></b></p>
</div>
</template>
@ -90,7 +89,7 @@ export default Vue.extend({
@media (min-width 500px)
padding 10px 16px
> i
> [data-icon]
margin-right 6px
> .activity

View File

@ -0,0 +1,23 @@
import VueRouter from 'vue-router';
// Style
import './style.styl';
import init from '../init';
import Index from './views/index.vue';
init(launch => {
document.title = 'Misskey';
// Init router
const router = new VueRouter({
mode: 'history',
base: '/test/',
routes: [
{ path: '/', component: Index },
]
});
// Launch the app
launch(router);
});

View File

@ -0,0 +1,6 @@
@import "../app"
@import "../reset"
html
height 100%
background var(--bg)

View File

@ -0,0 +1,82 @@
<template>
<main>
<ui-card>
<div slot="title">MFM Playground</div>
<section class="fit-top">
<ui-textarea v-model="mfm">
<span>MFM</span>
</ui-textarea>
</section>
<section>
<header>Preview</header>
<misskey-flavored-markdown :text="mfm" :i="$store.state.i"/>
</section>
<section>
<header style="margin-bottom:0;">AST</header>
<ui-textarea v-model="mfmAst" readonly tall style="margin-top:16px;"></ui-textarea>
</section>
</ui-card>
<ui-card>
<div slot="title">Dialog Generator</div>
<section class="fit-top">
<ui-select v-model="dialogType" placeholder="">
<option value="info">Information</option>
<option value="success">Success</option>
<option value="warning">Warning</option>
<option value="error">Error</option>
</ui-select>
<ui-input v-model="dialogTitle">
<span>Title</span>
</ui-input>
<ui-input v-model="dialogText">
<span>Text</span>
</ui-input>
<ui-switch v-model="dialogShowCancelButton">With cancel button</ui-switch>
<ui-button @click="showDialog">Show</ui-button>
</section>
</ui-card>
</main>
</template>
<script lang="ts">
import Vue from 'vue';
import parse from '../../../../mfm/parse';
import * as JSON5 from 'json5';
export default Vue.extend({
data() {
return {
mfm: '',
dialogType: 'success',
dialogTitle: '',
dialogText: 'Hello World!',
dialogShowCancelButton: false
};
},
computed: {
mfmAst(): any {
return JSON5.stringify(parse(this.mfm), null, 2);
}
},
methods: {
showDialog() {
this.$root.alert({
type: this.dialogType,
title: this.dialogTitle,
text: this.dialogText,
showCancelButton: this.dialogShowCancelButton
});
}
}
});
</script>
<style lang="stylus" scoped>
main
max-width 700px
margin 0 auto
</style>

View File

@ -37,15 +37,8 @@ export type Source = {
proxy?: string;
summalyProxy?: string;
accesslog?: string;
github_bot?: {
hook_secret: string;
username: string;
};
/**
* Service Worker
*/

View File

@ -14,11 +14,10 @@ import * as portscanner from 'portscanner';
import isRoot = require('is-root');
import Xev from 'xev';
import * as program from 'commander';
import * as sysUtils from 'systeminformation';
import mongo, { nativeDbConn } from './db/mongodb';
import Logger from './misc/logger';
import EnvironmentInfo from './misc/environmentInfo';
import MachineInfo from './misc/machineInfo';
import serverStats from './daemons/server-stats';
import notesStats from './daemons/notes-stats';
import loadConfig from './config/load';
@ -42,8 +41,6 @@ program
.parse(process.argv);
//#endregion
main();
/**
* Init process
*/
@ -105,6 +102,43 @@ async function workerMain() {
}
}
const runningNodejsVersion = process.version.slice(1).split('.').map(x => parseInt(x, 10));
const requiredNodejsVersion = [10, 0, 0];
const satisfyNodejsVersion = !lessThan(runningNodejsVersion, requiredNodejsVersion);
function isWellKnownPort(port: number): boolean {
return port < 1024;
}
async function isPortAvailable(port: number): Promise<boolean> {
return await portscanner.checkPortStatus(port, '127.0.0.1') === 'closed';
}
async function showMachine() {
const logger = new Logger('Machine');
logger.info(`Hostname: ${os.hostname()}`);
logger.info(`Platform: ${process.platform}`);
logger.info(`Architecture: ${process.arch}`);
logger.info(`CPU: ${os.cpus().length} core`);
const mem = await sysUtils.mem();
const totalmem = (mem.total / 1024 / 1024 / 1024).toFixed(1);
const availmem = (mem.available / 1024 / 1024 / 1024).toFixed(1);
logger.info(`MEM: ${totalmem}GB (available: ${availmem}GB)`);
}
function showEnvironment(): void {
const env = process.env.NODE_ENV;
const logger = new Logger('Env');
logger.info(typeof env == 'undefined' ? 'NODE_ENV is not set' : `NODE_ENV: ${env}`);
if (env !== 'production') {
logger.warn('The environment is not in production mode');
logger.warn('Do not use for production purpose');
}
logger.info(`You ${isRoot() ? '' : 'do not '}have root privileges`);
}
/**
* Init app
*/
@ -112,14 +146,15 @@ async function init(): Promise<Config> {
Logger.info('Welcome to Misskey!');
Logger.info(`<<< Misskey v${pkg.version} >>>`);
new Logger('Nodejs').info(`Version ${process.version}`);
if (lessThan(process.version.slice(1).split('.').map(x => parseInt(x, 10)), [10, 0, 0])) {
new Logger('Nodejs').error(`Node.js version is less than 10.0.0. Please upgrade it.`);
new Logger('Nodejs').info(`Version ${runningNodejsVersion.join('.')}`);
if (!satisfyNodejsVersion) {
new Logger('Nodejs').error(`Node.js version is less than ${requiredNodejsVersion.join('.')}. Please upgrade it.`);
process.exit(1);
}
await MachineInfo.show();
EnvironmentInfo.show();
await showMachine();
showEnvironment();
const configLogger = new Logger('Config');
let config;
@ -145,23 +180,25 @@ async function init(): Promise<Config> {
process.exit(1);
}
if (process.platform === 'linux' && !isRoot() && config.port < 1024) {
Logger.error('You need root privileges to listen on port below 1024 on Linux');
if (process.platform === 'linux' && isWellKnownPort(config.port) && !isRoot()) {
Logger.error('You need root privileges to listen on well-known port on Linux');
process.exit(1);
}
if (await portscanner.checkPortStatus(config.port, '127.0.0.1') === 'open') {
if (!await isPortAvailable(config.port)) {
Logger.error(`Port ${config.port} is already in use`);
process.exit(1);
}
// Try to connect to MongoDB
checkMongoDb(config);
await checkMongoDB(config);
return config;
}
function checkMongoDb(config: Config) {
const requiredMongoDBVersion = [3, 6];
function checkMongoDB(config: Config) {
const mongoDBLogger = new Logger('MongoDB');
const u = config.mongodb.user ? encodeURIComponent(config.mongodb.user) : null;
const p = config.mongodb.pass ? encodeURIComponent(config.mongodb.pass) : null;
@ -169,46 +206,35 @@ function checkMongoDb(config: Config) {
mongoDBLogger.info(`Connecting to ${uri}`);
mongo.then(() => {
mongoDBLogger.succ('Connectivity confirmed');
nativeDbConn().then(db => db.admin().serverInfo()).then(x => x.version).then((version: string) => {
mongoDBLogger.info(`Version: ${version}`);
if (lessThan(version.split('.').map(x => parseInt(x, 10)), [3, 6])) {
mongoDBLogger.error(`MongoDB version is less than 3.6. Please upgrade it.`);
if (lessThan(version.split('.').map(x => parseInt(x, 10)), requiredMongoDBVersion)) {
mongoDBLogger.error(`MongoDB version is less than ${requiredMongoDBVersion.join('.')}. Please upgrade it.`);
process.exit(1);
}
});
mongoDBLogger.succ('Connectivity confirmed');
})
.catch(err => {
mongoDBLogger.error(err.message);
});
}).catch(err => {
mongoDBLogger.error(err.message);
});
}
function spawnWorkers(limit: number) {
Logger.info('Starting workers...');
async function spawnWorkers(limit: number = Infinity) {
const workers = Math.min(limit, os.cpus().length);
Logger.info(`Starting ${workers} worker${workers === 1 ? '' : 's'}...`);
await Promise.all([...Array(workers)].map(spawnWorker));
Logger.succ('All workers started');
}
function spawnWorker(): Promise<void> {
return new Promise(res => {
// Count the machine's CPUs
const cpuCount = os.cpus().length;
const count = limit || cpuCount;
let started = 0;
// Create a worker for each CPU
for (let i = 0; i < count; i++) {
const worker = cluster.fork();
worker.on('message', message => {
if (message !== 'ready') return;
started++;
// When all workers started
if (started == count) {
Logger.succ('All workers started');
res();
}
});
}
const worker = cluster.fork();
worker.on('message', message => {
if (message !== 'ready') return;
Logger.succ('A worker started');
res();
});
});
}
@ -246,3 +272,5 @@ process.on('exit', code => {
});
//#endregion
main();

View File

@ -1,127 +1,135 @@
const { lib: emojilib } = require('emojilib');
const jsdom = require('jsdom');
const { JSDOM } = jsdom;
import config from '../config';
import { INote } from '../models/note';
import { TextElement } from './parse';
import { Node } from './parser';
import { intersperse } from '../prelude/array';
const handlers: { [key: string]: (window: any, token: any, mentionedRemoteUsers: INote['mentionedRemoteUsers']) => void } = {
bold({ document }, { bold }) {
const b = document.createElement('b');
b.textContent = bold;
document.body.appendChild(b);
},
big({ document }, { big }) {
const b = document.createElement('strong');
b.textContent = big;
document.body.appendChild(b);
},
motion({ document }, { big }) {
const b = document.createElement('strong');
b.textContent = big;
document.body.appendChild(b);
},
code({ document }, { code }) {
const pre = document.createElement('pre');
const inner = document.createElement('code');
inner.innerHTML = code;
pre.appendChild(inner);
document.body.appendChild(pre);
},
emoji({ document }, { content, emoji }) {
const found = emojilib[emoji];
const node = document.createTextNode(found ? found.char : content);
document.body.appendChild(node);
},
hashtag({ document }, { hashtag }) {
const a = document.createElement('a');
a.href = `${config.url}/tags/${hashtag}`;
a.textContent = `#${hashtag}`;
a.setAttribute('rel', 'tag');
document.body.appendChild(a);
},
'inline-code'({ document }, { code }) {
const element = document.createElement('code');
element.textContent = code;
document.body.appendChild(element);
},
math({ document }, { formula }) {
const element = document.createElement('code');
element.textContent = formula;
document.body.appendChild(element);
},
link({ document }, { url, title }) {
const a = document.createElement('a');
a.href = url;
a.textContent = title;
document.body.appendChild(a);
},
mention({ document }, { content, username, host }, mentionedRemoteUsers) {
const a = document.createElement('a');
const remoteUserInfo = mentionedRemoteUsers.find(remoteUser => remoteUser.username === username && remoteUser.host === host);
a.href = remoteUserInfo ? remoteUserInfo.uri : `${config.url}/${content}`;
a.textContent = content;
document.body.appendChild(a);
},
quote({ document }, { quote }) {
const blockquote = document.createElement('blockquote');
blockquote.textContent = quote;
document.body.appendChild(blockquote);
},
title({ document }, { content }) {
const h1 = document.createElement('h1');
h1.textContent = content;
document.body.appendChild(h1);
},
text({ document }, { content }) {
const nodes = (content as string).split('\n').map(x => document.createTextNode(x));
for (const x of intersperse('br', nodes)) {
if (x === 'br') {
document.body.appendChild(document.createElement('br'));
} else {
document.body.appendChild(x);
}
}
},
url({ document }, { url }) {
const a = document.createElement('a');
a.href = url;
a.textContent = url;
document.body.appendChild(a);
},
search({ document }, { content, query }) {
const a = document.createElement('a');
a.href = `https://www.google.com/?#q=${query}`;
a.textContent = content;
document.body.appendChild(a);
}
};
export default (tokens: TextElement[], mentionedRemoteUsers: INote['mentionedRemoteUsers'] = []) => {
export default (tokens: Node[], mentionedRemoteUsers: INote['mentionedRemoteUsers'] = []) => {
if (tokens == null) {
return null;
}
const { window } = new JSDOM('');
for (const token of tokens) {
handlers[token.type](window, token, mentionedRemoteUsers);
const doc = window.document;
function dive(nodes: Node[]): any[] {
return nodes.map(n => handlers[n.name](n));
}
return `<p>${window.document.body.innerHTML}</p>`;
const handlers: { [key: string]: (token: Node) => any } = {
bold(token) {
const el = doc.createElement('b');
dive(token.children).forEach(child => el.appendChild(child));
return el;
},
big(token) {
const el = doc.createElement('strong');
dive(token.children).forEach(child => el.appendChild(child));
return el;
},
motion(token) {
const el = doc.createElement('i');
dive(token.children).forEach(child => el.appendChild(child));
return el;
},
blockCode(token) {
const pre = doc.createElement('pre');
const inner = doc.createElement('code');
inner.innerHTML = token.props.code;
pre.appendChild(inner);
return pre;
},
emoji(token) {
return doc.createTextNode(token.props.emoji ? token.props.emoji : `:${token.props.name}:`);
},
hashtag(token) {
const a = doc.createElement('a');
a.href = `${config.url}/tags/${token.props.hashtag}`;
a.textContent = `#${token.props.hashtag}`;
a.setAttribute('rel', 'tag');
return a;
},
inlineCode(token) {
const el = doc.createElement('code');
el.textContent = token.props.code;
return el;
},
math(token) {
const el = doc.createElement('code');
el.textContent = token.props.formula;
return el;
},
link(token) {
const a = doc.createElement('a');
a.href = token.props.url;
dive(token.children).forEach(child => a.appendChild(child));
return a;
},
mention(token) {
const a = doc.createElement('a');
const { username, host, acct } = token.props;
const remoteUserInfo = mentionedRemoteUsers.find(remoteUser => remoteUser.username === username && remoteUser.host === host);
a.href = remoteUserInfo ? remoteUserInfo.uri : `${config.url}/${acct}`;
a.textContent = acct;
return a;
},
quote(token) {
const el = doc.createElement('blockquote');
dive(token.children).forEach(child => el.appendChild(child));
return el;
},
title(token) {
const el = doc.createElement('h1');
dive(token.children).forEach(child => el.appendChild(child));
return el;
},
text(token) {
const el = doc.createElement('span');
const nodes = (token.props.text as string).split('\n').map(x => doc.createTextNode(x));
for (const x of intersperse('br', nodes)) {
if (x === 'br') {
el.appendChild(doc.createElement('br'));
} else {
el.appendChild(x);
}
}
return el;
},
url(token) {
const a = doc.createElement('a');
a.href = token.props.url;
a.textContent = token.props.url;
return a;
},
search(token) {
const a = doc.createElement('a');
a.href = `https://www.google.com/?#q=${token.props.query}`;
a.textContent = token.props.content;
return a;
}
};
dive(tokens).forEach(x => {
doc.body.appendChild(x);
});
return `<p>${doc.body.innerHTML}</p>`;
};

82
src/mfm/parse.ts Normal file
View File

@ -0,0 +1,82 @@
import parser, { Node } from './parser';
import * as A from '../prelude/array';
import * as S from '../prelude/string';
export default (source: string): Node[] => {
if (source == null || source == '') {
return null;
}
let nodes: Node[] = parser.root.tryParse(source);
const combineText = (es: Node[]): Node =>
({ name: 'text', props: { text: S.concat(es.map(e => e.props.text)) } });
const concatText = (nodes: Node[]): Node[] =>
A.concat(A.groupOn(x => x.name, nodes).map(es =>
es[0].name === 'text' ? [combineText(es)] : es
));
const concatTextRecursive = (es: Node[]): void =>
es.filter(x => x.children).forEach(x => {
x.children = concatText(x.children);
concatTextRecursive(x.children);
});
nodes = concatText(nodes);
concatTextRecursive(nodes);
function getBeforeTextNode(node: Node): Node {
if (node == null) return null;
if (node.name == 'text') return node;
if (node.children) return getBeforeTextNode(node.children[node.children.length - 1]);
return null;
}
function getAfterTextNode(node: Node): Node {
if (node == null) return null;
if (node.name == 'text') return node;
if (node.children) return getBeforeTextNode(node.children[0]);
return null;
}
function isBlockNode(node: Node): boolean {
return ['blockCode', 'quote', 'title'].includes(node.name);
}
/**
* ブロック要素の前後にある改行を削除します
* (ブロック要素自体が改行の役割を果たすため、余計に改行されてしまう)
* @param nodes
*/
const removeNeedlessLineBreaks = (nodes: Node[]) => {
nodes.forEach((node, i) => {
if (node.children) removeNeedlessLineBreaks(node.children);
if (isBlockNode(node)) {
const before = getBeforeTextNode(nodes[i - 1]);
const after = getAfterTextNode(nodes[i + 1]);
if (before && before.props.text.endsWith('\n')) {
before.props.text = before.props.text.substring(0, before.props.text.length - 1);
}
if (after && after.props.text.startsWith('\n')) {
after.props.text = after.props.text.substring(1);
}
}
});
};
const removeEmptyTextNodes = (nodes: Node[]) => {
nodes.forEach(n => {
if (n.children) {
n.children = removeEmptyTextNodes(n.children);
}
});
return nodes.filter(n => !(n.name == 'text' && n.props.text == ''));
};
removeNeedlessLineBreaks(nodes);
nodes = removeEmptyTextNodes(nodes);
return nodes;
};

View File

@ -1,20 +0,0 @@
/**
* Big
*/
export type TextElementBig = {
type: 'big';
content: string;
big: string;
};
export default function(text: string) {
const match = text.match(/^\*\*\*(.+?)\*\*\*/);
if (!match) return null;
const big = match[0];
return {
type: 'big',
content: big,
big: match[1]
} as TextElementBig;
}

View File

@ -1,20 +0,0 @@
/**
* Bold
*/
export type TextElementBold = {
type: 'bold';
content: string;
bold: string;
};
export default function(text: string) {
const match = text.match(/^\*\*(.+?)\*\*/);
if (!match) return null;
const bold = match[0];
return {
type: 'bold',
content: bold,
bold: match[1]
} as TextElementBold;
}

View File

@ -1,24 +0,0 @@
/**
* Code (block)
*/
import genHtml from '../core/syntax-highlighter';
export type TextElementCode = {
type: 'code';
content: string;
code: string;
html: string;
};
export default function(text: string) {
const match = text.match(/^```([\s\S]+?)```/);
if (!match) return null;
const code = match[0];
return {
type: 'code',
content: code,
code: match[1],
html: genHtml(match[1].trim())
} as TextElementCode;
}

File diff suppressed because one or more lines are too long

View File

@ -1,33 +0,0 @@
/**
* Emoji
*/
import { emojiRegex } from "./emoji.regex";
export type TextElementEmoji = {
type: 'emoji';
content: string;
emoji?: string;
name?: string;
};
export default function(text: string) {
const name = text.match(/^:([a-zA-Z0-9+_-]+):/);
if (name) {
return {
type: 'emoji',
content: name[0],
name: name[1]
} as TextElementEmoji;
}
const unicode = text.match(emojiRegex);
if (unicode) {
const [content] = unicode;
return {
type: 'emoji',
content,
emoji: content
} as TextElementEmoji;
}
return null;
}

View File

@ -1,27 +0,0 @@
/**
* Hashtag
*/
export type TextElementHashtag = {
type: 'hashtag';
content: string;
hashtag: string;
};
export default function(text: string, before: string) {
const isBegin = before == '';
if (!(/^\s#[^\s\.,!\?#]+/.test(text) || (isBegin && /^#[^\s\.,!\?#]+/.test(text)))) return null;
const isHead = text.startsWith('#');
const hashtag = text.match(/^\s?#[^\s\.,!\?#]+/)[0];
const res: any[] = !isHead ? [{
type: 'text',
content: text[0]
}] : [];
res.push({
type: 'hashtag',
content: isHead ? hashtag : hashtag.substr(1),
hashtag: isHead ? hashtag.substr(1) : hashtag.substr(2)
});
return res as TextElementHashtag[];
}

View File

@ -1,25 +0,0 @@
/**
* Code (inline)
*/
import genHtml from '../core/syntax-highlighter';
export type TextElementInlineCode = {
type: 'inline-code';
content: string;
code: string;
html: string;
};
export default function(text: string) {
const match = text.match(/^`(.+?)`/);
if (!match) return null;
if (match[1].includes('´')) return null;
const code = match[0];
return {
type: 'inline-code',
content: code,
code: match[1],
html: genHtml(match[1])
} as TextElementInlineCode;
}

View File

@ -1,27 +0,0 @@
/**
* Link
*/
export type TextElementLink = {
type: 'link';
content: string;
title: string;
url: string;
silent: boolean;
};
export default function(text: string) {
const match = text.match(/^\??\[([^\[\]]+?)\]\((https?:\/\/[\w\/:%#@\$&\?!\(\)\[\]~\.=\+\-]+?)\)/);
if (!match) return null;
const silent = text.startsWith('?');
const link = match[0];
const title = match[1];
const url = match[2];
return {
type: 'link',
content: link,
title: title,
url: url,
silent: silent
} as TextElementLink;
}

View File

@ -1,20 +0,0 @@
/**
* Math
*/
export type TextElementMath = {
type: 'math';
content: string;
formula: string;
};
export default function(text: string) {
const match = text.match(/^\$(.+?)\$/);
if (!match) return null;
const math = match[0];
return {
type: 'math',
content: math,
formula: match[1]
} as TextElementMath;
}

View File

@ -1,29 +0,0 @@
/**
* Mention
*/
import parseAcct from '../../../misc/acct/parse';
import { toUnicode } from 'punycode';
export type TextElementMention = {
type: 'mention';
content: string;
canonical: string;
username: string;
host: string;
};
export default function(text: string, before: string) {
const match = text.match(/^@[a-z0-9_]+(?:@[a-z0-9\.\-]+[a-z0-9])?/i);
if (!match) return null;
if (/[a-zA-Z0-9]$/.test(before)) return null;
const mention = match[0];
const { username, host } = parseAcct(mention.substr(1));
const canonical = host != null ? `@${username}@${toUnicode(host)}` : mention;
return {
type: 'mention',
content: mention,
canonical,
username,
host
} as TextElementMention;
}

View File

@ -1,20 +0,0 @@
/**
* Motion
*/
export type TextElementMotion = {
type: 'motion';
content: string;
motion: string;
};
export default function(text: string) {
const match = text.match(/^\(\(\((.+?)\)\)\)/) || text.match(/^<motion>(.+?)<\/motion>/);
if (!match) return null;
const motion = match[0];
return {
type: 'motion',
content: motion,
motion: match[1]
} as TextElementMotion;
}

View File

@ -1,30 +0,0 @@
/**
* Quoted text
*/
export type TextElementQuote = {
type: 'quote';
content: string;
quote: string;
};
export default function(text: string, before: string) {
const isBegin = before == '';
const match = text.match(/^"([\s\S]+?)\n"/) || text.match(/^\n>([\s\S]+?)(\n\n|$)/) ||
(isBegin ? text.match(/^>([\s\S]+?)(\n\n|$)/) : null);
if (!match) return null;
const quote = match[1]
.split('\n')
.map(line => line.replace(/^>+/g, '').trim())
.join('\n')
.trim();
return {
type: 'quote',
content: match[0],
quote: quote,
} as TextElementQuote;
}

View File

@ -1,19 +0,0 @@
/**
* Search
*/
export type TextElementSearch = {
type: 'search';
content: string;
query: string;
};
export default function(text: string) {
const match = text.match(/^(.+?)( | )(検索|\[検索\]|Search|\[Search\])(\n|$)/i);
if (!match) return null;
return {
type: 'search',
content: match[0],
query: match[1]
};
}

View File

@ -1,21 +0,0 @@
/**
* Title
*/
export type TextElementTitle = {
type: 'title';
content: string;
title: string;
};
export default function(text: string, before: string) {
const isBegin = before == '';
const match = isBegin ? text.match(/^(【|\[)(.+?)(】|])\n/) : text.match(/^\n(【|\[)(.+?)(】|])\n/);
if (!match) return null;
return {
type: 'title',
content: match[0],
title: match[2]
} as TextElementTitle;
}

View File

@ -1,23 +0,0 @@
/**
* URL
*/
export type TextElementUrl = {
type: 'url';
content: string;
url: string;
};
export default function(text: string, before: string) {
const match = text.match(/^https?:\/\/[\w\/:%#@\$&\?!\(\)\[\]~\.,=\+\-]+/);
if (!match) return null;
let url = match[0];
if (url.endsWith('.')) url = url.substr(0, url.lastIndexOf('.'));
if (url.endsWith(',')) url = url.substr(0, url.lastIndexOf(','));
if (url.endsWith(')') && before.endsWith('(')) url = url.substr(0, url.lastIndexOf(')'));
return {
type: 'url',
content: url,
url: url
} as TextElementUrl;
}

View File

@ -1,100 +0,0 @@
/**
* Misskey Text Analyzer
*/
import { TextElementBold } from './elements/bold';
import { TextElementBig } from './elements/big';
import { TextElementCode } from './elements/code';
import { TextElementEmoji } from './elements/emoji';
import { TextElementHashtag } from './elements/hashtag';
import { TextElementInlineCode } from './elements/inline-code';
import { TextElementMath } from './elements/math';
import { TextElementLink } from './elements/link';
import { TextElementMention } from './elements/mention';
import { TextElementQuote } from './elements/quote';
import { TextElementSearch } from './elements/search';
import { TextElementTitle } from './elements/title';
import { TextElementUrl } from './elements/url';
import { TextElementMotion } from './elements/motion';
import { groupOn } from '../../prelude/array';
import * as A from '../../prelude/array';
import * as S from '../../prelude/string';
const elements = [
require('./elements/big'),
require('./elements/bold'),
require('./elements/title'),
require('./elements/url'),
require('./elements/link'),
require('./elements/mention'),
require('./elements/hashtag'),
require('./elements/code'),
require('./elements/inline-code'),
require('./elements/math'),
require('./elements/quote'),
require('./elements/emoji'),
require('./elements/search'),
require('./elements/motion')
].map(element => element.default as TextElementProcessor);
export type TextElement = { type: 'text', content: string }
| TextElementBold
| TextElementBig
| TextElementCode
| TextElementEmoji
| TextElementHashtag
| TextElementInlineCode
| TextElementMath
| TextElementLink
| TextElementMention
| TextElementQuote
| TextElementSearch
| TextElementTitle
| TextElementUrl
| TextElementMotion;
export type TextElementProcessor = (text: string, before: string) => TextElement | TextElement[];
export default (source: string): TextElement[] => {
if (source == null || source == '') {
return null;
}
const tokens: TextElement[] = [];
function push(token: TextElement) {
if (token != null) {
tokens.push(token);
source = source.substr(token.content.length);
}
}
// パース
while (source != '') {
const parsed = elements.some(el => {
let _tokens = el(source, tokens.map(token => token.content).join(''));
if (_tokens) {
if (!Array.isArray(_tokens)) {
_tokens = [_tokens];
}
_tokens.forEach(push);
return true;
} else {
return false;
}
});
if (!parsed) {
push({
type: 'text',
content: source[0]
});
}
}
const combineText = (es: TextElement[]): TextElement =>
({ type: 'text', content: S.concat(es.map(e => e.content)) });
return A.concat(groupOn(x => x.type, tokens).map(es =>
es[0].type === 'text' ? [combineText(es)] : es
));
};

274
src/mfm/parser.ts Normal file

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,4 @@
import { capitalize, toUpperCase } from "../../../prelude/string";
import { capitalize, toUpperCase } from "../prelude/string";
function escape(text: string) {
return text
@ -308,7 +308,7 @@ const elements: Element[] = [
];
// specify lang is todo
export default (source: string, lang?: string) => {
export default (source: string, lang?: string): string => {
let code = source;
let html = '';

View File

@ -1,4 +1,5 @@
export default (acct: string) => {
if (acct.startsWith('@')) acct = acct.substr(1);
const splitted = acct.split('@', 2);
return { username: splitted[0], host: splitted[1] || null };
};

View File

@ -1,17 +0,0 @@
import Logger from './logger';
import isRoot = require('is-root');
export default class {
public static show(): void {
const env = process.env.NODE_ENV;
const logger = new Logger('Env');
logger.info(typeof env == 'undefined' ? 'NODE_ENV is not set' : `NODE_ENV: ${env}`);
if (env !== 'production') {
logger.warn('The environment is not in production mode');
logger.warn('Do not use for production purpose');
}
logger.info(`You ${isRoot() ? '' : 'do not '}have root privileges`);
}
}

View File

@ -15,7 +15,10 @@ const defaultMeta: any = {
maxNoteTextLength: 1000,
enableTwitterIntegration: false,
enableGithubIntegration: false,
enableDiscordIntegration: false
enableDiscordIntegration: false,
enableExternalUserRecommendation: false,
externalUserRecommendationEngine: "https://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-misskey-api.cgi?{{host}}+{{user}}+{{limit}}+{{offset}}",
externalUserRecommendationTimeout: 300000
};
export default async function(): Promise<IMeta> {

View File

@ -1,17 +0,0 @@
import * as os from 'os';
import Logger from './logger';
import * as sysUtils from 'systeminformation';
export default class {
public static async show() {
const logger = new Logger('Machine');
logger.info(`Hostname: ${os.hostname()}`);
logger.info(`Platform: ${process.platform}`);
logger.info(`Architecture: ${process.arch}`);
logger.info(`CPU: ${os.cpus().length} core`);
const mem = await sysUtils.mem();
const totalmem = (mem.total / 1024 / 1024 / 1024).toFixed(1);
const availmem = (mem.available / 1024 / 1024 / 1024).toFixed(1);
logger.info(`MEM: ${totalmem}GB (available: ${availmem}GB)`);
}
}

View File

@ -125,6 +125,19 @@ if ((config as any).github) {
}
});
}
if ((config as any).user_recommendation) {
Meta.findOne({}).then(m => {
if (m != null && m.enableExternalUserRecommendation == null) {
Meta.update({}, {
$set: {
enableExternalUserRecommendation: true,
externalUserRecommendationEngine: (config as any).user_recommendation.engine,
externalUserRecommendationTimeout: (config as any).user_recommendation.timeout
}
});
}
});
}
export type IMeta = {
name?: string;
@ -184,6 +197,8 @@ export type IMeta = {
*/
maxNoteTextLength?: number;
summalyProxy?: string;
enableTwitterIntegration?: boolean;
twitterConsumerKey?: string;
twitterConsumerSecret?: string;
@ -195,4 +210,8 @@ export type IMeta = {
enableDiscordIntegration?: boolean;
discordClientId?: string;
discordClientSecret?: string;
enableExternalUserRecommendation?: boolean;
externalUserRecommendationEngine?: string;
externalUserRecommendationTimeout?: number;
};

View File

@ -18,6 +18,7 @@ Note.createIndex('uri', { sparse: true, unique: true });
Note.createIndex('userId');
Note.createIndex('mentions');
Note.createIndex('visibleUserIds');
Note.createIndex('replyId');
Note.createIndex('tagsLower');
Note.createIndex('_user.host');
Note.createIndex('_files._id');
@ -99,7 +100,6 @@ export type INote = {
host: string;
inbox?: string;
};
_replyIds?: mongo.ObjectID[];
_files?: IDriveFile[];
};
@ -258,6 +258,8 @@ export const pack = async (
delete _note._reply;
delete _note._renote;
delete _note._files;
delete _note._replyIds;
if (_note.geo) delete _note.geo.type;
// Populate user

View File

@ -26,6 +26,7 @@ export default User;
type IUserBase = {
_id: mongo.ObjectID;
createdAt: Date;
updatedAt?: Date;
deletedAt?: Date;
followersCount: number;
followingCount: number;
@ -37,6 +38,8 @@ type IUserBase = {
bannerId: mongo.ObjectID;
avatarUrl?: string;
bannerUrl?: string;
avatarColor?: any;
bannerColor?: any;
wallpaperId: mongo.ObjectID;
wallpaperUrl?: string;
data: any;
@ -104,7 +107,6 @@ export interface ILocalUser extends IUserBase {
birthday: string; // 'YYYY-MM-DD'
tags: string[];
};
lastUsedAt: Date;
isCat: boolean;
isAdmin?: boolean;
isModerator?: boolean;
@ -132,7 +134,7 @@ export interface IRemoteUser extends IUserBase {
id: string;
publicKeyPem: string;
};
updatedAt: Date;
lastFetchedAt: Date;
isAdmin: false;
isModerator: false;
}

View File

@ -35,17 +35,11 @@ export default async function(resolver: Resolver, actor: IRemoteUser, activity:
log(`Creating the (Re)Note: ${uri}`);
//#region Visibility
let visibility = 'public';
const visibility = getVisibility(activity.to, activity.cc, actor);
let visibleUsers: IUser[] = [];
if (!note.to.includes('https://www.w3.org/ns/activitystreams#Public')) {
if (note.cc.includes('https://www.w3.org/ns/activitystreams#Public')) {
visibility = 'home';
} else if (note.to.includes(`${actor.uri}/followers`)) { // TODO: person.followerと照合するべき
visibility = 'followers';
} else {
visibility = 'specified';
visibleUsers = await Promise.all(note.to.map(uri => resolvePerson(uri)));
}
if (visibility == 'specified') {
visibleUsers = await Promise.all(note.to.map(uri => resolvePerson(uri)));
}
//#endergion
@ -57,3 +51,22 @@ export default async function(resolver: Resolver, actor: IRemoteUser, activity:
uri
});
}
type visibility = 'public' | 'home' | 'followers' | 'specified' | 'private';
function getVisibility(to: string[], cc: string[], actor: IRemoteUser): visibility {
const PUBLIC = 'https://www.w3.org/ns/activitystreams#Public';
to = to || [];
cc = cc || [];
if (to.includes(PUBLIC)) {
return 'public';
} else if (cc.includes(PUBLIC)) {
return 'home';
} else if (to.includes(`${actor.uri}/followers`)) {
return 'followers';
} else {
return 'specified';
}
}

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