Compare commits

...

111 Commits

Author SHA1 Message Date
cb0874f15a 10.54.0 2018-11-16 23:19:34 +09:00
9239e37b45 Fix #3273 (#3277) 2018-11-16 23:14:11 +09:00
57d80932a4 Add an optional setting to remain deleted note (#3271)
Co-authored-by: Aya Morisawa <AyaMorisawa4869@gmail.com>
Co-authored-by: syuilo <syuilotan@yahoo.co.jp>
2018-11-16 23:13:37 +09:00
8569970fbe Update github-bot.ts 2018-11-16 23:10:48 +09:00
713e9ad5f4 Resolve #3274 2018-11-16 23:09:33 +09:00
59e229d962 Update github-bot.ts 2018-11-16 23:02:01 +09:00
3c5f09cda2 Clean up 2018-11-16 23:01:14 +09:00
e42aa2530d Update github-bot.ts
follow dvelop instead master
2018-11-16 23:00:34 +09:00
1fd298ac9c Update docker.en.md (#3272) 2018-11-16 22:47:10 +09:00
1a73f52541 Merge branch 'develop' of https://github.com/syuilo/misskey into develop 2018-11-16 22:32:17 +09:00
27e458f884 Do not use camelCase in html 2018-11-16 22:32:06 +09:00
ba3e2a9371 Update setup.en.md (#3270)
* [doc] run as root

* [doc] update setup guide headings
2018-11-16 22:31:53 +09:00
831e8f8583 Refactoring 2018-11-16 22:31:28 +09:00
0ff390ed80 [MFM] Improve various parsing
Resolve #2779
Resolve #3053
2018-11-16 21:57:19 +09:00
e3b8495431 [MFM] Better URL parsing 2018-11-16 21:30:01 +09:00
da10ba3fea [Client] Add missing icon
Resolve #3267
2018-11-16 18:34:52 +09:00
cc7de853b4 [Client] Wrap formula component to split code 2018-11-16 18:31:25 +09:00
23d8235197 Revert "[Client] Load katex async to reduce bundle size"
This reverts commit 37e3d60ade.
2018-11-16 18:26:19 +09:00
37e3d60ade [Client] Load katex async to reduce bundle size 2018-11-16 18:22:44 +09:00
83a3426dd5 Merge branch 'develop' of https://github.com/syuilo/misskey into develop 2018-11-16 17:56:08 +09:00
a2549192ca Update misskey-flavored-markdown.ts 2018-11-16 17:55:48 +09:00
9d3a1cab6e Fix #3224 (#3265) 2018-11-16 17:41:52 +09:00
06f8d8f0a3 Show server version on server.info.vue (#3264) 2018-11-16 17:24:03 +09:00
fa66b79e2d Update the locale when version or language changed (#3263) 2018-11-16 17:13:22 +09:00
81312f5a93 Remove a trailing whitespace (#3261) 2018-11-16 17:04:28 +09:00
ad84901f39 Support math rendering on MFM (#3260) 2018-11-16 17:03:52 +09:00
d2385a0e52 Do not show duplicate url-preview (#3259) 2018-11-16 16:35:13 +09:00
39285fc2d0 10.53.0 2018-11-16 05:56:58 +09:00
6e491c1466 Refactoring 2018-11-16 05:53:17 +09:00
84152aa663 Update typescript-eslint-parser requirement from 20.1.1 to 21.0.0 (#3237)
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.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-11-16 05:49:21 +09:00
600fc65c2f Update showdown requirement from 1.8.7 to 1.9.0 (#3252)
Updates the requirements on [showdown](https://github.com/showdownjs/showdown) to permit the latest version.
- [Release notes](https://github.com/showdownjs/showdown/releases)
- [Changelog](https://github.com/showdownjs/showdown/blob/master/CHANGELOG.md)
- [Commits](https://github.com/showdownjs/showdown/commits/1.9.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-11-16 05:49:07 +09:00
40e2733424 Update mongodb requirement from 3.1.8 to 3.1.9 (#3253)
Updates the requirements on [mongodb](https://github.com/mongodb/node-mongodb-native) to permit the latest version.
- [Release notes](https://github.com/mongodb/node-mongodb-native/releases)
- [Changelog](https://github.com/mongodb/node-mongodb-native/blob/master/HISTORY.md)
- [Commits](https://github.com/mongodb/node-mongodb-native/commits/v3.1.9)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-11-16 05:48:39 +09:00
bceb02d760 local only visibility (#3254)
* local only visibility

* fix UI
2018-11-16 05:47:29 +09:00
aaaaf2681a [Client] Add missing icon 2018-11-16 05:38:16 +09:00
3c3ef9bba0 [Client] ✌️ 2018-11-16 05:36:52 +09:00
338f3a981f Merge branch 'develop' of https://github.com/syuilo/misskey into develop 2018-11-16 05:26:48 +09:00
a86ae9fa50 Better UX 2018-11-16 05:26:36 +09:00
a3c4e8a1bc [Client] Improve admin dashboard 2018-11-16 05:21:52 +09:00
6a7c18e8db Merge pull request #3250 from syuilo/l10n_develop
New Crowdin translations
2018-11-16 05:10:41 +09:00
672b7a4c3d 🎨 2018-11-16 05:07:59 +09:00
bf3fee4481 Check the port is configured (#3251) 2018-11-16 03:25:35 +09:00
a3c8d1d732 New translations ja-JP.yml (Chinese Simplified) 2018-11-16 00:15:45 +09:00
bb03d8c49a New translations ja-JP.yml (Chinese Simplified) 2018-11-15 23:59:41 +09:00
fbd5abe3b6 New translations ja-JP.yml (Chinese Simplified) 2018-11-15 23:43:21 +09:00
5ac390abe9 New translations ja-JP.yml (Chinese Simplified) 2018-11-15 23:38:10 +09:00
766cae2299 Check Node.js version (#3245)
* Check Node.js version

* Fix bug
2018-11-15 22:17:06 +09:00
d9828fdc6a 10.52.0 2018-11-15 22:04:57 +09:00
4114ce4a04 [Client] Split some components to improve performance 2018-11-15 22:04:12 +09:00
6090630260 Merge pull request #3236 from syuilo/l10n_develop
New Crowdin translations
2018-11-15 21:44:39 +09:00
259cfeae17 Use Node.js official Docker image (#3241)
* Update Dockerfile

* Update Dockerfile
2018-11-15 21:43:02 +09:00
ebe15c4711 New translations ja-JP.yml (English) 2018-11-15 21:03:36 +09:00
75a740a110 New translations ja-JP.yml (English) 2018-11-15 20:53:18 +09:00
0c085c4f74 New translations ja-JP.yml (English) 2018-11-15 20:44:10 +09:00
1d819e79db New translations ja-JP.yml (Norwegian) 2018-11-15 19:24:47 +09:00
515b79dcf0 New translations ja-JP.yml (Dutch) 2018-11-15 19:24:41 +09:00
269e12abb4 New translations ja-JP.yml (Japanese, Kansai) 2018-11-15 19:24:36 +09:00
cf5be6ff5a New translations ja-JP.yml (Spanish) 2018-11-15 19:24:32 +09:00
f140adbc9d New translations ja-JP.yml (Russian) 2018-11-15 19:24:25 +09:00
6c31406bb0 New translations ja-JP.yml (Portuguese) 2018-11-15 19:24:19 +09:00
b6e8626908 New translations ja-JP.yml (Polish) 2018-11-15 19:24:15 +09:00
64a3a4915a New translations ja-JP.yml (Korean) 2018-11-15 19:24:11 +09:00
fd71f24d46 New translations ja-JP.yml (Italian) 2018-11-15 19:24:05 +09:00
65b5c6753f New translations ja-JP.yml (German) 2018-11-15 19:23:59 +09:00
7408bbce37 New translations ja-JP.yml (French) 2018-11-15 19:23:54 +09:00
0f58978c9f New translations ja-JP.yml (English) 2018-11-15 19:23:47 +09:00
01ca3fd6b2 New translations ja-JP.yml (Chinese Simplified) 2018-11-15 19:23:43 +09:00
26c366156b New translations ja-JP.yml (Catalan) 2018-11-15 19:23:37 +09:00
9d8f7b081d WIP: Add Discord auth (#3239)
* Add Discord auth

* Apply review 175263424
2018-11-15 19:15:04 +09:00
9d8ebb795d New translations ja-JP.yml (French) 2018-11-15 18:11:46 +09:00
8be98e4cb8 New translations ja-JP.yml (French) 2018-11-15 17:32:46 +09:00
3c229c9950 New translations ja-JP.yml (Chinese Simplified) 2018-11-15 13:51:55 +09:00
f2263faf7d New translations ja-JP.yml (Chinese Simplified) 2018-11-15 13:44:35 +09:00
39c7cf3e66 New translations ja-JP.yml (Chinese Simplified) 2018-11-15 13:32:36 +09:00
5ee24e5c09 New translations ja-JP.yml (French) 2018-11-15 07:21:58 +09:00
a34fdc2068 10.51.2 2018-11-15 07:04:25 +09:00
2c2cd893b8 🎨 2018-11-15 07:03:46 +09:00
a43b0548ed 10.51.1 2018-11-15 06:40:09 +09:00
93e95f56f4 Update src/client/app/admin/views/index.vue 2018-11-15 06:39:59 +09:00
cb0673b1ec 10.51.0 2018-11-15 06:26:15 +09:00
cd018db945 Update src/client/app/admin/views/index.vue 2018-11-15 06:23:40 +09:00
50fe67b99b [Client] Improve admin panel 2018-11-15 06:21:31 +09:00
1dba82aae5 [API] Add /instances 2018-11-15 06:21:13 +09:00
17c6d64750 [Client] Prevent cache locale file 2018-11-15 05:20:25 +09:00
b4c04efa23 Improve usability 2018-11-15 05:00:30 +09:00
152dd74abf 10.50.0 2018-11-15 04:26:33 +09:00
0985f7f609 [Client] Fix bugs 2018-11-15 04:24:40 +09:00
aecf9329bd New translations ja-JP.yml (Norwegian) 2018-11-15 04:24:24 +09:00
b2384605e7 New translations ja-JP.yml (Dutch) 2018-11-15 04:24:20 +09:00
57ab5ab604 New translations ja-JP.yml (Japanese, Kansai) 2018-11-15 04:24:15 +09:00
e493a20301 New translations ja-JP.yml (Spanish) 2018-11-15 04:24:09 +09:00
0bd5ed937c New translations ja-JP.yml (Russian) 2018-11-15 04:24:03 +09:00
6a9b3bc64e New translations ja-JP.yml (Portuguese) 2018-11-15 04:23:58 +09:00
4c1ef3e6a5 New translations ja-JP.yml (Polish) 2018-11-15 04:23:54 +09:00
2ea250f954 New translations ja-JP.yml (Korean) 2018-11-15 04:23:49 +09:00
5d810980f8 New translations ja-JP.yml (Italian) 2018-11-15 04:23:43 +09:00
d51b4e27cc New translations ja-JP.yml (German) 2018-11-15 04:23:37 +09:00
c01c555309 New translations ja-JP.yml (French) 2018-11-15 04:23:33 +09:00
ce2e66d9b0 New translations ja-JP.yml (English) 2018-11-15 04:23:27 +09:00
9550acd61e New translations ja-JP.yml (Chinese Simplified) 2018-11-15 04:23:23 +09:00
d95b5daa6d New translations ja-JP.yml (Catalan) 2018-11-15 04:23:18 +09:00
56d571c0f0 Moderator system
Closes #2357
2018-11-15 04:15:42 +09:00
dc9a19b9c7 [Client] Add missing icon 2018-11-15 03:17:48 +09:00
88a2c7715a [Client] Add missing icon 2018-11-15 03:14:52 +09:00
2fa8cb1b73 10.49.7 2018-11-15 01:46:01 +09:00
5f8a66fdb9 🎨 2018-11-15 01:45:13 +09:00
57320a94f9 [Client] Add missing icon 2018-11-15 01:43:26 +09:00
89f045d624 🎨 2018-11-15 01:43:06 +09:00
1a77dea7ed [Client] Fix icon 2018-11-15 01:09:50 +09:00
532a7b90f3 New translations ja-JP.yml (Chinese Simplified) 2018-11-15 00:55:47 +09:00
4e8c200349 New translations ja-JP.yml (Chinese Simplified) 2018-11-15 00:43:37 +09:00
d063d59a91 [Client] Improve UI 2018-11-15 00:01:49 +09:00
102 changed files with 1929 additions and 422 deletions

View File

@ -1,8 +1,7 @@
FROM alpine:3.8 AS base
FROM node:11-alpine AS base
ENV NODE_ENV=production
RUN apk add --no-cache nodejs nodejs-npm zlib
RUN npm i -g npm@latest
WORKDIR /misskey

View File

@ -13,7 +13,7 @@ This guide describes how to install and setup Misskey with Docker.
2. `cd misskey` Move to misskey directory.
3. `git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)` Checkout to the [latest release](https://github.com/syuilo/misskey/releases/latest) tag.
*2.* Make configuration files
*2.* Configure Misskey
----------------------------------------------------------------
1. `cp .config/example.yml .config/default.yml` Copy the `.config/example.yml` and rename it to `default.yml`.
2. `cp .config/mongo_initdb_example.js .config/mongo_initdb.js` Copy the `.config/mongo_initdb_example.js` and rename it to `mongo_initdb.js`.
@ -31,12 +31,12 @@ Build misskey with the following:
*5.* That is it.
----------------------------------------------------------------
Well done! Now, you have an environment that run to Misskey.
Well done! Now you have an environment to run Misskey.
### Launch normally
Just `docker-compose up -d`. GLHF!
### Way to Update to latest version of your Misskey
### How to update your Misskey server to the latest version
1. `git fetch`
2. `git stash`
3. `git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)`
@ -45,9 +45,9 @@ Just `docker-compose up -d`. GLHF!
6. Check [ChangeLog](../CHANGELOG.md) for migration information
7. `docker-compose stop && docker-compose up -d`
### Way to execute cli command:
### How to execute [cli commands](manage.en.md):
`docker-compose run --rm web node cli/mark-admin @example`
----------------------------------------------------------------
If you have any questions or troubles, feel free to contact us!
If you have any questions or trouble, feel free to contact us!

View File

@ -10,7 +10,7 @@ This guide describes how to install and setup Misskey.
*1.* Create Misskey user
----------------------------------------------------------------
Running misskey on root is not a good idea so we create a user for that.
Running misskey as root is not a good idea so we create a user for that.
In debian for exemple :
```
@ -32,7 +32,7 @@ Please install and setup these softwares:
*3.* Setup MongoDB
----------------------------------------------------------------
In root :
As root:
1. `mongo` Go to the mongo shell
2. `use misskey` Use the misskey database
3. `db.users.save( {dummy:"dummy"} )` Write dummy data to initialize the db.
@ -47,17 +47,17 @@ In root :
4. `git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)` Checkout to the [latest release](https://github.com/syuilo/misskey/releases/latest)
5. `npm install` Install misskey dependencies.
*(optional)* Generating VAPID keys
*(optional)* Generate VAPID keys
----------------------------------------------------------------
If you want to enable ServiceWorker, you need to generate VAPID keys:
Unless you have set your global node_modules location elsewhere, you need to run this in root.
Unless you have set your global node_modules location elsewhere, you need to run this as root.
``` shell
npm install web-push -g
web-push generate-vapid-keys
```
*5.* Make configuration file
*5.* Configure Misskey
----------------------------------------------------------------
1. `cp .config/example.yml .config/default.yml` Copy the `.config/example.yml` and rename it to `default.yml`.
2. Edit `default.yml`
@ -114,7 +114,7 @@ WantedBy=multi-user.target
You can check if the service is running with `systemctl status misskey`.
### Way to Update to latest version of your Misskey
### How to update your Misskey server to the latest version
1. `git fetch`
2. `git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)`
3. `npm install`

View File

@ -363,6 +363,7 @@ common/views/components/signin.vue:
or: "または"
signin-with-twitter: "Twitterでログイン"
signin-with-github: "GitHubでログイン"
signin-with-discord: "Discordでログイン"
login-failed: "ログインできませんでした。ユーザー名とパスワードを確認してください。"
common/views/components/signup.vue:
invitation-code: "招待コード"
@ -408,6 +409,13 @@ common/views/components/github-setting.vue:
reconnect: "再接続する"
connect: "GitHubと接続する"
disconnect: "切断する"
common/views/components/discord-setting.vue:
description: "お使いのDiscordアカウントをお使いのMisskeyアカウントに接続しておくと、プロフィールでDiscordアカウント情報が表示されるようになったり、Discordを用いた便利なサインインを利用できるようになります。"
connected-to: "次のDiscordアカウントに接続されています"
detail: "詳細..."
reconnect: "再接続する"
connect: "Discordと接続する"
disconnect: "切断する"
common/views/components/uploader.vue:
waiting: "待機中"
common/views/components/visibility-chooser.vue:
@ -911,6 +919,7 @@ admin/views/index.vue:
dashboard: "ダッシュボード"
instance: "インスタンス"
emoji: "カスタム絵文字"
moderators: "モデレーター"
users: "ユーザー"
update: "更新"
announcements: "お知らせ"
@ -955,7 +964,12 @@ admin/views/instance.vue:
github-integration-info: "コールバックURLは /api/gh/cb に設定します。"
enable-github-integration: "GitHub連携を有効にする"
github-integration-client-id: "Client ID"
github-integration-client-secret: "Client secret"
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"
proxy-account-config: "プロキシアカウントの設定"
proxy-account-info: "プロキシアカウントは、特定の条件下でユーザーのリモートフォローを代行するアカウントです。例えば、ユーザーがリモートユーザーをリストに入れたとき、リストに入れられたユーザーを誰もフォローしていないとアクティビティがサーバーに配達されないため、代わりにプロキシアカウントがフォローするようにします。"
proxy-account-username: "プロキシアカウントのユーザー名"
@ -1005,6 +1019,11 @@ admin/views/users.vue:
unverify-user: "ユーザーの公式アカウント解除"
unverify: "公式アカウントを解除する"
unverified: "公式アカウントを解除しました"
admin/views/moderators.vue:
add-moderator:
title: "モデレーターの登録"
add: "登録"
added: "モデレーターを登録しました"
admin/views/emoji.vue:
add-emoji:
title: "絵文字の登録"
@ -1332,6 +1351,10 @@ mobile/views/pages/settings.vue:
github-connect: "GitHubアカウントに接続する"
github-reconnect: "再接続する"
github-disconnect: "切断する"
discord: "Discord連携"
discord-connect: "Discordアカウントに接続する"
discord-reconnect: "再接続する"
discord-disconnect: "切断する"
update: "Misskey Update"
version: "バージョン:"
latest-version: "最新のバージョン:"

View File

@ -363,6 +363,7 @@ common/views/components/signin.vue:
or: "Oder"
signin-with-twitter: "Twitterでログイン"
signin-with-github: "GitHubでログイン"
signin-with-discord: "Discordでログイン"
login-failed: "ログインできませんでした。ユーザー名とパスワードを確認してください。"
common/views/components/signup.vue:
invitation-code: "招待コード"
@ -408,6 +409,13 @@ common/views/components/github-setting.vue:
reconnect: "再接続する"
connect: "GitHubと接続する"
disconnect: "切断する"
common/views/components/discord-setting.vue:
description: "お使いのDiscordアカウントをお使いのMisskeyアカウントに接続しておくと、プロフィールでDiscordアカウント情報が表示されるようになったり、Discordを用いた便利なサインインを利用できるようになります。"
connected-to: "次のDiscordアカウントに接続されています"
detail: "詳細..."
reconnect: "再接続する"
connect: "Discordと接続する"
disconnect: "切断する"
common/views/components/uploader.vue:
waiting: "Warten"
common/views/components/visibility-chooser.vue:
@ -911,6 +919,7 @@ admin/views/index.vue:
dashboard: "ダッシュボード"
instance: "インスタンス"
emoji: "カスタム絵文字"
moderators: "モデレーター"
users: "ユーザー"
update: "更新"
announcements: "お知らせ"
@ -955,7 +964,12 @@ admin/views/instance.vue:
github-integration-info: "コールバックURLは /api/gh/cb に設定します。"
enable-github-integration: "GitHub連携を有効にする"
github-integration-client-id: "Client ID"
github-integration-client-secret: "Client secret"
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"
proxy-account-config: "プロキシアカウントの設定"
proxy-account-info: "プロキシアカウントは、特定の条件下でユーザーのリモートフォローを代行するアカウントです。例えば、ユーザーがリモートユーザーをリストに入れたとき、リストに入れられたユーザーを誰もフォローしていないとアクティビティがサーバーに配達されないため、代わりにプロキシアカウントがフォローするようにします。"
proxy-account-username: "プロキシアカウントのユーザー名"
@ -1005,6 +1019,11 @@ admin/views/users.vue:
unverify-user: "ユーザーの公式アカウント解除"
unverify: "公式アカウントを解除する"
unverified: "公式アカウントを解除しました"
admin/views/moderators.vue:
add-moderator:
title: "モデレーターの登録"
add: "登録"
added: "モデレーターを登録しました"
admin/views/emoji.vue:
add-emoji:
title: "絵文字の登録"
@ -1332,6 +1351,10 @@ mobile/views/pages/settings.vue:
github-connect: "GitHubアカウントに接続する"
github-reconnect: "再接続する"
github-disconnect: "切断する"
discord: "Discord連携"
discord-connect: "Discordアカウントに接続する"
discord-reconnect: "再接続する"
discord-disconnect: "切断する"
update: "Misskey Update"
version: "バージョン:"
latest-version: "Neuste Version:"

View File

@ -16,7 +16,7 @@ common:
reaction-desc: "Easiest way to tell your emotions. Misskey allows you to add various type of reactions to others post. The emotional experience on Misskey will never be on other SNSs which only able to push “likes”."
ui: "Interface"
ui-desc: "No UI fits for everyone. Therefore, Misskey has a highly customizable UI for your taste. Make your original home by editing, adjusting layouts of timeline and placing selectable widgets you can easily customize."
drive: "Misskey Drive"
drive: "Drive"
drive-desc: "Wanna post a picture you have already uploaded? Wish to organize, name and create a folder for your uploaded files? Misskey Drive is the best solution for you. Very easy to share your files online."
outro: "Check further Misskey-unique features on your eyes! Feeling like this is not for you, try other instances as Misskey is a decentralized SNS so that you can easily find your mates. Then, GLHF!"
adblock:
@ -363,6 +363,7 @@ common/views/components/signin.vue:
or: "Or"
signin-with-twitter: "Log in with Twitter"
signin-with-github: "Log in with GitHub"
signin-with-discord: "Login 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"
@ -406,7 +407,14 @@ common/views/components/github-setting.vue:
connected-to: "You are connected to this GitHub account"
detail: "More..."
reconnect: "Reconnect"
connect: "Connect to GitHub"
connect: "Link your GitHub account"
disconnect: "Disconnect"
common/views/components/discord-setting.vue:
description: "Once you connect your Discord account to your Misskey account, you will be able to see information about your Discord account on your profile, and you will be able to sign-in using Discord."
connected-to: "You are connected to this Discord account"
detail: "Details…"
reconnect: "Reconnect"
connect: "Link your Discord account"
disconnect: "Disconnect"
common/views/components/uploader.vue:
waiting: "Waiting"
@ -835,7 +843,7 @@ common/views/components/mute-and-block.vue:
no-blocked-users: "No blocked users"
word-mute: "Word mute"
muted-words: "Muted keywords"
muted-words-description: "スペースで区切るとAND指定になり、改行で区切るとOR指定になります"
muted-words-description: "Separating with spaces results in AND specifications, and delimiting with line breaks results in OR specifications"
save: "Save"
common/views/components/password-settings.vue:
reset: "Change password"
@ -911,6 +919,7 @@ admin/views/index.vue:
dashboard: "Dashboard"
instance: "Instance"
emoji: "Emoji"
moderators: "Moderator"
users: "Users"
update: "Update"
announcements: "Announcements"
@ -955,7 +964,12 @@ admin/views/instance.vue:
github-integration-info: "The callback URL is set on /api/gh/cb."
enable-github-integration: "Enable connection to GitHub"
github-integration-client-id: "Client ID"
github-integration-client-secret: "Client secret"
github-integration-client-secret: "Client Secret"
discord-integration-config: "Setting of Discord Integration"
discord-integration-info: "The callback URL is set on /api/dc/cb."
enable-discord-integration: "Enable Discord connection"
discord-integration-client-id: "Client ID"
discord-integration-client-secret: "Client Secret"
proxy-account-config: "Proxy account"
proxy-account-info: "Proxy account can follow a remote user to deliver activities if no one in this instance follow him or her. When you add a remote user who is followed by nobody in this instance to your list, in order to get his or her data, proxy account follow him or her instead of your following."
proxy-account-username: "Proxy account user name"
@ -1005,6 +1019,11 @@ admin/views/users.vue:
unverify-user: "User account unverification settings"
unverify: "Unverify account"
unverified: "The account is now being unverified"
admin/views/moderators.vue:
add-moderator:
title: "Register Moderator"
add: "Register"
added: "Registered a Moderator."
admin/views/emoji.vue:
add-emoji:
title: "Add emoji"
@ -1332,6 +1351,10 @@ mobile/views/pages/settings.vue:
github-connect: "Connect to your GitHub account"
github-reconnect: "Reconnect"
github-disconnect: "Disconnect"
discord: "Discord Integration"
discord-connect: "Connect to your Discord account"
discord-reconnect: "Reconnect"
discord-disconnect: "Disconnect"
update: "Misskey Update"
version: "Current version:"
latest-version: "Latest version:"

View File

@ -363,6 +363,7 @@ common/views/components/signin.vue:
or: "O"
signin-with-twitter: "Ingresar con Twitter"
signin-with-github: "GitHubでログイン"
signin-with-discord: "Discordでログイン"
login-failed: "Autenticación fallida. Asegúrate de haber usado el nombre de usuario y contraseña correctos."
common/views/components/signup.vue:
invitation-code: "Código de invitación"
@ -408,6 +409,13 @@ common/views/components/github-setting.vue:
reconnect: "再接続する"
connect: "GitHubと接続する"
disconnect: "切断する"
common/views/components/discord-setting.vue:
description: "お使いのDiscordアカウントをお使いのMisskeyアカウントに接続しておくと、プロフィールでDiscordアカウント情報が表示されるようになったり、Discordを用いた便利なサインインを利用できるようになります。"
connected-to: "次のDiscordアカウントに接続されています"
detail: "詳細..."
reconnect: "再接続する"
connect: "Discordと接続する"
disconnect: "切断する"
common/views/components/uploader.vue:
waiting: "Un momento"
common/views/components/visibility-chooser.vue:
@ -911,6 +919,7 @@ admin/views/index.vue:
dashboard: "ダッシュボード"
instance: "インスタンス"
emoji: "カスタム絵文字"
moderators: "モデレーター"
users: "ユーザー"
update: "更新"
announcements: "お知らせ"
@ -955,7 +964,12 @@ admin/views/instance.vue:
github-integration-info: "コールバックURLは /api/gh/cb に設定します。"
enable-github-integration: "GitHub連携を有効にする"
github-integration-client-id: "Client ID"
github-integration-client-secret: "Client secret"
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"
proxy-account-config: "プロキシアカウントの設定"
proxy-account-info: "プロキシアカウントは、特定の条件下でユーザーのリモートフォローを代行するアカウントです。例えば、ユーザーがリモートユーザーをリストに入れたとき、リストに入れられたユーザーを誰もフォローしていないとアクティビティがサーバーに配達されないため、代わりにプロキシアカウントがフォローするようにします。"
proxy-account-username: "プロキシアカウントのユーザー名"
@ -1005,6 +1019,11 @@ admin/views/users.vue:
unverify-user: "ユーザーの公式アカウント解除"
unverify: "公式アカウントを解除する"
unverified: "公式アカウントを解除しました"
admin/views/moderators.vue:
add-moderator:
title: "モデレーターの登録"
add: "登録"
added: "モデレーターを登録しました"
admin/views/emoji.vue:
add-emoji:
title: "絵文字の登録"
@ -1332,6 +1351,10 @@ mobile/views/pages/settings.vue:
github-connect: "GitHubアカウントに接続する"
github-reconnect: "再接続する"
github-disconnect: "切断する"
discord: "Discord連携"
discord-connect: "Discordアカウントに接続する"
discord-reconnect: "再接続する"
discord-disconnect: "切断する"
update: "Misskey Update"
version: "バージョン:"
latest-version: "最新のバージョン:"

View File

@ -363,6 +363,7 @@ common/views/components/signin.vue:
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."
common/views/components/signup.vue:
invitation-code: "Code dinvitation"
@ -408,6 +409,13 @@ common/views/components/github-setting.vue:
reconnect: "Reconnecter"
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: "切断する"
common/views/components/uploader.vue:
waiting: "Veuillez patienter"
common/views/components/visibility-chooser.vue:
@ -500,7 +508,7 @@ common/views/pages/follow.vue:
signed-in-as: "Connecté·e en tant que {}"
following: "Suit"
follow: "Suivre"
request-pending: "Demande d'abonnement en attente"
request-pending: "Demande dabonnement en attente"
follow-processing: "Demande en attente"
follow-request: "Demande dabonnement"
desktop:
@ -601,7 +609,7 @@ desktop/views/components/media-video.vue:
desktop/views/components/followers-window.vue:
followers: "{} abonné·e·s"
desktop/views/components/followers.vue:
empty: "Il semble que vous n'avez pas encore d'abonné·e·s."
empty: "Il semble que vous navez pas encore dabonné·e·s."
desktop/views/components/following-window.vue:
following: "Suit {}"
desktop/views/components/following.vue:
@ -644,7 +652,7 @@ desktop/views/components/notes.vue:
error: "Échec du chargement."
retry: "Réessayer"
desktop/views/components/notifications.vue:
empty: "Pas de notifications"
empty: "Aucune de notification !"
desktop/views/components/post-form.vue:
add-visible-user: "+Ajouter un utilisateur"
attach-location-information: "Attacher des informations de localisation"
@ -888,7 +896,7 @@ desktop/views/components/ui.header.search.vue:
placeholder: "Chercher"
desktop/views/components/received-follow-requests-window.vue:
title: "Demandes de suivi"
accept: "Approuver"
accept: "Accepter"
reject: "Refuser"
desktop/views/components/user-lists-window.vue:
title: "Listes de l'utilisateur"
@ -911,6 +919,7 @@ admin/views/index.vue:
dashboard: "Tableau de bord"
instance: "Instance"
emoji: "Emoji"
moderators: "モデレーター"
users: "Utilisateur·rice·s"
update: "Mise à jour"
announcements: "Annonces"
@ -955,7 +964,12 @@ 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: "Secret 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"
proxy-account-config: "Compte proxy"
proxy-account-info: "プロキシアカウントは、特定の条件下でユーザーのリモートフォローを代行するアカウントです。例えば、ユーザーがリモートユーザーをリストに入れたとき、リストに入れられたユーザーを誰もフォローしていないとアクティビティがサーバーに配達されないため、代わりにプロキシアカウントがフォローするようにします。"
proxy-account-username: "Nom dutilisateur du compte proxy"
@ -1005,6 +1019,11 @@ admin/views/users.vue:
unverify-user: "ユーザーの公式アカウント解除"
unverify: "Ôter la vérification du compte"
unverified: "Ce compte n'est plus vérifié"
admin/views/moderators.vue:
add-moderator:
title: "モデレーターの登録"
add: "登録"
added: "モデレーターを登録しました"
admin/views/emoji.vue:
add-emoji:
title: "Ajouter un émoji"
@ -1171,10 +1190,10 @@ mobile/views/components/media-video.vue:
click-to-show: "Cliquer pour afficher"
common/views/components/follow-button.vue:
following: "Abonné·e"
follow: "Sabonner"
follow: " Suivre"
request-pending: "Demande en attente"
follow-processing: "フォロー処理中"
follow-request: "フォロー申請"
follow-processing: "En cours dabonnement"
follow-request: "Demande dabonnement"
mobile/views/components/friends-maker.vue:
title: "Abonnez-vous aux utilisateurs"
empty: "Impossible de trouver des utilisateurs·trices à recommander."
@ -1202,7 +1221,7 @@ mobile/views/components/note-sub.vue:
bot: "bot"
cat: "chat"
mobile/views/components/notifications.vue:
empty: "Pas de notifications"
empty: "Aucune de notification !"
mobile/views/components/post-form.vue:
add-visible-user: "Ajouter un utilisateur"
submit: "Publier"
@ -1284,7 +1303,7 @@ mobile/views/pages/note.vue:
next: "Note suivante"
mobile/views/pages/notifications.vue:
notifications: "Notifications"
read-all: "Êtes vous sûr de vouloir marqués toutes les notifications non-lus en tant que lus?"
read-all: "Êtes-vous sûr de vouloir marquer lensemble des notifications comme étant lues ?"
mobile/views/pages/games/reversi.vue:
reversi: "Reversi"
mobile/views/pages/search.vue:
@ -1332,6 +1351,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: "切断する"
update: "Mise à jour de Misskey"
version: "Version :"
latest-version: "Dernière version :"
@ -1371,7 +1394,7 @@ mobile/views/pages/user/home.vue:
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 connu"
no-users: "Aucun utilisateur·rice connu·e"
mobile/views/pages/user/home.friends.vue:
no-users: "Pass d'utilisateurs"
mobile/views/pages/user/home.notes.vue:

View File

@ -363,6 +363,7 @@ common/views/components/signin.vue:
or: "または"
signin-with-twitter: "Twitterでログイン"
signin-with-github: "GitHubでログイン"
signin-with-discord: "Discordでログイン"
login-failed: "ログインできませんでした。ユーザー名とパスワードを確認してください。"
common/views/components/signup.vue:
invitation-code: "招待コード"
@ -408,6 +409,13 @@ common/views/components/github-setting.vue:
reconnect: "再接続する"
connect: "GitHubと接続する"
disconnect: "切断する"
common/views/components/discord-setting.vue:
description: "お使いのDiscordアカウントをお使いのMisskeyアカウントに接続しておくと、プロフィールでDiscordアカウント情報が表示されるようになったり、Discordを用いた便利なサインインを利用できるようになります。"
connected-to: "次のDiscordアカウントに接続されています"
detail: "詳細..."
reconnect: "再接続する"
connect: "Discordと接続する"
disconnect: "切断する"
common/views/components/uploader.vue:
waiting: "待機中"
common/views/components/visibility-chooser.vue:
@ -911,6 +919,7 @@ admin/views/index.vue:
dashboard: "ダッシュボード"
instance: "インスタンス"
emoji: "カスタム絵文字"
moderators: "モデレーター"
users: "ユーザー"
update: "更新"
announcements: "お知らせ"
@ -955,7 +964,12 @@ admin/views/instance.vue:
github-integration-info: "コールバックURLは /api/gh/cb に設定します。"
enable-github-integration: "GitHub連携を有効にする"
github-integration-client-id: "Client ID"
github-integration-client-secret: "Client secret"
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"
proxy-account-config: "プロキシアカウントの設定"
proxy-account-info: "プロキシアカウントは、特定の条件下でユーザーのリモートフォローを代行するアカウントです。例えば、ユーザーがリモートユーザーをリストに入れたとき、リストに入れられたユーザーを誰もフォローしていないとアクティビティがサーバーに配達されないため、代わりにプロキシアカウントがフォローするようにします。"
proxy-account-username: "プロキシアカウントのユーザー名"
@ -1005,6 +1019,11 @@ admin/views/users.vue:
unverify-user: "ユーザーの公式アカウント解除"
unverify: "公式アカウントを解除する"
unverified: "公式アカウントを解除しました"
admin/views/moderators.vue:
add-moderator:
title: "モデレーターの登録"
add: "登録"
added: "モデレーターを登録しました"
admin/views/emoji.vue:
add-emoji:
title: "絵文字の登録"
@ -1332,6 +1351,10 @@ mobile/views/pages/settings.vue:
github-connect: "GitHubアカウントに接続する"
github-reconnect: "再接続する"
github-disconnect: "切断する"
discord: "Discord連携"
discord-connect: "Discordアカウントに接続する"
discord-reconnect: "再接続する"
discord-disconnect: "切断する"
update: "Misskey Update"
version: "バージョン:"
latest-version: "最新のバージョン:"

View File

@ -96,6 +96,9 @@ common:
specified: "ダイレクト"
specified-desc: "指定したユーザーにのみ公開"
private: "非公開"
local-public: "公開(ローカルのみ)"
local-home: "ホーム(ローカルのみ)"
local-followers: "フォロワー(ローカルのみ)"
note-placeholders:
a: "今どうしてる?"
@ -399,6 +402,7 @@ common/views/components/signin.vue:
or: "または"
signin-with-twitter: "Twitterでログイン"
signin-with-github: "GitHubでログイン"
signin-with-discord: "Discordでログイン"
login-failed: "ログインできませんでした。ユーザー名とパスワードを確認してください。"
common/views/components/signup.vue:
@ -450,6 +454,14 @@ common/views/components/github-setting.vue:
connect: "GitHubと接続する"
disconnect: "切断する"
common/views/components/discord-setting.vue:
description: "お使いのDiscordアカウントをお使いのMisskeyアカウントに接続しておくと、プロフィールでDiscordアカウント情報が表示されるようになったり、Discordを用いた便利なサインインを利用できるようになります。"
connected-to: "次のDiscordアカウントに接続されています"
detail: "詳細..."
reconnect: "再接続する"
connect: "Discordと接続する"
disconnect: "切断する"
common/views/components/uploader.vue:
waiting: "待機中"
@ -462,6 +474,9 @@ common/views/components/visibility-chooser.vue:
specified: "ダイレクト"
specified-desc: "指定したユーザーにのみ公開"
private: "非公開"
local-public: "公開(ローカルのみ)"
local-home: "ホーム(ローカルのみ)"
local-followers: "フォロワー(ローカルのみ)"
common/views/components/trends.vue:
count: "{}人が投稿"
@ -752,6 +767,7 @@ desktop/views/components/post-form.vue:
create-poll: "アンケートを作成"
text-remain: "残り{}文字"
recent-tags: "最近"
local-only-message: "この投稿はローカルにのみ公開されます"
click-to-tagging: "クリックでタグ付け"
visibility: "公開範囲"
geolocation-alert: "お使いの端末は位置情報に対応していません"
@ -790,6 +806,7 @@ desktop/views/components/settings.vue:
profile: "プロフィール"
notification: "通知"
apps: "アプリ"
tags: "ハッシュタグ"
mute-and-block: "ミュート/ブロック"
blocking: "ブロック"
security: "セキュリティ"
@ -834,6 +851,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: "左"
@ -1034,8 +1052,9 @@ admin/views/index.vue:
dashboard: "ダッシュボード"
instance: "インスタンス"
emoji: "カスタム絵文字"
moderators: "モデレーター"
users: "ユーザー"
update: "更新"
federation: "連合"
announcements: "お知らせ"
hashtags: "ハッシュタグ"
back-to-misskey: "Misskeyに戻る"
@ -1080,7 +1099,12 @@ admin/views/instance.vue:
github-integration-info: "コールバックURLは /api/gh/cb に設定します。"
enable-github-integration: "GitHub連携を有効にする"
github-integration-client-id: "Client ID"
github-integration-client-secret: "Client secret"
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"
proxy-account-config: "プロキシアカウントの設定"
proxy-account-info: "プロキシアカウントは、特定の条件下でユーザーのリモートフォローを代行するアカウントです。例えば、ユーザーがリモートユーザーをリストに入れたとき、リストに入れられたユーザーを誰もフォローしていないとアクティビティがサーバーに配達されないため、代わりにプロキシアカウントがフォローするようにします。"
proxy-account-username: "プロキシアカウントのユーザー名"
@ -1133,6 +1157,12 @@ admin/views/users.vue:
unverify: "公式アカウントを解除する"
unverified: "公式アカウントを解除しました"
admin/views/moderators.vue:
add-moderator:
title: "モデレーターの登録"
add: "登録"
added: "モデレーターを登録しました"
admin/views/emoji.vue:
add-emoji:
title: "絵文字の登録"
@ -1523,6 +1553,10 @@ mobile/views/pages/settings.vue:
github-connect: "GitHubアカウントに接続する"
github-reconnect: "再接続する"
github-disconnect: "切断する"
discord: "Discord連携"
discord-connect: "Discordアカウントに接続する"
discord-reconnect: "再接続する"
discord-disconnect: "切断する"
update: "Misskey Update"
version: "バージョン:"
latest-version: "最新のバージョン:"

View File

@ -363,6 +363,7 @@ common/views/components/signin.vue:
or: "それか"
signin-with-twitter: "Twitterでサインイン"
signin-with-github: "GitHubでログイン"
signin-with-discord: "Discordでログイン"
login-failed: "なんかログインできんかったわ。ユーザー名とパスワードとかを確認してや。"
common/views/components/signup.vue:
invitation-code: "招待コード"
@ -408,6 +409,13 @@ common/views/components/github-setting.vue:
reconnect: "再接続する"
connect: "GitHubと接続する"
disconnect: "切断する"
common/views/components/discord-setting.vue:
description: "お使いのDiscordアカウントをお使いのMisskeyアカウントに接続しておくと、プロフィールでDiscordアカウント情報が表示されるようになったり、Discordを用いた便利なサインインを利用できるようになります。"
connected-to: "次のDiscordアカウントに接続されています"
detail: "詳細..."
reconnect: "再接続する"
connect: "Discordと接続する"
disconnect: "切断する"
common/views/components/uploader.vue:
waiting: "待っとる"
common/views/components/visibility-chooser.vue:
@ -911,6 +919,7 @@ admin/views/index.vue:
dashboard: "ダッシュボード"
instance: "インスタンス"
emoji: "カスタム絵文字"
moderators: "モデレーター"
users: "ユーザー"
update: "更新"
announcements: "知っといてや"
@ -955,7 +964,12 @@ admin/views/instance.vue:
github-integration-info: "コールバックURLは /api/gh/cb に設定します。"
enable-github-integration: "GitHub連携を有効にする"
github-integration-client-id: "Client ID"
github-integration-client-secret: "Client secret"
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"
proxy-account-config: "プロキシアカウントの設定"
proxy-account-info: "プロキシアカウントは、特定の条件下でユーザーのリモートフォローを代行するアカウントです。例えば、ユーザーがリモートユーザーをリストに入れたとき、リストに入れられたユーザーを誰もフォローしていないとアクティビティがサーバーに配達されないため、代わりにプロキシアカウントがフォローするようにします。"
proxy-account-username: "プロキシアカウントのユーザー名"
@ -1005,6 +1019,11 @@ admin/views/users.vue:
unverify-user: "ユーザーの公式アカウント解除"
unverify: "公式アカウントを解除する"
unverified: "公式アカウントを解除しました"
admin/views/moderators.vue:
add-moderator:
title: "モデレーターの登録"
add: "登録"
added: "モデレーターを登録しました"
admin/views/emoji.vue:
add-emoji:
title: "絵文字の登録"
@ -1332,6 +1351,10 @@ mobile/views/pages/settings.vue:
github-connect: "GitHubアカウントに接続する"
github-reconnect: "再接続する"
github-disconnect: "切断する"
discord: "Discord連携"
discord-connect: "Discordアカウントに接続する"
discord-reconnect: "再接続する"
discord-disconnect: "切断する"
update: "あんたのMisskeyいつのや"
version: "バージョン:"
latest-version: "いっちゃん新しいやつ:"

View File

@ -363,6 +363,7 @@ common/views/components/signin.vue:
or: "または"
signin-with-twitter: "Twitterでログイン"
signin-with-github: "GitHubでログイン"
signin-with-discord: "Discordでログイン"
login-failed: "ログインできませんでした。ユーザー名とパスワードを確認してください。"
common/views/components/signup.vue:
invitation-code: "招待コード"
@ -408,6 +409,13 @@ common/views/components/github-setting.vue:
reconnect: "再接続する"
connect: "GitHubと接続する"
disconnect: "切断する"
common/views/components/discord-setting.vue:
description: "お使いのDiscordアカウントをお使いのMisskeyアカウントに接続しておくと、プロフィールでDiscordアカウント情報が表示されるようになったり、Discordを用いた便利なサインインを利用できるようになります。"
connected-to: "次のDiscordアカウントに接続されています"
detail: "詳細..."
reconnect: "再接続する"
connect: "Discordと接続する"
disconnect: "切断する"
common/views/components/uploader.vue:
waiting: "待機中"
common/views/components/visibility-chooser.vue:
@ -911,6 +919,7 @@ admin/views/index.vue:
dashboard: "ダッシュボード"
instance: "インスタンス"
emoji: "カスタム絵文字"
moderators: "モデレーター"
users: "ユーザー"
update: "更新"
announcements: "お知らせ"
@ -955,7 +964,12 @@ admin/views/instance.vue:
github-integration-info: "コールバックURLは /api/gh/cb に設定します。"
enable-github-integration: "GitHub連携を有効にする"
github-integration-client-id: "Client ID"
github-integration-client-secret: "Client secret"
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"
proxy-account-config: "プロキシアカウントの設定"
proxy-account-info: "プロキシアカウントは、特定の条件下でユーザーのリモートフォローを代行するアカウントです。例えば、ユーザーがリモートユーザーをリストに入れたとき、リストに入れられたユーザーを誰もフォローしていないとアクティビティがサーバーに配達されないため、代わりにプロキシアカウントがフォローするようにします。"
proxy-account-username: "プロキシアカウントのユーザー名"
@ -1005,6 +1019,11 @@ admin/views/users.vue:
unverify-user: "ユーザーの公式アカウント解除"
unverify: "公式アカウントを解除する"
unverified: "公式アカウントを解除しました"
admin/views/moderators.vue:
add-moderator:
title: "モデレーターの登録"
add: "登録"
added: "モデレーターを登録しました"
admin/views/emoji.vue:
add-emoji:
title: "絵文字の登録"
@ -1332,6 +1351,10 @@ mobile/views/pages/settings.vue:
github-connect: "GitHubアカウントに接続する"
github-reconnect: "再接続する"
github-disconnect: "切断する"
discord: "Discord連携"
discord-connect: "Discordアカウントに接続する"
discord-reconnect: "再接続する"
discord-disconnect: "切断する"
update: "Misskey Update"
version: "バージョン:"
latest-version: "最新のバージョン:"

View File

@ -363,6 +363,7 @@ common/views/components/signin.vue:
or: "または"
signin-with-twitter: "Twitterでログイン"
signin-with-github: "GitHubでログイン"
signin-with-discord: "Discordでログイン"
login-failed: "ログインできませんでした。ユーザー名とパスワードを確認してください。"
common/views/components/signup.vue:
invitation-code: "招待コード"
@ -408,6 +409,13 @@ common/views/components/github-setting.vue:
reconnect: "再接続する"
connect: "GitHubと接続する"
disconnect: "切断する"
common/views/components/discord-setting.vue:
description: "お使いのDiscordアカウントをお使いのMisskeyアカウントに接続しておくと、プロフィールでDiscordアカウント情報が表示されるようになったり、Discordを用いた便利なサインインを利用できるようになります。"
connected-to: "次のDiscordアカウントに接続されています"
detail: "詳細..."
reconnect: "再接続する"
connect: "Discordと接続する"
disconnect: "切断する"
common/views/components/uploader.vue:
waiting: "Bezig met wachten"
common/views/components/visibility-chooser.vue:
@ -911,6 +919,7 @@ admin/views/index.vue:
dashboard: "ダッシュボード"
instance: "インスタンス"
emoji: "カスタム絵文字"
moderators: "モデレーター"
users: "ユーザー"
update: "更新"
announcements: "お知らせ"
@ -955,7 +964,12 @@ admin/views/instance.vue:
github-integration-info: "コールバックURLは /api/gh/cb に設定します。"
enable-github-integration: "GitHub連携を有効にする"
github-integration-client-id: "Client ID"
github-integration-client-secret: "Client secret"
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"
proxy-account-config: "プロキシアカウントの設定"
proxy-account-info: "プロキシアカウントは、特定の条件下でユーザーのリモートフォローを代行するアカウントです。例えば、ユーザーがリモートユーザーをリストに入れたとき、リストに入れられたユーザーを誰もフォローしていないとアクティビティがサーバーに配達されないため、代わりにプロキシアカウントがフォローするようにします。"
proxy-account-username: "プロキシアカウントのユーザー名"
@ -1005,6 +1019,11 @@ admin/views/users.vue:
unverify-user: "ユーザーの公式アカウント解除"
unverify: "公式アカウントを解除する"
unverified: "公式アカウントを解除しました"
admin/views/moderators.vue:
add-moderator:
title: "モデレーターの登録"
add: "登録"
added: "モデレーターを登録しました"
admin/views/emoji.vue:
add-emoji:
title: "絵文字の登録"
@ -1332,6 +1351,10 @@ mobile/views/pages/settings.vue:
github-connect: "GitHubアカウントに接続する"
github-reconnect: "再接続する"
github-disconnect: "切断する"
discord: "Discord連携"
discord-connect: "Discordアカウントに接続する"
discord-reconnect: "再接続する"
discord-disconnect: "切断する"
update: "Misskey-update"
version: "Huidige versie:"
latest-version: "Nieuwste versie:"

View File

@ -363,6 +363,7 @@ common/views/components/signin.vue:
or: "Eller"
signin-with-twitter: "Twitterでログイン"
signin-with-github: "GitHubでログイン"
signin-with-discord: "Discordでログイン"
login-failed: "ログインできませんでした。ユーザー名とパスワードを確認してください。"
common/views/components/signup.vue:
invitation-code: "招待コード"
@ -408,6 +409,13 @@ common/views/components/github-setting.vue:
reconnect: "再接続する"
connect: "GitHubと接続する"
disconnect: "切断する"
common/views/components/discord-setting.vue:
description: "お使いのDiscordアカウントをお使いのMisskeyアカウントに接続しておくと、プロフィールでDiscordアカウント情報が表示されるようになったり、Discordを用いた便利なサインインを利用できるようになります。"
connected-to: "次のDiscordアカウントに接続されています"
detail: "詳細..."
reconnect: "再接続する"
connect: "Discordと接続する"
disconnect: "切断する"
common/views/components/uploader.vue:
waiting: "Venter"
common/views/components/visibility-chooser.vue:
@ -911,6 +919,7 @@ admin/views/index.vue:
dashboard: "ダッシュボード"
instance: "インスタンス"
emoji: "カスタム絵文字"
moderators: "モデレーター"
users: "ユーザー"
update: "更新"
announcements: "お知らせ"
@ -955,7 +964,12 @@ admin/views/instance.vue:
github-integration-info: "コールバックURLは /api/gh/cb に設定します。"
enable-github-integration: "GitHub連携を有効にする"
github-integration-client-id: "Client ID"
github-integration-client-secret: "Client secret"
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"
proxy-account-config: "プロキシアカウントの設定"
proxy-account-info: "プロキシアカウントは、特定の条件下でユーザーのリモートフォローを代行するアカウントです。例えば、ユーザーがリモートユーザーをリストに入れたとき、リストに入れられたユーザーを誰もフォローしていないとアクティビティがサーバーに配達されないため、代わりにプロキシアカウントがフォローするようにします。"
proxy-account-username: "プロキシアカウントのユーザー名"
@ -1005,6 +1019,11 @@ admin/views/users.vue:
unverify-user: "ユーザーの公式アカウント解除"
unverify: "公式アカウントを解除する"
unverified: "公式アカウントを解除しました"
admin/views/moderators.vue:
add-moderator:
title: "モデレーターの登録"
add: "登録"
added: "モデレーターを登録しました"
admin/views/emoji.vue:
add-emoji:
title: "絵文字の登録"
@ -1332,6 +1351,10 @@ mobile/views/pages/settings.vue:
github-connect: "GitHubアカウントに接続する"
github-reconnect: "再接続する"
github-disconnect: "切断する"
discord: "Discord連携"
discord-connect: "Discordアカウントに接続する"
discord-reconnect: "再接続する"
discord-disconnect: "切断する"
update: "Misskey Update"
version: "バージョン:"
latest-version: "最新のバージョン:"

View File

@ -363,6 +363,7 @@ common/views/components/signin.vue:
or: "または"
signin-with-twitter: "Zaloguj się za pomocą Twittera"
signin-with-github: "GitHubでログイン"
signin-with-discord: "Discordでログイン"
login-failed: "ログインできませんでした。ユーザー名とパスワードを確認してください。"
common/views/components/signup.vue:
invitation-code: "招待コード"
@ -408,6 +409,13 @@ common/views/components/github-setting.vue:
reconnect: "再接続する"
connect: "GitHubと接続する"
disconnect: "切断する"
common/views/components/discord-setting.vue:
description: "お使いのDiscordアカウントをお使いのMisskeyアカウントに接続しておくと、プロフィールでDiscordアカウント情報が表示されるようになったり、Discordを用いた便利なサインインを利用できるようになります。"
connected-to: "次のDiscordアカウントに接続されています"
detail: "詳細..."
reconnect: "再接続する"
connect: "Discordと接続する"
disconnect: "切断する"
common/views/components/uploader.vue:
waiting: "Oczekiwanie"
common/views/components/visibility-chooser.vue:
@ -911,6 +919,7 @@ admin/views/index.vue:
dashboard: "ダッシュボード"
instance: "インスタンス"
emoji: "カスタム絵文字"
moderators: "モデレーター"
users: "ユーザー"
update: "更新"
announcements: "お知らせ"
@ -955,7 +964,12 @@ admin/views/instance.vue:
github-integration-info: "コールバックURLは /api/gh/cb に設定します。"
enable-github-integration: "GitHub連携を有効にする"
github-integration-client-id: "Client ID"
github-integration-client-secret: "Client secret"
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"
proxy-account-config: "プロキシアカウントの設定"
proxy-account-info: "プロキシアカウントは、特定の条件下でユーザーのリモートフォローを代行するアカウントです。例えば、ユーザーがリモートユーザーをリストに入れたとき、リストに入れられたユーザーを誰もフォローしていないとアクティビティがサーバーに配達されないため、代わりにプロキシアカウントがフォローするようにします。"
proxy-account-username: "プロキシアカウントのユーザー名"
@ -1005,6 +1019,11 @@ admin/views/users.vue:
unverify-user: "ユーザーの公式アカウント解除"
unverify: "公式アカウントを解除する"
unverified: "公式アカウントを解除しました"
admin/views/moderators.vue:
add-moderator:
title: "モデレーターの登録"
add: "登録"
added: "モデレーターを登録しました"
admin/views/emoji.vue:
add-emoji:
title: "絵文字の登録"
@ -1332,6 +1351,10 @@ mobile/views/pages/settings.vue:
github-connect: "GitHubアカウントに接続する"
github-reconnect: "再接続する"
github-disconnect: "切断する"
discord: "Discord連携"
discord-connect: "Discordアカウントに接続する"
discord-reconnect: "再接続する"
discord-disconnect: "切断する"
update: "Aktualizacja Misskey"
version: "Wersja:"
latest-version: "Najnowsza wersja:"

View File

@ -363,6 +363,7 @@ common/views/components/signin.vue:
or: "または"
signin-with-twitter: "Twitterでログイン"
signin-with-github: "GitHubでログイン"
signin-with-discord: "Discordでログイン"
login-failed: "ログインできませんでした。ユーザー名とパスワードを確認してください。"
common/views/components/signup.vue:
invitation-code: "招待コード"
@ -408,6 +409,13 @@ common/views/components/github-setting.vue:
reconnect: "再接続する"
connect: "GitHubと接続する"
disconnect: "切断する"
common/views/components/discord-setting.vue:
description: "お使いのDiscordアカウントをお使いのMisskeyアカウントに接続しておくと、プロフィールでDiscordアカウント情報が表示されるようになったり、Discordを用いた便利なサインインを利用できるようになります。"
connected-to: "次のDiscordアカウントに接続されています"
detail: "詳細..."
reconnect: "再接続する"
connect: "Discordと接続する"
disconnect: "切断する"
common/views/components/uploader.vue:
waiting: "待機中"
common/views/components/visibility-chooser.vue:
@ -911,6 +919,7 @@ admin/views/index.vue:
dashboard: "ダッシュボード"
instance: "インスタンス"
emoji: "カスタム絵文字"
moderators: "モデレーター"
users: "ユーザー"
update: "更新"
announcements: "お知らせ"
@ -955,7 +964,12 @@ admin/views/instance.vue:
github-integration-info: "コールバックURLは /api/gh/cb に設定します。"
enable-github-integration: "GitHub連携を有効にする"
github-integration-client-id: "Client ID"
github-integration-client-secret: "Client secret"
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"
proxy-account-config: "プロキシアカウントの設定"
proxy-account-info: "プロキシアカウントは、特定の条件下でユーザーのリモートフォローを代行するアカウントです。例えば、ユーザーがリモートユーザーをリストに入れたとき、リストに入れられたユーザーを誰もフォローしていないとアクティビティがサーバーに配達されないため、代わりにプロキシアカウントがフォローするようにします。"
proxy-account-username: "プロキシアカウントのユーザー名"
@ -1005,6 +1019,11 @@ admin/views/users.vue:
unverify-user: "ユーザーの公式アカウント解除"
unverify: "公式アカウントを解除する"
unverified: "公式アカウントを解除しました"
admin/views/moderators.vue:
add-moderator:
title: "モデレーターの登録"
add: "登録"
added: "モデレーターを登録しました"
admin/views/emoji.vue:
add-emoji:
title: "絵文字の登録"
@ -1332,6 +1351,10 @@ mobile/views/pages/settings.vue:
github-connect: "GitHubアカウントに接続する"
github-reconnect: "再接続する"
github-disconnect: "切断する"
discord: "Discord連携"
discord-connect: "Discordアカウントに接続する"
discord-reconnect: "再接続する"
discord-disconnect: "切断する"
update: "Atualizar Misskey"
version: "Versão atual;"
latest-version: "Última versão:"

View File

@ -363,6 +363,7 @@ common/views/components/signin.vue:
or: "または"
signin-with-twitter: "Twitterでログイン"
signin-with-github: "GitHubでログイン"
signin-with-discord: "Discordでログイン"
login-failed: "ログインできませんでした。ユーザー名とパスワードを確認してください。"
common/views/components/signup.vue:
invitation-code: "招待コード"
@ -408,6 +409,13 @@ common/views/components/github-setting.vue:
reconnect: "再接続する"
connect: "GitHubと接続する"
disconnect: "切断する"
common/views/components/discord-setting.vue:
description: "お使いのDiscordアカウントをお使いのMisskeyアカウントに接続しておくと、プロフィールでDiscordアカウント情報が表示されるようになったり、Discordを用いた便利なサインインを利用できるようになります。"
connected-to: "次のDiscordアカウントに接続されています"
detail: "詳細..."
reconnect: "再接続する"
connect: "Discordと接続する"
disconnect: "切断する"
common/views/components/uploader.vue:
waiting: "待機中"
common/views/components/visibility-chooser.vue:
@ -911,6 +919,7 @@ admin/views/index.vue:
dashboard: "ダッシュボード"
instance: "インスタンス"
emoji: "カスタム絵文字"
moderators: "モデレーター"
users: "ユーザー"
update: "更新"
announcements: "お知らせ"
@ -955,7 +964,12 @@ admin/views/instance.vue:
github-integration-info: "コールバックURLは /api/gh/cb に設定します。"
enable-github-integration: "GitHub連携を有効にする"
github-integration-client-id: "Client ID"
github-integration-client-secret: "Client secret"
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"
proxy-account-config: "プロキシアカウントの設定"
proxy-account-info: "プロキシアカウントは、特定の条件下でユーザーのリモートフォローを代行するアカウントです。例えば、ユーザーがリモートユーザーをリストに入れたとき、リストに入れられたユーザーを誰もフォローしていないとアクティビティがサーバーに配達されないため、代わりにプロキシアカウントがフォローするようにします。"
proxy-account-username: "プロキシアカウントのユーザー名"
@ -1005,6 +1019,11 @@ admin/views/users.vue:
unverify-user: "ユーザーの公式アカウント解除"
unverify: "公式アカウントを解除する"
unverified: "公式アカウントを解除しました"
admin/views/moderators.vue:
add-moderator:
title: "モデレーターの登録"
add: "登録"
added: "モデレーターを登録しました"
admin/views/emoji.vue:
add-emoji:
title: "絵文字の登録"
@ -1332,6 +1351,10 @@ mobile/views/pages/settings.vue:
github-connect: "GitHubアカウントに接続する"
github-reconnect: "再接続する"
github-disconnect: "切断する"
discord: "Discord連携"
discord-connect: "Discordアカウントに接続する"
discord-reconnect: "再接続する"
discord-disconnect: "切断する"
update: "Misskey Update"
version: "バージョン:"
latest-version: "最新のバージョン:"

View File

@ -5,143 +5,143 @@ meta:
common:
misskey: "A ⭐ of fediverse"
about-title: "A ⭐ of fediverse."
about: "Misskeyを見つけていただき、ありがとうございます。Misskeyは、地球で生まれた<b>分散マイクロブログSNS</b>です。Fediverse(様々なSNSで構成される宇宙)の中に存在するため、他のSNSと相互に繋がっています。暫し都会の喧騒から離れて、新しいインターネットにダイブしてみませんか。"
about: "Misskey 是一个开源的程序 <b>decentralized microblogging service</b>. 我懒得翻译了... Sophisticated fully customizable Ui, varieties of reaction for posts, free file storage providing integrated management system and other advancing functions are available. Also, network system called “Fediverse” enables us to communicate with users on other Snss. Like, if you post something, then your posts will sent not only to Misskey but also mastodon. Just imagine that the planet is sending a microwave to other planet to communication."
intro:
title: "Misskeyって?"
title: "什么是 Misskey 呢?"
about: "Misskeyはオープンソースの<b>分散型マイクロブログSNS</b>です。リッチで高度にカスタマイズできるUI、投稿へのリアクション、ファイルを一元管理できるドライブなど、先進的な機能を揃えています。また、Fediverseと呼ばれるネットワークに接続できるため、他のSNSともやり取りできます。例えば、あなたが何か投稿すると、その投稿はMisskeyだけでなく他のSNSにも伝わります。ちょうどある惑星から他の惑星に電波を発信している様子をイメージしてください。"
features: "特"
rich-contents: "投稿"
rich-contents-desc: "自分の考え、話題の出来事、皆と共有したいことについて発信してください。必要であれば、様々な構文を使って投稿を装飾したり、好きな画像、動画などのファイルやアンケートを添付することもできます。"
reaction: "リアクション"
reaction-desc: "あなたの気持ちを伝える最も簡単な方法です。Misskeyは、他のユーザーの投稿に様々なリアクションを付けることができます。いちどMisskeyのリアクション機能を体験してしまうと、もう「いいね」の概念しか存在しないSNSには戻れなくなるかもしれません。"
ui: "インターフェース"
ui-desc: "どのようなUIが使いやすいかは人それぞれです。だから、Misskeyは自由度の高いUIを持っています。レイアウトやデザインを調整したり、カスタマイズ可能な様々なウィジェットを配置したりして、自分だけのホームを作ってください。"
drive: "ドライブ"
drive-desc: "以前投稿したことのある画像をまた投稿したくなったことはありませんかもしくは、アップロードしたファイルをフォルダ分けして整理したくなったことはありませんかMisskeyの根幹に組み込まれたドライブ機能によってそれらが解決します。ファイルの共有も簡単です。"
outro: "他にもMisskeyにしかない機能はまだまだあるので、ぜひあなた自身の目で確かめてください。Misskeyは分散型SNSなので、このインスタンスが気に入らなければ他のインスタンスを試すこともできます。それでは、GLHF!"
features: "特"
rich-contents: "发布"
rich-contents-desc: "您只需要发布您的想法, 热门话题或者任何您想分享的好东西. 你可以装饰你的文字, 加上你最喜欢的图片, 发送文件或者电影, 甚至创造一个投票. 这些事情您都可以在 Misskey 上做。"
reaction: "情绪"
reaction-desc: "一个最简单的方式去告诉别人你的情绪. Misskey 允许您在别人的帖子中加入各种的情绪反应类型, 就像 Facebook 一样. 在 Misskey 上的情感体验永远不会出现在其他只能点赞的SNSs上。"
ui: "交互界面"
ui-desc: "世界上没有一个UI可以适合每一个人. 所以, Misskey 提供一个可以高度定制的UI交互界面. 您可以通过编辑, 调整布局, 放置可选择的小部件来轻松定制您的专属UI界面。"
drive: "Misskey 云盘"
drive-desc: "想要发布一张您已经上传过的照片吗? 想要组织,命名和为上传的文件创建文件夹吗? Misskey 云盘是一个最好的解决方案. "
outro: "进一步深挖 Misskey 的更多功能, 如果您感觉这个功能不适合我, 试试其他例子. 因为 Misskey 是一个分散的 SNS, 这样您就可以很容易找到适合自己的一部分."
adblock:
detected: "広告ブロッカーを無効にしてください"
warning: "<strong>Misskeyは広告を掲載していません</strong>が、広告をブロックする機能が有効だと一部の機能が利用できなかったり、不具合が発生する場合があります。"
application-authorization: "アプリの連携"
close: "閉じる"
do-not-copy-paste: "ここにコードを入力したり張り付けたりしないでください。アカウントが不正利用される可能性があります。"
load-more: "もっと読み込む"
got-it: "わかった"
detected: "请关闭广告拦截器"
warning: "<strong>Misskey 不是广告网站</strong>如果您启用广告拦截器, 可能会导致某些功能无法正常使用。"
application-authorization: "应用程序授权"
close: "关闭"
do-not-copy-paste: "请不要在这里输入或粘贴代码。您帐户可能会受到损害。"
load-more: "加载更多"
got-it: "没问题"
customization-tips:
title: "カスタマイズのヒント"
paragraph: "<p>ホームのカスタマイズでは、ウィジェットを追加/削除したり、ドラッグ&ドロップして並べ替えたりすることができます。</p><p>一部のウィジェットは、<strong><strong>右</strong>クリック</strong>することで表示を変更することができます。</p><p>ウィジェットを削除するには、ヘッダーの<strong>「ゴミ箱」</strong>と書かれたエリアにウィジェットをドラッグ&ドロップします。</p><p>カスタマイズを終了するには、右上の「完了」をクリックします。</p>"
gotit: "Got it!"
title: "客制化提示"
paragraph: "<p>主页定制允许您添加或删除, 拖放和重新排列小组件.</p></p>您可以通过<strong><strong>右</strong>点击</strong>某些小部件来更改显示</p><p>若要删除小部件, 请将其拖到标头为<strong>「垃圾箱」</strong>的区域</p><p>如果您完成了定制过程,单击右上角的「完成」</p>"
gotit: "没问题!"
notification:
file-uploaded: "ファイルがアップロードされました"
message-from: "{}さんからメッセージ:"
reversi-invited: "対局への招待があります"
reversi-invited-by: "{}さんから"
notified-by: "{}さんから"
reply-from: "{}さんから返信:"
quoted-by: "{}さんが引用:"
file-uploaded: "文件已上传"
message-from: "信息来源 {}:"
reversi-invited: "您已被邀请加入一场游戏"
reversi-invited-by: "被邀请 {}:"
notified-by: "通知 {}:"
reply-from: "回复 {}:"
quoted-by: "引用 {}:"
time:
unknown: "なぞのじかん"
unknown: "这是个啥??? 不知道哎"
future: "未来"
just_now: "たった今"
just_now: "现在"
seconds_ago: "{}秒前"
minutes_ago: "{}分前"
hours_ago: "{}時間前"
days_ago: "{}前"
weeks_ago: "{}週間前"
months_ago: "{}月前"
hours_ago: "{}小时前"
days_ago: "{}前"
weeks_ago: "{}前"
months_ago: "{}月前"
years_ago: "{}年前"
month-and-day: "{month}月 {day}日"
trash: "ゴミ箱"
drive: "ドライブ"
messaging: "トーク"
trash: "垃圾箱"
drive: "Misskey 云盘"
messaging: "聊天"
weekday-short:
sunday: "日"
monday: ""
tuesday: ""
wednesday: ""
thursday: ""
friday: ""
saturday: ""
monday: ""
tuesday: ""
wednesday: ""
thursday: ""
friday: ""
saturday: ""
weekday:
sunday: "日曜日"
monday: "月曜日"
tuesday: "火曜日"
wednesday: "水曜日"
thursday: "木曜日"
friday: "金曜日"
saturday: "土曜日"
sunday: "星期日"
monday: "星期一"
tuesday: "星期二 "
wednesday: "星期三"
thursday: "星期四"
friday: "星期五"
saturday: "星期六"
reactions:
like: "いいね"
love: "しゅき"
like: ""
love: "喜爱"
laugh: "笑"
hmm: "ふぅ~む"
surprise: "わお"
congrats: "おめでとう"
angry: "おこ"
confused: "こまこまのこまり"
hmm: "emmm...?"
surprise: "哇! "
congrats: "恭喜"
angry: "生气"
confused: "困惑"
rip: "RIP"
pudding: "Pudding"
pudding: "布丁"
note-visibility:
public: "公"
home: "ホーム"
home-desc: "ホームタイムラインにのみ公開"
followers: "フォロワー"
followers-desc: "自分のフォロワーにのみ公開"
specified: "ダイレクト"
specified-desc: "指定したユーザーにのみ公開"
private: "非公開"
public: "公"
home: "首页"
home-desc: "仅发送至首页的时间线"
followers: "关注者"
followers-desc: "仅发送至粉丝"
specified: "指定用户"
specified-desc: "仅发送至指定用户"
private: "私密"
note-placeholders:
a: "今どうしてる"
b: "何かありましたか"
c: "何をお考えですか"
d: "言いたいことは"
e: "ここに書いてください"
f: "あなたが書くのを待っています..."
search: "索"
delete: "除"
loading: "読み込み中"
ok: "わかった"
update-available-title: "更新があります"
update-available: "Misskeyの新しいバージョンがあります({newer}。現在{current}を利用中)。ページを再度読み込みすると更新が適用されます。"
my-token-regenerated: "あなたのトークンが更新されたのでサインアウトします。"
i-like-sushi: "私は(プリンよりむしろ)寿司が好き"
show-reversi-board-labels: "リバーシのボードの行と列のラベルを表示"
use-contrast-reversi-stones: "リバーシのアイコンにコントラストを付ける"
verified-user: "公式アカウント"
disable-animated-mfm: "投稿内の動きのあるテキストを無効にする"
always-show-nsfw: "常に閲覧注意のメディアを表示する"
always-mark-nsfw: "常にメディアを閲覧注意として投稿"
show-full-acct: "ユーザー名のホストを省略しない"
show-via: "viaを表示する"
reduce-motion: "UIの動きを減らす"
this-setting-is-this-device-only: "このデバイスのみ"
use-os-default-emojis: "OS標準の絵文字を使用"
do-not-use-in-production: 'これは開発ビルドです。本番環境で使用しないでください。'
is-remote-user: "このユーザー情報はコピーです。"
is-remote-post: "この投稿情報はコピーです。"
view-on-remote: "正確な情報を見る"
a: "你在干什么?"
b: "发生了什么"
c: "你有什么想法"
d: "你想要发布些什么吗"
e: "写下来吧"
f: "等待你的书写..."
search: "索"
delete: "除"
loading: "正在加载, 等着就好啦"
ok: "没问题"
update-available-title: "有可用更新"
update-available: "新的 Misskey 版本现已发布({newer}。目前版本{current}). 刷新页面以应用更新。"
my-token-regenerated: "您的 Token 已被重置, 您将自动登出。"
i-like-sushi: "相比于布丁来说, 我更喜欢寿司。"
show-reversi-board-labels: "在 Reversi 中显示行和列表签"
use-contrast-reversi-stones: "Make the stone color clear in Reversi"
verified-user: "认证用户"
disable-animated-mfm: "在帖子中禁用动画文本"
always-show-nsfw: "总是显示 NSFW 的内容"
always-mark-nsfw: "总是用 NSFW 来标记附件"
show-full-acct: "不要从用户名中忽略主机名"
show-via: "显示..."
reduce-motion: "减弱UI中的动画效果"
this-setting-is-this-device-only: "设置仅在本设备中生效"
use-os-default-emojis: "使用设备系统默认的 emojis"
do-not-use-in-production: '这是一个开发者测试版. 请勿在生产环境中使用.'
is-remote-user: "该用户的信息已被复制."
is-remote-post: "该投稿已被复制."
view-on-remote: "查看准确的信息"
error:
title: '問題が発生しました'
retry: 'やり直す'
title: '哦不, 发生了一些问题! :('
retry: '重试'
reversi:
drawn: "引き分け"
my-turn: "あなたのターンです"
opponent-turn: "相手のターンです"
turn-of: "{name}のターンです"
past-turn-of: "{name}のターン"
won: "{name}の勝ち"
black: ""
drawn: "平局"
my-turn: "轮到你了"
opponent-turn: "轮到对手了"
turn-of: "{name}转折点"
past-turn-of: "轮到{name}的回合了"
won: "{name}获胜"
black: ""
white: "白"
total: "合"
this-turn: "{count}ターン目"
total: "合"
this-turn: "Turn {count}"
widgets:
analog-clock: "アナログ時計"
profile: "プロフィール"
calendar: "カレンダー"
timemachine: "カレンダー(タイムマシン)"
activity: "アクティビティ"
rss: "RSSリーダー"
memo: "付箋"
analog-clock: "指针时钟"
profile: "简介"
calendar: "日历"
timemachine: "时光机"
activity: "动态"
rss: "RSS 订阅"
memo: "便签"
trends: "トレンド"
photo-stream: "フォトストリーム"
posts-monitor: "投稿チャート"
@ -195,60 +195,60 @@ common/views/components/games/reversi/reversi.game.vue:
can-put-everywhere: "どこでも置けるモード"
common/views/components/games/reversi/reversi.index.vue:
title: "Misskey Reversi"
sub-title: "他のMisskeyユーザーとリバーシで対戦しよう"
invite: "招待"
rule: "遊び方"
rule-desc: "リバーシは、相手と交互に石をボードに置いて、相手の石を挟んで自分の色に変えてゆき、最終的に残った石が多い方が勝ちというボードゲームです。"
mode-invite: "招待"
mode-invite-desc: "指定したユーザーと対戦するモードです。"
invitations: "対局の招待があります!"
my-games: "自分の対局"
all-games: "みんなの対局"
enter-username: "ユーザー名を入力してください"
sub-title: "和你的朋友一起玩 Reversi!"
invite: "邀请"
rule: "游戏说明"
rule-desc: "Reversi是与对方交替地把石头放在板上把对方的石头夹在自己的颜色上最终留下的石头多的人获胜。"
mode-invite: "邀请"
mode-invite-desc: "邀请指定用户参加游戏"
invitations: "您收到了一则邀请!"
my-games: "我的游戏"
all-games: "所有游戏"
enter-username: "输入用户名"
game-state:
ended: "終了"
playing: "行中"
ended: "完成"
playing: "行中"
common/views/components/games/reversi/reversi.room.vue:
settings-of-the-game: "ゲームの設定"
choose-map: "マップを選択"
random: "ランダム"
black-or-white: "先手/後手"
black-is: "{}が黒"
rules: "ルール"
is-llotheo: "石の少ない方が勝ち(ロセオ)"
looped-map: "ループマップ"
can-put-everywhere: "どこでも置けるモード"
settings-of-the-bot: "Botの設定"
this-game-is-started-soon: "ゲームは数秒後に開始されます"
waiting-for-other: "相手の準備が完了するのを待っています"
waiting-for-me: "あなたの準備が完了するのを待っています"
waiting-for-both: "準備中"
cancel: "キャンセル"
ready: "準備完了"
cancel-ready: "準備続行"
settings-of-the-game: "游戏设置"
choose-map: "选择一个地图"
random: "随机"
black-or-white: "黑/白"
black-is: "{}是黑"
rules: "规则"
is-llotheo: "较少一方获胜"
looped-map: "环状地图"
can-put-everywhere: "可以随意放置"
settings-of-the-bot: "机器人设定"
this-game-is-started-soon: "游戏即将在数秒后开始"
waiting-for-other: "等待对手准备"
waiting-for-me: "等待您的准备"
waiting-for-both: "准备中"
cancel: "取消"
ready: "准备好啦"
cancel-ready: "取消准备"
common/views/components/connect-failed.vue:
title: "サーバーに接続できません"
description: "インターネット回線に問題があるか、サーバーがダウンまたはメンテナンスしている可能性があります。しばらくしてから{再度お試し}ください。"
thanks: "いつもMisskeyをご利用いただきありがとうございます。"
troubleshoot: "トラブルシュート"
title: "无法连接至服务器"
description: "您的网络连接可能出现了问题, 或是远程服务器暂时不可用. 请稍后{重试}."
thanks: "感谢您使用 Misskey"
troubleshoot: "故障排除"
common/views/components/connect-failed.troubleshooter.vue:
title: "トラブルシューティング"
network: "ネットワーク接続"
checking-network: "ネットワーク接続を確認中"
internet: "インターネット接続"
checking-internet: "インターネット接続を確認中"
server: "サーバー接続"
checking-server: "サーバー接続を確認中"
finding: "問題を調べています"
no-network: "ネットワークに接続されていません"
no-network-desc: "お使いのPCのネットワーク接続が正常か確認してください。"
no-internet: "インターネットに接続されていません"
no-internet-desc: "ネットワークには接続されていますが、インターネットには接続されていないようです。お使いのPCのインターネット接続が正常か確認してください。"
no-server: "Misskeyのサーバーに接続できません"
no-server-desc: "お使いのPCのインターネット接続は正常ですが、Misskeyのサーバーには接続できませんでした。サーバーがダウンまたはメンテナンスしている可能性があるので、しばらくしてから再度御アクセスください。"
success: "Misskeyのサーバーに接続できました"
success-desc: "正常に接続できるようです。ページを再度読み込みしてください。"
flush: "キャッシュの削除"
title: "正在排除故障"
network: "网络已连接"
checking-network: "正在检查网络连接"
internet: "网络连接"
checking-internet: "正在检查网络连接"
server: "已连接至服务器"
checking-server: "正在检查与服务器的连接"
finding: "搜索问题"
no-network: "无网络连接"
no-network-desc: "请确保您已连接至互联网"
no-internet: "无网络连接"
no-internet-desc: "请确保您已连接至互联网"
no-server: "无法连接到 Misskey 服务器"
no-server-desc: "您设备与互联网的网络连接正常, 但是无法连接至 Misskey 服务器. 这可能是服务器暂时不可用或正在维护. 请稍后再试."
success: "成功连接至 Misskey 服务器"
success-desc: "看起来我们连接正常. 请刷新网页."
flush: "清除缓存"
set-version: "バージョン指定"
common/views/components/media-banner.vue:
sensitive: "閲覧注意"
@ -305,36 +305,36 @@ common/views/components/messaging-room.form.vue:
input-message-here: "ここにメッセージを入力"
send: "送信"
attach-from-local: "PCからファイルを添付する"
attach-from-drive: "ドライブからファイルを添付する"
only-one-file-attached: "メッセージに添付できるのはひとつのファイルのみです"
attach-from-drive: "从云盘中添加文件"
only-one-file-attached: "在信息中只允许添加一个附件"
common/views/components/messaging-room.message.vue:
is-read: "既読"
deleted: "このメッセージは削除されました"
is-read: "已阅"
deleted: "这条信息已被删除"
common/views/components/nav.vue:
about: "Misskeyについて"
stats: "統計"
status: "ステータス"
wiki: "Wiki"
donors: "ドナー"
repository: "リポジトリ"
develop: "開発者"
feedback: "フィードバック"
about: "关于"
stats: "统计"
status: "状态"
wiki: "百科 (Wiki)"
donors: "捐赠者"
repository: ""
develop: "开发者"
feedback: "反馈"
common/views/components/note-menu.vue:
detail: "詳細"
copy-link: "リンクをコピー"
favorite: "お気に入り"
unfavorite: "お気に入り解除"
pin: "ピン留め"
unpin: "ピン留め解除"
delete: "除"
delete-confirm: "この投稿を削除しますか?"
remote: "投稿元で見る"
detail: "详细信息"
copy-link: "复制链接"
favorite: "收藏这个投稿"
unfavorite: "取消收藏"
pin: "固定个人资料"
unpin: "解除固定"
delete: "除"
delete-confirm: "确定删除这个投稿吗?"
remote: "显示原始投稿"
common/views/components/poll.vue:
vote-to: "「{}」に投票する"
vote-to: "为\"{}\"投票"
vote-count: "{}票"
total-users: "{}人投票"
vote: "投票する"
show-result: "結果を見る"
total-users: "{} 人投票"
vote: "投票"
show-result: "显示结果"
voted: "投票済み"
common/views/components/poll-editor.vue:
no-only-one-choice: "アンケートには、選択肢が最低2つ必要です"
@ -363,6 +363,7 @@ common/views/components/signin.vue:
or: "または"
signin-with-twitter: "Twitterでログイン"
signin-with-github: "GitHubでログイン"
signin-with-discord: "Discordでログイン"
login-failed: "ログインできませんでした。ユーザー名とパスワードを確認してください。"
common/views/components/signup.vue:
invitation-code: "招待コード"
@ -408,6 +409,13 @@ common/views/components/github-setting.vue:
reconnect: "再接続する"
connect: "GitHubと接続する"
disconnect: "切断する"
common/views/components/discord-setting.vue:
description: "お使いのDiscordアカウントをお使いのMisskeyアカウントに接続しておくと、プロフィールでDiscordアカウント情報が表示されるようになったり、Discordを用いた便利なサインインを利用できるようになります。"
connected-to: "次のDiscordアカウントに接続されています"
detail: "詳細..."
reconnect: "再接続する"
connect: "Discordと接続する"
disconnect: "切断する"
common/views/components/uploader.vue:
waiting: "待機中"
common/views/components/visibility-chooser.vue:
@ -911,6 +919,7 @@ admin/views/index.vue:
dashboard: "ダッシュボード"
instance: "インスタンス"
emoji: "カスタム絵文字"
moderators: "モデレーター"
users: "ユーザー"
update: "更新"
announcements: "お知らせ"
@ -955,7 +964,12 @@ admin/views/instance.vue:
github-integration-info: "コールバックURLは /api/gh/cb に設定します。"
enable-github-integration: "GitHub連携を有効にする"
github-integration-client-id: "Client ID"
github-integration-client-secret: "Client secret"
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"
proxy-account-config: "プロキシアカウントの設定"
proxy-account-info: "プロキシアカウントは、特定の条件下でユーザーのリモートフォローを代行するアカウントです。例えば、ユーザーがリモートユーザーをリストに入れたとき、リストに入れられたユーザーを誰もフォローしていないとアクティビティがサーバーに配達されないため、代わりにプロキシアカウントがフォローするようにします。"
proxy-account-username: "プロキシアカウントのユーザー名"
@ -1005,6 +1019,11 @@ admin/views/users.vue:
unverify-user: "ユーザーの公式アカウント解除"
unverify: "公式アカウントを解除する"
unverified: "公式アカウントを解除しました"
admin/views/moderators.vue:
add-moderator:
title: "モデレーターの登録"
add: "登録"
added: "モデレーターを登録しました"
admin/views/emoji.vue:
add-emoji:
title: "絵文字の登録"
@ -1332,6 +1351,10 @@ mobile/views/pages/settings.vue:
github-connect: "GitHubアカウントに接続する"
github-reconnect: "再接続する"
github-disconnect: "切断する"
discord: "Discord連携"
discord-connect: "Discordアカウントに接続する"
discord-reconnect: "再接続する"
discord-disconnect: "切断する"
update: "Misskey Update"
version: "バージョン:"
latest-version: "最新のバージョン:"

View File

@ -1,8 +1,8 @@
{
"name": "misskey",
"author": "syuilo <i@syuilo.com>",
"version": "10.49.6",
"clientVersion": "2.0.11783",
"version": "10.54.0",
"clientVersion": "2.0.11894",
"codename": "nighthike",
"main": "./built/index.js",
"private": true,
@ -46,6 +46,7 @@
"@types/is-root": "1.0.0",
"@types/is-url": "1.2.28",
"@types/js-yaml": "3.11.2",
"@types/katex": "0.5.0",
"@types/koa": "2.0.46",
"@types/koa-bodyparser": "5.0.1",
"@types/koa-compress": "2.0.8",
@ -140,6 +141,7 @@
"jsdom": "13.0.0",
"json5": "2.1.0",
"json5-loader": "1.0.1",
"katex": "0.10.0",
"koa": "2.6.1",
"koa-bodyparser": "4.2.1",
"koa-compress": "3.0.0",
@ -158,7 +160,7 @@
"mocha": "5.2.0",
"moji": "0.5.1",
"moment": "2.22.2",
"mongodb": "3.1.8",
"mongodb": "3.1.9",
"monk": "6.0.6",
"ms": "2.1.1",
"nan": "2.11.1",
@ -176,6 +178,7 @@
"pug": "2.0.3",
"punycode": "2.1.1",
"qrcode": "1.3.2",
"randomcolor": "0.5.3",
"ratelimiter": "3.2.0",
"recaptcha-promise": "0.1.3",
"reconnecting-websocket": "4.1.10",
@ -188,7 +191,7 @@
"s-age": "1.1.2",
"seedrandom": "2.4.4",
"sharp": "0.21.0",
"showdown": "1.8.7",
"showdown": "1.9.0",
"showdown-highlightjs-extension": "0.1.2",
"speakeasy": "2.0.0",
"stringz": "1.0.0",
@ -206,7 +209,7 @@
"ts-node": "7.0.1",
"tslint": "5.10.0",
"typescript": "3.1.6",
"typescript-eslint-parser": "20.1.1",
"typescript-eslint-parser": "21.0.0",
"uglify-es": "3.3.9",
"url-loader": "1.1.2",
"uuid": "3.3.2",
@ -218,6 +221,7 @@
"vue-i18n": "8.3.1",
"vue-js-modal": "1.3.26",
"vue-loader": "15.4.2",
"vue-marquee-text-component": "1.1.0",
"vue-router": "3.0.1",
"vue-style-loader": "4.1.2",
"vue-svg-inline-loader": "1.2.1",

View File

@ -41,7 +41,7 @@ export default Vue.extend({
methods: {
add() {
this.announcements.push({
this.announcements.unshift({
title: '',
text: ''
});

View File

@ -8,13 +8,19 @@
<p>{{ $t('@.ai-chan-kawaii') }}</p>
</header>
<marquee-text v-if="instances.length > 0" class="instances" :repeat="10" :duration="60">
<span v-for="instance in instances" class="instance">
<b :style="{ background: instance.bg }">{{ instance.host }}</b>{{ instance.notesCount | number }} / {{ instance.usersCount | number }}
</span>
</marquee-text>
<div v-if="stats" class="stats">
<div>
<div>
<div><fa icon="user"/></div>
<div>
<span>{{ $t('accounts') }}</span>
<b class="primary">{{ stats.originalUsersCount | number }}</b>
<b>{{ stats.originalUsersCount | number }}</b>
</div>
</div>
<div>
@ -27,7 +33,7 @@
<div><fa icon="pencil-alt"/></div>
<div>
<span>{{ $t('notes') }}</span>
<b class="primary">{{ stats.originalNotesCount | number }}</b>
<b>{{ stats.originalNotesCount | number }}</b>
</div>
</div>
<div>
@ -84,6 +90,8 @@ import XCpuMemory from "./cpu-memory.vue";
import XCharts from "./charts.vue";
import XApLog from "./ap-log.vue";
import { faDatabase } from '@fortawesome/free-solid-svg-icons';
import MarqueeText from 'vue-marquee-text-component';
import randomColor from 'randomcolor';
export default Vue.extend({
i18n: i18n('admin/views/dashboard.vue'),
@ -91,7 +99,8 @@ export default Vue.extend({
components: {
XCpuMemory,
XCharts,
XApLog
XApLog,
MarqueeText
},
data() {
@ -99,6 +108,8 @@ export default Vue.extend({
stats: null,
connection: null,
meta: null,
instances: [],
clock: null,
faDatabase
};
},
@ -106,22 +117,40 @@ export default Vue.extend({
created() {
this.connection = this.$root.stream.useSharedConnection('serverStats');
this.updateStats();
this.clock = setInterval(this.updateStats, 1000);
this.$root.getMeta().then(meta => {
this.meta = meta;
});
this.$root.api('stats').then(stats => {
this.stats = stats;
this.$root.api('instances', {
sort: '+notes'
}).then(instances => {
instances.forEach(i => {
i.bg = randomColor({
seed: i.host,
luminosity: 'dark'
});
});
this.instances = instances;
});
},
beforeDestroy() {
this.connection.dispose();
clearInterval(this.clock);
},
methods: {
setChartSrc(src) {
this.$refs.charts.setSrc(src);
},
updateStats() {
this.$root.api('stats', {}, false, true).then(stats => {
this.stats = stats;
});
}
}
});
@ -136,7 +165,6 @@ export default Vue.extend({
> header
display flex
margin-bottom 16px
padding-bottom 16px
border-bottom solid 1px var(--adminDashboardHeaderBorder)
color var(--adminDashboardHeaderFg)
@ -161,6 +189,20 @@ export default Vue.extend({
margin-left auto
margin-right 0
> .instances
padding 16px
color var(--adminDashboardHeaderFg)
font-size 13px
>>> .instance
margin 0 10px
> b
padding 2px 6px
margin-right 4px
border-radius 4px
color #fff
> .stats
display flex
justify-content space-between
@ -201,9 +243,6 @@ export default Vue.extend({
> b
display block
&.primary
color var(--primary)
> div:last-child
display flex
padding 6px 16px

View File

@ -20,13 +20,14 @@
<ul>
<li @click="nav('dashboard')" :class="{ active: page == 'dashboard' }"><fa icon="home" fixed-width/>{{ $t('dashboard') }}</li>
<li @click="nav('instance')" :class="{ active: page == 'instance' }"><fa icon="cog" fixed-width/>{{ $t('instance') }}</li>
<li @click="nav('moderators')" :class="{ active: page == 'moderators' }"><fa :icon="faHeadset" fixed-width/>{{ $t('moderators') }}</li>
<li @click="nav('users')" :class="{ active: page == 'users' }"><fa icon="users" fixed-width/>{{ $t('users') }}</li>
<!-- <li @click="nav('federation')" :class="{ active: page == 'federation' }"><fa :icon="faShareAlt" fixed-width/>{{ $t('federation') }}</li> -->
<li @click="nav('emoji')" :class="{ active: page == 'emoji' }"><fa :icon="faGrin" fixed-width/>{{ $t('emoji') }}</li>
<li @click="nav('announcements')" :class="{ active: page == 'announcements' }"><fa icon="broadcast-tower" fixed-width/>{{ $t('announcements') }}</li>
<li @click="nav('hashtags')" :class="{ active: page == 'hashtags' }"><fa icon="hashtag" fixed-width/>{{ $t('hashtags') }}</li>
<!-- <li @click="nav('drive')" :class="{ active: page == 'drive' }"><fa icon="cloud" fixed-width/>{{ $t('@.drive') }}</li> -->
<!-- <li @click="nav('update')" :class="{ active: page == 'update' }">{{ $t('update') }}</li> -->
</ul>
<div class="back-to-misskey">
<a href="/"><fa :icon="faArrowLeft"/> {{ $t('back-to-misskey') }}</a>
@ -36,14 +37,17 @@
</div>
</nav>
<main>
<div v-if="page == 'dashboard'"><x-dashboard/></div>
<div v-if="page == 'instance'"><x-instance/></div>
<div v-if="page == 'users'"><x-users/></div>
<div v-if="page == 'emoji'"><x-emoji/></div>
<div v-if="page == 'announcements'"><x-announcements/></div>
<div v-if="page == 'hashtags'"><x-hashtags/></div>
<div v-if="page == 'drive'"></div>
<div v-if="page == 'update'"></div>
<div class="page">
<div v-if="page == 'dashboard'"><x-dashboard/></div>
<div v-if="page == 'instance'"><x-instance/></div>
<div v-if="page == 'moderators'"><x-moderators/></div>
<div v-if="page == 'users'"><x-users/></div>
<div v-if="page == 'emoji'"><x-emoji/></div>
<div v-if="page == 'announcements'"><x-announcements/></div>
<div v-if="page == 'hashtags'"><x-hashtags/></div>
<div v-if="page == 'drive'"></div>
<div v-if="page == 'update'"></div>
</div>
</main>
</div>
</template>
@ -54,11 +58,12 @@ import i18n from '../../i18n';
import { version } from '../../config';
import XDashboard from "./dashboard.vue";
import XInstance from "./instance.vue";
import XModerators from "./moderators.vue";
import XEmoji from "./emoji.vue";
import XAnnouncements from "./announcements.vue";
import XHashtags from "./hashtags.vue";
import XUsers from "./users.vue";
import { faArrowLeft } from '@fortawesome/free-solid-svg-icons';
import { faHeadset, faArrowLeft, faShareAlt } from '@fortawesome/free-solid-svg-icons';
import { faGrin } from '@fortawesome/free-regular-svg-icons';
// Detect the user agent
@ -70,6 +75,7 @@ export default Vue.extend({
components: {
XDashboard,
XInstance,
XModerators,
XEmoji,
XAnnouncements,
XHashtags,
@ -85,7 +91,9 @@ export default Vue.extend({
isMobile,
navOpend: !isMobile,
faGrin,
faArrowLeft
faArrowLeft,
faHeadset,
faShareAlt
};
},
methods: {
@ -96,7 +104,7 @@ export default Vue.extend({
});
</script>
<style lang="stylus">
<style lang="stylus" scoped>
.mk-admin
$headerHeight = 48px
@ -257,7 +265,9 @@ export default Vue.extend({
> main
width 100%
padding 0 0 0 250px
max-width 1300px
> .page
max-width 1150px
&.isMobile
> main

View File

@ -76,6 +76,17 @@
<ui-button @click="updateMeta">{{ $t('save') }}</ui-button>
</section>
</ui-card>
<ui-card>
<div slot="title"><fa :icon="['fab', 'discord']"/> {{ $t('discord-integration-config') }}</div>
<section>
<ui-switch v-model="enableDiscordIntegration">{{ $t('enable-discord-integration') }}</ui-switch>
<ui-info>{{ $t('discord-integration-info') }}</ui-info>
<ui-input v-model="discordClientId" :disabled="!enableDiscordIntegration"><i slot="icon"><fa icon="key"/></i>{{ $t('discord-integration-client-id') }}</ui-input>
<ui-input v-model="discordClientSecret" :disabled="!enableDiscordIntegration"><i slot="icon"><fa icon="key"/></i>{{ $t('discord-integration-client-secret') }}</ui-input>
<ui-button @click="updateMeta">{{ $t('save') }}</ui-button>
</section>
</ui-card>
</div>
</template>
@ -113,6 +124,9 @@ export default Vue.extend({
enableGithubIntegration: false,
githubClientId: null,
githubClientSecret: null,
enableDiscordIntegration: false,
discordClientId: null,
discordClientSecret: null,
proxyAccount: null,
inviteCode: null,
faHeadset, faShieldAlt, faGhost
@ -141,6 +155,9 @@ export default Vue.extend({
this.enableGithubIntegration = meta.enableGithubIntegration;
this.githubClientId = meta.githubClientId;
this.githubClientSecret = meta.githubClientSecret;
this.enableDiscordIntegration = meta.enableDiscordIntegration;
this.discordClientId = meta.discordClientId;
this.discordClientSecret = meta.discordClientSecret;
});
},
@ -180,6 +197,9 @@ export default Vue.extend({
enableGithubIntegration: this.enableGithubIntegration,
githubClientId: this.githubClientId,
githubClientSecret: this.githubClientSecret,
enableDiscordIntegration: this.enableDiscordIntegration,
discordClientId: this.discordClientId,
discordClientSecret: this.discordClientSecret
}).then(() => {
this.$root.alert({
type: 'success',

View File

@ -0,0 +1,61 @@
<template>
<div class="jnhmugbb">
<ui-card>
<div slot="title"><fa icon="plus"/> {{ $t('add-moderator.title') }}</div>
<section class="fit-top">
<ui-input v-model="username" type="text">
<span slot="prefix">@</span>
</ui-input>
<ui-button @click="add" :disabled="adding">{{ $t('add-moderator.add') }}</ui-button>
</section>
</ui-card>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import i18n from '../../i18n';
import parseAcct from "../../../../misc/acct/parse";
export default Vue.extend({
i18n: i18n('admin/views/moderators.vue'),
data() {
return {
username: '',
adding: false
};
},
methods: {
async add() {
this.adding = true;
const process = async () => {
const user = await this.$root.api('users/show', parseAcct(this.username));
await this.$root.api('admin/moderators/add', { userId: user.id });
this.$root.alert({
type: 'success',
text: this.$t('add-moderator.added')
});
};
await process().catch(e => {
this.$root.alert({
type: 'error',
text: e.toString()
});
});
this.adding = false;
},
}
});
</script>
<style lang="stylus" scoped>
.jnhmugbb
@media (min-width 500px)
padding 16px
</style>

View File

@ -49,6 +49,7 @@ import parseAcct from "../../../../misc/acct/parse";
export default Vue.extend({
i18n: i18n('admin/views/users.vue'),
data() {
return {
verifyUsername: null,
@ -67,13 +68,19 @@ export default Vue.extend({
this.verifying = true;
const process = async () => {
const user = await this.$root.os.api('users/show', parseAcct(this.verifyUsername));
await this.$root.os.api('admin/verify-user', { userId: user.id });
//this.$root.os.apis.dialog({ text: this.$t('verified') });
const user = await this.$root.api('users/show', parseAcct(this.verifyUsername));
await this.$root.api('admin/verify-user', { userId: user.id });
this.$root.alert({
type: 'success',
text: this.$t('verified')
});
};
await process().catch(e => {
//this.$root.os.apis.dialog({ text: `Failed: ${e}` });
this.$root.alert({
type: 'error',
text: e.toString()
});
});
this.verifying = false;
@ -83,13 +90,19 @@ export default Vue.extend({
this.unverifying = true;
const process = async () => {
const user = await this.$root.os.api('users/show', parseAcct(this.unverifyUsername));
await this.$root.os.api('admin/unverify-user', { userId: user.id });
//this.$root.os.apis.dialog({ text: this.$t('unverified') });
const user = await this.$root.api('users/show', parseAcct(this.unverifyUsername));
await this.$root.api('admin/unverify-user', { userId: user.id });
this.$root.alert({
type: 'success',
text: this.$t('unverified')
});
};
await process().catch(e => {
//this.$root.os.apis.dialog({ text: `Failed: ${e}` });
this.$root.alert({
type: 'error',
text: e.toString()
});
});
this.unverifying = false;
@ -99,13 +112,19 @@ export default Vue.extend({
this.suspending = true;
const process = async () => {
const user = await this.$root.os.api('users/show', parseAcct(this.suspendUsername));
await this.$root.os.api('admin/suspend-user', { userId: user.id });
//this.$root.os.apis.dialog({ text: this.$t('suspended') });
const user = await this.$root.api('users/show', parseAcct(this.suspendUsername));
await this.$root.api('admin/suspend-user', { userId: user.id });
this.$root.alert({
type: 'success',
text: this.$t('suspended')
});
};
await process().catch(e => {
//this.$root.os.apis.dialog({ text: `Failed: ${e}` });
this.$root.alert({
type: 'error',
text: e.toString()
});
});
this.suspending = false;
@ -115,13 +134,19 @@ export default Vue.extend({
this.unsuspending = true;
const process = async () => {
const user = await this.$root.os.api('users/show', parseAcct(this.unsuspendUsername));
await this.$root.os.api('admin/unsuspend-user', { userId: user.id });
//this.$root.os.apis.dialog({ text: this.$t('unsuspended') });
const user = await this.$root.api('users/show', parseAcct(this.unsuspendUsername));
await this.$root.api('admin/unsuspend-user', { userId: user.id });
this.$root.alert({
type: 'success',
text: this.$t('unsuspended')
});
};
await process().catch(e => {
//this.$root.os.apis.dialog({ text: `Failed: ${e}` });
this.$root.alert({
type: 'error',
text: e.toString()
});
});
this.unsuspending = false;

View File

@ -43,6 +43,9 @@
if (`${url.pathname}/`.startsWith('/admin/')) app = 'admin';
//#endregion
// Script version
const ver = localStorage.getItem('v') || VERSION;
//#region Detect the user language
let lang = null;
@ -66,11 +69,14 @@
//#endregion
let locale = localStorage.getItem('locale');
if (locale == null) {
const locale = await fetch(`/assets/locales/${lang}.json`)
const localeKey = localStorage.getItem('localeKey');
if (locale == null || localeKey != `${ver}.${lang}`) {
const locale = await fetch(`/assets/locales/${lang}.json?ver=${ver}`)
.then(response => response.json());
localStorage.setItem('locale', JSON.stringify(locale));
localStorage.setItem('localeKey', `${ver}.${lang}`);
}
// Detect the user agent
@ -98,9 +104,6 @@
app = isMobile ? 'mobile' : 'desktop';
}
// Script version
const ver = localStorage.getItem('v') || VERSION;
// Get salt query
const salt = localStorage.getItem('salt')
? `?salt=${localStorage.getItem('salt')}`

View File

@ -1,5 +1,5 @@
import parse from '../../../../mfm/parse';
import { sum } from '../../../../prelude/array';
import { sum, unique } from '../../../../prelude/array';
import shouldMuteNote from './should-mute-note';
import MkNoteMenu from '../views/components/note-menu.vue';
import MkReactionPicker from '../views/components/reaction-picker.vue';
@ -78,9 +78,9 @@ export default (opts: Opts = {}) => ({
urls(): string[] {
if (this.appearNote.text) {
const ast = parse(this.appearNote.text);
return ast
return unique(ast
.filter(t => (t.type == 'url' || t.type == 'link') && !t.silent)
.map(t => t.url);
.map(t => t.url));
} else {
return null;
}
@ -141,11 +141,10 @@ export default (opts: Opts = {}) => ({
this.$root.api('notes/favorites/create', {
noteId: this.appearNote.id
}).then(() => {
// TODO
/*this.$root.alert({
pointer: false,
autoClose: true
});*/
this.$root.alert({
type: 'success',
splash: true
});
});
},

View File

@ -1,11 +1,11 @@
<template>
<div class="felqjxyj" :class="{ pointer }">
<div class="felqjxyj" :class="{ splash }">
<div class="bg" ref="bg" @click="onBgClick"></div>
<div class="main" ref="main">
<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">
<ui-horizon-group no-grow class="buttons" 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>
@ -31,15 +31,15 @@ export default Vue.extend({
},
text: {
type: String,
required: true
required: false
},
showCancelButton: {
type: Boolean,
default: false
},
pointer: {
splash: {
type: Boolean,
default: true
default: false
}
},
@ -72,6 +72,12 @@ export default Vue.extend({
duration: 300,
easing: [0, 0.5, 0.5, 1]
});
if (this.splash) {
setTimeout(() => {
this.close();
}, 1000);
}
});
},
@ -125,8 +131,13 @@ export default Vue.extend({
width 100%
height 100%
&:not(.pointer)
pointer-events none
&.splash
&, *
pointer-events none !important
> .main
min-width 0
width initial
> .bg
display block

View File

@ -0,0 +1,64 @@
<template>
<div class="mk-discord-setting">
<p>{{ $t('description') }}</p>
<p class="account" v-if="$store.state.i.discord" :title="`Discord ID: ${$store.state.i.discord.id}`">{{ $t('connected-to') }}: <a :href="`https://discordapp.com/users/${$store.state.i.discord.id}`" target="_blank">@{{ $store.state.i.discord.username }}#{{ $store.state.i.discord.discriminator }}</a></p>
<p>
<a :href="`${apiUrl}/connect/discord`" target="_blank" @click.prevent="connect">{{ $store.state.i.discord ? this.$t('reconnect') : this.$t('connect') }}</a>
<span v-if="$store.state.i.discord"> or </span>
<a :href="`${apiUrl}/disconnect/discord`" target="_blank" v-if="$store.state.i.discord" @click.prevent="disconnect">{{ $t('disconnect') }}</a>
</p>
<p class="id" v-if="$store.state.i.discord">Discord ID: {{ $store.state.i.discord.id }}</p>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import i18n from '../../../i18n';
import { apiUrl } from '../../../config';
export default Vue.extend({
i18n: i18n('common/views/components/discord-setting.vue'),
data() {
return {
form: null,
apiUrl
};
},
mounted() {
this.$watch('$store.state.i', () => {
if (this.$store.state.i.discord && this.form)
this.form.close();
}, {
deep: true
});
},
methods: {
connect() {
this.form = window.open(apiUrl + '/connect/discord',
'discord_connect_window',
'height=570, width=520');
},
disconnect() {
window.open(apiUrl + '/disconnect/discord',
'discord_disconnect_window',
'height=570, width=520');
}
}
});
</script>
<style lang="stylus" scoped>
.mk-discord-setting
.account
border solid 1px #e1e8ed
border-radius 4px
padding 16px
a
font-weight bold
color inherit
.id
color #8899a6
</style>

View File

@ -0,0 +1,26 @@
<template>
<span v-html="compiledFormula"></span>
</template>
<script lang="ts">
import Vue from 'vue';
import * as katex from 'katex';
export default Vue.extend({
props: {
formula: {
type: String,
required: true
}
},
computed: {
compiledFormula(): any {
return katex.renderToString(this.formula);
}
}
});
</script>
<style>
@import "../../../../../../node_modules/katex/dist/katex.min.css";
</style>

View File

@ -0,0 +1,20 @@
<template>
<x-formula :formula="formula"/>
</template>
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
components: {
XFormula: () => import('./formula-core.vue').then(m => m.default)
},
props: {
formula: {
type: String,
required: true
}
}
});
</script>

View File

@ -27,8 +27,6 @@ import uploader from './uploader.vue';
import streamIndicator from './stream-indicator.vue';
import ellipsis from './ellipsis.vue';
import urlPreview from './url-preview.vue';
import twitterSetting from './twitter-setting.vue';
import githubSetting from './github-setting.vue';
import fileTypeIcon from './file-type-icon.vue';
import emoji from './emoji.vue';
import welcomeTimeline from './welcome-timeline.vue';
@ -72,8 +70,6 @@ Vue.component('mk-uploader', uploader);
Vue.component('mk-stream-indicator', streamIndicator);
Vue.component('mk-ellipsis', ellipsis);
Vue.component('mk-url-preview', urlPreview);
Vue.component('mk-twitter-setting', twitterSetting);
Vue.component('mk-github-setting', githubSetting);
Vue.component('mk-file-type-icon', fileTypeIcon);
Vue.component('mk-emoji', emoji);
Vue.component('mk-welcome-timeline', welcomeTimeline);

View File

@ -34,6 +34,7 @@
import Vue from 'vue';
import i18n from '../../../i18n';
import parse from '../../../../../mfm/parse';
import { unique } from '../../../../../prelude/array';
export default Vue.extend({
i18n: i18n('common/views/components/messaging-room.message.vue'),
@ -49,9 +50,9 @@ export default Vue.extend({
urls(): string[] {
if (this.message.text) {
const ast = parse(this.message.text);
return ast
return unique(ast
.filter(t => (t.type == 'url' || t.type == 'link') && !t.silent)
.map(t => t.url);
.map(t => t.url));
} else {
return null;
}

View File

@ -20,7 +20,7 @@
<footer>
<transition name="fade">
<div class="new-message" v-show="showIndicator">
<button @click="onIndicatorClick"><i><fa icon="arrow-circle-down"/></i>{{ $t('new-message') }}</button>
<button @click="onIndicatorClick"><i><fa :icon="faArrowCircleDown"/></i>{{ $t('new-message') }}</button>
</div>
</transition>
<x-form :user="user" ref="form"/>
@ -34,6 +34,7 @@ import i18n from '../../../i18n';
import XMessage from './messaging-room.message.vue';
import XForm from './messaging-room.form.vue';
import { url } from '../../../config';
import { faArrowCircleDown } from '@fortawesome/free-solid-svg-icons';
export default Vue.extend({
i18n: i18n('common/views/components/messaging-room.vue'),
@ -52,7 +53,8 @@ export default Vue.extend({
existMoreMessages: false,
connection: null,
showIndicator: false,
timer: null
timer: null,
faArrowCircleDown
};
},

View File

@ -3,8 +3,9 @@ import { length } from 'stringz';
import parse from '../../../../../mfm/parse';
import getAcct from '../../../../../misc/acct/render';
import MkUrl from './url.vue';
import MkGoogle from './google.vue';
import { concat } from '../../../../../prelude/array';
import MkFormula from './formula.vue';
import MkGoogle from './google.vue';
export default Vue.component('misskey-flavored-markdown', {
props: {
@ -199,7 +200,17 @@ export default Vue.component('misskey-flavored-markdown', {
})];
}
case 'math': {
//const MkFormula = () => import('./formula.vue').then(m => m.default);
return [createElement(MkFormula, {
props: {
formula: token.formula
}
})];
}
case 'search': {
//const MkGoogle = () => import('./google.vue').then(m => m.default);
return [createElement(MkGoogle, {
props: {
q: token.query

View File

@ -14,11 +14,12 @@
<mk-time :time="note.createdAt"/>
</router-link>
<span class="visibility" v-if="note.visibility != 'public'">
<template v-if="note.visibility == 'home'"><fa icon="home"/></template>
<template v-if="note.visibility == 'followers'"><fa icon="unlock"/></template>
<template v-if="note.visibility == 'specified'"><fa icon="envelope"/></template>
<template v-if="note.visibility == 'private'"><fa icon="lock"/></template>
<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>
</header>
</template>
@ -115,4 +116,7 @@ export default Vue.extend({
> .visibility
margin-left 8px
> .localOnly
margin-left 4px
</style>

View File

@ -55,7 +55,7 @@ export default Vue.extend({
}
] : []
], [
this.note.userId == this.$store.state.i.id || this.$store.state.i.isAdmin ? [{
this.note.userId == this.$store.state.i.id || this.$store.state.i.isAdmin || this.$store.state.i.isModerator ? [{
icon: ['far', 'trash-alt'],
text: this.$t('delete'),
action: this.del
@ -78,8 +78,10 @@ export default Vue.extend({
this.$root.api('i/pin', {
noteId: this.note.id
}).then(() => {
// TODO
//this.$root.new(Ok);
this.$root.alert({
type: 'success',
splash: true
});
this.destroyDom();
});
},
@ -112,8 +114,10 @@ export default Vue.extend({
this.$root.api('notes/favorites/create', {
noteId: this.note.id
}).then(() => {
// TODO
//this.$root.new(Ok);
this.$root.alert({
type: 'success',
splash: true
});
this.destroyDom();
});
},
@ -122,8 +126,10 @@ export default Vue.extend({
this.$root.api('notes/favorites/delete', {
noteId: this.note.id
}).then(() => {
// TODO
//this.$root.new(Ok);
this.$root.alert({
type: 'success',
splash: true
});
this.destroyDom();
});
},

View File

@ -223,6 +223,5 @@ export default Vue.extend({
width 72px
height 72px
margin auto
box-shadow 0 0 16px rgba(0, 0, 0, 0.5)
</style>

View File

@ -14,6 +14,7 @@
<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>
</form>
</template>

View File

@ -1,7 +1,7 @@
<template>
<div class="nicnklzforebnpfgasiypmpdaaglujqm">
<label>
<span>{{ $t('light-theme') }}</span>
<span><fa :icon="faSun"/> {{ $t('light-theme') }}</span>
<ui-select v-model="light" :placeholder="$t('light-theme')">
<optgroup :label="$t('light-themes')">
<option v-for="x in lightThemes" :value="x.id" :key="x.id">{{ x.name }}</option>
@ -13,7 +13,7 @@
</label>
<label>
<span>{{ $t('dark-theme') }}</span>
<span><fa :icon="faMoon"/> {{ $t('dark-theme') }}</span>
<ui-select v-model="dark" :placeholder="$t('dark-theme')">
<optgroup :label="$t('dark-themes')">
<option v-for="x in darkThemes" :value="x.id" :key="x.id">{{ x.name }}</option>
@ -104,6 +104,7 @@ import { Chrome } from 'vue-color';
import * as uuid from 'uuid';
import * as tinycolor from 'tinycolor2';
import * as JSON5 from 'json5';
import { faMoon, faSun } from '@fortawesome/free-regular-svg-icons';
// 後方互換性のため
function convertOldThemedefinition(t) {
@ -135,7 +136,8 @@ export default Vue.extend({
myThemeDesc: '',
myThemePrimary: lightTheme.vars.primary,
myThemeSecondary: lightTheme.vars.secondary,
myThemeText: lightTheme.vars.text
myThemeText: lightTheme.vars.text,
faMoon, faSun
};
},

View File

@ -35,6 +35,24 @@
<span>{{ $t('private') }}</span>
</div>
</div>
<div @click="choose('local-public')" :class="{ active: v == 'local-public' }">
<div><fa icon="globe"/></div>
<div>
<span>{{ $t('local-public') }}</span>
</div>
</div>
<div @click="choose('local-home')" :class="{ active: v == 'local-home' }">
<div><fa icon="home"/></div>
<div>
<span>{{ $t('local-home') }}</span>
</div>
</div>
<div @click="choose('local-followers')" :class="{ active: v == 'local-followers' }">
<div><fa icon="unlock"/></div>
<div>
<span>{{ $t('local-followers') }}</span>
</div>
</div>
</div>
</div>
</template>

View File

@ -3,6 +3,7 @@
<p>Maintainer: <b><a :href="'mailto:' + meta.maintainer.email" target="_blank">{{ meta.maintainer.name }}</a></b></p>
<p>Machine: {{ meta.machine }}</p>
<p>Node: {{ meta.node }}</p>
<p>Version: {{ meta.version }} </p>
</div>
</template>

View File

@ -94,7 +94,7 @@ import MkRenoteFormWindow from './renote-form-window.vue';
import MkNoteMenu from '../../../common/views/components/note-menu.vue';
import MkReactionPicker from '../../../common/views/components/reaction-picker.vue';
import XSub from './note.sub.vue';
import { sum } from '../../../../../prelude/array';
import { sum, unique } from '../../../../../prelude/array';
import noteSubscriber from '../../../common/scripts/note-subscriber';
export default Vue.extend({
@ -149,9 +149,9 @@ export default Vue.extend({
urls(): string[] {
if (this.p.text) {
const ast = parse(this.p.text);
return ast
return unique(ast
.filter(t => (t.type == 'url' || t.type == 'link') && !t.silent)
.map(t => t.url);
.map(t => t.url));
} else {
return null;
}

View File

@ -2,7 +2,7 @@
<div
class="note"
:class="{ mini }"
v-show="appearNote.deletedAt == null && !hideThisNote"
v-show="(this.$store.state.settings.remainDeletedNote || appearNote.deletedAt == null) && !hideThisNote"
:tabindex="appearNote.deletedAt == null ? '-1' : null"
v-hotkey="keymap"
:title="title"
@ -20,12 +20,19 @@
<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>
<article>
<mk-avatar class="avatar" :user="appearNote.user"/>
<div class="main">
<mk-note-header class="header" :note="appearNote" :mini="mini"/>
<div class="body">
<div class="body" v-if="appearNote.deletedAt == null">
<p v-if="appearNote.cw != null" class="cw">
<span class="text" v-if="appearNote.cw != ''">{{ appearNote.cw }}</span>
<mk-cw-button v-model="showContent"/>
@ -46,7 +53,7 @@
<mk-url-preview v-for="url in urls" :url="url" :key="url" :mini="mini"/>
</div>
</div>
<footer>
<footer v-if="appearNote.deletedAt == null">
<span class="app" v-if="appearNote.app && mini && $store.state.settings.showVia">via <b>{{ appearNote.app.name }}</b></span>
<mk-reactions-viewer :note="appearNote" ref="reactionsViewer"/>
<button class="replyButton" @click="reply()" :title="$t('reply')">
@ -64,6 +71,7 @@
<fa icon="ellipsis-h"/>
</button>
</footer>
<div class="deleted" v-if="appearNote.deletedAt != null">{{ $t('deleted') }}</div>
</div>
</article>
<div class="replies" v-if="detail && replies.length > 0">
@ -82,6 +90,7 @@ import noteSubscriber from '../../../common/scripts/note-subscriber';
export default Vue.extend({
i18n: i18n('desktop/views/components/note.vue'),
components: {
XSub
},
@ -199,9 +208,6 @@ export default Vue.extend({
> span
flex-shrink 0
&:last-of-type
margin-right 8px
.name
overflow hidden
flex-shrink 1
@ -215,6 +221,18 @@ export default Vue.extend({
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
@ -327,6 +345,7 @@ export default Vue.extend({
margin-left 0.5em
color var(--noteHeaderInfo)
font-size 0.8em
> button
margin 0 28px 0 0
padding 0 8px
@ -360,6 +379,10 @@ export default Vue.extend({
&.reacted, &.reacted:hover
color var(--noteActionsReactionHover)
> .deleted
color var(--noteText)
opacity 0.7
</style>
<style lang="stylus" module>

View File

@ -14,6 +14,7 @@
<b>{{ $t('recent-tags') }}:</b>
<a v-for="tag in recentHashtags.slice(0, 5)" @click="addTag(tag)" :title="$t('click-to-tagging')">#{{ tag }}</a>
</div>
<div class="local-only" v-if="this.localOnly == true">{{ $t('local-only-message') }}</div>
<input v-show="useCw" v-model="cw" :placeholder="$t('annotations')">
<div class="textarea">
<textarea :class="{ with: (files.length != 0 || poll) }"
@ -112,6 +113,7 @@ export default Vue.extend({
geo: null,
visibility: this.$store.state.settings.rememberNoteVisibility ? (this.$store.state.device.visibility || this.$store.state.settings.defaultNoteVisibility) : this.$store.state.settings.defaultNoteVisibility,
visibleUsers: [],
localOnly: false,
autocomplete: null,
draghover: false,
recentHashtags: JSON.parse(localStorage.getItem('hashtags') || '[]'),
@ -363,7 +365,14 @@ export default Vue.extend({
source: this.$refs.visibilityButton
});
w.$once('chosen', v => {
this.visibility = v;
const m = v.match(/^local-(.+)/);
if (m) {
this.localOnly = true;
this.visibility = m[1];
} else {
this.localOnly = false;
this.visibility = v;
}
});
},
@ -407,6 +416,7 @@ export default Vue.extend({
cw: this.useCw ? this.cw || '' : undefined,
visibility: this.visibility,
visibleUserIds: this.visibility == 'specified' ? this.visibleUsers.map(u => u.id) : undefined,
localOnly: this.localOnly,
geo: this.geo ? {
coordinates: [this.geo.longitude, this.geo.latitude],
altitude: this.geo.altitude,
@ -498,6 +508,7 @@ export default Vue.extend({
border solid 1px var(--primaryAlpha01)
border-radius 4px
transition border-color .2s ease
padding-right 30px
&:hover
border-color var(--primaryAlpha02)
@ -640,6 +651,10 @@ export default Vue.extend({
margin-right 8px
white-space nowrap
> .local-only
margin 0 0 8px 0
color var(--primary)
> .mk-uploader
margin 8px 0 0 0
padding 8px

View File

@ -20,14 +20,21 @@
<ui-card>
<div slot="title"><fa :icon="['fab', 'twitter']"/> {{ $t('twitter') }}</div>
<section>
<mk-twitter-setting/>
<x-twitter-setting/>
</section>
</ui-card>
<ui-card>
<div slot="title"><fa :icon="['fab', 'github']"/> {{ $t('github') }}</div>
<section>
<mk-github-setting/>
<x-github-setting/>
</section>
</ui-card>
<ui-card>
<div slot="title"><fa :icon="['fab', 'discord']"/> {{ $t('discord') }}</div>
<section>
<x-discord-setting/>
</section>
</ui-card>
</div>
@ -123,6 +130,7 @@
<ui-switch v-model="showReplyTarget">{{ $t('show-reply-target') }}</ui-switch>
<ui-switch v-model="showMaps">{{ $t('show-maps') }}</ui-switch>
<ui-switch v-model="disableAnimatedMfm">{{ $t('@.disable-animated-mfm') }}</ui-switch>
<ui-switch v-model="remainDeletedNote">{{ $t('remain-deleted-note') }}</ui-switch>
</section>
<section>
<header>{{ $t('deck-column-align') }}</header>
@ -292,6 +300,16 @@ import X2fa from './settings.2fa.vue';
import XApps from './settings.apps.vue';
import XSignins from './settings.signins.vue';
import XTags from './settings.tags.vue';
import XTwitterSetting from '../../../common/views/components/twitter-setting.vue';
import XGithubSetting from '../../../common/views/components/github-setting.vue';
import XDiscordSetting from '../../../common/views/components/discord-setting.vue';
import XTheme from '../../../common/views/components/theme.vue';
import XDriveSettings from '../../../common/views/components/drive-settings.vue';
import XMuteAndBlock from '../../../common/views/components/mute-and-block.vue';
import XPasswordSettings from '../../../common/views/components/password-settings.vue';
import XProfileEditor from '../../../common/views/components/profile-editor.vue';
import XApiSettings from '../../../common/views/components/api-settings.vue';
import { url, langs, clientVersion as version } from '../../../config';
import checkForUpdate from '../../../common/scripts/check-for-update';
@ -302,12 +320,15 @@ export default Vue.extend({
XApps,
XSignins,
XTags,
XTheme: () => import('../../../common/views/components/theme.vue').then(m => m.default),
XDriveSettings: () => import('../../../common/views/components/drive-settings.vue').then(m => m.default),
XMuteAndBlock: () => import('../../../common/views/components/mute-and-block.vue').then(m => m.default),
XPasswordSettings: () => import('../../../common/views/components/password-settings.vue').then(m => m.default),
XProfileEditor: () => import('../../../common/views/components/profile-editor.vue').then(m => m.default),
XApiSettings: () => import('../../../common/views/components/api-settings.vue').then(m => m.default),
XTwitterSetting,
XGithubSetting,
XDiscordSetting,
XTheme,
XDriveSettings,
XMuteAndBlock,
XPasswordSettings,
XProfileEditor,
XApiSettings,
},
props: {
initialPage: {
@ -509,6 +530,11 @@ export default Vue.extend({
disableAnimatedMfm: {
get() { return this.$store.state.settings.disableAnimatedMfm; },
set(value) { this.$store.dispatch('settings/set', { key: 'disableAnimatedMfm', value }); }
},
remainDeletedNote: {
get() { return this.$store.state.settings.remainDeletedNote; },
set(value) { this.$store.dispatch('settings/set', { key: 'remainDeletedNote', value }); }
}
},
created() {

View File

@ -58,7 +58,7 @@
<i><fa icon="angle-right"/></i>
</p>
</li>
<li v-if="$store.state.i.isAdmin">
<li v-if="$store.state.i.isAdmin || $store.state.i.isModerator">
<a href="/admin">
<i><fa icon="terminal"/></i>
<span>{{ $t('admin') }}</span>

View File

@ -1,12 +1,12 @@
<template>
<x-column :menu="menu" :name="name" :column="column" :is-stacked="isStacked">
<span slot="header">
<template v-if="column.type == 'home'"><fa icon="home"/></template>
<template v-if="column.type == 'local'"><fa :icon="['far', 'comments']"/></template>
<template v-if="column.type == 'hybrid'"><fa icon="share-alt"/></template>
<template v-if="column.type == 'global'"><fa icon="globe"/></template>
<template v-if="column.type == 'list'"><fa icon="list"/></template>
<template v-if="column.type == 'hashtag'"><fa icon="hashtag"/></template>
<fa v-if="column.type == 'home'" icon="home"/>
<fa v-if="column.type == 'local'" :icon="['far', 'comments']"/>
<fa v-if="column.type == 'hybrid'" icon="share-alt"/>
<fa v-if="column.type == 'global'" icon="globe"/>
<fa v-if="column.type == 'list'" icon="list"/>
<fa v-if="column.type == 'hashtag'" icon="hashtag"/>
<span>{{ name }}</span>
</span>

View File

@ -307,8 +307,10 @@ export default Vue.extend({
listId: list.id,
userId: this.user.id
});
// TODO
//this.$root.new(Ok);
this.$root.alert({
type: 'success',
splash: true
});
});
}
}];

View File

@ -0,0 +1,26 @@
<template>
<div class="lkafjvabenanajk17kwqpsatoushincb">
<span><fa :icon="['fab', 'discord']"/><a :href="`https://discordapp.com/users/${user.discord.id}`" target="_blank">@{{ user.discord.username }}#{{ user.discord.discriminator }}</a></span>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
props: ['user']
});
</script>
<style lang="stylus" scoped>
.lkafjvabenanajk17kwqpsatoushincb
padding 32px
background #7289da
border-radius 6px
color #fff
a
margin-left 8px
color #fff
</style>

View File

@ -14,6 +14,7 @@
<x-profile :user="user"/>
<x-twitter :user="user" v-if="!user.host && user.twitter"/>
<x-github :user="user" v-if="!user.host && user.github"/>
<x-discord :user="user" v-if="!user.host && user.discord"/>
<mk-calendar @chosen="warp" :start="new Date(user.createdAt)"/>
<mk-activity :user="user"/>
<x-photos :user="user"/>
@ -39,6 +40,7 @@ import XFollowersYouKnow from './user.followers-you-know.vue';
import XFriends from './user.friends.vue';
import XTwitter from './user.twitter.vue';
import XGithub from './user.github.vue'; // ?MEM: Don't fix the intentional typo. (XGitHub -> `<x-git-hub>`)
import XDiscord from './user.discord.vue';
export default Vue.extend({
i18n: i18n(),
@ -50,7 +52,8 @@ export default Vue.extend({
XFollowersYouKnow,
XFriends,
XTwitter,
XGithub // ?MEM: Don't fix the intentional typo. (see L41)
XGithub, // ?MEM: Don't fix the intentional typo. (see L41)
XDiscord
},
data() {
return {

View File

@ -227,6 +227,7 @@ export default define({
background var(--desktopPostFormTextareaBg)
border none
border-bottom solid 1px var(--faceDivider)
padding-right 30px
&:focus
& + .emoji

View File

@ -115,6 +115,10 @@ import {
faChartLine,
faEllipsisV,
faStickyNote,
faUserPlus,
faExternalLinkSquareAlt,
faSync,
faArrowLeft,
} from '@fortawesome/free-solid-svg-icons';
import {
@ -135,11 +139,13 @@ import {
faClock as farClock,
faCalendarAlt as farCalendarAlt,
faHdd as farHdd,
faMoon as farMoon,
} from '@fortawesome/free-regular-svg-icons';
import {
faTwitter as fabTwitter,
faGithub as fabGithub,
faDiscord as fabDiscord
} from '@fortawesome/free-brands-svg-icons';
import i18n from './i18n';
@ -233,6 +239,10 @@ library.add(
faChartLine,
faEllipsisV,
faStickyNote,
faUserPlus,
faExternalLinkSquareAlt,
faSync,
faArrowLeft,
farBell,
farEnvelope,
@ -251,9 +261,11 @@ library.add(
farClock,
farCalendarAlt,
farHdd,
farMoon,
fabTwitter,
fabGithub
fabGithub,
fabDiscord
);
//#endregion

View File

@ -385,15 +385,19 @@ export default class MiOS extends EventEmitter {
* @param data パラメータ
*/
@autobind
public api(endpoint: string, data: { [x: string]: any } = {}, forceFetch = false): Promise<{ [x: string]: any }> {
if (++pending === 1) {
spinner = document.createElement('div');
spinner.setAttribute('id', 'wait');
document.body.appendChild(spinner);
public api(endpoint: string, data: { [x: string]: any } = {}, forceFetch = false, silent = false): Promise<{ [x: string]: any }> {
if (!silent) {
if (++pending === 1) {
spinner = document.createElement('div');
spinner.setAttribute('id', 'wait');
document.body.appendChild(spinner);
}
}
const onFinally = () => {
if (--pending === 0) spinner.parentNode.removeChild(spinner);
if (!silent) {
if (--pending === 0) spinner.parentNode.removeChild(spinner);
}
};
const promise = new Promise((resolve, reject) => {

View File

@ -92,7 +92,7 @@ import parse from '../../../../../mfm/parse';
import MkNoteMenu from '../../../common/views/components/note-menu.vue';
import MkReactionPicker from '../../../common/views/components/reaction-picker.vue';
import XSub from './note.sub.vue';
import { sum } from '../../../../../prelude/array';
import { sum, unique } from '../../../../../prelude/array';
import noteSubscriber from '../../../common/scripts/note-subscriber';
export default Vue.extend({
@ -143,9 +143,9 @@ export default Vue.extend({
urls(): string[] {
if (this.p.text) {
const ast = parse(this.p.text);
return ast
return unique(ast
.filter(t => (t.type == 'url' || t.type == 'link') && !t.silent)
.map(t => t.url);
.map(t => t.url));
} else {
return null;
}

View File

@ -16,12 +16,19 @@
<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>
<article>
<mk-avatar class="avatar" :user="appearNote.user" v-if="$store.state.device.postStyle != 'smart'"/>
<div class="main">
<mk-note-header class="header" :note="appearNote" :mini="true"/>
<div class="body">
<div class="body" v-if="appearNote.deletedAt == null">
<p v-if="appearNote.cw != null" class="cw">
<span class="text" v-if="appearNote.cw != ''">{{ appearNote.cw }}</span>
<mk-cw-button v-model="showContent"/>
@ -30,7 +37,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" :i="$store.state.i" :class="$style.text" :custom-emojis="appearNote.emojis"/>
<a class="rp" v-if="appearNote.renote != null">RN:</a>
</div>
<div class="files" v-if="appearNote.files.length > 0">
@ -43,7 +50,7 @@
</div>
<span class="app" v-if="appearNote.app && $store.state.settings.showVia">via <b>{{ appearNote.app.name }}</b></span>
</div>
<footer>
<footer v-if="appearNote.deletedAt == null">
<mk-reactions-viewer :note="appearNote" ref="reactionsViewer"/>
<button @click="reply()">
<template v-if="appearNote.reply"><fa icon="reply-all"/></template>
@ -60,6 +67,7 @@
<fa icon="ellipsis-h"/>
</button>
</footer>
<div class="deleted" v-if="appearNote.deletedAt != null">{{ $t('deleted') }}</div>
</div>
</article>
</div>
@ -163,9 +171,6 @@ export default Vue.extend({
> span
flex-shrink 0
&:last-of-type
margin-right 8px
.name
overflow hidden
flex-shrink 1
@ -179,6 +184,18 @@ export default Vue.extend({
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
@ -339,6 +356,10 @@ export default Vue.extend({
&.reacted
color var(--primary)
> .deleted
color var(--noteText)
opacity 0.7
</style>
<style lang="stylus" module>

View File

@ -102,6 +102,7 @@ export default Vue.extend({
geo: null,
visibility: this.$store.state.settings.rememberNoteVisibility ? (this.$store.state.device.visibility || this.$store.state.settings.defaultNoteVisibility) : this.$store.state.settings.defaultNoteVisibility,
visibleUsers: [],
localOnly: false,
useCw: false,
cw: null,
recentHashtags: JSON.parse(localStorage.getItem('hashtags') || '[]'),
@ -274,7 +275,14 @@ export default Vue.extend({
compact: true
});
w.$once('chosen', v => {
this.visibility = v;
const m = v.match(/^local-(.+)/);
if (m) {
this.localOnly = true;
this.visibility = m[1];
} else {
this.localOnly = false;
this.visibility = v;
}
});
},
@ -320,6 +328,7 @@ export default Vue.extend({
} : null,
visibility: this.visibility,
visibleUserIds: this.visibility == 'specified' ? this.visibleUsers.map(u => u.id) : undefined,
localOnly: this.localOnly,
viaMobile: viaMobile
}).then(data => {
this.$emit('posted');

View File

@ -30,7 +30,7 @@
<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"><a href="/admin"><i><fa icon="terminal"/></i><span>{{ $t('admin') }}</span><i><fa icon="angle-right"/></i></a></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>
</ul>
</div>

View File

@ -140,6 +140,19 @@
</section>
</ui-card>
<ui-card>
<div slot="title"><fa :icon="['fab', 'discord']"/> {{ $t('discord') }}</div>
<section>
<p class="account" v-if="$store.state.i.discord"><a :href="`https://discordapp.com/users/${$store.state.i.discord.id}`" target="_blank">@{{ $store.state.i.discord.username }}#{{ $store.state.i.discord.discriminator }}</a></p>
<p>
<a :href="`${apiUrl}/connect/discord`" target="_blank">{{ $store.state.i.discord ? this.$t('discord-reconnect') : this.$t('discord-connect') }}</a>
<span v-if="$store.state.i.discord"> or </span>
<a :href="`${apiUrl}/disconnect/discord`" target="_blank" v-if="$store.state.i.discord">{{ $t('discord-disconnect') }}</a>
</p>
</section>
</ui-card>
<x-api-settings />
<ui-card>
@ -179,17 +192,23 @@ import Vue from 'vue';
import i18n from '../../../i18n';
import { apiUrl, clientVersion as version, codename, langs } from '../../../config';
import checkForUpdate from '../../../common/scripts/check-for-update';
import XTheme from '../../../common/views/components/theme.vue';
import XDriveSettings from '../../../common/views/components/drive-settings.vue';
import XMuteAndBlock from '../../../common/views/components/mute-and-block.vue';
import XPasswordSettings from '../../../common/views/components/password-settings.vue';
import XProfileEditor from '../../../common/views/components/profile-editor.vue';
import XApiSettings from '../../../common/views/components/api-settings.vue';
export default Vue.extend({
i18n: i18n('mobile/views/pages/settings.vue'),
components: {
XTheme: () => import('../../../common/views/components/theme.vue').then(m => m.default),
XDriveSettings: () => import('../../../common/views/components/drive-settings.vue').then(m => m.default),
XMuteAndBlock: () => import('../../../common/views/components/mute-and-block.vue').then(m => m.default),
XPasswordSettings: () => import('../../../common/views/components/password-settings.vue').then(m => m.default),
XProfileEditor: () => import('../../../common/views/components/profile-editor.vue').then(m => m.default),
XApiSettings: () => import('../../../common/views/components/api-settings.vue').then(m => m.default),
XTheme,
XDriveSettings,
XMuteAndBlock,
XPasswordSettings,
XProfileEditor,
XApiSettings,
},
data() {

View File

@ -15,6 +15,7 @@ const defaultSettings = {
tagTimelines: [],
fetchOnScroll: true,
showMaps: true,
remainDeletedNote: false,
showPostFormOnTopOfTl: false,
suggestRecentHashtags: true,
showClockOnHeader: true,

View File

@ -26,6 +26,13 @@ props:
ja-JP: "モバイル端末から投稿したか否か(自己申告であることに留意)"
en-US: "Whether this note sent via a mobile device"
localOnly:
type: "boolean"
optional: true
desc:
ja-JP: "ローカルのみに公開する投稿か否か"
en-US: "Whether this note is no federation"
text:
type: "string"
optional: true

View File

@ -112,7 +112,12 @@ async function init(): Promise<Config> {
Logger.info('Welcome to Misskey!');
Logger.info(`<<< Misskey v${pkg.version} >>>`);
new Logger('Deps').info(`Node.js ${process.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.`);
process.exit(1);
}
await MachineInfo.show();
EnvironmentInfo.show();
@ -135,6 +140,11 @@ async function init(): Promise<Config> {
configLogger.succ('Loaded');
if (config.port == null) {
Logger.error('The port is not configured. Please configure port.');
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');
process.exit(1);

View File

@ -53,6 +53,12 @@ const handlers: { [key: string]: (window: any, token: any, mentionedRemoteUsers:
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;

View File

@ -8,7 +8,9 @@ export type TextElementHashtag = {
hashtag: string;
};
export default function(text: string, isBegin: boolean) {
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];

View File

@ -0,0 +1,20 @@
/**
* 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

@ -12,9 +12,10 @@ export type TextElementMention = {
host: string;
};
export default function(text: 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;

View File

@ -8,7 +8,9 @@ export type TextElementQuote = {
quote: string;
};
export default function(text: string, isBegin: boolean) {
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);

View File

@ -8,7 +8,9 @@ export type TextElementTitle = {
title: string;
};
export default function(text: string, isBegin: boolean) {
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 {

View File

@ -8,10 +8,13 @@ export type TextElementUrl = {
url: string;
};
export default function(text: string) {
const match = text.match(/^https?:\/\/[\w\/:%#@\$&\?!\(\)\[\]~\.=\+\-]+/);
export default function(text: string, before: string) {
const match = text.match(/^https?:\/\/[\w\/:%#@\$&\?!\(\)\[\]~\.,=\+\-]+/);
if (!match) return null;
const url = match[0];
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,

View File

@ -8,6 +8,7 @@ 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';
@ -29,6 +30,7 @@ const elements = [
require('./elements/hashtag'),
require('./elements/code'),
require('./elements/inline-code'),
require('./elements/math'),
require('./elements/quote'),
require('./elements/emoji'),
require('./elements/search'),
@ -42,6 +44,7 @@ export type TextElement = { type: 'text', content: string }
| TextElementEmoji
| TextElementHashtag
| TextElementInlineCode
| TextElementMath
| TextElementLink
| TextElementMention
| TextElementQuote
@ -49,7 +52,7 @@ export type TextElement = { type: 'text', content: string }
| TextElementTitle
| TextElementUrl
| TextElementMotion;
export type TextElementProcessor = (text: string, isBegin: boolean) => TextElement | TextElement[];
export type TextElementProcessor = (text: string, before: string) => TextElement | TextElement[];
export default (source: string): TextElement[] => {
if (source == null || source == '') {
@ -65,12 +68,10 @@ export default (source: string): TextElement[] => {
}
}
let i = 0;
// パース
while (source != '') {
const parsed = elements.some(el => {
let _tokens = el(source, i == 0);
let _tokens = el(source, tokens.map(token => token.content).join(''));
if (_tokens) {
if (!Array.isArray(_tokens)) {
_tokens = [_tokens];
@ -88,8 +89,6 @@ export default (source: string): TextElement[] => {
content: source[0]
});
}
i++;
}
const combineText = (es: TextElement[]): TextElement =>

View File

@ -15,6 +15,7 @@ const defaultMeta: any = {
maxNoteTextLength: 1000,
enableTwitterIntegration: false,
enableGithubIntegration: false,
enableDiscordIntegration: false
};
export default async function(): Promise<IMeta> {

View File

@ -191,4 +191,8 @@ export type IMeta = {
enableGithubIntegration?: boolean;
githubClientId?: string;
githubClientSecret?: string;
enableDiscordIntegration?: boolean;
discordClientId?: string;
discordClientSecret?: string;
};

View File

@ -50,6 +50,7 @@ export type INote = {
userId: mongo.ObjectID;
appId: mongo.ObjectID;
viaMobile: boolean;
localOnly: boolean;
renoteCount: number;
repliesCount: number;
reactionCounts: any;

View File

@ -88,6 +88,14 @@ export interface ILocalUser extends IUserBase {
id: string;
login: string;
};
discord: {
accessToken: string;
refreshToken: string;
expiresDate: number;
id: string;
username: string;
discriminator: string;
};
line: {
userId: string;
};
@ -99,6 +107,7 @@ export interface ILocalUser extends IUserBase {
lastUsedAt: Date;
isCat: boolean;
isAdmin?: boolean;
isModerator?: boolean;
isVerified?: boolean;
twoFactorSecret: string;
twoFactorEnabled: boolean;
@ -125,6 +134,7 @@ export interface IRemoteUser extends IUserBase {
};
updatedAt: Date;
isAdmin: false;
isModerator: false;
}
export type IUser = ILocalUser | IRemoteUser;
@ -289,6 +299,11 @@ export const pack = (
if (_user.github) {
delete _user.github.accessToken;
}
if (_user.discord) {
delete _user.discord.accessToken;
delete _user.discord.refreshToken;
delete _user.discord.expiresDate;
}
delete _user.line;
// Visible via only the official client

View File

@ -6,6 +6,8 @@ export function createHttpJob(data: any) {
}
export function deliver(user: ILocalUser, content: any, to: any) {
if (content == null) return;
createHttpJob({
type: 'deliver',
user,

View File

@ -92,7 +92,7 @@ export default async (job: bq.Job, done: any): Promise<void> => {
done();
return;
}
//#region Log
publishApLogStream({
direction: 'in',

View File

@ -116,6 +116,7 @@ export async function createNote(value: any, resolver?: Resolver, silent = false
cw: note.summary,
text: text,
viaMobile: false,
localOnly: false,
geo: undefined,
visibility,
visibleUsers,

View File

@ -66,7 +66,8 @@ router.get('/notes/:note', async (ctx, next) => {
const note = await Note.findOne({
_id: new mongo.ObjectID(ctx.params.note),
visibility: { $in: ['public', 'home'] }
visibility: { $in: ['public', 'home'] },
localOnly: { $ne: true }
});
if (note === null) {
@ -83,7 +84,8 @@ router.get('/notes/:note', async (ctx, next) => {
router.get('/notes/:note/activity', async ctx => {
const note = await Note.findOne({
_id: new mongo.ObjectID(ctx.params.note),
visibility: { $in: ['public', 'home'] }
visibility: { $in: ['public', 'home'] },
localOnly: { $ne: true }
});
if (note === null) {

View File

@ -55,7 +55,8 @@ export default async (ctx: Router.IRouterContext) => {
const query = {
userId: user._id,
visibility: { $in: ['public', 'home'] }
visibility: { $in: ['public', 'home'] },
localOnly: { $ne: true }
} as any;
if (sinceId) {

View File

@ -29,6 +29,10 @@ export default (endpoint: string, user: IUser, app: IApp, data: any, file?: any)
return rej('YOU_ARE_NOT_ADMIN');
}
if (ep.meta.requireModerator && !user.isAdmin && !user.isModerator) {
return rej('YOU_ARE_NOT_MODERATOR');
}
if (app && ep.meta.kind && !app.permission.some(p => p === ep.meta.kind)) {
return rej('PERMISSION_DENIED');
}

View File

@ -30,6 +30,11 @@ export interface IEndpointMeta {
*/
requireAdmin?: boolean;
/**
* 管理者またはモデレーターのみ使えるエンドポイントか否か
*/
requireModerator?: boolean;
/**
* エンドポイントのリミテーションに関するやつ
* 省略した場合はリミテーションは無いものとして解釈されます。

View File

@ -8,7 +8,7 @@ export const meta = {
},
requireCredential: true,
requireAdmin: true,
requireModerator: true,
params: {
name: {

View File

@ -8,7 +8,7 @@ export const meta = {
},
requireCredential: true,
requireAdmin: true,
requireModerator: true,
params: {
host: {

View File

@ -9,7 +9,7 @@ export const meta = {
},
requireCredential: true,
requireAdmin: true,
requireModerator: true,
params: {
id: {

View File

@ -9,7 +9,7 @@ export const meta = {
},
requireCredential: true,
requireAdmin: true,
requireModerator: true,
params: {
id: {

View File

@ -8,7 +8,7 @@ export const meta = {
},
requireCredential: true,
requireAdmin: true,
requireModerator: true,
params: {}
};

View File

@ -0,0 +1,45 @@
import $ from 'cafy';
import ID, { transform } from '../../../../../misc/cafy-id';
import define from '../../../define';
import User from '../../../../../models/user';
export const meta = {
desc: {
'ja-JP': '指定したユーザーをモデレーターにします。',
'en-US': 'Mark a user as moderator.'
},
requireCredential: true,
requireAdmin: true,
params: {
userId: {
validator: $.type(ID),
transform: transform,
desc: {
'ja-JP': '対象のユーザーID',
'en-US': 'The user ID'
}
},
}
};
export default define(meta, (ps) => new Promise(async (res, rej) => {
const user = await User.findOne({
_id: ps.userId
});
if (user == null) {
return rej('user not found');
}
await User.update({
_id: user._id
}, {
$set: {
isModerator: true
}
});
res();
}));

View File

@ -0,0 +1,45 @@
import $ from 'cafy';
import ID, { transform } from '../../../../../misc/cafy-id';
import define from '../../../define';
import User from '../../../../../models/user';
export const meta = {
desc: {
'ja-JP': '指定したユーザーをモデレーター解除します。',
'en-US': 'Unmark a user as moderator.'
},
requireCredential: true,
requireAdmin: true,
params: {
userId: {
validator: $.type(ID),
transform: transform,
desc: {
'ja-JP': '対象のユーザーID',
'en-US': 'The user ID'
}
},
}
};
export default define(meta, (ps) => new Promise(async (res, rej) => {
const user = await User.findOne({
_id: ps.userId
});
if (user == null) {
return rej('user not found');
}
await User.update({
_id: user._id
}, {
$set: {
isModerator: false
}
});
res();
}));

View File

@ -10,7 +10,7 @@ export const meta = {
},
requireCredential: true,
requireAdmin: true,
requireModerator: true,
params: {
userId: {

View File

@ -10,7 +10,7 @@ export const meta = {
},
requireCredential: true,
requireAdmin: true,
requireModerator: true,
params: {
userId: {

View File

@ -10,7 +10,7 @@ export const meta = {
},
requireCredential: true,
requireAdmin: true,
requireModerator: true,
params: {
userId: {

View File

@ -8,7 +8,7 @@ export const meta = {
},
requireCredential: true,
requireAdmin: true,
requireModerator: true,
params: {
broadcasts: {
@ -177,9 +177,30 @@ export const meta = {
githubClientSecret: {
validator: $.str.optional.nullable,
desc: {
'ja-JP': 'GitHubアプリのClient secret'
'ja-JP': 'GitHubアプリのClient Secret'
}
},
enableDiscordIntegration: {
validator: $.bool.optional,
desc: {
'ja-JP': 'Discord連携機能を有効にするか否か'
}
},
discordClientId: {
validator: $.str.optional.nullable,
desc: {
'ja-JP': 'DiscordアプリのClient ID'
}
},
discordClientSecret: {
validator: $.str.optional.nullable,
desc: {
'ja-JP': 'DiscordアプリのClient Secret'
}
}
}
};
@ -282,6 +303,18 @@ export default define(meta, (ps) => new Promise(async (res, rej) => {
set.githubClientSecret = ps.githubClientSecret;
}
if (ps.enableDiscordIntegration !== undefined) {
set.enableDiscordIntegration = ps.enableDiscordIntegration;
}
if (ps.discordClientId !== undefined) {
set.discordClientId = ps.discordClientId;
}
if (ps.discordClientSecret !== undefined) {
set.discordClientSecret = ps.discordClientSecret;
}
await Meta.update({}, {
$set: set
}, { upsert: true });

View File

@ -10,7 +10,7 @@ export const meta = {
},
requireCredential: true,
requireAdmin: true,
requireModerator: true,
params: {
userId: {

View File

@ -0,0 +1,51 @@
import $ from 'cafy';
import define from '../define';
import Instance from '../../../models/instance';
export const meta = {
requireCredential: false,
params: {
limit: {
validator: $.num.optional.range(1, 100),
default: 30
},
offset: {
validator: $.num.optional.min(0),
default: 0
},
sort: {
validator: $.str.optional.or('+notes|-notes'),
}
}
};
export default define(meta, (ps, me) => new Promise(async (res, rej) => {
let _sort;
if (ps.sort) {
if (ps.sort == '+notes') {
_sort = {
notesCount: -1
};
} else if (ps.sort == '-notes') {
_sort = {
notesCount: 1
};
}
} else {
_sort = {
_id: -1
};
}
const instances = await Instance
.find({}, {
limit: ps.limit,
sort: _sort,
skip: ps.offset
});
res(instances);
}));

View File

@ -79,12 +79,13 @@ export default define(meta, (ps, me) => new Promise(async (res, rej) => {
objectStorage: config.drive && config.drive.storage === 'minio',
twitter: instance.enableTwitterIntegration,
github: instance.enableGithubIntegration,
discord: instance.enableDiscordIntegration,
serviceWorker: config.sw ? true : false,
userRecommendation: config.user_recommendation ? config.user_recommendation : {}
};
}
if (me && me.isAdmin) {
if (me && (me.isAdmin || me.isModerator)) {
response.hidedTags = instance.hidedTags;
response.recaptchaSecretKey = instance.recaptchaSecretKey;
response.proxyAccount = instance.proxyAccount;
@ -94,6 +95,9 @@ export default define(meta, (ps, me) => new Promise(async (res, rej) => {
response.enableGithubIntegration = instance.enableGithubIntegration;
response.githubClientId = instance.githubClientId;
response.githubClientSecret = instance.githubClientSecret;
response.enableDiscordIntegration = instance.enableDiscordIntegration;
response.discordClientId = instance.discordClientId;
response.discordClientSecret = instance.discordClientSecret;
}
res(response);

View File

@ -74,6 +74,14 @@ export const meta = {
}
},
localOnly: {
validator: $.bool.optional,
default: false,
desc: {
'ja-JP': 'ローカルのみに投稿か否か。'
}
},
geo: {
validator: $.obj({
coordinates: $.arr().length(2)
@ -226,6 +234,7 @@ export default define(meta, (ps, user, app) => new Promise(async (res, rej) => {
cw: ps.cw,
app,
viaMobile: ps.viaMobile,
localOnly: ps.localOnly,
visibility: ps.visibility,
visibleUsers,
geo: ps.geo

View File

@ -38,7 +38,7 @@ export default define(meta, (ps, user) => new Promise(async (res, rej) => {
return rej('note not found');
}
if (!user.isAdmin && !note.userId.equals(user._id)) {
if (!user.isAdmin && !user.isModerator && !note.userId.equals(user._id)) {
return rej('access denied');
}

View File

@ -43,6 +43,7 @@ endpoints.forEach(endpoint => endpoint.meta.requireFile
router.post('/signup', require('./private/signup').default);
router.post('/signin', require('./private/signin').default);
router.use(require('./service/discord').routes());
router.use(require('./service/github').routes());
router.use(require('./service/github-bot').routes());
router.use(require('./service/twitter').routes());

View File

@ -0,0 +1,306 @@
import * as Koa from 'koa';
import * as Router from 'koa-router';
import * as request from 'request';
import { OAuth2 } from 'oauth';
import User, { pack, ILocalUser } from '../../../models/user';
import config from '../../../config';
import { publishMainStream } from '../../../stream';
import redis from '../../../db/redis';
import uuid = require('uuid');
import signin from '../common/signin';
import fetchMeta from '../../../misc/fetch-meta';
function getUserToken(ctx: Koa.Context) {
return ((ctx.headers['cookie'] || '').match(/i=(!\w+)/) || [null, null])[1];
}
function compareOrigin(ctx: Koa.Context) {
function normalizeUrl(url: string) {
return url ? url.endsWith('/') ? url.substr(0, url.length - 1) : url : '';
}
const referer = ctx.headers['referer'];
return (normalizeUrl(referer) == normalizeUrl(config.url));
}
// Init router
const router = new Router();
router.get('/disconnect/discord', async ctx => {
if (!compareOrigin(ctx)) {
ctx.throw(400, 'invalid origin');
return;
}
const userToken = getUserToken(ctx);
if (!userToken) {
ctx.throw(400, 'signin required');
return;
}
const user = await User.findOneAndUpdate({
host: null,
'token': userToken
}, {
$set: {
'discord': null
}
});
ctx.body = `Discordの連携を解除しました :v:`;
// Publish i updated event
publishMainStream(user._id, 'meUpdated', await pack(user, user, {
detail: true,
includeSecrets: true
}));
});
async function getOAuth2() {
const meta = await fetchMeta();
if (meta.enableDiscordIntegration) {
return new OAuth2(
meta.discordClientId,
meta.discordClientSecret,
'https://discordapp.com/',
'api/oauth2/authorize',
'api/oauth2/token');
} else {
return null;
}
}
router.get('/connect/discord', async ctx => {
if (!compareOrigin(ctx)) {
ctx.throw(400, 'invalid origin');
return;
}
const userToken = getUserToken(ctx);
if (!userToken) {
ctx.throw(400, 'signin required');
return;
}
const params = {
redirect_uri: `${config.url}/api/dc/cb`,
scope: ['identify'],
state: uuid(),
response_type: 'code'
};
redis.set(userToken, JSON.stringify(params));
const oauth2 = await getOAuth2();
ctx.redirect(oauth2.getAuthorizeUrl(params));
});
router.get('/signin/discord', async ctx => {
const sessid = uuid();
const params = {
redirect_uri: `${config.url}/api/dc/cb`,
scope: ['identify'],
state: uuid(),
response_type: 'code'
};
const expires = 1000 * 60 * 60; // 1h
ctx.cookies.set('signin_with_discord_session_id', sessid, {
path: '/',
domain: config.host,
secure: config.url.startsWith('https'),
httpOnly: true,
expires: new Date(Date.now() + expires),
maxAge: expires
});
redis.set(sessid, JSON.stringify(params));
const oauth2 = await getOAuth2();
ctx.redirect(oauth2.getAuthorizeUrl(params));
});
router.get('/dc/cb', async ctx => {
const userToken = getUserToken(ctx);
const oauth2 = await getOAuth2();
if (!userToken) {
const sessid = ctx.cookies.get('signin_with_discord_session_id');
if (!sessid) {
ctx.throw(400, 'invalid session');
return;
}
const code = ctx.query.code;
if (!code) {
ctx.throw(400, 'invalid session');
return;
}
const { redirect_uri, state } = await new Promise<any>((res, rej) => {
redis.get(sessid, async (_, state) => {
res(JSON.parse(state));
});
});
if (ctx.query.state !== state) {
ctx.throw(400, 'invalid session');
return;
}
const { accessToken, refreshToken, expiresDate } = await new Promise<any>((res, rej) =>
oauth2.getOAuthAccessToken(
code,
{
grant_type: 'authorization_code',
redirect_uri
},
(err, accessToken, refreshToken, result) => {
if (err)
rej(err);
else if (result.error)
rej(result.error);
else
res({
accessToken,
refreshToken,
expiresDate: Date.now() + Number(result.expires_in) * 1000
});
}));
const { id, username, discriminator } = await new Promise<any>((res, rej) =>
request({
url: 'https://discordapp.com/api/users/@me',
headers: {
'Authorization': `Bearer ${accessToken}`,
'User-Agent': config.user_agent
}
}, (err, response, body) => {
if (err)
rej(err);
else
res(JSON.parse(body));
}));
if (!id || !username || !discriminator) {
ctx.throw(400, 'invalid session');
return;
}
let user = await User.findOne({
host: null,
'discord.id': id
}) as ILocalUser;
if (!user) {
ctx.throw(404, `@${username}#${discriminator}と連携しているMisskeyアカウントはありませんでした...`);
return;
}
user = await User.findOneAndUpdate({
host: null,
'discord.id': id
}, {
$set: {
discord: {
accessToken,
refreshToken,
expiresDate,
username,
discriminator
}
}
}) as ILocalUser;
signin(ctx, user, true);
} else {
const code = ctx.query.code;
if (!code) {
ctx.throw(400, 'invalid session');
return;
}
const { redirect_uri, state } = await new Promise<any>((res, rej) => {
redis.get(userToken, async (_, state) => {
res(JSON.parse(state));
});
});
if (ctx.query.state !== state) {
ctx.throw(400, 'invalid session');
return;
}
const { accessToken, refreshToken, expiresDate } = await new Promise<any>((res, rej) =>
oauth2.getOAuthAccessToken(
code,
{
grant_type: 'authorization_code',
redirect_uri
},
(err, accessToken, refreshToken, result) => {
if (err)
rej(err);
else if (result.error)
rej(result.error);
else
res({
accessToken,
refreshToken,
expiresDate: Date.now() + Number(result.expires_in) * 1000
});
}));
const { id, username, discriminator } = await new Promise<any>((res, rej) =>
request({
url: 'https://discordapp.com/api/users/@me',
headers: {
'Authorization': `Bearer ${accessToken}`,
'User-Agent': config.user_agent
}
}, (err, response, body) => {
if (err)
rej(err);
else
res(JSON.parse(body));
}));
if (!id || !username || !discriminator) {
ctx.throw(400, 'invalid session');
return;
}
const user = await User.findOneAndUpdate({
host: null,
token: userToken
}, {
$set: {
discord: {
accessToken,
refreshToken,
expiresDate,
id,
username,
discriminator
}
}
});
ctx.body = `Discord: @${username}#${discriminator} を、Misskey: @${user.username} に接続しました!`;
// Publish i updated event
publishMainStream(user._id, 'meUpdated', await pack(user, user, {
detail: true,
includeSecrets: true
}));
}
});
module.exports = router;

View File

@ -75,9 +75,9 @@ handler.on('status', event => {
const parentState = parentStatuses[0].state;
const stillFailed = parentState == 'failure' || parentState == 'error';
if (stillFailed) {
post(`**BUILD STILL FAILED⚠**: ?[${commit.commit.message}](${commit.html_url})`);
post(`⚠️**BUILD STILL FAILED**⚠️: ?[${commit.commit.message}](${commit.html_url})`);
} else {
post(`**🚨BUILD FAILED🚨**: →→→?[${commit.commit.message}](${commit.html_url})←←←`);
post(`🚨**BUILD FAILED**🚨: →→→?[${commit.commit.message}](${commit.html_url})←←←`);
}
});
break;
@ -87,7 +87,7 @@ handler.on('status', event => {
handler.on('push', event => {
const ref = event.ref;
switch (ref) {
case 'refs/heads/master':
case 'refs/heads/develop':
const pusher = event.pusher;
const compare = event.compare;
const commits: any[] = event.commits;
@ -96,10 +96,6 @@ handler.on('push', event => {
commits.reverse().map(commit => `・[?[${commit.id.substr(0, 7)}](${commit.url})] ${commit.message.split('\n')[0]}`).join('\n'),
].join('\n'));
break;
case 'refs/heads/release':
const commit = event.commits[0];
post(`RELEASED: ${commit.message}`);
break;
}
});
@ -128,6 +124,17 @@ handler.on('issue_comment', event => {
post(text);
});
handler.on('release', event => {
const action = event.action;
const release = event.release;
let text: string;
switch (action) {
case 'published': text = `🎁 **NEW RELEASE**: [${release.tag_name}](${release.html_url}) is out now. Enjoy!`; break;
default: return;
}
post(text);
});
handler.on('watch', event => {
const sender = event.sender;
post(`(((⭐️))) Starred by **${sender.login}** (((⭐️)))`, false);

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