Compare commits
	
		
			444 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | cc5d2b2875 | ||
|   | 94ef03db9e | ||
|   | 038bd100b2 | ||
|   | 3b5c3f086a | ||
|   | a136715111 | ||
|   | daa22d68fa | ||
|   | f24d202024 | ||
|   | d3e0b8574b | ||
|   | f4482cc34a | ||
|   | 3ff226cd6b | ||
|   | 5c0d37d021 | ||
|   | b958959cca | ||
|   | 762418d0fa | ||
|   | 6831f0c192 | ||
|   | 64635fff2d | ||
|   | e7e861fb5c | ||
|   | 08523ce271 | ||
|   | 833f63c1a9 | ||
|   | 1c05825bc8 | ||
|   | 26bb088a3d | ||
|   | 5c361cef23 | ||
|   | 04bef96aee | ||
|   | a791981da9 | ||
|   | 264c47e07a | ||
|   | 863c44d15c | ||
|   | cdec6f202e | ||
|   | bdf6c739a9 | ||
|   | 843dd5fb58 | ||
|   | c05853289a | ||
|   | 11c5d257f2 | ||
|   | cee1a27348 | ||
|   | 690dc75e45 | ||
|   | 8dc82b7a6e | ||
|   | a396b519bb | ||
|   | d5f9ce0893 | ||
|   | c1d7ae99ab | ||
|   | d8aee7c310 | ||
|   | 3e43d847ca | ||
|   | 70273931b2 | ||
|   | cc94d2acc5 | ||
|   | 327d9702ca | ||
|   | 1cdb285fe6 | ||
|   | e9e61e3034 | ||
|   | b613a51035 | ||
|   | 63e62ecb02 | ||
|   | d11122af3f | ||
|   | e8ddb7f6ee | ||
|   | 5ad0a158bc | ||
|   | e3ea29a8b6 | ||
|   | ead201ac3d | ||
|   | 19af2d7a7b | ||
|   | 8ba87443ca | ||
|   | 162ace2fd6 | ||
|   | f51fdc0dbf | ||
|   | d3d612a89b | ||
|   | 7c7f32d9a6 | ||
| ![greenkeeper[bot]](/assets/img/avatar_default.png)  | c8b6b6e44f | ||
|   | 12daa80071 | ||
|   | 2f8cc36d4b | ||
|   | 1af4f94338 | ||
|   | 172a0a85aa | ||
|   | d37c06884d | ||
|   | 80e52c57e1 | ||
|   | 213a7f137e | ||
|   | 4848b71ca0 | ||
|   | 13bad106cc | ||
|   | 3bebf82501 | ||
|   | e9a8090d7e | ||
|   | e2a79abbe0 | ||
|   | d7f57a4415 | ||
|   | 9dd5ed7f1a | ||
|   | 432e18a0c0 | ||
|   | 9a2d435cb1 | ||
|   | b02274c178 | ||
|   | 91408bceb1 | ||
|   | e1fd7e3f0c | ||
|   | d18498cb6b | ||
|   | b3986b8963 | ||
|   | 75e3d6f7fb | ||
|   | ded78aa294 | ||
|   | 58e8938364 | ||
|   | 6e8e6c7352 | ||
|   | 270de03646 | ||
|   | b6c7ff109b | ||
|   | 9b72a5a46d | ||
|   | 626e06c5fd | ||
|   | b09d10ac52 | ||
|   | d1568cda19 | ||
|   | 3400b4fa0d | ||
|   | 4455f110b1 | ||
|   | 25fc37449b | ||
|   | e5ffc7c492 | ||
|   | 5c118e6d8a | ||
|   | b49c70e67e | ||
|   | 3760fdeed0 | ||
|   | 3aece449e4 | ||
|   | dcd2d8be77 | ||
|   | b90e6f9abb | ||
|   | d984652aa1 | ||
|   | f176de6d2e | ||
|   | ef31efabb2 | ||
|   | 53763acb76 | ||
|   | 6f39010133 | ||
|   | 04b5fe6af4 | ||
|   | 626f43f424 | ||
|   | bebcc72deb | ||
|   | 9f285779ec | ||
|   | 57d3e9fc32 | ||
|   | 84cf09c1d0 | ||
|   | 0848bad960 | ||
|   | c1b13c3b5b | ||
|   | 8abc4ed65a | ||
|   | 0eebe620cb | ||
|   | 62a0d87795 | ||
|   | 8318633749 | ||
|   | a453f8aa2e | ||
|   | 54d2b90c25 | ||
|   | 7e1865984d | ||
|   | a2c56cc112 | ||
|   | 5c0ee8ca48 | ||
|   | 7397b2b82b | ||
|   | ddcbe21ce6 | ||
|   | 8fc7d1377d | ||
|   | 092403f362 | ||
|   | bb179922b9 | ||
|   | c29f912461 | ||
|   | 83d3e1cfe6 | ||
|   | 2914f0f65d | ||
|   | 99aa588ae7 | ||
|   | 0085e1f3ab | ||
|   | 53a9eb13f8 | ||
|   | b8c56c4dda | ||
|   | 59266b3190 | ||
|   | 0dc94547f5 | ||
|   | 29fc6de330 | ||
| ![greenkeeper[bot]](/assets/img/avatar_default.png)  | e24d0c40cd | ||
|   | e95845777a | ||
|   | 167648f61c | ||
|   | 9e6d6ff0dd | ||
|   | e659cc3d58 | ||
|   | ff6d45571a | ||
|   | 6cc9a2c945 | ||
|   | a873401bd7 | ||
|   | 6b19745241 | ||
|   | 982fae80aa | ||
|   | 77b15a3535 | ||
|   | 72754ede4e | ||
|   | b8ed8336e0 | ||
|   | 13f82856f9 | ||
|   | a62013f54d | ||
|   | 4c180869c6 | ||
|   | 7bbf022978 | ||
|   | 6b0d48423d | ||
|   | a617b8dbed | ||
|   | c57f472caf | ||
|   | e1ba19fd7e | ||
|   | 1bf8cbeb29 | ||
|   | f13faf2243 | ||
|   | 6cccd9d288 | ||
|   | be2cde106b | ||
|   | 17263fb459 | ||
|   | fed04ef5ae | ||
|   | 969b6dbcad | ||
|   | aa50d0ee11 | ||
|   | f09999ad5a | ||
|   | 35814faf8a | ||
|   | 8447a7fafa | ||
|   | c6e6c5e3ce | ||
|   | 85cbd8dd47 | ||
|   | bebc9003a3 | ||
|   | 3c081fbd65 | ||
|   | fdcf874306 | ||
|   | 6cbb741fa1 | ||
|   | 24129c1cb9 | ||
|   | f0938c36f5 | ||
|   | 484a6eda2e | ||
|   | 3f2ebffbe7 | ||
|   | ff278a7d8f | ||
|   | 844a3c3aff | ||
|   | 0db48993e9 | ||
|   | 81e21c4314 | ||
|   | ba0e57396d | ||
|   | 6a728d160a | ||
|   | 180e507bc8 | ||
|   | f3b7611ded | ||
|   | c344de5546 | ||
|   | 0bd0aa2bf7 | ||
|   | c786cbb3a1 | ||
|   | cd856f653d | ||
|   | d528c09da6 | ||
|   | 76b7ad006d | ||
|   | ff33e405a3 | ||
|   | f74de26d63 | ||
|   | 2c823798d8 | ||
|   | 381e261bbb | ||
|   | ba9bb5db6c | ||
|   | cd12bb33a5 | ||
|   | e333aee232 | ||
|   | 54571f60c3 | ||
|   | dd743aaeac | ||
|   | 22c76dc9f8 | ||
|   | 7c7e09cf64 | ||
|   | e5e3d69371 | ||
|   | 82a700b24e | ||
|   | 0579425a4f | ||
|   | 218e74569d | ||
|   | 448f54cf84 | ||
|   | c139e13049 | ||
|   | 65116fef32 | ||
|   | a0a35b7dca | ||
|   | 11fb8a24b7 | ||
|   | 512336685c | ||
|   | 484f281c19 | ||
|   | 2169bc5d3e | ||
|   | c653c84ad2 | ||
|   | 050f75aa60 | ||
|   | dae3f3552a | ||
|   | 8b09b170d6 | ||
|   | ec88f2ed8a | ||
|   | 607d8502ff | ||
|   | 2f084d7c15 | ||
|   | 5bf6e7d8f9 | ||
|   | 31cb9fbfaf | ||
|   | c7c48f3bea | ||
|   | 6732d22e6c | ||
|   | 04c6b7fe31 | ||
|   | 2687879dbd | ||
|   | 20a660fa89 | ||
|   | ba9781e1a8 | ||
|   | f65ac74914 | ||
|   | 6c33d9aeed | ||
|   | 68e86ad40d | ||
|   | 0aa4aa49a7 | ||
|   | 0ff3846e49 | ||
|   | bfb81299c3 | ||
|   | 0362a8e73c | ||
|   | f00f5cbed1 | ||
|   | c4e8cabae9 | ||
|   | 1729d05e8c | ||
|   | 770fb46ca7 | ||
|   | a3c4e54bc0 | ||
|   | b8a77fbada | ||
|   | 9182ebfc19 | ||
|   | 25c0cf5848 | ||
|   | a160dc0a4d | ||
|   | 28f1ca9c17 | ||
|   | 6399a0f046 | ||
|   | 639413608b | ||
|   | c14e4c7d22 | ||
|   | c74ac64237 | ||
|   | 4b3289ed99 | ||
|   | 0c432b39dc | ||
|   | c4b9276713 | ||
|   | df300c0663 | ||
|   | 518114cbbd | ||
|   | 999f0e4d58 | ||
|   | c2663529c1 | ||
|   | 9df74a02b6 | ||
|   | 71c9964e19 | ||
|   | ae2e47f6a9 | ||
|   | 1524d35f66 | ||
|   | 845be966a0 | ||
|   | 80818d79eb | ||
|   | cb9b3c00dd | ||
|   | b3997fb5df | ||
|   | 09dde6b78a | ||
|   | 3345d3ab35 | ||
|   | 366be7bbdd | ||
|   | 7008ea66f8 | ||
|   | 70f881e989 | ||
|   | 94d2355089 | ||
|   | dfbe48b25b | ||
|   | 931cb38b54 | ||
|   | e5fd34f94e | ||
|   | c638d7eb48 | ||
|   | 7e96384618 | ||
|   | 829cb99f5b | ||
|   | 1f93c99304 | ||
|   | dbb7c756cd | ||
|   | 13f381710c | ||
|   | 70897c0e9a | ||
|   | f51d1c5264 | ||
|   | 70d0937aab | ||
|   | 7d1ab6102f | ||
|   | 77ddd778be | ||
|   | 890ecb693f | ||
|   | 209fe7dcaf | ||
|   | e0d6f7c7c4 | ||
|   | 5d3fe9599b | ||
|   | 0fe0b6d254 | ||
|   | b794216eaf | ||
|   | 1fccde38f6 | ||
|   | 41bd436d3e | ||
|   | c66155ed48 | ||
|   | 627bd410fa | ||
|   | 41a3932c6b | ||
|   | 785b8d7846 | ||
|   | 622c8f9598 | ||
|   | ef978a6364 | ||
| ![greenkeeper[bot]](/assets/img/avatar_default.png)  | d95fbe1c6b | ||
|   | d4ffddc2ab | ||
|   | 3d497cedfc | ||
|   | e8de29ae79 | ||
|   | b622946844 | ||
|   | d013f78cc7 | ||
|   | 2afbafdb3b | ||
|   | 67148114a8 | ||
|   | 7903140ec2 | ||
|   | cefd296200 | ||
|   | 99d1c15851 | ||
|   | a3107ab26f | ||
|   | 854cfae75b | ||
|   | 36ab82957d | ||
|   | de9f54386c | ||
|   | 7f43820765 | ||
|   | 955e907e7f | ||
|   | 4c18022e7d | ||
|   | 509f59e46d | ||
|   | f14c372f5e | ||
|   | f028800a96 | ||
|   | 8a1ce7a4f3 | ||
|   | ea7a139ae0 | ||
|   | 63959eb3da | ||
|   | a6adbc4e56 | ||
|   | b418cb67ba | ||
|   | 0ccc360c0a | ||
|   | 1e0dda3c40 | ||
|   | 9197793bc8 | ||
|   | 29f62241bc | ||
|   | 8de1e91dec | ||
|   | de822a22d4 | ||
|   | f2cef456bd | ||
|   | 5d681d0fd6 | ||
|   | 2ed24ebd75 | ||
|   | 6e6824ecb0 | ||
|   | 0504a4f659 | ||
|   | 9a261755d2 | ||
|   | 8533663b26 | ||
|   | 0a4015b8a2 | ||
|   | dcfe56322e | ||
|   | d00a693026 | ||
|   | fb36ecad70 | ||
|   | 26c39768ca | ||
|   | df8abcfce8 | ||
|   | e3aab0e9e3 | ||
|   | e3dfc49ed0 | ||
|   | 8485284f63 | ||
|   | e549e19c03 | ||
|   | 2ace47cbb9 | ||
|   | dc184e7bc9 | ||
|   | aef1bd094b | ||
|   | 4f8b22f53b | ||
|   | 0f3cbafe91 | ||
|   | 16ad232c40 | ||
|   | 4d235a2be5 | ||
|   | aadf6fa9b1 | ||
|   | a72e9bc8b2 | ||
|   | f11ef93a81 | ||
|   | 9136556218 | ||
|   | 3ead008295 | ||
|   | 9ff5693442 | ||
|   | ac84b42394 | ||
|   | a79361c71f | ||
|   | 85e17d5dc7 | ||
|   | 45493fd093 | ||
|   | 6f987a2391 | ||
|   | ddf785a393 | ||
|   | b8e20fe717 | ||
|   | 82555bf9b6 | ||
|   | ffe6f6c168 | ||
|   | 6b11f5bb7d | ||
|   | 1a65d14864 | ||
|   | 6c1f1ffdb1 | ||
|   | 61cdbd5dd2 | ||
| ![greenkeeper[bot]](/assets/img/avatar_default.png)  | e7e321e2b3 | ||
|   | fb5f6fdc10 | ||
|   | 00290fbf75 | ||
|   | ff02dc723b | ||
|   | 67521c0d2a | ||
|   | da8765150b | ||
|   | ea7f51bc12 | ||
|   | 1b34b3b7e2 | ||
|   | bca4ceb7ae | ||
|   | 5648cd53d0 | ||
|   | 8dab37539f | ||
|   | 2dd42c0061 | ||
|   | dfafed504a | ||
|   | 9fcd2bcb0a | ||
|   | 4c701b91a6 | ||
|   | 84f7aa6d09 | ||
|   | 82f0c64dee | ||
|   | 4b7c6b124b | ||
|   | e043b678d4 | ||
|   | fef4f7fce8 | ||
|   | 9732b3521a | ||
|   | a59fcc4aec | ||
|   | 979e1e78fb | ||
|   | c1a929022f | ||
|   | 611bb81032 | ||
|   | 5047020e6d | ||
|   | fb74a6a689 | ||
|   | a14a216c8d | ||
|   | 549e212a59 | ||
|   | 1bdc91ad47 | ||
|   | 67f288479c | ||
|   | 496e45c2bb | ||
|   | e458bd3cc7 | ||
|   | 031911c463 | ||
|   | 4aa7f638f9 | ||
| ![greenkeeper[bot]](/assets/img/avatar_default.png)  | f6f4ea69ae | ||
|   | ef945597f2 | ||
| ![greenkeeper[bot]](/assets/img/avatar_default.png)  | 3ab4e1d368 | ||
| ![greenkeeper[bot]](/assets/img/avatar_default.png)  | c6216f5b5f | ||
|   | 4f24d58a79 | ||
|   | 73d6e7ba66 | ||
|   | 949707e18e | ||
|   | f51b299c17 | ||
|   | d2e0faa533 | ||
|   | 22015044a5 | ||
|   | 61f86dcb2b | ||
|   | 8f3bce6b11 | ||
|   | ee736e73a9 | ||
| ![greenkeeper[bot]](/assets/img/avatar_default.png)  | 99f867897e | ||
|   | c66c5b6e75 | ||
|   | f25ecc19b9 | ||
|   | 48e09970f3 | ||
|   | f05cb79604 | ||
|   | 46d3293edd | ||
|   | 9703d613cf | ||
|   | 704e217dbb | ||
|   | a103032d94 | ||
|   | c7207a4bd7 | ||
|   | 35c65fe589 | ||
|   | 6d5bd0c484 | ||
|   | cfbb6e8092 | ||
|   | feef4a933e | ||
|   | 468bc67569 | ||
|   | 0d517fa52f | ||
|   | d9054367c1 | ||
|   | 1213373027 | ||
|   | 100a525507 | ||
|   | 92ba64c35c | ||
|   | a8ee51ffd6 | ||
|   | 5538afc61d | 
| @@ -30,7 +30,7 @@ while : | ||||
|   touch patreon.cache && \ | ||||
|   rm patreon.cache && \ | ||||
|   cat patreon.raw.cache | \ | ||||
|   jq -r '(.data|map(select(.relationships.currently_entitled_tiers.data[]))|map(.relationships.user.data.id))as$data|.included|map(select(.attributes.hide_pledges==false))|map(select(.id as$id|$data|contains([$id])))|map(.attributes|[.full_name,.thumb_url,.url]|@tsv)|.[]|@text' >> patreon.cache && \ | ||||
|   jq -r '(.data|map(select(.relationships.currently_entitled_tiers.data[]))|map(.relationships.user.data.id))as$data|.included|map(select(.id as$id|$data|contains([$id])))|map(.attributes|[.full_name,.thumb_url,.url]|@tsv)|.[]|@text' >> patreon.cache && \ | ||||
|   echo '<table><tr>' >> patreon.md.cache && \ | ||||
|   cat patreon.cache | \ | ||||
|   awk -F'\t' '{print $2,$1}' | \ | ||||
|   | ||||
| @@ -164,3 +164,6 @@ drive: | ||||
| #  external: true | ||||
| #  engine: http://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-misskey-api.cgi?{{host}}+{{user}}+{{limit}}+{{offset}} | ||||
| #  timeout: 300000 | ||||
|  | ||||
| # Max allowed note text length in charactors | ||||
| maxNoteTextLength: 1000 | ||||
|   | ||||
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -16,3 +16,4 @@ api-docs.json | ||||
| /redis | ||||
| /mongo | ||||
| /elasticsearch | ||||
| *.code-workspace | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| FROM alpine:latest AS base | ||||
| FROM alpine:edge AS base | ||||
|  | ||||
| ENV NODE_ENV=production | ||||
|  | ||||
|   | ||||
| @@ -28,7 +28,7 @@ Please install and setup these softwares: | ||||
| ##### Optional | ||||
| * [Redis](https://redis.io/) | ||||
|   * Redis is optional, but we strongly recommended to install it | ||||
| * [Elasticsearch](https://www.elastic.co/) - used to provide searching feature instead of MongoDB | ||||
| * [Elasticsearch](https://www.elastic.co/) - required to enable the search feature | ||||
|  | ||||
| *3.* Setup MongoDB | ||||
| ---------------------------------------------------------------- | ||||
|   | ||||
| @@ -1,3 +1,6 @@ | ||||
| # **DO NOT edit locale files** except `ja-JP.yml`. | ||||
|  | ||||
| When you add text to the ja-JP file (of syuilo/misskey), it will automatically be applied to other language files. | ||||
| Translations added in ja-JP file should contain the original Japanese strings. | ||||
|  | ||||
| Please see [Contribution guide](../CONTRIBUTING.md) for more information. | ||||
|   | ||||
| @@ -25,6 +25,14 @@ common: | ||||
|   application-authorization: "アプリの連携" | ||||
|   close: "閉じる" | ||||
|   do-not-copy-paste: "ここにコードを入力したり張り付けたりしないでください。アカウントが不正利用される可能性があります。" | ||||
|   BSoD: | ||||
|     fatal-error: ":( 致命的な問題が発生しました。" | ||||
|     update-browser-os: "お使いのブラウザ(またはOS)のバージョンを更新すると解決する可能性があります。" | ||||
|     error-code: "エラーコード" | ||||
|     browser-version: "ブラウザ バージョン" | ||||
|     client-version: "クライアント バージョン" | ||||
|     email-support: "問題が解決しない場合は、上記の情報をお書き添えの上 syuilotan@yahoo.co.jp までご連絡ください。" | ||||
|     thanks: "Thank you for using Misskey." | ||||
|   got-it: "わかった" | ||||
|   customization-tips: | ||||
|     title: "カスタマイズのヒント" | ||||
| @@ -115,6 +123,12 @@ common: | ||||
|   reduce-motion: "UIの動きを減らす" | ||||
|   this-setting-is-this-device-only: "このデバイスのみ" | ||||
|   do-not-use-in-production: 'これは開発ビルドです。本番環境で使用しないでください。' | ||||
|   is-remote-user: "このユーザー情報はコピーです。" | ||||
|   is-remote-post: "この投稿情報はコピーです。" | ||||
|   view-on-remote: "正確な情報を見る" | ||||
|   error: | ||||
|     title: '問題が発生しました' | ||||
|     retry: 'やり直す' | ||||
|   reversi: | ||||
|     drawn: "引き分け" | ||||
|     my-turn: "あなたのターンです" | ||||
| @@ -170,6 +184,7 @@ common: | ||||
|     rename: "名前を変更" | ||||
|     stack-left: "左に重ねる" | ||||
|     pop-right: "右に出す" | ||||
|   dev: "アプリの作成に失敗しました。再度お試しください。" | ||||
| auth/views/form.vue: | ||||
|   share-access: "<i>{{ app.name }}</i>があなたのアカウントにアクセスすることを<b>許可</b>しますか?" | ||||
|   permission-ask: "このアプリは次の権限を要求しています:" | ||||
| @@ -416,6 +431,25 @@ common/views/components/visibility-chooser.vue: | ||||
| common/views/components/trends.vue: | ||||
|   count: "{}人が投稿" | ||||
|   empty: "トレンドなし" | ||||
| common/views/components/profile-editor.vue: | ||||
|   title: "プロフィール" | ||||
|   name: "名前" | ||||
|   account: "アカウント" | ||||
|   location: "場所" | ||||
|   description: "自己紹介" | ||||
|   birthday: "誕生日" | ||||
|   avatar: "アイコン" | ||||
|   banner: "バナー" | ||||
|   is-cat: "このアカウントはCatです" | ||||
|   is-bot: "このアカウントはBotです" | ||||
|   is-locked: "フォローを承認制にする" | ||||
|   careful-bot: "Botからのフォローだけ承認制にする" | ||||
|   advanced: "その他" | ||||
|   privacy: "プライバシー" | ||||
|   save: "保存" | ||||
|   saved: "プロフィールを保存しました" | ||||
|   uploading: "アップロード中" | ||||
|   upload-failed: "アップロードに失敗しました" | ||||
| common/views/widgets/broadcast.vue: | ||||
|   fetching: "確認中" | ||||
|   no-broadcasts: "お知らせはありません" | ||||
| @@ -640,7 +674,7 @@ desktop/views/components/note-detail.vue: | ||||
|   location: "位置情報" | ||||
|   renote: "Renote" | ||||
|   add-reaction: "リアクション" | ||||
| desktop/views/components/notes.note.vue: | ||||
| desktop/views/components/note.vue: | ||||
|   reposted-by: "{}がRenote" | ||||
|   reply: "返信" | ||||
|   renote: "Renote" | ||||
| @@ -726,8 +760,12 @@ desktop/views/components/settings.vue: | ||||
|   advanced: "詳細設定" | ||||
|   api-via-stream: "ストリームを経由したAPIリクエスト" | ||||
|   api-via-stream-desc: "この設定をオンにすると、websocket接続を経由してAPIリクエストが行われます(パフォーマンス向上が期待できます)。オフにすると、ネイティブの fetch APIが利用されます。この設定はこのデバイスのみ有効です。" | ||||
|   deck-nav: "デッキ内ナビゲーション" | ||||
|   deck-nav-desc: "デッキを使用しているとき、ナビゲーションが発生する際にページ遷移を行わずに一時的なカラムで受けるようにします。" | ||||
|   deck-default: "デッキをデフォルトのUIにする" | ||||
|   display: "デザインと表示" | ||||
|   customize: "ホームをカスタマイズ" | ||||
|   wallpaper: "壁紙" | ||||
|   choose-wallpaper: "壁紙を選択" | ||||
|   delete-wallpaper: "壁紙を削除" | ||||
|   dark-mode: "ダークモード" | ||||
| @@ -739,17 +777,19 @@ desktop/views/components/settings.vue: | ||||
|   suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する" | ||||
|   show-clock-on-header: "右上に時計を表示する" | ||||
|   show-reply-target: "リプライ先を表示する" | ||||
|   timeline: "タイムライン" | ||||
|   show-my-renotes: "自分の行ったRenoteをタイムラインに表示する" | ||||
|   show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する" | ||||
|   show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する" | ||||
|   show-maps: "マップの自動展開" | ||||
|   deck-column-align: "デッキのカラムの位置" | ||||
|   deck-column-align-center: "中央" | ||||
|   deck-column-align-left: "左" | ||||
|   sound: "サウンド" | ||||
|   enable-sounds: "サウンドを有効にする" | ||||
|   enable-sounds-desc: "投稿やメッセージを送受信したときなどにサウンドを再生します。この設定はブラウザに記憶されます。" | ||||
|   volume: "ボリューム" | ||||
|   test: "テスト" | ||||
|   mobile: "モバイル" | ||||
|   disable-via-mobile: "「モバイルからの投稿」フラグを付けない" | ||||
|   language: "言語" | ||||
|   pick-language: "言語を選択" | ||||
|   recommended: "推奨" | ||||
| @@ -828,21 +868,6 @@ desktop/views/components/settings.password.vue: | ||||
|   enter-new-password-again: "もう一度新しいパスワードを入力してください" | ||||
|   not-match: "新しいパスワードが一致しません" | ||||
|   changed: "パスワードを変更しました" | ||||
| desktop/views/components/settings.profile.vue: | ||||
|   avatar: "アイコン" | ||||
|   choice-avatar: "画像を選択" | ||||
|   name: "名前" | ||||
|   location: "場所" | ||||
|   description: "自己紹介" | ||||
|   birthday: "誕生日" | ||||
|   save: "保存" | ||||
|   locked-account: "アカウントの保護" | ||||
|   is-locked: "フォローを承認制にする" | ||||
|   careful-bot: "Botからのフォローだけ承認制にする" | ||||
|   other: "その他" | ||||
|   is-bot: "このアカウントはBotです" | ||||
|   is-cat: "このアカウントはCatです" | ||||
|   profile-updated: "プロフィールを更新しました" | ||||
| desktop/views/components/sub-note-content.vue: | ||||
|   private: "この投稿は非公開です" | ||||
|   deleted: "この投稿は削除されました" | ||||
| @@ -914,6 +939,8 @@ desktop/views/pages/admin/admin.vue: | ||||
|   drive: "ドライブ" | ||||
|   users: "ユーザー" | ||||
|   update: "更新" | ||||
|   announcements: "お知らせ" | ||||
|   hashtags: "ハッシュタグ" | ||||
| desktop/views/pages/admin/admin.dashboard.vue: | ||||
|   dashboard: "ダッシュボード" | ||||
|   all-users: "全てのユーザー" | ||||
| @@ -921,6 +948,9 @@ desktop/views/pages/admin/admin.dashboard.vue: | ||||
|   all-notes: "全ての投稿" | ||||
|   original-notes: "このインスタンスの投稿" | ||||
|   invite: "招待" | ||||
|   banner-url: "Banner URL" | ||||
|   disableRegistration: "Disable new user registration" | ||||
|   disableLocalTimeline: "Disable the local timeline" | ||||
| desktop/views/pages/admin/admin.suspend-user.vue: | ||||
|   suspend-user: "ユーザーの凍結" | ||||
|   suspend: "凍結" | ||||
| @@ -937,14 +967,23 @@ desktop/views/pages/admin/admin.unverify-user.vue: | ||||
|   unverify-user: "ユーザーの公式アカウント解除" | ||||
|   unverify: "公式アカウントを解除する" | ||||
|   unverified: "公式アカウントを解除しました" | ||||
| desktop/views/pages/admin/admin.announcements.vue: | ||||
|   announcements: "お知らせ" | ||||
| desktop/views/pages/admin/admin.hashtags.vue: | ||||
|   hided-tags: "Hidden Tags" | ||||
| desktop/views/pages/deck/deck.tl-column.vue: | ||||
|   is-media-only: "メディア投稿のみ" | ||||
|   is-media-view: "メディアビュー" | ||||
|   edit: "オプション" | ||||
| desktop/views/pages/deck/deck.note.vue: | ||||
|   reposted-by: "{}がRenote" | ||||
|   private: "この投稿は非公開です" | ||||
|   deleted: "この投稿は削除されました" | ||||
| desktop/views/pages/deck/deck.user-column.vue: | ||||
|   posts: "投稿" | ||||
|   following: "フォロー" | ||||
|   followers: "フォロワー" | ||||
|   images: "画像" | ||||
|   activity: "アクティビティ" | ||||
|   timeline: "タイムライン" | ||||
|   pinned-notes: "ピン留めされた投稿" | ||||
|   push-to-a-list: "リストに追加" | ||||
| desktop/views/pages/stats/stats.vue: | ||||
|   all-users: "全てのユーザー" | ||||
|   original-users: "このインスタンスのユーザー" | ||||
| @@ -997,9 +1036,6 @@ desktop/views/pages/user/user.friends.vue: | ||||
|   no-users: "よく話すユーザーはいません" | ||||
| desktop/views/pages/user/user.vue: | ||||
|   is-suspended: "このユーザーは凍結されています。" | ||||
|   is-remote: "このユーザーはリモートユーザーです。" | ||||
|   view-remote: "正確な情報を見る" | ||||
| desktop/views/pages/user/user.home.vue: | ||||
|   last-used-at: "最終アクセス" | ||||
| desktop/views/pages/user/user.photos.vue: | ||||
|   title: "フォト" | ||||
| @@ -1020,6 +1056,10 @@ desktop/views/pages/user/user.header.vue: | ||||
|   following: "フォロー" | ||||
|   followers: "フォロワー" | ||||
|   is-bot: "このアカウントはBotです" | ||||
|   years-old: "歳" | ||||
|   year: "年" | ||||
|   month: "月" | ||||
|   day: "日" | ||||
| desktop/views/pages/user/user.timeline.vue: | ||||
|   default: "投稿" | ||||
|   with-replies: "投稿と返信" | ||||
| @@ -1221,24 +1261,6 @@ mobile/views/pages/notifications.vue: | ||||
|   read-all: "すべての通知を既読にしますか?" | ||||
| mobile/views/pages/games/reversi.vue: | ||||
|   reversi: "リバーシ" | ||||
| mobile/views/pages/settings/settings.profile.vue: | ||||
|   title: "プロフィール" | ||||
|   name: "名前" | ||||
|   account: "アカウント" | ||||
|   location: "場所" | ||||
|   description: "自己紹介" | ||||
|   birthday: "誕生日" | ||||
|   avatar: "アイコン" | ||||
|   banner: "バナー" | ||||
|   is-cat: "このアカウントはCatです" | ||||
|   is-locked: "フォローを承認制にする" | ||||
|   careful-bot: "Botからのフォローだけ承認制にする" | ||||
|   advanced: "その他" | ||||
|   privacy: "プライバシー" | ||||
|   save: "保存" | ||||
|   saved: "プロフィールを保存しました" | ||||
|   uploading: "アップロード中" | ||||
|   upload-failed: "アップロードに失敗しました" | ||||
| mobile/views/pages/search.vue: | ||||
|   search: "検索" | ||||
|   empty: "「{}」に関する投稿は見つかりませんでした。" | ||||
| @@ -1294,6 +1316,7 @@ mobile/views/pages/settings.vue: | ||||
|   signout: "サインアウト" | ||||
|   sound: "サウンド" | ||||
|   enable-sounds: "サウンドを有効にする" | ||||
|   mark-as-read-all-unread-notes: "すべての投稿を既読にする" | ||||
| mobile/views/pages/user.vue: | ||||
|   follows-you: "フォローされています" | ||||
|   following: "フォロー" | ||||
| @@ -1303,8 +1326,6 @@ mobile/views/pages/user.vue: | ||||
|   timeline: "タイムライン" | ||||
|   media: "メディア" | ||||
|   is-suspended: "このユーザーは凍結されています。" | ||||
|   is-remote: "このユーザーはリモートユーザーです。" | ||||
|   view-remote: "正確な情報を見る" | ||||
| mobile/views/pages/user/home.vue: | ||||
|   recent-notes: "最近の投稿" | ||||
|   images: "画像" | ||||
| @@ -1350,3 +1371,29 @@ docs: | ||||
|       description: "説明" | ||||
| dev/views/index.vue: | ||||
|   manage-apps: "アプリの管理" | ||||
| dev/views/apps.vue: | ||||
|   manage-apps: "アプリを管理" | ||||
|   create-app: "アプリ作成" | ||||
|   app-missing: "アプリなし" | ||||
| dev/views/new-app.vue: | ||||
|   create-app: "アプリケーションの作成" | ||||
|   app-name: "アプリケーション名" | ||||
|   app-name-desc: "あなたのアプリの名称。" | ||||
|   app-name-ex: "ex) Misskey for iOS" | ||||
|   app-overview: "アプリの概要" | ||||
|   app-desc: "あなたのアプリの簡単な説明や紹介。" | ||||
|   app-desc-ex: "ex) Misskey iOSクライアント。" | ||||
|   callback-url: "コールバックURL (オプション)" | ||||
|   callback-url-desc: "ユーザーが認証フォームで認証した際にリダイレクトするURLを設定できます。" | ||||
|   authority: "権限" | ||||
|   authority-desc: "ここで要求した機能だけがAPIからアクセスできます。" | ||||
|   authority-warning: "アプリ作成後も変更できますが、新たな権限を付与する場合、その時点で関連付けられているユーザーキーはすべて無効になります。" | ||||
|   account-read: "アカウントの情報を見る。" | ||||
|   account-write: "アカウントの情報を操作する。" | ||||
|   note-write: "投稿する。" | ||||
|   reaction-write: "リアクションしたりリアクションをキャンセルする。" | ||||
|   following-write: "フォローしたりフォロー解除する。" | ||||
|   drive-read: "ドライブを見る。" | ||||
|   drive-write: "ドライブを操作する。" | ||||
|   notification-read: "通知を見る。" | ||||
|   notification-write: "通知を操作する。" | ||||
|   | ||||
| @@ -14,30 +14,38 @@ common: | ||||
|     rich-contents-desc: "自分の考え、話題の出来事、皆と共有したいことについて発信してください。必要であれば、様々な構文を使って投稿を装飾したり、好きな画像、動画などのファイルやアンケートを添付することもできます。" | ||||
|     reaction: "Reaktionen" | ||||
|     reaction-desc: "あなたの気持ちを伝える最も簡単な方法です。Misskeyは、他のユーザーの投稿に様々なリアクションを付けることができます。いちどMisskeyのリアクション機能を体験してしまうと、もう「いいね」の概念しか存在しないSNSには戻れなくなるかもしれません。" | ||||
|     ui: "インターフェース" | ||||
|     ui: "Benutzeroberfläche" | ||||
|     ui-desc: "どのようなUIが使いやすいかは人それぞれです。だから、Misskeyは自由度の高いUIを持っています。レイアウトやデザインを調整したり、カスタマイズ可能な様々なウィジェットを配置したりして、自分だけのホームを作ってください。" | ||||
|     drive: "ドライブ" | ||||
|     drive: "Drive" | ||||
|     drive-desc: "以前投稿したことのある画像をまた投稿したくなったことはありませんか?もしくは、アップロードしたファイルをフォルダ分けして整理したくなったことはありませんか?Misskeyの根幹に組み込まれたドライブ機能によってそれらが解決します。ファイルの共有も簡単です。" | ||||
|     outro: "他にもMisskeyにしかない機能はまだまだあるので、ぜひあなた自身の目で確かめてください。Misskeyは分散型SNSなので、このインスタンスが気に入らなければ他のインスタンスを試すこともできます。それでは、GLHF!" | ||||
|   adblock: | ||||
|     detected: "広告ブロッカーを無効にしてください" | ||||
|     detected: "Bitte deaktiviere den Werbeblocker." | ||||
|     warning: "<strong>Misskeyは広告を掲載していません</strong>が、広告をブロックする機能が有効だと一部の機能が利用できなかったり、不具合が発生する場合があります。" | ||||
|   application-authorization: "アプリの連携" | ||||
|   application-authorization: "Autorisierte Anwendungen" | ||||
|   close: "Schließen" | ||||
|   do-not-copy-paste: "ここにコードを入力したり張り付けたりしないでください。アカウントが不正利用される可能性があります。" | ||||
|   got-it: "わかった" | ||||
|   BSoD: | ||||
|     fatal-error: "Ein schwerwiegender Fehler ist aufgetreten :(" | ||||
|     update-browser-os: "お使いのブラウザ(またはOS)のバージョンを更新すると解決する可能性があります。" | ||||
|     error-code: "Fehlercode" | ||||
|     browser-version: "Browserversion" | ||||
|     client-version: "Clientversion" | ||||
|     email-support: "問題が解決しない場合は、上記の情報をお書き添えの上 syuilotan@yahoo.co.jp までご連絡ください。" | ||||
|     thanks: "Vielen Dank dass du Misskey verwendest." | ||||
|   got-it: "Verstanden!" | ||||
|   customization-tips: | ||||
|     title: "カスタマイズのヒント" | ||||
|     title: "Anpassung-Tipps" | ||||
|     paragraph1: "ホームのカスタマイズでは、ウィジェットを追加/削除したり、ドラッグ&ドロップして並べ替えたりすることができます。" | ||||
|     paragraph2: "一部のウィジェットは、<strong><strong>右</strong>クリック</strong>することで表示を変更することができます。" | ||||
|     paragraph3: "ウィジェットを削除するには、ヘッダーの<strong>「ゴミ箱」</strong>と書かれたエリアにウィジェットをドラッグ&ドロップします。" | ||||
|     paragraph4: "カスタマイズを終了するには、右上の「完了」をクリックします。" | ||||
|     gotit: "Got it!" | ||||
|     gotit: "Verstanden!" | ||||
|   notification: | ||||
|     file-uploaded: "Datei hochgeladen!" | ||||
|     message-from: "{}さんからメッセージ:" | ||||
|     message-from: "Nachricht von {}:" | ||||
|     reversi-invited: "対局への招待があります" | ||||
|     reversi-invited-by: "{}さんから" | ||||
|     reversi-invited-by: "Eingeladen von {}:" | ||||
|     notified-by: "Benachrichtigt von {}:" | ||||
|     reply-from: "Antwort von {}:" | ||||
|     quoted-by: "Zitiert von {}:" | ||||
| @@ -52,7 +60,7 @@ common: | ||||
|     weeks_ago: "vor {0} Woche{0:n}" | ||||
|     months_ago: "vor {0} Monat{0:en}" | ||||
|     years_ago: "vor {} Jahr{0:en}" | ||||
|   month-and-day: "{month}月 {day}日" | ||||
|   month-and-day: "{day}/{month}" | ||||
|   trash: "Papierkorb" | ||||
|   weekday-short: | ||||
|     sunday: "So" | ||||
| @@ -71,7 +79,7 @@ common: | ||||
|     friday: "Freitag" | ||||
|     saturday: "Samstag" | ||||
|   reactions: | ||||
|     like: "いいね" | ||||
|     like: "Gefällt mir" | ||||
|     love: "Lieben" | ||||
|     laugh: "Lachen" | ||||
|     hmm: "Hmm...?" | ||||
| @@ -83,13 +91,13 @@ common: | ||||
|     pudding: "Pudding" | ||||
|   note-visibility: | ||||
|     public: "Öffentlich" | ||||
|     home: "ホーム" | ||||
|     home-desc: "ホームタイムラインにのみ公開" | ||||
|     home: "Startseite" | ||||
|     home-desc: "Nur auf die Startseite posten" | ||||
|     followers: "Abonnenten" | ||||
|     followers-desc: "自分のフォロワーにのみ公開" | ||||
|     specified: "ダイレクト" | ||||
|     specified-desc: "指定したユーザーにのみ公開" | ||||
|     private: "非公開" | ||||
|     followers-desc: "Nur für diejenigen sichtbar, die dir folgen" | ||||
|     specified: "Direkt" | ||||
|     specified-desc: "Nur für bestimmte Benutzer posten" | ||||
|     private: "Privat" | ||||
|   note-placeholders: | ||||
|     a: "Was machst du gerade?" | ||||
|     b: "Was ist so passiert?" | ||||
| @@ -97,31 +105,37 @@ common: | ||||
|     d: "Willst du etwas sagen?" | ||||
|     e: "Schreib hier etwas!" | ||||
|     f: "Warte darauf, das du schreibst." | ||||
|   search: "検索" | ||||
|   search: "Suche" | ||||
|   delete: "Löschen" | ||||
|   loading: "Laden" | ||||
|   ok: "OK" | ||||
|   update-available-title: "更新があります" | ||||
|   update-available-title: "Aktualisierung verfügbar" | ||||
|   update-available: "Eine neue Version von Misskey ist verfügbar ({newer}, aktuell ist {current}). Lade die Seite neu um die aktuelle Version zu laden" | ||||
|   my-token-regenerated: "Dein Token wurde generiert. Du wirst jetzt abgemeldet." | ||||
|   i-like-sushi: "私は(プリンよりむしろ)寿司が好き" | ||||
|   i-like-sushi: "Ich bevorzuge Sushi anstelle von Pudding" | ||||
|   show-reversi-board-labels: "リバーシのボードの行と列のラベルを表示" | ||||
|   use-contrast-reversi-stones: "リバーシのアイコンにコントラストを付ける" | ||||
|   verified-user: "公式アカウント" | ||||
|   verified-user: "Verifizierter Benutzer" | ||||
|   disable-animated-mfm: "投稿内の動きのあるテキストを無効にする" | ||||
|   always-show-nsfw: "常に閲覧注意のメディアを表示する" | ||||
|   always-mark-nsfw: "常にメディアを閲覧注意として投稿" | ||||
|   show-full-acct: "ユーザー名のホストを省略しない" | ||||
|   reduce-motion: "UIの動きを減らす" | ||||
|   this-setting-is-this-device-only: "このデバイスのみ" | ||||
|   do-not-use-in-production: 'これは開発ビルドです。本番環境で使用しないでください。' | ||||
|   reduce-motion: "Animationen der Benutzeroberfläche reduzieren" | ||||
|   this-setting-is-this-device-only: "Nur auf diesem Gerät" | ||||
|   do-not-use-in-production: 'Dies ist eine Entwicklungsversion. Nicht in einer Produktionsumgebung verwenden.' | ||||
|   is-remote-user: "このユーザー情報はコピーです。" | ||||
|   is-remote-post: "この投稿情報はコピーです。" | ||||
|   view-on-remote: "正確な情報を見る" | ||||
|   error: | ||||
|     title: '問題が発生しました' | ||||
|     retry: 'Erneut versuchen' | ||||
|   reversi: | ||||
|     drawn: "引き分け" | ||||
|     my-turn: "あなたのターンです" | ||||
|     opponent-turn: "相手のターンです" | ||||
|     turn-of: "{}のターンです" | ||||
|     past-turn-of: "{}のターン" | ||||
|     won: "{}の勝ち" | ||||
|     drawn: "Unentschieden" | ||||
|     my-turn: "Du bist am Zug" | ||||
|     opponent-turn: "Dein Gegner ist an der Reihe" | ||||
|     turn-of: "{} ist am Zug" | ||||
|     past-turn-of: "Zug von {}" | ||||
|     won: "{} hat gewonnen!" | ||||
|     black: "Schwarz" | ||||
|     white: "Weiß" | ||||
|     total: "Gesamt" | ||||
| @@ -154,7 +168,7 @@ common: | ||||
|     widgets: "Widget hinzufügen:" | ||||
|     home: "Startseite" | ||||
|     local: "Lokal" | ||||
|     hybrid: "ソーシャル" | ||||
|     hybrid: "Sozial" | ||||
|     hashtag: "Hashtag" | ||||
|     global: "Global" | ||||
|     mentions: "Erwähnungen" | ||||
| @@ -169,31 +183,32 @@ common: | ||||
|     add-column: "Eine Spalte hinzufügen" | ||||
|     rename: "Umbenennen" | ||||
|     stack-left: "Nach links schichten" | ||||
|     pop-right: "右に出す" | ||||
|     pop-right: "Rechts andocken" | ||||
|   dev: "Fehler beim Erstellen der Applikation. Bitte versuche es erneut." | ||||
| auth/views/form.vue: | ||||
|   share-access: "<i>{{ app.name }}</i>があなたのアカウントにアクセスすることを<b>許可</b>しますか?" | ||||
|   permission-ask: "このアプリは次の権限を要求しています:" | ||||
|   account-read: "アカウントの情報を見る。" | ||||
|   account-write: "アカウントの情報を操作する。" | ||||
|   note-write: "投稿する。" | ||||
|   note-write: "Senden." | ||||
|   like-write: "いいねしたりいいね解除する。" | ||||
|   following-write: "フォローしたりフォロー解除する。" | ||||
|   drive-read: "ドライブを見る。" | ||||
|   drive-write: "ドライブを操作する。" | ||||
|   notification-read: "通知を見る。" | ||||
|   notification-write: "通知を操作する。" | ||||
|   notification-write: "Benachrichtigungen verwalten." | ||||
|   cancel: "Abbrechen" | ||||
|   accept: "Zugriff erlauben." | ||||
| auth/views/index.vue: | ||||
|   loading: "Lädt" | ||||
|   denied: "アプリケーションの連携をキャンセルしました。" | ||||
|   denied: "Autorisierung der Anwendung wurde verweigert." | ||||
|   denied-paragraph: "このアプリがあなたのアカウントにアクセスすることはありません。" | ||||
|   already-authorized: "このアプリは既に連携済みです" | ||||
|   allowed: "アプリケーションの連携を許可しました" | ||||
|   already-authorized: "Diese Anwendung ist bereits autorisiert." | ||||
|   allowed: "Autorisierung der Anwendung wurde erlaubt." | ||||
|   callback-url: "アプリケーションに戻っています" | ||||
|   please-go-back: "アプリケーションに戻って、やっていってください。" | ||||
|   error: "セッションが存在しません。" | ||||
|   sign-in: "サインインしてください" | ||||
|   please-go-back: "Bitte gehe zurück zur Anwendung." | ||||
|   error: "Sitzung ist nicht vorhanden." | ||||
|   sign-in: "Bitte melde dich an." | ||||
| common/views/components/games/reversi/reversi.vue: | ||||
|   matching: | ||||
|     waiting-for: "Warten auf {}" | ||||
| @@ -206,36 +221,36 @@ 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: "招待" | ||||
|   sub-title: "Spiele Reversi mit deinen Freunden!" | ||||
|   invite: "Einladen" | ||||
|   rule: "Spielanleitung" | ||||
|   rule-desc: "リバーシは、相手と交互に石をボードに置いて、相手の石を挟んで自分の色に変えてゆき、最終的に残った石が多い方が勝ちというボードゲームです。" | ||||
|   mode-invite: "Einladen" | ||||
|   mode-invite-desc: "指定したユーザーと対戦するモードです。" | ||||
|   invitations: "対局の招待があります!" | ||||
|   my-games: "自分の対局" | ||||
|   all-games: "みんなの対局" | ||||
|   enter-username: "ユーザー名を入力してください" | ||||
|   all-games: "Alle Spiele" | ||||
|   enter-username: "Bitte gib einen Benutzernamen ein" | ||||
|   game-state: | ||||
|     ended: "終了" | ||||
|     ended: "Fertig" | ||||
|     playing: "進行中" | ||||
| common/views/components/games/reversi/reversi.room.vue: | ||||
|   settings-of-the-game: "ゲームの設定" | ||||
|   choose-map: "マップを選択" | ||||
|   random: "ランダム" | ||||
|   black-or-white: "先手/後手" | ||||
|   black-is: "{}が黒" | ||||
|   rules: "ルール" | ||||
|   settings-of-the-game: "Spieleinstellungen" | ||||
|   choose-map: "Wähle eine Karte" | ||||
|   random: "Zufällige Auswahl" | ||||
|   black-or-white: "Schwarz/Weiß" | ||||
|   black-is: "Schwarz ist {}" | ||||
|   rules: "Regeln" | ||||
|   is-llotheo: "石の少ない方が勝ち(ロセオ)" | ||||
|   looped-map: "ループマップ" | ||||
|   can-put-everywhere: "どこでも置けるモード" | ||||
|   settings-of-the-bot: "Botの設定" | ||||
|   this-game-is-started-soon: "ゲームは数秒後に開始されます" | ||||
|   waiting-for-other: "相手の準備が完了するのを待っています" | ||||
|   waiting-for-other: "Warte auf den Gegner" | ||||
|   waiting-for-me: "あなたの準備が完了するのを待っています" | ||||
|   waiting-for-both: "準備中" | ||||
|   cancel: "キャンセル" | ||||
|   ready: "準備完了" | ||||
|   cancel: "Abbrechen" | ||||
|   ready: "Bereit" | ||||
|   cancel-ready: "準備続行" | ||||
| common/views/components/connect-failed.vue: | ||||
|   title: "Verbindung zum Server ist fehlgeschlagen" | ||||
| @@ -262,29 +277,29 @@ common/views/components/connect-failed.troubleshooter.vue: | ||||
|   flush: "Cache leeren" | ||||
|   set-version: "Version angeben" | ||||
| common/views/components/media-banner.vue: | ||||
|   sensitive: "閲覧注意" | ||||
|   click-to-show: "クリックして表示" | ||||
|   sensitive: "Dieser Inhalt ist NSFW" | ||||
|   click-to-show: "Klicke zum den Inhalt anzusehen" | ||||
| common/views/components/theme.vue: | ||||
|   light-theme: "非ダークモード時に使用するテーマ" | ||||
|   dark-theme: "ダークモード時に使用するテーマ" | ||||
|   light-themes: "明るいテーマ" | ||||
|   dark-themes: "暗いテーマ" | ||||
|   light-theme: "Thema" | ||||
|   dark-theme: "Thema während des Nachtmodus" | ||||
|   light-themes: "Helles Thema" | ||||
|   dark-themes: "Dunkles Thema" | ||||
|   install-a-theme: "テーマのインストール" | ||||
|   theme-code: "テーマコード" | ||||
|   install: "インストール" | ||||
|   installed: "「{}」をインストールしました" | ||||
|   create-a-theme: "テーマの作成" | ||||
|   save-created-theme: "テーマを保存" | ||||
|   primary-color: "プライマリ カラー" | ||||
|   secondary-color: "セカンダリ カラー" | ||||
|   text-color: "文字色" | ||||
|   base-theme: "ベーステーマ" | ||||
|   base-theme-light: "Light" | ||||
|   base-theme-dark: "Dark" | ||||
|   theme-name: "テーマ名" | ||||
|   preview-created-theme: "プレビュー" | ||||
|   invalid-theme: "テーマが正しくありません。" | ||||
|   already-installed: "既にそのテーマはインストールされています。" | ||||
|   install: "Anwenden" | ||||
|   installed: "\"{}\" wurde installiert" | ||||
|   create-a-theme: "Thema erstellen" | ||||
|   save-created-theme: "Thema speichern" | ||||
|   primary-color: "Primäre Farbe" | ||||
|   secondary-color: "Sekundäre Farbe" | ||||
|   text-color: "Textfarbe" | ||||
|   base-theme: "Basisthema" | ||||
|   base-theme-light: "Hell" | ||||
|   base-theme-dark: "Dunkel" | ||||
|   theme-name: "Name des Themas" | ||||
|   preview-created-theme: "Vorschau" | ||||
|   invalid-theme: "Thema ist ungültig" | ||||
|   already-installed: "Thema ist bereits installiert" | ||||
|   saved: "保存しました" | ||||
|   manage-themes: "テーマの管理" | ||||
|   builtin-themes: "標準テーマ" | ||||
| @@ -293,10 +308,10 @@ common/views/components/theme.vue: | ||||
|   select-theme: "テーマを選択してください" | ||||
|   uninstall: "アンインストール" | ||||
|   uninstalled: "「{}」をアンインストールしました" | ||||
|   author: "作者" | ||||
|   author: "Autor" | ||||
|   desc: "説明" | ||||
|   export: "エクスポート" | ||||
|   import: "インポート" | ||||
|   export: "Exportieren" | ||||
|   import: "Importieren" | ||||
|   import-by-code: "またはコードをペースト" | ||||
|   theme-name-required: "テーマ名は必須です。" | ||||
| common/views/components/cw-button.vue: | ||||
| @@ -334,8 +349,8 @@ common/views/components/nav.vue: | ||||
| common/views/components/note-menu.vue: | ||||
|   detail: "詳細" | ||||
|   copy-link: "リンクをコピー" | ||||
|   favorite: "Diese Anmerkung favorisieren" | ||||
|   unfavorite: "お気に入り解除" | ||||
|   favorite: "Diese Notiz favorisieren" | ||||
|   unfavorite: "Aus Favoriten entfernen" | ||||
|   pin: "An die Profilseite pinnen" | ||||
|   unpin: "ピン留め解除" | ||||
|   delete: "Löschen" | ||||
| @@ -362,7 +377,7 @@ common/views/components/signin.vue: | ||||
|   token: "Token" | ||||
|   signing-in: "Melde an..." | ||||
|   signin: "Anmelden" | ||||
|   or: "または" | ||||
|   or: "Oder" | ||||
|   signin-with-twitter: "Twitterでログイン" | ||||
|   login-failed: "ログインできませんでした。ユーザー名とパスワードを確認してください。" | ||||
| common/views/components/signup.vue: | ||||
| @@ -416,6 +431,25 @@ common/views/components/visibility-chooser.vue: | ||||
| common/views/components/trends.vue: | ||||
|   count: "{}人が投稿" | ||||
|   empty: "トレンドなし" | ||||
| common/views/components/profile-editor.vue: | ||||
|   title: "プロフィール" | ||||
|   name: "名前" | ||||
|   account: "アカウント" | ||||
|   location: "場所" | ||||
|   description: "自己紹介" | ||||
|   birthday: "誕生日" | ||||
|   avatar: "アイコン" | ||||
|   banner: "バナー" | ||||
|   is-cat: "このアカウントはCatです" | ||||
|   is-bot: "このアカウントはBotです" | ||||
|   is-locked: "フォローを承認制にする" | ||||
|   careful-bot: "Botからのフォローだけ承認制にする" | ||||
|   advanced: "その他" | ||||
|   privacy: "プライバシー" | ||||
|   save: "保存" | ||||
|   saved: "プロフィールを保存しました" | ||||
|   uploading: "アップロード中" | ||||
|   upload-failed: "アップロードに失敗しました" | ||||
| common/views/widgets/broadcast.vue: | ||||
|   fetching: "Laden" | ||||
|   no-broadcasts: "Keine Broadcasts" | ||||
| @@ -510,7 +544,7 @@ desktop/views/components/charts.vue: | ||||
|   notes: "投稿" | ||||
|   users: "ユーザー" | ||||
|   drive: "ドライブ" | ||||
|   network: "ネットワーク" | ||||
|   network: "Netzwerk" | ||||
|   charts: | ||||
|     notes: "投稿の増減 (統合)" | ||||
|     local-notes: "投稿の増減 (ローカル)" | ||||
| @@ -522,9 +556,9 @@ desktop/views/components/charts.vue: | ||||
|     drive-total: "ドライブ使用量の積算" | ||||
|     drive-files: "ドライブのファイル数の増減" | ||||
|     drive-files-total: "ドライブのファイル数の積算" | ||||
|     network-requests: "リクエスト" | ||||
|     network-time: "応答時間" | ||||
|     network-usage: "通信量" | ||||
|     network-requests: "Anfragen" | ||||
|     network-time: "Antwortzeit" | ||||
|     network-usage: "Datenverkehr" | ||||
| desktop/views/components/choose-file-from-drive-window.vue: | ||||
|   choose-file: "Datei auswählen" | ||||
|   upload: "Dateien von deinem PC hochladen" | ||||
| @@ -558,7 +592,7 @@ desktop/views/components/drive.file.vue: | ||||
|     open-in-app: "In der App öffnen" | ||||
|     add-app: "App hinzufügen" | ||||
|     rename-file: "Datei umbennen" | ||||
|     input-new-file-name: "Geben Sie den neuen Dateinamen an" | ||||
|     input-new-file-name: "Gib den neuen Dateinamen an" | ||||
|     copied: "Kopieren erfolgreich" | ||||
|     copied-url-to-clipboard: "URL wurde in die Zwischenablage kopiert" | ||||
| desktop/views/components/drive.folder.vue: | ||||
| @@ -640,25 +674,25 @@ desktop/views/components/note-detail.vue: | ||||
|   location: "Ort" | ||||
|   renote: "Anmerkung" | ||||
|   add-reaction: "Reaktion hinzufügen" | ||||
| desktop/views/components/notes.note.vue: | ||||
|   reposted-by: "Auch geteilt von" | ||||
|   reply: "Antworten" | ||||
|   renote: "Anmerken" | ||||
|   add-reaction: "Eine Reaktion hinzufügen" | ||||
|   detail: "Zeige Details" | ||||
|   private: "Dieser Beitrag ist eine privat" | ||||
|   deleted: "Dieser Beitrag wurde entfernt" | ||||
| desktop/views/components/note.vue: | ||||
|   reposted-by: "{}がRenote" | ||||
|   reply: "返信" | ||||
|   renote: "Renote" | ||||
|   add-reaction: "リアクション" | ||||
|   detail: "詳細" | ||||
|   private: "この投稿は非公開です" | ||||
|   deleted: "この投稿は削除されました" | ||||
| desktop/views/components/notes.vue: | ||||
|   error: "Laden fehlgeschlagen." | ||||
|   retry: "Erneut versuchen" | ||||
|   load-more: "もっと読み込む" | ||||
|   load-more: "Mehr laden" | ||||
| desktop/views/components/notifications.vue: | ||||
|   more: "Mehr" | ||||
|   empty: "Keine Benachrichtigungen" | ||||
| desktop/views/components/post-form.vue: | ||||
|   add-visible-user: "+ユーザーを追加" | ||||
|   add-visible-user: "+Nutzer hinzufügen" | ||||
|   attach-location-information: "位置情報を添付する" | ||||
|   hide-contents: "内容を隠す" | ||||
|   hide-contents: "Inhalt verstecken" | ||||
|   reply-placeholder: "Antworte auf diese Anmerkung..." | ||||
|   quote-placeholder: "Zitiere diese Anmerkung..." | ||||
|   submit: "Beitragsform" | ||||
| @@ -679,10 +713,10 @@ desktop/views/components/post-form.vue: | ||||
|   text-remain: "{} Zeichen verbleibend" | ||||
|   recent-tags: "最近" | ||||
|   click-to-tagging: "クリックでタグ付け" | ||||
|   visibility: "公開範囲" | ||||
|   visibility: "Sichtbarkeit" | ||||
|   geolocation-alert: "お使いの端末は位置情報に対応していません" | ||||
|   error: "エラー" | ||||
|   enter-username: "ユーザー名を入力してください" | ||||
|   error: "Fehler" | ||||
|   enter-username: "Bitte gib einen Benutzernamen ein..." | ||||
|   annotations: "内容への注釈 (オプション)" | ||||
| desktop/views/components/post-form-window.vue: | ||||
|   note: "Neue Notiz" | ||||
| @@ -726,30 +760,36 @@ desktop/views/components/settings.vue: | ||||
|   advanced: "Erweiterte Einstellungen" | ||||
|   api-via-stream: "API-Anfrage via stream" | ||||
|   api-via-stream-desc: "API-Anfrage über WebSocket statt native Aktualisierungs-API (für bessere Leistung). Diese Einstellung wird im Browser gespeichert." | ||||
|   deck-nav: "デッキ内ナビゲーション" | ||||
|   deck-nav-desc: "デッキを使用しているとき、ナビゲーションが発生する際にページ遷移を行わずに一時的なカラムで受けるようにします。" | ||||
|   deck-default: "デッキをデフォルトのUIにする" | ||||
|   display: "Erscheinungsbild und Anzeige" | ||||
|   customize: "Startseite anpassen" | ||||
|   wallpaper: "壁紙" | ||||
|   choose-wallpaper: "壁紙を選択" | ||||
|   delete-wallpaper: "壁紙を削除" | ||||
|   dark-mode: "Nacht Modus" | ||||
|   use-shadow: "UIに影を使用" | ||||
|   rounded-corners: "UIの角を丸める" | ||||
|   rounded-corners: "Abgerundete Ecken" | ||||
|   circle-icons: "Kreisförmige Icons" | ||||
|   contrasted-acct: "ユーザー名にコントラストを付ける" | ||||
|   post-form-on-timeline: "タイムライン上部に投稿フォームを表示する" | ||||
|   suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する" | ||||
|   show-clock-on-header: "右上に時計を表示する" | ||||
|   show-reply-target: "Zeige Antworten" | ||||
|   timeline: "タイムライン" | ||||
|   show-my-renotes: "Zeige meine Reposts auf der Zeitleiste" | ||||
|   show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する" | ||||
|   show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する" | ||||
|   show-maps: "Karte anzeigen" | ||||
|   deck-column-align: "デッキのカラムの位置" | ||||
|   deck-column-align-center: "中央" | ||||
|   deck-column-align-left: "左" | ||||
|   sound: "Ton" | ||||
|   enable-sounds: "Ton aktivieren" | ||||
|   enable-sounds-desc: "Spiel einen Ton ab beim Erhalten eines Beitrags bzw. einer Nachricht. Diese Einstellung wird im Browser gespeichert." | ||||
|   volume: "Lautstärke" | ||||
|   test: "Test" | ||||
|   mobile: "Mobil" | ||||
|   disable-via-mobile: "Diesen Beitrag nicht mit 'vom Handy' absenden" | ||||
|   language: "Sprache" | ||||
|   pick-language: "Sprache auswählen" | ||||
|   recommended: "Empfohlen" | ||||
| @@ -822,27 +862,12 @@ desktop/views/components/settings.drive.vue: | ||||
| desktop/views/components/settings.mute.vue: | ||||
|   no-users: "ミュートしているユーザーはいません" | ||||
| desktop/views/components/settings.password.vue: | ||||
|   reset: "パスワードを変更する" | ||||
|   reset: "Passwort ändern" | ||||
|   enter-current-password: "Derzeitiges Passwort eingeben" | ||||
|   enter-new-password: "Neues Passwort eingeben" | ||||
|   enter-new-password-again: "Neues Passwort erneut eingeben" | ||||
|   not-match: "新しいパスワードが一致しません" | ||||
|   changed: "パスワードを変更しました" | ||||
| desktop/views/components/settings.profile.vue: | ||||
|   avatar: "アイコン" | ||||
|   choice-avatar: "画像を選択" | ||||
|   name: "名前" | ||||
|   location: "場所" | ||||
|   description: "自己紹介" | ||||
|   birthday: "誕生日" | ||||
|   save: "Profil aktualisieren" | ||||
|   locked-account: "アカウントの保護" | ||||
|   is-locked: "フォローを承認制にする" | ||||
|   careful-bot: "Botからのフォローだけ承認制にする" | ||||
|   other: "その他" | ||||
|   is-bot: "このアカウントはBotです" | ||||
|   is-cat: "このアカウントはCatです" | ||||
|   profile-updated: "プロフィールを更新しました" | ||||
|   not-match: "Passwörter stimmen nicht überein." | ||||
|   changed: "Passwort geändert" | ||||
| desktop/views/components/sub-note-content.vue: | ||||
|   private: "この投稿は非公開です" | ||||
|   deleted: "この投稿は削除されました" | ||||
| @@ -902,7 +927,7 @@ desktop/views/components/user-preview.vue: | ||||
| desktop/views/components/users-list.vue: | ||||
|   all: "すべて" | ||||
|   iknow: "知り合い" | ||||
|   load-more: "もっと" | ||||
|   load-more: "Mehr" | ||||
|   fetching: "Lade…" | ||||
| desktop/views/components/users-list-item.vue: | ||||
|   followed: "フォローされています" | ||||
| @@ -914,6 +939,8 @@ desktop/views/pages/admin/admin.vue: | ||||
|   drive: "ドライブ" | ||||
|   users: "ユーザー" | ||||
|   update: "更新" | ||||
|   announcements: "お知らせ" | ||||
|   hashtags: "ハッシュタグ" | ||||
| desktop/views/pages/admin/admin.dashboard.vue: | ||||
|   dashboard: "ダッシュボード" | ||||
|   all-users: "全てのユーザー" | ||||
| @@ -921,6 +948,9 @@ desktop/views/pages/admin/admin.dashboard.vue: | ||||
|   all-notes: "全ての投稿" | ||||
|   original-notes: "このインスタンスの投稿" | ||||
|   invite: "招待" | ||||
|   banner-url: "Banner URL" | ||||
|   disableRegistration: "Disable new user registration" | ||||
|   disableLocalTimeline: "Disable the local timeline" | ||||
| desktop/views/pages/admin/admin.suspend-user.vue: | ||||
|   suspend-user: "ユーザーの凍結" | ||||
|   suspend: "凍結" | ||||
| @@ -937,14 +967,23 @@ desktop/views/pages/admin/admin.unverify-user.vue: | ||||
|   unverify-user: "ユーザーの公式アカウント解除" | ||||
|   unverify: "公式アカウントを解除する" | ||||
|   unverified: "公式アカウントを解除しました" | ||||
| desktop/views/pages/admin/admin.announcements.vue: | ||||
|   announcements: "お知らせ" | ||||
| desktop/views/pages/admin/admin.hashtags.vue: | ||||
|   hided-tags: "Hidden Tags" | ||||
| desktop/views/pages/deck/deck.tl-column.vue: | ||||
|   is-media-only: "メディア投稿のみ" | ||||
|   is-media-view: "メディアビュー" | ||||
|   edit: "オプション" | ||||
| desktop/views/pages/deck/deck.note.vue: | ||||
|   reposted-by: "{}がRenote" | ||||
|   private: "この投稿は非公開です" | ||||
|   deleted: "この投稿は削除されました" | ||||
| desktop/views/pages/deck/deck.user-column.vue: | ||||
|   posts: "投稿" | ||||
|   following: "フォロー" | ||||
|   followers: "フォロワー" | ||||
|   images: "画像" | ||||
|   activity: "アクティビティ" | ||||
|   timeline: "タイムライン" | ||||
|   pinned-notes: "ピン留めされた投稿" | ||||
|   push-to-a-list: "リストに追加" | ||||
| desktop/views/pages/stats/stats.vue: | ||||
|   all-users: "全てのユーザー" | ||||
|   original-users: "このインスタンスのユーザー" | ||||
| @@ -997,9 +1036,6 @@ desktop/views/pages/user/user.friends.vue: | ||||
|   no-users: "よく話すユーザーはいません" | ||||
| desktop/views/pages/user/user.vue: | ||||
|   is-suspended: "このユーザーは凍結されています。" | ||||
|   is-remote: "このユーザーはリモートユーザーです。" | ||||
|   view-remote: "正確な情報を見る" | ||||
| desktop/views/pages/user/user.home.vue: | ||||
|   last-used-at: "最終アクセス" | ||||
| desktop/views/pages/user/user.photos.vue: | ||||
|   title: "フォト" | ||||
| @@ -1020,6 +1056,10 @@ desktop/views/pages/user/user.header.vue: | ||||
|   following: "フォロー" | ||||
|   followers: "フォロワー" | ||||
|   is-bot: "このアカウントはBotです" | ||||
|   years-old: "歳" | ||||
|   year: "年" | ||||
|   month: "月" | ||||
|   day: "日" | ||||
| desktop/views/pages/user/user.timeline.vue: | ||||
|   default: "投稿" | ||||
|   with-replies: "投稿と返信" | ||||
| @@ -1165,19 +1205,19 @@ mobile/views/components/ui.nav.vue: | ||||
| mobile/views/components/user-timeline.vue: | ||||
|   no-notes: "このユーザーは投稿していないようです。" | ||||
|   no-notes-with-media: "メディア付き投稿はありません。" | ||||
|   load-more: "もっと" | ||||
|   load-more: "Mehr" | ||||
| mobile/views/components/users-list.vue: | ||||
|   all: "すべて" | ||||
|   known: "知り合い" | ||||
|   load-more: "もっと" | ||||
|   load-more: "Mehr" | ||||
| mobile/views/pages/favorites.vue: | ||||
|   title: "お気に入り" | ||||
|   title: "Favoriten" | ||||
| mobile/views/pages/user-lists.vue: | ||||
|   title: "リスト" | ||||
|   enter-list-name: "リスト名を入力してください" | ||||
| mobile/views/pages/drive.vue: | ||||
|   drive: "ドライブ" | ||||
|   more: "もっと見る" | ||||
|   more: "Mehr laden" | ||||
| mobile/views/pages/signup.vue: | ||||
|   lets-start: "📦 始めましょう" | ||||
| mobile/views/pages/followers.vue: | ||||
| @@ -1221,24 +1261,6 @@ mobile/views/pages/notifications.vue: | ||||
|   read-all: "すべての通知を既読にしますか?" | ||||
| mobile/views/pages/games/reversi.vue: | ||||
|   reversi: "リバーシ" | ||||
| mobile/views/pages/settings/settings.profile.vue: | ||||
|   title: "Profil" | ||||
|   name: "名前" | ||||
|   account: "アカウント" | ||||
|   location: "場所" | ||||
|   description: "自己紹介" | ||||
|   birthday: "誕生日" | ||||
|   avatar: "アイコン" | ||||
|   banner: "バナー" | ||||
|   is-cat: "このアカウントはCatです" | ||||
|   is-locked: "フォローを承認制にする" | ||||
|   careful-bot: "Botからのフォローだけ承認制にする" | ||||
|   advanced: "その他" | ||||
|   privacy: "プライバシー" | ||||
|   save: "保存" | ||||
|   saved: "Profil wurde aktualisiert" | ||||
|   uploading: "アップロード中" | ||||
|   upload-failed: "アップロードに失敗しました" | ||||
| mobile/views/pages/search.vue: | ||||
|   search: "検索" | ||||
|   empty: "「{}」に関する投稿は見つかりませんでした。" | ||||
| @@ -1294,6 +1316,7 @@ mobile/views/pages/settings.vue: | ||||
|   signout: "サインアウト" | ||||
|   sound: "サウンド" | ||||
|   enable-sounds: "サウンドを有効にする" | ||||
|   mark-as-read-all-unread-notes: "すべての投稿を既読にする" | ||||
| mobile/views/pages/user.vue: | ||||
|   follows-you: "フォローされています" | ||||
|   following: "フォロー" | ||||
| @@ -1303,13 +1326,11 @@ mobile/views/pages/user.vue: | ||||
|   timeline: "タイムライン" | ||||
|   media: "メディア" | ||||
|   is-suspended: "このユーザーは凍結されています。" | ||||
|   is-remote: "このユーザーはリモートユーザーです。" | ||||
|   view-remote: "正確な情報を見る" | ||||
| mobile/views/pages/user/home.vue: | ||||
|   recent-notes: "最近の投稿" | ||||
|   images: "画像" | ||||
|   activity: "アクティビティ" | ||||
|   keywords: "キーワード" | ||||
|   keywords: "Schlagwörter" | ||||
|   domains: "頻出ドメイン" | ||||
|   frequently-replied-users: "よく会話するユーザー" | ||||
|   followers-you-know: "知り合いのフォロワー" | ||||
| @@ -1350,3 +1371,29 @@ docs: | ||||
|       description: "説明" | ||||
| dev/views/index.vue: | ||||
|   manage-apps: "アプリの管理" | ||||
| dev/views/apps.vue: | ||||
|   manage-apps: "アプリを管理" | ||||
|   create-app: "アプリ作成" | ||||
|   app-missing: "アプリなし" | ||||
| dev/views/new-app.vue: | ||||
|   create-app: "アプリケーションの作成" | ||||
|   app-name: "アプリケーション名" | ||||
|   app-name-desc: "あなたのアプリの名称。" | ||||
|   app-name-ex: "ex) Misskey for iOS" | ||||
|   app-overview: "アプリの概要" | ||||
|   app-desc: "あなたのアプリの簡単な説明や紹介。" | ||||
|   app-desc-ex: "ex) Misskey iOSクライアント。" | ||||
|   callback-url: "コールバックURL (オプション)" | ||||
|   callback-url-desc: "ユーザーが認証フォームで認証した際にリダイレクトするURLを設定できます。" | ||||
|   authority: "権限" | ||||
|   authority-desc: "ここで要求した機能だけがAPIからアクセスできます。" | ||||
|   authority-warning: "アプリ作成後も変更できますが、新たな権限を付与する場合、その時点で関連付けられているユーザーキーはすべて無効になります。" | ||||
|   account-read: "アカウントの情報を見る。" | ||||
|   account-write: "アカウントの情報を操作する。" | ||||
|   note-write: "投稿する。" | ||||
|   reaction-write: "リアクションしたりリアクションをキャンセルする。" | ||||
|   following-write: "フォローしたりフォロー解除する。" | ||||
|   drive-read: "ドライブを見る。" | ||||
|   drive-write: "ドライブを操作する。" | ||||
|   notification-read: "通知を見る。" | ||||
|   notification-write: "通知を操作する。" | ||||
|   | ||||
| @@ -25,6 +25,14 @@ common: | ||||
|   application-authorization: "Application authorizations" | ||||
|   close: "Close" | ||||
|   do-not-copy-paste: "Please do not enter or paste the code here. Account may be compromised." | ||||
|   BSoD: | ||||
|     fatal-error: "A fatal error has occurred :(" | ||||
|     update-browser-os: "You might resolve to update the version of your browser (or OS)." | ||||
|     error-code: "Error code" | ||||
|     browser-version: "Browser version" | ||||
|     client-version: "Client version" | ||||
|     email-support: "If the problem persists, contact syuilotan@yahoo.co.jp please on the above information." | ||||
|     thanks: "Thank you for using Misskey." | ||||
|   got-it: "Got it!" | ||||
|   customization-tips: | ||||
|     title: "Customization tips" | ||||
| @@ -110,11 +118,17 @@ common: | ||||
|   verified-user: "Verified account" | ||||
|   disable-animated-mfm: "Disable animated texts in a post" | ||||
|   always-show-nsfw: "Always show NSFW contents" | ||||
|   always-mark-nsfw: "Always post with a warning about media attachment" | ||||
|   always-mark-nsfw: "Always mark posts with media attachments as NSFW" | ||||
|   show-full-acct: "Do not omit the hostname from the username" | ||||
|   reduce-motion: "Reduce motion in UI" | ||||
|   this-setting-is-this-device-only: "Only for this device" | ||||
|   do-not-use-in-production: 'As this is for development, do not use this in production.' | ||||
|   is-remote-user: "This user information is copied." | ||||
|   is-remote-post: "This post information is a copy." | ||||
|   view-on-remote: "View it on remote" | ||||
|   error: | ||||
|     title: 'Something happened :(' | ||||
|     retry: 'Retry' | ||||
|   reversi: | ||||
|     drawn: "Draw" | ||||
|     my-turn: "Your turn" | ||||
| @@ -170,6 +184,7 @@ common: | ||||
|     rename: "Rename" | ||||
|     stack-left: "Stack to the left" | ||||
|     pop-right: "Dock on the right" | ||||
|   dev: "Failed to create the application. Please try again." | ||||
| auth/views/form.vue: | ||||
|   share-access: "Would you <b>allow</b> <i>{{ app.name }}</i> to access your account?" | ||||
|   permission-ask: "This application requires the following permissions:" | ||||
| @@ -265,7 +280,7 @@ common/views/components/media-banner.vue: | ||||
|   sensitive: "NSFW" | ||||
|   click-to-show: "Click to show" | ||||
| common/views/components/theme.vue: | ||||
|   light-theme: "Theme during non-dark mode" | ||||
|   light-theme: "Theme" | ||||
|   dark-theme: "Theme during dark mode" | ||||
|   light-themes: "Light theme" | ||||
|   dark-themes: "Dark theme" | ||||
| @@ -416,6 +431,25 @@ common/views/components/visibility-chooser.vue: | ||||
| common/views/components/trends.vue: | ||||
|   count: "{} users mentioned" | ||||
|   empty: "No popular hashtag trends" | ||||
| common/views/components/profile-editor.vue: | ||||
|   title: "Profile" | ||||
|   name: "Name" | ||||
|   account: "Account" | ||||
|   location: "Location" | ||||
|   description: "About me" | ||||
|   birthday: "Birthday" | ||||
|   avatar: "Avatar" | ||||
|   banner: "Banner" | ||||
|   is-cat: "This account is a Cat" | ||||
|   is-bot: "This account is a Bot" | ||||
|   is-locked: "Follower requests require approval" | ||||
|   careful-bot: "Follower requests from bots require approval" | ||||
|   advanced: "Advanced" | ||||
|   privacy: "Privacy" | ||||
|   save: "Update profile" | ||||
|   saved: "Profile updated successfully" | ||||
|   uploading: "Uploading" | ||||
|   upload-failed: "Failed to upload" | ||||
| common/views/widgets/broadcast.vue: | ||||
|   fetching: "Fetching" | ||||
|   no-broadcasts: "No announcements" | ||||
| @@ -463,7 +497,7 @@ common/views/widgets/tips.vue: | ||||
|   tips-line10: "Using the Time Machine widget makes it easy to trace back to the past timeline." | ||||
|   tips-line11: "You can pin posts to user page by clicking on \"...\"" | ||||
|   tips-line13: "All the files attached to the post are saved to Drive." | ||||
|   tips-line14: "While customizing the home, you can right click on the widget and change the design." | ||||
|   tips-line14: "While customizing your home layout, you can right click on a widget to change its design." | ||||
|   tips-line17: "Surrounding the text with ** ** will highlight it." | ||||
|   tips-line19: "Several windows can be detached outside the browser." | ||||
|   tips-line20: "The percentage of the calendar widget shows the percentage of time elapsed." | ||||
| @@ -640,14 +674,14 @@ desktop/views/components/note-detail.vue: | ||||
|   location: "Location" | ||||
|   renote: "Repost" | ||||
|   add-reaction: "Add a reaction" | ||||
| desktop/views/components/notes.note.vue: | ||||
| desktop/views/components/note.vue: | ||||
|   reposted-by: "Reposted by {}" | ||||
|   reply: "Reply" | ||||
|   renote: "Repost" | ||||
|   renote: "Renote" | ||||
|   add-reaction: "Add a reaction" | ||||
|   detail: "Show details" | ||||
|   private: "Post is private" | ||||
|   deleted: "Post has been deleted" | ||||
|   detail: "Details" | ||||
|   private: "This post is private" | ||||
|   deleted: "This post has been deleted" | ||||
| desktop/views/components/notes.vue: | ||||
|   error: "Loading failed." | ||||
|   retry: "Retry" | ||||
| @@ -726,8 +760,12 @@ desktop/views/components/settings.vue: | ||||
|   advanced: "Advanced settings" | ||||
|   api-via-stream: "API request via stream" | ||||
|   api-via-stream-desc: "API request is performed via the WebSocket connection instead of native fetch API (for better performance). This setting is stored in the browser." | ||||
|   deck-nav: "Transitionless deck navigation" | ||||
|   deck-nav-desc: "You get a temporary column without page transitions during navigation when using the deck." | ||||
|   deck-default: "Use Deck as default UI" | ||||
|   display: "Design and display" | ||||
|   customize: "Customize home layout" | ||||
|   wallpaper: "Wallpaper" | ||||
|   choose-wallpaper: "Choose a background" | ||||
|   delete-wallpaper: "Remove background" | ||||
|   dark-mode: "Dark Mode" | ||||
| @@ -739,17 +777,19 @@ desktop/views/components/settings.vue: | ||||
|   suggest-recent-hashtags: "Show recent popular hashtags on the post form" | ||||
|   show-clock-on-header: "Show clock on upper-right" | ||||
|   show-reply-target: "Display reply target" | ||||
|   timeline: "Timeline" | ||||
|   show-my-renotes: "Show my renotes in the timeline" | ||||
|   show-renoted-my-notes: "Show renoted my posts in timelines" | ||||
|   show-renoted-my-notes: "Show renoted posts of mine in timelines" | ||||
|   show-local-renotes: "Show renoted local posts in timelines" | ||||
|   show-maps: "Display a map to show the location" | ||||
|   deck-column-align: "Deck column alignment" | ||||
|   deck-column-align-center: "Center" | ||||
|   deck-column-align-left: "Left" | ||||
|   sound: "Sound" | ||||
|   enable-sounds: "Enable sound" | ||||
|   enable-sounds-desc: "Play a sound when you receive a post/message. This setting is stored in the browser." | ||||
|   volume: "Volume" | ||||
|   test: "Test" | ||||
|   mobile: "Mobile" | ||||
|   disable-via-mobile: "Don't mark the post as 'from mobile'" | ||||
|   language: "Language" | ||||
|   pick-language: "Select a language" | ||||
|   recommended: "Recommended" | ||||
| @@ -828,21 +868,6 @@ desktop/views/components/settings.password.vue: | ||||
|   enter-new-password-again: "Enter new password again" | ||||
|   not-match: "The new passwords do not match" | ||||
|   changed: "Password updated" | ||||
| desktop/views/components/settings.profile.vue: | ||||
|   avatar: "Avatar" | ||||
|   choice-avatar: "Select an image" | ||||
|   name: "Name" | ||||
|   location: "Location" | ||||
|   description: "Description" | ||||
|   birthday: "Birthday" | ||||
|   save: "Update profile" | ||||
|   locked-account: "Protect your account" | ||||
|   is-locked: "Follow request needs approval" | ||||
|   careful-bot: "Botからのフォローだけ承認制にする" | ||||
|   other: "Other" | ||||
|   is-bot: "This account is a Bot" | ||||
|   is-cat: "This account is a Cat" | ||||
|   profile-updated: "Your profile has been updated" | ||||
| desktop/views/components/sub-note-content.vue: | ||||
|   private: "This post is private" | ||||
|   deleted: "This post has been deleted" | ||||
| @@ -875,7 +900,7 @@ desktop/views/components/ui.header.account.vue: | ||||
|   admin: "Admin" | ||||
|   settings: "Settings" | ||||
|   signout: "Sign out" | ||||
|   dark: "Submerge in dark" | ||||
|   dark: "Toggle dark mode" | ||||
| desktop/views/components/ui.header.nav.vue: | ||||
|   home: "Home" | ||||
|   deck: "Deck" | ||||
| @@ -914,6 +939,8 @@ desktop/views/pages/admin/admin.vue: | ||||
|   drive: "Drive" | ||||
|   users: "Users" | ||||
|   update: "Updates" | ||||
|   announcements: "Announcements" | ||||
|   hashtags: "Hashtags" | ||||
| desktop/views/pages/admin/admin.dashboard.vue: | ||||
|   dashboard: "Dashboard" | ||||
|   all-users: "All Users" | ||||
| @@ -921,6 +948,9 @@ desktop/views/pages/admin/admin.dashboard.vue: | ||||
|   all-notes: "All the posts" | ||||
|   original-notes: "Posts on this instance" | ||||
|   invite: "Invite" | ||||
|   banner-url: "Banner URL" | ||||
|   disableRegistration: "Disable new user registration" | ||||
|   disableLocalTimeline: "Disable the local timeline" | ||||
| desktop/views/pages/admin/admin.suspend-user.vue: | ||||
|   suspend-user: "Suspend a user" | ||||
|   suspend: "Suspend" | ||||
| @@ -937,14 +967,23 @@ desktop/views/pages/admin/admin.unverify-user.vue: | ||||
|   unverify-user: "User account unverification settings" | ||||
|   unverify: "Unverify account" | ||||
|   unverified: "The account is now being unverified" | ||||
| desktop/views/pages/admin/admin.announcements.vue: | ||||
|   announcements: "Announcements" | ||||
| desktop/views/pages/admin/admin.hashtags.vue: | ||||
|   hided-tags: "Hidden Tags" | ||||
| desktop/views/pages/deck/deck.tl-column.vue: | ||||
|   is-media-only: "Only media posts" | ||||
|   is-media-view: "Media view" | ||||
|   edit: "Options" | ||||
| desktop/views/pages/deck/deck.note.vue: | ||||
|   reposted-by: "Reposted by {}" | ||||
|   private: "This post is private" | ||||
|   deleted: "This post has been deleted" | ||||
| desktop/views/pages/deck/deck.user-column.vue: | ||||
|   posts: "Posts" | ||||
|   following: "Following" | ||||
|   followers: "Followers" | ||||
|   images: "Images" | ||||
|   activity: "Activity" | ||||
|   timeline: "Timeline" | ||||
|   pinned-notes: "Pinned posts" | ||||
|   push-to-a-list: "Add to list" | ||||
| desktop/views/pages/stats/stats.vue: | ||||
|   all-users: "All Users" | ||||
|   original-users: "Users on this instance" | ||||
| @@ -959,7 +998,7 @@ desktop/views/pages/welcome.vue: | ||||
|   signup-button: "Sign up" | ||||
|   timeline: "Timeline" | ||||
|   announcements: "Announcements" | ||||
|   photos: "Recent uploaded" | ||||
|   photos: "Recent Images" | ||||
|   powered-by-misskey: "Powered by <b>Misskey</b>." | ||||
|   info: "Information" | ||||
| desktop/views/pages/drive.vue: | ||||
| @@ -997,10 +1036,7 @@ desktop/views/pages/user/user.friends.vue: | ||||
|   no-users: "No frequent mentions" | ||||
| desktop/views/pages/user/user.vue: | ||||
|   is-suspended: "This account has been suspended." | ||||
|   is-remote: "This profile belongs to a remote user. The profile that you see here may not be complete. " | ||||
|   view-remote: "See their complete profile" | ||||
| desktop/views/pages/user/user.home.vue: | ||||
|   last-used-at: "Last active:" | ||||
|   last-used-at: "Last active" | ||||
| desktop/views/pages/user/user.photos.vue: | ||||
|   title: "Photos" | ||||
|   loading: "Loading" | ||||
| @@ -1020,6 +1056,10 @@ desktop/views/pages/user/user.header.vue: | ||||
|   following: "Following" | ||||
|   followers: "Followers" | ||||
|   is-bot: "This account is a Bot" | ||||
|   years-old: " years old" | ||||
|   year: "/" | ||||
|   month: "/" | ||||
|   day: "-" | ||||
| desktop/views/pages/user/user.timeline.vue: | ||||
|   default: "Posts" | ||||
|   with-replies: "Posts and replies" | ||||
| @@ -1164,11 +1204,11 @@ mobile/views/components/ui.nav.vue: | ||||
|   about: "About Misskey" | ||||
| mobile/views/components/user-timeline.vue: | ||||
|   no-notes: "It seems this user hasn't posted anything yet." | ||||
|   no-notes-with-media: "There are no posts attaching media" | ||||
|   no-notes-with-media: "There are no notes with media attachments" | ||||
|   load-more: "More" | ||||
| mobile/views/components/users-list.vue: | ||||
|   all: "All" | ||||
|   known: "You know" | ||||
|   known: "In common" | ||||
|   load-more: "More" | ||||
| mobile/views/pages/favorites.vue: | ||||
|   title: "Favorites" | ||||
| @@ -1221,24 +1261,6 @@ mobile/views/pages/notifications.vue: | ||||
|   read-all: "Do you wish to mark all notifications as read?" | ||||
| mobile/views/pages/games/reversi.vue: | ||||
|   reversi: "Reversi" | ||||
| mobile/views/pages/settings/settings.profile.vue: | ||||
|   title: "Profile" | ||||
|   name: "Name" | ||||
|   account: "Account" | ||||
|   location: "Location" | ||||
|   description: "Biography" | ||||
|   birthday: "Birthday" | ||||
|   avatar: "Avatar" | ||||
|   banner: "Banner" | ||||
|   is-cat: "This account is a Cat" | ||||
|   is-locked: "Follow request needs approval" | ||||
|   careful-bot: "Botからのフォローだけ承認制にする" | ||||
|   advanced: "Advanced" | ||||
|   privacy: "Privacy" | ||||
|   save: "Update profile" | ||||
|   saved: "Profile updated" | ||||
|   uploading: "Uploading" | ||||
|   upload-failed: "Failed to upload" | ||||
| mobile/views/pages/search.vue: | ||||
|   search: "Search" | ||||
|   empty: "No posts were found for '{}'" | ||||
| @@ -1260,7 +1282,7 @@ mobile/views/pages/settings.vue: | ||||
|   timeline: "Timeline" | ||||
|   show-reply-target: "Show reply target" | ||||
|   show-my-renotes: "Show my reposts" | ||||
|   show-renoted-my-notes: "Show renoted my posts" | ||||
|   show-renoted-my-notes: "Show renoted posts of mine" | ||||
|   show-local-renotes: "Show renoted local posts" | ||||
|   post-style: "Post design" | ||||
|   post-style-standard: "Standard" | ||||
| @@ -1294,6 +1316,7 @@ mobile/views/pages/settings.vue: | ||||
|   signout: "Sign out" | ||||
|   sound: "Sounds" | ||||
|   enable-sounds: "Enable sounds" | ||||
|   mark-as-read-all-unread-notes: "Mark all posts as read" | ||||
| mobile/views/pages/user.vue: | ||||
|   follows-you: "Follows you" | ||||
|   following: "Following" | ||||
| @@ -1303,8 +1326,6 @@ mobile/views/pages/user.vue: | ||||
|   timeline: "Timeline" | ||||
|   media: "Media" | ||||
|   is-suspended: "This account has been suspended." | ||||
|   is-remote: "The user is a remote user. The profile that you see here may not complete." | ||||
|   view-remote: "See his/her complete profile" | ||||
| mobile/views/pages/user/home.vue: | ||||
|   recent-notes: "Recent notes" | ||||
|   images: "Images" | ||||
| @@ -1350,3 +1371,29 @@ docs: | ||||
|       description: "Description" | ||||
| dev/views/index.vue: | ||||
|   manage-apps: "Manage apps" | ||||
| dev/views/apps.vue: | ||||
|   manage-apps: "Manage apps" | ||||
|   create-app: "Create app" | ||||
|   app-missing: "No apps" | ||||
| dev/views/new-app.vue: | ||||
|   create-app: "Creating application" | ||||
|   app-name: "Application name" | ||||
|   app-name-desc: "The name of your app" | ||||
|   app-name-ex: "ex) Misskey for iOS" | ||||
|   app-overview: "Application summary" | ||||
|   app-desc: "A brief description or introduction of your app." | ||||
|   app-desc-ex: "ex) Misskey iOS client." | ||||
|   callback-url: "The callback URL (optional)" | ||||
|   callback-url-desc: "The URL to redirect to after the user is authenticated via the authentication form." | ||||
|   authority: "Permissions" | ||||
|   authority-desc: "Only the functions requested here can be accessed via the API." | ||||
|   authority-warning: "You can change it even after creating the application, but if you give different permissions, all user keys associated at that time will be invalidated." | ||||
|   account-read: "View account information." | ||||
|   account-write: "Modify account information." | ||||
|   note-write: "Post." | ||||
|   reaction-write: "Add or remove reactions." | ||||
|   following-write: "Follow and unfollow." | ||||
|   drive-read: "Read the drive." | ||||
|   drive-write: "Upload/delete files in the drive." | ||||
|   notification-read: "Read your notifications." | ||||
|   notification-write: "Manage your notifications." | ||||
|   | ||||
| @@ -25,6 +25,14 @@ common: | ||||
|   application-authorization: "Autorizaciones de la aplicación." | ||||
|   close: "Cerrar" | ||||
|   do-not-copy-paste: "Por favor no copies código aquí. Tu cuenta puede resultar comprometida." | ||||
|   BSoD: | ||||
|     fatal-error: ":( 致命的な問題が発生しました。" | ||||
|     update-browser-os: "お使いのブラウザ(またはOS)のバージョンを更新すると解決する可能性があります。" | ||||
|     error-code: "エラーコード" | ||||
|     browser-version: "ブラウザ バージョン" | ||||
|     client-version: "クライアント バージョン" | ||||
|     email-support: "問題が解決しない場合は、上記の情報をお書き添えの上 syuilotan@yahoo.co.jp までご連絡ください。" | ||||
|     thanks: "Thank you for using Misskey." | ||||
|   got-it: "¡Listo!" | ||||
|   customization-tips: | ||||
|     title: "Consejos de personalización" | ||||
| @@ -115,6 +123,12 @@ common: | ||||
|   reduce-motion: "UIの動きを減らす" | ||||
|   this-setting-is-this-device-only: "このデバイスのみ" | ||||
|   do-not-use-in-production: 'Esto está en desarrollo, no usarlo para producción.' | ||||
|   is-remote-user: "このユーザー情報はコピーです。" | ||||
|   is-remote-post: "この投稿情報はコピーです。" | ||||
|   view-on-remote: "正確な情報を見る" | ||||
|   error: | ||||
|     title: '問題が発生しました' | ||||
|     retry: 'やり直す' | ||||
|   reversi: | ||||
|     drawn: "Empatado" | ||||
|     my-turn: "Mi turno" | ||||
| @@ -170,6 +184,7 @@ common: | ||||
|     rename: "Renombrar" | ||||
|     stack-left: "A la izqda." | ||||
|     pop-right: "A la dcha." | ||||
|   dev: "アプリの作成に失敗しました。再度お試しください。" | ||||
| auth/views/form.vue: | ||||
|   share-access: "¿Deseas <b>permitir</b> a <i>{{ app.name }}</i> acceder a tu cuenta?" | ||||
|   permission-ask: "La aplicación requiere los siguientes permisos:" | ||||
| @@ -416,6 +431,25 @@ common/views/components/visibility-chooser.vue: | ||||
| common/views/components/trends.vue: | ||||
|   count: "{}人が投稿" | ||||
|   empty: "トレンドなし" | ||||
| common/views/components/profile-editor.vue: | ||||
|   title: "プロフィール" | ||||
|   name: "名前" | ||||
|   account: "アカウント" | ||||
|   location: "場所" | ||||
|   description: "自己紹介" | ||||
|   birthday: "誕生日" | ||||
|   avatar: "アイコン" | ||||
|   banner: "バナー" | ||||
|   is-cat: "このアカウントはCatです" | ||||
|   is-bot: "このアカウントはBotです" | ||||
|   is-locked: "フォローを承認制にする" | ||||
|   careful-bot: "Botからのフォローだけ承認制にする" | ||||
|   advanced: "その他" | ||||
|   privacy: "プライバシー" | ||||
|   save: "保存" | ||||
|   saved: "プロフィールを保存しました" | ||||
|   uploading: "アップロード中" | ||||
|   upload-failed: "アップロードに失敗しました" | ||||
| common/views/widgets/broadcast.vue: | ||||
|   fetching: "Recuperando" | ||||
|   no-broadcasts: "Sin emisión" | ||||
| @@ -640,14 +674,14 @@ desktop/views/components/note-detail.vue: | ||||
|   location: "Localización" | ||||
|   renote: "Republicar" | ||||
|   add-reaction: "Agregar una reacción" | ||||
| desktop/views/components/notes.note.vue: | ||||
|   reposted-by: "Republicado por {}" | ||||
|   reply: "Responder" | ||||
|   renote: "Republicar" | ||||
|   add-reaction: "Agregar una reacción" | ||||
|   detail: "Mostrar detalles" | ||||
|   private: "Esta publicación es privada" | ||||
|   deleted: "Esta publicación ha sido borrada" | ||||
| desktop/views/components/note.vue: | ||||
|   reposted-by: "{}がRenote" | ||||
|   reply: "返信" | ||||
|   renote: "Renote" | ||||
|   add-reaction: "リアクション" | ||||
|   detail: "詳細" | ||||
|   private: "この投稿は非公開です" | ||||
|   deleted: "この投稿は削除されました" | ||||
| desktop/views/components/notes.vue: | ||||
|   error: "Error al cargar." | ||||
|   retry: "Reintentar" | ||||
| @@ -726,8 +760,12 @@ desktop/views/components/settings.vue: | ||||
|   advanced: "Configuración avanzada" | ||||
|   api-via-stream: "Solicitar API por medio de un stream" | ||||
|   api-via-stream-desc: "Las peticiones de las API se realizan por conexiones WebSocket en lugar de las tradicionales (para una mejora en el rendimiento). Esta función depende del navegador." | ||||
|   deck-nav: "デッキ内ナビゲーション" | ||||
|   deck-nav-desc: "デッキを使用しているとき、ナビゲーションが発生する際にページ遷移を行わずに一時的なカラムで受けるようにします。" | ||||
|   deck-default: "デッキをデフォルトのUIにする" | ||||
|   display: "Diseño y pantalla" | ||||
|   customize: "Personaliza la página principal" | ||||
|   wallpaper: "壁紙" | ||||
|   choose-wallpaper: "Elije un fondo" | ||||
|   delete-wallpaper: "Suprimir fondo" | ||||
|   dark-mode: "Modo Nocturno" | ||||
| @@ -739,17 +777,19 @@ desktop/views/components/settings.vue: | ||||
|   suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する" | ||||
|   show-clock-on-header: "右上に時計を表示する" | ||||
|   show-reply-target: "リプライ先を表示する" | ||||
|   timeline: "タイムライン" | ||||
|   show-my-renotes: "自分の行ったRenoteをタイムラインに表示する" | ||||
|   show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する" | ||||
|   show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する" | ||||
|   show-maps: "マップの自動展開" | ||||
|   deck-column-align: "デッキのカラムの位置" | ||||
|   deck-column-align-center: "中央" | ||||
|   deck-column-align-left: "左" | ||||
|   sound: "サウンド" | ||||
|   enable-sounds: "サウンドを有効にする" | ||||
|   enable-sounds-desc: "投稿やメッセージを送受信したときなどにサウンドを再生します。この設定はブラウザに記憶されます。" | ||||
|   volume: "ボリューム" | ||||
|   test: "テスト" | ||||
|   mobile: "モバイル" | ||||
|   disable-via-mobile: "「モバイルからの投稿」フラグを付けない" | ||||
|   language: "言語" | ||||
|   pick-language: "言語を選択" | ||||
|   recommended: "推奨" | ||||
| @@ -828,21 +868,6 @@ desktop/views/components/settings.password.vue: | ||||
|   enter-new-password-again: "Ingresar nueva contraseña de nuevo" | ||||
|   not-match: "Las nuevas contraseñas no se corresponden consigo mismas" | ||||
|   changed: "Contraseña actualizada" | ||||
| desktop/views/components/settings.profile.vue: | ||||
|   avatar: "Avatar" | ||||
|   choice-avatar: "Escoger una imagen" | ||||
|   name: "Nombre" | ||||
|   location: "Localización" | ||||
|   description: "Descripción" | ||||
|   birthday: "Fecha de nacimiento" | ||||
|   save: "Perfil actualizado" | ||||
|   locked-account: "Protege tu cuenta" | ||||
|   is-locked: "フォローを承認制にする" | ||||
|   careful-bot: "Botからのフォローだけ承認制にする" | ||||
|   other: "その他" | ||||
|   is-bot: "このアカウントはBotです" | ||||
|   is-cat: "このアカウントはCatです" | ||||
|   profile-updated: "プロフィールを更新しました" | ||||
| desktop/views/components/sub-note-content.vue: | ||||
|   private: "この投稿は非公開です" | ||||
|   deleted: "この投稿は削除されました" | ||||
| @@ -914,6 +939,8 @@ desktop/views/pages/admin/admin.vue: | ||||
|   drive: "ドライブ" | ||||
|   users: "ユーザー" | ||||
|   update: "更新" | ||||
|   announcements: "お知らせ" | ||||
|   hashtags: "ハッシュタグ" | ||||
| desktop/views/pages/admin/admin.dashboard.vue: | ||||
|   dashboard: "ダッシュボード" | ||||
|   all-users: "全てのユーザー" | ||||
| @@ -921,6 +948,9 @@ desktop/views/pages/admin/admin.dashboard.vue: | ||||
|   all-notes: "全ての投稿" | ||||
|   original-notes: "このインスタンスの投稿" | ||||
|   invite: "招待" | ||||
|   banner-url: "Banner URL" | ||||
|   disableRegistration: "Disable new user registration" | ||||
|   disableLocalTimeline: "Disable the local timeline" | ||||
| desktop/views/pages/admin/admin.suspend-user.vue: | ||||
|   suspend-user: "ユーザーの凍結" | ||||
|   suspend: "凍結" | ||||
| @@ -937,14 +967,23 @@ desktop/views/pages/admin/admin.unverify-user.vue: | ||||
|   unverify-user: "ユーザーの公式アカウント解除" | ||||
|   unverify: "公式アカウントを解除する" | ||||
|   unverified: "公式アカウントを解除しました" | ||||
| desktop/views/pages/admin/admin.announcements.vue: | ||||
|   announcements: "お知らせ" | ||||
| desktop/views/pages/admin/admin.hashtags.vue: | ||||
|   hided-tags: "Hidden Tags" | ||||
| desktop/views/pages/deck/deck.tl-column.vue: | ||||
|   is-media-only: "メディア投稿のみ" | ||||
|   is-media-view: "メディアビュー" | ||||
|   edit: "オプション" | ||||
| desktop/views/pages/deck/deck.note.vue: | ||||
|   reposted-by: "{}がRenote" | ||||
|   private: "この投稿は非公開です" | ||||
|   deleted: "この投稿は削除されました" | ||||
| desktop/views/pages/deck/deck.user-column.vue: | ||||
|   posts: "投稿" | ||||
|   following: "フォロー" | ||||
|   followers: "フォロワー" | ||||
|   images: "画像" | ||||
|   activity: "アクティビティ" | ||||
|   timeline: "タイムライン" | ||||
|   pinned-notes: "ピン留めされた投稿" | ||||
|   push-to-a-list: "リストに追加" | ||||
| desktop/views/pages/stats/stats.vue: | ||||
|   all-users: "全てのユーザー" | ||||
|   original-users: "このインスタンスのユーザー" | ||||
| @@ -997,9 +1036,6 @@ desktop/views/pages/user/user.friends.vue: | ||||
|   no-users: "よく話すユーザーはいません" | ||||
| desktop/views/pages/user/user.vue: | ||||
|   is-suspended: "このユーザーは凍結されています。" | ||||
|   is-remote: "このユーザーはリモートユーザーです。" | ||||
|   view-remote: "正確な情報を見る" | ||||
| desktop/views/pages/user/user.home.vue: | ||||
|   last-used-at: "最終アクセス" | ||||
| desktop/views/pages/user/user.photos.vue: | ||||
|   title: "フォト" | ||||
| @@ -1020,6 +1056,10 @@ desktop/views/pages/user/user.header.vue: | ||||
|   following: "フォロー" | ||||
|   followers: "フォロワー" | ||||
|   is-bot: "このアカウントはBotです" | ||||
|   years-old: "歳" | ||||
|   year: "年" | ||||
|   month: "月" | ||||
|   day: "日" | ||||
| desktop/views/pages/user/user.timeline.vue: | ||||
|   default: "投稿" | ||||
|   with-replies: "投稿と返信" | ||||
| @@ -1221,24 +1261,6 @@ mobile/views/pages/notifications.vue: | ||||
|   read-all: "すべての通知を既読にしますか?" | ||||
| mobile/views/pages/games/reversi.vue: | ||||
|   reversi: "リバーシ" | ||||
| mobile/views/pages/settings/settings.profile.vue: | ||||
|   title: "プロフィール" | ||||
|   name: "名前" | ||||
|   account: "アカウント" | ||||
|   location: "場所" | ||||
|   description: "自己紹介" | ||||
|   birthday: "誕生日" | ||||
|   avatar: "アイコン" | ||||
|   banner: "バナー" | ||||
|   is-cat: "このアカウントはCatです" | ||||
|   is-locked: "フォローを承認制にする" | ||||
|   careful-bot: "Botからのフォローだけ承認制にする" | ||||
|   advanced: "その他" | ||||
|   privacy: "プライバシー" | ||||
|   save: "保存" | ||||
|   saved: "プロフィールを保存しました" | ||||
|   uploading: "アップロード中" | ||||
|   upload-failed: "アップロードに失敗しました" | ||||
| mobile/views/pages/search.vue: | ||||
|   search: "検索" | ||||
|   empty: "「{}」に関する投稿は見つかりませんでした。" | ||||
| @@ -1294,6 +1316,7 @@ mobile/views/pages/settings.vue: | ||||
|   signout: "サインアウト" | ||||
|   sound: "サウンド" | ||||
|   enable-sounds: "サウンドを有効にする" | ||||
|   mark-as-read-all-unread-notes: "すべての投稿を既読にする" | ||||
| mobile/views/pages/user.vue: | ||||
|   follows-you: "フォローされています" | ||||
|   following: "フォロー" | ||||
| @@ -1303,8 +1326,6 @@ mobile/views/pages/user.vue: | ||||
|   timeline: "タイムライン" | ||||
|   media: "メディア" | ||||
|   is-suspended: "このユーザーは凍結されています。" | ||||
|   is-remote: "このユーザーはリモートユーザーです。" | ||||
|   view-remote: "正確な情報を見る" | ||||
| mobile/views/pages/user/home.vue: | ||||
|   recent-notes: "最近の投稿" | ||||
|   images: "画像" | ||||
| @@ -1350,3 +1371,29 @@ docs: | ||||
|       description: "説明" | ||||
| dev/views/index.vue: | ||||
|   manage-apps: "アプリの管理" | ||||
| dev/views/apps.vue: | ||||
|   manage-apps: "アプリを管理" | ||||
|   create-app: "アプリ作成" | ||||
|   app-missing: "アプリなし" | ||||
| dev/views/new-app.vue: | ||||
|   create-app: "アプリケーションの作成" | ||||
|   app-name: "アプリケーション名" | ||||
|   app-name-desc: "あなたのアプリの名称。" | ||||
|   app-name-ex: "ex) Misskey for iOS" | ||||
|   app-overview: "アプリの概要" | ||||
|   app-desc: "あなたのアプリの簡単な説明や紹介。" | ||||
|   app-desc-ex: "ex) Misskey iOSクライアント。" | ||||
|   callback-url: "コールバックURL (オプション)" | ||||
|   callback-url-desc: "ユーザーが認証フォームで認証した際にリダイレクトするURLを設定できます。" | ||||
|   authority: "権限" | ||||
|   authority-desc: "ここで要求した機能だけがAPIからアクセスできます。" | ||||
|   authority-warning: "アプリ作成後も変更できますが、新たな権限を付与する場合、その時点で関連付けられているユーザーキーはすべて無効になります。" | ||||
|   account-read: "アカウントの情報を見る。" | ||||
|   account-write: "アカウントの情報を操作する。" | ||||
|   note-write: "投稿する。" | ||||
|   reaction-write: "リアクションしたりリアクションをキャンセルする。" | ||||
|   following-write: "フォローしたりフォロー解除する。" | ||||
|   drive-read: "ドライブを見る。" | ||||
|   drive-write: "ドライブを操作する。" | ||||
|   notification-read: "通知を見る。" | ||||
|   notification-write: "通知を操作する。" | ||||
|   | ||||
| @@ -5,7 +5,7 @@ meta: | ||||
| common: | ||||
|   misskey: "Une ⭐ du fédiverse" | ||||
|   about-title: "Une ⭐ du fédivers." | ||||
|   about: "Merci d'avoir découvert Misskey. Misskey est une <b>plateforme de microblogage distribuée</b> née sur Terre. Parce qu'il fait partie du Fédivers (un univers composé de diverses plateformes de réseaux sociaux organisées), il est mutuellement connecté avec d'autres plateformes de réseaux sociaux. Désirez-vous prendre une pause, pendant un instant, loin de l'agitation de la ville et plonger dans un nouvel Internet ?" | ||||
|   about: "Merci d’avoir choisis Misskey. Misskey est une <b>plateforme de micro-blogging distribuée</b> née sur Terre et fait partie du Fédiverse (un univers composé de diverses plateformes de réseaux sociaux organisées), elle est connectée mutuellement avec d’autres plateformes de réseaux sociaux. Désirez-vous prendre une pause, un court instant, loin de l’agitation de la ville et plonger dans un Internet d’un nouveau genre ?" | ||||
|   intro: | ||||
|     title: "C’est quoi Misskey ?" | ||||
|     about: "Misskeyはオープンソースの<b>分散型マイクロブログSNS</b>です。リッチで高度にカスタマイズできるUI、投稿へのリアクション、ファイルを一元管理できるドライブなど、先進的な機能を揃えています。また、Fediverseと呼ばれるネットワークに接続できるため、他のSNSともやり取りできます。例えば、あなたが何か投稿すると、その投稿はMisskeyだけでなく他のSNSにも伝わります。ちょうどある惑星から他の惑星に電波を発信している様子をイメージしてください。" | ||||
| @@ -25,6 +25,14 @@ common: | ||||
|   application-authorization: "Permissions de l'application" | ||||
|   close: "Fermer" | ||||
|   do-not-copy-paste: "Veuillez ne pas entrer ou coller le code ici. Le compte peut être compromis." | ||||
|   BSoD: | ||||
|     fatal-error: ":( 致命的な問題が発生しました。" | ||||
|     update-browser-os: "お使いのブラウザ(またはOS)のバージョンを更新すると解決する可能性があります。" | ||||
|     error-code: "エラーコード" | ||||
|     browser-version: "ブラウザ バージョン" | ||||
|     client-version: "クライアント バージョン" | ||||
|     email-support: "問題が解決しない場合は、上記の情報をお書き添えの上 syuilotan@yahoo.co.jp までご連絡ください。" | ||||
|     thanks: "Thank you for using Misskey." | ||||
|   got-it: "J'ai compris !" | ||||
|   customization-tips: | ||||
|     title: "Conseils de personnalisation" | ||||
| @@ -43,7 +51,7 @@ common: | ||||
|     quoted-by: "Cité·e par {} :" | ||||
|   time: | ||||
|     unknown: "inconnu" | ||||
|     future: "à l'instant" | ||||
|     future: "à l’instant" | ||||
|     just_now: "à l'instant" | ||||
|     seconds_ago: "Il y a {} seconde·s" | ||||
|     minutes_ago: "Il y a {} minute·s" | ||||
| @@ -106,15 +114,21 @@ common: | ||||
|   my-token-regenerated: "Votre jeton vient d’être généré, vous allez maintenant être déconnecté." | ||||
|   i-like-sushi: "Je préfère les sushis plutôt que le pudding" | ||||
|   show-reversi-board-labels: "Afficher les étiquettes des lignes et colonnes dans Reversi" | ||||
|   use-contrast-reversi-stones: "リバーシのアイコンにコントラストを付ける" | ||||
|   use-contrast-reversi-stones: "Icône avec contraste sur Reversi" | ||||
|   verified-user: "Compte vérifié" | ||||
|   disable-animated-mfm: "Désactiver les textes animés dans les publications" | ||||
|   always-show-nsfw: "常に閲覧注意のメディアを表示する" | ||||
|   always-mark-nsfw: "常にメディアを閲覧注意として投稿" | ||||
|   always-show-nsfw: "Toujours afficher les contenus sensibles" | ||||
|   always-mark-nsfw: "Toujours marquer les notes ayant des attachements comme sensibles" | ||||
|   show-full-acct: "Afficher l’adresse complète de l’utilisateur" | ||||
|   reduce-motion: "Réduire les animations dans l’interface utilisateur" | ||||
|   this-setting-is-this-device-only: "Uniquement sur cet appareil" | ||||
|   do-not-use-in-production: 'Il s’agit d’une version de développement. Ne pas utiliser dans un environnement de production.' | ||||
|   is-remote-user: "このユーザー情報はコピーです。" | ||||
|   is-remote-post: "この投稿情報はコピーです。" | ||||
|   view-on-remote: "正確な情報を見る" | ||||
|   error: | ||||
|     title: '問題が発生しました' | ||||
|     retry: 'やり直す' | ||||
|   reversi: | ||||
|     drawn: "Partie nulle" | ||||
|     my-turn: "C’est votre tour" | ||||
| @@ -170,6 +184,7 @@ common: | ||||
|     rename: "Renommer" | ||||
|     stack-left: "Vers la gauche" | ||||
|     pop-right: "Vers la droite" | ||||
|   dev: "アプリの作成に失敗しました。再度お試しください。" | ||||
| auth/views/form.vue: | ||||
|   share-access: "Désirez-vous <b>autoriser</b> <i>{{ app.name }}</i> à avoir accès à votre compte ?" | ||||
|   permission-ask: "Cette application nécessite les autorisations suivantes :" | ||||
| @@ -254,7 +269,7 @@ common/views/components/connect-failed.troubleshooter.vue: | ||||
|   no-network: "Aucune connexion au réseau" | ||||
|   no-network-desc: "Veuillez vérifier que vous êtes bien connecté au réseau." | ||||
|   no-internet: "Aucune connexion internet." | ||||
|   no-internet-desc: "Veuillez vérifier que vous êtes bien connecté à internet." | ||||
|   no-internet-desc: "Assurez-vous que vous êtes bien connectés à internet." | ||||
|   no-server: "Impossible de se connecter au serveur" | ||||
|   no-server-desc: "Votre connexion semble correcte, mais il a été impossible de vous connecter au serveur de Misskey. Il se peut que le serveur soit hors-ligne ou en maintenance, veuillez ressayer plus tard." | ||||
|   success: "Connexion au serveur de Misskey réussie !" | ||||
| @@ -265,8 +280,8 @@ common/views/components/media-banner.vue: | ||||
|   sensitive: "Contenu sensible" | ||||
|   click-to-show: "Cliquer pour afficher" | ||||
| common/views/components/theme.vue: | ||||
|   light-theme: "非ダークモード時に使用するテーマ" | ||||
|   dark-theme: "ダークモード時に使用するテーマ" | ||||
|   light-theme: "Thème durant le mode clair" | ||||
|   dark-theme: "Thème durant le mode sombre" | ||||
|   light-themes: "Thème clair" | ||||
|   dark-themes: "Thème sombre" | ||||
|   install-a-theme: "Installer un thème" | ||||
| @@ -335,7 +350,7 @@ common/views/components/note-menu.vue: | ||||
|   detail: "Détails" | ||||
|   copy-link: "Copier le lien" | ||||
|   favorite: "Mettre cette note en favoris" | ||||
|   unfavorite: "お気に入り解除" | ||||
|   unfavorite: "Retirer des favoris" | ||||
|   pin: "Épingler sur votre profil" | ||||
|   unpin: "Désépingler" | ||||
|   delete: "Supprimer" | ||||
| @@ -416,6 +431,25 @@ common/views/components/visibility-chooser.vue: | ||||
| common/views/components/trends.vue: | ||||
|   count: "{} utilisateurs·rices mentionnés·es" | ||||
|   empty: "Aucune tendance" | ||||
| common/views/components/profile-editor.vue: | ||||
|   title: "Profil" | ||||
|   name: "Nom" | ||||
|   account: "Compte" | ||||
|   location: "Lieu" | ||||
|   description: "À propos de moi" | ||||
|   birthday: "Date de naissance" | ||||
|   avatar: "Avatar" | ||||
|   banner: "Bannière" | ||||
|   is-cat: "Ce compte est un Chat" | ||||
|   is-bot: "Ce compte est un Bot" | ||||
|   is-locked: "Demandes d’abonnements requièrent l’approbation" | ||||
|   careful-bot: "Botからのフォローだけ承認制にする" | ||||
|   advanced: "Avancé" | ||||
|   privacy: "Vie privée" | ||||
|   save: "Mettre à jour le profil" | ||||
|   saved: "Profil mis à jour avec succès" | ||||
|   uploading: "En cours d'envoi …" | ||||
|   upload-failed: "Échec de l'envoi" | ||||
| common/views/widgets/broadcast.vue: | ||||
|   fetching: "Récupération" | ||||
|   no-broadcasts: "Aucune annonce" | ||||
| @@ -640,14 +674,14 @@ desktop/views/components/note-detail.vue: | ||||
|   location: "Géolocalisation" | ||||
|   renote: "Republier" | ||||
|   add-reaction: "Ajouter votre reaction" | ||||
| desktop/views/components/notes.note.vue: | ||||
|   reposted-by: "Reposté par {}" | ||||
| desktop/views/components/note.vue: | ||||
|   reposted-by: "Partagé par {}" | ||||
|   reply: "Répondre" | ||||
|   renote: "Republier" | ||||
|   add-reaction: "Ajouter votre reaction" | ||||
|   detail: "Afficher les détails" | ||||
|   private: "cette publication est privée" | ||||
|   deleted: "cette publication a été supprimée" | ||||
|   renote: "Partager" | ||||
|   add-reaction: "リアクション" | ||||
|   detail: "詳細" | ||||
|   private: "この投稿は非公開です" | ||||
|   deleted: "この投稿は削除されました" | ||||
| desktop/views/components/notes.vue: | ||||
|   error: "Échec du chargement." | ||||
|   retry: "Réessayer" | ||||
| @@ -726,8 +760,12 @@ desktop/views/components/settings.vue: | ||||
|   advanced: "Paramètres avancés" | ||||
|   api-via-stream: "Requête API via le flux" | ||||
|   api-via-stream-desc: "この設定をオンにすると、websocket接続を経由してAPIリクエストが行われます(パフォーマンス向上が期待できます)。オフにすると、ネイティブの fetch APIが利用されます。この設定はこのデバイスのみ有効です。" | ||||
|   deck-nav: "デッキ内ナビゲーション" | ||||
|   deck-nav-desc: "デッキを使用しているとき、ナビゲーションが発生する際にページ遷移を行わずに一時的なカラムで受けるようにします。" | ||||
|   deck-default: "デッキをデフォルトのUIにする" | ||||
|   display: "Affichage et design" | ||||
|   customize: "Personnaliser l'Accueil" | ||||
|   wallpaper: "壁紙" | ||||
|   choose-wallpaper: "Sélectionner un fond d'écran" | ||||
|   delete-wallpaper: "Supprimer le fond d'écran" | ||||
|   dark-mode: "Mode nuit" | ||||
| @@ -739,17 +777,19 @@ desktop/views/components/settings.vue: | ||||
|   suggest-recent-hashtags: "Afficher les hashtags populaires dans le champs de saisie" | ||||
|   show-clock-on-header: "Afficher l'horloge à droite sur le coté supérieur" | ||||
|   show-reply-target: "Afficher les réponses" | ||||
|   timeline: "タイムライン" | ||||
|   show-my-renotes: "Afficher mes republications dans le fil" | ||||
|   show-renoted-my-notes: "Afficher mes republications dans les fils" | ||||
|   show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する" | ||||
|   show-maps: "Afficher la carte" | ||||
|   deck-column-align: "デッキのカラムの位置" | ||||
|   deck-column-align-center: "中央" | ||||
|   deck-column-align-left: "左" | ||||
|   sound: "Son" | ||||
|   enable-sounds: "Activer le son" | ||||
|   enable-sounds-desc: "Jouer un son lorsque vous recevez un message. Ce paramètre est sauvegardé dans le navigateur." | ||||
|   volume: "Volume" | ||||
|   test: "Test" | ||||
|   mobile: "Mobile" | ||||
|   disable-via-mobile: "Enlever la mention publié via 'un périphérique mobile'" | ||||
|   language: "Langue" | ||||
|   pick-language: "Sélectionner une langue" | ||||
|   recommended: "Recommandé" | ||||
| @@ -786,9 +826,9 @@ desktop/views/components/settings.vue: | ||||
|   task-manager: "Gestionnaire de tâches" | ||||
|   third-parties: "Services tiers" | ||||
|   navbar-position: "ナビゲーションバーの位置" | ||||
|   navbar-position-top: "上" | ||||
|   navbar-position-left: "左" | ||||
|   navbar-position-right: "右" | ||||
|   navbar-position-top: "En haut" | ||||
|   navbar-position-left: "à gauche" | ||||
|   navbar-position-right: "à droite" | ||||
| desktop/views/components/settings.2fa.vue: | ||||
|   intro: "Si vous configurez la vérication en deux étapes vous aurez non seulement besoin de votre mot de passe mais aussi un appareil déjà pré-enregistré(tel que votre smartphone) ce qui ameliora grandement la sécurité de votre compte." | ||||
|   detail: "Voir les détails..." | ||||
| @@ -828,21 +868,6 @@ desktop/views/components/settings.password.vue: | ||||
|   enter-new-password-again: "Entrez à nouveau le nouveau mot de passe" | ||||
|   not-match: "Le nouveau mot de passe ne correspond pas." | ||||
|   changed: "Mot de passe modifié avec succès" | ||||
| desktop/views/components/settings.profile.vue: | ||||
|   avatar: "Avatar" | ||||
|   choice-avatar: "Choose an image" | ||||
|   name: "Nom" | ||||
|   location: "Localisation" | ||||
|   description: "Description" | ||||
|   birthday: "Date de naissance" | ||||
|   save: "Mettre à jour le profil" | ||||
|   locked-account: "Protéger votre compte" | ||||
|   is-locked: "Demande d’abonnement en attente d’approbation" | ||||
|   careful-bot: "Botからのフォローだけ承認制にする" | ||||
|   other: "Autre" | ||||
|   is-bot: "Ce compte est un Bot" | ||||
|   is-cat: "Ce compte est un Chat" | ||||
|   profile-updated: "Profil mis à jour" | ||||
| desktop/views/components/sub-note-content.vue: | ||||
|   private: "cette publication est privée" | ||||
|   deleted: "cette publication a été supprimée" | ||||
| @@ -914,6 +939,8 @@ desktop/views/pages/admin/admin.vue: | ||||
|   drive: "Drive" | ||||
|   users: "Utilisateur·rice·s" | ||||
|   update: "Mises à jour" | ||||
|   announcements: "お知らせ" | ||||
|   hashtags: "ハッシュタグ" | ||||
| desktop/views/pages/admin/admin.dashboard.vue: | ||||
|   dashboard: "Tableau de bord" | ||||
|   all-users: "Toutes les utilisateurrices" | ||||
| @@ -921,6 +948,9 @@ desktop/views/pages/admin/admin.dashboard.vue: | ||||
|   all-notes: "Toutes les publications" | ||||
|   original-notes: "Publications sur cette instance" | ||||
|   invite: "Invitation" | ||||
|   banner-url: "Banner URL" | ||||
|   disableRegistration: "Disable new user registration" | ||||
|   disableLocalTimeline: "Disable the local timeline" | ||||
| desktop/views/pages/admin/admin.suspend-user.vue: | ||||
|   suspend-user: "Suspendre un·e utilisateur·rice" | ||||
|   suspend: "Suspendre" | ||||
| @@ -937,14 +967,23 @@ desktop/views/pages/admin/admin.unverify-user.vue: | ||||
|   unverify-user: "ユーザーの公式アカウント解除" | ||||
|   unverify: "Ôter la vérification du compte" | ||||
|   unverified: "Ce compte n'est pas vérifié" | ||||
| desktop/views/pages/admin/admin.announcements.vue: | ||||
|   announcements: "お知らせ" | ||||
| desktop/views/pages/admin/admin.hashtags.vue: | ||||
|   hided-tags: "Hidden Tags" | ||||
| desktop/views/pages/deck/deck.tl-column.vue: | ||||
|   is-media-only: "Les publications médias uniquement" | ||||
|   is-media-view: "Vue média" | ||||
|   edit: "Options" | ||||
| desktop/views/pages/deck/deck.note.vue: | ||||
|   reposted-by: "Reposté par {}" | ||||
|   private: "cette publication est privée" | ||||
|   deleted: "cette publication a été supprimée" | ||||
| desktop/views/pages/deck/deck.user-column.vue: | ||||
|   posts: "投稿" | ||||
|   following: "フォロー" | ||||
|   followers: "フォロワー" | ||||
|   images: "画像" | ||||
|   activity: "アクティビティ" | ||||
|   timeline: "タイムライン" | ||||
|   pinned-notes: "ピン留めされた投稿" | ||||
|   push-to-a-list: "リストに追加" | ||||
| desktop/views/pages/stats/stats.vue: | ||||
|   all-users: "Toutes les utilisateurrices" | ||||
|   original-users: "Utilisateur·rice·s sur cette instance" | ||||
| @@ -997,10 +1036,7 @@ desktop/views/pages/user/user.friends.vue: | ||||
|   no-users: "Pas d'utilisateurs" | ||||
| desktop/views/pages/user/user.vue: | ||||
|   is-suspended: "Ce compte a été suspendu." | ||||
|   is-remote: "Cet utilisateur n'est pas un utilisateur Misskey. Certaines informations peuvent ne pas refléter ce profil dans sa totalité." | ||||
|   view-remote: "Consulter le profil complet" | ||||
| desktop/views/pages/user/user.home.vue: | ||||
|   last-used-at: "Last used at" | ||||
|   last-used-at: "最終アクセス" | ||||
| desktop/views/pages/user/user.photos.vue: | ||||
|   title: "Photos" | ||||
|   loading: "Chargement en cours" | ||||
| @@ -1020,6 +1056,10 @@ desktop/views/pages/user/user.header.vue: | ||||
|   following: "Suit" | ||||
|   followers: "Abonné·e·s" | ||||
|   is-bot: "Ce compte est un Bot" | ||||
|   years-old: "歳" | ||||
|   year: "年" | ||||
|   month: "月" | ||||
|   day: "日" | ||||
| desktop/views/pages/user/user.timeline.vue: | ||||
|   default: "Publications" | ||||
|   with-replies: "Publications et réponses" | ||||
| @@ -1221,24 +1261,6 @@ mobile/views/pages/notifications.vue: | ||||
|   read-all: "Êtes vous sûr de vouloir marqués toutes les notifications non-lus en tant que lus?" | ||||
| mobile/views/pages/games/reversi.vue: | ||||
|   reversi: "Reversi" | ||||
| mobile/views/pages/settings/settings.profile.vue: | ||||
|   title: "Profil" | ||||
|   name: "Nom" | ||||
|   account: "Compte" | ||||
|   location: "Lieu" | ||||
|   description: "Description" | ||||
|   birthday: "Date de naissance" | ||||
|   avatar: "Avatar" | ||||
|   banner: "Bannière" | ||||
|   is-cat: "Ce compte est un Bot" | ||||
|   is-locked: "Demande d’abonnement en attente d’approbation" | ||||
|   careful-bot: "Botからのフォローだけ承認制にする" | ||||
|   advanced: "Avancé" | ||||
|   privacy: "Vie privée" | ||||
|   save: "Mettre à jour le profil" | ||||
|   saved: "Profil mis à jour avec succès" | ||||
|   uploading: "En cours d'envoi" | ||||
|   upload-failed: "Échec de l'envoi" | ||||
| mobile/views/pages/search.vue: | ||||
|   search: "Chercher" | ||||
|   empty: "Aucun message trouvé pour '{}' " | ||||
| @@ -1294,6 +1316,7 @@ mobile/views/pages/settings.vue: | ||||
|   signout: "Déconnexion" | ||||
|   sound: "Sons" | ||||
|   enable-sounds: "Activer les sons" | ||||
|   mark-as-read-all-unread-notes: "すべての投稿を既読にする" | ||||
| mobile/views/pages/user.vue: | ||||
|   follows-you: "Vous suit" | ||||
|   following: "Abonnements" | ||||
| @@ -1303,8 +1326,6 @@ mobile/views/pages/user.vue: | ||||
|   timeline: "Fil d'actualité" | ||||
|   media: "Media" | ||||
|   is-suspended: "This account has been suspended." | ||||
|   is-remote: "Ceci est le profil d’un utilisateur·rice distant·e. Certaines informations peuvent ne pas refléter ce profil dans sa totalité." | ||||
|   view-remote: "Consulter son profil complet" | ||||
| mobile/views/pages/user/home.vue: | ||||
|   recent-notes: "Notes récentes" | ||||
|   images: "Images" | ||||
| @@ -1350,3 +1371,29 @@ docs: | ||||
|       description: "Description" | ||||
| dev/views/index.vue: | ||||
|   manage-apps: "Gestion des applications" | ||||
| dev/views/apps.vue: | ||||
|   manage-apps: "アプリを管理" | ||||
|   create-app: "アプリ作成" | ||||
|   app-missing: "アプリなし" | ||||
| dev/views/new-app.vue: | ||||
|   create-app: "アプリケーションの作成" | ||||
|   app-name: "アプリケーション名" | ||||
|   app-name-desc: "あなたのアプリの名称。" | ||||
|   app-name-ex: "ex) Misskey for iOS" | ||||
|   app-overview: "アプリの概要" | ||||
|   app-desc: "あなたのアプリの簡単な説明や紹介。" | ||||
|   app-desc-ex: "ex) Misskey iOSクライアント。" | ||||
|   callback-url: "コールバックURL (オプション)" | ||||
|   callback-url-desc: "ユーザーが認証フォームで認証した際にリダイレクトするURLを設定できます。" | ||||
|   authority: "権限" | ||||
|   authority-desc: "ここで要求した機能だけがAPIからアクセスできます。" | ||||
|   authority-warning: "アプリ作成後も変更できますが、新たな権限を付与する場合、その時点で関連付けられているユーザーキーはすべて無効になります。" | ||||
|   account-read: "アカウントの情報を見る。" | ||||
|   account-write: "アカウントの情報を操作する。" | ||||
|   note-write: "投稿する。" | ||||
|   reaction-write: "リアクションしたりリアクションをキャンセルする。" | ||||
|   following-write: "フォローしたりフォロー解除する。" | ||||
|   drive-read: "ドライブを見る。" | ||||
|   drive-write: "ドライブを操作する。" | ||||
|   notification-read: "通知を見る。" | ||||
|   notification-write: "通知を操作する。" | ||||
|   | ||||
| @@ -25,6 +25,14 @@ common: | ||||
|   application-authorization: "アプリの連携" | ||||
|   close: "閉じる" | ||||
|   do-not-copy-paste: "ここにコードを入力したり張り付けたりしないでください。アカウントが不正利用される可能性があります。" | ||||
|   BSoD: | ||||
|     fatal-error: ":( 致命的な問題が発生しました。" | ||||
|     update-browser-os: "お使いのブラウザ(またはOS)のバージョンを更新すると解決する可能性があります。" | ||||
|     error-code: "エラーコード" | ||||
|     browser-version: "ブラウザ バージョン" | ||||
|     client-version: "クライアント バージョン" | ||||
|     email-support: "問題が解決しない場合は、上記の情報をお書き添えの上 syuilotan@yahoo.co.jp までご連絡ください。" | ||||
|     thanks: "Thank you for using Misskey." | ||||
|   got-it: "わかった" | ||||
|   customization-tips: | ||||
|     title: "カスタマイズのヒント" | ||||
| @@ -115,6 +123,12 @@ common: | ||||
|   reduce-motion: "UIの動きを減らす" | ||||
|   this-setting-is-this-device-only: "このデバイスのみ" | ||||
|   do-not-use-in-production: 'これは開発ビルドです。本番環境で使用しないでください。' | ||||
|   is-remote-user: "このユーザー情報はコピーです。" | ||||
|   is-remote-post: "この投稿情報はコピーです。" | ||||
|   view-on-remote: "正確な情報を見る" | ||||
|   error: | ||||
|     title: '問題が発生しました' | ||||
|     retry: 'やり直す' | ||||
|   reversi: | ||||
|     drawn: "引き分け" | ||||
|     my-turn: "あなたのターンです" | ||||
| @@ -170,6 +184,7 @@ common: | ||||
|     rename: "名前を変更" | ||||
|     stack-left: "左に重ねる" | ||||
|     pop-right: "右に出す" | ||||
|   dev: "アプリの作成に失敗しました。再度お試しください。" | ||||
| auth/views/form.vue: | ||||
|   share-access: "<i>{{ app.name }}</i>があなたのアカウントにアクセスすることを<b>許可</b>しますか?" | ||||
|   permission-ask: "このアプリは次の権限を要求しています:" | ||||
| @@ -416,6 +431,25 @@ common/views/components/visibility-chooser.vue: | ||||
| common/views/components/trends.vue: | ||||
|   count: "{}人が投稿" | ||||
|   empty: "トレンドなし" | ||||
| common/views/components/profile-editor.vue: | ||||
|   title: "プロフィール" | ||||
|   name: "名前" | ||||
|   account: "アカウント" | ||||
|   location: "場所" | ||||
|   description: "自己紹介" | ||||
|   birthday: "誕生日" | ||||
|   avatar: "アイコン" | ||||
|   banner: "バナー" | ||||
|   is-cat: "このアカウントはCatです" | ||||
|   is-bot: "このアカウントはBotです" | ||||
|   is-locked: "フォローを承認制にする" | ||||
|   careful-bot: "Botからのフォローだけ承認制にする" | ||||
|   advanced: "その他" | ||||
|   privacy: "プライバシー" | ||||
|   save: "保存" | ||||
|   saved: "プロフィールを保存しました" | ||||
|   uploading: "アップロード中" | ||||
|   upload-failed: "アップロードに失敗しました" | ||||
| common/views/widgets/broadcast.vue: | ||||
|   fetching: "確認中" | ||||
|   no-broadcasts: "お知らせはありません" | ||||
| @@ -640,7 +674,7 @@ desktop/views/components/note-detail.vue: | ||||
|   location: "位置情報" | ||||
|   renote: "Renote" | ||||
|   add-reaction: "リアクション" | ||||
| desktop/views/components/notes.note.vue: | ||||
| desktop/views/components/note.vue: | ||||
|   reposted-by: "{}がRenote" | ||||
|   reply: "返信" | ||||
|   renote: "Renote" | ||||
| @@ -726,8 +760,12 @@ desktop/views/components/settings.vue: | ||||
|   advanced: "詳細設定" | ||||
|   api-via-stream: "ストリームを経由したAPIリクエスト" | ||||
|   api-via-stream-desc: "この設定をオンにすると、websocket接続を経由してAPIリクエストが行われます(パフォーマンス向上が期待できます)。オフにすると、ネイティブの fetch APIが利用されます。この設定はこのデバイスのみ有効です。" | ||||
|   deck-nav: "デッキ内ナビゲーション" | ||||
|   deck-nav-desc: "デッキを使用しているとき、ナビゲーションが発生する際にページ遷移を行わずに一時的なカラムで受けるようにします。" | ||||
|   deck-default: "デッキをデフォルトのUIにする" | ||||
|   display: "デザインと表示" | ||||
|   customize: "ホームをカスタマイズ" | ||||
|   wallpaper: "壁紙" | ||||
|   choose-wallpaper: "壁紙を選択" | ||||
|   delete-wallpaper: "壁紙を削除" | ||||
|   dark-mode: "ダークモード" | ||||
| @@ -739,17 +777,19 @@ desktop/views/components/settings.vue: | ||||
|   suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する" | ||||
|   show-clock-on-header: "右上に時計を表示する" | ||||
|   show-reply-target: "リプライ先を表示する" | ||||
|   timeline: "タイムライン" | ||||
|   show-my-renotes: "自分の行ったRenoteをタイムラインに表示する" | ||||
|   show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する" | ||||
|   show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する" | ||||
|   show-maps: "マップの自動展開" | ||||
|   deck-column-align: "デッキのカラムの位置" | ||||
|   deck-column-align-center: "中央" | ||||
|   deck-column-align-left: "左" | ||||
|   sound: "サウンド" | ||||
|   enable-sounds: "サウンドを有効にする" | ||||
|   enable-sounds-desc: "投稿やメッセージを送受信したときなどにサウンドを再生します。この設定はブラウザに記憶されます。" | ||||
|   volume: "ボリューム" | ||||
|   test: "テスト" | ||||
|   mobile: "モバイル" | ||||
|   disable-via-mobile: "「モバイルからの投稿」フラグを付けない" | ||||
|   language: "言語" | ||||
|   pick-language: "言語を選択" | ||||
|   recommended: "推奨" | ||||
| @@ -828,21 +868,6 @@ desktop/views/components/settings.password.vue: | ||||
|   enter-new-password-again: "もう一度新しいパスワードを入力してください" | ||||
|   not-match: "新しいパスワードが一致しません" | ||||
|   changed: "パスワードを変更しました" | ||||
| desktop/views/components/settings.profile.vue: | ||||
|   avatar: "アイコン" | ||||
|   choice-avatar: "画像を選択" | ||||
|   name: "名前" | ||||
|   location: "場所" | ||||
|   description: "自己紹介" | ||||
|   birthday: "誕生日" | ||||
|   save: "保存" | ||||
|   locked-account: "アカウントの保護" | ||||
|   is-locked: "フォローを承認制にする" | ||||
|   careful-bot: "Botからのフォローだけ承認制にする" | ||||
|   other: "その他" | ||||
|   is-bot: "このアカウントはBotです" | ||||
|   is-cat: "このアカウントはCatです" | ||||
|   profile-updated: "プロフィールを更新しました" | ||||
| desktop/views/components/sub-note-content.vue: | ||||
|   private: "この投稿は非公開です" | ||||
|   deleted: "この投稿は削除されました" | ||||
| @@ -914,6 +939,8 @@ desktop/views/pages/admin/admin.vue: | ||||
|   drive: "ドライブ" | ||||
|   users: "ユーザー" | ||||
|   update: "更新" | ||||
|   announcements: "お知らせ" | ||||
|   hashtags: "ハッシュタグ" | ||||
| desktop/views/pages/admin/admin.dashboard.vue: | ||||
|   dashboard: "ダッシュボード" | ||||
|   all-users: "全てのユーザー" | ||||
| @@ -921,6 +948,9 @@ desktop/views/pages/admin/admin.dashboard.vue: | ||||
|   all-notes: "全ての投稿" | ||||
|   original-notes: "このインスタンスの投稿" | ||||
|   invite: "招待" | ||||
|   banner-url: "Banner URL" | ||||
|   disableRegistration: "Disable new user registration" | ||||
|   disableLocalTimeline: "Disable the local timeline" | ||||
| desktop/views/pages/admin/admin.suspend-user.vue: | ||||
|   suspend-user: "ユーザーの凍結" | ||||
|   suspend: "凍結" | ||||
| @@ -937,14 +967,23 @@ desktop/views/pages/admin/admin.unverify-user.vue: | ||||
|   unverify-user: "ユーザーの公式アカウント解除" | ||||
|   unverify: "公式アカウントを解除する" | ||||
|   unverified: "公式アカウントを解除しました" | ||||
| desktop/views/pages/admin/admin.announcements.vue: | ||||
|   announcements: "お知らせ" | ||||
| desktop/views/pages/admin/admin.hashtags.vue: | ||||
|   hided-tags: "Hidden Tags" | ||||
| desktop/views/pages/deck/deck.tl-column.vue: | ||||
|   is-media-only: "メディア投稿のみ" | ||||
|   is-media-view: "メディアビュー" | ||||
|   edit: "オプション" | ||||
| desktop/views/pages/deck/deck.note.vue: | ||||
|   reposted-by: "{}がRenote" | ||||
|   private: "この投稿は非公開です" | ||||
|   deleted: "この投稿は削除されました" | ||||
| desktop/views/pages/deck/deck.user-column.vue: | ||||
|   posts: "投稿" | ||||
|   following: "フォロー" | ||||
|   followers: "フォロワー" | ||||
|   images: "画像" | ||||
|   activity: "アクティビティ" | ||||
|   timeline: "タイムライン" | ||||
|   pinned-notes: "ピン留めされた投稿" | ||||
|   push-to-a-list: "リストに追加" | ||||
| desktop/views/pages/stats/stats.vue: | ||||
|   all-users: "全てのユーザー" | ||||
|   original-users: "このインスタンスのユーザー" | ||||
| @@ -997,9 +1036,6 @@ desktop/views/pages/user/user.friends.vue: | ||||
|   no-users: "よく話すユーザーはいません" | ||||
| desktop/views/pages/user/user.vue: | ||||
|   is-suspended: "このユーザーは凍結されています。" | ||||
|   is-remote: "このユーザーはリモートユーザーです。" | ||||
|   view-remote: "正確な情報を見る" | ||||
| desktop/views/pages/user/user.home.vue: | ||||
|   last-used-at: "最終アクセス" | ||||
| desktop/views/pages/user/user.photos.vue: | ||||
|   title: "フォト" | ||||
| @@ -1020,6 +1056,10 @@ desktop/views/pages/user/user.header.vue: | ||||
|   following: "フォロー" | ||||
|   followers: "フォロワー" | ||||
|   is-bot: "このアカウントはBotです" | ||||
|   years-old: "歳" | ||||
|   year: "年" | ||||
|   month: "月" | ||||
|   day: "日" | ||||
| desktop/views/pages/user/user.timeline.vue: | ||||
|   default: "投稿" | ||||
|   with-replies: "投稿と返信" | ||||
| @@ -1221,24 +1261,6 @@ mobile/views/pages/notifications.vue: | ||||
|   read-all: "すべての通知を既読にしますか?" | ||||
| mobile/views/pages/games/reversi.vue: | ||||
|   reversi: "リバーシ" | ||||
| mobile/views/pages/settings/settings.profile.vue: | ||||
|   title: "プロフィール" | ||||
|   name: "名前" | ||||
|   account: "アカウント" | ||||
|   location: "場所" | ||||
|   description: "自己紹介" | ||||
|   birthday: "誕生日" | ||||
|   avatar: "アイコン" | ||||
|   banner: "バナー" | ||||
|   is-cat: "このアカウントはCatです" | ||||
|   is-locked: "フォローを承認制にする" | ||||
|   careful-bot: "Botからのフォローだけ承認制にする" | ||||
|   advanced: "その他" | ||||
|   privacy: "プライバシー" | ||||
|   save: "保存" | ||||
|   saved: "プロフィールを保存しました" | ||||
|   uploading: "アップロード中" | ||||
|   upload-failed: "アップロードに失敗しました" | ||||
| mobile/views/pages/search.vue: | ||||
|   search: "検索" | ||||
|   empty: "「{}」に関する投稿は見つかりませんでした。" | ||||
| @@ -1294,6 +1316,7 @@ mobile/views/pages/settings.vue: | ||||
|   signout: "サインアウト" | ||||
|   sound: "サウンド" | ||||
|   enable-sounds: "サウンドを有効にする" | ||||
|   mark-as-read-all-unread-notes: "すべての投稿を既読にする" | ||||
| mobile/views/pages/user.vue: | ||||
|   follows-you: "フォローされています" | ||||
|   following: "フォロー" | ||||
| @@ -1303,8 +1326,6 @@ mobile/views/pages/user.vue: | ||||
|   timeline: "タイムライン" | ||||
|   media: "メディア" | ||||
|   is-suspended: "このユーザーは凍結されています。" | ||||
|   is-remote: "このユーザーはリモートユーザーです。" | ||||
|   view-remote: "正確な情報を見る" | ||||
| mobile/views/pages/user/home.vue: | ||||
|   recent-notes: "最近の投稿" | ||||
|   images: "画像" | ||||
| @@ -1350,3 +1371,29 @@ docs: | ||||
|       description: "説明" | ||||
| dev/views/index.vue: | ||||
|   manage-apps: "アプリの管理" | ||||
| dev/views/apps.vue: | ||||
|   manage-apps: "アプリを管理" | ||||
|   create-app: "アプリ作成" | ||||
|   app-missing: "アプリなし" | ||||
| dev/views/new-app.vue: | ||||
|   create-app: "アプリケーションの作成" | ||||
|   app-name: "アプリケーション名" | ||||
|   app-name-desc: "あなたのアプリの名称。" | ||||
|   app-name-ex: "ex) Misskey for iOS" | ||||
|   app-overview: "アプリの概要" | ||||
|   app-desc: "あなたのアプリの簡単な説明や紹介。" | ||||
|   app-desc-ex: "ex) Misskey iOSクライアント。" | ||||
|   callback-url: "コールバックURL (オプション)" | ||||
|   callback-url-desc: "ユーザーが認証フォームで認証した際にリダイレクトするURLを設定できます。" | ||||
|   authority: "権限" | ||||
|   authority-desc: "ここで要求した機能だけがAPIからアクセスできます。" | ||||
|   authority-warning: "アプリ作成後も変更できますが、新たな権限を付与する場合、その時点で関連付けられているユーザーキーはすべて無効になります。" | ||||
|   account-read: "アカウントの情報を見る。" | ||||
|   account-write: "アカウントの情報を操作する。" | ||||
|   note-write: "投稿する。" | ||||
|   reaction-write: "リアクションしたりリアクションをキャンセルする。" | ||||
|   following-write: "フォローしたりフォロー解除する。" | ||||
|   drive-read: "ドライブを見る。" | ||||
|   drive-write: "ドライブを操作する。" | ||||
|   notification-read: "通知を見る。" | ||||
|   notification-write: "通知を操作する。" | ||||
|   | ||||
| @@ -25,6 +25,15 @@ common: | ||||
|   application-authorization: "アプリの連携" | ||||
|   close: "閉じる" | ||||
|   do-not-copy-paste: "ここにコードを入力したり張り付けたりしないでください。アカウントが不正利用される可能性があります。" | ||||
|   BSoD: | ||||
|     fatal-error: ":( 致命的な問題が発生しました。" | ||||
|     update-browser-os: "お使いのブラウザ(またはOS)のバージョンを更新すると解決する可能性があります。" | ||||
|     error-code: "エラーコード" | ||||
|     browser-version: "ブラウザ バージョン" | ||||
|     client-version: "クライアント バージョン" | ||||
|     email-support: "問題が解決しない場合は、上記の情報をお書き添えの上 syuilotan@yahoo.co.jp までご連絡ください。" | ||||
|     thanks: "Thank you for using Misskey." | ||||
|  | ||||
|   got-it: "わかった" | ||||
|   customization-tips: | ||||
|     title: "カスタマイズのヒント" | ||||
| @@ -124,6 +133,14 @@ common: | ||||
|  | ||||
|   do-not-use-in-production: 'これは開発ビルドです。本番環境で使用しないでください。' | ||||
|  | ||||
|   is-remote-user: "このユーザー情報はコピーです。" | ||||
|   is-remote-post: "この投稿情報はコピーです。" | ||||
|   view-on-remote: "正確な情報を見る" | ||||
|  | ||||
|   error: | ||||
|     title: '問題が発生しました' | ||||
|     retry: 'やり直す' | ||||
|  | ||||
|   reversi: | ||||
|     drawn: "引き分け" | ||||
|     my-turn: "あなたのターンです" | ||||
| @@ -182,6 +199,8 @@ common: | ||||
|     stack-left: "左に重ねる" | ||||
|     pop-right: "右に出す" | ||||
|  | ||||
|   dev: "アプリの作成に失敗しました。再度お試しください。" | ||||
|  | ||||
| auth/views/form.vue: | ||||
|   share-access: "<i>{{ app.name }}</i>があなたのアカウントにアクセスすることを<b>許可</b>しますか?" | ||||
|   permission-ask: "このアプリは次の権限を要求しています:" | ||||
| @@ -456,6 +475,26 @@ common/views/components/trends.vue: | ||||
|   count: "{}人が投稿" | ||||
|   empty: "トレンドなし" | ||||
|  | ||||
| common/views/components/profile-editor.vue: | ||||
|   title: "プロフィール" | ||||
|   name: "名前" | ||||
|   account: "アカウント" | ||||
|   location: "場所" | ||||
|   description: "自己紹介" | ||||
|   birthday: "誕生日" | ||||
|   avatar: "アイコン" | ||||
|   banner: "バナー" | ||||
|   is-cat: "このアカウントはCatです" | ||||
|   is-bot: "このアカウントはBotです" | ||||
|   is-locked: "フォローを承認制にする" | ||||
|   careful-bot: "Botからのフォローだけ承認制にする" | ||||
|   advanced: "その他" | ||||
|   privacy: "プライバシー" | ||||
|   save: "保存" | ||||
|   saved: "プロフィールを保存しました" | ||||
|   uploading: "アップロード中" | ||||
|   upload-failed: "アップロードに失敗しました" | ||||
|  | ||||
| common/views/widgets/broadcast.vue: | ||||
|   fetching: "確認中" | ||||
|   no-broadcasts: "お知らせはありません" | ||||
| @@ -567,6 +606,9 @@ desktop/views/components/charts.vue: | ||||
|   drive: "ドライブ" | ||||
|   network: "ネットワーク" | ||||
|   charts: | ||||
|     federation: "フェデレーション" | ||||
|     federation-instances: "インスタンスの増減" | ||||
|     federation-instances-total: "インスタンスの積算" | ||||
|     notes: "投稿の増減 (統合)" | ||||
|     local-notes: "投稿の増減 (ローカル)" | ||||
|     remote-notes: "投稿の増減 (リモート)" | ||||
| @@ -718,7 +760,7 @@ desktop/views/components/note-detail.vue: | ||||
|   renote: "Renote" | ||||
|   add-reaction: "リアクション" | ||||
|  | ||||
| desktop/views/components/notes.note.vue: | ||||
| desktop/views/components/note.vue: | ||||
|   reposted-by: "{}がRenote" | ||||
|   reply: "返信" | ||||
|   renote: "Renote" | ||||
| @@ -814,9 +856,13 @@ desktop/views/components/settings.vue: | ||||
|   advanced: "詳細設定" | ||||
|   api-via-stream: "ストリームを経由したAPIリクエスト" | ||||
|   api-via-stream-desc: "この設定をオンにすると、websocket接続を経由してAPIリクエストが行われます(パフォーマンス向上が期待できます)。オフにすると、ネイティブの fetch APIが利用されます。この設定はこのデバイスのみ有効です。" | ||||
|   deck-nav: "デッキ内ナビゲーション" | ||||
|   deck-nav-desc: "デッキを使用しているとき、ナビゲーションが発生する際にページ遷移を行わずに一時的なカラムで受けるようにします。" | ||||
|   deck-default: "デッキをデフォルトのUIにする" | ||||
|  | ||||
|   display: "デザインと表示" | ||||
|   customize: "ホームをカスタマイズ" | ||||
|   wallpaper: "壁紙" | ||||
|   choose-wallpaper: "壁紙を選択" | ||||
|   delete-wallpaper: "壁紙を削除" | ||||
|   dark-mode: "ダークモード" | ||||
| @@ -828,10 +874,14 @@ desktop/views/components/settings.vue: | ||||
|   suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する" | ||||
|   show-clock-on-header: "右上に時計を表示する" | ||||
|   show-reply-target: "リプライ先を表示する" | ||||
|   timeline: "タイムライン" | ||||
|   show-my-renotes: "自分の行ったRenoteをタイムラインに表示する" | ||||
|   show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する" | ||||
|   show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する" | ||||
|   show-maps: "マップの自動展開" | ||||
|   deck-column-align: "デッキのカラムの位置" | ||||
|   deck-column-align-center: "中央" | ||||
|   deck-column-align-left: "左" | ||||
|  | ||||
|   sound: "サウンド" | ||||
|   enable-sounds: "サウンドを有効にする" | ||||
| @@ -839,9 +889,6 @@ desktop/views/components/settings.vue: | ||||
|   volume: "ボリューム" | ||||
|   test: "テスト" | ||||
|  | ||||
|   mobile: "モバイル" | ||||
|   disable-via-mobile: "「モバイルからの投稿」フラグを付けない" | ||||
|  | ||||
|   language: "言語" | ||||
|   pick-language: "言語を選択" | ||||
|   recommended: "推奨" | ||||
| @@ -933,22 +980,6 @@ desktop/views/components/settings.password.vue: | ||||
|   not-match: "新しいパスワードが一致しません" | ||||
|   changed: "パスワードを変更しました" | ||||
|  | ||||
| desktop/views/components/settings.profile.vue: | ||||
|   avatar: "アイコン" | ||||
|   choice-avatar: "画像を選択" | ||||
|   name: "名前" | ||||
|   location: "場所" | ||||
|   description: "自己紹介" | ||||
|   birthday: "誕生日" | ||||
|   save: "保存" | ||||
|   locked-account: "アカウントの保護" | ||||
|   is-locked: "フォローを承認制にする" | ||||
|   careful-bot: "Botからのフォローだけ承認制にする" | ||||
|   other: "その他" | ||||
|   is-bot: "このアカウントはBotです" | ||||
|   is-cat: "このアカウントはCatです" | ||||
|   profile-updated: "プロフィールを更新しました" | ||||
|  | ||||
| desktop/views/components/sub-note-content.vue: | ||||
|   private: "この投稿は非公開です" | ||||
|   deleted: "この投稿は削除されました" | ||||
| @@ -1035,6 +1066,8 @@ desktop/views/pages/admin/admin.vue: | ||||
|   drive: "ドライブ" | ||||
|   users: "ユーザー" | ||||
|   update: "更新" | ||||
|   announcements: "お知らせ" | ||||
|   hashtags: "ハッシュタグ" | ||||
|  | ||||
| desktop/views/pages/admin/admin.dashboard.vue: | ||||
|   dashboard: "ダッシュボード" | ||||
| @@ -1043,6 +1076,9 @@ desktop/views/pages/admin/admin.dashboard.vue: | ||||
|   all-notes: "全ての投稿" | ||||
|   original-notes: "このインスタンスの投稿" | ||||
|   invite: "招待" | ||||
|   banner-url: "Banner URL" | ||||
|   disableRegistration: "Disable new user registration" | ||||
|   disableLocalTimeline: "Disable the local timeline" | ||||
|  | ||||
| desktop/views/pages/admin/admin.suspend-user.vue: | ||||
|   suspend-user: "ユーザーの凍結" | ||||
| @@ -1064,15 +1100,26 @@ desktop/views/pages/admin/admin.unverify-user.vue: | ||||
|   unverify: "公式アカウントを解除する" | ||||
|   unverified: "公式アカウントを解除しました" | ||||
|  | ||||
| desktop/views/pages/admin/admin.announcements.vue: | ||||
|   announcements: "お知らせ" | ||||
|  | ||||
| desktop/views/pages/admin/admin.hashtags.vue: | ||||
|   hided-tags: "Hidden Tags" | ||||
|  | ||||
| desktop/views/pages/deck/deck.tl-column.vue: | ||||
|   is-media-only: "メディア投稿のみ" | ||||
|   is-media-view: "メディアビュー" | ||||
|   edit: "オプション" | ||||
|  | ||||
| desktop/views/pages/deck/deck.note.vue: | ||||
|   reposted-by: "{}がRenote" | ||||
|   private: "この投稿は非公開です" | ||||
|   deleted: "この投稿は削除されました" | ||||
| desktop/views/pages/deck/deck.user-column.vue: | ||||
|   posts: "投稿" | ||||
|   following: "フォロー" | ||||
|   followers: "フォロワー" | ||||
|   images: "画像" | ||||
|   activity: "アクティビティ" | ||||
|   timeline: "タイムライン" | ||||
|   pinned-notes: "ピン留めされた投稿" | ||||
|   push-to-a-list: "リストに追加" | ||||
|  | ||||
| desktop/views/pages/stats/stats.vue: | ||||
|   all-users: "全てのユーザー" | ||||
| @@ -1139,10 +1186,6 @@ desktop/views/pages/user/user.friends.vue: | ||||
|  | ||||
| desktop/views/pages/user/user.vue: | ||||
|   is-suspended: "このユーザーは凍結されています。" | ||||
|   is-remote: "このユーザーはリモートユーザーです。" | ||||
|   view-remote: "正確な情報を見る" | ||||
|  | ||||
| desktop/views/pages/user/user.home.vue: | ||||
|   last-used-at: "最終アクセス" | ||||
|  | ||||
| desktop/views/pages/user/user.photos.vue: | ||||
| @@ -1166,6 +1209,10 @@ desktop/views/pages/user/user.header.vue: | ||||
|   following: "フォロー" | ||||
|   followers: "フォロワー" | ||||
|   is-bot: "このアカウントはBotです" | ||||
|   years-old: "歳" | ||||
|   year: "年" | ||||
|   month: "月" | ||||
|   day: "日" | ||||
|  | ||||
| desktop/views/pages/user/user.timeline.vue: | ||||
|   default: "投稿" | ||||
| @@ -1417,25 +1464,6 @@ mobile/views/pages/notifications.vue: | ||||
| mobile/views/pages/games/reversi.vue: | ||||
|   reversi: "リバーシ" | ||||
|  | ||||
| mobile/views/pages/settings/settings.profile.vue: | ||||
|   title: "プロフィール" | ||||
|   name: "名前" | ||||
|   account: "アカウント" | ||||
|   location: "場所" | ||||
|   description: "自己紹介" | ||||
|   birthday: "誕生日" | ||||
|   avatar: "アイコン" | ||||
|   banner: "バナー" | ||||
|   is-cat: "このアカウントはCatです" | ||||
|   is-locked: "フォローを承認制にする" | ||||
|   careful-bot: "Botからのフォローだけ承認制にする" | ||||
|   advanced: "その他" | ||||
|   privacy: "プライバシー" | ||||
|   save: "保存" | ||||
|   saved: "プロフィールを保存しました" | ||||
|   uploading: "アップロード中" | ||||
|   upload-failed: "アップロードに失敗しました" | ||||
|  | ||||
| mobile/views/pages/search.vue: | ||||
|   search: "検索" | ||||
|   empty: "「{}」に関する投稿は見つかりませんでした。" | ||||
| @@ -1493,6 +1521,7 @@ mobile/views/pages/settings.vue: | ||||
|   signout: "サインアウト" | ||||
|   sound: "サウンド" | ||||
|   enable-sounds: "サウンドを有効にする" | ||||
|   mark-as-read-all-unread-notes: "すべての投稿を既読にする" | ||||
|  | ||||
| mobile/views/pages/user.vue: | ||||
|   follows-you: "フォローされています" | ||||
| @@ -1503,8 +1532,6 @@ mobile/views/pages/user.vue: | ||||
|   timeline: "タイムライン" | ||||
|   media: "メディア" | ||||
|   is-suspended: "このユーザーは凍結されています。" | ||||
|   is-remote: "このユーザーはリモートユーザーです。" | ||||
|   view-remote: "正確な情報を見る" | ||||
|  | ||||
| mobile/views/pages/user/home.vue: | ||||
|   recent-notes: "最近の投稿" | ||||
| @@ -1558,3 +1585,31 @@ docs: | ||||
|  | ||||
| dev/views/index.vue: | ||||
|   manage-apps: "アプリの管理" | ||||
|  | ||||
| dev/views/apps.vue: | ||||
|   manage-apps: "アプリを管理" | ||||
|   create-app: "アプリ作成" | ||||
|   app-missing: "アプリなし" | ||||
|  | ||||
| dev/views/new-app.vue: | ||||
|   create-app: "アプリケーションの作成" | ||||
|   app-name: "アプリケーション名" | ||||
|   app-name-desc: "あなたのアプリの名称。" | ||||
|   app-name-ex: "ex) Misskey for iOS" | ||||
|   app-overview: "アプリの概要" | ||||
|   app-desc: "あなたのアプリの簡単な説明や紹介。" | ||||
|   app-desc-ex: "ex) Misskey iOSクライアント。" | ||||
|   callback-url: "コールバックURL (オプション)" | ||||
|   callback-url-desc: "ユーザーが認証フォームで認証した際にリダイレクトするURLを設定できます。" | ||||
|   authority: "権限" | ||||
|   authority-desc: "ここで要求した機能だけがAPIからアクセスできます。" | ||||
|   authority-warning: "アプリ作成後も変更できますが、新たな権限を付与する場合、その時点で関連付けられているユーザーキーはすべて無効になります。" | ||||
|   account-read: "アカウントの情報を見る。" | ||||
|   account-write: "アカウントの情報を操作する。" | ||||
|   note-write: "投稿する。" | ||||
|   reaction-write: "リアクションしたりリアクションをキャンセルする。" | ||||
|   following-write: "フォローしたりフォロー解除する。" | ||||
|   drive-read: "ドライブを見る。" | ||||
|   drive-write: "ドライブを操作する。" | ||||
|   notification-read: "通知を見る。" | ||||
|   notification-write: "通知を操作する。" | ||||
|   | ||||
| @@ -17,7 +17,7 @@ common: | ||||
|     ui: "インターフェイス" | ||||
|     ui-desc: "このUIええ言うてたで、知らんけど。あんたの好みのUIなんて知ったこっちゃない。Misskeyは好きにいじれるからな、レイアウトやデザイン変えたり、色んなウィジェットひっつけたりして、あんただけのMisskey作って楽しんでな!" | ||||
|     drive: "ドライブ" | ||||
|     drive-desc: "「こないだの画像、どこやったかな…また投稿したいんやけど…」「さっきのファイルあのフォルダに直しといて」そんなこと言わんとって。Misskeyはもとからドライブ機能持っとるさかい、心配あらへん。ファイルの「わけわけ」したってな。" | ||||
|     drive-desc: "「こないだの画像、どこやったかな……また投稿したいんやけど……」「さっきのファイルあのフォルダに直しといて」そんなこと言わんとって。Misskeyはもとからドライブ機能持っとるさかい、心配あらへん。ファイルの「わけわけ」したってな。" | ||||
|     outro: "Misskeyの機能は無限大や!知らんけど。知らん言うとるやんけ、あんたが見に行けや!Misskeyは分散型SNSやから、ここがあかんくても他がある。阪神でもオリックスでもワイは応援するで!" | ||||
|   adblock: | ||||
|     detected: "広告ブロッカーを無効にしてや" | ||||
| @@ -25,6 +25,14 @@ common: | ||||
|   application-authorization: "アプリの連携" | ||||
|   close: "さいなら" | ||||
|   do-not-copy-paste: "ここにコードを入力したり張り付けたりせんといてください。アカウントが不正利用されるかも分からん。知らんけど。" | ||||
|   BSoD: | ||||
|     fatal-error: "あかん、やってもうたわ… (致命的なエラー" | ||||
|     update-browser-os: "ブラウザ(またはOS)のバージョン更新してくれへん?なおるかもしれんわ。" | ||||
|     error-code: "エラーコード" | ||||
|     browser-version: "ブラウザ バージョン" | ||||
|     client-version: "クライアント バージョン" | ||||
|     email-support: "それでもあかん?せやったら syuilotan@yahoo.co.jp に連絡してや!" | ||||
|     thanks: "Thank you おおきに。Misskey" | ||||
|   got-it: "ほい" | ||||
|   customization-tips: | ||||
|     title: "カスタマイズのヒント" | ||||
| @@ -115,6 +123,12 @@ common: | ||||
|   reduce-motion: "UI、動き過ぎや、静かにしてや" | ||||
|   this-setting-is-this-device-only: "このデバイスのみ" | ||||
|   do-not-use-in-production: '開発ビルドや。本番環境で使わんといて!知らんで!' | ||||
|   is-remote-user: "このユーザー情報はコピーです。" | ||||
|   is-remote-post: "この投稿情報はコピーです。" | ||||
|   view-on-remote: "ちゃんとした情報見せてや!" | ||||
|   error: | ||||
|     title: '問題が起こったわ' | ||||
|     retry: 'もっぺん' | ||||
|   reversi: | ||||
|     drawn: "おあいこ" | ||||
|     my-turn: "あんさんのターンや" | ||||
| @@ -170,6 +184,7 @@ common: | ||||
|     rename: "名前を変更や!" | ||||
|     stack-left: "左に重ねんで!" | ||||
|     pop-right: "右に出すで!" | ||||
|   dev: "アプリの作成あかんかったわ。もっぺんやってみて。" | ||||
| auth/views/form.vue: | ||||
|   share-access: "<i>{{ app.name }}</i>があんさんのアカウントにアクセスすんのを<b>許可</b>してもええか?" | ||||
|   permission-ask: "このアプリは次の権限を要求してんで:" | ||||
| @@ -369,7 +384,7 @@ common/views/components/signup.vue: | ||||
|   invitation-code: "招待コード" | ||||
|   invitation-info: "招待コードをもっとらんのやったら、<a href=\"{}\">管理者</a>まで連絡してや。" | ||||
|   username: "ユーザー名" | ||||
|   checking: "確認中や…" | ||||
|   checking: "確認中や……" | ||||
|   available: "使えるで" | ||||
|   unavailable: "もう使われとるで" | ||||
|   error: "通信あかんわ" | ||||
| @@ -416,6 +431,25 @@ common/views/components/visibility-chooser.vue: | ||||
| common/views/components/trends.vue: | ||||
|   count: "{}人が投稿" | ||||
|   empty: "流行は自分で作るんや" | ||||
| common/views/components/profile-editor.vue: | ||||
|   title: "プロフィール" | ||||
|   name: "名前" | ||||
|   account: "アカウント" | ||||
|   location: "場所" | ||||
|   description: "自己紹介" | ||||
|   birthday: "誕生日" | ||||
|   avatar: "アイコン" | ||||
|   banner: "バナー" | ||||
|   is-cat: "このアカウントはCatやで" | ||||
|   is-bot: "このアカウントはBotやで" | ||||
|   is-locked: "他人のフォローは許可してからや!" | ||||
|   careful-bot: "Botからのフォローだけは許可制や" | ||||
|   advanced: "その他" | ||||
|   privacy: "プライバシーってなんや?オカンの年齢か?" | ||||
|   save: "保存" | ||||
|   saved: "プロフィールを保存したで" | ||||
|   uploading: "アップロードしとります" | ||||
|   upload-failed: "これアップロードでけへんわ" | ||||
| common/views/widgets/broadcast.vue: | ||||
|   fetching: "見てみるわ…" | ||||
|   no-broadcasts: "お知らせはあらへんで" | ||||
| @@ -491,10 +525,10 @@ desktop: | ||||
|   choose-avatar: "アバターにする画像選んでや" | ||||
|   invalid-filetype: "この形式のファイル無理やねん" | ||||
| desktop/views/components/activity.chart.vue: | ||||
|   total: "黒いの… 全部" | ||||
|   notes: "青いの… 投稿" | ||||
|   replies: "赤いの… 返信" | ||||
|   renotes: "みどり… Renotes" | ||||
|   total: "黒いの ... 全部" | ||||
|   notes: "青いの ... 投稿" | ||||
|   replies: "赤いの ... 返信" | ||||
|   renotes: "碧いの ... Renotes" | ||||
| desktop/views/components/activity.vue: | ||||
|   title: "アクティビティ" | ||||
|   toggle: "表示変える" | ||||
| @@ -552,7 +586,7 @@ desktop/views/components/drive.file.vue: | ||||
|     unmark-as-sensitive: "やっぱ見せたるわ" | ||||
|     copy-url: "URLをコピー" | ||||
|     download: "ダウンロード" | ||||
|     else-files: "もっとあるで…" | ||||
|     else-files: "まだあんで..." | ||||
|     set-as-avatar: "アイコンにする" | ||||
|     set-as-banner: "バナーにする" | ||||
|     open-in-app: "アプリで開く" | ||||
| @@ -586,7 +620,7 @@ desktop/views/components/drive.vue: | ||||
|   url-upload: "URLアップロード" | ||||
|   url-of-file: "このURLのファイルをアップロードしたいねん" | ||||
|   url-upload-requested: "アップロードしたい言うといたで" | ||||
|   may-take-time: "アップロード終わるまで時間かかるわ、知らんけど。たこ焼き何個食べれるやろか…" | ||||
|   may-take-time: "アップロード終わるんにちょい時間かかるかもしれへんわ。" | ||||
|   create-folder: "フォルダー作成" | ||||
|   folder-name: "フォルダー名" | ||||
|   contextmenu: | ||||
| @@ -616,7 +650,7 @@ desktop/views/components/following.vue: | ||||
| desktop/views/components/friends-maker.vue: | ||||
|   title: "おもろそうやな:" | ||||
|   empty: "おもろいユーザー居らんかったわ" | ||||
|   fetching: "読みこんどるで…" | ||||
|   fetching: "読み込んどります" | ||||
|   refresh: "もっとあるやろ!" | ||||
|   close: "さいなら" | ||||
| desktop/views/components/game-window.vue: | ||||
| @@ -640,7 +674,7 @@ desktop/views/components/note-detail.vue: | ||||
|   location: "ここおるで:" | ||||
|   renote: "Renote" | ||||
|   add-reaction: "リアクション" | ||||
| desktop/views/components/notes.note.vue: | ||||
| desktop/views/components/note.vue: | ||||
|   reposted-by: "{}がRenote" | ||||
|   reply: "返す" | ||||
|   renote: "Renote" | ||||
| @@ -688,11 +722,11 @@ desktop/views/components/post-form-window.vue: | ||||
|   note: "新規投稿" | ||||
|   reply: "返す" | ||||
|   attaches: "添付: {}メディア" | ||||
|   uploading-media: "{}個のメディアを上げてるで…" | ||||
|   uploading-media: "{}個のメディアを上げとんねん……" | ||||
| desktop/views/components/progress-dialog.vue: | ||||
|   waiting: "待っとる" | ||||
| desktop/views/components/renote-form.vue: | ||||
|   quote: "持ってくる…" | ||||
|   quote: "取ってくる……" | ||||
|   cancel: "やめとくわ" | ||||
|   renote: "Renote" | ||||
|   reposting: "やっとります..." | ||||
| @@ -726,8 +760,12 @@ desktop/views/components/settings.vue: | ||||
|   advanced: "もっと設定" | ||||
|   api-via-stream: "ストリームを経由したAPIリクエスト" | ||||
|   api-via-stream-desc: "この設定をオンにすると、WebSocket接続を経由してAPIリクエストが行われんで(パフォーマンス向上するかも、知らんけど)。オフにすると、ネイティブの fetch API が利用されるで。この設定はこのデバイスのみ有効やで。" | ||||
|   deck-nav: "デッキ内ナビゲーション" | ||||
|   deck-nav-desc: "デッキを使うとるとき、ナビゲーションが発生するときにページ移動せんで、一時的なカラムで受けれるようにするで" | ||||
|   deck-default: "デッキをデフォルトのUIにする" | ||||
|   display: "見た感じ" | ||||
|   customize: "ホームをカスタマイズ" | ||||
|   wallpaper: "壁紙" | ||||
|   choose-wallpaper: "壁紙選ぶ" | ||||
|   delete-wallpaper: "壁紙ほかす" | ||||
|   dark-mode: "夜にすんで" | ||||
| @@ -739,17 +777,19 @@ desktop/views/components/settings.vue: | ||||
|   suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示すんで" | ||||
|   show-clock-on-header: "右上をカリヨン広場にする(時計表示)" | ||||
|   show-reply-target: "どこにリプライするんや見せて" | ||||
|   timeline: "タイムライン" | ||||
|   show-my-renotes: "わしのRenoteもタイムライン載せてくれや" | ||||
|   show-renoted-my-notes: "わしのRenoteもタイムライン載せてくれや" | ||||
|   show-local-renotes: "ローカル投稿のRenoteも見たいんや" | ||||
|   show-maps: "地図勝手にバァーって開いてくれ" | ||||
|   deck-column-align: "デッキのカラムの位置" | ||||
|   deck-column-align-center: "真ん中" | ||||
|   deck-column-align-left: "左" | ||||
|   sound: "サウンド" | ||||
|   enable-sounds: "サウンド鳴らす" | ||||
|   enable-sounds-desc: "投稿やメッセージもろたとき、音鳴らしたるわ。大丈夫や、この設定はブラウザが覚えてくれとる。" | ||||
|   volume: "ボリューム" | ||||
|   test: "テスト" | ||||
|   mobile: "モバイル" | ||||
|   disable-via-mobile: "「モバイルからの投稿」フラグなんて要らんわ" | ||||
|   language: "言語" | ||||
|   pick-language: "言語選んでや" | ||||
|   recommended: "おすすめ" | ||||
| @@ -768,7 +808,7 @@ desktop/views/components/settings.vue: | ||||
|   update: "Misskey Update" | ||||
|   version: "バージョン:" | ||||
|   latest-version: "最新のバージョン:" | ||||
|   update-checking: "アップデートはあらへんか…" | ||||
|   update-checking: "アップデートはあらへんか……" | ||||
|   do-update: "アップデートあるか見てみる" | ||||
|   update-settings: "もっと設定" | ||||
|   prevent-update: "アップデートしたないわ、また今度や(やめときや)" | ||||
| @@ -828,21 +868,6 @@ desktop/views/components/settings.password.vue: | ||||
|   enter-new-password-again: "もういっぺんさらのパスワードを入れてや" | ||||
|   not-match: "パスワードがおうとらん" | ||||
|   changed: "パスワード変えたわ" | ||||
| desktop/views/components/settings.profile.vue: | ||||
|   avatar: "アイコン" | ||||
|   choice-avatar: "画像選んでや" | ||||
|   name: "名前" | ||||
|   location: "場所" | ||||
|   description: "ワイのこと" | ||||
|   birthday: "誕生日" | ||||
|   save: "保存" | ||||
|   locked-account: "アカウント守る" | ||||
|   is-locked: "他人のフォローは許可してからや!" | ||||
|   careful-bot: "Botからのフォローだけ承認制にする" | ||||
|   other: "その他" | ||||
|   is-bot: "このアカウントはBotやで" | ||||
|   is-cat: "このアカウントはCatやで" | ||||
|   profile-updated: "プロフィールを更新したで" | ||||
| desktop/views/components/sub-note-content.vue: | ||||
|   private: "この投稿は見せられへんわ" | ||||
|   deleted: "この投稿なんか無くなってもうたわ" | ||||
| @@ -903,7 +928,7 @@ desktop/views/components/users-list.vue: | ||||
|   all: "すべて" | ||||
|   iknow: "知っとる" | ||||
|   load-more: "もっと" | ||||
|   fetching: "読みこんどるで…" | ||||
|   fetching: "読み込んどります" | ||||
| desktop/views/components/users-list-item.vue: | ||||
|   followed: "フォローされとるで" | ||||
| desktop/views/components/window.vue: | ||||
| @@ -914,6 +939,8 @@ desktop/views/pages/admin/admin.vue: | ||||
|   drive: "ドライブ" | ||||
|   users: "ユーザー" | ||||
|   update: "更新" | ||||
|   announcements: "お知らせ" | ||||
|   hashtags: "ハッシュタグ" | ||||
| desktop/views/pages/admin/admin.dashboard.vue: | ||||
|   dashboard: "ダッシュボード" | ||||
|   all-users: "知り合い全員や" | ||||
| @@ -921,6 +948,9 @@ desktop/views/pages/admin/admin.dashboard.vue: | ||||
|   all-notes: "全ての投稿" | ||||
|   original-notes: "このインスタンスの投稿" | ||||
|   invite: "来てや" | ||||
|   banner-url: "Banner URL" | ||||
|   disableRegistration: "Disable new user registration" | ||||
|   disableLocalTimeline: "Disable the local timeline" | ||||
| desktop/views/pages/admin/admin.suspend-user.vue: | ||||
|   suspend-user: "ユーザーの凍結" | ||||
|   suspend: "凍結" | ||||
| @@ -937,25 +967,34 @@ desktop/views/pages/admin/admin.unverify-user.vue: | ||||
|   unverify-user: "ユーザーの公式アカウントにせーへん" | ||||
|   unverify: "公式アカウントにはさせへんで" | ||||
|   unverified: "公式アカウントを解除したで" | ||||
| desktop/views/pages/admin/admin.announcements.vue: | ||||
|   announcements: "お知らせ" | ||||
| desktop/views/pages/admin/admin.hashtags.vue: | ||||
|   hided-tags: "Hidden Tags" | ||||
| desktop/views/pages/deck/deck.tl-column.vue: | ||||
|   is-media-only: "メディア投稿だけや" | ||||
|   is-media-view: "メディアビュー" | ||||
|   edit: "オプション" | ||||
| desktop/views/pages/deck/deck.note.vue: | ||||
|   reposted-by: "{}がRenote" | ||||
|   private: "この投稿は見せられへんわ" | ||||
|   deleted: "この投稿なんか無くなってもうたわ" | ||||
| desktop/views/pages/deck/deck.user-column.vue: | ||||
|   posts: "投稿" | ||||
|   following: "フォロー" | ||||
|   followers: "フォロワー" | ||||
|   images: "画像" | ||||
|   activity: "アクティビティ" | ||||
|   timeline: "タイムライン" | ||||
|   pinned-notes: "ピン留めされた投稿" | ||||
|   push-to-a-list: "リストに追加" | ||||
| desktop/views/pages/stats/stats.vue: | ||||
|   all-users: "全てのユーザー" | ||||
|   original-users: "ここの人らだけ" | ||||
|   all-notes: "全ての投稿" | ||||
|   original-notes: "このインスタンスの投稿" | ||||
| desktop/views/pages/welcome.vue: | ||||
|   about: "もっと…" | ||||
|   about: "もうちょい……" | ||||
|   gotit: "ほい" | ||||
|   signin: "サインイン" | ||||
|   signup: "サインアップ" | ||||
|   signin-button: "サインイン中…" | ||||
|   signin-button: "やっとる" | ||||
|   signup-button: "サインアップ" | ||||
|   timeline: "タイムライン" | ||||
|   announcements: "知っときや" | ||||
| @@ -989,21 +1028,18 @@ desktop/views/pages/user-list.users.vue: | ||||
|   username: "ユーザー名" | ||||
| desktop/views/pages/user/user.followers-you-know.vue: | ||||
|   title: "知っとるフォロワー" | ||||
|   loading: "読み込んどる…" | ||||
|   loading: "読み込んどります" | ||||
|   no-users: "フォロワー全員知らんわ" | ||||
| desktop/views/pages/user/user.friends.vue: | ||||
|   title: "よう話すツレ" | ||||
|   loading: "読み込んどる…" | ||||
|   loading: "読み込んどります" | ||||
|   no-users: "よう話すツレは居らん" | ||||
| desktop/views/pages/user/user.vue: | ||||
|   is-suspended: "このユーザーはあかんわ。凍結されとる。" | ||||
|   is-remote: "このユーザーはリモートユーザーや。" | ||||
|   view-remote: "ちゃんとした情報を見る" | ||||
| desktop/views/pages/user/user.home.vue: | ||||
|   last-used-at: "最後いつ来た?" | ||||
|   last-used-at: "最終アクセス" | ||||
| desktop/views/pages/user/user.photos.vue: | ||||
|   title: "写真" | ||||
|   loading: "読み込んどる…" | ||||
|   loading: "読み込んどります" | ||||
|   no-photos: "写真はあらへんで" | ||||
| desktop/views/pages/user/user.profile.vue: | ||||
|   follows-you: "フォローされとるで" | ||||
| @@ -1020,6 +1056,10 @@ desktop/views/pages/user/user.header.vue: | ||||
|   following: "フォロー" | ||||
|   followers: "フォロワー" | ||||
|   is-bot: "このアカウントはBotや" | ||||
|   years-old: "歳" | ||||
|   year: "年" | ||||
|   month: "月" | ||||
|   day: "日" | ||||
| desktop/views/pages/user/user.timeline.vue: | ||||
|   default: "投稿" | ||||
|   with-replies: "投稿と返信" | ||||
| @@ -1096,7 +1136,7 @@ mobile/views/components/follow-button.vue: | ||||
| mobile/views/components/friends-maker.vue: | ||||
|   title: "おもろそうやな" | ||||
|   empty: "おすすめのユーザーはおらん。" | ||||
|   fetching: "読みこんどるで…" | ||||
|   fetching: "読み込んどります" | ||||
|   refresh: "もっとあるやろ!" | ||||
|   close: "さいなら" | ||||
| mobile/views/components/note.vue: | ||||
| @@ -1221,24 +1261,6 @@ mobile/views/pages/notifications.vue: | ||||
|   read-all: "通知全部読んだか?" | ||||
| mobile/views/pages/games/reversi.vue: | ||||
|   reversi: "リバーシ" | ||||
| mobile/views/pages/settings/settings.profile.vue: | ||||
|   title: "プロフィール" | ||||
|   name: "名前" | ||||
|   account: "アカウント" | ||||
|   location: "場所" | ||||
|   description: "ワイのこと" | ||||
|   birthday: "誕生日" | ||||
|   avatar: "アイコン" | ||||
|   banner: "バナー" | ||||
|   is-cat: "このアカウントはCatや" | ||||
|   is-locked: "他人のフォローは許可してからや!" | ||||
|   careful-bot: "Botからのフォローだけ承認制にする" | ||||
|   advanced: "その他" | ||||
|   privacy: "プライバシーってなんや?オカンの年齢か?" | ||||
|   save: "保存" | ||||
|   saved: "プロフィールを保存したで" | ||||
|   uploading: "アップロードしとるで…" | ||||
|   upload-failed: "これアップロードでけへんわ" | ||||
| mobile/views/pages/search.vue: | ||||
|   search: "探す" | ||||
|   empty: "ワイは「{}」なんて投稿知らんわ、無いんちゃう?知らんけど。" | ||||
| @@ -1284,7 +1306,7 @@ mobile/views/pages/settings.vue: | ||||
|   update: "あんたのMisskeyいつのや?" | ||||
|   version: "バージョン:" | ||||
|   latest-version: "いっちゃん新しいやつ:" | ||||
|   update-checking: "アップデートはあらへんか…" | ||||
|   update-checking: "アップデートあるか見とるで" | ||||
|   check-for-updates: "アップデートあるんかな?" | ||||
|   no-updates: "アップデートあらへんわ" | ||||
|   no-updates-desc: "つこてるMisskeyは最新や!" | ||||
| @@ -1294,6 +1316,7 @@ mobile/views/pages/settings.vue: | ||||
|   signout: "さいなら" | ||||
|   sound: "サウンド" | ||||
|   enable-sounds: "サウンド鳴らす" | ||||
|   mark-as-read-all-unread-notes: "すべての投稿を既読にする" | ||||
| mobile/views/pages/user.vue: | ||||
|   follows-you: "フォローされとるで" | ||||
|   following: "フォロー" | ||||
| @@ -1303,8 +1326,6 @@ mobile/views/pages/user.vue: | ||||
|   timeline: "タイムライン" | ||||
|   media: "メディア" | ||||
|   is-suspended: "このユーザーはあかんわ。凍結されとる。" | ||||
|   is-remote: "このユーザーは東京とかそこらへんのリモートユーザーや。" | ||||
|   view-remote: "ちゃんとした情報を見る" | ||||
| mobile/views/pages/user/home.vue: | ||||
|   recent-notes: "最近儲かりまっか?" | ||||
|   images: "画像" | ||||
| @@ -1315,16 +1336,16 @@ mobile/views/pages/user/home.vue: | ||||
|   followers-you-know: "知っとるフォロワー" | ||||
|   last-used-at: "最後いつ来た?" | ||||
| mobile/views/pages/user/home.followers-you-know.vue: | ||||
|   loading: "読み込んどる…" | ||||
|   loading: "読み込んどります" | ||||
|   no-users: "知っとるユーザーは居らん" | ||||
| mobile/views/pages/user/home.friends.vue: | ||||
|   loading: "読み込んどる…" | ||||
|   loading: "読み込んどります" | ||||
|   no-users: "よう話すユーザーは居らん" | ||||
| mobile/views/pages/user/home.notes.vue: | ||||
|   loading: "読み込んどる…" | ||||
|   loading: "読み込んどります" | ||||
|   no-notes: "投稿はあらへん" | ||||
| mobile/views/pages/user/home.photos.vue: | ||||
|   loading: "読み込んどる…" | ||||
|   loading: "読み込んどります" | ||||
|   no-photos: "写真はあらへんで" | ||||
| docs: | ||||
|   edit-this-page-on-github: "間違いや改善点を見つけましたか?" | ||||
| @@ -1350,3 +1371,29 @@ docs: | ||||
|       description: "説明" | ||||
| dev/views/index.vue: | ||||
|   manage-apps: "アプリの管理" | ||||
| dev/views/apps.vue: | ||||
|   manage-apps: "アプリを管理" | ||||
|   create-app: "アプリ作成" | ||||
|   app-missing: "アプリなし" | ||||
| dev/views/new-app.vue: | ||||
|   create-app: "アプリケーションの作成" | ||||
|   app-name: "アプリケーション名" | ||||
|   app-name-desc: "あなたのアプリの名称。" | ||||
|   app-name-ex: "ex) Misskey for iOS" | ||||
|   app-overview: "アプリの概要" | ||||
|   app-desc: "あなたのアプリの簡単な説明や紹介。" | ||||
|   app-desc-ex: "ex) Misskey iOSクライアント。" | ||||
|   callback-url: "コールバックURL (オプション)" | ||||
|   callback-url-desc: "ユーザーが認証フォームで認証した際にリダイレクトするURLを設定できます。" | ||||
|   authority: "権限" | ||||
|   authority-desc: "ここで要求した機能だけがAPIからアクセスできます。" | ||||
|   authority-warning: "アプリ作成後も変更できますが、新たな権限を付与する場合、その時点で関連付けられているユーザーキーはすべて無効になります。" | ||||
|   account-read: "アカウントの情報を見る。" | ||||
|   account-write: "アカウントの情報を操作する。" | ||||
|   note-write: "投稿する。" | ||||
|   reaction-write: "リアクションしたりリアクションをキャンセルする。" | ||||
|   following-write: "フォローしたりフォロー解除する。" | ||||
|   drive-read: "ドライブを見る。" | ||||
|   drive-write: "ドライブを操作する。" | ||||
|   notification-read: "通知を見る。" | ||||
|   notification-write: "通知を操作する。" | ||||
|   | ||||
| @@ -25,6 +25,14 @@ common: | ||||
|   application-authorization: "앱의 연계" | ||||
|   close: "닫기" | ||||
|   do-not-copy-paste: "ここにコードを入力したり張り付けたりしないでください。アカウントが不正利用される可能性があります。" | ||||
|   BSoD: | ||||
|     fatal-error: ":( 致命的な問題が発生しました。" | ||||
|     update-browser-os: "お使いのブラウザ(またはOS)のバージョンを更新すると解決する可能性があります。" | ||||
|     error-code: "エラーコード" | ||||
|     browser-version: "ブラウザ バージョン" | ||||
|     client-version: "クライアント バージョン" | ||||
|     email-support: "問題が解決しない場合は、上記の情報をお書き添えの上 syuilotan@yahoo.co.jp までご連絡ください。" | ||||
|     thanks: "Thank you for using Misskey." | ||||
|   got-it: "알았습니다" | ||||
|   customization-tips: | ||||
|     title: "사용자 정의 팁" | ||||
| @@ -115,6 +123,12 @@ common: | ||||
|   reduce-motion: "UIの動きを減らす" | ||||
|   this-setting-is-this-device-only: "이 장치만" | ||||
|   do-not-use-in-production: '이것은 개발 빌드입니다. 프로덕션 환경에서 사용하지 마십시오.' | ||||
|   is-remote-user: "このユーザー情報はコピーです。" | ||||
|   is-remote-post: "この投稿情報はコピーです。" | ||||
|   view-on-remote: "正確な情報を見る" | ||||
|   error: | ||||
|     title: '問題が発生しました' | ||||
|     retry: 'やり直す' | ||||
|   reversi: | ||||
|     drawn: "무승부" | ||||
|     my-turn: "당신의 차례입니다" | ||||
| @@ -170,6 +184,7 @@ common: | ||||
|     rename: "이름 변경" | ||||
|     stack-left: "左に重ねる" | ||||
|     pop-right: "右に出す" | ||||
|   dev: "アプリの作成に失敗しました。再度お試しください。" | ||||
| auth/views/form.vue: | ||||
|   share-access: "<i>{{ app.name }}</i>があなたのアカウントにアクセスすることを<b>許可</b>しますか?" | ||||
|   permission-ask: "このアプリは次の権限を要求しています:" | ||||
| @@ -416,6 +431,25 @@ common/views/components/visibility-chooser.vue: | ||||
| common/views/components/trends.vue: | ||||
|   count: "{}人が投稿" | ||||
|   empty: "トレンドなし" | ||||
| common/views/components/profile-editor.vue: | ||||
|   title: "プロフィール" | ||||
|   name: "名前" | ||||
|   account: "アカウント" | ||||
|   location: "場所" | ||||
|   description: "自己紹介" | ||||
|   birthday: "誕生日" | ||||
|   avatar: "アイコン" | ||||
|   banner: "バナー" | ||||
|   is-cat: "このアカウントはCatです" | ||||
|   is-bot: "このアカウントはBotです" | ||||
|   is-locked: "フォローを承認制にする" | ||||
|   careful-bot: "Botからのフォローだけ承認制にする" | ||||
|   advanced: "その他" | ||||
|   privacy: "プライバシー" | ||||
|   save: "保存" | ||||
|   saved: "プロフィールを保存しました" | ||||
|   uploading: "アップロード中" | ||||
|   upload-failed: "アップロードに失敗しました" | ||||
| common/views/widgets/broadcast.vue: | ||||
|   fetching: "確認中" | ||||
|   no-broadcasts: "お知らせはありません" | ||||
| @@ -640,7 +674,7 @@ desktop/views/components/note-detail.vue: | ||||
|   location: "位置情報" | ||||
|   renote: "Renote" | ||||
|   add-reaction: "リアクション" | ||||
| desktop/views/components/notes.note.vue: | ||||
| desktop/views/components/note.vue: | ||||
|   reposted-by: "{}がRenote" | ||||
|   reply: "返信" | ||||
|   renote: "Renote" | ||||
| @@ -726,8 +760,12 @@ desktop/views/components/settings.vue: | ||||
|   advanced: "詳細設定" | ||||
|   api-via-stream: "ストリームを経由したAPIリクエスト" | ||||
|   api-via-stream-desc: "この設定をオンにすると、websocket接続を経由してAPIリクエストが行われます(パフォーマンス向上が期待できます)。オフにすると、ネイティブの fetch APIが利用されます。この設定はこのデバイスのみ有効です。" | ||||
|   deck-nav: "デッキ内ナビゲーション" | ||||
|   deck-nav-desc: "デッキを使用しているとき、ナビゲーションが発生する際にページ遷移を行わずに一時的なカラムで受けるようにします。" | ||||
|   deck-default: "デッキをデフォルトのUIにする" | ||||
|   display: "デザインと表示" | ||||
|   customize: "ホームをカスタマイズ" | ||||
|   wallpaper: "壁紙" | ||||
|   choose-wallpaper: "壁紙を選択" | ||||
|   delete-wallpaper: "壁紙を削除" | ||||
|   dark-mode: "ダークモード" | ||||
| @@ -739,17 +777,19 @@ desktop/views/components/settings.vue: | ||||
|   suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する" | ||||
|   show-clock-on-header: "右上に時計を表示する" | ||||
|   show-reply-target: "リプライ先を表示する" | ||||
|   timeline: "タイムライン" | ||||
|   show-my-renotes: "自分の行ったRenoteをタイムラインに表示する" | ||||
|   show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する" | ||||
|   show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する" | ||||
|   show-maps: "マップの自動展開" | ||||
|   deck-column-align: "デッキのカラムの位置" | ||||
|   deck-column-align-center: "中央" | ||||
|   deck-column-align-left: "左" | ||||
|   sound: "サウンド" | ||||
|   enable-sounds: "サウンドを有効にする" | ||||
|   enable-sounds-desc: "投稿やメッセージを送受信したときなどにサウンドを再生します。この設定はブラウザに記憶されます。" | ||||
|   volume: "ボリューム" | ||||
|   test: "テスト" | ||||
|   mobile: "モバイル" | ||||
|   disable-via-mobile: "「モバイルからの投稿」フラグを付けない" | ||||
|   language: "言語" | ||||
|   pick-language: "言語を選択" | ||||
|   recommended: "推奨" | ||||
| @@ -828,21 +868,6 @@ desktop/views/components/settings.password.vue: | ||||
|   enter-new-password-again: "もう一度新しいパスワードを入力してください" | ||||
|   not-match: "新しいパスワードが一致しません" | ||||
|   changed: "パスワードを変更しました" | ||||
| desktop/views/components/settings.profile.vue: | ||||
|   avatar: "アイコン" | ||||
|   choice-avatar: "画像を選択" | ||||
|   name: "名前" | ||||
|   location: "場所" | ||||
|   description: "自己紹介" | ||||
|   birthday: "誕生日" | ||||
|   save: "保存" | ||||
|   locked-account: "アカウントの保護" | ||||
|   is-locked: "フォローを承認制にする" | ||||
|   careful-bot: "Botからのフォローだけ承認制にする" | ||||
|   other: "その他" | ||||
|   is-bot: "このアカウントはBotです" | ||||
|   is-cat: "このアカウントはCatです" | ||||
|   profile-updated: "プロフィールを更新しました" | ||||
| desktop/views/components/sub-note-content.vue: | ||||
|   private: "この投稿は非公開です" | ||||
|   deleted: "この投稿は削除されました" | ||||
| @@ -914,6 +939,8 @@ desktop/views/pages/admin/admin.vue: | ||||
|   drive: "ドライブ" | ||||
|   users: "ユーザー" | ||||
|   update: "更新" | ||||
|   announcements: "お知らせ" | ||||
|   hashtags: "ハッシュタグ" | ||||
| desktop/views/pages/admin/admin.dashboard.vue: | ||||
|   dashboard: "ダッシュボード" | ||||
|   all-users: "全てのユーザー" | ||||
| @@ -921,6 +948,9 @@ desktop/views/pages/admin/admin.dashboard.vue: | ||||
|   all-notes: "全ての投稿" | ||||
|   original-notes: "このインスタンスの投稿" | ||||
|   invite: "招待" | ||||
|   banner-url: "Banner URL" | ||||
|   disableRegistration: "Disable new user registration" | ||||
|   disableLocalTimeline: "Disable the local timeline" | ||||
| desktop/views/pages/admin/admin.suspend-user.vue: | ||||
|   suspend-user: "ユーザーの凍結" | ||||
|   suspend: "凍結" | ||||
| @@ -937,14 +967,23 @@ desktop/views/pages/admin/admin.unverify-user.vue: | ||||
|   unverify-user: "ユーザーの公式アカウント解除" | ||||
|   unverify: "公式アカウントを解除する" | ||||
|   unverified: "公式アカウントを解除しました" | ||||
| desktop/views/pages/admin/admin.announcements.vue: | ||||
|   announcements: "お知らせ" | ||||
| desktop/views/pages/admin/admin.hashtags.vue: | ||||
|   hided-tags: "Hidden Tags" | ||||
| desktop/views/pages/deck/deck.tl-column.vue: | ||||
|   is-media-only: "メディア投稿のみ" | ||||
|   is-media-view: "メディアビュー" | ||||
|   edit: "オプション" | ||||
| desktop/views/pages/deck/deck.note.vue: | ||||
|   reposted-by: "{}がRenote" | ||||
|   private: "この投稿は非公開です" | ||||
|   deleted: "この投稿は削除されました" | ||||
| desktop/views/pages/deck/deck.user-column.vue: | ||||
|   posts: "投稿" | ||||
|   following: "フォロー" | ||||
|   followers: "フォロワー" | ||||
|   images: "画像" | ||||
|   activity: "アクティビティ" | ||||
|   timeline: "タイムライン" | ||||
|   pinned-notes: "ピン留めされた投稿" | ||||
|   push-to-a-list: "リストに追加" | ||||
| desktop/views/pages/stats/stats.vue: | ||||
|   all-users: "全てのユーザー" | ||||
|   original-users: "このインスタンスのユーザー" | ||||
| @@ -997,9 +1036,6 @@ desktop/views/pages/user/user.friends.vue: | ||||
|   no-users: "よく話すユーザーはいません" | ||||
| desktop/views/pages/user/user.vue: | ||||
|   is-suspended: "このユーザーは凍結されています。" | ||||
|   is-remote: "このユーザーはリモートユーザーです。" | ||||
|   view-remote: "正確な情報を見る" | ||||
| desktop/views/pages/user/user.home.vue: | ||||
|   last-used-at: "最終アクセス" | ||||
| desktop/views/pages/user/user.photos.vue: | ||||
|   title: "フォト" | ||||
| @@ -1020,6 +1056,10 @@ desktop/views/pages/user/user.header.vue: | ||||
|   following: "フォロー" | ||||
|   followers: "フォロワー" | ||||
|   is-bot: "このアカウントはBotです" | ||||
|   years-old: "歳" | ||||
|   year: "年" | ||||
|   month: "月" | ||||
|   day: "日" | ||||
| desktop/views/pages/user/user.timeline.vue: | ||||
|   default: "投稿" | ||||
|   with-replies: "投稿と返信" | ||||
| @@ -1221,24 +1261,6 @@ mobile/views/pages/notifications.vue: | ||||
|   read-all: "すべての通知を既読にしますか?" | ||||
| mobile/views/pages/games/reversi.vue: | ||||
|   reversi: "リバーシ" | ||||
| mobile/views/pages/settings/settings.profile.vue: | ||||
|   title: "プロフィール" | ||||
|   name: "名前" | ||||
|   account: "アカウント" | ||||
|   location: "場所" | ||||
|   description: "自己紹介" | ||||
|   birthday: "誕生日" | ||||
|   avatar: "アイコン" | ||||
|   banner: "バナー" | ||||
|   is-cat: "このアカウントはCatです" | ||||
|   is-locked: "フォローを承認制にする" | ||||
|   careful-bot: "Botからのフォローだけ承認制にする" | ||||
|   advanced: "その他" | ||||
|   privacy: "プライバシー" | ||||
|   save: "保存" | ||||
|   saved: "プロフィールを保存しました" | ||||
|   uploading: "アップロード中" | ||||
|   upload-failed: "アップロードに失敗しました" | ||||
| mobile/views/pages/search.vue: | ||||
|   search: "検索" | ||||
|   empty: "「{}」に関する投稿は見つかりませんでした。" | ||||
| @@ -1294,6 +1316,7 @@ mobile/views/pages/settings.vue: | ||||
|   signout: "サインアウト" | ||||
|   sound: "サウンド" | ||||
|   enable-sounds: "サウンドを有効にする" | ||||
|   mark-as-read-all-unread-notes: "すべての投稿を既読にする" | ||||
| mobile/views/pages/user.vue: | ||||
|   follows-you: "フォローされています" | ||||
|   following: "フォロー" | ||||
| @@ -1303,8 +1326,6 @@ mobile/views/pages/user.vue: | ||||
|   timeline: "タイムライン" | ||||
|   media: "メディア" | ||||
|   is-suspended: "このユーザーは凍結されています。" | ||||
|   is-remote: "このユーザーはリモートユーザーです。" | ||||
|   view-remote: "正確な情報を見る" | ||||
| mobile/views/pages/user/home.vue: | ||||
|   recent-notes: "最近の投稿" | ||||
|   images: "画像" | ||||
| @@ -1350,3 +1371,29 @@ docs: | ||||
|       description: "説明" | ||||
| dev/views/index.vue: | ||||
|   manage-apps: "アプリの管理" | ||||
| dev/views/apps.vue: | ||||
|   manage-apps: "アプリを管理" | ||||
|   create-app: "アプリ作成" | ||||
|   app-missing: "アプリなし" | ||||
| dev/views/new-app.vue: | ||||
|   create-app: "アプリケーションの作成" | ||||
|   app-name: "アプリケーション名" | ||||
|   app-name-desc: "あなたのアプリの名称。" | ||||
|   app-name-ex: "ex) Misskey for iOS" | ||||
|   app-overview: "アプリの概要" | ||||
|   app-desc: "あなたのアプリの簡単な説明や紹介。" | ||||
|   app-desc-ex: "ex) Misskey iOSクライアント。" | ||||
|   callback-url: "コールバックURL (オプション)" | ||||
|   callback-url-desc: "ユーザーが認証フォームで認証した際にリダイレクトするURLを設定できます。" | ||||
|   authority: "権限" | ||||
|   authority-desc: "ここで要求した機能だけがAPIからアクセスできます。" | ||||
|   authority-warning: "アプリ作成後も変更できますが、新たな権限を付与する場合、その時点で関連付けられているユーザーキーはすべて無効になります。" | ||||
|   account-read: "アカウントの情報を見る。" | ||||
|   account-write: "アカウントの情報を操作する。" | ||||
|   note-write: "投稿する。" | ||||
|   reaction-write: "リアクションしたりリアクションをキャンセルする。" | ||||
|   following-write: "フォローしたりフォロー解除する。" | ||||
|   drive-read: "ドライブを見る。" | ||||
|   drive-write: "ドライブを操作する。" | ||||
|   notification-read: "通知を見る。" | ||||
|   notification-write: "通知を操作する。" | ||||
|   | ||||
| @@ -25,6 +25,14 @@ common: | ||||
|   application-authorization: "アプリの連携" | ||||
|   close: "閉じる" | ||||
|   do-not-copy-paste: "ここにコードを入力したり張り付けたりしないでください。アカウントが不正利用される可能性があります。" | ||||
|   BSoD: | ||||
|     fatal-error: ":( 致命的な問題が発生しました。" | ||||
|     update-browser-os: "お使いのブラウザ(またはOS)のバージョンを更新すると解決する可能性があります。" | ||||
|     error-code: "エラーコード" | ||||
|     browser-version: "ブラウザ バージョン" | ||||
|     client-version: "クライアント バージョン" | ||||
|     email-support: "問題が解決しない場合は、上記の情報をお書き添えの上 syuilotan@yahoo.co.jp までご連絡ください。" | ||||
|     thanks: "Thank you for using Misskey." | ||||
|   got-it: "わかった" | ||||
|   customization-tips: | ||||
|     title: "カスタマイズのヒント" | ||||
| @@ -115,6 +123,12 @@ common: | ||||
|   reduce-motion: "UIの動きを減らす" | ||||
|   this-setting-is-this-device-only: "このデバイスのみ" | ||||
|   do-not-use-in-production: 'これは開発ビルドです。本番環境で使用しないでください。' | ||||
|   is-remote-user: "このユーザー情報はコピーです。" | ||||
|   is-remote-post: "この投稿情報はコピーです。" | ||||
|   view-on-remote: "正確な情報を見る" | ||||
|   error: | ||||
|     title: '問題が発生しました' | ||||
|     retry: 'やり直す' | ||||
|   reversi: | ||||
|     drawn: "引き分け" | ||||
|     my-turn: "あなたのターンです" | ||||
| @@ -170,6 +184,7 @@ common: | ||||
|     rename: "名前を変更" | ||||
|     stack-left: "左に重ねる" | ||||
|     pop-right: "右に出す" | ||||
|   dev: "アプリの作成に失敗しました。再度お試しください。" | ||||
| auth/views/form.vue: | ||||
|   share-access: "<i>{{ app.name }}</i>があなたのアカウントにアクセスすることを<b>許可</b>しますか?" | ||||
|   permission-ask: "このアプリは次の権限を要求しています:" | ||||
| @@ -416,6 +431,25 @@ common/views/components/visibility-chooser.vue: | ||||
| common/views/components/trends.vue: | ||||
|   count: "{}人が投稿" | ||||
|   empty: "トレンドなし" | ||||
| common/views/components/profile-editor.vue: | ||||
|   title: "プロフィール" | ||||
|   name: "名前" | ||||
|   account: "アカウント" | ||||
|   location: "場所" | ||||
|   description: "自己紹介" | ||||
|   birthday: "誕生日" | ||||
|   avatar: "アイコン" | ||||
|   banner: "バナー" | ||||
|   is-cat: "このアカウントはCatです" | ||||
|   is-bot: "このアカウントはBotです" | ||||
|   is-locked: "フォローを承認制にする" | ||||
|   careful-bot: "Botからのフォローだけ承認制にする" | ||||
|   advanced: "その他" | ||||
|   privacy: "プライバシー" | ||||
|   save: "保存" | ||||
|   saved: "プロフィールを保存しました" | ||||
|   uploading: "アップロード中" | ||||
|   upload-failed: "アップロードに失敗しました" | ||||
| common/views/widgets/broadcast.vue: | ||||
|   fetching: "Bezig met ophalen" | ||||
|   no-broadcasts: "Geen uitzendingen" | ||||
| @@ -640,12 +674,12 @@ desktop/views/components/note-detail.vue: | ||||
|   location: "Locatie" | ||||
|   renote: "Renote" | ||||
|   add-reaction: "リアクション" | ||||
| desktop/views/components/notes.note.vue: | ||||
|   reposted-by: "Hergeplaatst door {}" | ||||
|   reply: "Antwoord" | ||||
| desktop/views/components/note.vue: | ||||
|   reposted-by: "{}がRenote" | ||||
|   reply: "返信" | ||||
|   renote: "Renote" | ||||
|   add-reaction: "Reactie toevoegen" | ||||
|   detail: "Details tonen" | ||||
|   add-reaction: "リアクション" | ||||
|   detail: "詳細" | ||||
|   private: "この投稿は非公開です" | ||||
|   deleted: "この投稿は削除されました" | ||||
| desktop/views/components/notes.vue: | ||||
| @@ -726,8 +760,12 @@ desktop/views/components/settings.vue: | ||||
|   advanced: "Geavanceerde instellingen" | ||||
|   api-via-stream: "API-verzoek via stream" | ||||
|   api-via-stream-desc: "API-verzoek wordt uitgevoerd via de WebSocket-verbinding i.p.v. de ingebouwde ophaal-API (voor verbeterde prestaties). Deze instelling wordt opgeslagen in je browser." | ||||
|   deck-nav: "デッキ内ナビゲーション" | ||||
|   deck-nav-desc: "デッキを使用しているとき、ナビゲーションが発生する際にページ遷移を行わずに一時的なカラムで受けるようにします。" | ||||
|   deck-default: "デッキをデフォルトのUIにする" | ||||
|   display: "Ontwerp en weergave" | ||||
|   customize: "Startpagina aanpassen" | ||||
|   wallpaper: "壁紙" | ||||
|   choose-wallpaper: "壁紙を選択" | ||||
|   delete-wallpaper: "壁紙を削除" | ||||
|   dark-mode: "Donkere modus" | ||||
| @@ -739,17 +777,19 @@ desktop/views/components/settings.vue: | ||||
|   suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する" | ||||
|   show-clock-on-header: "右上に時計を表示する" | ||||
|   show-reply-target: "Antwoord-knop tonen" | ||||
|   timeline: "タイムライン" | ||||
|   show-my-renotes: "Mijn renote tonen op de tijdlijn" | ||||
|   show-renoted-my-notes: "Mijn gerenote bericht tonen op de tijdlijn" | ||||
|   show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する" | ||||
|   show-maps: "Kaart tonen" | ||||
|   deck-column-align: "デッキのカラムの位置" | ||||
|   deck-column-align-center: "中央" | ||||
|   deck-column-align-left: "左" | ||||
|   sound: "Geluid" | ||||
|   enable-sounds: "Geluid inschakelen" | ||||
|   enable-sounds-desc: "Een geluid afspelen bij het ontvangen van een bericht. Deze instelling wordt opgeslagen in je browser." | ||||
|   volume: "Volume" | ||||
|   test: "Testen" | ||||
|   mobile: "Mobiel" | ||||
|   disable-via-mobile: "Berichten niet markeren als 'via mobiel'" | ||||
|   language: "Taal" | ||||
|   pick-language: "Selecteer een taal" | ||||
|   recommended: "Aanbevolen" | ||||
| @@ -828,21 +868,6 @@ desktop/views/components/settings.password.vue: | ||||
|   enter-new-password-again: "Voer je nieuwe wachtwoord nogmaals in" | ||||
|   not-match: "Het nieuwe wachtwoord komt niet overeen" | ||||
|   changed: "Wachtwoord bijgewerkt" | ||||
| desktop/views/components/settings.profile.vue: | ||||
|   avatar: "Gebruikersafbeelding" | ||||
|   choice-avatar: "Kies een afbeelding" | ||||
|   name: "Naam" | ||||
|   location: "Locatie" | ||||
|   description: "Omschrijving" | ||||
|   birthday: "Geboortedatum" | ||||
|   save: "Profiel bijwerken" | ||||
|   locked-account: "アカウントの保護" | ||||
|   is-locked: "フォローを承認制にする" | ||||
|   careful-bot: "Botからのフォローだけ承認制にする" | ||||
|   other: "その他" | ||||
|   is-bot: "Dit account is een Bot" | ||||
|   is-cat: "Dit account is een Kat" | ||||
|   profile-updated: "プロフィールを更新しました" | ||||
| desktop/views/components/sub-note-content.vue: | ||||
|   private: "この投稿は非公開です" | ||||
|   deleted: "この投稿は削除されました" | ||||
| @@ -914,6 +939,8 @@ desktop/views/pages/admin/admin.vue: | ||||
|   drive: "ドライブ" | ||||
|   users: "ユーザー" | ||||
|   update: "更新" | ||||
|   announcements: "お知らせ" | ||||
|   hashtags: "ハッシュタグ" | ||||
| desktop/views/pages/admin/admin.dashboard.vue: | ||||
|   dashboard: "ダッシュボード" | ||||
|   all-users: "全てのユーザー" | ||||
| @@ -921,6 +948,9 @@ desktop/views/pages/admin/admin.dashboard.vue: | ||||
|   all-notes: "全ての投稿" | ||||
|   original-notes: "このインスタンスの投稿" | ||||
|   invite: "招待" | ||||
|   banner-url: "Banner URL" | ||||
|   disableRegistration: "Disable new user registration" | ||||
|   disableLocalTimeline: "Disable the local timeline" | ||||
| desktop/views/pages/admin/admin.suspend-user.vue: | ||||
|   suspend-user: "ユーザーの凍結" | ||||
|   suspend: "凍結" | ||||
| @@ -937,14 +967,23 @@ desktop/views/pages/admin/admin.unverify-user.vue: | ||||
|   unverify-user: "ユーザーの公式アカウント解除" | ||||
|   unverify: "公式アカウントを解除する" | ||||
|   unverified: "公式アカウントを解除しました" | ||||
| desktop/views/pages/admin/admin.announcements.vue: | ||||
|   announcements: "お知らせ" | ||||
| desktop/views/pages/admin/admin.hashtags.vue: | ||||
|   hided-tags: "Hidden Tags" | ||||
| desktop/views/pages/deck/deck.tl-column.vue: | ||||
|   is-media-only: "メディア投稿のみ" | ||||
|   is-media-view: "メディアビュー" | ||||
|   edit: "オプション" | ||||
| desktop/views/pages/deck/deck.note.vue: | ||||
|   reposted-by: "{}がRenote" | ||||
|   private: "この投稿は非公開です" | ||||
|   deleted: "この投稿は削除されました" | ||||
| desktop/views/pages/deck/deck.user-column.vue: | ||||
|   posts: "投稿" | ||||
|   following: "フォロー" | ||||
|   followers: "フォロワー" | ||||
|   images: "画像" | ||||
|   activity: "アクティビティ" | ||||
|   timeline: "タイムライン" | ||||
|   pinned-notes: "ピン留めされた投稿" | ||||
|   push-to-a-list: "リストに追加" | ||||
| desktop/views/pages/stats/stats.vue: | ||||
|   all-users: "全てのユーザー" | ||||
|   original-users: "このインスタンスのユーザー" | ||||
| @@ -997,10 +1036,7 @@ desktop/views/pages/user/user.friends.vue: | ||||
|   no-users: "Geen gebruikers" | ||||
| desktop/views/pages/user/user.vue: | ||||
|   is-suspended: "このユーザーは凍結されています。" | ||||
|   is-remote: "このユーザーはリモートユーザーです。" | ||||
|   view-remote: "正確な情報を見る" | ||||
| desktop/views/pages/user/user.home.vue: | ||||
|   last-used-at: "Laatst actief: " | ||||
|   last-used-at: "最終アクセス" | ||||
| desktop/views/pages/user/user.photos.vue: | ||||
|   title: "Foto's" | ||||
|   loading: "Bezig met laden" | ||||
| @@ -1020,6 +1056,10 @@ desktop/views/pages/user/user.header.vue: | ||||
|   following: "フォロー" | ||||
|   followers: "フォロワー" | ||||
|   is-bot: "このアカウントはBotです" | ||||
|   years-old: "歳" | ||||
|   year: "年" | ||||
|   month: "月" | ||||
|   day: "日" | ||||
| desktop/views/pages/user/user.timeline.vue: | ||||
|   default: "Berichten" | ||||
|   with-replies: "Berichten en antwoorden" | ||||
| @@ -1221,24 +1261,6 @@ mobile/views/pages/notifications.vue: | ||||
|   read-all: "Weet je zeker dat je alle meldingen wilt markeren als gelezen?" | ||||
| mobile/views/pages/games/reversi.vue: | ||||
|   reversi: "リバーシ" | ||||
| mobile/views/pages/settings/settings.profile.vue: | ||||
|   title: "Profiel" | ||||
|   name: "Naam" | ||||
|   account: "Account" | ||||
|   location: "Locatie" | ||||
|   description: "Omschrijving" | ||||
|   birthday: "Geboortedatum" | ||||
|   avatar: "Gebruikersafbeelding" | ||||
|   banner: "Omslagfoto" | ||||
|   is-cat: "Dit account is een Kat" | ||||
|   is-locked: "フォローを承認制にする" | ||||
|   careful-bot: "Botからのフォローだけ承認制にする" | ||||
|   advanced: "その他" | ||||
|   privacy: "プライバシー" | ||||
|   save: "Profiel bijwerken" | ||||
|   saved: "Profiel bijgewerkt" | ||||
|   uploading: "Bezig met uploaden" | ||||
|   upload-failed: "Upload mislukt" | ||||
| mobile/views/pages/search.vue: | ||||
|   search: "Zoeken" | ||||
|   empty: "Geen berichten gevonden voor '{}'" | ||||
| @@ -1294,6 +1316,7 @@ mobile/views/pages/settings.vue: | ||||
|   signout: "Uitloggen" | ||||
|   sound: "サウンド" | ||||
|   enable-sounds: "サウンドを有効にする" | ||||
|   mark-as-read-all-unread-notes: "すべての投稿を既読にする" | ||||
| mobile/views/pages/user.vue: | ||||
|   follows-you: "Volgt jou" | ||||
|   following: "Volgend" | ||||
| @@ -1303,8 +1326,6 @@ mobile/views/pages/user.vue: | ||||
|   timeline: "Tijdlijn" | ||||
|   media: "Media" | ||||
|   is-suspended: "Dit account is geschorst." | ||||
|   is-remote: "Deze gebruiker is een externe gebruiker; de informatie is daarom niet volledig. " | ||||
|   view-remote: "Volledige informatie bekijken" | ||||
| mobile/views/pages/user/home.vue: | ||||
|   recent-notes: "Recente notities" | ||||
|   images: "Afbeeldingen" | ||||
| @@ -1313,7 +1334,7 @@ mobile/views/pages/user/home.vue: | ||||
|   domains: "Domeinnamen" | ||||
|   frequently-replied-users: "Frequent gesproken gebruikers" | ||||
|   followers-you-know: "Volgers die je kent" | ||||
|   last-used-at: "Laatst actief:" | ||||
|   last-used-at: "Laatst actief" | ||||
| mobile/views/pages/user/home.followers-you-know.vue: | ||||
|   loading: "Bezig met laden" | ||||
|   no-users: "Geen gebruikers" | ||||
| @@ -1350,3 +1371,29 @@ docs: | ||||
|       description: "Omschrijving" | ||||
| dev/views/index.vue: | ||||
|   manage-apps: "アプリの管理" | ||||
| dev/views/apps.vue: | ||||
|   manage-apps: "アプリを管理" | ||||
|   create-app: "アプリ作成" | ||||
|   app-missing: "アプリなし" | ||||
| dev/views/new-app.vue: | ||||
|   create-app: "アプリケーションの作成" | ||||
|   app-name: "アプリケーション名" | ||||
|   app-name-desc: "あなたのアプリの名称。" | ||||
|   app-name-ex: "ex) Misskey for iOS" | ||||
|   app-overview: "アプリの概要" | ||||
|   app-desc: "あなたのアプリの簡単な説明や紹介。" | ||||
|   app-desc-ex: "ex) Misskey iOSクライアント。" | ||||
|   callback-url: "コールバックURL (オプション)" | ||||
|   callback-url-desc: "ユーザーが認証フォームで認証した際にリダイレクトするURLを設定できます。" | ||||
|   authority: "権限" | ||||
|   authority-desc: "ここで要求した機能だけがAPIからアクセスできます。" | ||||
|   authority-warning: "アプリ作成後も変更できますが、新たな権限を付与する場合、その時点で関連付けられているユーザーキーはすべて無効になります。" | ||||
|   account-read: "アカウントの情報を見る。" | ||||
|   account-write: "アカウントの情報を操作する。" | ||||
|   note-write: "投稿する。" | ||||
|   reaction-write: "リアクションしたりリアクションをキャンセルする。" | ||||
|   following-write: "フォローしたりフォロー解除する。" | ||||
|   drive-read: "ドライブを見る。" | ||||
|   drive-write: "ドライブを操作する。" | ||||
|   notification-read: "通知を見る。" | ||||
|   notification-write: "通知を操作する。" | ||||
|   | ||||
| @@ -25,6 +25,14 @@ common: | ||||
|   application-authorization: "アプリの連携" | ||||
|   close: "Lukk" | ||||
|   do-not-copy-paste: "ここにコードを入力したり張り付けたりしないでください。アカウントが不正利用される可能性があります。" | ||||
|   BSoD: | ||||
|     fatal-error: ":( 致命的な問題が発生しました。" | ||||
|     update-browser-os: "お使いのブラウザ(またはOS)のバージョンを更新すると解決する可能性があります。" | ||||
|     error-code: "エラーコード" | ||||
|     browser-version: "ブラウザ バージョン" | ||||
|     client-version: "クライアント バージョン" | ||||
|     email-support: "問題が解決しない場合は、上記の情報をお書き添えの上 syuilotan@yahoo.co.jp までご連絡ください。" | ||||
|     thanks: "Thank you for using Misskey." | ||||
|   got-it: "Skjønner!" | ||||
|   customization-tips: | ||||
|     title: "カスタマイズのヒント" | ||||
| @@ -115,6 +123,12 @@ common: | ||||
|   reduce-motion: "UIの動きを減らす" | ||||
|   this-setting-is-this-device-only: "このデバイスのみ" | ||||
|   do-not-use-in-production: 'これは開発ビルドです。本番環境で使用しないでください。' | ||||
|   is-remote-user: "このユーザー情報はコピーです。" | ||||
|   is-remote-post: "この投稿情報はコピーです。" | ||||
|   view-on-remote: "正確な情報を見る" | ||||
|   error: | ||||
|     title: '問題が発生しました' | ||||
|     retry: 'やり直す' | ||||
|   reversi: | ||||
|     drawn: "引き分け" | ||||
|     my-turn: "あなたのターンです" | ||||
| @@ -170,6 +184,7 @@ common: | ||||
|     rename: "Endre navn" | ||||
|     stack-left: "左に重ねる" | ||||
|     pop-right: "Til høyre" | ||||
|   dev: "アプリの作成に失敗しました。再度お試しください。" | ||||
| auth/views/form.vue: | ||||
|   share-access: "<i>{{ app.name }}</i>があなたのアカウントにアクセスすることを<b>許可</b>しますか?" | ||||
|   permission-ask: "このアプリは次の権限を要求しています:" | ||||
| @@ -416,6 +431,25 @@ common/views/components/visibility-chooser.vue: | ||||
| common/views/components/trends.vue: | ||||
|   count: "{}人が投稿" | ||||
|   empty: "トレンドなし" | ||||
| common/views/components/profile-editor.vue: | ||||
|   title: "プロフィール" | ||||
|   name: "名前" | ||||
|   account: "アカウント" | ||||
|   location: "場所" | ||||
|   description: "自己紹介" | ||||
|   birthday: "誕生日" | ||||
|   avatar: "アイコン" | ||||
|   banner: "バナー" | ||||
|   is-cat: "このアカウントはCatです" | ||||
|   is-bot: "このアカウントはBotです" | ||||
|   is-locked: "フォローを承認制にする" | ||||
|   careful-bot: "Botからのフォローだけ承認制にする" | ||||
|   advanced: "その他" | ||||
|   privacy: "プライバシー" | ||||
|   save: "保存" | ||||
|   saved: "プロフィールを保存しました" | ||||
|   uploading: "アップロード中" | ||||
|   upload-failed: "アップロードに失敗しました" | ||||
| common/views/widgets/broadcast.vue: | ||||
|   fetching: "Henter" | ||||
|   no-broadcasts: "お知らせはありません" | ||||
| @@ -640,12 +674,12 @@ desktop/views/components/note-detail.vue: | ||||
|   location: "Lokasjon" | ||||
|   renote: "Renote" | ||||
|   add-reaction: "リアクション" | ||||
| desktop/views/components/notes.note.vue: | ||||
| desktop/views/components/note.vue: | ||||
|   reposted-by: "{}がRenote" | ||||
|   reply: "Svar" | ||||
|   reply: "返信" | ||||
|   renote: "Renote" | ||||
|   add-reaction: "リアクション" | ||||
|   detail: "Vis detaljer" | ||||
|   detail: "詳細" | ||||
|   private: "この投稿は非公開です" | ||||
|   deleted: "この投稿は削除されました" | ||||
| desktop/views/components/notes.vue: | ||||
| @@ -726,8 +760,12 @@ desktop/views/components/settings.vue: | ||||
|   advanced: "Avanserte innstillinger" | ||||
|   api-via-stream: "ストリームを経由したAPIリクエスト" | ||||
|   api-via-stream-desc: "この設定をオンにすると、websocket接続を経由してAPIリクエストが行われます(パフォーマンス向上が期待できます)。オフにすると、ネイティブの fetch APIが利用されます。この設定はこのデバイスのみ有効です。" | ||||
|   deck-nav: "デッキ内ナビゲーション" | ||||
|   deck-nav-desc: "デッキを使用しているとき、ナビゲーションが発生する際にページ遷移を行わずに一時的なカラムで受けるようにします。" | ||||
|   deck-default: "デッキをデフォルトのUIにする" | ||||
|   display: "デザインと表示" | ||||
|   customize: "ホームをカスタマイズ" | ||||
|   wallpaper: "壁紙" | ||||
|   choose-wallpaper: "壁紙を選択" | ||||
|   delete-wallpaper: "壁紙を削除" | ||||
|   dark-mode: "ダークモード" | ||||
| @@ -739,17 +777,19 @@ desktop/views/components/settings.vue: | ||||
|   suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する" | ||||
|   show-clock-on-header: "右上に時計を表示する" | ||||
|   show-reply-target: "リプライ先を表示する" | ||||
|   timeline: "タイムライン" | ||||
|   show-my-renotes: "自分の行ったRenoteをタイムラインに表示する" | ||||
|   show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する" | ||||
|   show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する" | ||||
|   show-maps: "マップの自動展開" | ||||
|   deck-column-align: "デッキのカラムの位置" | ||||
|   deck-column-align-center: "中央" | ||||
|   deck-column-align-left: "左" | ||||
|   sound: "Lyd" | ||||
|   enable-sounds: "サウンドを有効にする" | ||||
|   enable-sounds-desc: "投稿やメッセージを送受信したときなどにサウンドを再生します。この設定はブラウザに記憶されます。" | ||||
|   volume: "Volum" | ||||
|   test: "Test" | ||||
|   mobile: "Mobil" | ||||
|   disable-via-mobile: "「モバイルからの投稿」フラグを付けない" | ||||
|   language: "Språk" | ||||
|   pick-language: "Velg språk" | ||||
|   recommended: "Anbefalt" | ||||
| @@ -828,21 +868,6 @@ desktop/views/components/settings.password.vue: | ||||
|   enter-new-password-again: "もう一度新しいパスワードを入力してください" | ||||
|   not-match: "新しいパスワードが一致しません" | ||||
|   changed: "パスワードを変更しました" | ||||
| desktop/views/components/settings.profile.vue: | ||||
|   avatar: "Avatar" | ||||
|   choice-avatar: "Velg et bilde" | ||||
|   name: "Navn" | ||||
|   location: "Lokasjon" | ||||
|   description: "Om meg" | ||||
|   birthday: "Bursdag" | ||||
|   save: "Lagre profilen" | ||||
|   locked-account: "アカウントの保護" | ||||
|   is-locked: "フォローを承認制にする" | ||||
|   careful-bot: "Botからのフォローだけ承認制にする" | ||||
|   other: "Annet" | ||||
|   is-bot: "このアカウントはBotです" | ||||
|   is-cat: "このアカウントはCatです" | ||||
|   profile-updated: "プロフィールを更新しました" | ||||
| desktop/views/components/sub-note-content.vue: | ||||
|   private: "この投稿は非公開です" | ||||
|   deleted: "この投稿は削除されました" | ||||
| @@ -914,6 +939,8 @@ desktop/views/pages/admin/admin.vue: | ||||
|   drive: "Disk" | ||||
|   users: "Brukere" | ||||
|   update: "Oppdater" | ||||
|   announcements: "お知らせ" | ||||
|   hashtags: "ハッシュタグ" | ||||
| desktop/views/pages/admin/admin.dashboard.vue: | ||||
|   dashboard: "ダッシュボード" | ||||
|   all-users: "全てのユーザー" | ||||
| @@ -921,6 +948,9 @@ desktop/views/pages/admin/admin.dashboard.vue: | ||||
|   all-notes: "全ての投稿" | ||||
|   original-notes: "このインスタンスの投稿" | ||||
|   invite: "Inviter" | ||||
|   banner-url: "Banner URL" | ||||
|   disableRegistration: "Disable new user registration" | ||||
|   disableLocalTimeline: "Disable the local timeline" | ||||
| desktop/views/pages/admin/admin.suspend-user.vue: | ||||
|   suspend-user: "ユーザーの凍結" | ||||
|   suspend: "Suspender" | ||||
| @@ -937,14 +967,23 @@ desktop/views/pages/admin/admin.unverify-user.vue: | ||||
|   unverify-user: "ユーザーの公式アカウント解除" | ||||
|   unverify: "公式アカウントを解除する" | ||||
|   unverified: "公式アカウントを解除しました" | ||||
| desktop/views/pages/admin/admin.announcements.vue: | ||||
|   announcements: "お知らせ" | ||||
| desktop/views/pages/admin/admin.hashtags.vue: | ||||
|   hided-tags: "Hidden Tags" | ||||
| desktop/views/pages/deck/deck.tl-column.vue: | ||||
|   is-media-only: "メディア投稿のみ" | ||||
|   is-media-view: "メディアビュー" | ||||
|   edit: "オプション" | ||||
| desktop/views/pages/deck/deck.note.vue: | ||||
|   reposted-by: "{}がRenote" | ||||
|   private: "この投稿は非公開です" | ||||
|   deleted: "この投稿は削除されました" | ||||
| desktop/views/pages/deck/deck.user-column.vue: | ||||
|   posts: "投稿" | ||||
|   following: "フォロー" | ||||
|   followers: "フォロワー" | ||||
|   images: "画像" | ||||
|   activity: "アクティビティ" | ||||
|   timeline: "タイムライン" | ||||
|   pinned-notes: "ピン留めされた投稿" | ||||
|   push-to-a-list: "リストに追加" | ||||
| desktop/views/pages/stats/stats.vue: | ||||
|   all-users: "全てのユーザー" | ||||
|   original-users: "このインスタンスのユーザー" | ||||
| @@ -997,9 +1036,6 @@ desktop/views/pages/user/user.friends.vue: | ||||
|   no-users: "よく話すユーザーはいません" | ||||
| desktop/views/pages/user/user.vue: | ||||
|   is-suspended: "このユーザーは凍結されています。" | ||||
|   is-remote: "このユーザーはリモートユーザーです。" | ||||
|   view-remote: "正確な情報を見る" | ||||
| desktop/views/pages/user/user.home.vue: | ||||
|   last-used-at: "最終アクセス" | ||||
| desktop/views/pages/user/user.photos.vue: | ||||
|   title: "Bilder" | ||||
| @@ -1020,6 +1056,10 @@ desktop/views/pages/user/user.header.vue: | ||||
|   following: "Følger" | ||||
|   followers: "フォロワー" | ||||
|   is-bot: "このアカウントはBotです" | ||||
|   years-old: "歳" | ||||
|   year: "年" | ||||
|   month: "月" | ||||
|   day: "日" | ||||
| desktop/views/pages/user/user.timeline.vue: | ||||
|   default: "Innlegg" | ||||
|   with-replies: "Innlegg og svar" | ||||
| @@ -1221,24 +1261,6 @@ mobile/views/pages/notifications.vue: | ||||
|   read-all: "すべての通知を既読にしますか?" | ||||
| mobile/views/pages/games/reversi.vue: | ||||
|   reversi: "Reversi" | ||||
| mobile/views/pages/settings/settings.profile.vue: | ||||
|   title: "プロフィール" | ||||
|   name: "Navn" | ||||
|   account: "Konto" | ||||
|   location: "Lokasjon" | ||||
|   description: "Om meg" | ||||
|   birthday: "Bursdag" | ||||
|   avatar: "Avatar" | ||||
|   banner: "Banner" | ||||
|   is-cat: "このアカウントはCatです" | ||||
|   is-locked: "フォローを承認制にする" | ||||
|   careful-bot: "Botからのフォローだけ承認制にする" | ||||
|   advanced: "Avansert" | ||||
|   privacy: "プライバシー" | ||||
|   save: "Lagre profilen" | ||||
|   saved: "プロフィールを保存しました" | ||||
|   uploading: "アップロード中" | ||||
|   upload-failed: "アップロードに失敗しました" | ||||
| mobile/views/pages/search.vue: | ||||
|   search: "Søk" | ||||
|   empty: "「{}」に関する投稿は見つかりませんでした。" | ||||
| @@ -1294,6 +1316,7 @@ mobile/views/pages/settings.vue: | ||||
|   signout: "サインアウト" | ||||
|   sound: "Lyder" | ||||
|   enable-sounds: "サウンドを有効にする" | ||||
|   mark-as-read-all-unread-notes: "すべての投稿を既読にする" | ||||
| mobile/views/pages/user.vue: | ||||
|   follows-you: "フォローされています" | ||||
|   following: "Følger" | ||||
| @@ -1303,8 +1326,6 @@ mobile/views/pages/user.vue: | ||||
|   timeline: "タイムライン" | ||||
|   media: "Media" | ||||
|   is-suspended: "このユーザーは凍結されています。" | ||||
|   is-remote: "このユーザーはリモートユーザーです。" | ||||
|   view-remote: "正確な情報を見る" | ||||
| mobile/views/pages/user/home.vue: | ||||
|   recent-notes: "Nylige innlegg" | ||||
|   images: "Bilder" | ||||
| @@ -1350,3 +1371,29 @@ docs: | ||||
|       description: "Beskrivelse" | ||||
| dev/views/index.vue: | ||||
|   manage-apps: "アプリの管理" | ||||
| dev/views/apps.vue: | ||||
|   manage-apps: "アプリを管理" | ||||
|   create-app: "アプリ作成" | ||||
|   app-missing: "アプリなし" | ||||
| dev/views/new-app.vue: | ||||
|   create-app: "アプリケーションの作成" | ||||
|   app-name: "アプリケーション名" | ||||
|   app-name-desc: "あなたのアプリの名称。" | ||||
|   app-name-ex: "ex) Misskey for iOS" | ||||
|   app-overview: "アプリの概要" | ||||
|   app-desc: "あなたのアプリの簡単な説明や紹介。" | ||||
|   app-desc-ex: "ex) Misskey iOSクライアント。" | ||||
|   callback-url: "コールバックURL (オプション)" | ||||
|   callback-url-desc: "ユーザーが認証フォームで認証した際にリダイレクトするURLを設定できます。" | ||||
|   authority: "権限" | ||||
|   authority-desc: "ここで要求した機能だけがAPIからアクセスできます。" | ||||
|   authority-warning: "アプリ作成後も変更できますが、新たな権限を付与する場合、その時点で関連付けられているユーザーキーはすべて無効になります。" | ||||
|   account-read: "アカウントの情報を見る。" | ||||
|   account-write: "アカウントの情報を操作する。" | ||||
|   note-write: "投稿する。" | ||||
|   reaction-write: "リアクションしたりリアクションをキャンセルする。" | ||||
|   following-write: "フォローしたりフォロー解除する。" | ||||
|   drive-read: "ドライブを見る。" | ||||
|   drive-write: "ドライブを操作する。" | ||||
|   notification-read: "通知を見る。" | ||||
|   notification-write: "通知を操作する。" | ||||
|   | ||||
| @@ -25,6 +25,14 @@ common: | ||||
|   application-authorization: "アプリの連携" | ||||
|   close: "Zamknij" | ||||
|   do-not-copy-paste: "ここにコードを入力したり張り付けたりしないでください。アカウントが不正利用される可能性があります。" | ||||
|   BSoD: | ||||
|     fatal-error: ":( 致命的な問題が発生しました。" | ||||
|     update-browser-os: "お使いのブラウザ(またはOS)のバージョンを更新すると解決する可能性があります。" | ||||
|     error-code: "エラーコード" | ||||
|     browser-version: "ブラウザ バージョン" | ||||
|     client-version: "クライアント バージョン" | ||||
|     email-support: "問題が解決しない場合は、上記の情報をお書き添えの上 syuilotan@yahoo.co.jp までご連絡ください。" | ||||
|     thanks: "Thank you for using Misskey." | ||||
|   got-it: "Rozumiem!" | ||||
|   customization-tips: | ||||
|     title: "Wskazówki o dostosowywaniu" | ||||
| @@ -115,6 +123,12 @@ common: | ||||
|   reduce-motion: "UIの動きを減らす" | ||||
|   this-setting-is-this-device-only: "このデバイスのみ" | ||||
|   do-not-use-in-production: 'これは開発ビルドです。本番環境で使用しないでください。' | ||||
|   is-remote-user: "このユーザー情報はコピーです。" | ||||
|   is-remote-post: "この投稿情報はコピーです。" | ||||
|   view-on-remote: "正確な情報を見る" | ||||
|   error: | ||||
|     title: '問題が発生しました' | ||||
|     retry: 'やり直す' | ||||
|   reversi: | ||||
|     drawn: "Remis" | ||||
|     my-turn: "Twoja kolej" | ||||
| @@ -170,6 +184,7 @@ common: | ||||
|     rename: "Zmień nazwę" | ||||
|     stack-left: "Przypnij do lewej" | ||||
|     pop-right: "Odepnij w prawo" | ||||
|   dev: "アプリの作成に失敗しました。再度お試しください。" | ||||
| auth/views/form.vue: | ||||
|   share-access: "Czy chcesz <b>zezwolić</b> <i>{{ app.name }}</i> na dostęp do Twojego konta?" | ||||
|   permission-ask: "Ta aplikacja wymaga następujących uprawnień:" | ||||
| @@ -416,6 +431,25 @@ common/views/components/visibility-chooser.vue: | ||||
| common/views/components/trends.vue: | ||||
|   count: "{}人が投稿" | ||||
|   empty: "トレンドなし" | ||||
| common/views/components/profile-editor.vue: | ||||
|   title: "プロフィール" | ||||
|   name: "名前" | ||||
|   account: "アカウント" | ||||
|   location: "場所" | ||||
|   description: "自己紹介" | ||||
|   birthday: "誕生日" | ||||
|   avatar: "アイコン" | ||||
|   banner: "バナー" | ||||
|   is-cat: "このアカウントはCatです" | ||||
|   is-bot: "このアカウントはBotです" | ||||
|   is-locked: "フォローを承認制にする" | ||||
|   careful-bot: "Botからのフォローだけ承認制にする" | ||||
|   advanced: "その他" | ||||
|   privacy: "プライバシー" | ||||
|   save: "保存" | ||||
|   saved: "プロフィールを保存しました" | ||||
|   uploading: "アップロード中" | ||||
|   upload-failed: "アップロードに失敗しました" | ||||
| common/views/widgets/broadcast.vue: | ||||
|   fetching: "Sprawdzanie" | ||||
|   no-broadcasts: "Brak transmisji" | ||||
| @@ -640,14 +674,14 @@ desktop/views/components/note-detail.vue: | ||||
|   location: "Informacje o lokalizacji" | ||||
|   renote: "Udostępnienie" | ||||
|   add-reaction: "Dodaj reakcję" | ||||
| desktop/views/components/notes.note.vue: | ||||
|   reposted-by: "Udostępniono przez {}" | ||||
|   reply: "Odpowiedz" | ||||
|   renote: "Udostępnij" | ||||
|   add-reaction: "Dodaj reakcję" | ||||
|   detail: "Pokaż szczegóły" | ||||
|   private: "ten wpis jest prywatny" | ||||
|   deleted: "ten wpis został usunięty" | ||||
| desktop/views/components/note.vue: | ||||
|   reposted-by: "{}がRenote" | ||||
|   reply: "返信" | ||||
|   renote: "Renote" | ||||
|   add-reaction: "リアクション" | ||||
|   detail: "詳細" | ||||
|   private: "この投稿は非公開です" | ||||
|   deleted: "この投稿は削除されました" | ||||
| desktop/views/components/notes.vue: | ||||
|   error: "Ładowanie nie powiodło się." | ||||
|   retry: "Spróbuj ponownie" | ||||
| @@ -726,8 +760,12 @@ desktop/views/components/settings.vue: | ||||
|   advanced: "Ustawienia zaawansowane" | ||||
|   api-via-stream: "ストリームを経由したAPIリクエスト" | ||||
|   api-via-stream-desc: "この設定をオンにすると、websocket接続を経由してAPIリクエストが行われます(パフォーマンス向上が期待できます)。オフにすると、ネイティブの fetch APIが利用されます。この設定はこのデバイスのみ有効です。" | ||||
|   deck-nav: "デッキ内ナビゲーション" | ||||
|   deck-nav-desc: "デッキを使用しているとき、ナビゲーションが発生する際にページ遷移を行わずに一時的なカラムで受けるようにします。" | ||||
|   deck-default: "デッキをデフォルトのUIにする" | ||||
|   display: "Wygląd i wyświetlanie" | ||||
|   customize: "Dostosuj stronę główną" | ||||
|   wallpaper: "壁紙" | ||||
|   choose-wallpaper: "Wybierz tło" | ||||
|   delete-wallpaper: "Usuń tło" | ||||
|   dark-mode: "Tryb ciemny" | ||||
| @@ -739,17 +777,19 @@ desktop/views/components/settings.vue: | ||||
|   suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する" | ||||
|   show-clock-on-header: "右上に時計を表示する" | ||||
|   show-reply-target: "Pokazuj cel odpowiedzi" | ||||
|   timeline: "タイムライン" | ||||
|   show-my-renotes: "Pokazuj moje udostępnienia na osi czasu" | ||||
|   show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する" | ||||
|   show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する" | ||||
|   show-maps: "Automatycznie pokazuj mapę" | ||||
|   deck-column-align: "デッキのカラムの位置" | ||||
|   deck-column-align-center: "中央" | ||||
|   deck-column-align-left: "左" | ||||
|   sound: "Dźwięk" | ||||
|   enable-sounds: "Włącz dźwięk" | ||||
|   enable-sounds-desc: "Odtwarzaj dźwięk przy wstawianiu wpisów, wysyłaniu lub otrzymywaniu wiadomości. Opcja ta jest zapamiętywana przez przeglądarkę." | ||||
|   volume: "Głośność" | ||||
|   test: "Test" | ||||
|   mobile: "Wersja mobilna" | ||||
|   disable-via-mobile: "Nie oznaczaj wpisów jako „wysłane z telefonu”" | ||||
|   language: "Język" | ||||
|   pick-language: "Wybierz język" | ||||
|   recommended: "Zalecane" | ||||
| @@ -828,21 +868,6 @@ desktop/views/components/settings.password.vue: | ||||
|   enter-new-password-again: "Wprowadź ponownie nowe hasło" | ||||
|   not-match: "Nowe hasła nie pasują do siebie" | ||||
|   changed: "Pomyślnie zmieniono hasło" | ||||
| desktop/views/components/settings.profile.vue: | ||||
|   avatar: "Awatar" | ||||
|   choice-avatar: "Wybierz obraz" | ||||
|   name: "Nazwa" | ||||
|   location: "Lokalizacja" | ||||
|   description: "Opis" | ||||
|   birthday: "Data urodzenia" | ||||
|   save: "Aktualizuj profil" | ||||
|   locked-account: "Zabezpiecz swoje konto" | ||||
|   is-locked: "フォローを承認制にする" | ||||
|   careful-bot: "Botからのフォローだけ承認制にする" | ||||
|   other: "Inne" | ||||
|   is-bot: "To konto jest prowadzone przez bota" | ||||
|   is-cat: "To konto jest prowadzone przez kota" | ||||
|   profile-updated: "Zaktualizowano profil" | ||||
| desktop/views/components/sub-note-content.vue: | ||||
|   private: "ten wpis jest prywatny" | ||||
|   deleted: "ten wpis został usunięty" | ||||
| @@ -914,6 +939,8 @@ desktop/views/pages/admin/admin.vue: | ||||
|   drive: "ドライブ" | ||||
|   users: "ユーザー" | ||||
|   update: "更新" | ||||
|   announcements: "お知らせ" | ||||
|   hashtags: "ハッシュタグ" | ||||
| desktop/views/pages/admin/admin.dashboard.vue: | ||||
|   dashboard: "ダッシュボード" | ||||
|   all-users: "全てのユーザー" | ||||
| @@ -921,6 +948,9 @@ desktop/views/pages/admin/admin.dashboard.vue: | ||||
|   all-notes: "全ての投稿" | ||||
|   original-notes: "このインスタンスの投稿" | ||||
|   invite: "招待" | ||||
|   banner-url: "Banner URL" | ||||
|   disableRegistration: "Disable new user registration" | ||||
|   disableLocalTimeline: "Disable the local timeline" | ||||
| desktop/views/pages/admin/admin.suspend-user.vue: | ||||
|   suspend-user: "ユーザーの凍結" | ||||
|   suspend: "凍結" | ||||
| @@ -937,14 +967,23 @@ desktop/views/pages/admin/admin.unverify-user.vue: | ||||
|   unverify-user: "ユーザーの公式アカウント解除" | ||||
|   unverify: "公式アカウントを解除する" | ||||
|   unverified: "公式アカウントを解除しました" | ||||
| desktop/views/pages/admin/admin.announcements.vue: | ||||
|   announcements: "お知らせ" | ||||
| desktop/views/pages/admin/admin.hashtags.vue: | ||||
|   hided-tags: "Hidden Tags" | ||||
| desktop/views/pages/deck/deck.tl-column.vue: | ||||
|   is-media-only: "Tylko wpisy z zawartością multimedialną" | ||||
|   is-media-view: "Widok multimediów" | ||||
|   edit: "Opcje" | ||||
| desktop/views/pages/deck/deck.note.vue: | ||||
|   reposted-by: "Udostępniono przez {}" | ||||
|   private: "ten wpis jest prywatny" | ||||
|   deleted: "ten wpis został usunięty" | ||||
| desktop/views/pages/deck/deck.user-column.vue: | ||||
|   posts: "投稿" | ||||
|   following: "フォロー" | ||||
|   followers: "フォロワー" | ||||
|   images: "画像" | ||||
|   activity: "アクティビティ" | ||||
|   timeline: "タイムライン" | ||||
|   pinned-notes: "ピン留めされた投稿" | ||||
|   push-to-a-list: "リストに追加" | ||||
| desktop/views/pages/stats/stats.vue: | ||||
|   all-users: "全てのユーザー" | ||||
|   original-users: "このインスタンスのユーザー" | ||||
| @@ -997,10 +1036,7 @@ desktop/views/pages/user/user.friends.vue: | ||||
|   no-users: "Brak użytkowników" | ||||
| desktop/views/pages/user/user.vue: | ||||
|   is-suspended: "To konto zostało zawieszone." | ||||
|   is-remote: "To jest użytkownik zdalnej instancji, informacje mogą nie być w pełni dokładne." | ||||
|   view-remote: "Wyświetl dokładne informacje" | ||||
| desktop/views/pages/user/user.home.vue: | ||||
|   last-used-at: "Ostatnio aktywny: " | ||||
|   last-used-at: "最終アクセス" | ||||
| desktop/views/pages/user/user.photos.vue: | ||||
|   title: "Zdjęcia" | ||||
|   loading: "Ładowanie" | ||||
| @@ -1020,6 +1056,10 @@ desktop/views/pages/user/user.header.vue: | ||||
|   following: "Śledzeni" | ||||
|   followers: "Śledzący" | ||||
|   is-bot: "To konto jest botem" | ||||
|   years-old: "歳" | ||||
|   year: "年" | ||||
|   month: "月" | ||||
|   day: "日" | ||||
| desktop/views/pages/user/user.timeline.vue: | ||||
|   default: "Wpisy" | ||||
|   with-replies: "Wpisy i odpowiedzi" | ||||
| @@ -1221,24 +1261,6 @@ mobile/views/pages/notifications.vue: | ||||
|   read-all: "Czy na pewno chcesz oznaczyć wszystkie powiadomienia jako przeczytane?" | ||||
| mobile/views/pages/games/reversi.vue: | ||||
|   reversi: "Reversi" | ||||
| mobile/views/pages/settings/settings.profile.vue: | ||||
|   title: "Profil" | ||||
|   name: "Nazwa" | ||||
|   account: "Konto" | ||||
|   location: "Lokalizacja" | ||||
|   description: "Opis" | ||||
|   birthday: "Data urodzenia" | ||||
|   avatar: "Awatar" | ||||
|   banner: "Baner" | ||||
|   is-cat: "To konto jest prowadzone przez kota" | ||||
|   is-locked: "フォローを承認制にする" | ||||
|   careful-bot: "Botからのフォローだけ承認制にする" | ||||
|   advanced: "その他" | ||||
|   privacy: "プライバシー" | ||||
|   save: "Aktualizuj profil" | ||||
|   saved: "Pomyślnie zaktualizowano profil" | ||||
|   uploading: "Wysyłanie" | ||||
|   upload-failed: "Wysyłanie nie powiodło się" | ||||
| mobile/views/pages/search.vue: | ||||
|   search: "Szukaj" | ||||
|   empty: "Nie znaleziono wpisów zawierających '{}'" | ||||
| @@ -1294,6 +1316,7 @@ mobile/views/pages/settings.vue: | ||||
|   signout: "Wyloguj" | ||||
|   sound: "サウンド" | ||||
|   enable-sounds: "サウンドを有効にする" | ||||
|   mark-as-read-all-unread-notes: "すべての投稿を既読にする" | ||||
| mobile/views/pages/user.vue: | ||||
|   follows-you: "Śledzi Cię" | ||||
|   following: "Śledzeni" | ||||
| @@ -1303,8 +1326,6 @@ mobile/views/pages/user.vue: | ||||
|   timeline: "Oś czasu" | ||||
|   media: "Multimedia" | ||||
|   is-suspended: "To konto zostało zablokowane" | ||||
|   is-remote: "To jest użytkownik zdalnej instancji, informacje mogą nie być w pełni dokładne." | ||||
|   view-remote: "Wyświetl dokładne informacje" | ||||
| mobile/views/pages/user/home.vue: | ||||
|   recent-notes: "Ostatnie wpisy" | ||||
|   images: "Zdjęcia" | ||||
| @@ -1350,3 +1371,29 @@ docs: | ||||
|       description: "Opis" | ||||
| dev/views/index.vue: | ||||
|   manage-apps: "Zarządzaj aplikacjami" | ||||
| dev/views/apps.vue: | ||||
|   manage-apps: "アプリを管理" | ||||
|   create-app: "アプリ作成" | ||||
|   app-missing: "アプリなし" | ||||
| dev/views/new-app.vue: | ||||
|   create-app: "アプリケーションの作成" | ||||
|   app-name: "アプリケーション名" | ||||
|   app-name-desc: "あなたのアプリの名称。" | ||||
|   app-name-ex: "ex) Misskey for iOS" | ||||
|   app-overview: "アプリの概要" | ||||
|   app-desc: "あなたのアプリの簡単な説明や紹介。" | ||||
|   app-desc-ex: "ex) Misskey iOSクライアント。" | ||||
|   callback-url: "コールバックURL (オプション)" | ||||
|   callback-url-desc: "ユーザーが認証フォームで認証した際にリダイレクトするURLを設定できます。" | ||||
|   authority: "権限" | ||||
|   authority-desc: "ここで要求した機能だけがAPIからアクセスできます。" | ||||
|   authority-warning: "アプリ作成後も変更できますが、新たな権限を付与する場合、その時点で関連付けられているユーザーキーはすべて無効になります。" | ||||
|   account-read: "アカウントの情報を見る。" | ||||
|   account-write: "アカウントの情報を操作する。" | ||||
|   note-write: "投稿する。" | ||||
|   reaction-write: "リアクションしたりリアクションをキャンセルする。" | ||||
|   following-write: "フォローしたりフォロー解除する。" | ||||
|   drive-read: "ドライブを見る。" | ||||
|   drive-write: "ドライブを操作する。" | ||||
|   notification-read: "通知を見る。" | ||||
|   notification-write: "通知を操作する。" | ||||
|   | ||||
| @@ -25,6 +25,14 @@ common: | ||||
|   application-authorization: "Aplicativos autorizados" | ||||
|   close: "Fechar" | ||||
|   do-not-copy-paste: "Por favor, não digite ou copie o código aqui. A conta pode ser comprometida." | ||||
|   BSoD: | ||||
|     fatal-error: ":( 致命的な問題が発生しました。" | ||||
|     update-browser-os: "お使いのブラウザ(またはOS)のバージョンを更新すると解決する可能性があります。" | ||||
|     error-code: "エラーコード" | ||||
|     browser-version: "ブラウザ バージョン" | ||||
|     client-version: "クライアント バージョン" | ||||
|     email-support: "問題が解決しない場合は、上記の情報をお書き添えの上 syuilotan@yahoo.co.jp までご連絡ください。" | ||||
|     thanks: "Thank you for using Misskey." | ||||
|   got-it: "Entendi!" | ||||
|   customization-tips: | ||||
|     title: "Dicas de personalização" | ||||
| @@ -115,6 +123,12 @@ common: | ||||
|   reduce-motion: "UIの動きを減らす" | ||||
|   this-setting-is-this-device-only: "このデバイスのみ" | ||||
|   do-not-use-in-production: 'これは開発ビルドです。本番環境で使用しないでください。' | ||||
|   is-remote-user: "このユーザー情報はコピーです。" | ||||
|   is-remote-post: "この投稿情報はコピーです。" | ||||
|   view-on-remote: "正確な情報を見る" | ||||
|   error: | ||||
|     title: '問題が発生しました' | ||||
|     retry: 'やり直す' | ||||
|   reversi: | ||||
|     drawn: "Empatado" | ||||
|     my-turn: "Seu turno" | ||||
| @@ -170,6 +184,7 @@ common: | ||||
|     rename: "Renomear" | ||||
|     stack-left: "左に重ねる" | ||||
|     pop-right: "Acoplar à direita" | ||||
|   dev: "アプリの作成に失敗しました。再度お試しください。" | ||||
| auth/views/form.vue: | ||||
|   share-access: "Você <b>permite</b> que <i>{{ app.name }}</i> acesse sua conta?" | ||||
|   permission-ask: "Este aplicativo precisa das seguintes permissões:" | ||||
| @@ -416,6 +431,25 @@ common/views/components/visibility-chooser.vue: | ||||
| common/views/components/trends.vue: | ||||
|   count: "{}人が投稿" | ||||
|   empty: "トレンドなし" | ||||
| common/views/components/profile-editor.vue: | ||||
|   title: "プロフィール" | ||||
|   name: "名前" | ||||
|   account: "アカウント" | ||||
|   location: "場所" | ||||
|   description: "自己紹介" | ||||
|   birthday: "誕生日" | ||||
|   avatar: "アイコン" | ||||
|   banner: "バナー" | ||||
|   is-cat: "このアカウントはCatです" | ||||
|   is-bot: "このアカウントはBotです" | ||||
|   is-locked: "フォローを承認制にする" | ||||
|   careful-bot: "Botからのフォローだけ承認制にする" | ||||
|   advanced: "その他" | ||||
|   privacy: "プライバシー" | ||||
|   save: "保存" | ||||
|   saved: "プロフィールを保存しました" | ||||
|   uploading: "アップロード中" | ||||
|   upload-failed: "アップロードに失敗しました" | ||||
| common/views/widgets/broadcast.vue: | ||||
|   fetching: "確認中" | ||||
|   no-broadcasts: "お知らせはありません" | ||||
| @@ -640,7 +674,7 @@ desktop/views/components/note-detail.vue: | ||||
|   location: "位置情報" | ||||
|   renote: "Renote" | ||||
|   add-reaction: "リアクション" | ||||
| desktop/views/components/notes.note.vue: | ||||
| desktop/views/components/note.vue: | ||||
|   reposted-by: "{}がRenote" | ||||
|   reply: "返信" | ||||
|   renote: "Renote" | ||||
| @@ -726,8 +760,12 @@ desktop/views/components/settings.vue: | ||||
|   advanced: "詳細設定" | ||||
|   api-via-stream: "ストリームを経由したAPIリクエスト" | ||||
|   api-via-stream-desc: "この設定をオンにすると、websocket接続を経由してAPIリクエストが行われます(パフォーマンス向上が期待できます)。オフにすると、ネイティブの fetch APIが利用されます。この設定はこのデバイスのみ有効です。" | ||||
|   deck-nav: "デッキ内ナビゲーション" | ||||
|   deck-nav-desc: "デッキを使用しているとき、ナビゲーションが発生する際にページ遷移を行わずに一時的なカラムで受けるようにします。" | ||||
|   deck-default: "デッキをデフォルトのUIにする" | ||||
|   display: "デザインと表示" | ||||
|   customize: "ホームをカスタマイズ" | ||||
|   wallpaper: "壁紙" | ||||
|   choose-wallpaper: "壁紙を選択" | ||||
|   delete-wallpaper: "壁紙を削除" | ||||
|   dark-mode: "ダークモード" | ||||
| @@ -739,17 +777,19 @@ desktop/views/components/settings.vue: | ||||
|   suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する" | ||||
|   show-clock-on-header: "右上に時計を表示する" | ||||
|   show-reply-target: "リプライ先を表示する" | ||||
|   timeline: "タイムライン" | ||||
|   show-my-renotes: "自分の行ったRenoteをタイムラインに表示する" | ||||
|   show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する" | ||||
|   show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する" | ||||
|   show-maps: "マップの自動展開" | ||||
|   deck-column-align: "デッキのカラムの位置" | ||||
|   deck-column-align-center: "中央" | ||||
|   deck-column-align-left: "左" | ||||
|   sound: "サウンド" | ||||
|   enable-sounds: "サウンドを有効にする" | ||||
|   enable-sounds-desc: "投稿やメッセージを送受信したときなどにサウンドを再生します。この設定はブラウザに記憶されます。" | ||||
|   volume: "ボリューム" | ||||
|   test: "テスト" | ||||
|   mobile: "モバイル" | ||||
|   disable-via-mobile: "「モバイルからの投稿」フラグを付けない" | ||||
|   language: "言語" | ||||
|   pick-language: "言語を選択" | ||||
|   recommended: "推奨" | ||||
| @@ -828,21 +868,6 @@ desktop/views/components/settings.password.vue: | ||||
|   enter-new-password-again: "もう一度新しいパスワードを入力してください" | ||||
|   not-match: "新しいパスワードが一致しません" | ||||
|   changed: "パスワードを変更しました" | ||||
| desktop/views/components/settings.profile.vue: | ||||
|   avatar: "アイコン" | ||||
|   choice-avatar: "画像を選択" | ||||
|   name: "名前" | ||||
|   location: "場所" | ||||
|   description: "自己紹介" | ||||
|   birthday: "誕生日" | ||||
|   save: "保存" | ||||
|   locked-account: "アカウントの保護" | ||||
|   is-locked: "フォローを承認制にする" | ||||
|   careful-bot: "Botからのフォローだけ承認制にする" | ||||
|   other: "その他" | ||||
|   is-bot: "このアカウントはBotです" | ||||
|   is-cat: "このアカウントはCatです" | ||||
|   profile-updated: "プロフィールを更新しました" | ||||
| desktop/views/components/sub-note-content.vue: | ||||
|   private: "この投稿は非公開です" | ||||
|   deleted: "この投稿は削除されました" | ||||
| @@ -914,6 +939,8 @@ desktop/views/pages/admin/admin.vue: | ||||
|   drive: "ドライブ" | ||||
|   users: "Usuários" | ||||
|   update: "Actualizações" | ||||
|   announcements: "お知らせ" | ||||
|   hashtags: "ハッシュタグ" | ||||
| desktop/views/pages/admin/admin.dashboard.vue: | ||||
|   dashboard: "ダッシュボード" | ||||
|   all-users: "Todos os usuários" | ||||
| @@ -921,6 +948,9 @@ desktop/views/pages/admin/admin.dashboard.vue: | ||||
|   all-notes: "全ての投稿" | ||||
|   original-notes: "このインスタンスの投稿" | ||||
|   invite: "招待" | ||||
|   banner-url: "Banner URL" | ||||
|   disableRegistration: "Disable new user registration" | ||||
|   disableLocalTimeline: "Disable the local timeline" | ||||
| desktop/views/pages/admin/admin.suspend-user.vue: | ||||
|   suspend-user: "ユーザーの凍結" | ||||
|   suspend: "凍結" | ||||
| @@ -937,14 +967,23 @@ desktop/views/pages/admin/admin.unverify-user.vue: | ||||
|   unverify-user: "ユーザーの公式アカウント解除" | ||||
|   unverify: "公式アカウントを解除する" | ||||
|   unverified: "公式アカウントを解除しました" | ||||
| desktop/views/pages/admin/admin.announcements.vue: | ||||
|   announcements: "お知らせ" | ||||
| desktop/views/pages/admin/admin.hashtags.vue: | ||||
|   hided-tags: "Hidden Tags" | ||||
| desktop/views/pages/deck/deck.tl-column.vue: | ||||
|   is-media-only: "メディア投稿のみ" | ||||
|   is-media-view: "メディアビュー" | ||||
|   edit: "オプション" | ||||
| desktop/views/pages/deck/deck.note.vue: | ||||
|   reposted-by: "{}がRenote" | ||||
|   private: "この投稿は非公開です" | ||||
|   deleted: "この投稿は削除されました" | ||||
| desktop/views/pages/deck/deck.user-column.vue: | ||||
|   posts: "投稿" | ||||
|   following: "フォロー" | ||||
|   followers: "フォロワー" | ||||
|   images: "画像" | ||||
|   activity: "アクティビティ" | ||||
|   timeline: "タイムライン" | ||||
|   pinned-notes: "ピン留めされた投稿" | ||||
|   push-to-a-list: "リストに追加" | ||||
| desktop/views/pages/stats/stats.vue: | ||||
|   all-users: "全てのユーザー" | ||||
|   original-users: "このインスタンスのユーザー" | ||||
| @@ -997,9 +1036,6 @@ desktop/views/pages/user/user.friends.vue: | ||||
|   no-users: "よく話すユーザーはいません" | ||||
| desktop/views/pages/user/user.vue: | ||||
|   is-suspended: "このユーザーは凍結されています。" | ||||
|   is-remote: "このユーザーはリモートユーザーです。" | ||||
|   view-remote: "正確な情報を見る" | ||||
| desktop/views/pages/user/user.home.vue: | ||||
|   last-used-at: "最終アクセス" | ||||
| desktop/views/pages/user/user.photos.vue: | ||||
|   title: "フォト" | ||||
| @@ -1020,6 +1056,10 @@ desktop/views/pages/user/user.header.vue: | ||||
|   following: "フォロー" | ||||
|   followers: "フォロワー" | ||||
|   is-bot: "このアカウントはBotです" | ||||
|   years-old: "歳" | ||||
|   year: "年" | ||||
|   month: "月" | ||||
|   day: "日" | ||||
| desktop/views/pages/user/user.timeline.vue: | ||||
|   default: "投稿" | ||||
|   with-replies: "投稿と返信" | ||||
| @@ -1221,24 +1261,6 @@ mobile/views/pages/notifications.vue: | ||||
|   read-all: "すべての通知を既読にしますか?" | ||||
| mobile/views/pages/games/reversi.vue: | ||||
|   reversi: "リバーシ" | ||||
| mobile/views/pages/settings/settings.profile.vue: | ||||
|   title: "プロフィール" | ||||
|   name: "Nome" | ||||
|   account: "Conta" | ||||
|   location: "Lugar" | ||||
|   description: "Biografia" | ||||
|   birthday: "Data de nascimento" | ||||
|   avatar: "Avatar" | ||||
|   banner: "Capa" | ||||
|   is-cat: "Esta conta é gato" | ||||
|   is-locked: "Pedido para seguir precisa ser aprovado" | ||||
|   careful-bot: "Botからのフォローだけ承認制にする" | ||||
|   advanced: "Avançado" | ||||
|   privacy: "Provacidade" | ||||
|   save: "Atualizar perfil" | ||||
|   saved: "Perfil atualizado" | ||||
|   uploading: "Enviando" | ||||
|   upload-failed: "Falha ao enviar" | ||||
| mobile/views/pages/search.vue: | ||||
|   search: "Pesquisar" | ||||
|   empty: "「{}」に関する投稿は見つかりませんでした。" | ||||
| @@ -1294,6 +1316,7 @@ mobile/views/pages/settings.vue: | ||||
|   signout: "Sair" | ||||
|   sound: "Sons" | ||||
|   enable-sounds: "Ativar sons" | ||||
|   mark-as-read-all-unread-notes: "すべての投稿を既読にする" | ||||
| mobile/views/pages/user.vue: | ||||
|   follows-you: "Te segue" | ||||
|   following: "Seguindo" | ||||
| @@ -1303,8 +1326,6 @@ mobile/views/pages/user.vue: | ||||
|   timeline: "Linha do tempo" | ||||
|   media: "Mídia" | ||||
|   is-suspended: "Esta conta foi suspensa" | ||||
|   is-remote: "Este é uma usuário remoto. O perfil que vê aqui pode não estar completo." | ||||
|   view-remote: "Ver o perfil completo." | ||||
| mobile/views/pages/user/home.vue: | ||||
|   recent-notes: "Notas recentes" | ||||
|   images: "Imagens" | ||||
| @@ -1313,7 +1334,7 @@ mobile/views/pages/user/home.vue: | ||||
|   domains: "Domínios" | ||||
|   frequently-replied-users: "Perguntas frequentes" | ||||
|   followers-you-know: "Seguidores que você conhece" | ||||
|   last-used-at: "Ativo pela última vez:" | ||||
|   last-used-at: "Ativo pela última vez" | ||||
| mobile/views/pages/user/home.followers-you-know.vue: | ||||
|   loading: "Carregando" | ||||
|   no-users: "知り合いのユーザーはいません" | ||||
| @@ -1350,3 +1371,29 @@ docs: | ||||
|       description: "Descrição" | ||||
| dev/views/index.vue: | ||||
|   manage-apps: "Gerenciar aplicativos" | ||||
| dev/views/apps.vue: | ||||
|   manage-apps: "アプリを管理" | ||||
|   create-app: "アプリ作成" | ||||
|   app-missing: "アプリなし" | ||||
| dev/views/new-app.vue: | ||||
|   create-app: "アプリケーションの作成" | ||||
|   app-name: "アプリケーション名" | ||||
|   app-name-desc: "あなたのアプリの名称。" | ||||
|   app-name-ex: "ex) Misskey for iOS" | ||||
|   app-overview: "アプリの概要" | ||||
|   app-desc: "あなたのアプリの簡単な説明や紹介。" | ||||
|   app-desc-ex: "ex) Misskey iOSクライアント。" | ||||
|   callback-url: "コールバックURL (オプション)" | ||||
|   callback-url-desc: "ユーザーが認証フォームで認証した際にリダイレクトするURLを設定できます。" | ||||
|   authority: "権限" | ||||
|   authority-desc: "ここで要求した機能だけがAPIからアクセスできます。" | ||||
|   authority-warning: "アプリ作成後も変更できますが、新たな権限を付与する場合、その時点で関連付けられているユーザーキーはすべて無効になります。" | ||||
|   account-read: "アカウントの情報を見る。" | ||||
|   account-write: "アカウントの情報を操作する。" | ||||
|   note-write: "投稿する。" | ||||
|   reaction-write: "リアクションしたりリアクションをキャンセルする。" | ||||
|   following-write: "フォローしたりフォロー解除する。" | ||||
|   drive-read: "ドライブを見る。" | ||||
|   drive-write: "ドライブを操作する。" | ||||
|   notification-read: "通知を見る。" | ||||
|   notification-write: "通知を操作する。" | ||||
|   | ||||
| @@ -25,6 +25,14 @@ common: | ||||
|   application-authorization: "アプリの連携" | ||||
|   close: "閉じる" | ||||
|   do-not-copy-paste: "ここにコードを入力したり張り付けたりしないでください。アカウントが不正利用される可能性があります。" | ||||
|   BSoD: | ||||
|     fatal-error: ":( 致命的な問題が発生しました。" | ||||
|     update-browser-os: "お使いのブラウザ(またはOS)のバージョンを更新すると解決する可能性があります。" | ||||
|     error-code: "エラーコード" | ||||
|     browser-version: "ブラウザ バージョン" | ||||
|     client-version: "クライアント バージョン" | ||||
|     email-support: "問題が解決しない場合は、上記の情報をお書き添えの上 syuilotan@yahoo.co.jp までご連絡ください。" | ||||
|     thanks: "Thank you for using Misskey." | ||||
|   got-it: "わかった" | ||||
|   customization-tips: | ||||
|     title: "カスタマイズのヒント" | ||||
| @@ -115,6 +123,12 @@ common: | ||||
|   reduce-motion: "UIの動きを減らす" | ||||
|   this-setting-is-this-device-only: "このデバイスのみ" | ||||
|   do-not-use-in-production: 'これは開発ビルドです。本番環境で使用しないでください。' | ||||
|   is-remote-user: "このユーザー情報はコピーです。" | ||||
|   is-remote-post: "この投稿情報はコピーです。" | ||||
|   view-on-remote: "正確な情報を見る" | ||||
|   error: | ||||
|     title: '問題が発生しました' | ||||
|     retry: 'やり直す' | ||||
|   reversi: | ||||
|     drawn: "引き分け" | ||||
|     my-turn: "あなたのターンです" | ||||
| @@ -170,6 +184,7 @@ common: | ||||
|     rename: "名前を変更" | ||||
|     stack-left: "左に重ねる" | ||||
|     pop-right: "右に出す" | ||||
|   dev: "アプリの作成に失敗しました。再度お試しください。" | ||||
| auth/views/form.vue: | ||||
|   share-access: "<i>{{ app.name }}</i>があなたのアカウントにアクセスすることを<b>許可</b>しますか?" | ||||
|   permission-ask: "このアプリは次の権限を要求しています:" | ||||
| @@ -416,6 +431,25 @@ common/views/components/visibility-chooser.vue: | ||||
| common/views/components/trends.vue: | ||||
|   count: "{}人が投稿" | ||||
|   empty: "トレンドなし" | ||||
| common/views/components/profile-editor.vue: | ||||
|   title: "プロフィール" | ||||
|   name: "名前" | ||||
|   account: "アカウント" | ||||
|   location: "場所" | ||||
|   description: "自己紹介" | ||||
|   birthday: "誕生日" | ||||
|   avatar: "アイコン" | ||||
|   banner: "バナー" | ||||
|   is-cat: "このアカウントはCatです" | ||||
|   is-bot: "このアカウントはBotです" | ||||
|   is-locked: "フォローを承認制にする" | ||||
|   careful-bot: "Botからのフォローだけ承認制にする" | ||||
|   advanced: "その他" | ||||
|   privacy: "プライバシー" | ||||
|   save: "保存" | ||||
|   saved: "プロフィールを保存しました" | ||||
|   uploading: "アップロード中" | ||||
|   upload-failed: "アップロードに失敗しました" | ||||
| common/views/widgets/broadcast.vue: | ||||
|   fetching: "確認中" | ||||
|   no-broadcasts: "お知らせはありません" | ||||
| @@ -640,7 +674,7 @@ desktop/views/components/note-detail.vue: | ||||
|   location: "位置情報" | ||||
|   renote: "Renote" | ||||
|   add-reaction: "リアクション" | ||||
| desktop/views/components/notes.note.vue: | ||||
| desktop/views/components/note.vue: | ||||
|   reposted-by: "{}がRenote" | ||||
|   reply: "返信" | ||||
|   renote: "Renote" | ||||
| @@ -726,8 +760,12 @@ desktop/views/components/settings.vue: | ||||
|   advanced: "詳細設定" | ||||
|   api-via-stream: "ストリームを経由したAPIリクエスト" | ||||
|   api-via-stream-desc: "この設定をオンにすると、websocket接続を経由してAPIリクエストが行われます(パフォーマンス向上が期待できます)。オフにすると、ネイティブの fetch APIが利用されます。この設定はこのデバイスのみ有効です。" | ||||
|   deck-nav: "デッキ内ナビゲーション" | ||||
|   deck-nav-desc: "デッキを使用しているとき、ナビゲーションが発生する際にページ遷移を行わずに一時的なカラムで受けるようにします。" | ||||
|   deck-default: "デッキをデフォルトのUIにする" | ||||
|   display: "デザインと表示" | ||||
|   customize: "ホームをカスタマイズ" | ||||
|   wallpaper: "壁紙" | ||||
|   choose-wallpaper: "壁紙を選択" | ||||
|   delete-wallpaper: "壁紙を削除" | ||||
|   dark-mode: "ダークモード" | ||||
| @@ -739,17 +777,19 @@ desktop/views/components/settings.vue: | ||||
|   suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する" | ||||
|   show-clock-on-header: "右上に時計を表示する" | ||||
|   show-reply-target: "リプライ先を表示する" | ||||
|   timeline: "タイムライン" | ||||
|   show-my-renotes: "自分の行ったRenoteをタイムラインに表示する" | ||||
|   show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する" | ||||
|   show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する" | ||||
|   show-maps: "マップの自動展開" | ||||
|   deck-column-align: "デッキのカラムの位置" | ||||
|   deck-column-align-center: "中央" | ||||
|   deck-column-align-left: "左" | ||||
|   sound: "サウンド" | ||||
|   enable-sounds: "サウンドを有効にする" | ||||
|   enable-sounds-desc: "投稿やメッセージを送受信したときなどにサウンドを再生します。この設定はブラウザに記憶されます。" | ||||
|   volume: "ボリューム" | ||||
|   test: "テスト" | ||||
|   mobile: "モバイル" | ||||
|   disable-via-mobile: "「モバイルからの投稿」フラグを付けない" | ||||
|   language: "言語" | ||||
|   pick-language: "言語を選択" | ||||
|   recommended: "推奨" | ||||
| @@ -828,21 +868,6 @@ desktop/views/components/settings.password.vue: | ||||
|   enter-new-password-again: "もう一度新しいパスワードを入力してください" | ||||
|   not-match: "新しいパスワードが一致しません" | ||||
|   changed: "パスワードを変更しました" | ||||
| desktop/views/components/settings.profile.vue: | ||||
|   avatar: "アイコン" | ||||
|   choice-avatar: "画像を選択" | ||||
|   name: "名前" | ||||
|   location: "場所" | ||||
|   description: "自己紹介" | ||||
|   birthday: "誕生日" | ||||
|   save: "保存" | ||||
|   locked-account: "アカウントの保護" | ||||
|   is-locked: "フォローを承認制にする" | ||||
|   careful-bot: "Botからのフォローだけ承認制にする" | ||||
|   other: "その他" | ||||
|   is-bot: "このアカウントはBotです" | ||||
|   is-cat: "このアカウントはCatです" | ||||
|   profile-updated: "プロフィールを更新しました" | ||||
| desktop/views/components/sub-note-content.vue: | ||||
|   private: "この投稿は非公開です" | ||||
|   deleted: "この投稿は削除されました" | ||||
| @@ -914,6 +939,8 @@ desktop/views/pages/admin/admin.vue: | ||||
|   drive: "ドライブ" | ||||
|   users: "ユーザー" | ||||
|   update: "更新" | ||||
|   announcements: "お知らせ" | ||||
|   hashtags: "ハッシュタグ" | ||||
| desktop/views/pages/admin/admin.dashboard.vue: | ||||
|   dashboard: "ダッシュボード" | ||||
|   all-users: "全てのユーザー" | ||||
| @@ -921,6 +948,9 @@ desktop/views/pages/admin/admin.dashboard.vue: | ||||
|   all-notes: "全ての投稿" | ||||
|   original-notes: "このインスタンスの投稿" | ||||
|   invite: "招待" | ||||
|   banner-url: "Banner URL" | ||||
|   disableRegistration: "Disable new user registration" | ||||
|   disableLocalTimeline: "Disable the local timeline" | ||||
| desktop/views/pages/admin/admin.suspend-user.vue: | ||||
|   suspend-user: "ユーザーの凍結" | ||||
|   suspend: "凍結" | ||||
| @@ -937,14 +967,23 @@ desktop/views/pages/admin/admin.unverify-user.vue: | ||||
|   unverify-user: "ユーザーの公式アカウント解除" | ||||
|   unverify: "公式アカウントを解除する" | ||||
|   unverified: "公式アカウントを解除しました" | ||||
| desktop/views/pages/admin/admin.announcements.vue: | ||||
|   announcements: "お知らせ" | ||||
| desktop/views/pages/admin/admin.hashtags.vue: | ||||
|   hided-tags: "Hidden Tags" | ||||
| desktop/views/pages/deck/deck.tl-column.vue: | ||||
|   is-media-only: "メディア投稿のみ" | ||||
|   is-media-view: "メディアビュー" | ||||
|   edit: "オプション" | ||||
| desktop/views/pages/deck/deck.note.vue: | ||||
|   reposted-by: "{}がRenote" | ||||
|   private: "この投稿は非公開です" | ||||
|   deleted: "この投稿は削除されました" | ||||
| desktop/views/pages/deck/deck.user-column.vue: | ||||
|   posts: "投稿" | ||||
|   following: "フォロー" | ||||
|   followers: "フォロワー" | ||||
|   images: "画像" | ||||
|   activity: "アクティビティ" | ||||
|   timeline: "タイムライン" | ||||
|   pinned-notes: "ピン留めされた投稿" | ||||
|   push-to-a-list: "リストに追加" | ||||
| desktop/views/pages/stats/stats.vue: | ||||
|   all-users: "全てのユーザー" | ||||
|   original-users: "このインスタンスのユーザー" | ||||
| @@ -997,9 +1036,6 @@ desktop/views/pages/user/user.friends.vue: | ||||
|   no-users: "よく話すユーザーはいません" | ||||
| desktop/views/pages/user/user.vue: | ||||
|   is-suspended: "このユーザーは凍結されています。" | ||||
|   is-remote: "このユーザーはリモートユーザーです。" | ||||
|   view-remote: "正確な情報を見る" | ||||
| desktop/views/pages/user/user.home.vue: | ||||
|   last-used-at: "最終アクセス" | ||||
| desktop/views/pages/user/user.photos.vue: | ||||
|   title: "フォト" | ||||
| @@ -1020,6 +1056,10 @@ desktop/views/pages/user/user.header.vue: | ||||
|   following: "フォロー" | ||||
|   followers: "フォロワー" | ||||
|   is-bot: "このアカウントはBotです" | ||||
|   years-old: "歳" | ||||
|   year: "年" | ||||
|   month: "月" | ||||
|   day: "日" | ||||
| desktop/views/pages/user/user.timeline.vue: | ||||
|   default: "投稿" | ||||
|   with-replies: "投稿と返信" | ||||
| @@ -1221,24 +1261,6 @@ mobile/views/pages/notifications.vue: | ||||
|   read-all: "すべての通知を既読にしますか?" | ||||
| mobile/views/pages/games/reversi.vue: | ||||
|   reversi: "リバーシ" | ||||
| mobile/views/pages/settings/settings.profile.vue: | ||||
|   title: "プロフィール" | ||||
|   name: "名前" | ||||
|   account: "アカウント" | ||||
|   location: "場所" | ||||
|   description: "自己紹介" | ||||
|   birthday: "誕生日" | ||||
|   avatar: "アイコン" | ||||
|   banner: "バナー" | ||||
|   is-cat: "このアカウントはCatです" | ||||
|   is-locked: "フォローを承認制にする" | ||||
|   careful-bot: "Botからのフォローだけ承認制にする" | ||||
|   advanced: "その他" | ||||
|   privacy: "プライバシー" | ||||
|   save: "保存" | ||||
|   saved: "プロフィールを保存しました" | ||||
|   uploading: "アップロード中" | ||||
|   upload-failed: "アップロードに失敗しました" | ||||
| mobile/views/pages/search.vue: | ||||
|   search: "検索" | ||||
|   empty: "「{}」に関する投稿は見つかりませんでした。" | ||||
| @@ -1294,6 +1316,7 @@ mobile/views/pages/settings.vue: | ||||
|   signout: "サインアウト" | ||||
|   sound: "サウンド" | ||||
|   enable-sounds: "サウンドを有効にする" | ||||
|   mark-as-read-all-unread-notes: "すべての投稿を既読にする" | ||||
| mobile/views/pages/user.vue: | ||||
|   follows-you: "フォローされています" | ||||
|   following: "フォロー" | ||||
| @@ -1303,8 +1326,6 @@ mobile/views/pages/user.vue: | ||||
|   timeline: "タイムライン" | ||||
|   media: "メディア" | ||||
|   is-suspended: "このユーザーは凍結されています。" | ||||
|   is-remote: "このユーザーはリモートユーザーです。" | ||||
|   view-remote: "正確な情報を見る" | ||||
| mobile/views/pages/user/home.vue: | ||||
|   recent-notes: "最近の投稿" | ||||
|   images: "画像" | ||||
| @@ -1350,3 +1371,29 @@ docs: | ||||
|       description: "説明" | ||||
| dev/views/index.vue: | ||||
|   manage-apps: "アプリの管理" | ||||
| dev/views/apps.vue: | ||||
|   manage-apps: "アプリを管理" | ||||
|   create-app: "アプリ作成" | ||||
|   app-missing: "アプリなし" | ||||
| dev/views/new-app.vue: | ||||
|   create-app: "アプリケーションの作成" | ||||
|   app-name: "アプリケーション名" | ||||
|   app-name-desc: "あなたのアプリの名称。" | ||||
|   app-name-ex: "ex) Misskey for iOS" | ||||
|   app-overview: "アプリの概要" | ||||
|   app-desc: "あなたのアプリの簡単な説明や紹介。" | ||||
|   app-desc-ex: "ex) Misskey iOSクライアント。" | ||||
|   callback-url: "コールバックURL (オプション)" | ||||
|   callback-url-desc: "ユーザーが認証フォームで認証した際にリダイレクトするURLを設定できます。" | ||||
|   authority: "権限" | ||||
|   authority-desc: "ここで要求した機能だけがAPIからアクセスできます。" | ||||
|   authority-warning: "アプリ作成後も変更できますが、新たな権限を付与する場合、その時点で関連付けられているユーザーキーはすべて無効になります。" | ||||
|   account-read: "アカウントの情報を見る。" | ||||
|   account-write: "アカウントの情報を操作する。" | ||||
|   note-write: "投稿する。" | ||||
|   reaction-write: "リアクションしたりリアクションをキャンセルする。" | ||||
|   following-write: "フォローしたりフォロー解除する。" | ||||
|   drive-read: "ドライブを見る。" | ||||
|   drive-write: "ドライブを操作する。" | ||||
|   notification-read: "通知を見る。" | ||||
|   notification-write: "通知を操作する。" | ||||
|   | ||||
| @@ -25,6 +25,14 @@ common: | ||||
|   application-authorization: "アプリの連携" | ||||
|   close: "閉じる" | ||||
|   do-not-copy-paste: "ここにコードを入力したり張り付けたりしないでください。アカウントが不正利用される可能性があります。" | ||||
|   BSoD: | ||||
|     fatal-error: ":( 致命的な問題が発生しました。" | ||||
|     update-browser-os: "お使いのブラウザ(またはOS)のバージョンを更新すると解決する可能性があります。" | ||||
|     error-code: "エラーコード" | ||||
|     browser-version: "ブラウザ バージョン" | ||||
|     client-version: "クライアント バージョン" | ||||
|     email-support: "問題が解決しない場合は、上記の情報をお書き添えの上 syuilotan@yahoo.co.jp までご連絡ください。" | ||||
|     thanks: "Thank you for using Misskey." | ||||
|   got-it: "わかった" | ||||
|   customization-tips: | ||||
|     title: "カスタマイズのヒント" | ||||
| @@ -115,6 +123,12 @@ common: | ||||
|   reduce-motion: "UIの動きを減らす" | ||||
|   this-setting-is-this-device-only: "このデバイスのみ" | ||||
|   do-not-use-in-production: 'これは開発ビルドです。本番環境で使用しないでください。' | ||||
|   is-remote-user: "このユーザー情報はコピーです。" | ||||
|   is-remote-post: "この投稿情報はコピーです。" | ||||
|   view-on-remote: "正確な情報を見る" | ||||
|   error: | ||||
|     title: '問題が発生しました' | ||||
|     retry: 'やり直す' | ||||
|   reversi: | ||||
|     drawn: "引き分け" | ||||
|     my-turn: "あなたのターンです" | ||||
| @@ -170,6 +184,7 @@ common: | ||||
|     rename: "名前を変更" | ||||
|     stack-left: "左に重ねる" | ||||
|     pop-right: "右に出す" | ||||
|   dev: "アプリの作成に失敗しました。再度お試しください。" | ||||
| auth/views/form.vue: | ||||
|   share-access: "<i>{{ app.name }}</i>があなたのアカウントにアクセスすることを<b>許可</b>しますか?" | ||||
|   permission-ask: "このアプリは次の権限を要求しています:" | ||||
| @@ -416,6 +431,25 @@ common/views/components/visibility-chooser.vue: | ||||
| common/views/components/trends.vue: | ||||
|   count: "{}人が投稿" | ||||
|   empty: "トレンドなし" | ||||
| common/views/components/profile-editor.vue: | ||||
|   title: "プロフィール" | ||||
|   name: "名前" | ||||
|   account: "アカウント" | ||||
|   location: "場所" | ||||
|   description: "自己紹介" | ||||
|   birthday: "誕生日" | ||||
|   avatar: "アイコン" | ||||
|   banner: "バナー" | ||||
|   is-cat: "このアカウントはCatです" | ||||
|   is-bot: "このアカウントはBotです" | ||||
|   is-locked: "フォローを承認制にする" | ||||
|   careful-bot: "Botからのフォローだけ承認制にする" | ||||
|   advanced: "その他" | ||||
|   privacy: "プライバシー" | ||||
|   save: "保存" | ||||
|   saved: "プロフィールを保存しました" | ||||
|   uploading: "アップロード中" | ||||
|   upload-failed: "アップロードに失敗しました" | ||||
| common/views/widgets/broadcast.vue: | ||||
|   fetching: "確認中" | ||||
|   no-broadcasts: "お知らせはありません" | ||||
| @@ -640,7 +674,7 @@ desktop/views/components/note-detail.vue: | ||||
|   location: "位置情報" | ||||
|   renote: "Renote" | ||||
|   add-reaction: "リアクション" | ||||
| desktop/views/components/notes.note.vue: | ||||
| desktop/views/components/note.vue: | ||||
|   reposted-by: "{}がRenote" | ||||
|   reply: "返信" | ||||
|   renote: "Renote" | ||||
| @@ -726,8 +760,12 @@ desktop/views/components/settings.vue: | ||||
|   advanced: "詳細設定" | ||||
|   api-via-stream: "ストリームを経由したAPIリクエスト" | ||||
|   api-via-stream-desc: "この設定をオンにすると、websocket接続を経由してAPIリクエストが行われます(パフォーマンス向上が期待できます)。オフにすると、ネイティブの fetch APIが利用されます。この設定はこのデバイスのみ有効です。" | ||||
|   deck-nav: "デッキ内ナビゲーション" | ||||
|   deck-nav-desc: "デッキを使用しているとき、ナビゲーションが発生する際にページ遷移を行わずに一時的なカラムで受けるようにします。" | ||||
|   deck-default: "デッキをデフォルトのUIにする" | ||||
|   display: "デザインと表示" | ||||
|   customize: "ホームをカスタマイズ" | ||||
|   wallpaper: "壁紙" | ||||
|   choose-wallpaper: "壁紙を選択" | ||||
|   delete-wallpaper: "壁紙を削除" | ||||
|   dark-mode: "ダークモード" | ||||
| @@ -739,17 +777,19 @@ desktop/views/components/settings.vue: | ||||
|   suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する" | ||||
|   show-clock-on-header: "右上に時計を表示する" | ||||
|   show-reply-target: "リプライ先を表示する" | ||||
|   timeline: "タイムライン" | ||||
|   show-my-renotes: "自分の行ったRenoteをタイムラインに表示する" | ||||
|   show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する" | ||||
|   show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する" | ||||
|   show-maps: "マップの自動展開" | ||||
|   deck-column-align: "デッキのカラムの位置" | ||||
|   deck-column-align-center: "中央" | ||||
|   deck-column-align-left: "左" | ||||
|   sound: "サウンド" | ||||
|   enable-sounds: "サウンドを有効にする" | ||||
|   enable-sounds-desc: "投稿やメッセージを送受信したときなどにサウンドを再生します。この設定はブラウザに記憶されます。" | ||||
|   volume: "ボリューム" | ||||
|   test: "テスト" | ||||
|   mobile: "モバイル" | ||||
|   disable-via-mobile: "「モバイルからの投稿」フラグを付けない" | ||||
|   language: "言語" | ||||
|   pick-language: "言語を選択" | ||||
|   recommended: "推奨" | ||||
| @@ -828,21 +868,6 @@ desktop/views/components/settings.password.vue: | ||||
|   enter-new-password-again: "もう一度新しいパスワードを入力してください" | ||||
|   not-match: "新しいパスワードが一致しません" | ||||
|   changed: "パスワードを変更しました" | ||||
| desktop/views/components/settings.profile.vue: | ||||
|   avatar: "アイコン" | ||||
|   choice-avatar: "画像を選択" | ||||
|   name: "名前" | ||||
|   location: "場所" | ||||
|   description: "自己紹介" | ||||
|   birthday: "誕生日" | ||||
|   save: "保存" | ||||
|   locked-account: "アカウントの保護" | ||||
|   is-locked: "フォローを承認制にする" | ||||
|   careful-bot: "Botからのフォローだけ承認制にする" | ||||
|   other: "その他" | ||||
|   is-bot: "このアカウントはBotです" | ||||
|   is-cat: "このアカウントはCatです" | ||||
|   profile-updated: "プロフィールを更新しました" | ||||
| desktop/views/components/sub-note-content.vue: | ||||
|   private: "この投稿は非公開です" | ||||
|   deleted: "この投稿は削除されました" | ||||
| @@ -914,6 +939,8 @@ desktop/views/pages/admin/admin.vue: | ||||
|   drive: "ドライブ" | ||||
|   users: "ユーザー" | ||||
|   update: "更新" | ||||
|   announcements: "お知らせ" | ||||
|   hashtags: "ハッシュタグ" | ||||
| desktop/views/pages/admin/admin.dashboard.vue: | ||||
|   dashboard: "ダッシュボード" | ||||
|   all-users: "全てのユーザー" | ||||
| @@ -921,6 +948,9 @@ desktop/views/pages/admin/admin.dashboard.vue: | ||||
|   all-notes: "全ての投稿" | ||||
|   original-notes: "このインスタンスの投稿" | ||||
|   invite: "招待" | ||||
|   banner-url: "Banner URL" | ||||
|   disableRegistration: "Disable new user registration" | ||||
|   disableLocalTimeline: "Disable the local timeline" | ||||
| desktop/views/pages/admin/admin.suspend-user.vue: | ||||
|   suspend-user: "ユーザーの凍結" | ||||
|   suspend: "凍結" | ||||
| @@ -937,14 +967,23 @@ desktop/views/pages/admin/admin.unverify-user.vue: | ||||
|   unverify-user: "ユーザーの公式アカウント解除" | ||||
|   unverify: "公式アカウントを解除する" | ||||
|   unverified: "公式アカウントを解除しました" | ||||
| desktop/views/pages/admin/admin.announcements.vue: | ||||
|   announcements: "お知らせ" | ||||
| desktop/views/pages/admin/admin.hashtags.vue: | ||||
|   hided-tags: "Hidden Tags" | ||||
| desktop/views/pages/deck/deck.tl-column.vue: | ||||
|   is-media-only: "メディア投稿のみ" | ||||
|   is-media-view: "メディアビュー" | ||||
|   edit: "オプション" | ||||
| desktop/views/pages/deck/deck.note.vue: | ||||
|   reposted-by: "{}がRenote" | ||||
|   private: "この投稿は非公開です" | ||||
|   deleted: "この投稿は削除されました" | ||||
| desktop/views/pages/deck/deck.user-column.vue: | ||||
|   posts: "投稿" | ||||
|   following: "フォロー" | ||||
|   followers: "フォロワー" | ||||
|   images: "画像" | ||||
|   activity: "アクティビティ" | ||||
|   timeline: "タイムライン" | ||||
|   pinned-notes: "ピン留めされた投稿" | ||||
|   push-to-a-list: "リストに追加" | ||||
| desktop/views/pages/stats/stats.vue: | ||||
|   all-users: "全てのユーザー" | ||||
|   original-users: "このインスタンスのユーザー" | ||||
| @@ -997,9 +1036,6 @@ desktop/views/pages/user/user.friends.vue: | ||||
|   no-users: "よく話すユーザーはいません" | ||||
| desktop/views/pages/user/user.vue: | ||||
|   is-suspended: "このユーザーは凍結されています。" | ||||
|   is-remote: "このユーザーはリモートユーザーです。" | ||||
|   view-remote: "正確な情報を見る" | ||||
| desktop/views/pages/user/user.home.vue: | ||||
|   last-used-at: "最終アクセス" | ||||
| desktop/views/pages/user/user.photos.vue: | ||||
|   title: "フォト" | ||||
| @@ -1020,6 +1056,10 @@ desktop/views/pages/user/user.header.vue: | ||||
|   following: "フォロー" | ||||
|   followers: "フォロワー" | ||||
|   is-bot: "このアカウントはBotです" | ||||
|   years-old: "歳" | ||||
|   year: "年" | ||||
|   month: "月" | ||||
|   day: "日" | ||||
| desktop/views/pages/user/user.timeline.vue: | ||||
|   default: "投稿" | ||||
|   with-replies: "投稿と返信" | ||||
| @@ -1221,24 +1261,6 @@ mobile/views/pages/notifications.vue: | ||||
|   read-all: "すべての通知を既読にしますか?" | ||||
| mobile/views/pages/games/reversi.vue: | ||||
|   reversi: "リバーシ" | ||||
| mobile/views/pages/settings/settings.profile.vue: | ||||
|   title: "プロフィール" | ||||
|   name: "名前" | ||||
|   account: "アカウント" | ||||
|   location: "場所" | ||||
|   description: "自己紹介" | ||||
|   birthday: "誕生日" | ||||
|   avatar: "アイコン" | ||||
|   banner: "バナー" | ||||
|   is-cat: "このアカウントはCatです" | ||||
|   is-locked: "フォローを承認制にする" | ||||
|   careful-bot: "Botからのフォローだけ承認制にする" | ||||
|   advanced: "その他" | ||||
|   privacy: "プライバシー" | ||||
|   save: "保存" | ||||
|   saved: "プロフィールを保存しました" | ||||
|   uploading: "アップロード中" | ||||
|   upload-failed: "アップロードに失敗しました" | ||||
| mobile/views/pages/search.vue: | ||||
|   search: "検索" | ||||
|   empty: "「{}」に関する投稿は見つかりませんでした。" | ||||
| @@ -1294,6 +1316,7 @@ mobile/views/pages/settings.vue: | ||||
|   signout: "サインアウト" | ||||
|   sound: "サウンド" | ||||
|   enable-sounds: "サウンドを有効にする" | ||||
|   mark-as-read-all-unread-notes: "すべての投稿を既読にする" | ||||
| mobile/views/pages/user.vue: | ||||
|   follows-you: "フォローされています" | ||||
|   following: "フォロー" | ||||
| @@ -1303,8 +1326,6 @@ mobile/views/pages/user.vue: | ||||
|   timeline: "タイムライン" | ||||
|   media: "メディア" | ||||
|   is-suspended: "このユーザーは凍結されています。" | ||||
|   is-remote: "このユーザーはリモートユーザーです。" | ||||
|   view-remote: "正確な情報を見る" | ||||
| mobile/views/pages/user/home.vue: | ||||
|   recent-notes: "最近の投稿" | ||||
|   images: "画像" | ||||
| @@ -1350,3 +1371,29 @@ docs: | ||||
|       description: "説明" | ||||
| dev/views/index.vue: | ||||
|   manage-apps: "アプリの管理" | ||||
| dev/views/apps.vue: | ||||
|   manage-apps: "アプリを管理" | ||||
|   create-app: "アプリ作成" | ||||
|   app-missing: "アプリなし" | ||||
| dev/views/new-app.vue: | ||||
|   create-app: "アプリケーションの作成" | ||||
|   app-name: "アプリケーション名" | ||||
|   app-name-desc: "あなたのアプリの名称。" | ||||
|   app-name-ex: "ex) Misskey for iOS" | ||||
|   app-overview: "アプリの概要" | ||||
|   app-desc: "あなたのアプリの簡単な説明や紹介。" | ||||
|   app-desc-ex: "ex) Misskey iOSクライアント。" | ||||
|   callback-url: "コールバックURL (オプション)" | ||||
|   callback-url-desc: "ユーザーが認証フォームで認証した際にリダイレクトするURLを設定できます。" | ||||
|   authority: "権限" | ||||
|   authority-desc: "ここで要求した機能だけがAPIからアクセスできます。" | ||||
|   authority-warning: "アプリ作成後も変更できますが、新たな権限を付与する場合、その時点で関連付けられているユーザーキーはすべて無効になります。" | ||||
|   account-read: "アカウントの情報を見る。" | ||||
|   account-write: "アカウントの情報を操作する。" | ||||
|   note-write: "投稿する。" | ||||
|   reaction-write: "リアクションしたりリアクションをキャンセルする。" | ||||
|   following-write: "フォローしたりフォロー解除する。" | ||||
|   drive-read: "ドライブを見る。" | ||||
|   drive-write: "ドライブを操作する。" | ||||
|   notification-read: "通知を見る。" | ||||
|   notification-write: "通知を操作する。" | ||||
|   | ||||
							
								
								
									
										27
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										27
									
								
								package.json
									
									
									
									
									
								
							| @@ -1,8 +1,8 @@ | ||||
| { | ||||
| 	"name": "misskey", | ||||
| 	"author": "syuilo <i@syuilo.com>", | ||||
| 	"version": "10.20.0", | ||||
| 	"clientVersion": "1.0.10607", | ||||
| 	"version": "10.31.0", | ||||
| 	"clientVersion": "1.0.11051", | ||||
| 	"codename": "nighthike", | ||||
| 	"main": "./built/index.js", | ||||
| 	"private": true, | ||||
| @@ -20,10 +20,10 @@ | ||||
| 		"format": "gulp format" | ||||
| 	}, | ||||
| 	"dependencies": { | ||||
| 		"@fortawesome/fontawesome-svg-core": "1.2.4", | ||||
| 		"@fortawesome/free-brands-svg-icons": "5.3.1", | ||||
| 		"@fortawesome/free-regular-svg-icons": "5.3.1", | ||||
| 		"@fortawesome/free-solid-svg-icons": "5.3.1", | ||||
| 		"@fortawesome/fontawesome-svg-core": "1.2.6", | ||||
| 		"@fortawesome/free-brands-svg-icons": "5.4.1", | ||||
| 		"@fortawesome/free-regular-svg-icons": "5.4.1", | ||||
| 		"@fortawesome/free-solid-svg-icons": "5.4.1", | ||||
| 		"@koa/cors": "2.2.2", | ||||
| 		"@prezzemolo/rap": "0.1.2", | ||||
| 		"@prezzemolo/zip": "0.0.3", | ||||
| @@ -33,7 +33,7 @@ | ||||
| 		"@types/debug": "0.0.31", | ||||
| 		"@types/deep-equal": "1.0.1", | ||||
| 		"@types/double-ended-queue": "2.1.0", | ||||
| 		"@types/elasticsearch": "5.0.27", | ||||
| 		"@types/elasticsearch": "5.0.28", | ||||
| 		"@types/file-type": "5.2.1", | ||||
| 		"@types/gulp": "3.8.36", | ||||
| 		"@types/gulp-htmlmin": "1.3.32", | ||||
| @@ -84,6 +84,7 @@ | ||||
| 		"@types/websocket": "0.0.40", | ||||
| 		"@types/ws": "6.0.1", | ||||
| 		"animejs": "2.2.0", | ||||
| 		"apexcharts": "2.1.5", | ||||
| 		"autobind-decorator": "2.1.0", | ||||
| 		"autosize": "4.0.2", | ||||
| 		"autwh": "0.1.0", | ||||
| @@ -113,7 +114,7 @@ | ||||
| 		"eventemitter3": "3.1.0", | ||||
| 		"exif-js": "2.3.0", | ||||
| 		"file-loader": "2.0.0", | ||||
| 		"file-type": "10.0.0", | ||||
| 		"file-type": "10.1.0", | ||||
| 		"fuckadblock": "3.2.1", | ||||
| 		"gulp": "3.9.1", | ||||
| 		"gulp-cssnano": "2.1.3", | ||||
| @@ -179,7 +180,7 @@ | ||||
| 		"qrcode": "1.3.0", | ||||
| 		"ratelimiter": "3.2.0", | ||||
| 		"recaptcha-promise": "0.1.3", | ||||
| 		"reconnecting-websocket": "4.1.8", | ||||
| 		"reconnecting-websocket": "4.1.10", | ||||
| 		"redis": "2.8.0", | ||||
| 		"request": "2.88.0", | ||||
| 		"request-promise-native": "1.0.5", | ||||
| @@ -190,7 +191,7 @@ | ||||
| 		"sass-loader": "7.1.0", | ||||
| 		"seedrandom": "2.4.4", | ||||
| 		"sharp": "0.21.0", | ||||
| 		"showdown": "1.8.6", | ||||
| 		"showdown": "1.8.7", | ||||
| 		"showdown-highlightjs-extension": "0.1.2", | ||||
| 		"single-line-log": "1.1.2", | ||||
| 		"speakeasy": "2.0.0", | ||||
| @@ -199,7 +200,7 @@ | ||||
| 		"stylus": "0.54.5", | ||||
| 		"stylus-loader": "3.0.2", | ||||
| 		"summaly": "2.2.0", | ||||
| 		"systeminformation": "3.45.7", | ||||
| 		"systeminformation": "3.45.9", | ||||
| 		"syuilo-password-strength": "0.0.1", | ||||
| 		"textarea-caret": "3.1.0", | ||||
| 		"tinycolor2": "1.4.1", | ||||
| @@ -224,7 +225,7 @@ | ||||
| 		"vue-router": "3.0.1", | ||||
| 		"vue-style-loader": "4.1.2", | ||||
| 		"vue-svg-inline-loader": "1.2.1", | ||||
| 		"vue-sweetalert2": "1.5.5", | ||||
| 		"vue-sweetalert2": "1.5.6", | ||||
| 		"vue-template-compiler": "2.5.17", | ||||
| 		"vuedraggable": "2.16.0", | ||||
| 		"vuewordcloud": "18.7.11", | ||||
| @@ -232,7 +233,7 @@ | ||||
| 		"vuex-persistedstate": "2.5.4", | ||||
| 		"web-push": "3.3.3", | ||||
| 		"webfinger.js": "2.6.6", | ||||
| 		"webpack": "4.20.2", | ||||
| 		"webpack": "4.22.0", | ||||
| 		"webpack-cli": "3.1.2", | ||||
| 		"websocket": "1.0.28", | ||||
| 		"ws": "6.1.0", | ||||
|   | ||||
							
								
								
									
										122
									
								
								src/chart/drive.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								src/chart/drive.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,122 @@ | ||||
| import autobind from 'autobind-decorator'; | ||||
| import Chart, { Obj } from './'; | ||||
| import DriveFile, { IDriveFile } from '../models/drive-file'; | ||||
| import { isLocalUser } from '../models/user'; | ||||
|  | ||||
| /** | ||||
|  * ドライブに関するチャート | ||||
|  */ | ||||
| type DriveLog = { | ||||
| 	local: { | ||||
| 		/** | ||||
| 		 * 集計期間時点での、全ドライブファイル数 | ||||
| 		 */ | ||||
| 		totalCount: number; | ||||
|  | ||||
| 		/** | ||||
| 		 * 集計期間時点での、全ドライブファイルの合計サイズ | ||||
| 		 */ | ||||
| 		totalSize: number; | ||||
|  | ||||
| 		/** | ||||
| 		 * 増加したドライブファイル数 | ||||
| 		 */ | ||||
| 		incCount: number; | ||||
|  | ||||
| 		/** | ||||
| 		 * 増加したドライブ使用量 | ||||
| 		 */ | ||||
| 		incSize: number; | ||||
|  | ||||
| 		/** | ||||
| 		 * 減少したドライブファイル数 | ||||
| 		 */ | ||||
| 		decCount: number; | ||||
|  | ||||
| 		/** | ||||
| 		 * 減少したドライブ使用量 | ||||
| 		 */ | ||||
| 		decSize: number; | ||||
| 	}; | ||||
|  | ||||
| 	remote: DriveLog['local']; | ||||
| }; | ||||
|  | ||||
| class DriveChart extends Chart<DriveLog> { | ||||
| 	constructor() { | ||||
| 		super('drive'); | ||||
| 	} | ||||
|  | ||||
| 	@autobind | ||||
| 	protected async getTemplate(init: boolean, latest?: DriveLog): Promise<DriveLog> { | ||||
| 		const calcSize = (local: boolean) => DriveFile | ||||
| 			.aggregate([{ | ||||
| 				$match: { | ||||
| 					'metadata._user.host': local ? null : { $ne: null }, | ||||
| 					'metadata.deletedAt': { $exists: false } | ||||
| 				} | ||||
| 			}, { | ||||
| 				$project: { | ||||
| 					length: true | ||||
| 				} | ||||
| 			}, { | ||||
| 				$group: { | ||||
| 					_id: null, | ||||
| 					usage: { $sum: '$length' } | ||||
| 				} | ||||
| 			}]) | ||||
| 			.then(res => res.length > 0 ? res[0].usage : 0); | ||||
|  | ||||
| 		const [localCount, remoteCount, localSize, remoteSize] = init ? await Promise.all([ | ||||
| 			DriveFile.count({ 'metadata._user.host': null }), | ||||
| 			DriveFile.count({ 'metadata._user.host': { $ne: null } }), | ||||
| 			calcSize(true), | ||||
| 			calcSize(false) | ||||
| 		]) : [ | ||||
| 			latest ? latest.local.totalCount : 0, | ||||
| 			latest ? latest.remote.totalCount : 0, | ||||
| 			latest ? latest.local.totalSize : 0, | ||||
| 			latest ? latest.remote.totalSize : 0 | ||||
| 		]; | ||||
|  | ||||
| 		return { | ||||
| 			local: { | ||||
| 				totalCount: localCount, | ||||
| 				totalSize: localSize, | ||||
| 				incCount: 0, | ||||
| 				incSize: 0, | ||||
| 				decCount: 0, | ||||
| 				decSize: 0 | ||||
| 			}, | ||||
| 			remote: { | ||||
| 				totalCount: remoteCount, | ||||
| 				totalSize: remoteSize, | ||||
| 				incCount: 0, | ||||
| 				incSize: 0, | ||||
| 				decCount: 0, | ||||
| 				decSize: 0 | ||||
| 			} | ||||
| 		}; | ||||
| 	} | ||||
|  | ||||
| 	@autobind | ||||
| 	public async update(file: IDriveFile, isAdditional: boolean) { | ||||
| 		const update: Obj = {}; | ||||
|  | ||||
| 		update.totalCount = isAdditional ? 1 : -1; | ||||
| 		update.totalSize = isAdditional ? file.length : -file.length; | ||||
| 		if (isAdditional) { | ||||
| 			update.incCount = 1; | ||||
| 			update.incSize = file.length; | ||||
| 		} else { | ||||
| 			update.decCount = 1; | ||||
| 			update.decSize = file.length; | ||||
| 		} | ||||
|  | ||||
| 		await this.inc({ | ||||
| 			[isLocalUser(file.metadata._user) ? 'local' : 'remote']: update | ||||
| 		}); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| export default new DriveChart(); | ||||
							
								
								
									
										66
									
								
								src/chart/federation.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								src/chart/federation.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,66 @@ | ||||
| import autobind from 'autobind-decorator'; | ||||
| import Chart, { Obj } from '.'; | ||||
| import Instance from '../models/instance'; | ||||
|  | ||||
| /** | ||||
|  * フェデレーションに関するチャート | ||||
|  */ | ||||
| type FederationLog = { | ||||
| 	instance: { | ||||
| 		/** | ||||
| 		 * インスタンス数の合計 | ||||
| 		 */ | ||||
| 		total: number; | ||||
|  | ||||
| 		/** | ||||
| 		 * 増加インスタンス数 | ||||
| 		 */ | ||||
| 		inc: number; | ||||
|  | ||||
| 		/** | ||||
| 		 * 減少インスタンス数 | ||||
| 		 */ | ||||
| 		dec: number; | ||||
| 	}; | ||||
| }; | ||||
|  | ||||
| class FederationChart extends Chart<FederationLog> { | ||||
| 	constructor() { | ||||
| 		super('federation'); | ||||
| 	} | ||||
|  | ||||
| 	@autobind | ||||
| 	protected async getTemplate(init: boolean, latest?: FederationLog): Promise<FederationLog> { | ||||
| 		const [total] = init ? await Promise.all([ | ||||
| 			Instance.count({}) | ||||
| 		]) : [ | ||||
| 			latest ? latest.instance.total : 0 | ||||
| 		]; | ||||
|  | ||||
| 		return { | ||||
| 			instance: { | ||||
| 				total: total, | ||||
| 				inc: 0, | ||||
| 				dec: 0 | ||||
| 			} | ||||
| 		}; | ||||
| 	} | ||||
|  | ||||
| 	@autobind | ||||
| 	public async update(isAdditional: boolean) { | ||||
| 		const update: Obj = {}; | ||||
|  | ||||
| 		update.total = isAdditional ? 1 : -1; | ||||
| 		if (isAdditional) { | ||||
| 			update.inc = 1; | ||||
| 		} else { | ||||
| 			update.dec = 1; | ||||
| 		} | ||||
|  | ||||
| 		await this.inc({ | ||||
| 			instance: update | ||||
| 		}); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| export default new FederationChart(); | ||||
							
								
								
									
										56
									
								
								src/chart/hashtag.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								src/chart/hashtag.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,56 @@ | ||||
| import autobind from 'autobind-decorator'; | ||||
| import Chart, { Obj } from './'; | ||||
| import { IUser, isLocalUser } from '../models/user'; | ||||
| import db from '../db/mongodb'; | ||||
|  | ||||
| /** | ||||
|  * ハッシュタグに関するチャート | ||||
|  */ | ||||
| type HashtagLog = { | ||||
| 	local: { | ||||
| 		/** | ||||
| 		 * 投稿された数 | ||||
| 		 */ | ||||
| 		count: number; | ||||
| 	}; | ||||
|  | ||||
| 	remote: HashtagLog['local']; | ||||
| }; | ||||
|  | ||||
| class HashtagChart extends Chart<HashtagLog> { | ||||
| 	constructor() { | ||||
| 		super('hashtag', true); | ||||
|  | ||||
| 		// 後方互換性のため | ||||
| 		db.get('chart.hashtag').findOne().then(doc => { | ||||
| 			if (doc != null && doc.data.local == null) { | ||||
| 				db.get('chart.hashtag').drop(); | ||||
| 			} | ||||
| 		}); | ||||
| 	} | ||||
|  | ||||
| 	@autobind | ||||
| 	protected async getTemplate(init: boolean, latest?: HashtagLog): Promise<HashtagLog> { | ||||
| 		return { | ||||
| 			local: { | ||||
| 				count: 0 | ||||
| 			}, | ||||
| 			remote: { | ||||
| 				count: 0 | ||||
| 			} | ||||
| 		}; | ||||
| 	} | ||||
|  | ||||
| 	@autobind | ||||
| 	public async update(hashtag: string, user: IUser) { | ||||
| 		const update: Obj = { | ||||
| 			count: 1 | ||||
| 		}; | ||||
|  | ||||
| 		await this.incIfUnique({ | ||||
| 			[isLocalUser(user) ? 'local' : 'remote']: update | ||||
| 		}, 'users', user._id.toHexString(), hashtag); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| export default new HashtagChart(); | ||||
							
								
								
									
										285
									
								
								src/chart/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										285
									
								
								src/chart/index.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,285 @@ | ||||
| /** | ||||
|  * チャートエンジン | ||||
|  */ | ||||
|  | ||||
| const nestedProperty = require('nested-property'); | ||||
| import autobind from 'autobind-decorator'; | ||||
| import * as mongo from 'mongodb'; | ||||
| import db from '../db/mongodb'; | ||||
| import { ICollection } from 'monk'; | ||||
|  | ||||
| export type Obj = { [key: string]: any }; | ||||
|  | ||||
| export type Partial<T> = { | ||||
| 	[P in keyof T]?: Partial<T[P]>; | ||||
| }; | ||||
|  | ||||
| type ArrayValue<T> = { | ||||
| 	[P in keyof T]: T[P] extends number ? Array<T[P]> : ArrayValue<T[P]>; | ||||
| }; | ||||
|  | ||||
| type Span = 'day' | 'hour'; | ||||
|  | ||||
| //#region Chart Core | ||||
| type Log<T extends Obj> = { | ||||
| 	_id: mongo.ObjectID; | ||||
|  | ||||
| 	/** | ||||
| 	 * 集計のグループ | ||||
| 	 */ | ||||
| 	group?: any; | ||||
|  | ||||
| 	/** | ||||
| 	 * 集計日時 | ||||
| 	 */ | ||||
| 	date: Date; | ||||
|  | ||||
| 	/** | ||||
| 	 * 集計期間 | ||||
| 	 */ | ||||
| 	span: Span; | ||||
|  | ||||
| 	/** | ||||
| 	 * データ | ||||
| 	 */ | ||||
| 	data: T; | ||||
|  | ||||
| 	/** | ||||
| 	 * ユニークインクリメント用 | ||||
| 	 */ | ||||
| 	unique?: Obj; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * 様々なチャートの管理を司るクラス | ||||
|  */ | ||||
| export default abstract class Chart<T> { | ||||
| 	protected collection: ICollection<Log<T>>; | ||||
| 	protected abstract async getTemplate(init: boolean, latest?: T, group?: any): Promise<T>; | ||||
|  | ||||
| 	constructor(name: string, grouped = false) { | ||||
| 		this.collection = db.get<Log<T>>(`chart.${name}`); | ||||
| 		if (grouped) { | ||||
| 			this.collection.createIndex({ span: -1, date: -1, group: -1 }, { unique: true }); | ||||
| 		} else { | ||||
| 			this.collection.createIndex({ span: -1, date: -1 }, { unique: true }); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	@autobind | ||||
| 	private convertQuery(x: Obj, path: string): Obj { | ||||
| 		const query: Obj = {}; | ||||
|  | ||||
| 		const dive = (x: Obj, path: string) => { | ||||
| 			Object.entries(x).forEach(([k, v]) => { | ||||
| 				const p = path ? `${path}.${k}` : k; | ||||
| 				if (typeof v === 'number') { | ||||
| 					query[p] = v; | ||||
| 				} else { | ||||
| 					dive(v, p); | ||||
| 				} | ||||
| 			}); | ||||
| 		}; | ||||
|  | ||||
| 		dive(x, path); | ||||
|  | ||||
| 		return query; | ||||
| 	} | ||||
|  | ||||
| 	@autobind | ||||
| 	private async getCurrentLog(span: Span, group?: any): Promise<Log<T>> { | ||||
| 		const now = new Date(); | ||||
| 		const y = now.getFullYear(); | ||||
| 		const m = now.getMonth(); | ||||
| 		const d = now.getDate(); | ||||
| 		const h = now.getHours(); | ||||
|  | ||||
| 		const current = | ||||
| 			span == 'day' ? new Date(y, m, d) : | ||||
| 			span == 'hour' ? new Date(y, m, d, h) : | ||||
| 			null; | ||||
|  | ||||
| 		// 現在(今日または今のHour)のログ | ||||
| 		const currentLog = await this.collection.findOne({ | ||||
| 			group: group, | ||||
| 			span: span, | ||||
| 			date: current | ||||
| 		}); | ||||
|  | ||||
| 		if (currentLog) { | ||||
| 			return currentLog; | ||||
| 		} | ||||
|  | ||||
| 		// 集計期間が変わってから、初めてのチャート更新なら | ||||
| 		// 最も最近のログを持ってくる | ||||
| 		// * 例えば集計期間が「日」である場合で考えると、 | ||||
| 		// * 昨日何もチャートを更新するような出来事がなかった場合は、 | ||||
| 		// * ログがそもそも作られずドキュメントが存在しないということがあり得るため、 | ||||
| 		// * 「昨日の」と決め打ちせずに「もっとも最近の」とします | ||||
| 		const latest = await this.collection.findOne({ | ||||
| 			group: group, | ||||
| 			span: span | ||||
| 		}, { | ||||
| 			sort: { | ||||
| 				date: -1 | ||||
| 			} | ||||
| 		}); | ||||
|  | ||||
| 		if (latest) { | ||||
| 			// 現在のログを初期挿入 | ||||
| 			const data = await this.getTemplate(false, latest.data); | ||||
|  | ||||
| 			const log = await this.collection.insert({ | ||||
| 				group: group, | ||||
| 				span: span, | ||||
| 				date: current, | ||||
| 				data: data | ||||
| 			}); | ||||
|  | ||||
| 			return log; | ||||
| 		} else { | ||||
| 			// ログが存在しなかったら | ||||
| 			// * Misskeyインスタンスを建てて初めてのチャート更新時など | ||||
|  | ||||
| 			// 空のログを作成 | ||||
| 			const data = await this.getTemplate(true, null, group); | ||||
|  | ||||
| 			const log = await this.collection.insert({ | ||||
| 				group: group, | ||||
| 				span: span, | ||||
| 				date: current, | ||||
| 				data: data | ||||
| 			}); | ||||
|  | ||||
| 			return log; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	@autobind | ||||
| 	protected commit(query: Obj, group?: any, uniqueKey?: string, uniqueValue?: string): void { | ||||
| 		const update = (log: Log<T>) => { | ||||
| 			// ユニークインクリメントの場合、指定のキーに指定の値が既に存在していたら弾く | ||||
| 			if ( | ||||
| 				uniqueKey && | ||||
| 				log.unique && | ||||
| 				log.unique[uniqueKey] && | ||||
| 				log.unique[uniqueKey].includes(uniqueValue) | ||||
| 			) return; | ||||
|  | ||||
| 			// ユニークインクリメントの指定のキーに値を追加 | ||||
| 			if (uniqueKey) { | ||||
| 				query['$push'] = { | ||||
| 					[`unique.${uniqueKey}`]: uniqueValue | ||||
| 				}; | ||||
| 			} | ||||
|  | ||||
| 			this.collection.update({ | ||||
| 				_id: log._id | ||||
| 			}, query); | ||||
| 		}; | ||||
|  | ||||
| 		this.getCurrentLog('day', group).then(log => update(log)); | ||||
| 		this.getCurrentLog('hour', group).then(log => update(log)); | ||||
| 	} | ||||
|  | ||||
| 	@autobind | ||||
| 	protected inc(inc: Partial<T>, group?: any): void { | ||||
| 		this.commit({ | ||||
| 			$inc: this.convertQuery(inc, 'data') | ||||
| 		}, group); | ||||
| 	} | ||||
|  | ||||
| 	@autobind | ||||
| 	protected incIfUnique(inc: Partial<T>, key: string, value: string, group?: any): void { | ||||
| 		this.commit({ | ||||
| 			$inc: this.convertQuery(inc, 'data') | ||||
| 		}, group, key, value); | ||||
| 	} | ||||
|  | ||||
| 	@autobind | ||||
| 	public async getChart(span: Span, range: number, group?: any): Promise<ArrayValue<T>> { | ||||
| 		const promisedChart: Promise<T>[] = []; | ||||
|  | ||||
| 		const now = new Date(); | ||||
| 		const y = now.getFullYear(); | ||||
| 		const m = now.getMonth(); | ||||
| 		const d = now.getDate(); | ||||
| 		const h = now.getHours(); | ||||
|  | ||||
| 		const gt = | ||||
| 			span == 'day' ? new Date(y, m, d - range) : | ||||
| 			span == 'hour' ? new Date(y, m, d, h - range) : null; | ||||
|  | ||||
| 		const logs = await this.collection.find({ | ||||
| 			group: group, | ||||
| 			span: span, | ||||
| 			date: { | ||||
| 				$gt: gt | ||||
| 			} | ||||
| 		}, { | ||||
| 			sort: { | ||||
| 				date: -1 | ||||
| 			}, | ||||
| 			fields: { | ||||
| 				_id: 0 | ||||
| 			} | ||||
| 		}); | ||||
|  | ||||
| 		for (let i = (range - 1); i >= 0; i--) { | ||||
| 			const current = | ||||
| 				span == 'day' ? new Date(y, m, d - i) : | ||||
| 				span == 'hour' ? new Date(y, m, d, h - i) : | ||||
| 				null; | ||||
|  | ||||
| 			const log = logs.find(l => l.date.getTime() == current.getTime()); | ||||
|  | ||||
| 			if (log) { | ||||
| 				promisedChart.unshift(Promise.resolve(log.data)); | ||||
| 			} else { // 隙間埋め | ||||
| 				const latest = logs.find(l => l.date.getTime() < current.getTime()); | ||||
| 				promisedChart.unshift(this.getTemplate(false, latest ? latest.data : null)); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		const chart = await Promise.all(promisedChart); | ||||
|  | ||||
| 		const res: ArrayValue<T> = {} as any; | ||||
|  | ||||
| 		/** | ||||
| 		 * [{ | ||||
| 		 * 	xxxxx: 1, | ||||
| 		 * 	yyyyy: 5 | ||||
| 		 * }, { | ||||
| 		 * 	xxxxx: 2, | ||||
| 		 * 	yyyyy: 6 | ||||
| 		 * }, { | ||||
| 		 * 	xxxxx: 3, | ||||
| 		 * 	yyyyy: 7 | ||||
| 		 * }] | ||||
| 		 * | ||||
| 		 * を | ||||
| 		 * | ||||
| 		 * { | ||||
| 		 * 	xxxxx: [1, 2, 3], | ||||
| 		 * 	yyyyy: [5, 6, 7] | ||||
| 		 * } | ||||
| 		 * | ||||
| 		 * にする | ||||
| 		 */ | ||||
| 		const dive = (x: Obj, path?: string) => { | ||||
| 			Object.entries(x).forEach(([k, v]) => { | ||||
| 				const p = path ? `${path}.${k}` : k; | ||||
| 				if (typeof v == 'object') { | ||||
| 					dive(v, p); | ||||
| 				} else { | ||||
| 					nestedProperty.set(res, p, chart.map(s => nestedProperty.get(s, p))); | ||||
| 				} | ||||
| 			}); | ||||
| 		}; | ||||
|  | ||||
| 		dive(chart[0]); | ||||
|  | ||||
| 		return res; | ||||
| 	} | ||||
| } | ||||
| //#endregion | ||||
							
								
								
									
										64
									
								
								src/chart/network.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								src/chart/network.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,64 @@ | ||||
| import autobind from 'autobind-decorator'; | ||||
| import Chart, { Partial } from './'; | ||||
|  | ||||
| /** | ||||
|  * ネットワークに関するチャート | ||||
|  */ | ||||
| type NetworkLog = { | ||||
| 	/** | ||||
| 	 * 受信したリクエスト数 | ||||
| 	 */ | ||||
| 	incomingRequests: number; | ||||
|  | ||||
| 	/** | ||||
| 	 * 送信したリクエスト数 | ||||
| 	 */ | ||||
| 	outgoingRequests: number; | ||||
|  | ||||
| 	/** | ||||
| 	 * 応答時間の合計 | ||||
| 	 * TIP: (totalTime / incomingRequests) でひとつのリクエストに平均でどれくらいの時間がかかったか知れる | ||||
| 	 */ | ||||
| 	totalTime: number; | ||||
|  | ||||
| 	/** | ||||
| 	 * 合計受信データ量 | ||||
| 	 */ | ||||
| 	incomingBytes: number; | ||||
|  | ||||
| 	/** | ||||
| 	 * 合計送信データ量 | ||||
| 	 */ | ||||
| 	outgoingBytes: number; | ||||
| }; | ||||
|  | ||||
| class NetworkChart extends Chart<NetworkLog> { | ||||
| 	constructor() { | ||||
| 		super('network'); | ||||
| 	} | ||||
|  | ||||
| 	@autobind | ||||
| 	protected async getTemplate(init: boolean, latest?: NetworkLog): Promise<NetworkLog> { | ||||
| 		return { | ||||
| 			incomingRequests: 0, | ||||
| 			outgoingRequests: 0, | ||||
| 			totalTime: 0, | ||||
| 			incomingBytes: 0, | ||||
| 			outgoingBytes: 0 | ||||
| 		}; | ||||
| 	} | ||||
|  | ||||
| 	@autobind | ||||
| 	public async update(incomingRequests: number, time: number, incomingBytes: number, outgoingBytes: number) { | ||||
| 		const inc: Partial<NetworkLog> = { | ||||
| 			incomingRequests: incomingRequests, | ||||
| 			totalTime: time, | ||||
| 			incomingBytes: incomingBytes, | ||||
| 			outgoingBytes: outgoingBytes | ||||
| 		}; | ||||
|  | ||||
| 		await this.inc(inc); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| export default new NetworkChart(); | ||||
							
								
								
									
										114
									
								
								src/chart/notes.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								src/chart/notes.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,114 @@ | ||||
| import autobind from 'autobind-decorator'; | ||||
| import Chart, { Obj } from '.'; | ||||
| import Note, { INote } from '../models/note'; | ||||
| import { isLocalUser } from '../models/user'; | ||||
|  | ||||
| /** | ||||
|  * 投稿に関するチャート | ||||
|  */ | ||||
| type NotesLog = { | ||||
| 	local: { | ||||
| 		/** | ||||
| 		 * 集計期間時点での、全投稿数 | ||||
| 		 */ | ||||
| 		total: number; | ||||
|  | ||||
| 		/** | ||||
| 		 * 増加した投稿数 | ||||
| 		 */ | ||||
| 		inc: number; | ||||
|  | ||||
| 		/** | ||||
| 		 * 減少した投稿数 | ||||
| 		 */ | ||||
| 		dec: number; | ||||
|  | ||||
| 		diffs: { | ||||
| 			/** | ||||
| 			 * 通常の投稿数の差分 | ||||
| 			 */ | ||||
| 			normal: number; | ||||
|  | ||||
| 			/** | ||||
| 			 * リプライの投稿数の差分 | ||||
| 			 */ | ||||
| 			reply: number; | ||||
|  | ||||
| 			/** | ||||
| 			 * Renoteの投稿数の差分 | ||||
| 			 */ | ||||
| 			renote: number; | ||||
| 		}; | ||||
| 	}; | ||||
|  | ||||
| 	remote: NotesLog['local']; | ||||
| }; | ||||
|  | ||||
| class NotesChart extends Chart<NotesLog> { | ||||
| 	constructor() { | ||||
| 		super('notes'); | ||||
| 	} | ||||
|  | ||||
| 	@autobind | ||||
| 	protected async getTemplate(init: boolean, latest?: NotesLog): Promise<NotesLog> { | ||||
| 		const [localCount, remoteCount] = init ? await Promise.all([ | ||||
| 			Note.count({ '_user.host': null }), | ||||
| 			Note.count({ '_user.host': { $ne: null } }) | ||||
| 		]) : [ | ||||
| 			latest ? latest.local.total : 0, | ||||
| 			latest ? latest.remote.total : 0 | ||||
| 		]; | ||||
|  | ||||
| 		return { | ||||
| 			local: { | ||||
| 				total: localCount, | ||||
| 				inc: 0, | ||||
| 				dec: 0, | ||||
| 				diffs: { | ||||
| 					normal: 0, | ||||
| 					reply: 0, | ||||
| 					renote: 0 | ||||
| 				} | ||||
| 			}, | ||||
| 			remote: { | ||||
| 				total: remoteCount, | ||||
| 				inc: 0, | ||||
| 				dec: 0, | ||||
| 				diffs: { | ||||
| 					normal: 0, | ||||
| 					reply: 0, | ||||
| 					renote: 0 | ||||
| 				} | ||||
| 			} | ||||
| 		}; | ||||
| 	} | ||||
|  | ||||
| 	@autobind | ||||
| 	public async update(note: INote, isAdditional: boolean) { | ||||
| 		const update: Obj = { | ||||
| 			diffs: {} | ||||
| 		}; | ||||
|  | ||||
| 		update.total = isAdditional ? 1 : -1; | ||||
|  | ||||
| 		if (isAdditional) { | ||||
| 			update.inc = 1; | ||||
| 		} else { | ||||
| 			update.dec = 1; | ||||
| 		} | ||||
|  | ||||
| 		if (note.replyId != null) { | ||||
| 			update.diffs.reply = isAdditional ? 1 : -1; | ||||
| 		} else if (note.renoteId != null) { | ||||
| 			update.diffs.renote = isAdditional ? 1 : -1; | ||||
| 		} else { | ||||
| 			update.diffs.normal = isAdditional ? 1 : -1; | ||||
| 		} | ||||
|  | ||||
| 		await this.inc({ | ||||
| 			[isLocalUser(note._user) ? 'local' : 'remote']: update | ||||
| 		}); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| export default new NotesChart(); | ||||
							
								
								
									
										101
									
								
								src/chart/per-user-drive.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								src/chart/per-user-drive.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,101 @@ | ||||
| import autobind from 'autobind-decorator'; | ||||
| import Chart, { Obj } from './'; | ||||
| import DriveFile, { IDriveFile } from '../models/drive-file'; | ||||
|  | ||||
| /** | ||||
|  * ユーザーごとのドライブに関するチャート | ||||
|  */ | ||||
| type PerUserDriveLog = { | ||||
| 	/** | ||||
| 	 * 集計期間時点での、全ドライブファイル数 | ||||
| 	 */ | ||||
| 	totalCount: number; | ||||
|  | ||||
| 	/** | ||||
| 	 * 集計期間時点での、全ドライブファイルの合計サイズ | ||||
| 	 */ | ||||
| 	totalSize: number; | ||||
|  | ||||
| 	/** | ||||
| 	 * 増加したドライブファイル数 | ||||
| 	 */ | ||||
| 	incCount: number; | ||||
|  | ||||
| 	/** | ||||
| 	 * 増加したドライブ使用量 | ||||
| 	 */ | ||||
| 	incSize: number; | ||||
|  | ||||
| 	/** | ||||
| 	 * 減少したドライブファイル数 | ||||
| 	 */ | ||||
| 	decCount: number; | ||||
|  | ||||
| 	/** | ||||
| 	 * 減少したドライブ使用量 | ||||
| 	 */ | ||||
| 	decSize: number; | ||||
| }; | ||||
|  | ||||
| class PerUserDriveChart extends Chart<PerUserDriveLog> { | ||||
| 	constructor() { | ||||
| 		super('perUserDrive', true); | ||||
| 	} | ||||
|  | ||||
| 	@autobind | ||||
| 	protected async getTemplate(init: boolean, latest?: PerUserDriveLog, group?: any): Promise<PerUserDriveLog> { | ||||
| 		const calcSize = () => DriveFile | ||||
| 			.aggregate([{ | ||||
| 				$match: { | ||||
| 					'metadata.userId': group, | ||||
| 					'metadata.deletedAt': { $exists: false } | ||||
| 				} | ||||
| 			}, { | ||||
| 				$project: { | ||||
| 					length: true | ||||
| 				} | ||||
| 			}, { | ||||
| 				$group: { | ||||
| 					_id: null, | ||||
| 					usage: { $sum: '$length' } | ||||
| 				} | ||||
| 			}]) | ||||
| 			.then(res => res.length > 0 ? res[0].usage : 0); | ||||
|  | ||||
| 		const [count, size] = init ? await Promise.all([ | ||||
| 			DriveFile.count({ 'metadata.userId': group }), | ||||
| 			calcSize() | ||||
| 		]) : [ | ||||
| 			latest ? latest.totalCount : 0, | ||||
| 			latest ? latest.totalSize : 0 | ||||
| 		]; | ||||
|  | ||||
| 		return { | ||||
| 			totalCount: count, | ||||
| 			totalSize: size, | ||||
| 			incCount: 0, | ||||
| 			incSize: 0, | ||||
| 			decCount: 0, | ||||
| 			decSize: 0 | ||||
| 		}; | ||||
| 	} | ||||
|  | ||||
| 	@autobind | ||||
| 	public async update(file: IDriveFile, isAdditional: boolean) { | ||||
| 		const update: Obj = {}; | ||||
|  | ||||
| 		update.totalCount = isAdditional ? 1 : -1; | ||||
| 		update.totalSize = isAdditional ? file.length : -file.length; | ||||
| 		if (isAdditional) { | ||||
| 			update.incCount = 1; | ||||
| 			update.incSize = file.length; | ||||
| 		} else { | ||||
| 			update.decCount = 1; | ||||
| 			update.decSize = file.length; | ||||
| 		} | ||||
|  | ||||
| 		await this.inc(update, file.metadata.userId); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| export default new PerUserDriveChart(); | ||||
							
								
								
									
										128
									
								
								src/chart/per-user-following.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								src/chart/per-user-following.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,128 @@ | ||||
| import autobind from 'autobind-decorator'; | ||||
| import Chart, { Obj } from './'; | ||||
| import Following from '../models/following'; | ||||
| import { IUser, isLocalUser } from '../models/user'; | ||||
|  | ||||
| /** | ||||
|  * ユーザーごとのフォローに関するチャート | ||||
|  */ | ||||
| type PerUserFollowingLog = { | ||||
| 	local: { | ||||
| 		/** | ||||
| 		 * フォローしている | ||||
| 		 */ | ||||
| 		followings: { | ||||
| 			/** | ||||
| 			 * 合計 | ||||
| 			 */ | ||||
| 			total: number; | ||||
|  | ||||
| 			/** | ||||
| 			 * フォローした数 | ||||
| 			 */ | ||||
| 			inc: number; | ||||
|  | ||||
| 			/** | ||||
| 			 * フォロー解除した数 | ||||
| 			 */ | ||||
| 			dec: number; | ||||
| 		}; | ||||
|  | ||||
| 		/** | ||||
| 		 * フォローされている | ||||
| 		 */ | ||||
| 		followers: { | ||||
| 			/** | ||||
| 			 * 合計 | ||||
| 			 */ | ||||
| 			total: number; | ||||
|  | ||||
| 			/** | ||||
| 			 * フォローされた数 | ||||
| 			 */ | ||||
| 			inc: number; | ||||
|  | ||||
| 			/** | ||||
| 			 * フォロー解除された数 | ||||
| 			 */ | ||||
| 			dec: number; | ||||
| 		}; | ||||
| 	}; | ||||
|  | ||||
| 	remote: PerUserFollowingLog['local']; | ||||
| }; | ||||
|  | ||||
| class PerUserFollowingChart extends Chart<PerUserFollowingLog> { | ||||
| 	constructor() { | ||||
| 		super('perUserFollowing', true); | ||||
| 	} | ||||
|  | ||||
| 	@autobind | ||||
| 	protected async getTemplate(init: boolean, latest?: PerUserFollowingLog, group?: any): Promise<PerUserFollowingLog> { | ||||
| 		const [ | ||||
| 			localFollowingsCount, | ||||
| 			localFollowersCount, | ||||
| 			remoteFollowingsCount, | ||||
| 			remoteFollowersCount | ||||
| 		] = init ? await Promise.all([ | ||||
| 			Following.count({ followerId: group, '_followee.host': null }), | ||||
| 			Following.count({ followeeId: group, '_follower.host': null }), | ||||
| 			Following.count({ followerId: group, '_followee.host': { $ne: null } }), | ||||
| 			Following.count({ followeeId: group, '_follower.host': { $ne: null } }) | ||||
| 		]) : [ | ||||
| 			latest ? latest.local.followings.total : 0, | ||||
| 			latest ? latest.local.followers.total : 0, | ||||
| 			latest ? latest.remote.followings.total : 0, | ||||
| 			latest ? latest.remote.followers.total : 0 | ||||
| 		]; | ||||
|  | ||||
| 		return { | ||||
| 			local: { | ||||
| 				followings: { | ||||
| 					total: localFollowingsCount, | ||||
| 					inc: 0, | ||||
| 					dec: 0 | ||||
| 				}, | ||||
| 				followers: { | ||||
| 					total: localFollowersCount, | ||||
| 					inc: 0, | ||||
| 					dec: 0 | ||||
| 				} | ||||
| 			}, | ||||
| 			remote: { | ||||
| 				followings: { | ||||
| 					total: remoteFollowingsCount, | ||||
| 					inc: 0, | ||||
| 					dec: 0 | ||||
| 				}, | ||||
| 				followers: { | ||||
| 					total: remoteFollowersCount, | ||||
| 					inc: 0, | ||||
| 					dec: 0 | ||||
| 				} | ||||
| 			} | ||||
| 		}; | ||||
| 	} | ||||
|  | ||||
| 	@autobind | ||||
| 	public async update(follower: IUser, followee: IUser, isFollow: boolean) { | ||||
| 		const update: Obj = {}; | ||||
|  | ||||
| 		update.total = isFollow ? 1 : -1; | ||||
|  | ||||
| 		if (isFollow) { | ||||
| 			update.inc = 1; | ||||
| 		} else { | ||||
| 			update.dec = 1; | ||||
| 		} | ||||
|  | ||||
| 		this.inc({ | ||||
| 			[isLocalUser(follower) ? 'local' : 'remote']: { followings: update } | ||||
| 		}, follower._id); | ||||
| 		this.inc({ | ||||
| 			[isLocalUser(followee) ? 'local' : 'remote']: { followers: update } | ||||
| 		}, followee._id); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| export default new PerUserFollowingChart(); | ||||
							
								
								
									
										94
									
								
								src/chart/per-user-notes.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								src/chart/per-user-notes.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,94 @@ | ||||
| import autobind from 'autobind-decorator'; | ||||
| import Chart, { Obj } from './'; | ||||
| import Note, { INote } from '../models/note'; | ||||
| import { IUser } from '../models/user'; | ||||
|  | ||||
| /** | ||||
|  * ユーザーごとの投稿に関するチャート | ||||
|  */ | ||||
| type PerUserNotesLog = { | ||||
| 	/** | ||||
| 	 * 集計期間時点での、全投稿数 | ||||
| 	 */ | ||||
| 	total: number; | ||||
|  | ||||
| 	/** | ||||
| 	 * 増加した投稿数 | ||||
| 	 */ | ||||
| 	inc: number; | ||||
|  | ||||
| 	/** | ||||
| 	 * 減少した投稿数 | ||||
| 	 */ | ||||
| 	dec: number; | ||||
|  | ||||
| 	diffs: { | ||||
| 		/** | ||||
| 		 * 通常の投稿数の差分 | ||||
| 		 */ | ||||
| 		normal: number; | ||||
|  | ||||
| 		/** | ||||
| 		 * リプライの投稿数の差分 | ||||
| 		 */ | ||||
| 		reply: number; | ||||
|  | ||||
| 		/** | ||||
| 		 * Renoteの投稿数の差分 | ||||
| 		 */ | ||||
| 		renote: number; | ||||
| 	}; | ||||
| }; | ||||
|  | ||||
| class PerUserNotesChart extends Chart<PerUserNotesLog> { | ||||
| 	constructor() { | ||||
| 		super('perUserNotes', true); | ||||
| 	} | ||||
|  | ||||
| 	@autobind | ||||
| 	protected async getTemplate(init: boolean, latest?: PerUserNotesLog, group?: any): Promise<PerUserNotesLog> { | ||||
| 		const [count] = init ? await Promise.all([ | ||||
| 			Note.count({ userId: group, deletedAt: null }), | ||||
| 		]) : [ | ||||
| 			latest ? latest.total : 0 | ||||
| 		]; | ||||
|  | ||||
| 		return { | ||||
| 			total: count, | ||||
| 			inc: 0, | ||||
| 			dec: 0, | ||||
| 			diffs: { | ||||
| 				normal: 0, | ||||
| 				reply: 0, | ||||
| 				renote: 0 | ||||
| 			} | ||||
| 		}; | ||||
| 	} | ||||
|  | ||||
| 	@autobind | ||||
| 	public async update(user: IUser, note: INote, isAdditional: boolean) { | ||||
| 		const update: Obj = { | ||||
| 			diffs: {} | ||||
| 		}; | ||||
|  | ||||
| 		update.total = isAdditional ? 1 : -1; | ||||
|  | ||||
| 		if (isAdditional) { | ||||
| 			update.inc = 1; | ||||
| 		} else { | ||||
| 			update.dec = 1; | ||||
| 		} | ||||
|  | ||||
| 		if (note.replyId != null) { | ||||
| 			update.diffs.reply = isAdditional ? 1 : -1; | ||||
| 		} else if (note.renoteId != null) { | ||||
| 			update.diffs.renote = isAdditional ? 1 : -1; | ||||
| 		} else { | ||||
| 			update.diffs.normal = isAdditional ? 1 : -1; | ||||
| 		} | ||||
|  | ||||
| 		await this.inc(update, user._id); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| export default new PerUserNotesChart(); | ||||
							
								
								
									
										45
									
								
								src/chart/per-user-reactions.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								src/chart/per-user-reactions.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | ||||
| import autobind from 'autobind-decorator'; | ||||
| import Chart from './'; | ||||
| import { IUser, isLocalUser } from '../models/user'; | ||||
| import { INote } from '../models/note'; | ||||
|  | ||||
| /** | ||||
|  * ユーザーごとのリアクションに関するチャート | ||||
|  */ | ||||
| type PerUserReactionsLog = { | ||||
| 	local: { | ||||
| 		/** | ||||
| 		 * リアクションされた数 | ||||
| 		 */ | ||||
| 		count: number; | ||||
| 	}; | ||||
|  | ||||
| 	remote: PerUserReactionsLog['local']; | ||||
| }; | ||||
|  | ||||
| class PerUserReactionsChart extends Chart<PerUserReactionsLog> { | ||||
| 	constructor() { | ||||
| 		super('perUserReaction', true); | ||||
| 	} | ||||
|  | ||||
| 	@autobind | ||||
| 	protected async getTemplate(init: boolean, latest?: PerUserReactionsLog, group?: any): Promise<PerUserReactionsLog> { | ||||
| 		return { | ||||
| 			local: { | ||||
| 				count: 0 | ||||
| 			}, | ||||
| 			remote: { | ||||
| 				count: 0 | ||||
| 			} | ||||
| 		}; | ||||
| 	} | ||||
|  | ||||
| 	@autobind | ||||
| 	public async update(user: IUser, note: INote) { | ||||
| 		this.inc({ | ||||
| 			[isLocalUser(user) ? 'local' : 'remote']: { count: 1 } | ||||
| 		}, note.userId); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| export default new PerUserReactionsChart(); | ||||
							
								
								
									
										75
									
								
								src/chart/users.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								src/chart/users.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,75 @@ | ||||
| import autobind from 'autobind-decorator'; | ||||
| import Chart, { Obj } from './'; | ||||
| import User, { IUser, isLocalUser } from '../models/user'; | ||||
|  | ||||
| /** | ||||
|  * ユーザーに関するチャート | ||||
|  */ | ||||
| type UsersLog = { | ||||
| 	local: { | ||||
| 		/** | ||||
| 		 * 集計期間時点での、全ユーザー数 | ||||
| 		 */ | ||||
| 		total: number; | ||||
|  | ||||
| 		/** | ||||
| 		 * 増加したユーザー数 | ||||
| 		 */ | ||||
| 		inc: number; | ||||
|  | ||||
| 		/** | ||||
| 		 * 減少したユーザー数 | ||||
| 		 */ | ||||
| 		dec: number; | ||||
| 	}; | ||||
|  | ||||
| 	remote: UsersLog['local']; | ||||
| }; | ||||
|  | ||||
| class UsersChart extends Chart<UsersLog> { | ||||
| 	constructor() { | ||||
| 		super('users'); | ||||
| 	} | ||||
|  | ||||
| 	@autobind | ||||
| 	protected async getTemplate(init: boolean, latest?: UsersLog): Promise<UsersLog> { | ||||
| 		const [localCount, remoteCount] = init ? await Promise.all([ | ||||
| 			User.count({ host: null }), | ||||
| 			User.count({ host: { $ne: null } }) | ||||
| 		]) : [ | ||||
| 			latest ? latest.local.total : 0, | ||||
| 			latest ? latest.remote.total : 0 | ||||
| 		]; | ||||
|  | ||||
| 		return { | ||||
| 			local: { | ||||
| 				total: localCount, | ||||
| 				inc: 0, | ||||
| 				dec: 0 | ||||
| 			}, | ||||
| 			remote: { | ||||
| 				total: remoteCount, | ||||
| 				inc: 0, | ||||
| 				dec: 0 | ||||
| 			} | ||||
| 		}; | ||||
| 	} | ||||
|  | ||||
| 	@autobind | ||||
| 	public async update(user: IUser, isAdditional: boolean) { | ||||
| 		const update: Obj = {}; | ||||
|  | ||||
| 		update.total = isAdditional ? 1 : -1; | ||||
| 		if (isAdditional) { | ||||
| 			update.inc = 1; | ||||
| 		} else { | ||||
| 			update.dec = 1; | ||||
| 		} | ||||
|  | ||||
| 		await this.inc({ | ||||
| 			[isLocalUser(user) ? 'local' : 'remote']: update | ||||
| 		}); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| export default new UsersChart(); | ||||
| @@ -46,6 +46,16 @@ const getKeyMap = keymap => Object.entries(keymap).map(([patterns, callback]): a | ||||
|  | ||||
| const ignoreElemens = ['input', 'textarea']; | ||||
|  | ||||
| function match(e: KeyboardEvent, patterns: action['patterns']): boolean { | ||||
| 	const key = e.code.toLowerCase(); | ||||
| 	return patterns.some(pattern => pattern.which.includes(key) && | ||||
| 		pattern.ctrl == e.ctrlKey && | ||||
| 		pattern.shift == e.shiftKey && | ||||
| 		pattern.alt == e.altKey && | ||||
| 		e.metaKey == false | ||||
| 	); | ||||
| } | ||||
|  | ||||
| export default { | ||||
| 	install(Vue) { | ||||
| 		Vue.directive('hotkey', { | ||||
| @@ -55,37 +65,27 @@ export default { | ||||
| 				const actions = getKeyMap(binding.value); | ||||
|  | ||||
| 				// flatten | ||||
| 				const reservedKeys = concat(concat(actions.map(a => a.patterns.map(p => p.which)))); | ||||
| 				const reservedKeys = concat(actions.map(a => a.patterns)); | ||||
|  | ||||
| 				el.dataset.reservedKeys = reservedKeys.map(key => `'${key}'`).join(' '); | ||||
| 				el._misskey_reservedKeys = reservedKeys; | ||||
|  | ||||
| 				el._keyHandler = (e: KeyboardEvent) => { | ||||
| 					const key = e.code.toLowerCase(); | ||||
|  | ||||
| 					const targetReservedKeys = document.activeElement ? ((document.activeElement as any).dataset || {}).reservedKeys || '' : ''; | ||||
| 					const targetReservedKeys = document.activeElement ? ((document.activeElement as any)._misskey_reservedKeys || []) : []; | ||||
| 					if (document.activeElement && ignoreElemens.some(el => document.activeElement.matches(el))) return; | ||||
|  | ||||
| 					for (const action of actions) { | ||||
| 						if (el._hotkey_global && targetReservedKeys.includes(`'${key}'`)) break; | ||||
|  | ||||
| 						const matched = action.patterns.some(pattern => { | ||||
| 							const matched = pattern.which.includes(key) && | ||||
| 								pattern.ctrl == e.ctrlKey && | ||||
| 								pattern.shift == e.shiftKey && | ||||
| 								pattern.alt == e.altKey && | ||||
| 								e.metaKey == false; | ||||
|  | ||||
| 							if (matched) { | ||||
| 								e.preventDefault(); | ||||
| 								e.stopPropagation(); | ||||
| 								action.callback(e); | ||||
| 								return true; | ||||
| 							} else { | ||||
| 								return false; | ||||
| 							} | ||||
| 						}); | ||||
| 						const matched = match(e, action.patterns); | ||||
|  | ||||
| 						if (matched) { | ||||
| 							if (el._hotkey_global) { | ||||
| 								if (match(e, targetReservedKeys)) { | ||||
| 									return; | ||||
| 								} | ||||
| 							} | ||||
|  | ||||
| 							e.preventDefault(); | ||||
| 							e.stopPropagation(); | ||||
| 							action.callback(e); | ||||
| 							break; | ||||
| 						} | ||||
| 					} | ||||
|   | ||||
| @@ -29,12 +29,12 @@ export default (opts: Opts = {}) => ({ | ||||
| 	computed: { | ||||
| 		keymap(): any { | ||||
| 			return { | ||||
| 				'r|left': () => this.reply(true), | ||||
| 				'r': () => this.reply(true), | ||||
| 				'e|a|plus': () => this.react(true), | ||||
| 				'q|right': () => this.renote(true), | ||||
| 				'q': () => this.renote(true), | ||||
| 				'f|b': this.favorite, | ||||
| 				'delete|ctrl+d': this.del, | ||||
| 				'ctrl+q|ctrl+right': this.renoteDirectly, | ||||
| 				'ctrl+q': this.renoteDirectly, | ||||
| 				'up|k|shift+tab': this.focusBefore, | ||||
| 				'down|j|tab': this.focusAfter, | ||||
| 				'esc': this.blur, | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| import Vue from 'vue'; | ||||
|  | ||||
| import profileEditor from './profile-editor.vue'; | ||||
| import noteSkeleton from './note-skeleton.vue'; | ||||
| import theme from './theme.vue'; | ||||
| import instance from './instance.vue'; | ||||
| @@ -45,6 +46,7 @@ import uiSelect from './ui/select.vue'; | ||||
| import formButton from './ui/form/button.vue'; | ||||
| import formRadio from './ui/form/radio.vue'; | ||||
|  | ||||
| Vue.component('mk-profile-editor', profileEditor); | ||||
| Vue.component('mk-note-skeleton', noteSkeleton); | ||||
| Vue.component('mk-theme', theme); | ||||
| Vue.component('mk-instance', instance); | ||||
|   | ||||
| @@ -114,10 +114,9 @@ export default Vue.component('misskey-flavored-markdown', { | ||||
| 				} | ||||
|  | ||||
| 				case 'mention': { | ||||
| 					return (createElement as any)('a', { | ||||
| 					return (createElement as any)('router-link', { | ||||
| 						attrs: { | ||||
| 							href: `${url}/${token.canonical}`, | ||||
| 							target: '_blank', | ||||
| 							to: `/${token.canonical}`, | ||||
| 							dataIsMe: (this as any).i && getAcct((this as any).i) == getAcct(token), | ||||
| 							style: 'color:var(--mfmMention);' | ||||
| 						}, | ||||
| @@ -129,10 +128,9 @@ export default Vue.component('misskey-flavored-markdown', { | ||||
| 				} | ||||
|  | ||||
| 				case 'hashtag': { | ||||
| 					return [createElement('a', { | ||||
| 					return [createElement('router-link', { | ||||
| 						attrs: { | ||||
| 							href: `${url}/tags/${encodeURIComponent(token.hashtag)}`, | ||||
| 							target: '_blank', | ||||
| 							to: `/tags/${encodeURIComponent(token.hashtag)}`, | ||||
| 							style: 'color:var(--mfmHashtag);' | ||||
| 						} | ||||
| 					}, token.content)]; | ||||
|   | ||||
| @@ -49,6 +49,7 @@ | ||||
| 
 | ||||
| 		<div> | ||||
| 			<ui-switch v-model="isCat" @change="save(false)">%i18n:@is-cat%</ui-switch> | ||||
| 			<ui-switch v-model="isBot" @change="save(false)">%i18n:@is-bot%</ui-switch> | ||||
| 			<ui-switch v-model="alwaysMarkNsfw">%i18n:common.always-mark-nsfw%</ui-switch> | ||||
| 		</div> | ||||
| 	</section> | ||||
| @@ -66,7 +67,7 @@ | ||||
| 
 | ||||
| <script lang="ts"> | ||||
| import Vue from 'vue'; | ||||
| import { apiUrl, host } from '../../../../config'; | ||||
| import { apiUrl, host } from '../../../config'; | ||||
| 
 | ||||
| export default Vue.extend({ | ||||
| 	data() { | ||||
| @@ -80,6 +81,7 @@ export default Vue.extend({ | ||||
| 			avatarId: null, | ||||
| 			bannerId: null, | ||||
| 			isCat: false, | ||||
| 			isBot: false, | ||||
| 			isLocked: false, | ||||
| 			carefulBot: false, | ||||
| 			saving: false, | ||||
| @@ -104,6 +106,7 @@ export default Vue.extend({ | ||||
| 		this.avatarId = this.$store.state.i.avatarId; | ||||
| 		this.bannerId = this.$store.state.i.bannerId; | ||||
| 		this.isCat = this.$store.state.i.isCat; | ||||
| 		this.isBot = this.$store.state.i.isBot; | ||||
| 		this.isLocked = this.$store.state.i.isLocked; | ||||
| 		this.carefulBot = this.$store.state.i.carefulBot; | ||||
| 	}, | ||||
| @@ -164,6 +167,7 @@ export default Vue.extend({ | ||||
| 				avatarId: this.avatarId, | ||||
| 				bannerId: this.bannerId, | ||||
| 				isCat: this.isCat, | ||||
| 				isBot: this.isBot, | ||||
| 				isLocked: this.isLocked, | ||||
| 				carefulBot: this.carefulBot | ||||
| 			}).then(i => { | ||||
| @@ -1,5 +1,5 @@ | ||||
| <template> | ||||
| <div class="ui-card"> | ||||
| <div class="ui-card" :class="{ shadow: $store.state.settings.useShadow }"> | ||||
| 	<header> | ||||
| 		<slot name="title"></slot> | ||||
| 	</header> | ||||
| @@ -24,7 +24,10 @@ export default Vue.extend({ | ||||
| 	margin 16px | ||||
| 	color var(--faceText) | ||||
| 	background var(--face) | ||||
| 	box-shadow 0 3px 1px -2px rgba(#000, 0.2), 0 2px 2px 0 rgba(#000, 0.14), 0 1px 5px 0 rgba(#000, 0.12) | ||||
| 	border-radius var(--round) | ||||
|  | ||||
| 	&.shadow | ||||
| 		box-shadow 0 3px 1px -2px rgba(#000, 0.2), 0 2px 2px 0 rgba(#000, 0.14), 0 1px 5px 0 rgba(#000, 0.12) | ||||
|  | ||||
| 	> header | ||||
| 		padding 16px | ||||
|   | ||||
| @@ -122,17 +122,19 @@ export default Vue.extend({ | ||||
| 		} | ||||
| 	}, | ||||
| 	mounted() { | ||||
| 		if (this.$refs.prefix) { | ||||
| 			this.$refs.label.style.left = (this.$refs.prefix.offsetLeft + this.$refs.prefix.offsetWidth) + 'px'; | ||||
| 			if (this.$refs.prefix.offsetWidth) { | ||||
| 				this.$refs.input.style.paddingLeft = this.$refs.prefix.offsetWidth + 'px'; | ||||
| 		this.$nextTick(() => { | ||||
| 			if (this.$refs.prefix) { | ||||
| 				this.$refs.label.style.left = (this.$refs.prefix.offsetLeft + this.$refs.prefix.offsetWidth) + 'px'; | ||||
| 				if (this.$refs.prefix.offsetWidth) { | ||||
| 					this.$refs.input.style.paddingLeft = this.$refs.prefix.offsetWidth + 'px'; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		if (this.$refs.suffix) { | ||||
| 			if (this.$refs.suffix.offsetWidth) { | ||||
| 				this.$refs.input.style.paddingRight = this.$refs.suffix.offsetWidth + 'px'; | ||||
| 			if (this.$refs.suffix) { | ||||
| 				if (this.$refs.suffix.offsetWidth) { | ||||
| 					this.$refs.input.style.paddingRight = this.$refs.suffix.offsetWidth + 'px'; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		}); | ||||
| 	}, | ||||
| 	methods: { | ||||
| 		focus() { | ||||
|   | ||||
| @@ -5,7 +5,7 @@ | ||||
|  | ||||
| 		<p :class="$style.fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p> | ||||
| 		<div :class="$style.stream" v-if="!fetching && images.length > 0"> | ||||
| 			<div v-for="image in images" :class="$style.img" :style="`background-image: url(${image.url})`"></div> | ||||
| 			<div v-for="image in images" :class="$style.img" :style="`background-image: url(${image.thumbnailUrl || image.url})`"></div> | ||||
| 		</div> | ||||
| 		<p :class="$style.empty" v-if="!fetching && images.length == 0">%i18n:@no-photos%</p> | ||||
| 	</mk-widget-container> | ||||
| @@ -73,9 +73,6 @@ export default define({ | ||||
| 		border-radius 8px | ||||
|  | ||||
| .stream | ||||
| 	display -webkit-flex | ||||
| 	display -moz-flex | ||||
| 	display -ms-flex | ||||
| 	display flex | ||||
| 	justify-content center | ||||
| 	flex-wrap wrap | ||||
|   | ||||
| @@ -44,7 +44,6 @@ export default define({ | ||||
| 		}, | ||||
| 		fetch() { | ||||
| 			fetch(`https://api.rss2json.com/v1/api.json?rss_url=${this.props.url}`, { | ||||
| 				cache: 'no-cache' | ||||
| 			}).then(res => { | ||||
| 				res.json().then(feed => { | ||||
| 					this.items = feed.items; | ||||
|   | ||||
| @@ -21,6 +21,7 @@ import updateAvatar from './api/update-avatar'; | ||||
| import updateBanner from './api/update-banner'; | ||||
|  | ||||
| import MkIndex from './views/pages/index.vue'; | ||||
| import MkHome from './views/pages/home.vue'; | ||||
| import MkDeck from './views/pages/deck/deck.vue'; | ||||
| import MkAdmin from './views/pages/admin/admin.vue'; | ||||
| import MkStats from './views/pages/stats/stats.vue'; | ||||
| @@ -54,6 +55,7 @@ init(async (launch) => { | ||||
| 		mode: 'history', | ||||
| 		routes: [ | ||||
| 			{ path: '/', name: 'index', component: MkIndex }, | ||||
| 			{ path: '/home', name: 'home', component: MkHome }, | ||||
| 			{ path: '/deck', name: 'deck', component: MkDeck }, | ||||
| 			{ path: '/admin', name: 'admin', component: MkAdmin }, | ||||
| 			{ path: '/stats', name: 'stats', component: MkStats }, | ||||
| @@ -64,11 +66,11 @@ init(async (launch) => { | ||||
| 			{ path: '/i/drive/folder/:folder', component: MkDrive }, | ||||
| 			{ path: '/selectdrive', component: MkSelectDrive }, | ||||
| 			{ path: '/search', component: MkSearch }, | ||||
| 			{ path: '/tags/:tag', component: MkTag }, | ||||
| 			{ path: '/tags/:tag', name: 'tag', component: MkTag }, | ||||
| 			{ path: '/share', component: MkShare }, | ||||
| 			{ path: '/reversi/:game?', component: MkReversi }, | ||||
| 			{ path: '/@:user', component: MkUser }, | ||||
| 			{ path: '/notes/:note', component: MkNote }, | ||||
| 			{ path: '/@:user', name: 'user', component: MkUser }, | ||||
| 			{ path: '/notes/:note', name: 'note', component: MkNote }, | ||||
| 			{ path: '/authorize-follow', component: MkFollow } | ||||
| 		] | ||||
| 	}); | ||||
|   | ||||
| @@ -33,7 +33,7 @@ export default Vue.extend({ | ||||
| 				}, | ||||
| 				tooltips: { | ||||
| 					intersect: false, | ||||
| 					mode: 'x', | ||||
| 					mode: 'index', | ||||
| 					position: 'nearest' | ||||
| 				} | ||||
| 			}, this.opts || {})); | ||||
|   | ||||
| @@ -3,6 +3,10 @@ | ||||
| 	<header> | ||||
| 		<b>%i18n:@title%:</b> | ||||
| 		<select v-model="chartType"> | ||||
| 			<optgroup label="%i18n:@federation%"> | ||||
| 				<option value="federation-instances">%i18n:@charts.federation-instances%</option> | ||||
| 				<option value="federation-instances-total">%i18n:@charts.federation-instances-total%</option> | ||||
| 			</optgroup> | ||||
| 			<optgroup label="%i18n:@users%"> | ||||
| 				<option value="users">%i18n:@charts.users%</option> | ||||
| 				<option value="users-total">%i18n:@charts.users-total%</option> | ||||
| @@ -56,6 +60,11 @@ const rgba = (color: string): string => { | ||||
| 	return color.replace('rgb', 'rgba').replace(')', ', 0.1)'); | ||||
| }; | ||||
|  | ||||
| const limit = 35; | ||||
|  | ||||
| const sum = (...arr) => arr.reduce((r, a) => r.map((b, i) => a[i] + b)); | ||||
| const negate = arr => arr.map(x => -x); | ||||
|  | ||||
| export default Vue.extend({ | ||||
| 	components: { | ||||
| 		XChart | ||||
| @@ -63,6 +72,7 @@ export default Vue.extend({ | ||||
|  | ||||
| 	data() { | ||||
| 		return { | ||||
| 			now: null, | ||||
| 			chart: null, | ||||
| 			chartType: 'notes', | ||||
| 			span: 'hour' | ||||
| @@ -73,6 +83,8 @@ export default Vue.extend({ | ||||
| 		data(): any { | ||||
| 			if (this.chart == null) return null; | ||||
| 			switch (this.chartType) { | ||||
| 				case 'federation-instances': return this.federationInstancesChart(false); | ||||
| 				case 'federation-instances-total': return this.federationInstancesChart(true); | ||||
| 				case 'users': return this.usersChart(false); | ||||
| 				case 'users-total': return this.usersChart(true); | ||||
| 				case 'notes': return this.notesChart('combined'); | ||||
| @@ -90,32 +102,88 @@ export default Vue.extend({ | ||||
| 		}, | ||||
|  | ||||
| 		stats(): any[] { | ||||
| 			return ( | ||||
| 			const stats = | ||||
| 				this.span == 'day' ? this.chart.perDay : | ||||
| 				this.span == 'hour' ? this.chart.perHour : | ||||
| 				null | ||||
| 			); | ||||
| 				null; | ||||
|  | ||||
| 			return stats; | ||||
| 		} | ||||
| 	}, | ||||
|  | ||||
| 	created() { | ||||
| 		(this as any).api('chart', { | ||||
| 			limit: 35 | ||||
| 		}).then(chart => { | ||||
| 			this.chart = chart; | ||||
| 		}); | ||||
| 	async created() { | ||||
| 		this.now = new Date(); | ||||
|  | ||||
| 		const [perHour, perDay] = await Promise.all([Promise.all([ | ||||
| 			(this as any).api('charts/federation', { limit: limit, span: 'hour' }), | ||||
| 			(this as any).api('charts/users', { limit: limit, span: 'hour' }), | ||||
| 			(this as any).api('charts/notes', { limit: limit, span: 'hour' }), | ||||
| 			(this as any).api('charts/drive', { limit: limit, span: 'hour' }), | ||||
| 			(this as any).api('charts/network', { limit: limit, span: 'hour' }) | ||||
| 		]), Promise.all([ | ||||
| 			(this as any).api('charts/federation', { limit: limit, span: 'day' }), | ||||
| 			(this as any).api('charts/users', { limit: limit, span: 'day' }), | ||||
| 			(this as any).api('charts/notes', { limit: limit, span: 'day' }), | ||||
| 			(this as any).api('charts/drive', { limit: limit, span: 'day' }), | ||||
| 			(this as any).api('charts/network', { limit: limit, span: 'day' }) | ||||
| 		])]); | ||||
|  | ||||
| 		const chart = { | ||||
| 			perHour: { | ||||
| 				federation: perHour[0], | ||||
| 				users: perHour[1], | ||||
| 				notes: perHour[2], | ||||
| 				drive: perHour[3], | ||||
| 				network: perHour[4] | ||||
| 			}, | ||||
| 			perDay: { | ||||
| 				federation: perDay[0], | ||||
| 				users: perDay[1], | ||||
| 				notes: perDay[2], | ||||
| 				drive: perDay[3], | ||||
| 				network: perDay[4] | ||||
| 			} | ||||
| 		}; | ||||
|  | ||||
| 		this.chart = chart; | ||||
| 	}, | ||||
|  | ||||
| 	methods: { | ||||
| 		notesChart(type: string): any { | ||||
| 			const data = this.stats.slice().reverse().map(x => ({ | ||||
| 				date: new Date(x.date), | ||||
| 				normal: type == 'local' ? x.notes.local.diffs.normal : type == 'remote' ? x.notes.remote.diffs.normal : x.notes.local.diffs.normal + x.notes.remote.diffs.normal, | ||||
| 				reply: type == 'local' ? x.notes.local.diffs.reply : type == 'remote' ? x.notes.remote.diffs.reply : x.notes.local.diffs.reply + x.notes.remote.diffs.reply, | ||||
| 				renote: type == 'local' ? x.notes.local.diffs.renote : type == 'remote' ? x.notes.remote.diffs.renote : x.notes.local.diffs.renote + x.notes.remote.diffs.renote, | ||||
| 				all: type == 'local' ? (x.notes.local.inc + -x.notes.local.dec) : type == 'remote' ? (x.notes.remote.inc + -x.notes.remote.dec) : (x.notes.local.inc + -x.notes.local.dec) + (x.notes.remote.inc + -x.notes.remote.dec) | ||||
| 			})); | ||||
| 		getDate(i: number) { | ||||
| 			const y = this.now.getFullYear(); | ||||
| 			const m = this.now.getMonth(); | ||||
| 			const d = this.now.getDate(); | ||||
| 			const h = this.now.getHours(); | ||||
|  | ||||
| 			return ( | ||||
| 				this.span == 'day' ? new Date(y, m, d - i) : | ||||
| 				this.span == 'hour' ? new Date(y, m, d, h - i) : | ||||
| 				null | ||||
| 			); | ||||
| 		}, | ||||
|  | ||||
| 		format(arr) { | ||||
| 			return arr.map((v, i) => ({ t: this.getDate(i).getTime(), y: v })); | ||||
| 		}, | ||||
|  | ||||
| 		federationInstancesChart(total: boolean): any { | ||||
| 			return [{ | ||||
| 				datasets: [{ | ||||
| 					label: 'Instances', | ||||
| 					fill: true, | ||||
| 					backgroundColor: rgba(colors.localPlus), | ||||
| 					borderColor: colors.localPlus, | ||||
| 					borderWidth: 2, | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: this.format(total | ||||
| 						? this.stats.federation.instance.total | ||||
| 						: sum(this.stats.federation.instance.inc, negate(this.stats.federation.instance.dec))) | ||||
| 				}] | ||||
| 			}]; | ||||
| 		}, | ||||
|  | ||||
| 		notesChart(type: string): any { | ||||
| 			return [{ | ||||
| 				datasets: [{ | ||||
| 					label: 'All', | ||||
| @@ -125,7 +193,10 @@ export default Vue.extend({ | ||||
| 					borderDash: [4, 4], | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.all })) | ||||
| 					data: this.format(type == 'combined' | ||||
| 						? sum(this.stats.notes.local.inc, negate(this.stats.notes.local.dec), this.stats.notes.remote.inc, negate(this.stats.notes.remote.dec)) | ||||
| 						: sum(this.stats.notes[type].inc, negate(this.stats.notes[type].dec)) | ||||
| 					) | ||||
| 				}, { | ||||
| 					label: 'Renotes', | ||||
| 					fill: true, | ||||
| @@ -134,7 +205,10 @@ export default Vue.extend({ | ||||
| 					borderWidth: 2, | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.renote })) | ||||
| 					data: this.format(type == 'combined' | ||||
| 						? sum(this.stats.notes.local.diffs.renote, this.stats.notes.remote.diffs.renote) | ||||
| 						: this.stats.notes[type].diffs.renote | ||||
| 					) | ||||
| 				}, { | ||||
| 					label: 'Replies', | ||||
| 					fill: true, | ||||
| @@ -143,7 +217,10 @@ export default Vue.extend({ | ||||
| 					borderWidth: 2, | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.reply })) | ||||
| 					data: this.format(type == 'combined' | ||||
| 						? sum(this.stats.notes.local.diffs.reply, this.stats.notes.remote.diffs.reply) | ||||
| 						: this.stats.notes[type].diffs.reply | ||||
| 					) | ||||
| 				}, { | ||||
| 					label: 'Normal', | ||||
| 					fill: true, | ||||
| @@ -152,7 +229,10 @@ export default Vue.extend({ | ||||
| 					borderWidth: 2, | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.normal })) | ||||
| 					data: this.format(type == 'combined' | ||||
| 						? sum(this.stats.notes.local.diffs.normal, this.stats.notes.remote.diffs.normal) | ||||
| 						: this.stats.notes[type].diffs.normal | ||||
| 					) | ||||
| 				}] | ||||
| 			}, { | ||||
| 				scales: { | ||||
| @@ -176,12 +256,6 @@ export default Vue.extend({ | ||||
| 		}, | ||||
|  | ||||
| 		notesTotalChart(): any { | ||||
| 			const data = this.stats.slice().reverse().map(x => ({ | ||||
| 				date: new Date(x.date), | ||||
| 				localCount: x.notes.local.total, | ||||
| 				remoteCount: x.notes.remote.total | ||||
| 			})); | ||||
|  | ||||
| 			return [{ | ||||
| 				datasets: [{ | ||||
| 					label: 'Combined', | ||||
| @@ -191,7 +265,7 @@ export default Vue.extend({ | ||||
| 					borderDash: [4, 4], | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.remoteCount + x.localCount })) | ||||
| 					data: this.format(sum(this.stats.notes.local.total, this.stats.notes.remote.total)) | ||||
| 				}, { | ||||
| 					label: 'Local', | ||||
| 					fill: true, | ||||
| @@ -200,7 +274,7 @@ export default Vue.extend({ | ||||
| 					borderWidth: 2, | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.localCount })) | ||||
| 					data: this.format(this.stats.notes.local.total) | ||||
| 				}, { | ||||
| 					label: 'Remote', | ||||
| 					fill: true, | ||||
| @@ -209,7 +283,7 @@ export default Vue.extend({ | ||||
| 					borderWidth: 2, | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.remoteCount })) | ||||
| 					data: this.format(this.stats.notes.remote.total) | ||||
| 				}] | ||||
| 			}, { | ||||
| 				scales: { | ||||
| @@ -233,12 +307,6 @@ export default Vue.extend({ | ||||
| 		}, | ||||
|  | ||||
| 		usersChart(total: boolean): any { | ||||
| 			const data = this.stats.slice().reverse().map(x => ({ | ||||
| 				date: new Date(x.date), | ||||
| 				localCount: total ? x.users.local.total : (x.users.local.inc + -x.users.local.dec), | ||||
| 				remoteCount: total ? x.users.remote.total : (x.users.remote.inc + -x.users.remote.dec) | ||||
| 			})); | ||||
|  | ||||
| 			return [{ | ||||
| 				datasets: [{ | ||||
| 					label: 'Combined', | ||||
| @@ -248,7 +316,10 @@ export default Vue.extend({ | ||||
| 					borderDash: [4, 4], | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.remoteCount + x.localCount })) | ||||
| 					data: this.format(total | ||||
| 						? sum(this.stats.users.local.total, this.stats.users.remote.total) | ||||
| 						: sum(this.stats.users.local.inc, negate(this.stats.users.local.dec), this.stats.users.remote.inc, negate(this.stats.users.remote.dec)) | ||||
| 					) | ||||
| 				}, { | ||||
| 					label: 'Local', | ||||
| 					fill: true, | ||||
| @@ -257,7 +328,10 @@ export default Vue.extend({ | ||||
| 					borderWidth: 2, | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.localCount })) | ||||
| 					data: this.format(total | ||||
| 						? this.stats.users.local.total | ||||
| 						: sum(this.stats.users.local.inc, negate(this.stats.users.local.dec)) | ||||
| 					) | ||||
| 				}, { | ||||
| 					label: 'Remote', | ||||
| 					fill: true, | ||||
| @@ -266,7 +340,10 @@ export default Vue.extend({ | ||||
| 					borderWidth: 2, | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.remoteCount })) | ||||
| 					data: this.format(total | ||||
| 						? this.stats.users.remote.total | ||||
| 						: sum(this.stats.users.remote.inc, negate(this.stats.users.remote.dec)) | ||||
| 					) | ||||
| 				}] | ||||
| 			}, { | ||||
| 				scales: { | ||||
| @@ -290,14 +367,6 @@ export default Vue.extend({ | ||||
| 		}, | ||||
|  | ||||
| 		driveChart(): any { | ||||
| 			const data = this.stats.slice().reverse().map(x => ({ | ||||
| 				date: new Date(x.date), | ||||
| 				localInc: x.drive.local.incSize, | ||||
| 				localDec: -x.drive.local.decSize, | ||||
| 				remoteInc: x.drive.remote.incSize, | ||||
| 				remoteDec: -x.drive.remote.decSize, | ||||
| 			})); | ||||
|  | ||||
| 			return [{ | ||||
| 				datasets: [{ | ||||
| 					label: 'All', | ||||
| @@ -307,7 +376,7 @@ export default Vue.extend({ | ||||
| 					borderDash: [4, 4], | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.localInc + x.localDec + x.remoteInc + x.remoteDec })) | ||||
| 					data: this.format(sum(this.stats.drive.local.incSize, negate(this.stats.drive.local.decSize), this.stats.drive.remote.incSize, negate(this.stats.drive.remote.decSize))) | ||||
| 				}, { | ||||
| 					label: 'Local +', | ||||
| 					fill: true, | ||||
| @@ -316,7 +385,7 @@ export default Vue.extend({ | ||||
| 					borderWidth: 2, | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.localInc })) | ||||
| 					data: this.format(this.stats.drive.local.incSize) | ||||
| 				}, { | ||||
| 					label: 'Local -', | ||||
| 					fill: true, | ||||
| @@ -325,7 +394,7 @@ export default Vue.extend({ | ||||
| 					borderWidth: 2, | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.localDec })) | ||||
| 					data: this.format(negate(this.stats.drive.local.decSize)) | ||||
| 				}, { | ||||
| 					label: 'Remote +', | ||||
| 					fill: true, | ||||
| @@ -334,7 +403,7 @@ export default Vue.extend({ | ||||
| 					borderWidth: 2, | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.remoteInc })) | ||||
| 					data: this.format(this.stats.drive.remote.incSize) | ||||
| 				}, { | ||||
| 					label: 'Remote -', | ||||
| 					fill: true, | ||||
| @@ -343,7 +412,7 @@ export default Vue.extend({ | ||||
| 					borderWidth: 2, | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.remoteDec })) | ||||
| 					data: this.format(negate(this.stats.drive.remote.decSize)) | ||||
| 				}] | ||||
| 			}, { | ||||
| 				scales: { | ||||
| @@ -367,12 +436,6 @@ export default Vue.extend({ | ||||
| 		}, | ||||
|  | ||||
| 		driveTotalChart(): any { | ||||
| 			const data = this.stats.slice().reverse().map(x => ({ | ||||
| 				date: new Date(x.date), | ||||
| 				localSize: x.drive.local.totalSize, | ||||
| 				remoteSize: x.drive.remote.totalSize | ||||
| 			})); | ||||
|  | ||||
| 			return [{ | ||||
| 				datasets: [{ | ||||
| 					label: 'Combined', | ||||
| @@ -382,7 +445,7 @@ export default Vue.extend({ | ||||
| 					borderDash: [4, 4], | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.remoteSize + x.localSize })) | ||||
| 					data: this.format(sum(this.stats.drive.local.totalSize, this.stats.drive.remote.totalSize)) | ||||
| 				}, { | ||||
| 					label: 'Local', | ||||
| 					fill: true, | ||||
| @@ -391,7 +454,7 @@ export default Vue.extend({ | ||||
| 					borderWidth: 2, | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.localSize })) | ||||
| 					data: this.format(this.stats.drive.local.totalSize) | ||||
| 				}, { | ||||
| 					label: 'Remote', | ||||
| 					fill: true, | ||||
| @@ -400,7 +463,7 @@ export default Vue.extend({ | ||||
| 					borderWidth: 2, | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.remoteSize })) | ||||
| 					data: this.format(this.stats.drive.remote.totalSize) | ||||
| 				}] | ||||
| 			}, { | ||||
| 				scales: { | ||||
| @@ -424,14 +487,6 @@ export default Vue.extend({ | ||||
| 		}, | ||||
|  | ||||
| 		driveFilesChart(): any { | ||||
| 			const data = this.stats.slice().reverse().map(x => ({ | ||||
| 				date: new Date(x.date), | ||||
| 				localInc: x.drive.local.incCount, | ||||
| 				localDec: -x.drive.local.decCount, | ||||
| 				remoteInc: x.drive.remote.incCount, | ||||
| 				remoteDec: -x.drive.remote.decCount | ||||
| 			})); | ||||
|  | ||||
| 			return [{ | ||||
| 				datasets: [{ | ||||
| 					label: 'All', | ||||
| @@ -441,7 +496,7 @@ export default Vue.extend({ | ||||
| 					borderDash: [4, 4], | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.localInc + x.localDec + x.remoteInc + x.remoteDec })) | ||||
| 					data: this.format(sum(this.stats.drive.local.incCount, negate(this.stats.drive.local.decCount), this.stats.drive.remote.incCount, negate(this.stats.drive.remote.decCount))) | ||||
| 				}, { | ||||
| 					label: 'Local +', | ||||
| 					fill: true, | ||||
| @@ -450,7 +505,7 @@ export default Vue.extend({ | ||||
| 					borderWidth: 2, | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.localInc })) | ||||
| 					data: this.format(this.stats.drive.local.incCount) | ||||
| 				}, { | ||||
| 					label: 'Local -', | ||||
| 					fill: true, | ||||
| @@ -459,7 +514,7 @@ export default Vue.extend({ | ||||
| 					borderWidth: 2, | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.localDec })) | ||||
| 					data: this.format(negate(this.stats.drive.local.decCount)) | ||||
| 				}, { | ||||
| 					label: 'Remote +', | ||||
| 					fill: true, | ||||
| @@ -468,7 +523,7 @@ export default Vue.extend({ | ||||
| 					borderWidth: 2, | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.remoteInc })) | ||||
| 					data: this.format(this.stats.drive.remote.incCount) | ||||
| 				}, { | ||||
| 					label: 'Remote -', | ||||
| 					fill: true, | ||||
| @@ -477,7 +532,7 @@ export default Vue.extend({ | ||||
| 					borderWidth: 2, | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.remoteDec })) | ||||
| 					data: this.format(negate(this.stats.drive.remote.decCount)) | ||||
| 				}] | ||||
| 			}, { | ||||
| 				scales: { | ||||
| @@ -501,12 +556,6 @@ export default Vue.extend({ | ||||
| 		}, | ||||
|  | ||||
| 		driveFilesTotalChart(): any { | ||||
| 			const data = this.stats.slice().reverse().map(x => ({ | ||||
| 				date: new Date(x.date), | ||||
| 				localCount: x.drive.local.totalCount, | ||||
| 				remoteCount: x.drive.remote.totalCount, | ||||
| 			})); | ||||
|  | ||||
| 			return [{ | ||||
| 				datasets: [{ | ||||
| 					label: 'Combined', | ||||
| @@ -516,7 +565,7 @@ export default Vue.extend({ | ||||
| 					borderDash: [4, 4], | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.localCount + x.remoteCount })) | ||||
| 					data: this.format(sum(this.stats.drive.local.totalCount, this.stats.drive.remote.totalCount)) | ||||
| 				}, { | ||||
| 					label: 'Local', | ||||
| 					fill: true, | ||||
| @@ -525,7 +574,7 @@ export default Vue.extend({ | ||||
| 					borderWidth: 2, | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.localCount })) | ||||
| 					data: this.format(this.stats.drive.local.totalCount) | ||||
| 				}, { | ||||
| 					label: 'Remote', | ||||
| 					fill: true, | ||||
| @@ -534,7 +583,7 @@ export default Vue.extend({ | ||||
| 					borderWidth: 2, | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.remoteCount })) | ||||
| 					data: this.format(this.stats.drive.remote.totalCount) | ||||
| 				}] | ||||
| 			}, { | ||||
| 				scales: { | ||||
| @@ -558,30 +607,26 @@ export default Vue.extend({ | ||||
| 		}, | ||||
|  | ||||
| 		networkRequestsChart(): any { | ||||
| 			const data = this.stats.slice().reverse().map(x => ({ | ||||
| 				date: new Date(x.date), | ||||
| 				requests: x.network.requests | ||||
| 			})); | ||||
|  | ||||
| 			return [{ | ||||
| 				datasets: [{ | ||||
| 					label: 'Requests', | ||||
| 					label: 'Incoming', | ||||
| 					fill: true, | ||||
| 					backgroundColor: rgba(colors.localPlus), | ||||
| 					borderColor: colors.localPlus, | ||||
| 					borderWidth: 2, | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.requests })) | ||||
| 					data: this.format(this.stats.network.incomingRequests) | ||||
| 				}] | ||||
| 			}]; | ||||
| 		}, | ||||
|  | ||||
| 		networkTimeChart(): any { | ||||
| 			const data = this.stats.slice().reverse().map(x => ({ | ||||
| 				date: new Date(x.date), | ||||
| 				time: x.network.requests != 0 ? (x.network.totalTime / x.network.requests) : 0, | ||||
| 			})); | ||||
| 			const data = []; | ||||
|  | ||||
| 			for (let i = 0; i < limit; i++) { | ||||
| 				data.push(this.stats.network.incomingRequests[i] != 0 ? (this.stats.network.totalTime[i] / this.stats.network.incomingRequests[i]) : 0); | ||||
| 			} | ||||
|  | ||||
| 			return [{ | ||||
| 				datasets: [{ | ||||
| @@ -592,18 +637,12 @@ export default Vue.extend({ | ||||
| 					borderWidth: 2, | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.time })) | ||||
| 					data: this.format(data) | ||||
| 				}] | ||||
| 			}]; | ||||
| 		}, | ||||
|  | ||||
| 		networkUsageChart(): any { | ||||
| 			const data = this.stats.slice().reverse().map(x => ({ | ||||
| 				date: new Date(x.date), | ||||
| 				incoming: x.network.incomingBytes, | ||||
| 				outgoing: x.network.outgoingBytes | ||||
| 			})); | ||||
|  | ||||
| 			return [{ | ||||
| 				datasets: [{ | ||||
| 					label: 'Incoming', | ||||
| @@ -613,7 +652,7 @@ export default Vue.extend({ | ||||
| 					borderWidth: 2, | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.incoming })) | ||||
| 					data: this.format(this.stats.network.incomingBytes) | ||||
| 				}, { | ||||
| 					label: 'Outgoing', | ||||
| 					fill: true, | ||||
| @@ -622,7 +661,7 @@ export default Vue.extend({ | ||||
| 					borderWidth: 2, | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.outgoing })) | ||||
| 					data: this.format(this.stats.network.outgoingBytes) | ||||
| 				}] | ||||
| 			}, { | ||||
| 				scales: { | ||||
| @@ -649,8 +688,6 @@ export default Vue.extend({ | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
|  | ||||
|  | ||||
| .gkgckalzgidaygcxnugepioremxvxvpt | ||||
| 	padding 32px | ||||
| 	background #fff | ||||
|   | ||||
| @@ -117,11 +117,11 @@ export default Vue.extend({ | ||||
| 	mounted() { | ||||
| 		this.connection = (this as any).os.stream.useSharedConnection('drive'); | ||||
|  | ||||
| 		this.connection.on('file_created', this.onStreamDriveFileCreated); | ||||
| 		this.connection.on('file_updated', this.onStreamDriveFileUpdated); | ||||
| 		this.connection.on('file_deleted', this.onStreamDriveFileDeleted); | ||||
| 		this.connection.on('folder_created', this.onStreamDriveFolderCreated); | ||||
| 		this.connection.on('folder_updated', this.onStreamDriveFolderUpdated); | ||||
| 		this.connection.on('fileCreated', this.onStreamDriveFileCreated); | ||||
| 		this.connection.on('fileUpdated', this.onStreamDriveFileUpdated); | ||||
| 		this.connection.on('fileDeleted', this.onStreamDriveFileDeleted); | ||||
| 		this.connection.on('folderCreated', this.onStreamDriveFolderCreated); | ||||
| 		this.connection.on('folderUpdated', this.onStreamDriveFolderUpdated); | ||||
|  | ||||
| 		if (this.initFolder) { | ||||
| 			this.move(this.initFolder); | ||||
|   | ||||
| @@ -91,7 +91,7 @@ import MkPostFormWindow from './post-form-window.vue'; | ||||
| 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 './notes.note.sub.vue'; | ||||
| import XSub from './note.sub.vue'; | ||||
| import { sum } from '../../../../../prelude/array'; | ||||
| import noteSubscriber from '../../../common/scripts/note-subscriber'; | ||||
|  | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| <template> | ||||
| <div class="tkfdzaxtkdeianobciwadajxzbddorql" :title="title"> | ||||
| <div class="tkfdzaxtkdeianobciwadajxzbddorql" :class="{ mini }" :title="title"> | ||||
| 	<mk-avatar class="avatar" :user="note.user"/> | ||||
| 	<div class="main"> | ||||
| 		<mk-note-header class="header" :note="note"/> | ||||
| @@ -24,6 +24,11 @@ export default Vue.extend({ | ||||
| 		note: { | ||||
| 			type: Object, | ||||
| 			required: true | ||||
| 		}, | ||||
| 		mini: { | ||||
| 			type: Boolean, | ||||
| 			required: false, | ||||
| 			default: false | ||||
| 		} | ||||
| 	}, | ||||
| 
 | ||||
| @@ -44,11 +49,19 @@ export default Vue.extend({ | ||||
| <style lang="stylus" scoped> | ||||
| .tkfdzaxtkdeianobciwadajxzbddorql | ||||
| 	display flex | ||||
| 	margin 0 | ||||
| 	padding 16px 32px | ||||
| 	font-size 0.9em | ||||
| 	background var(--subNoteBg) | ||||
| 
 | ||||
| 	&.mini | ||||
| 		padding 16px | ||||
| 		font-size 10px | ||||
| 
 | ||||
| 		> .avatar | ||||
| 			margin 0 8px 0 0 | ||||
| 			width 38px | ||||
| 			height 38px | ||||
| 
 | ||||
| 	> .avatar | ||||
| 		flex-shrink 0 | ||||
| 		display block | ||||
| @@ -1,13 +1,23 @@ | ||||
| <template> | ||||
| <div class="note" v-show="appearNote.deletedAt == null" :tabindex="appearNote.deletedAt == null ? '-1' : null" v-hotkey="keymap" :title="title"> | ||||
| <div | ||||
| 	class="note" | ||||
| 	:class="{ mini }" | ||||
| 	v-show="appearNote.deletedAt == null" | ||||
| 	:tabindex="appearNote.deletedAt == null ? '-1' : null" | ||||
| 	v-hotkey="keymap" | ||||
| 	:title="title" | ||||
| > | ||||
| 	<div class="conversation" v-if="detail && conversation.length > 0"> | ||||
| 		<x-sub v-for="note in conversation" :key="note.id" :note="note" :mini="mini"/> | ||||
| 	</div> | ||||
| 	<div class="reply-to" v-if="appearNote.reply && (!$store.getters.isSignedIn || $store.state.settings.showReplyTarget)"> | ||||
| 		<x-sub :note="appearNote.reply"/> | ||||
| 		<x-sub :note="appearNote.reply" :mini="mini"/> | ||||
| 	</div> | ||||
| 	<div class="renote" v-if="isRenote"> | ||||
| 		<mk-avatar class="avatar" :user="note.user"/> | ||||
| 		%fa:retweet% | ||||
| 		<span>{{ '%i18n:@reposted-by%'.substr(0, '%i18n:@reposted-by%'.indexOf('{')) }}</span> | ||||
| 		<a class="name" :href="note.user | userPage" v-user-preview="note.userId">{{ note.user | userName }}</a> | ||||
| 		<router-link class="name" :to="note.user | userPage" v-user-preview="note.userId">{{ note.user | userName }}</router-link> | ||||
| 		<span>{{ '%i18n:@reposted-by%'.substr('%i18n:@reposted-by%'.indexOf('}') + 1) }}</span> | ||||
| 		<mk-time :time="note.createdAt"/> | ||||
| 	</div> | ||||
| @@ -25,15 +35,15 @@ | ||||
| 						<span v-if="appearNote.isHidden" style="opacity: 0.5">%i18n:@private%</span> | ||||
| 						<a class="reply" v-if="appearNote.reply">%fa:reply%</a> | ||||
| 						<misskey-flavored-markdown v-if="appearNote.text" :text="appearNote.text" :i="$store.state.i" :class="$style.text"/> | ||||
| 						<a class="rp" v-if="appearNote.renote">RP:</a> | ||||
| 						<a class="rp" v-if="appearNote.renote">RN:</a> | ||||
| 					</div> | ||||
| 					<div class="files" v-if="appearNote.files.length > 0"> | ||||
| 						<mk-media-list :media-list="appearNote.files"/> | ||||
| 					</div> | ||||
| 					<mk-poll v-if="appearNote.poll" :note="appearNote" ref="pollViewer"/> | ||||
| 					<a class="location" v-if="appearNote.geo" :href="`https://maps.google.com/maps?q=${appearNote.geo.coordinates[1]},${appearNote.geo.coordinates[0]}`" target="_blank">%fa:map-marker-alt% 位置情報</a> | ||||
| 					<div class="renote" v-if="appearNote.renote"><mk-note-preview :note="appearNote.renote"/></div> | ||||
| 					<mk-url-preview v-for="url in urls" :url="url" :key="url"/> | ||||
| 					<div class="renote" v-if="appearNote.renote"><mk-note-preview :note="appearNote.renote" :mini="mini"/></div> | ||||
| 					<mk-url-preview v-for="url in urls" :url="url" :key="url" :mini="mini"/> | ||||
| 				</div> | ||||
| 			</div> | ||||
| 			<footer> | ||||
| @@ -55,15 +65,16 @@ | ||||
| 			</footer> | ||||
| 		</div> | ||||
| 	</article> | ||||
| 	<div class="replies" v-if="detail && replies.length > 0"> | ||||
| 		<x-sub v-for="note in replies" :key="note.id" :note="note" :mini="mini"/> | ||||
| 	</div> | ||||
| </div> | ||||
| </template> | ||||
| 
 | ||||
| <script lang="ts"> | ||||
| import Vue from 'vue'; | ||||
| 
 | ||||
| import MkPostFormWindow from './post-form-window.vue'; | ||||
| import MkRenoteFormWindow from './renote-form-window.vue'; | ||||
| import XSub from './notes.note.sub.vue'; | ||||
| import XSub from './note.sub.vue'; | ||||
| import noteMixin from '../../../common/scripts/note-mixin'; | ||||
| import noteSubscriber from '../../../common/scripts/note-subscriber'; | ||||
| 
 | ||||
| @@ -81,6 +92,40 @@ export default Vue.extend({ | ||||
| 		note: { | ||||
| 			type: Object, | ||||
| 			required: true | ||||
| 		}, | ||||
| 		detail: { | ||||
| 			type: Boolean, | ||||
| 			required: false, | ||||
| 			default: false | ||||
| 		}, | ||||
| 		mini: { | ||||
| 			type: Boolean, | ||||
| 			required: false, | ||||
| 			default: false | ||||
| 		} | ||||
| 	}, | ||||
| 
 | ||||
| 	data() { | ||||
| 		return { | ||||
| 			conversation: [], | ||||
| 			replies: [] | ||||
| 		}; | ||||
| 	}, | ||||
| 
 | ||||
| 	created() { | ||||
| 		if (this.detail) { | ||||
| 			(this as any).api('notes/replies', { | ||||
| 				noteId: this.appearNote.id, | ||||
| 				limit: 8 | ||||
| 			}).then(replies => { | ||||
| 				this.replies = replies; | ||||
| 			}); | ||||
| 
 | ||||
| 			(this as any).api('notes/conversation', { | ||||
| 				noteId: this.appearNote.replyId | ||||
| 			}).then(conversation => { | ||||
| 				this.conversation = conversation.reverse(); | ||||
| 			}); | ||||
| 		} | ||||
| 	} | ||||
| }); | ||||
| @@ -93,14 +138,23 @@ export default Vue.extend({ | ||||
| 	background var(--face) | ||||
| 	border-bottom solid 1px var(--faceDivider) | ||||
| 
 | ||||
| 	&[data-round] | ||||
| 		&:first-child | ||||
| 			border-top-left-radius 6px | ||||
| 			border-top-right-radius 6px | ||||
| 	&.mini | ||||
| 		font-size 13px | ||||
| 
 | ||||
| 			> .renote | ||||
| 				border-top-left-radius 6px | ||||
| 				border-top-right-radius 6px | ||||
| 		> .renote | ||||
| 			padding 8px 16px 0 16px | ||||
| 
 | ||||
| 			.avatar | ||||
| 				width 20px | ||||
| 				height 20px | ||||
| 
 | ||||
| 		> article | ||||
| 			padding 16px 16px 4px | ||||
| 
 | ||||
| 			> .avatar | ||||
| 				margin 0 10px 8px 0 | ||||
| 				width 42px | ||||
| 				height 42px | ||||
| 
 | ||||
| 	&:last-of-type | ||||
| 		border-bottom none | ||||
| @@ -129,6 +183,7 @@ export default Vue.extend({ | ||||
| 		background linear-gradient(to bottom, var(--renoteGradient) 0%, var(--face) 100%) | ||||
| 
 | ||||
| 		.avatar | ||||
| 			flex-shrink 0 | ||||
| 			display inline-block | ||||
| 			width 28px | ||||
| 			height 28px | ||||
| @@ -273,6 +328,9 @@ export default Vue.extend({ | ||||
| 					border none | ||||
| 					cursor pointer | ||||
| 
 | ||||
| 					&:last-child | ||||
| 						margin-right 0 | ||||
| 
 | ||||
| 					&:hover | ||||
| 						color var(--noteActionsHover) | ||||
| 
 | ||||
| @@ -4,9 +4,9 @@ | ||||
|  | ||||
| 	<slot name="empty" v-if="notes.length == 0 && !fetching && requestInitPromise == null"></slot> | ||||
|  | ||||
| 	<div v-if="!fetching && requestInitPromise != null"> | ||||
| 		<p>%i18n:@error%</p> | ||||
| 		<button @click="resolveInitPromise">%i18n:@retry%</button> | ||||
| 	<div v-if="!fetching && requestInitPromise != null" class="error"> | ||||
| 		<p>%fa:exclamation-triangle% %i18n:common.error.title%</p> | ||||
| 		<ui-button @click="resolveInitPromise">%i18n:common.error.retry%</ui-button> | ||||
| 	</div> | ||||
|  | ||||
| 	<div class="placeholder" v-if="fetching"> | ||||
| @@ -38,9 +38,8 @@ | ||||
| <script lang="ts"> | ||||
| import Vue from 'vue'; | ||||
| import * as config from '../../../config'; | ||||
| import getNoteSummary from '../../../../../misc/get-note-summary'; | ||||
|  | ||||
| import XNote from './notes.note.vue'; | ||||
| import XNote from './note.vue'; | ||||
|  | ||||
| const displayLimit = 30; | ||||
|  | ||||
| @@ -61,7 +60,6 @@ export default Vue.extend({ | ||||
| 			requestInitPromise: null as () => Promise<any[]>, | ||||
| 			notes: [], | ||||
| 			queue: [], | ||||
| 			unreadCount: 0, | ||||
| 			fetching: true, | ||||
| 			moreFetching: false | ||||
| 		}; | ||||
| @@ -80,12 +78,10 @@ export default Vue.extend({ | ||||
| 	}, | ||||
|  | ||||
| 	mounted() { | ||||
| 		document.addEventListener('visibilitychange', this.onVisibilitychange, false); | ||||
| 		window.addEventListener('scroll', this.onScroll, { passive: true }); | ||||
| 	}, | ||||
|  | ||||
| 	beforeDestroy() { | ||||
| 		document.removeEventListener('visibilitychange', this.onVisibilitychange); | ||||
| 		window.removeEventListener('scroll', this.onScroll); | ||||
| 	}, | ||||
|  | ||||
| @@ -147,10 +143,9 @@ export default Vue.extend({ | ||||
| 			} | ||||
| 			//#endregion | ||||
|  | ||||
| 			// 投稿が自分のものではないかつ、タブが非表示またはスクロール位置が最上部ではないならタイトルで通知 | ||||
| 			if ((document.hidden || !this.isScrollTop()) && note.userId !== this.$store.state.i.id) { | ||||
| 				this.unreadCount++; | ||||
| 				document.title = `(${this.unreadCount}) ${getNoteSummary(note)}`; | ||||
| 			// タブが非表示またはスクロール位置が最上部ではないならタイトルで通知 | ||||
| 			if (document.hidden || !this.isScrollTop()) { | ||||
| 				this.$store.commit('pushBehindNote', note); | ||||
| 			} | ||||
|  | ||||
| 			if (this.isScrollTop()) { | ||||
| @@ -195,21 +190,9 @@ export default Vue.extend({ | ||||
| 			this.moreFetching = false; | ||||
| 		}, | ||||
|  | ||||
| 		clearNotification() { | ||||
| 			this.unreadCount = 0; | ||||
| 			document.title = (this as any).os.instanceName; | ||||
| 		}, | ||||
|  | ||||
| 		onVisibilitychange() { | ||||
| 			if (!document.hidden) { | ||||
| 				this.clearNotification(); | ||||
| 			} | ||||
| 		}, | ||||
|  | ||||
| 		onScroll() { | ||||
| 			if (this.isScrollTop()) { | ||||
| 				this.releaseQueue(); | ||||
| 				this.clearNotification(); | ||||
| 			} | ||||
|  | ||||
| 			if (this.$store.state.settings.fetchOnScroll !== false) { | ||||
| @@ -232,6 +215,16 @@ export default Vue.extend({ | ||||
| 		> * | ||||
| 			transition transform .3s ease, opacity .3s ease | ||||
|  | ||||
| 	> .error | ||||
| 		max-width 300px | ||||
| 		margin 0 auto | ||||
| 		padding 32px | ||||
| 		text-align center | ||||
| 		color var(--text) | ||||
|  | ||||
| 		> p | ||||
| 			margin 0 0 8px 0 | ||||
|  | ||||
| 	> .placeholder | ||||
| 		padding 32px | ||||
| 		opacity 0.3 | ||||
|   | ||||
| @@ -307,7 +307,7 @@ export default Vue.extend({ | ||||
| 		display block | ||||
| 		width 100% | ||||
| 		padding 16px | ||||
| 		color #555 | ||||
| 		color var(--text) | ||||
| 		border-top solid 1px rgba(#000, 0.05) | ||||
|  | ||||
| 		&:hover | ||||
| @@ -326,6 +326,6 @@ export default Vue.extend({ | ||||
| 		margin 0 | ||||
| 		padding 16px | ||||
| 		text-align center | ||||
| 		color #aaa | ||||
| 		color var(--text) | ||||
|  | ||||
| </style> | ||||
|   | ||||
| @@ -12,7 +12,7 @@ | ||||
| 		</div> | ||||
| 		<div class="hashtags" v-if="recentHashtags.length > 0 && $store.state.settings.suggestRecentHashtags"> | ||||
| 			<b>%i18n:@recent-tags%:</b> | ||||
| 			<a v-for="tag in recentHashtags.slice(0, 5)" @click="addTag(tag)" title="%@click-to-tagging%">#{{ tag }}</a> | ||||
| 			<a v-for="tag in recentHashtags.slice(0, 5)" @click="addTag(tag)" title="%i18n:@click-to-tagging%">#{{ tag }}</a> | ||||
| 		</div> | ||||
| 		<input v-show="useCw" v-model="cw" placeholder="%i18n:@annotations%"> | ||||
| 		<textarea :class="{ with: (files.length != 0 || poll) }" | ||||
| @@ -45,7 +45,7 @@ | ||||
| 		<span v-if="visibility === 'specified'">%fa:envelope%</span> | ||||
| 		<span v-if="visibility === 'private'">%fa:lock%</span> | ||||
| 	</button> | ||||
| 	<p class="text-count" :class="{ over: this.trimmedLength(text) > 1000 }">{{ 1000 - this.trimmedLength(text) }}</p> | ||||
| 	<p class="text-count" :class="{ over: this.trimmedLength(text) > this.maxNoteTextLength }">{{ this.maxNoteTextLength - this.trimmedLength(text) }}</p> | ||||
| 	<button :class="{ posting }" class="submit" :disabled="!canPost" @click="post"> | ||||
| 		{{ posting ? '%i18n:@posting%' : submitText }}<mk-ellipsis v-if="posting"/> | ||||
| 	</button> | ||||
| @@ -107,10 +107,17 @@ export default Vue.extend({ | ||||
| 			visibleUsers: [], | ||||
| 			autocomplete: null, | ||||
| 			draghover: false, | ||||
| 			recentHashtags: JSON.parse(localStorage.getItem('hashtags') || '[]') | ||||
| 			recentHashtags: JSON.parse(localStorage.getItem('hashtags') || '[]'), | ||||
| 			maxNoteTextLength: 1000 | ||||
| 		}; | ||||
| 	}, | ||||
|  | ||||
| 	created() { | ||||
| 		(this as any).os.getMeta().then(meta => { | ||||
| 			this.maxNoteTextLength = meta.maxNoteTextLength; | ||||
| 		}); | ||||
| 	}, | ||||
|  | ||||
| 	computed: { | ||||
| 		draftId(): string { | ||||
| 			return this.renote | ||||
| @@ -149,7 +156,7 @@ export default Vue.extend({ | ||||
| 		canPost(): boolean { | ||||
| 			return !this.posting && | ||||
| 				(1 <= this.text.length || 1 <= this.files.length || this.poll || this.renote) && | ||||
| 				(length(this.text.trim()) <= 1000); | ||||
| 				(length(this.text.trim()) <= this.maxNoteTextLength); | ||||
| 		} | ||||
| 	}, | ||||
|  | ||||
|   | ||||
| @@ -2,10 +2,10 @@ | ||||
| <div class="2fa"> | ||||
| 	<p>%i18n:@intro%<a href="%i18n:@url%" target="_blank">%i18n:@detail%</a></p> | ||||
| 	<div class="ui info warn"><p>%fa:exclamation-triangle%%i18n:@caution%</p></div> | ||||
| 	<p v-if="!data && !$store.state.i.twoFactorEnabled"><button @click="register" class="ui primary">%i18n:@register%</button></p> | ||||
| 	<p v-if="!data && !$store.state.i.twoFactorEnabled"><ui-button @click="register">%i18n:@register%</ui-button></p> | ||||
| 	<template v-if="$store.state.i.twoFactorEnabled"> | ||||
| 		<p>%i18n:@already-registered%</p> | ||||
| 		<button @click="unregister" class="ui">%i18n:@unregister%</button> | ||||
| 		<ui-button @click="unregister">%i18n:@unregister%</ui-button> | ||||
| 	</template> | ||||
| 	<div v-if="data"> | ||||
| 		<ol> | ||||
| @@ -13,7 +13,7 @@ | ||||
| 			<li>%i18n:@scan%<br><img :src="data.qr"></li> | ||||
| 			<li>%i18n:@done%<br> | ||||
| 				<input type="number" v-model="token" class="ui"> | ||||
| 				<button @click="submit" class="ui primary">%i18n:@submit%</button> | ||||
| 				<ui-button primary @click="submit">%i18n:@submit%</ui-button> | ||||
| 			</li> | ||||
| 		</ol> | ||||
| 		<div class="ui info"><p>%fa:info-circle%%i18n:@info%</p></div> | ||||
|   | ||||
| @@ -1,10 +1,12 @@ | ||||
| <template> | ||||
| <div class="root api"> | ||||
| 	<p>%i18n:@token% <code>{{ $store.state.i.token }}</code></p> | ||||
| 	<ui-input :value="$store.state.i.token" readonly> | ||||
| 		<span>%i18n:@token%</span> | ||||
| 	</ui-input> | ||||
| 	<p>%i18n:@intro%</p> | ||||
| 	<div class="ui info warn"><p>%fa:exclamation-triangle%%i18n:@caution%</p></div> | ||||
| 	<p>%i18n:@regeneration-of-token%</p> | ||||
| 	<button class="ui" @click="regenerateToken">%i18n:@regenerate-token%</button> | ||||
| 	<ui-button @click="regenerateToken">%i18n:@regenerate-token%</ui-button> | ||||
| </div> | ||||
| </template> | ||||
|  | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| <template> | ||||
| <div class="root"> | ||||
| 	<template v-if="!fetching"> | ||||
| 		<p><b>{{ capacity | bytes }}</b>%i18n:max%<b>{{ usage | bytes }}</b>%i18n:in-use%</p> | ||||
| 		<p><b>{{ capacity | bytes }}</b>%i18n:@max%<b>{{ usage | bytes }}</b>%i18n:@in-use%</p> | ||||
| 	</template> | ||||
| </div> | ||||
| </template> | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| <template> | ||||
| <div> | ||||
| 	<button @click="reset" class="ui primary">%i18n:@reset%</button> | ||||
| 	<ui-button @click="reset">%i18n:@reset%</ui-button> | ||||
| </div> | ||||
| </template> | ||||
|  | ||||
|   | ||||
| @@ -1,106 +0,0 @@ | ||||
| <template> | ||||
| <div class="profile"> | ||||
| 	<label class="avatar ui from group"> | ||||
| 		<p>%i18n:@avatar%</p> | ||||
| 		<img class="avatar" :src="$store.state.i.avatarUrl" alt="avatar"/> | ||||
| 		<button class="ui" @click="updateAvatar">%i18n:@choice-avatar%</button> | ||||
| 	</label> | ||||
| 	<label class="ui from group"> | ||||
| 		<ui-input v-model="name" type="text">%i18n:@name%</ui-input> | ||||
| 	</label> | ||||
| 	<label class="ui from group"> | ||||
| 		<ui-input v-model="location" type="text">%i18n:@location%</ui-input> | ||||
| 	</label> | ||||
| 	<label class="ui from group"> | ||||
| 		<ui-textarea v-model="description">%i18n:@description%</ui-textarea> | ||||
| 	</label> | ||||
| 	<label class="ui from group"> | ||||
| 		<p>%i18n:@birthday%</p> | ||||
| 		<input type="date" v-model="birthday"/> | ||||
| 	</label> | ||||
| 	<ui-button primary @click="save">%i18n:@save%</ui-button> | ||||
| 	<section> | ||||
| 		<h2>%i18n:@locked-account%</h2> | ||||
| 		<ui-switch v-model="isLocked" @change="save(false)">%i18n:@is-locked%</ui-switch> | ||||
| 		<ui-switch v-model="carefulBot" @change="save(false)">%i18n:@careful-bot%</ui-switch> | ||||
| 	</section> | ||||
| 	<section> | ||||
| 		<h2>%i18n:@other%</h2> | ||||
| 		<ui-switch v-model="isBot" @change="save(false)">%i18n:@is-bot%</ui-switch> | ||||
| 		<ui-switch v-model="isCat" @change="save(false)">%i18n:@is-cat%</ui-switch> | ||||
| 		<ui-switch v-model="alwaysMarkNsfw">%i18n:common.always-mark-nsfw%</ui-switch> | ||||
| 	</section> | ||||
| </div> | ||||
| </template> | ||||
|  | ||||
| <script lang="ts"> | ||||
| import Vue from 'vue'; | ||||
|  | ||||
| export default Vue.extend({ | ||||
| 	data() { | ||||
| 		return { | ||||
| 			name: null, | ||||
| 			location: null, | ||||
| 			description: null, | ||||
| 			birthday: null, | ||||
| 			isBot: false, | ||||
| 			isCat: false, | ||||
| 			isLocked: false, | ||||
| 			carefulBot: false, | ||||
| 		}; | ||||
| 	}, | ||||
| 	computed: { | ||||
| 		alwaysMarkNsfw: { | ||||
| 			get() { return this.$store.state.i.settings.alwaysMarkNsfw; }, | ||||
| 			set(value) { (this as any).api('i/update', { alwaysMarkNsfw: value }); } | ||||
| 		}, | ||||
| 	}, | ||||
| 	created() { | ||||
| 		this.name = this.$store.state.i.name || ''; | ||||
| 		this.location = this.$store.state.i.profile.location; | ||||
| 		this.description = this.$store.state.i.description; | ||||
| 		this.birthday = this.$store.state.i.profile.birthday; | ||||
| 		this.isCat = this.$store.state.i.isCat; | ||||
| 		this.isBot = this.$store.state.i.isBot; | ||||
| 		this.isLocked = this.$store.state.i.isLocked; | ||||
| 		this.carefulBot = this.$store.state.i.carefulBot; | ||||
| 	}, | ||||
| 	methods: { | ||||
| 		updateAvatar() { | ||||
| 			(this as any).apis.updateAvatar(); | ||||
| 		}, | ||||
| 		save(notify) { | ||||
| 			(this as any).api('i/update', { | ||||
| 				name: this.name || null, | ||||
| 				location: this.location || null, | ||||
| 				description: this.description || null, | ||||
| 				birthday: this.birthday || null, | ||||
| 				isCat: this.isCat, | ||||
| 				isBot: this.isBot, | ||||
| 				isLocked: this.isLocked, | ||||
| 				carefulBot: this.carefulBot | ||||
| 			}).then(() => { | ||||
| 				if (notify) { | ||||
| 					(this as any).apis.notify('%i18n:@profile-updated%'); | ||||
| 				} | ||||
| 			}); | ||||
| 		} | ||||
| 	} | ||||
| }); | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| .profile | ||||
| 	> .avatar | ||||
| 		> img | ||||
| 			display inline-block | ||||
| 			vertical-align top | ||||
| 			width 64px | ||||
| 			height 64px | ||||
| 			border-radius 4px | ||||
|  | ||||
| 		> button | ||||
| 			margin-left 8px | ||||
|  | ||||
| </style> | ||||
|  | ||||
| @@ -2,38 +2,66 @@ | ||||
| <div class="mk-settings"> | ||||
| 	<div class="nav"> | ||||
| 		<p :class="{ active: page == 'profile' }" @mousedown="page = 'profile'">%fa:user .fw%%i18n:@profile%</p> | ||||
| 		<p :class="{ active: page == 'theme' }" @mousedown="page = 'theme'">%fa:palette .fw%%i18n:@theme%</p> | ||||
| 		<p :class="{ active: page == 'web' }" @mousedown="page = 'web'">%fa:desktop .fw%Web</p> | ||||
| 		<p :class="{ active: page == 'notification' }" @mousedown="page = 'notification'">%fa:R bell .fw%%i18n:@notification%</p> | ||||
| 		<p :class="{ active: page == 'drive' }" @mousedown="page = 'drive'">%fa:cloud .fw%%i18n:@drive%</p> | ||||
| 		<p :class="{ active: page == 'hashtags' }" @mousedown="page = 'hashtags'">%fa:hashtag .fw%%i18n:@tags%</p> | ||||
| 		<p :class="{ active: page == 'mute' }" @mousedown="page = 'mute'">%fa:ban .fw%%i18n:@mute%</p> | ||||
| 		<p :class="{ active: page == 'apps' }" @mousedown="page = 'apps'">%fa:puzzle-piece .fw%%i18n:@apps%</p> | ||||
| 		<p :class="{ active: page == 'twitter' }" @mousedown="page = 'twitter'">%fa:B twitter .fw%Twitter</p> | ||||
| 		<p :class="{ active: page == 'security' }" @mousedown="page = 'security'">%fa:unlock-alt .fw%%i18n:@security%</p> | ||||
| 		<p :class="{ active: page == 'api' }" @mousedown="page = 'api'">%fa:key .fw%API</p> | ||||
| 		<p :class="{ active: page == 'other' }" @mousedown="page = 'other'">%fa:cogs .fw%%i18n:@other%</p> | ||||
| 	</div> | ||||
| 	<div class="pages"> | ||||
| 		<section class="profile" v-show="page == 'profile'"> | ||||
| 			<h1>%i18n:@profile%</h1> | ||||
| 			<x-profile/> | ||||
| 		</section> | ||||
| 		<div class="profile" v-show="page == 'profile'"> | ||||
| 			<mk-profile-editor/> | ||||
|  | ||||
| 		<section class="web" v-show="page == 'web'"> | ||||
| 			<h1>%i18n:@theme%</h1> | ||||
| 			<mk-theme/> | ||||
| 		</section> | ||||
| 			<ui-card> | ||||
| 				<div slot="title">%fa:B twitter% %i18n:@twitter%</div> | ||||
| 				<section> | ||||
| 					<mk-twitter-setting/> | ||||
| 				</section> | ||||
| 			</ui-card> | ||||
| 		</div> | ||||
|  | ||||
| 		<section class="web" v-show="page == 'web'"> | ||||
| 			<h1>%i18n:@behaviour%</h1> | ||||
| 			<ui-switch v-model="fetchOnScroll"> | ||||
| 				%i18n:@fetch-on-scroll% | ||||
| 				<span slot="desc">%i18n:@fetch-on-scroll-desc%</span> | ||||
| 			</ui-switch> | ||||
| 			<ui-switch v-model="autoPopout"> | ||||
| 				%i18n:@auto-popout% | ||||
| 				<span slot="desc">%i18n:@auto-popout-desc%</span> | ||||
| 			</ui-switch> | ||||
| 		<ui-card class="theme" v-show="page == 'theme'"> | ||||
| 			<div slot="title">%fa:palette% %i18n:@theme%</div> | ||||
|  | ||||
| 			<section> | ||||
| 				<mk-theme/> | ||||
| 			</section> | ||||
| 		</ui-card> | ||||
|  | ||||
| 		<ui-card class="web" v-show="page == 'web'"> | ||||
| 			<div slot="title">%fa:sliders-h% %i18n:@behaviour%</div> | ||||
|  | ||||
| 			<section> | ||||
| 				<ui-switch v-model="fetchOnScroll"> | ||||
| 					%i18n:@fetch-on-scroll% | ||||
| 					<span slot="desc">%i18n:@fetch-on-scroll-desc%</span> | ||||
| 				</ui-switch> | ||||
| 				<ui-switch v-model="autoPopout"> | ||||
| 					%i18n:@auto-popout% | ||||
| 					<span slot="desc">%i18n:@auto-popout-desc%</span> | ||||
| 				</ui-switch> | ||||
| 				<ui-switch v-model="deckNav">%i18n:@deck-nav%<span slot="desc">%i18n:@deck-nav-desc%</span></ui-switch> | ||||
|  | ||||
| 				<details> | ||||
| 					<summary>%i18n:@advanced%</summary> | ||||
| 					<ui-switch v-model="apiViaStream"> | ||||
| 						%i18n:@api-via-stream% | ||||
| 						<span slot="desc">%i18n:@api-via-stream-desc%</span> | ||||
| 					</ui-switch> | ||||
| 				</details> | ||||
| 			</section> | ||||
|  | ||||
| 			<section> | ||||
| 				<header>%i18n:@timeline%</header> | ||||
| 				<ui-switch v-model="showMyRenotes">%i18n:@show-my-renotes%</ui-switch> | ||||
| 				<ui-switch v-model="showRenotedMyNotes">%i18n:@show-renoted-my-notes%</ui-switch> | ||||
| 				<ui-switch v-model="showLocalRenotes">%i18n:@show-local-renotes%</ui-switch> | ||||
| 			</section> | ||||
|  | ||||
| 			<section> | ||||
| 				<header>%i18n:@note-visibility%</header> | ||||
| @@ -49,24 +77,30 @@ | ||||
| 					</ui-select> | ||||
| 				</section> | ||||
| 			</section> | ||||
| 		</ui-card> | ||||
|  | ||||
| 			<details> | ||||
| 				<summary>%i18n:@advanced%</summary> | ||||
| 				<ui-switch v-model="apiViaStream"> | ||||
| 					%i18n:@api-via-stream% | ||||
| 					<span slot="desc">%i18n:@api-via-stream-desc%</span> | ||||
| 				</ui-switch> | ||||
| 			</details> | ||||
| 		</section> | ||||
| 		<ui-card class="web" v-show="page == 'web'"> | ||||
| 			<div slot="title">%fa:desktop% %i18n:@display%</div> | ||||
|  | ||||
| 		<section class="web" v-show="page == 'web'"> | ||||
| 			<h1>%i18n:@display%</h1> | ||||
| 			<div class="div"> | ||||
| 				<button class="ui button" @click="customizeHome" style="margin-bottom: 16px">%i18n:@customize%</button> | ||||
| 			</div> | ||||
| 			<div class="div"> | ||||
| 				<button class="ui" @click="updateWallpaper">%i18n:@choose-wallpaper%</button> | ||||
| 				<button class="ui" @click="deleteWallpaper">%i18n:@delete-wallpaper%</button> | ||||
| 			<section> | ||||
| 				<ui-switch v-model="showPostFormOnTopOfTl">%i18n:@post-form-on-timeline%</ui-switch> | ||||
| 				<ui-button @click="customizeHome">%i18n:@customize%</ui-button> | ||||
| 			</section> | ||||
| 			<section> | ||||
| 				<header>%i18n:@wallpaper%</header> | ||||
| 				<ui-button @click="updateWallpaper">%i18n:@choose-wallpaper%</ui-button> | ||||
| 				<ui-button @click="deleteWallpaper">%i18n:@delete-wallpaper%</ui-button> | ||||
| 			</section> | ||||
| 			<section> | ||||
| 				<header>%i18n:@navbar-position%</header> | ||||
| 				<ui-radio v-model="navbar" value="top">%i18n:@navbar-position-top%</ui-radio> | ||||
| 				<ui-radio v-model="navbar" value="left">%i18n:@navbar-position-left%</ui-radio> | ||||
| 				<ui-radio v-model="navbar" value="right">%i18n:@navbar-position-right%</ui-radio> | ||||
| 			</section> | ||||
| 			<section> | ||||
| 				<ui-switch v-model="deckDefault">%i18n:@deck-default%</ui-switch> | ||||
| 			</section> | ||||
| 			<section> | ||||
| 				<ui-switch v-model="darkmode">%i18n:@dark-mode%</ui-switch> | ||||
| 				<ui-switch v-model="useShadow">%i18n:@use-shadow%</ui-switch> | ||||
| 				<ui-switch v-model="roundedCorners">%i18n:@rounded-corners%</ui-switch> | ||||
| @@ -75,171 +109,192 @@ | ||||
| 				<ui-switch v-model="contrastedAcct">%i18n:@contrasted-acct%</ui-switch> | ||||
| 				<ui-switch v-model="showFullAcct">%i18n:common.show-full-acct%</ui-switch> | ||||
| 				<ui-switch v-model="iLikeSushi">%i18n:common.i-like-sushi%</ui-switch> | ||||
| 			</div> | ||||
| 			<ui-switch v-model="showPostFormOnTopOfTl">%i18n:@post-form-on-timeline%</ui-switch> | ||||
| 			<ui-switch v-model="suggestRecentHashtags">%i18n:@suggest-recent-hashtags%</ui-switch> | ||||
| 			<ui-switch v-model="showClockOnHeader">%i18n:@show-clock-on-header%</ui-switch> | ||||
| 			<ui-switch v-model="alwaysShowNsfw">%i18n:common.always-show-nsfw%</ui-switch> | ||||
| 			<ui-switch v-model="showReplyTarget">%i18n:@show-reply-target%</ui-switch> | ||||
| 			<ui-switch v-model="showMyRenotes">%i18n:@show-my-renotes%</ui-switch> | ||||
| 			<ui-switch v-model="showRenotedMyNotes">%i18n:@show-renoted-my-notes%</ui-switch> | ||||
| 			<ui-switch v-model="showLocalRenotes">%i18n:@show-local-renotes%</ui-switch> | ||||
| 			<ui-switch v-model="showMaps">%i18n:@show-maps%</ui-switch> | ||||
| 			<ui-switch v-model="disableAnimatedMfm">%i18n:common.disable-animated-mfm%</ui-switch> | ||||
| 			<ui-switch v-model="games_reversi_showBoardLabels">%i18n:common.show-reversi-board-labels%</ui-switch> | ||||
| 			<ui-switch v-model="games_reversi_useContrastStones">%i18n:common.use-contrast-reversi-stones%</ui-switch> | ||||
| 			</section> | ||||
| 			<section> | ||||
| 				<ui-switch v-model="suggestRecentHashtags">%i18n:@suggest-recent-hashtags%</ui-switch> | ||||
| 				<ui-switch v-model="showClockOnHeader">%i18n:@show-clock-on-header%</ui-switch> | ||||
| 				<ui-switch v-model="alwaysShowNsfw">%i18n:common.always-show-nsfw%</ui-switch> | ||||
| 				<ui-switch v-model="showReplyTarget">%i18n:@show-reply-target%</ui-switch> | ||||
| 				<ui-switch v-model="showMaps">%i18n:@show-maps%</ui-switch> | ||||
| 				<ui-switch v-model="disableAnimatedMfm">%i18n:common.disable-animated-mfm%</ui-switch> | ||||
| 			</section> | ||||
| 			<section> | ||||
| 				<header>%i18n:@deck-column-align%</header> | ||||
| 				<ui-radio v-model="deckColumnAlign" value="center">%i18n:@deck-column-align-center%</ui-radio> | ||||
| 				<ui-radio v-model="deckColumnAlign" value="left">%i18n:@deck-column-align-left%</ui-radio> | ||||
| 			</section> | ||||
| 			<section> | ||||
| 				<ui-switch v-model="games_reversi_showBoardLabels">%i18n:common.show-reversi-board-labels%</ui-switch> | ||||
| 				<ui-switch v-model="games_reversi_useContrastStones">%i18n:common.use-contrast-reversi-stones%</ui-switch> | ||||
| 			</section> | ||||
| 		</ui-card> | ||||
|  | ||||
| 		<ui-card class="web" v-show="page == 'web'"> | ||||
| 			<div slot="title">%fa:volume-up% %i18n:@sound%</div> | ||||
|  | ||||
| 			<section> | ||||
| 				<header>%i18n:@navbar-position%</header> | ||||
| 				<ui-radio v-model="navbar" value="top">%i18n:@navbar-position-top%</ui-radio> | ||||
| 				<ui-radio v-model="navbar" value="left">%i18n:@navbar-position-left%</ui-radio> | ||||
| 				<ui-radio v-model="navbar" value="right">%i18n:@navbar-position-right%</ui-radio> | ||||
| 			</section> | ||||
| 		</section> | ||||
|  | ||||
| 		<section class="web" v-show="page == 'web'"> | ||||
| 			<h1>%i18n:@sound%</h1> | ||||
| 			<ui-switch v-model="enableSounds"> | ||||
| 				%i18n:@enable-sounds% | ||||
| 				<span slot="desc">%i18n:@enable-sounds-desc%</span> | ||||
| 			</ui-switch> | ||||
| 			<label>%i18n:@volume%</label> | ||||
| 			<input type="range" | ||||
| 				v-model="soundVolume" | ||||
| 				:disabled="!enableSounds" | ||||
| 				max="1" | ||||
| 				step="0.1" | ||||
| 			/> | ||||
| 			<button class="ui button" @click="soundTest">%fa:volume-up% %i18n:@test%</button> | ||||
| 		</section> | ||||
|  | ||||
| 		<section class="web" v-show="page == 'web'"> | ||||
| 			<h1>%i18n:@mobile%</h1> | ||||
| 			<ui-switch v-model="disableViaMobile">%i18n:@disable-via-mobile%</ui-switch> | ||||
| 		</section> | ||||
|  | ||||
| 		<section class="web" v-show="page == 'web'"> | ||||
| 			<h1>%i18n:@language%</h1> | ||||
| 			<select v-model="lang" placeholder="%i18n:@pick-language%"> | ||||
| 				<optgroup label="%i18n:@recommended%"> | ||||
| 					<option value="">%i18n:@auto%</option> | ||||
| 				</optgroup> | ||||
|  | ||||
| 				<optgroup label="%i18n:@specify-language%"> | ||||
| 					<option v-for="x in langs" :value="x[0]" :key="x[0]">{{ x[1] }}</option> | ||||
| 				</optgroup> | ||||
| 			</select> | ||||
| 			<div class="none ui info"> | ||||
| 				<p>%fa:info-circle%%i18n:@language-desc%</p> | ||||
| 			</div> | ||||
| 		</section> | ||||
|  | ||||
| 		<section class="web" v-show="page == 'web'"> | ||||
| 			<h1>%i18n:@cache%</h1> | ||||
| 			<button class="ui button" @click="clean">%i18n:@clean-cache%</button> | ||||
| 			<div class="none ui info warn"> | ||||
| 				<p>%fa:exclamation-triangle%%i18n:@cache-warn%</p> | ||||
| 			</div> | ||||
| 		</section> | ||||
|  | ||||
| 		<section class="notification" v-show="page == 'notification'"> | ||||
| 			<h1>%i18n:@notification%</h1> | ||||
| 			<ui-switch v-model="$store.state.i.settings.autoWatch" @change="onChangeAutoWatch"> | ||||
| 				%i18n:@auto-watch% | ||||
| 				<span slot="desc">%i18n:@auto-watch-desc%</span> | ||||
| 			</ui-switch> | ||||
| 		</section> | ||||
|  | ||||
| 		<section class="drive" v-show="page == 'drive'"> | ||||
| 			<h1>%i18n:@drive%</h1> | ||||
| 			<x-drive/> | ||||
| 		</section> | ||||
|  | ||||
| 		<section class="hashtags" v-show="page == 'hashtags'"> | ||||
| 			<h1>%i18n:@tags%</h1> | ||||
| 			<x-tags/> | ||||
| 		</section> | ||||
|  | ||||
| 		<section class="mute" v-show="page == 'mute'"> | ||||
| 			<h1>%i18n:@mute%</h1> | ||||
| 			<x-mute/> | ||||
| 		</section> | ||||
|  | ||||
| 		<section class="apps" v-show="page == 'apps'"> | ||||
| 			<h1>%i18n:@apps%</h1> | ||||
| 			<x-apps/> | ||||
| 		</section> | ||||
|  | ||||
| 		<section class="twitter" v-show="page == 'twitter'"> | ||||
| 			<h1>Twitter</h1> | ||||
| 			<mk-twitter-setting/> | ||||
| 		</section> | ||||
|  | ||||
| 		<section class="password" v-show="page == 'security'"> | ||||
| 			<h1>%i18n:@password%</h1> | ||||
| 			<x-password/> | ||||
| 		</section> | ||||
|  | ||||
| 		<section class="2fa" v-show="page == 'security'"> | ||||
| 			<h1>%i18n:@2fa%</h1> | ||||
| 			<x-2fa/> | ||||
| 		</section> | ||||
|  | ||||
| 		<section class="signin" v-show="page == 'security'"> | ||||
| 			<h1>%i18n:@signin%</h1> | ||||
| 			<x-signins/> | ||||
| 		</section> | ||||
|  | ||||
| 		<section class="api" v-show="page == 'api'"> | ||||
| 			<h1>API</h1> | ||||
| 			<x-api/> | ||||
| 		</section> | ||||
|  | ||||
| 		<section class="other" v-show="page == 'other'"> | ||||
| 			<h1>%i18n:@about%</h1> | ||||
| 			<p v-if="meta">%i18n:@operator%: <i><a :href="meta.maintainer.url" target="_blank">{{ meta.maintainer.name }}</a></i></p> | ||||
| 		</section> | ||||
|  | ||||
| 		<section class="other" v-show="page == 'other'"> | ||||
| 			<h1>%i18n:@update%</h1> | ||||
| 			<p> | ||||
| 				<span>%i18n:@version% <i>{{ version }}</i></span> | ||||
| 				<template v-if="latestVersion !== undefined"> | ||||
| 					<br> | ||||
| 					<span>%i18n:@latest-version% <i>{{ latestVersion ? latestVersion : version }}</i></span> | ||||
| 				</template> | ||||
| 			</p> | ||||
| 			<button class="ui button block" @click="checkForUpdate" :disabled="checkingForUpdate"> | ||||
| 				<template v-if="checkingForUpdate">%i18n:@update-checking%<mk-ellipsis/></template> | ||||
| 				<template v-else>%i18n:@do-update%</template> | ||||
| 			</button> | ||||
| 			<details> | ||||
| 				<summary>%i18n:@update-settings%</summary> | ||||
| 				<ui-switch v-model="preventUpdate"> | ||||
| 					%i18n:@prevent-update% | ||||
| 					<span slot="desc">%i18n:@prevent-update-desc%</span> | ||||
| 				<ui-switch v-model="enableSounds"> | ||||
| 					%i18n:@enable-sounds% | ||||
| 					<span slot="desc">%i18n:@enable-sounds-desc%</span> | ||||
| 				</ui-switch> | ||||
| 			</details> | ||||
| 		</section> | ||||
| 				<label>%i18n:@volume%</label> | ||||
| 				<input type="range" | ||||
| 					v-model="soundVolume" | ||||
| 					:disabled="!enableSounds" | ||||
| 					max="1" | ||||
| 					step="0.1" | ||||
| 				/> | ||||
| 				<ui-button @click="soundTest">%fa:volume-up% %i18n:@test%</ui-button> | ||||
| 			</section> | ||||
| 		</ui-card> | ||||
|  | ||||
| 		<section class="other" v-show="page == 'other'"> | ||||
| 			<h1>%i18n:@advanced-settings%</h1> | ||||
| 			<ui-switch v-model="debug"> | ||||
| 				%i18n:@debug-mode% | ||||
| 				<span slot="desc">%i18n:@debug-mode-desc%</span> | ||||
| 			</ui-switch> | ||||
| 			<ui-switch v-model="enableExperimentalFeatures"> | ||||
| 				%i18n:@experimental% | ||||
| 				<span slot="desc">%i18n:@experimental-desc%</span> | ||||
| 			</ui-switch> | ||||
| 		</section> | ||||
| 		<ui-card class="web" v-show="page == 'web'"> | ||||
| 			<div slot="title">%fa:language% %i18n:@language%</div> | ||||
| 			<section class="fit-top"> | ||||
| 				<ui-select v-model="lang" placeholder="%i18n:@pick-language%"> | ||||
| 					<optgroup label="%i18n:@recommended%"> | ||||
| 						<option value="">%i18n:@auto%</option> | ||||
| 					</optgroup> | ||||
|  | ||||
| 					<optgroup label="%i18n:@specify-language%"> | ||||
| 						<option v-for="x in langs" :value="x[0]" :key="x[0]">{{ x[1] }}</option> | ||||
| 					</optgroup> | ||||
| 				</ui-select> | ||||
| 				<div class="none ui info"> | ||||
| 					<p>%fa:info-circle%%i18n:@language-desc%</p> | ||||
| 				</div> | ||||
| 			</section> | ||||
| 		</ui-card> | ||||
|  | ||||
| 		<ui-card class="web" v-show="page == 'web'"> | ||||
| 			<div slot="title">%fa:trash-alt R% %i18n:@cache%</div> | ||||
| 			<section> | ||||
| 				<ui-button @click="clean">%i18n:@clean-cache%</ui-button> | ||||
| 				<div class="none ui info warn"> | ||||
| 					<p>%fa:exclamation-triangle%%i18n:@cache-warn%</p> | ||||
| 				</div> | ||||
| 			</section> | ||||
| 		</ui-card> | ||||
|  | ||||
| 		<ui-card class="notification" v-show="page == 'notification'"> | ||||
| 			<div slot="title">%fa:bell R% %i18n:@notification%</div> | ||||
| 			<section> | ||||
| 				<ui-switch v-model="$store.state.i.settings.autoWatch" @change="onChangeAutoWatch"> | ||||
| 					%i18n:@auto-watch% | ||||
| 					<span slot="desc">%i18n:@auto-watch-desc%</span> | ||||
| 				</ui-switch> | ||||
| 				<section> | ||||
| 					<ui-button @click="readAllUnreadNotes">%i18n:@mark-as-read-all-unread-notes%</ui-button> | ||||
| 				</section> | ||||
| 			</section> | ||||
| 		</ui-card> | ||||
|  | ||||
| 		<ui-card class="drive" v-show="page == 'drive'"> | ||||
| 			<div slot="title">%fa:cloud% %i18n:@drive%</div> | ||||
| 			<section> | ||||
| 				<x-drive/> | ||||
| 			</section> | ||||
| 		</ui-card> | ||||
|  | ||||
| 		<ui-card class="hashtags" v-show="page == 'hashtags'"> | ||||
| 			<div slot="title">%fa:hashtag% %i18n:@tags%</div> | ||||
| 			<section> | ||||
| 				<x-tags/> | ||||
| 			</section> | ||||
| 		</ui-card> | ||||
|  | ||||
| 		<ui-card class="mute" v-show="page == 'mute'"> | ||||
| 			<div slot="title">%fa:ban% %i18n:@mute%</div> | ||||
| 			<section> | ||||
| 				<x-mute/> | ||||
| 			</section> | ||||
| 		</ui-card> | ||||
|  | ||||
| 		<ui-card class="apps" v-show="page == 'apps'"> | ||||
| 			<div slot="title">%fa:puzzle-piece% %i18n:@apps%</div> | ||||
| 			<section> | ||||
| 				<x-apps/> | ||||
| 			</section> | ||||
| 		</ui-card> | ||||
|  | ||||
| 		<ui-card class="password" v-show="page == 'security'"> | ||||
| 			<div slot="title">%fa:unlock-alt% %i18n:@password%</div> | ||||
| 			<section> | ||||
| 				<x-password/> | ||||
| 			</section> | ||||
| 		</ui-card> | ||||
|  | ||||
| 		<ui-card class="2fa" v-show="page == 'security'"> | ||||
| 			<div slot="title">%fa:mobile-alt% %i18n:@2fa%</div> | ||||
| 			<section> | ||||
| 				<x-2fa/> | ||||
| 			</section> | ||||
| 		</ui-card> | ||||
|  | ||||
| 		<ui-card class="signin" v-show="page == 'security'"> | ||||
| 			<div slot="title">%fa:sign-in-alt% %i18n:@signin%</div> | ||||
| 			<section> | ||||
| 				<x-signins/> | ||||
| 			</section> | ||||
| 		</ui-card> | ||||
|  | ||||
| 		<ui-card class="api" v-show="page == 'api'"> | ||||
| 			<div slot="title">%fa:key% API</div> | ||||
| 			<section class="fit-top"> | ||||
| 				<x-api/> | ||||
| 			</section> | ||||
| 		</ui-card> | ||||
|  | ||||
| 		<ui-card class="other" v-show="page == 'other'"> | ||||
| 			<div slot="title">%fa:info-circle% %i18n:@about%</div> | ||||
| 			<section> | ||||
| 				<p v-if="meta">%i18n:@operator%: <i><a :href="meta.maintainer.url" target="_blank">{{ meta.maintainer.name }}</a></i></p> | ||||
| 			</section> | ||||
| 		</ui-card> | ||||
|  | ||||
| 		<ui-card class="other" v-show="page == 'other'"> | ||||
| 			<div slot="title">%fa:sync-alt% %i18n:@update%</div> | ||||
| 			<section> | ||||
| 				<p> | ||||
| 					<span>%i18n:@version% <i>{{ version }}</i></span> | ||||
| 					<template v-if="latestVersion !== undefined"> | ||||
| 						<br> | ||||
| 						<span>%i18n:@latest-version% <i>{{ latestVersion ? latestVersion : version }}</i></span> | ||||
| 					</template> | ||||
| 				</p> | ||||
| 				<button class="ui button block" @click="checkForUpdate" :disabled="checkingForUpdate"> | ||||
| 					<template v-if="checkingForUpdate">%i18n:@update-checking%<mk-ellipsis/></template> | ||||
| 					<template v-else>%i18n:@do-update%</template> | ||||
| 				</button> | ||||
| 				<details> | ||||
| 					<summary>%i18n:@update-settings%</summary> | ||||
| 					<ui-switch v-model="preventUpdate"> | ||||
| 						%i18n:@prevent-update% | ||||
| 						<span slot="desc">%i18n:@prevent-update-desc%</span> | ||||
| 					</ui-switch> | ||||
| 				</details> | ||||
| 			</section> | ||||
| 		</ui-card> | ||||
|  | ||||
| 		<ui-card class="other" v-show="page == 'other'"> | ||||
| 			<div slot="title">%fa:cogs% %i18n:@advanced-settings%</div> | ||||
| 			<section> | ||||
| 				<ui-switch v-model="debug"> | ||||
| 					%i18n:@debug-mode% | ||||
| 					<span slot="desc">%i18n:@debug-mode-desc%</span> | ||||
| 				</ui-switch> | ||||
| 				<ui-switch v-model="enableExperimentalFeatures"> | ||||
| 					%i18n:@experimental% | ||||
| 					<span slot="desc">%i18n:@experimental-desc%</span> | ||||
| 				</ui-switch> | ||||
| 			</section> | ||||
| 		</ui-card> | ||||
| 	</div> | ||||
| </div> | ||||
| </template> | ||||
|  | ||||
| <script lang="ts"> | ||||
| import Vue from 'vue'; | ||||
| import XProfile from './settings.profile.vue'; | ||||
| import XMute from './settings.mute.vue'; | ||||
| import XPassword from './settings.password.vue'; | ||||
| import X2fa from './settings.2fa.vue'; | ||||
| @@ -253,7 +308,6 @@ import checkForUpdate from '../../../common/scripts/check-for-update'; | ||||
|  | ||||
| export default Vue.extend({ | ||||
| 	components: { | ||||
| 		XProfile, | ||||
| 		XMute, | ||||
| 		XPassword, | ||||
| 		X2fa, | ||||
| @@ -295,6 +349,11 @@ export default Vue.extend({ | ||||
| 			set(value) { this.$store.commit('device/set', { key: 'autoPopout', value }); } | ||||
| 		}, | ||||
|  | ||||
| 		deckNav: { | ||||
| 			get() { return this.$store.state.settings.deckNav; }, | ||||
| 			set(value) { this.$store.commit('settings/set', { key: 'deckNav', value }); } | ||||
| 		}, | ||||
|  | ||||
| 		darkmode: { | ||||
| 			get() { return this.$store.state.device.darkmode; }, | ||||
| 			set(value) { this.$store.commit('device/set', { key: 'darkmode', value }); } | ||||
| @@ -305,6 +364,16 @@ export default Vue.extend({ | ||||
| 			set(value) { this.$store.commit('device/set', { key: 'navbar', value }); } | ||||
| 		}, | ||||
|  | ||||
| 		deckColumnAlign: { | ||||
| 			get() { return this.$store.state.device.deckColumnAlign; }, | ||||
| 			set(value) { this.$store.commit('device/set', { key: 'deckColumnAlign', value }); } | ||||
| 		}, | ||||
|  | ||||
| 		deckDefault: { | ||||
| 			get() { return this.$store.state.device.deckDefault; }, | ||||
| 			set(value) { this.$store.commit('device/set', { key: 'deckDefault', value }); } | ||||
| 		}, | ||||
|  | ||||
| 		enableSounds: { | ||||
| 			get() { return this.$store.state.device.enableSounds; }, | ||||
| 			set(value) { this.$store.commit('device/set', { key: 'enableSounds', value }); } | ||||
| @@ -438,11 +507,6 @@ export default Vue.extend({ | ||||
| 		disableAnimatedMfm: { | ||||
| 			get() { return this.$store.state.settings.disableAnimatedMfm; }, | ||||
| 			set(value) { this.$store.dispatch('settings/set', { key: 'disableAnimatedMfm', value }); } | ||||
| 		}, | ||||
|  | ||||
| 		disableViaMobile: { | ||||
| 			get() { return this.$store.state.settings.disableViaMobile; }, | ||||
| 			set(value) { this.$store.dispatch('settings/set', { key: 'disableViaMobile', value }); } | ||||
| 		} | ||||
| 	}, | ||||
| 	created() { | ||||
| @@ -451,6 +515,9 @@ export default Vue.extend({ | ||||
| 		}); | ||||
| 	}, | ||||
| 	methods: { | ||||
| 		readAllUnreadNotes() { | ||||
| 			(this as any).api('i/read_all_unread_notes'); | ||||
| 		}, | ||||
| 		customizeHome() { | ||||
| 			this.$router.push('/i/customize-home'); | ||||
| 			this.$emit('done'); | ||||
| @@ -520,7 +587,8 @@ export default Vue.extend({ | ||||
| 		height 100% | ||||
| 		padding 16px 0 0 0 | ||||
| 		overflow auto | ||||
| 		border-right solid 1px var(--faceDivider) | ||||
| 		box-shadow var(--shadowRight) | ||||
| 		z-index 1 | ||||
|  | ||||
| 		> p | ||||
| 			display block | ||||
| @@ -546,34 +614,10 @@ export default Vue.extend({ | ||||
| 		height 100% | ||||
| 		flex auto | ||||
| 		overflow auto | ||||
| 		background var(--bg) | ||||
|  | ||||
| 		> section | ||||
| 			margin 32px | ||||
| 			color var(--text) | ||||
|  | ||||
| 			> h1 | ||||
| 				margin 0 0 1em 0 | ||||
| 				padding 0 0 8px 0 | ||||
| 				font-size 1em | ||||
| 				border-bottom solid 1px var(--faceDivider) | ||||
|  | ||||
| 			&, >>> * | ||||
| 				.ui.button.block | ||||
| 					margin 16px 0 | ||||
|  | ||||
| 				> section | ||||
| 					margin 32px 0 | ||||
|  | ||||
| 					> h2 | ||||
| 						margin 0 0 1em 0 | ||||
| 						padding 0 0 8px 0 | ||||
| 						font-size 1em | ||||
| 						color var(--text) | ||||
| 						border-bottom solid 1px var(--faceDivider) | ||||
|  | ||||
| 		> .web | ||||
| 			> .div | ||||
| 				border-bottom solid 1px var(--faceDivider) | ||||
| 				margin 16px 0 | ||||
|  | ||||
| </style> | ||||
|   | ||||
| @@ -5,7 +5,7 @@ | ||||
| 		<span v-if="note.deletedAt" style="opacity: 0.5">%i18n:@deleted%</span> | ||||
| 		<a class="reply" v-if="note.replyId">%fa:reply%</a> | ||||
| 		<misskey-flavored-markdown v-if="note.text" :text="note.text" :i="$store.state.i"/> | ||||
| 		<a class="rp" v-if="note.renoteId" :href="`/notes/${note.renoteId}`">RP: ...</a> | ||||
| 		<a class="rp" v-if="note.renoteId" :href="`/notes/${note.renoteId}`">RN: ...</a> | ||||
| 	</div> | ||||
| 	<details v-if="note.files.length > 0"> | ||||
| 		<summary>({{ '%i18n:@media-count%'.replace('{}', note.files.length) }})</summary> | ||||
|   | ||||
| @@ -2,18 +2,22 @@ | ||||
| <div class="nav"> | ||||
| 	<ul> | ||||
| 		<template v-if="$store.getters.isSignedIn"> | ||||
| 			<li class="home" :class="{ active: $route.name == 'index' }" @click="goToTop"> | ||||
| 				<router-link to="/"> | ||||
| 					%fa:home% | ||||
| 					<p>%i18n:@home%</p> | ||||
| 				</router-link> | ||||
| 			</li> | ||||
| 			<li class="deck" :class="{ active: $route.name == 'deck' }" @click="goToTop"> | ||||
| 				<router-link to="/deck"> | ||||
| 					%fa:columns% | ||||
| 					<p>%i18n:@deck%</p> | ||||
| 				</router-link> | ||||
| 			</li> | ||||
| 			<template v-if="$store.state.device.deckDefault"> | ||||
| 				<li class="deck" :class="{ active: $route.name == 'deck' || $route.name == 'index' }" @click="goToTop"> | ||||
| 					<router-link to="/">%fa:columns%<p>%i18n:@deck%</p></router-link> | ||||
| 				</li> | ||||
| 				<li class="home" :class="{ active: $route.name == 'home' }" @click="goToTop"> | ||||
| 					<router-link to="/home">%fa:home%<p>%i18n:@home%</p></router-link> | ||||
| 				</li> | ||||
| 			</template> | ||||
| 			<template v-else> | ||||
| 				<li class="home" :class="{ active: $route.name == 'home' || $route.name == 'index' }" @click="goToTop"> | ||||
| 					<router-link to="/">%fa:home%<p>%i18n:@home%</p></router-link> | ||||
| 				</li> | ||||
| 				<li class="deck" :class="{ active: $route.name == 'deck' }" @click="goToTop"> | ||||
| 					<router-link to="/deck">%fa:columns%<p>%i18n:@deck%</p></router-link> | ||||
| 				</li> | ||||
| 			</template> | ||||
| 			<li class="messaging"> | ||||
| 				<a @click="messaging"> | ||||
| 					%fa:comments% | ||||
|   | ||||
| @@ -6,12 +6,22 @@ | ||||
| 		</div> | ||||
|  | ||||
| 		<div class="nav" v-if="$store.getters.isSignedIn"> | ||||
| 			<div class="home" :class="{ active: $route.name == 'index' }" @click="goToTop"> | ||||
| 				<router-link to="/">%fa:home%</router-link> | ||||
| 			</div> | ||||
| 			<div class="deck" :class="{ active: $route.name == 'deck' }" @click="goToTop"> | ||||
| 				<router-link to="/deck">%fa:columns%</router-link> | ||||
| 			</div> | ||||
| 			<template v-if="$store.state.device.deckDefault"> | ||||
| 				<div class="deck" :class="{ active: $route.name == 'deck' || $route.name == 'index' }" @click="goToTop"> | ||||
| 					<router-link to="/">%fa:columns%</router-link> | ||||
| 				</div> | ||||
| 				<div class="home" :class="{ active: $route.name == 'home' }" @click="goToTop"> | ||||
| 					<router-link to="/home">%fa:home%</router-link> | ||||
| 				</div> | ||||
| 			</template> | ||||
| 			<template v-else> | ||||
| 				<div class="home" :class="{ active: $route.name == 'home' || $route.name == 'index' }" @click="goToTop"> | ||||
| 					<router-link to="/">%fa:home%</router-link> | ||||
| 				</div> | ||||
| 				<div class="deck" :class="{ active: $route.name == 'deck' }" @click="goToTop"> | ||||
| 					<router-link to="/deck">%fa:columns%</router-link> | ||||
| 				</div> | ||||
| 			</template> | ||||
| 			<div class="messaging"> | ||||
| 				<a @click="messaging">%fa:comments%<template v-if="hasUnreadMessagingMessage">%fa:circle%</template></a> | ||||
| 			</div> | ||||
|   | ||||
| @@ -2,8 +2,8 @@ | ||||
| <div class="mk-ui" v-hotkey.global="keymap"> | ||||
| 	<div class="bg" v-if="$store.getters.isSignedIn && $store.state.i.wallpaperUrl" :style="style"></div> | ||||
| 	<x-header class="header" v-if="navbar == 'top'" v-show="!zenMode" ref="header"/> | ||||
| 	<x-sidebar class="sidebar" v-if="navbar != 'top'" ref="sidebar"/> | ||||
| 	<div class="content" :class="[{ sidebar: navbar != 'top' }, navbar]"> | ||||
| 	<x-sidebar class="sidebar" v-if="navbar != 'top'" v-show="!zenMode" ref="sidebar"/> | ||||
| 	<div class="content" :class="[{ sidebar: navbar != 'top', zen: zenMode }, navbar]"> | ||||
| 		<slot></slot> | ||||
| 	</div> | ||||
| 	<mk-stream-indicator v-if="$store.getters.isSignedIn"/> | ||||
| @@ -73,7 +73,9 @@ export default Vue.extend({ | ||||
| 		toggleZenMode() { | ||||
| 			this.zenMode = !this.zenMode; | ||||
| 			this.$nextTick(() => { | ||||
| 				this.$store.commit('setUiHeaderHeight', this.$refs.header.$el.offsetHeight); | ||||
| 				if (this.$refs.header) { | ||||
| 					this.$store.commit('setUiHeaderHeight', this.$refs.header.$el.offsetHeight); | ||||
| 				} | ||||
| 			}); | ||||
| 		} | ||||
| 	} | ||||
| @@ -102,4 +104,7 @@ export default Vue.extend({ | ||||
| 	> .content.sidebar.right | ||||
| 		padding-right 68px | ||||
|  | ||||
| 	> .content.zen | ||||
| 		padding 0 !important | ||||
|  | ||||
| </style> | ||||
|   | ||||
| @@ -1,14 +1,14 @@ | ||||
| <template> | ||||
| <x-widgets-column v-if="column.type == 'widgets'" :column="column" :is-stacked="isStacked"/> | ||||
| <x-notifications-column v-else-if="column.type == 'notifications'" :column="column" :is-stacked="isStacked"/> | ||||
| <x-tl-column v-else-if="column.type == 'home'" :column="column" :is-stacked="isStacked"/> | ||||
| <x-tl-column v-else-if="column.type == 'local'" :column="column" :is-stacked="isStacked"/> | ||||
| <x-tl-column v-else-if="column.type == 'hybrid'" :column="column" :is-stacked="isStacked"/> | ||||
| <x-tl-column v-else-if="column.type == 'global'" :column="column" :is-stacked="isStacked"/> | ||||
| <x-tl-column v-else-if="column.type == 'list'" :column="column" :is-stacked="isStacked"/> | ||||
| <x-tl-column v-else-if="column.type == 'hashtag'" :column="column" :is-stacked="isStacked"/> | ||||
| <x-mentions-column v-else-if="column.type == 'mentions'" :column="column" :is-stacked="isStacked"/> | ||||
| <x-direct-column v-else-if="column.type == 'direct'" :column="column" :is-stacked="isStacked"/> | ||||
| <x-widgets-column v-if="column.type == 'widgets'" :column="column" :is-stacked="isStacked" v-on="$listeners"/> | ||||
| <x-notifications-column v-else-if="column.type == 'notifications'" :column="column" :is-stacked="isStacked" v-on="$listeners"/> | ||||
| <x-tl-column v-else-if="column.type == 'home'" :column="column" :is-stacked="isStacked" v-on="$listeners"/> | ||||
| <x-tl-column v-else-if="column.type == 'local'" :column="column" :is-stacked="isStacked" v-on="$listeners"/> | ||||
| <x-tl-column v-else-if="column.type == 'hybrid'" :column="column" :is-stacked="isStacked" v-on="$listeners"/> | ||||
| <x-tl-column v-else-if="column.type == 'global'" :column="column" :is-stacked="isStacked" v-on="$listeners"/> | ||||
| <x-tl-column v-else-if="column.type == 'list'" :column="column" :is-stacked="isStacked" v-on="$listeners"/> | ||||
| <x-tl-column v-else-if="column.type == 'hashtag'" :column="column" :is-stacked="isStacked" v-on="$listeners"/> | ||||
| <x-mentions-column v-else-if="column.type == 'mentions'" :column="column" :is-stacked="isStacked" v-on="$listeners"/> | ||||
| <x-direct-column v-else-if="column.type == 'direct'" :column="column" :is-stacked="isStacked" v-on="$listeners"/> | ||||
| </template> | ||||
|  | ||||
| <script lang="ts"> | ||||
| @@ -38,6 +38,12 @@ export default Vue.extend({ | ||||
| 			required: false, | ||||
| 			default: false | ||||
| 		} | ||||
| 	}, | ||||
|  | ||||
| 	methods: { | ||||
| 		focus() { | ||||
| 			this.$children[0].focus(); | ||||
| 		} | ||||
| 	} | ||||
| }); | ||||
| </script> | ||||
|   | ||||
| @@ -1,9 +1,9 @@ | ||||
| <template> | ||||
| <div class="dnpfarvgbnfmyzbdquhhzyxcmstpdqzs" :class="{ naked, narrow, active, isStacked, draghover, dragging, dropready }" | ||||
| 		@dragover.prevent.stop="onDragover" | ||||
| 		@dragenter.prevent="onDragenter" | ||||
| 		@dragleave="onDragleave" | ||||
| 		@drop.prevent.stop="onDrop"> | ||||
| 		@drop.prevent.stop="onDrop" | ||||
| 		v-hotkey="keymap"> | ||||
| 	<header :class="{ indicate: count > 0 }" | ||||
| 			draggable="true" | ||||
| 			@click="goTop" | ||||
| @@ -16,7 +16,8 @@ | ||||
| 		</button> | ||||
| 		<slot name="header"></slot> | ||||
| 		<span class="count" v-if="count > 0">({{ count }})</span> | ||||
| 		<button class="menu" ref="menu" @click.stop="showMenu">%fa:caret-down%</button> | ||||
| 		<button v-if="!isTemporaryColumn" class="menu" ref="menu" @click.stop="showMenu">%fa:caret-down%</button> | ||||
| 		<button v-else class="close" @click.stop="close">%fa:times%</button> | ||||
| 	</header> | ||||
| 	<div ref="body" v-show="active"> | ||||
| 		<slot></slot> | ||||
| @@ -34,11 +35,13 @@ export default Vue.extend({ | ||||
| 	props: { | ||||
| 		column: { | ||||
| 			type: Object, | ||||
| 			required: true | ||||
| 			required: false, | ||||
| 			default: null | ||||
| 		}, | ||||
| 		isStacked: { | ||||
| 			type: Boolean, | ||||
| 			required: true | ||||
| 			required: false, | ||||
| 			default: false | ||||
| 		}, | ||||
| 		name: { | ||||
| 			type: String, | ||||
| @@ -61,6 +64,21 @@ export default Vue.extend({ | ||||
| 		} | ||||
| 	}, | ||||
|  | ||||
| 	computed: { | ||||
| 		isTemporaryColumn(): boolean { | ||||
| 			return this.column == null; | ||||
| 		}, | ||||
|  | ||||
| 		keymap(): any { | ||||
| 			return { | ||||
| 				'shift+up': () => this.$parent.$emit('parentFocus', 'up'), | ||||
| 				'shift+down': () => this.$parent.$emit('parentFocus', 'down'), | ||||
| 				'shift+left': () => this.$parent.$emit('parentFocus', 'left'), | ||||
| 				'shift+right': () => this.$parent.$emit('parentFocus', 'right'), | ||||
| 			}; | ||||
| 		} | ||||
| 	}, | ||||
|  | ||||
| 	inject: { | ||||
| 		getColumnVm: { from: 'getColumnVm' } | ||||
| 	}, | ||||
| @@ -96,14 +114,20 @@ export default Vue.extend({ | ||||
|  | ||||
| 	mounted() { | ||||
| 		this.$refs.body.addEventListener('scroll', this.onScroll, { passive: true }); | ||||
| 		this.$root.$on('deck.column.dragStart', this.onOtherDragStart); | ||||
| 		this.$root.$on('deck.column.dragEnd', this.onOtherDragEnd); | ||||
|  | ||||
| 		if (!this.isTemporaryColumn) { | ||||
| 			this.$root.$on('deck.column.dragStart', this.onOtherDragStart); | ||||
| 			this.$root.$on('deck.column.dragEnd', this.onOtherDragEnd); | ||||
| 		} | ||||
| 	}, | ||||
|  | ||||
| 	beforeDestroy() { | ||||
| 		this.$refs.body.removeEventListener('scroll', this.onScroll); | ||||
| 		this.$root.$off('deck.column.dragStart', this.onOtherDragStart); | ||||
| 		this.$root.$off('deck.column.dragEnd', this.onOtherDragEnd); | ||||
|  | ||||
| 		if (!this.isTemporaryColumn) { | ||||
| 			this.$root.$off('deck.column.dragStart', this.onOtherDragStart); | ||||
| 			this.$root.$off('deck.column.dragEnd', this.onOtherDragEnd); | ||||
| 		} | ||||
| 	}, | ||||
|  | ||||
| 	methods: { | ||||
| @@ -203,6 +227,7 @@ export default Vue.extend({ | ||||
| 		}, | ||||
|  | ||||
| 		onContextmenu(e) { | ||||
| 			if (this.isTemporaryColumn) return; | ||||
| 			contextmenu((this as any).os)(e, this.getMenu()); | ||||
| 		}, | ||||
|  | ||||
| @@ -214,6 +239,13 @@ export default Vue.extend({ | ||||
| 			}); | ||||
| 		}, | ||||
|  | ||||
| 		close() { | ||||
| 			this.$store.commit('device/set', { | ||||
| 				key: 'deckTemporaryColumn', | ||||
| 				value: null | ||||
| 			}); | ||||
| 		}, | ||||
|  | ||||
| 		goTop() { | ||||
| 			this.$refs.body.scrollTo({ | ||||
| 				top: 0, | ||||
| @@ -222,6 +254,12 @@ export default Vue.extend({ | ||||
| 		}, | ||||
|  | ||||
| 		onDragstart(e) { | ||||
| 			// テンポラリカラムはドラッグさせない | ||||
| 			if (this.isTemporaryColumn) { | ||||
| 				e.preventDefault(); | ||||
| 				return; | ||||
| 			} | ||||
|  | ||||
| 			e.dataTransfer.effectAllowed = 'move'; | ||||
| 			e.dataTransfer.setData('mk-deck-column', this.column.id); | ||||
| 			this.dragging = true; | ||||
| @@ -232,6 +270,12 @@ export default Vue.extend({ | ||||
| 		}, | ||||
|  | ||||
| 		onDragover(e) { | ||||
| 			// テンポラリカラムにはドロップさせない | ||||
| 			if (this.isTemporaryColumn) { | ||||
| 				e.dataTransfer.dropEffect = 'none'; | ||||
| 				return; | ||||
| 			} | ||||
|  | ||||
| 			// 自分自身がドラッグされている場合 | ||||
| 			if (this.dragging) { | ||||
| 				// 自分自身にはドロップさせない | ||||
| @@ -242,9 +286,7 @@ export default Vue.extend({ | ||||
| 			const isDeckColumn = e.dataTransfer.types[0] == 'mk-deck-column'; | ||||
|  | ||||
| 			e.dataTransfer.dropEffect = isDeckColumn ? 'move' : 'none'; | ||||
| 		}, | ||||
|  | ||||
| 		onDragenter() { | ||||
| 			if (!this.dragging) this.draghover = true; | ||||
| 		}, | ||||
|  | ||||
| @@ -349,6 +391,7 @@ export default Vue.extend({ | ||||
|  | ||||
| 		> .toggleActive | ||||
| 		> .menu | ||||
| 		> .close | ||||
| 			padding 0 | ||||
| 			width $header-height | ||||
| 			line-height $header-height | ||||
| @@ -365,6 +408,7 @@ export default Vue.extend({ | ||||
| 			margin-left -16px | ||||
|  | ||||
| 		> .menu | ||||
| 		> .close | ||||
| 			margin-left auto | ||||
| 			margin-right -16px | ||||
|  | ||||
|   | ||||
| @@ -34,5 +34,11 @@ export default Vue.extend({ | ||||
| 			return '%i18n:common.deck.direct%'; | ||||
| 		} | ||||
| 	}, | ||||
|  | ||||
| 	methods: { | ||||
| 		focus() { | ||||
| 			this.$refs.tl.focus(); | ||||
| 		} | ||||
| 	} | ||||
| }); | ||||
| </script> | ||||
|   | ||||
| @@ -58,6 +58,7 @@ export default Vue.extend({ | ||||
| 				}, rej); | ||||
| 			})); | ||||
| 		}, | ||||
|  | ||||
| 		more() { | ||||
| 			this.moreFetching = true; | ||||
|  | ||||
| @@ -82,11 +83,16 @@ export default Vue.extend({ | ||||
|  | ||||
| 			return promise; | ||||
| 		}, | ||||
|  | ||||
| 		onNote(note) { | ||||
| 			// Prepend a note | ||||
| 			if (note.visibility == 'specified') { | ||||
| 				(this.$refs.timeline as any).prepend(note); | ||||
| 			} | ||||
| 		}, | ||||
|  | ||||
| 		focus() { | ||||
| 			this.$refs.timeline.focus(); | ||||
| 		} | ||||
| 	} | ||||
| }); | ||||
|   | ||||
							
								
								
									
										112
									
								
								src/client/app/desktop/views/pages/deck/deck.hashtag-column.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								src/client/app/desktop/views/pages/deck/deck.hashtag-column.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,112 @@ | ||||
| <template> | ||||
| <x-column> | ||||
| 	<span slot="header"> | ||||
| 		%fa:hashtag%<span>{{ tag }}</span> | ||||
| 	</span> | ||||
|  | ||||
| 	<div class="xroyrflcmhhtmlwmyiwpfqiirqokfueb"> | ||||
| 		<div ref="chart" class="chart"></div> | ||||
| 		<x-hashtag-tl :tag-tl="tagTl" class="tl"/> | ||||
| 	</div> | ||||
| </x-column> | ||||
| </template> | ||||
|  | ||||
| <script lang="ts"> | ||||
| import Vue from 'vue'; | ||||
| import XColumn from './deck.column.vue'; | ||||
| import XHashtagTl from './deck.hashtag-tl.vue'; | ||||
| import * as ApexCharts from 'apexcharts'; | ||||
|  | ||||
| export default Vue.extend({ | ||||
| 	components: { | ||||
| 		XColumn, | ||||
| 		XHashtagTl | ||||
| 	}, | ||||
|  | ||||
| 	props: { | ||||
| 		tag: { | ||||
| 			type: String, | ||||
| 			required: true | ||||
| 		} | ||||
| 	}, | ||||
|  | ||||
| 	computed: { | ||||
| 		tagTl(): any { | ||||
| 			return { | ||||
| 				query: [[this.tag]] | ||||
| 			}; | ||||
| 		} | ||||
| 	}, | ||||
|  | ||||
| 	mounted() { | ||||
| 		(this as any).api('charts/hashtag', { | ||||
| 			tag: this.tag, | ||||
| 			span: 'hour', | ||||
| 			limit: 24 | ||||
| 		}).then(stats => { | ||||
| 			const local = []; | ||||
| 			const remote = []; | ||||
|  | ||||
| 			const now = new Date(); | ||||
| 			const y = now.getFullYear(); | ||||
| 			const m = now.getMonth(); | ||||
| 			const d = now.getDate(); | ||||
| 			const h = now.getHours(); | ||||
|  | ||||
| 			for (let i = 0; i < 24; i++) { | ||||
| 				const x = new Date(y, m, d, h - i); | ||||
| 				local.push([x, stats.local.count[i]]); | ||||
| 				remote.push([x, stats.remote.count[i]]); | ||||
| 			} | ||||
|  | ||||
| 			const chart = new ApexCharts(this.$refs.chart, { | ||||
| 				chart: { | ||||
| 					type: 'area', | ||||
| 					height: 70, | ||||
| 					sparkline: { | ||||
| 						enabled: true | ||||
| 					}, | ||||
| 				}, | ||||
| 				grid: { | ||||
| 					clipMarkers: false, | ||||
| 					padding: { | ||||
| 						top: 16, | ||||
| 						right: 16, | ||||
| 						bottom: 16, | ||||
| 						left: 16 | ||||
| 					} | ||||
| 				}, | ||||
| 				stroke: { | ||||
| 					curve: 'straight', | ||||
| 					width: 2 | ||||
| 				}, | ||||
| 				series: [{ | ||||
| 					name: 'Local', | ||||
| 					data: local | ||||
| 				}, { | ||||
| 					name: 'Remote', | ||||
| 					data: remote | ||||
| 				}], | ||||
| 				xaxis: { | ||||
| 					type: 'datetime', | ||||
| 				} | ||||
| 			}); | ||||
|  | ||||
| 			chart.render(); | ||||
| 		}); | ||||
| 	} | ||||
| }); | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| .xroyrflcmhhtmlwmyiwpfqiirqokfueb | ||||
| 	background var(--deckColumnBg) | ||||
|  | ||||
| 	> .chart | ||||
| 		margin-bottom 16px | ||||
| 		background var(--face) | ||||
|  | ||||
| 	> .tl | ||||
| 		background var(--face) | ||||
|  | ||||
| </style> | ||||
| @@ -1,5 +1,5 @@ | ||||
| <template> | ||||
| 	<x-notes ref="timeline" :more="existMore ? more : null" :media-view="mediaView"/> | ||||
| <x-notes ref="timeline" :more="existMore ? more : null" :media-view="mediaView"/> | ||||
| </template> | ||||
|  | ||||
| <script lang="ts"> | ||||
| @@ -47,14 +47,16 @@ export default Vue.extend({ | ||||
|  | ||||
| 	mounted() { | ||||
| 		if (this.connection) this.connection.close(); | ||||
| 		this.connection = (this as any).os.stream.connectToChannel('hashtag', this.tagTl.query); | ||||
| 		this.connection = (this as any).os.stream.connectToChannel('hashtag', { | ||||
| 			q: this.tagTl.query | ||||
| 		}); | ||||
| 		this.connection.on('note', this.onNote); | ||||
|  | ||||
| 		this.fetch(); | ||||
| 	}, | ||||
|  | ||||
| 	beforeDestroy() { | ||||
| 		this.connection.close(); | ||||
| 		this.connection.dispose(); | ||||
| 	}, | ||||
|  | ||||
| 	methods: { | ||||
| @@ -80,6 +82,7 @@ export default Vue.extend({ | ||||
| 				}, rej); | ||||
| 			})); | ||||
| 		}, | ||||
|  | ||||
| 		more() { | ||||
| 			this.moreFetching = true; | ||||
|  | ||||
| @@ -105,11 +108,16 @@ export default Vue.extend({ | ||||
|  | ||||
| 			return promise; | ||||
| 		}, | ||||
|  | ||||
| 		onNote(note) { | ||||
| 			if (this.mediaOnly && note.files.length == 0) return; | ||||
|  | ||||
| 			// Prepend a note | ||||
| 			(this.$refs.timeline as any).prepend(note); | ||||
| 		}, | ||||
|  | ||||
| 		focus() { | ||||
| 			this.$refs.timeline.focus(); | ||||
| 		} | ||||
| 	} | ||||
| }); | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| <template> | ||||
| 	<x-notes ref="timeline" :more="existMore ? more : null" :media-view="mediaView"/> | ||||
| <x-notes ref="timeline" :more="existMore ? more : null" :media-view="mediaView"/> | ||||
| </template> | ||||
|  | ||||
| <script lang="ts"> | ||||
| @@ -84,6 +84,7 @@ export default Vue.extend({ | ||||
| 				}, rej); | ||||
| 			})); | ||||
| 		}, | ||||
|  | ||||
| 		more() { | ||||
| 			this.moreFetching = true; | ||||
|  | ||||
| @@ -109,17 +110,24 @@ export default Vue.extend({ | ||||
|  | ||||
| 			return promise; | ||||
| 		}, | ||||
|  | ||||
| 		onNote(note) { | ||||
| 			if (this.mediaOnly && note.files.length == 0) return; | ||||
|  | ||||
| 			// Prepend a note | ||||
| 			(this.$refs.timeline as any).prepend(note); | ||||
| 		}, | ||||
|  | ||||
| 		onUserAdded() { | ||||
| 			this.fetch(); | ||||
| 		}, | ||||
|  | ||||
| 		onUserRemoved() { | ||||
| 			this.fetch(); | ||||
| 		}, | ||||
|  | ||||
| 		focus() { | ||||
| 			this.$refs.timeline.focus(); | ||||
| 		} | ||||
| 	} | ||||
| }); | ||||
|   | ||||
| @@ -2,7 +2,7 @@ | ||||
| <x-column :name="name" :column="column" :is-stacked="isStacked"> | ||||
| 	<span slot="header">%fa:at%{{ name }}</span> | ||||
|  | ||||
| 	<x-mentions/> | ||||
| 	<x-mentions ref="tl"/> | ||||
| </x-column> | ||||
| </template> | ||||
|  | ||||
| @@ -34,5 +34,11 @@ export default Vue.extend({ | ||||
| 			return '%i18n:common.deck.mentions%'; | ||||
| 		} | ||||
| 	}, | ||||
|  | ||||
| 	methods: { | ||||
| 		focus() { | ||||
| 			this.$refs.tl.focus(); | ||||
| 		} | ||||
| 	} | ||||
| }); | ||||
| </script> | ||||
|   | ||||
| @@ -57,6 +57,7 @@ export default Vue.extend({ | ||||
| 				}, rej); | ||||
| 			})); | ||||
| 		}, | ||||
|  | ||||
| 		more() { | ||||
| 			this.moreFetching = true; | ||||
|  | ||||
| @@ -80,9 +81,14 @@ export default Vue.extend({ | ||||
|  | ||||
| 			return promise; | ||||
| 		}, | ||||
|  | ||||
| 		onNote(note) { | ||||
| 			// Prepend a note | ||||
| 			(this.$refs.timeline as any).prepend(note); | ||||
| 		}, | ||||
|  | ||||
| 		focus() { | ||||
| 			this.$refs.timeline.focus(); | ||||
| 		} | ||||
| 	} | ||||
| }); | ||||
|   | ||||
							
								
								
									
										74
									
								
								src/client/app/desktop/views/pages/deck/deck.note-column.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								src/client/app/desktop/views/pages/deck/deck.note-column.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,74 @@ | ||||
| <template> | ||||
| <x-column> | ||||
| 	<span slot="header"> | ||||
| 		%fa:comment-alt R%<span>{{ title }}</span> | ||||
| 	</span> | ||||
|  | ||||
| 	<div class="rvtscbadixhhbsczoorqoaygovdeecsx" v-if="note"> | ||||
| 		<div class="is-remote" v-if="note.user.host != null"> | ||||
| 			<details> | ||||
| 				<summary>%fa:exclamation-triangle% %i18n:common.is-remote-post%</summary> | ||||
| 				<a :href="note.url || note.uri" target="_blank">%i18n:common.view-on-remote%</a> | ||||
| 			</details> | ||||
| 		</div> | ||||
| 		<x-note :note="note" :detail="true" :mini="true"/> | ||||
| 	</div> | ||||
| </x-column> | ||||
| </template> | ||||
|  | ||||
| <script lang="ts"> | ||||
| import Vue from 'vue'; | ||||
| import XColumn from './deck.column.vue'; | ||||
| import XNotes from './deck.notes.vue'; | ||||
| import XNote from '../../components/note.vue'; | ||||
|  | ||||
| export default Vue.extend({ | ||||
| 	components: { | ||||
| 		XColumn, | ||||
| 		XNotes, | ||||
| 		XNote | ||||
| 	}, | ||||
|  | ||||
| 	props: { | ||||
| 		noteId: { | ||||
| 			type: String, | ||||
| 			required: true | ||||
| 		} | ||||
| 	}, | ||||
|  | ||||
| 	data() { | ||||
| 		return { | ||||
| 			note: null, | ||||
| 			fetching: true | ||||
| 		}; | ||||
| 	}, | ||||
|  | ||||
| 	computed: { | ||||
| 		title(): string { | ||||
| 			return this.note ? Vue.filter('userName')(this.note.user) : ''; | ||||
| 		} | ||||
| 	}, | ||||
|  | ||||
| 	created() { | ||||
| 		(this as any).api('notes/show', { noteId: this.noteId }).then(note => { | ||||
| 			this.note = note; | ||||
| 			this.fetching = false; | ||||
| 		}); | ||||
| 	} | ||||
| }); | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| .rvtscbadixhhbsczoorqoaygovdeecsx | ||||
| 	> .is-remote | ||||
| 		padding 8px 16px | ||||
| 		font-size 12px | ||||
|  | ||||
| 		&.is-remote | ||||
| 			color var(--remoteInfoFg) | ||||
| 			background var(--remoteInfoBg) | ||||
|  | ||||
| 		> a | ||||
| 			font-weight bold | ||||
|  | ||||
| </style> | ||||
| @@ -1,71 +0,0 @@ | ||||
| <template> | ||||
| <div class="fnlfosztlhtptnongximhlbykxblytcq"> | ||||
| 	<mk-avatar class="avatar" :user="note.user"/> | ||||
| 	<div class="main"> | ||||
| 		<mk-note-header class="header" :note="note" :mini="true"/> | ||||
| 		<div class="body"> | ||||
| 			<mk-sub-note-content class="text" :note="note"/> | ||||
| 		</div> | ||||
| 	</div> | ||||
| </div> | ||||
| </template> | ||||
|  | ||||
| <script lang="ts"> | ||||
| import Vue from 'vue'; | ||||
|  | ||||
| export default Vue.extend({ | ||||
| 	props: { | ||||
| 		note: { | ||||
| 			type: Object, | ||||
| 			required: true | ||||
| 		}, | ||||
| 		// TODO | ||||
| 		truncate: { | ||||
| 			type: Boolean, | ||||
| 			default: true | ||||
| 		} | ||||
| 	} | ||||
| }); | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| .fnlfosztlhtptnongximhlbykxblytcq | ||||
| 	display flex | ||||
| 	padding 16px | ||||
| 	font-size 10px | ||||
| 	background var(--subNoteBg) | ||||
|  | ||||
| 	&.smart | ||||
| 		> .main | ||||
| 			width 100% | ||||
|  | ||||
| 			> header | ||||
| 				align-items center | ||||
|  | ||||
| 	> .avatar | ||||
| 		flex-shrink 0 | ||||
| 		display block | ||||
| 		margin 0 8px 0 0 | ||||
| 		width 38px | ||||
| 		height 38px | ||||
| 		border-radius 8px | ||||
|  | ||||
| 	> .main | ||||
| 		flex 1 | ||||
| 		min-width 0 | ||||
|  | ||||
| 		> .header | ||||
| 			margin-bottom 2px | ||||
|  | ||||
| 		> .body | ||||
|  | ||||
| 			> .text | ||||
| 				margin 0 | ||||
| 				padding 0 | ||||
| 				color var(--subNoteText) | ||||
|  | ||||
| 				pre | ||||
| 					max-height 120px | ||||
| 					font-size 80% | ||||
|  | ||||
| </style> | ||||
| @@ -1,323 +0,0 @@ | ||||
| <template> | ||||
| <div | ||||
| 	v-if="!mediaView" | ||||
| 	v-show="appearNote.deletedAt == null" | ||||
| 	:tabindex="appearNote.deletedAt == null ? '-1' : null" | ||||
| 	class="zyjjkidcqjnlegkqebitfviomuqmseqk" | ||||
| 	:class="{ renote: isRenote }" | ||||
| 	v-hotkey="keymap" | ||||
| 	:title="title" | ||||
| > | ||||
| 	<div class="reply-to" v-if="appearNote.reply && (!$store.getters.isSignedIn || $store.state.settings.showReplyTarget)"> | ||||
| 		<x-sub :note="appearNote.reply"/> | ||||
| 	</div> | ||||
| 	<div class="renote" v-if="isRenote"> | ||||
| 		<mk-avatar class="avatar" :user="note.user"/> | ||||
| 		%fa:retweet% | ||||
| 		<span>{{ '%i18n:@reposted-by%'.substr(0, '%i18n:@reposted-by%'.indexOf('{')) }}</span> | ||||
| 		<router-link class="name" :to="note.user | userPage">{{ note.user | userName }}</router-link> | ||||
| 		<span>{{ '%i18n:@reposted-by%'.substr('%i18n:@reposted-by%'.indexOf('}') + 1) }}</span> | ||||
| 		<mk-time :time="note.createdAt"/> | ||||
| 	</div> | ||||
| 	<article> | ||||
| 		<mk-avatar class="avatar" :user="appearNote.user"/> | ||||
| 		<div class="main"> | ||||
| 			<mk-note-header class="header" :note="appearNote" :mini="true"/> | ||||
| 			<div class="body"> | ||||
| 				<p v-if="appearNote.cw != null" class="cw"> | ||||
| 					<span class="text" v-if="appearNote.cw != ''">{{ appearNote.cw }}</span> | ||||
| 					<mk-cw-button v-model="showContent"/> | ||||
| 				</p> | ||||
| 				<div class="content" v-show="appearNote.cw == null || showContent"> | ||||
| 					<div class="text"> | ||||
| 						<span v-if="appearNote.isHidden" style="opacity: 0.5">(%i18n:@private%)</span> | ||||
| 						<a class="reply" v-if="appearNote.reply">%fa:reply%</a> | ||||
| 						<misskey-flavored-markdown v-if="appearNote.text" :text="appearNote.text" :i="$store.state.i"/> | ||||
| 						<a class="rp" v-if="appearNote.renote != null">RP:</a> | ||||
| 					</div> | ||||
| 					<div class="files" v-if="appearNote.files.length > 0"> | ||||
| 						<mk-media-list :media-list="appearNote.files"/> | ||||
| 					</div> | ||||
| 					<mk-poll v-if="appearNote.poll" :note="appearNote" ref="pollViewer"/> | ||||
| 					<a class="location" v-if="appearNote.geo" :href="`https://maps.google.com/maps?q=${appearNote.geo.coordinates[1]},${appearNote.geo.coordinates[0]}`" target="_blank">%fa:map-marker-alt% %i18n:@location%</a> | ||||
| 					<div class="renote" v-if="appearNote.renote"> | ||||
| 						<mk-note-preview :note="appearNote.renote" :mini="true"/> | ||||
| 					</div> | ||||
| 					<mk-url-preview v-for="url in urls" :url="url" :key="url" :detail="false" :mini="true"/> | ||||
| 				</div> | ||||
| 				<span class="app" v-if="appearNote.app">via <b>{{ appearNote.app.name }}</b></span> | ||||
| 			</div> | ||||
| 			<footer> | ||||
| 				<mk-reactions-viewer :note="appearNote" ref="reactionsViewer"/> | ||||
| 				<button @click="reply()"> | ||||
| 					<template v-if="appearNote.reply">%fa:reply-all%</template> | ||||
| 					<template v-else>%fa:reply%</template> | ||||
| 				</button> | ||||
| 				<button @click="renote()" title="Renote">%fa:retweet%</button> | ||||
| 				<button :class="{ reacted: appearNote.myReaction != null }" @click="react()" ref="reactButton">%fa:plus%</button> | ||||
| 				<button class="menu" @click="menu()" ref="menuButton">%fa:ellipsis-h%</button> | ||||
| 			</footer> | ||||
| 		</div> | ||||
| 	</article> | ||||
| </div> | ||||
| <div v-else class="srwrkujossgfuhrbnvqkybtzxpblgchi"> | ||||
| 	<div v-if="note.files.length > 0"> | ||||
| 		<mk-media-list :media-list="note.files"/> | ||||
| 	</div> | ||||
| 	<div v-if="note.renote && note.renote.files.length > 0"> | ||||
| 		<mk-media-list :media-list="note.renote.files"/> | ||||
| 	</div> | ||||
| </div> | ||||
| </template> | ||||
|  | ||||
| <script lang="ts"> | ||||
| import Vue from 'vue'; | ||||
| import MkPostFormWindow from '../../components/post-form-window.vue'; | ||||
| import MkRenoteFormWindow from '../../components/renote-form-window.vue'; | ||||
| import XSub from './deck.note.sub.vue'; | ||||
| import noteMixin from '../../../../common/scripts/note-mixin'; | ||||
| import noteSubscriber from '../../../../common/scripts/note-subscriber'; | ||||
|  | ||||
| export default Vue.extend({ | ||||
| 	components: { | ||||
| 		XSub | ||||
| 	}, | ||||
|  | ||||
| 	mixins: [ | ||||
| 		noteMixin(), | ||||
| 		noteSubscriber('note') | ||||
| 	], | ||||
|  | ||||
| 	props: { | ||||
| 		note: { | ||||
| 			type: Object, | ||||
| 			required: true | ||||
| 		}, | ||||
| 		mediaView: { | ||||
| 			type: Boolean, | ||||
| 			required: false, | ||||
| 			default: false | ||||
| 		} | ||||
| 	} | ||||
| }); | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| .srwrkujossgfuhrbnvqkybtzxpblgchi | ||||
| 	font-size 13px | ||||
| 	margin 4px 12px | ||||
|  | ||||
| 	&:first-child | ||||
| 		margin-top 12px | ||||
|  | ||||
| 	&:last-child | ||||
| 		margin-bottom 12px | ||||
|  | ||||
| .zyjjkidcqjnlegkqebitfviomuqmseqk | ||||
| 	font-size 13px | ||||
| 	border-bottom solid 1px var(--faceDivider) | ||||
|  | ||||
| 	&:focus | ||||
| 		z-index 1 | ||||
|  | ||||
| 		&:after | ||||
| 			content "" | ||||
| 			pointer-events none | ||||
| 			position absolute | ||||
| 			top 2px | ||||
| 			right 2px | ||||
| 			bottom 2px | ||||
| 			left 2px | ||||
| 			border 2px solid var(--primaryAlpha03) | ||||
| 			border-radius 4px | ||||
|  | ||||
| 	&:last-of-type | ||||
| 		border-bottom none | ||||
|  | ||||
| 	&.smart | ||||
| 		> article | ||||
| 			> .main | ||||
| 				> header | ||||
| 					align-items center | ||||
| 					margin-bottom 4px | ||||
|  | ||||
| 	> .renote | ||||
| 		display flex | ||||
| 		align-items center | ||||
| 		padding 8px 16px 0 16px | ||||
| 		line-height 28px | ||||
| 		white-space pre | ||||
| 		color var(--renoteText) | ||||
| 		background linear-gradient(to bottom, var(--renoteGradient) 0%, var(--face) 100%) | ||||
|  | ||||
| 		.avatar | ||||
| 			flex-shrink 0 | ||||
| 			display inline-block | ||||
| 			width 20px | ||||
| 			height 20px | ||||
| 			margin 0 8px 0 0 | ||||
| 			border-radius 6px | ||||
|  | ||||
| 		[data-fa] | ||||
| 			margin-right 4px | ||||
|  | ||||
| 		> span | ||||
| 			flex-shrink 0 | ||||
|  | ||||
| 			&:last-of-type | ||||
| 				margin-right 8px | ||||
|  | ||||
| 		.name | ||||
| 			overflow hidden | ||||
| 			flex-shrink 1 | ||||
| 			text-overflow ellipsis | ||||
| 			white-space nowrap | ||||
| 			font-weight bold | ||||
|  | ||||
| 		> .mk-time | ||||
| 			display block | ||||
| 			margin-left auto | ||||
| 			flex-shrink 0 | ||||
| 			font-size 0.9em | ||||
|  | ||||
| 		& + article | ||||
| 			padding-top 8px | ||||
|  | ||||
| 	> article | ||||
| 		display flex | ||||
| 		padding 16px 16px 4px | ||||
|  | ||||
| 		> .avatar | ||||
| 			flex-shrink 0 | ||||
| 			display block | ||||
| 			margin 0 10px 8px 0 | ||||
| 			width 42px | ||||
| 			height 42px | ||||
| 			border-radius 6px | ||||
| 			//position -webkit-sticky | ||||
| 			//position sticky | ||||
| 			//top 62px | ||||
|  | ||||
| 		> .main | ||||
| 			flex 1 | ||||
| 			min-width 0 | ||||
|  | ||||
| 			> .body | ||||
|  | ||||
| 				> .cw | ||||
| 					cursor default | ||||
| 					display block | ||||
| 					margin 0 | ||||
| 					padding 0 | ||||
| 					overflow-wrap break-word | ||||
| 					color var(--noteText) | ||||
|  | ||||
| 					> .text | ||||
| 						margin-right 8px | ||||
|  | ||||
| 				> .content | ||||
|  | ||||
| 					> .text | ||||
| 						display block | ||||
| 						margin 0 | ||||
| 						padding 0 | ||||
| 						overflow-wrap break-word | ||||
| 						color var(--noteText) | ||||
|  | ||||
| 						>>> .title | ||||
| 							display block | ||||
| 							margin-bottom 4px | ||||
| 							padding 4px | ||||
| 							font-size 90% | ||||
| 							text-align center | ||||
| 							background var(--mfmTitleBg) | ||||
| 							border-radius 4px | ||||
|  | ||||
| 						>>> .code | ||||
| 							margin 8px 0 | ||||
|  | ||||
| 						>>> .quote | ||||
| 							margin 8px | ||||
| 							padding 6px 12px | ||||
| 							color var(--mfmQuote) | ||||
| 							border-left solid 3px var(--mfmQuoteLine) | ||||
|  | ||||
| 						> .reply | ||||
| 							margin-right 8px | ||||
| 							color var(--noteText) | ||||
|  | ||||
| 						> .rp | ||||
| 							margin-left 4px | ||||
| 							font-style oblique | ||||
| 							color var(--renoteText) | ||||
|  | ||||
| 						[data-is-me]:after | ||||
| 							content "you" | ||||
| 							padding 0 4px | ||||
| 							margin-left 4px | ||||
| 							font-size 80% | ||||
| 							color var(--primaryForeground) | ||||
| 							background var(--primary) | ||||
| 							border-radius 4px | ||||
|  | ||||
| 					.mk-url-preview | ||||
| 						margin-top 8px | ||||
|  | ||||
| 					> .files | ||||
| 						> img | ||||
| 							display block | ||||
| 							max-width 100% | ||||
|  | ||||
| 					> .location | ||||
| 						margin 4px 0 | ||||
| 						font-size 12px | ||||
| 						color #ccc | ||||
|  | ||||
| 					> .map | ||||
| 						width 100% | ||||
| 						height 200px | ||||
|  | ||||
| 						&:empty | ||||
| 							display none | ||||
|  | ||||
| 					> .mk-poll | ||||
| 						font-size 80% | ||||
|  | ||||
| 					> .renote | ||||
| 						margin 8px 0 | ||||
|  | ||||
| 						> * | ||||
| 							padding 16px | ||||
| 							border dashed 1px var(--quoteBorder) | ||||
| 							border-radius 8px | ||||
|  | ||||
| 				> .app | ||||
| 					font-size 12px | ||||
| 					color #ccc | ||||
|  | ||||
| 			> footer | ||||
| 				> button | ||||
| 					margin 0 | ||||
| 					padding 4px 8px 8px 8px | ||||
| 					background transparent | ||||
| 					border none | ||||
| 					box-shadow none | ||||
| 					font-size 1em | ||||
| 					color var(--noteActions) | ||||
| 					cursor pointer | ||||
|  | ||||
| 					&:not(:last-child) | ||||
| 						margin-right 28px | ||||
|  | ||||
| 					&:hover | ||||
| 						color var(--noteActionsHover) | ||||
|  | ||||
| 					> .count | ||||
| 						display inline | ||||
| 						margin 0 0 0 8px | ||||
| 						color #999 | ||||
|  | ||||
| 					&.reacted | ||||
| 						color var(--primary) | ||||
|  | ||||
| </style> | ||||
| @@ -8,16 +8,21 @@ | ||||
| 		</template> | ||||
| 	</div> | ||||
|  | ||||
| 	<div v-if="!fetching && requestInitPromise != null"> | ||||
| 		<p>%i18n:@error%</p> | ||||
| 		<button @click="resolveInitPromise">%i18n:@retry%</button> | ||||
| 	<div v-if="!fetching && requestInitPromise != null" class="error"> | ||||
| 		<p>%fa:exclamation-triangle% %i18n:common.error.title%</p> | ||||
| 		<ui-button @click="resolveInitPromise">%i18n:common.error.retry%</ui-button> | ||||
| 	</div> | ||||
|  | ||||
| 	<!-- トランジションを有効にするとなぜかメモリリークする --> | ||||
| 	<!--<transition-group name="mk-notes" class="transition">--> | ||||
| 	<div class="notes"> | ||||
| 	<!--<transition-group name="mk-notes" class="transition" ref="notes">--> | ||||
| 	<div class="notes" ref="notes"> | ||||
| 		<template v-for="(note, i) in _notes"> | ||||
| 			<x-note :note="note" :key="note.id" @update:note="onNoteUpdated(i, $event)" :media-view="mediaView"/> | ||||
| 			<x-note | ||||
| 				:note="note" | ||||
| 				:key="note.id" | ||||
| 				@update:note="onNoteUpdated(i, $event)" | ||||
| 				:media-view="mediaView" | ||||
| 				:mini="true"/> | ||||
| 			<p class="date" :key="note.id + '_date'" v-if="i != notes.length - 1 && note._date != _notes[i + 1]._date"> | ||||
| 				<span>%fa:angle-up%{{ note._datetext }}</span> | ||||
| 				<span>%fa:angle-down%{{ _notes[i + 1]._datetext }}</span> | ||||
| @@ -38,7 +43,7 @@ | ||||
| <script lang="ts"> | ||||
| import Vue from 'vue'; | ||||
|  | ||||
| import XNote from './deck.note.vue'; | ||||
| import XNote from '../../components/note.vue'; | ||||
|  | ||||
| const displayLimit = 20; | ||||
|  | ||||
| @@ -102,7 +107,7 @@ export default Vue.extend({ | ||||
|  | ||||
| 	methods: { | ||||
| 		focus() { | ||||
| 			(this.$el as any).children[0].focus(); | ||||
| 			(this.$refs.notes as any).children[0].focus ? (this.$refs.notes as any).children[0].focus() : (this.$refs.notes as any).$el.children[0].focus(); | ||||
| 		}, | ||||
|  | ||||
| 		onNoteUpdated(i, note) { | ||||
| @@ -154,6 +159,11 @@ export default Vue.extend({ | ||||
| 			} | ||||
| 			//#endregion | ||||
|  | ||||
| 			// タブが非表示またはスクロール位置が最上部ではないならタイトルで通知 | ||||
| 			if (document.hidden || !this.isScrollTop()) { | ||||
| 				this.$store.commit('pushBehindNote', note); | ||||
| 			} | ||||
|  | ||||
| 			if (this.isScrollTop()) { | ||||
| 				// Prepend the note | ||||
| 				this.notes.unshift(note); | ||||
| @@ -211,6 +221,13 @@ export default Vue.extend({ | ||||
| 		> * | ||||
| 			transition transform .3s ease, opacity .3s ease | ||||
|  | ||||
| 	> .error | ||||
| 		max-width 300px | ||||
| 		margin 0 auto | ||||
| 		padding 16px | ||||
| 		text-align center | ||||
| 		color var(--text) | ||||
|  | ||||
| 	> .placeholder | ||||
| 		padding 16px | ||||
| 		opacity 0.3 | ||||
| @@ -219,8 +236,8 @@ export default Vue.extend({ | ||||
| 		> .date | ||||
| 			display block | ||||
| 			margin 0 | ||||
| 			line-height 32px | ||||
| 			font-size 14px | ||||
| 			line-height 28px | ||||
| 			font-size 12px | ||||
| 			text-align center | ||||
| 			color var(--dateDividerFg) | ||||
| 			background var(--dateDividerBg) | ||||
|   | ||||
| @@ -66,15 +66,15 @@ | ||||
| 	</div> | ||||
|  | ||||
| 	<template v-if="notification.type == 'quote'"> | ||||
| 		<x-note :note="notification.note" @update:note="onNoteUpdated"/> | ||||
| 		<x-note :note="notification.note" @update:note="onNoteUpdated" :mini="true"/> | ||||
| 	</template> | ||||
|  | ||||
| 	<template v-if="notification.type == 'reply'"> | ||||
| 		<x-note :note="notification.note" @update:note="onNoteUpdated"/> | ||||
| 		<x-note :note="notification.note" @update:note="onNoteUpdated" :mini="true"/> | ||||
| 	</template> | ||||
|  | ||||
| 	<template v-if="notification.type == 'mention'"> | ||||
| 		<x-note :note="notification.note" @update:note="onNoteUpdated"/> | ||||
| 		<x-note :note="notification.note" @update:note="onNoteUpdated" :mini="true"/> | ||||
| 	</template> | ||||
| </div> | ||||
| </template> | ||||
| @@ -82,7 +82,7 @@ | ||||
| <script lang="ts"> | ||||
| import Vue from 'vue'; | ||||
| import getNoteSummary from '../../../../../../misc/get-note-summary'; | ||||
| import XNote from './deck.note.vue'; | ||||
| import XNote from '../../components/note.vue'; | ||||
|  | ||||
| export default Vue.extend({ | ||||
| 	components: { | ||||
|   | ||||
| @@ -178,9 +178,9 @@ export default Vue.extend({ | ||||
| 		> .date | ||||
| 			display block | ||||
| 			margin 0 | ||||
| 			line-height 32px | ||||
| 			line-height 28px | ||||
| 			text-align center | ||||
| 			font-size 0.8em | ||||
| 			font-size 12px | ||||
| 			color var(--dateDividerFg) | ||||
| 			background var(--dateDividerBg) | ||||
| 			border-bottom solid 1px var(--faceDivider) | ||||
|   | ||||
| @@ -14,9 +14,25 @@ | ||||
| 		<ui-switch v-model="column.isMediaOnly" @change="onChangeSettings">%i18n:@is-media-only%</ui-switch> | ||||
| 		<ui-switch v-model="column.isMediaView" @change="onChangeSettings">%i18n:@is-media-view%</ui-switch> | ||||
| 	</div> | ||||
| 	<x-list-tl v-if="column.type == 'list'" :list="column.list" :media-only="column.isMediaOnly" :media-view="column.isMediaView"/> | ||||
| 	<x-hashtag-tl v-if="column.type == 'hashtag'" :tag-tl="$store.state.settings.tagTimelines.find(x => x.id == column.tagTlId)" :media-only="column.isMediaOnly" :media-view="column.isMediaView"/> | ||||
| 	<x-tl v-else :src="column.type" :media-only="column.isMediaOnly" :media-view="column.isMediaView"/> | ||||
|  | ||||
| 	<x-list-tl v-if="column.type == 'list'" | ||||
| 		:list="column.list" | ||||
| 		:media-only="column.isMediaOnly" | ||||
| 		:media-view="column.isMediaView" | ||||
| 		ref="tl" | ||||
| 	/> | ||||
| 	<x-hashtag-tl v-else-if="column.type == 'hashtag'" | ||||
| 		:tag-tl="$store.state.settings.tagTimelines.find(x => x.id == column.tagTlId)" | ||||
| 		:media-only="column.isMediaOnly" | ||||
| 		:media-view="column.isMediaView" | ||||
| 		ref="tl" | ||||
| 	/> | ||||
| 	<x-tl v-else | ||||
| 		:src="column.type" | ||||
| 		:media-only="column.isMediaOnly" | ||||
| 		:media-view="column.isMediaView" | ||||
| 		ref="tl" | ||||
| 	/> | ||||
| </x-column> | ||||
| </template> | ||||
|  | ||||
| @@ -77,6 +93,10 @@ export default Vue.extend({ | ||||
| 	methods: { | ||||
| 		onChangeSettings(v) { | ||||
| 			this.$store.dispatch('settings/saveDeck'); | ||||
| 		}, | ||||
|  | ||||
| 		focus() { | ||||
| 			this.$refs.tl.focus(); | ||||
| 		} | ||||
| 	} | ||||
| }); | ||||
|   | ||||
							
								
								
									
										472
									
								
								src/client/app/desktop/views/pages/deck/deck.user-column.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										472
									
								
								src/client/app/desktop/views/pages/deck/deck.user-column.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,472 @@ | ||||
| <template> | ||||
| <x-column> | ||||
| 	<span slot="header"> | ||||
| 		%fa:user%<span>{{ title }}</span> | ||||
| 	</span> | ||||
|  | ||||
| 	<div class="zubukjlciycdsyynicqrnlsmdwmymzqu" v-if="user"> | ||||
| 		<div class="is-remote" v-if="user.host != null"> | ||||
| 			<details> | ||||
| 				<summary>%fa:exclamation-triangle% %i18n:common.is-remote-user%</summary> | ||||
| 				<a :href="user.url || user.uri" target="_blank">%i18n:common.view-on-remote%</a> | ||||
| 			</details> | ||||
| 		</div> | ||||
| 		<header :style="bannerStyle"> | ||||
| 			<div> | ||||
| 				<button class="menu" @click="menu" ref="menu">%fa:ellipsis-h%</button> | ||||
| 				<mk-follow-button v-if="$store.getters.isSignedIn && user.id != $store.state.i.id" :user="user" class="follow"/> | ||||
| 				<mk-avatar class="avatar" :user="user" :disable-preview="true"/> | ||||
| 				<span class="name">{{ user | userName }}</span> | ||||
| 				<span class="acct">@{{ user | acct }}</span> | ||||
| 			</div> | ||||
| 		</header> | ||||
| 		<div class="info"> | ||||
| 			<div class="description"> | ||||
| 				<misskey-flavored-markdown v-if="user.description" :text="user.description" :i="$store.state.i"/> | ||||
| 			</div> | ||||
| 			<div class="counts"> | ||||
| 				<div> | ||||
| 					<b>{{ user.notesCount | number }}</b> | ||||
| 					<span>%i18n:@posts%</span> | ||||
| 				</div> | ||||
| 				<div> | ||||
| 					<b>{{ user.followingCount | number }}</b> | ||||
| 					<span>%i18n:@following%</span> | ||||
| 				</div> | ||||
| 				<div> | ||||
| 					<b>{{ user.followersCount | number }}</b> | ||||
| 					<span>%i18n:@followers%</span> | ||||
| 				</div> | ||||
| 			</div> | ||||
| 		</div> | ||||
| 		<div class="pinned" v-if="user.pinnedNotes && user.pinnedNotes.length > 0"> | ||||
| 			<p class="caption" @click="toggleShowPinned">%fa:thumbtack% %i18n:@pinned-notes%</p> | ||||
| 			<span class="angle" v-if="showPinned">%fa:angle-up%</span> | ||||
| 			<span class="angle" v-else>%fa:angle-down%</span> | ||||
| 			<div class="notes" v-show="showPinned"> | ||||
| 				<x-note v-for="n in user.pinnedNotes" :key="n.id" :note="n" :mini="true"/> | ||||
| 			</div> | ||||
| 		</div> | ||||
| 		<div class="images" v-if="images.length > 0"> | ||||
| 			<p class="caption" @click="toggleShowImages">%fa:images R% %i18n:@images%</p> | ||||
| 			<span class="angle" v-if="showImages">%fa:angle-up%</span> | ||||
| 			<span class="angle" v-else>%fa:angle-down%</span> | ||||
| 			<div v-show="showImages"> | ||||
| 				<router-link v-for="image in images" | ||||
| 					:style="`background-image: url(${image.thumbnailUrl})`" | ||||
| 					:key="`${image.id}:${image._note.id}`" | ||||
| 					:to="image._note | notePage" | ||||
| 					:title="`${image.name}\n${(new Date(image.createdAt)).toLocaleString()}`" | ||||
| 				></router-link> | ||||
| 			</div> | ||||
| 		</div> | ||||
| 		<div class="activity"> | ||||
| 			<p class="caption" @click="toggleShowActivity">%fa:chart-bar R% %i18n:@activity%</p> | ||||
| 			<span class="angle" v-if="showActivity">%fa:angle-up%</span> | ||||
| 			<span class="angle" v-else>%fa:angle-down%</span> | ||||
| 			<div v-show="showActivity"> | ||||
| 				<div ref="chart"></div> | ||||
| 			</div> | ||||
| 		</div> | ||||
| 		<div class="tl"> | ||||
| 			<p class="caption">%fa:comment-alt R% %i18n:@timeline%</p> | ||||
| 			<div> | ||||
| 				<x-notes ref="timeline" :more="existMore ? fetchMoreNotes : null"/> | ||||
| 			</div> | ||||
| 		</div> | ||||
| 	</div> | ||||
| </x-column> | ||||
| </template> | ||||
|  | ||||
| <script lang="ts"> | ||||
| import Vue from 'vue'; | ||||
| import parseAcct from '../../../../../../misc/acct/parse'; | ||||
| import XColumn from './deck.column.vue'; | ||||
| import XNotes from './deck.notes.vue'; | ||||
| import XNote from '../../components/note.vue'; | ||||
| import Menu from '../../../../common/views/components/menu.vue'; | ||||
| import MkUserListsWindow from '../../components/user-lists-window.vue'; | ||||
| import Ok from '../../../../common/views/components/ok.vue'; | ||||
| import { concat } from '../../../../../../prelude/array'; | ||||
| import * as ApexCharts from 'apexcharts'; | ||||
|  | ||||
| const fetchLimit = 10; | ||||
|  | ||||
| export default Vue.extend({ | ||||
| 	components: { | ||||
| 		XColumn, | ||||
| 		XNotes, | ||||
| 		XNote | ||||
| 	}, | ||||
|  | ||||
| 	props: { | ||||
| 		acct: { | ||||
| 			type: String, | ||||
| 			required: true | ||||
| 		} | ||||
| 	}, | ||||
|  | ||||
| 	data() { | ||||
| 		return { | ||||
| 			user: null, | ||||
| 			fetching: true, | ||||
| 			existMore: false, | ||||
| 			moreFetching: false, | ||||
| 			withFiles: false, | ||||
| 			images: [], | ||||
| 			showPinned: true, | ||||
| 			showImages: true, | ||||
| 			showActivity: true | ||||
| 		}; | ||||
| 	}, | ||||
|  | ||||
| 	computed: { | ||||
| 		title(): string { | ||||
| 			return this.user ? Vue.filter('userName')(this.user) : ''; | ||||
| 		}, | ||||
|  | ||||
| 		bannerStyle(): any { | ||||
| 			if (this.user == null) return {}; | ||||
| 			if (this.user.bannerUrl == null) return {}; | ||||
| 			return { | ||||
| 				backgroundColor: this.user.bannerColor && this.user.bannerColor.length == 3 ? `rgb(${ this.user.bannerColor.join(',') })` : null, | ||||
| 				backgroundImage: `url(${ this.user.bannerUrl })` | ||||
| 			}; | ||||
| 		}, | ||||
| 	}, | ||||
|  | ||||
| 	created() { | ||||
| 		(this as any).api('users/show', parseAcct(this.acct)).then(user => { | ||||
| 			this.user = user; | ||||
| 			this.fetching = false; | ||||
|  | ||||
| 			this.$nextTick(() => { | ||||
| 				(this.$refs.timeline as any).init(() => this.initTl()); | ||||
| 			}); | ||||
|  | ||||
| 			const image = [ | ||||
| 				'image/jpeg', | ||||
| 				'image/png', | ||||
| 				'image/gif' | ||||
| 			]; | ||||
|  | ||||
| 			(this as any).api('users/notes', { | ||||
| 				userId: this.user.id, | ||||
| 				fileType: image, | ||||
| 				limit: 9 | ||||
| 			}).then(notes => { | ||||
| 				notes.forEach(note => { | ||||
| 					note.files.forEach(file => { | ||||
| 						file._note = note; | ||||
| 					}); | ||||
| 				}); | ||||
| 				const files = concat(notes.map((n: any): any[] => n.files)); | ||||
| 				this.images = files.filter(f => image.includes(f.type)).slice(0, 9); | ||||
| 			}); | ||||
|  | ||||
| 			(this as any).api('charts/user/notes', { | ||||
| 				userId: this.user.id, | ||||
| 				span: 'day', | ||||
| 				limit: 21 | ||||
| 			}).then(stats => { | ||||
| 				const normal = []; | ||||
| 				const reply = []; | ||||
| 				const renote = []; | ||||
|  | ||||
| 				const now = new Date(); | ||||
| 				const y = now.getFullYear(); | ||||
| 				const m = now.getMonth(); | ||||
| 				const d = now.getDate(); | ||||
|  | ||||
| 				for (let i = 0; i < 21; i++) { | ||||
| 					const x = new Date(y, m, d - i); | ||||
| 					normal.push([ | ||||
| 						x, | ||||
| 						stats.diffs.normal[i] | ||||
| 					]); | ||||
| 					reply.push([ | ||||
| 						x, | ||||
| 						stats.diffs.reply[i] | ||||
| 					]); | ||||
| 					renote.push([ | ||||
| 						x, | ||||
| 						stats.diffs.renote[i] | ||||
| 					]); | ||||
| 				} | ||||
|  | ||||
| 				const chart = new ApexCharts(this.$refs.chart, { | ||||
| 					chart: { | ||||
| 						type: 'bar', | ||||
| 						stacked: true, | ||||
| 						height: 100, | ||||
| 						sparkline: { | ||||
| 							enabled: true | ||||
| 						}, | ||||
| 					}, | ||||
| 					plotOptions: { | ||||
| 						bar: { | ||||
| 							columnWidth: '90%', | ||||
| 							endingShape: 'rounded' | ||||
| 						} | ||||
| 					}, | ||||
| 					grid: { | ||||
| 						clipMarkers: false, | ||||
| 						padding: { | ||||
| 							top: 16, | ||||
| 							right: 16, | ||||
| 							bottom: 16, | ||||
| 							left: 16 | ||||
| 						} | ||||
| 					}, | ||||
| 					tooltip: { | ||||
| 						shared: true, | ||||
| 						intersect: false | ||||
| 					}, | ||||
| 					series: [{ | ||||
| 						name: 'Normal', | ||||
| 						data: normal | ||||
| 					}, { | ||||
| 						name: 'Reply', | ||||
| 						data: reply | ||||
| 					}, { | ||||
| 						name: 'Renote', | ||||
| 						data: renote | ||||
| 					}], | ||||
| 					xaxis: { | ||||
| 						type: 'datetime', | ||||
| 						crosshairs: { | ||||
| 							width: 1, | ||||
| 							opacity: 1 | ||||
| 						} | ||||
| 					} | ||||
| 				}); | ||||
|  | ||||
| 				chart.render(); | ||||
| 			}); | ||||
| 		}); | ||||
| 	}, | ||||
|  | ||||
| 	methods: { | ||||
| 		initTl() { | ||||
| 			return new Promise((res, rej) => { | ||||
| 				(this as any).api('users/notes', { | ||||
| 					userId: this.user.id, | ||||
| 					limit: fetchLimit + 1, | ||||
| 					withFiles: this.withFiles, | ||||
| 					includeMyRenotes: this.$store.state.settings.showMyRenotes, | ||||
| 					includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes, | ||||
| 					includeLocalRenotes: this.$store.state.settings.showLocalRenotes | ||||
| 				}).then(notes => { | ||||
| 					if (notes.length == fetchLimit + 1) { | ||||
| 						notes.pop(); | ||||
| 						this.existMore = true; | ||||
| 					} | ||||
| 					res(notes); | ||||
| 				}, rej); | ||||
| 			}); | ||||
| 		}, | ||||
|  | ||||
| 		fetchMoreNotes() { | ||||
| 			this.moreFetching = true; | ||||
|  | ||||
| 			const promise = (this as any).api('users/notes', { | ||||
| 				userId: this.user.id, | ||||
| 				limit: fetchLimit + 1, | ||||
| 				untilId: (this.$refs.timeline as any).tail().id, | ||||
| 				withFiles: this.withFiles, | ||||
| 				includeMyRenotes: this.$store.state.settings.showMyRenotes, | ||||
| 				includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes, | ||||
| 				includeLocalRenotes: this.$store.state.settings.showLocalRenotes | ||||
| 			}); | ||||
|  | ||||
| 			promise.then(notes => { | ||||
| 				if (notes.length == fetchLimit + 1) { | ||||
| 					notes.pop(); | ||||
| 				} else { | ||||
| 					this.existMore = false; | ||||
| 				} | ||||
| 				notes.forEach(n => (this.$refs.timeline as any).append(n)); | ||||
| 				this.moreFetching = false; | ||||
| 			}); | ||||
|  | ||||
| 			return promise; | ||||
| 		}, | ||||
|  | ||||
| 		menu() { | ||||
| 			let menu = [{ | ||||
| 				icon: '%fa:list%', | ||||
| 				text: '%i18n:@push-to-a-list%', | ||||
| 				action: () => { | ||||
| 					const w = (this as any).os.new(MkUserListsWindow); | ||||
| 					w.$once('choosen', async list => { | ||||
| 						w.close(); | ||||
| 						await (this as any).api('users/lists/push', { | ||||
| 							listId: list.id, | ||||
| 							userId: this.user.id | ||||
| 						}); | ||||
| 						(this as any).os.new(Ok); | ||||
| 					}); | ||||
| 				} | ||||
| 			}]; | ||||
|  | ||||
| 			this.os.new(Menu, { | ||||
| 				source: this.$refs.menu, | ||||
| 				compact: false, | ||||
| 				items: menu | ||||
| 			}); | ||||
| 		}, | ||||
|  | ||||
| 		toggleShowPinned() { | ||||
| 			this.showPinned = !this.showPinned; | ||||
| 		}, | ||||
|  | ||||
| 		toggleShowImages() { | ||||
| 			this.showImages = !this.showImages; | ||||
| 		}, | ||||
|  | ||||
| 		toggleShowActivity() { | ||||
| 			this.showActivity = !this.showActivity; | ||||
| 		} | ||||
| 	} | ||||
| }); | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| .zubukjlciycdsyynicqrnlsmdwmymzqu | ||||
| 	background var(--deckColumnBg) | ||||
|  | ||||
| 	> .is-remote | ||||
| 		padding 8px 16px | ||||
| 		font-size 12px | ||||
|  | ||||
| 		&.is-remote | ||||
| 			color var(--remoteInfoFg) | ||||
| 			background var(--remoteInfoBg) | ||||
|  | ||||
| 		> a | ||||
| 			font-weight bold | ||||
|  | ||||
| 	> header | ||||
| 		overflow hidden | ||||
| 		background-size cover | ||||
| 		background-position center | ||||
|  | ||||
| 		> div | ||||
| 			padding 32px | ||||
| 			background rgba(#000, 0.5) | ||||
| 			color #fff | ||||
| 			text-align center | ||||
|  | ||||
| 			> .menu | ||||
| 				position absolute | ||||
| 				top 8px | ||||
| 				left 8px | ||||
| 				padding 8px | ||||
| 				font-size 16px | ||||
| 				text-shadow 0 0 8px #000 | ||||
|  | ||||
| 			> .follow | ||||
| 				position absolute | ||||
| 				top 16px | ||||
| 				right 16px | ||||
|  | ||||
| 			> .avatar | ||||
| 				display block | ||||
| 				width 64px | ||||
| 				height 64px | ||||
| 				margin 0 auto | ||||
|  | ||||
| 			> .name | ||||
| 				display block | ||||
| 				margin-top 8px | ||||
| 				font-weight bold | ||||
| 				text-shadow 0 0 8px #000 | ||||
|  | ||||
| 			> .acct | ||||
| 				font-size 14px | ||||
| 				opacity 0.7 | ||||
| 				text-shadow 0 0 8px #000 | ||||
|  | ||||
| 	> .info | ||||
| 		padding 16px | ||||
| 		font-size 12px | ||||
| 		color var(--text) | ||||
| 		text-align center | ||||
| 		background var(--face) | ||||
|  | ||||
| 		&:before | ||||
| 			content "" | ||||
| 			display blcok | ||||
| 			position absolute | ||||
| 			top -32px | ||||
| 			left 0 | ||||
| 			right 0 | ||||
| 			width 0px | ||||
| 			margin 0 auto | ||||
| 			border-top solid 16px transparent | ||||
| 			border-left solid 16px transparent | ||||
| 			border-right solid 16px transparent | ||||
| 			border-bottom solid 16px var(--face) | ||||
|  | ||||
| 		> .counts | ||||
| 			display grid | ||||
| 			grid-template-columns 1fr 1fr 1fr | ||||
| 			margin-top 8px | ||||
| 			border-top solid 1px var(--faceDivider) | ||||
|  | ||||
| 			> div | ||||
| 				padding 8px 8px 0 8px | ||||
| 				text-align center | ||||
|  | ||||
| 				> b | ||||
| 					display block | ||||
| 					font-size 110% | ||||
|  | ||||
| 				> span | ||||
| 					display block | ||||
| 					font-size 80% | ||||
| 					opacity 0.7 | ||||
|  | ||||
| 	> * | ||||
| 		> p.caption | ||||
| 			margin 0 | ||||
| 			padding 8px 16px | ||||
| 			font-size 12px | ||||
| 			color var(--text) | ||||
|  | ||||
| 			& + .angle | ||||
| 				position absolute | ||||
| 				top 0 | ||||
| 				right 8px | ||||
| 				padding 6px | ||||
| 				font-size 14px | ||||
| 				color var(--text) | ||||
|  | ||||
| 	> .pinned | ||||
| 		> .notes | ||||
| 			background var(--face) | ||||
|  | ||||
| 	> .images | ||||
| 		> div | ||||
| 			display grid | ||||
| 			grid-template-columns 1fr 1fr 1fr | ||||
| 			gap 8px | ||||
| 			padding 16px | ||||
| 			background var(--face) | ||||
|  | ||||
| 			> * | ||||
| 				height 70px | ||||
| 				background-position center center | ||||
| 				background-size cover | ||||
| 				background-clip content-box | ||||
| 				border-radius 4px | ||||
|  | ||||
| 	> .activity | ||||
| 		> div | ||||
| 			background var(--face) | ||||
|  | ||||
| 	> .tl | ||||
| 		> div | ||||
| 			background var(--face) | ||||
|  | ||||
| </style> | ||||
| @@ -1,13 +1,18 @@ | ||||
| <template> | ||||
| <mk-ui :class="$style.root"> | ||||
| 	<div class="qlvquzbjribqcaozciifydkngcwtyzje" :style="style"> | ||||
| 	<div class="qlvquzbjribqcaozciifydkngcwtyzje" ref="body" :style="style" :class="{ center: $store.state.device.deckColumnAlign == 'center' }" v-hotkey.global="keymap"> | ||||
| 		<template v-for="ids in layout"> | ||||
| 			<div v-if="ids.length > 1" class="folder"> | ||||
| 				<template v-for="id, i in ids"> | ||||
| 					<x-column-core :ref="id" :key="id" :column="columns.find(c => c.id == id)" :is-stacked="true"/> | ||||
| 					<x-column-core :ref="id" :key="id" :column="columns.find(c => c.id == id)" :is-stacked="true" @parentFocus="moveFocus(id, $event)"/> | ||||
| 				</template> | ||||
| 			</div> | ||||
| 			<x-column-core v-else :ref="ids[0]" :key="ids[0]" :column="columns.find(c => c.id == ids[0])"/> | ||||
| 			<x-column-core v-else :ref="ids[0]" :key="ids[0]" :column="columns.find(c => c.id == ids[0])" @parentFocus="moveFocus(ids[0], $event)"/> | ||||
| 		</template> | ||||
| 		<template v-if="temporaryColumn"> | ||||
| 			<x-user-column v-if="temporaryColumn.type == 'user'" :acct="temporaryColumn.acct" :key="temporaryColumn.acct"/> | ||||
| 			<x-note-column v-else-if="temporaryColumn.type == 'note'" :note-id="temporaryColumn.noteId" :key="temporaryColumn.noteId"/> | ||||
| 			<x-hashtag-column v-else-if="temporaryColumn.type == 'tag'" :tag="temporaryColumn.tag" :key="temporaryColumn.tag"/> | ||||
| 		</template> | ||||
| 		<button ref="add" @click="add" title="%i18n:common.deck.add-column%">%fa:plus%</button> | ||||
| 	</div> | ||||
| @@ -19,11 +24,18 @@ import Vue from 'vue'; | ||||
| import XColumnCore from './deck.column-core.vue'; | ||||
| import Menu from '../../../../common/views/components/menu.vue'; | ||||
| import MkUserListsWindow from '../../components/user-lists-window.vue'; | ||||
| import XUserColumn from './deck.user-column.vue'; | ||||
| import XNoteColumn from './deck.note-column.vue'; | ||||
| import XHashtagColumn from './deck.hashtag-column.vue'; | ||||
|  | ||||
| import * as uuid from 'uuid'; | ||||
|  | ||||
| export default Vue.extend({ | ||||
| 	components: { | ||||
| 		XColumnCore | ||||
| 		XColumnCore, | ||||
| 		XUserColumn, | ||||
| 		XNoteColumn, | ||||
| 		XHashtagColumn | ||||
| 	}, | ||||
|  | ||||
| 	computed: { | ||||
| @@ -31,15 +43,40 @@ export default Vue.extend({ | ||||
| 			if (this.$store.state.settings.deck == null) return []; | ||||
| 			return this.$store.state.settings.deck.columns; | ||||
| 		}, | ||||
|  | ||||
| 		layout(): any[] { | ||||
| 			if (this.$store.state.settings.deck == null) return []; | ||||
| 			if (this.$store.state.settings.deck.layout == null) return this.$store.state.settings.deck.columns.map(c => [c.id]); | ||||
| 			return this.$store.state.settings.deck.layout; | ||||
| 		}, | ||||
|  | ||||
| 		style(): any { | ||||
| 			return { | ||||
| 				height: `calc(100vh - ${this.$store.state.uiHeaderHeight}px)` | ||||
| 			}; | ||||
| 		}, | ||||
|  | ||||
| 		temporaryColumn(): any { | ||||
| 			return this.$store.state.device.deckTemporaryColumn; | ||||
| 		}, | ||||
|  | ||||
| 		keymap(): any { | ||||
| 			return { | ||||
| 				't': this.focus | ||||
| 			}; | ||||
| 		} | ||||
| 	}, | ||||
|  | ||||
| 	watch: { | ||||
| 		temporaryColumn() { | ||||
| 			if (this.temporaryColumn != null) { | ||||
| 				this.$nextTick(() => { | ||||
| 					this.$refs.body.scrollTo({ | ||||
| 						left: this.$refs.body.scrollWidth - this.$refs.body.clientWidth, | ||||
| 						behavior: 'smooth' | ||||
| 					}); | ||||
| 				}); | ||||
| 			} | ||||
| 		} | ||||
| 	}, | ||||
|  | ||||
| @@ -50,6 +87,8 @@ export default Vue.extend({ | ||||
| 	}, | ||||
|  | ||||
| 	created() { | ||||
| 		this.$store.commit('navHook', this.onNav); | ||||
|  | ||||
| 		if (this.$store.state.settings.deck == null) { | ||||
| 			const deck = { | ||||
| 				columns: [/*{ | ||||
| @@ -95,6 +134,8 @@ export default Vue.extend({ | ||||
| 	}, | ||||
|  | ||||
| 	beforeDestroy() { | ||||
| 		this.$store.commit('navHook', null); | ||||
|  | ||||
| 		document.documentElement.style.overflow = 'auto'; | ||||
| 	}, | ||||
|  | ||||
| @@ -103,6 +144,39 @@ export default Vue.extend({ | ||||
| 			return this.$refs[id][0]; | ||||
| 		}, | ||||
|  | ||||
| 		onNav(to) { | ||||
| 			if (!this.$store.state.settings.deckNav) return false; | ||||
|  | ||||
| 			if (to.name == 'user') { | ||||
| 				this.$store.commit('device/set', { | ||||
| 					key: 'deckTemporaryColumn', | ||||
| 					value: { | ||||
| 						type: 'user', | ||||
| 						acct: to.params.user | ||||
| 					} | ||||
| 				}); | ||||
| 				return true; | ||||
| 			} else if (to.name == 'note') { | ||||
| 				this.$store.commit('device/set', { | ||||
| 					key: 'deckTemporaryColumn', | ||||
| 					value: { | ||||
| 						type: 'note', | ||||
| 						noteId: to.params.note | ||||
| 					} | ||||
| 				}); | ||||
| 				return true; | ||||
| 			} else if (to.name == 'tag') { | ||||
| 				this.$store.commit('device/set', { | ||||
| 					key: 'deckTemporaryColumn', | ||||
| 					value: { | ||||
| 						type: 'tag', | ||||
| 						tag: to.params.tag | ||||
| 					} | ||||
| 				}); | ||||
| 				return true; | ||||
| 			} | ||||
| 		}, | ||||
|  | ||||
| 		add() { | ||||
| 			this.os.new(Menu, { | ||||
| 				source: this.$refs.add, | ||||
| @@ -210,6 +284,71 @@ export default Vue.extend({ | ||||
| 					} | ||||
| 				}] | ||||
| 			}); | ||||
| 		}, | ||||
|  | ||||
| 		focus() { | ||||
| 			// Flatten array of arrays | ||||
| 			const ids = [].concat.apply([], this.layout); | ||||
| 			const firstTl = ids.find(id => this.isTlColumn(id)); | ||||
|  | ||||
| 			if (firstTl) { | ||||
| 				this.$refs[firstTl][0].focus(); | ||||
| 			} | ||||
| 		}, | ||||
|  | ||||
| 		moveFocus(id, direction) { | ||||
| 			let targetColumn; | ||||
|  | ||||
| 			if (direction == 'right') { | ||||
| 				const currentColumnIndex = this.layout.findIndex(ids => ids.includes(id)); | ||||
| 				this.layout.some((ids, i) => { | ||||
| 					if (i <= currentColumnIndex) return false; | ||||
| 					const tl = ids.find(id => this.isTlColumn(id)); | ||||
| 					if (tl) { | ||||
| 						targetColumn = tl; | ||||
| 						return true; | ||||
| 					} | ||||
| 				}); | ||||
| 			} else if (direction == 'left') { | ||||
| 				const currentColumnIndex = [...this.layout].reverse().findIndex(ids => ids.includes(id)); | ||||
| 				[...this.layout].reverse().some((ids, i) => { | ||||
| 					if (i <= currentColumnIndex) return false; | ||||
| 					const tl = ids.find(id => this.isTlColumn(id)); | ||||
| 					if (tl) { | ||||
| 						targetColumn = tl; | ||||
| 						return true; | ||||
| 					} | ||||
| 				}); | ||||
| 			} else if (direction == 'down') { | ||||
| 				const currentColumn = this.layout.find(ids => ids.includes(id)); | ||||
| 				const currentIndex = currentColumn.indexOf(id); | ||||
| 				currentColumn.some((_id, i) => { | ||||
| 					if (i <= currentIndex) return false; | ||||
| 					if (this.isTlColumn(_id)) { | ||||
| 						targetColumn = _id; | ||||
| 						return true; | ||||
| 					} | ||||
| 				}); | ||||
| 			} else if (direction == 'up') { | ||||
| 				const currentColumn = [...this.layout.find(ids => ids.includes(id))].reverse(); | ||||
| 				const currentIndex = currentColumn.indexOf(id); | ||||
| 				currentColumn.some((_id, i) => { | ||||
| 					if (i <= currentIndex) return false; | ||||
| 					if (this.isTlColumn(_id)) { | ||||
| 						targetColumn = _id; | ||||
| 						return true; | ||||
| 					} | ||||
| 				}); | ||||
| 			} | ||||
|  | ||||
| 			if (targetColumn) { | ||||
| 				this.$refs[targetColumn][0].focus(); | ||||
| 			} | ||||
| 		}, | ||||
|  | ||||
| 		isTlColumn(id) { | ||||
| 			const column = this.columns.find(c => c.id === id); | ||||
| 			return ['home', 'local', 'hybrid', 'global', 'list', 'hashtag', 'mentions', 'direct'].includes(column.type); | ||||
| 		} | ||||
| 	} | ||||
| }); | ||||
| @@ -240,12 +379,13 @@ export default Vue.extend({ | ||||
| 			> *:not(:last-child) | ||||
| 				margin-bottom 8px | ||||
|  | ||||
| 	> * | ||||
| 		&:first-child | ||||
| 			margin-left auto | ||||
| 	&.center | ||||
| 		> * | ||||
| 			&:first-child | ||||
| 				margin-left auto | ||||
|  | ||||
| 		&:last-child | ||||
| 			margin-right auto | ||||
| 			&:last-child | ||||
| 				margin-right auto | ||||
|  | ||||
| 	> button | ||||
| 		padding 0 16px | ||||
|   | ||||
| @@ -1,16 +1,25 @@ | ||||
| <template> | ||||
| <component :is="$store.getters.isSignedIn ? 'home' : 'welcome'"></component> | ||||
| <component :is="page"></component> | ||||
| </template> | ||||
|  | ||||
| <script lang="ts"> | ||||
| import Vue from 'vue'; | ||||
| import Home from './home.vue'; | ||||
| import Welcome from './welcome.vue'; | ||||
| import Deck from './deck/deck.vue'; | ||||
|  | ||||
| export default Vue.extend({ | ||||
| 	components: { | ||||
| 		Home, | ||||
| 		Deck, | ||||
| 		Welcome | ||||
| 	}, | ||||
|  | ||||
| 	computed: { | ||||
| 		page(): string { | ||||
| 			if (!this.$store.getters.isSignedIn) return 'welcome'; | ||||
| 			return this.$store.state.device.deckDefault ? 'deck' : 'home'; | ||||
| 		} | ||||
| 	} | ||||
| }); | ||||
| </script> | ||||
|   | ||||
| @@ -18,7 +18,7 @@ | ||||
| 		</div> | ||||
| 		<div class="info"> | ||||
| 			<span class="location" v-if="user.host === null && user.profile.location">%fa:map-marker% {{ user.profile.location }}</span> | ||||
| 			<span class="birthday" v-if="user.host === null && user.profile.birthday">%fa:birthday-cake% {{ user.profile.birthday.replace('-', '年').replace('-', '月') + '日' }} ({{ age }}歳)</span> | ||||
| 			<span class="birthday" v-if="user.host === null && user.profile.birthday">%fa:birthday-cake% {{ user.profile.birthday.replace('-', '%i18n:@year%').replace('-', '%i18n:@month%') + '%i18n:@day%' }} ({{ age }}%i18n:@years-old%)</span> | ||||
| 		</div> | ||||
| 		<div class="status"> | ||||
| 			<span class="notes-count"><b>{{ user.notesCount | number }}</b>%i18n:@posts%</span> | ||||
|   | ||||
| @@ -60,9 +60,6 @@ export default Vue.extend({ | ||||
| 			margin-right 4px | ||||
|  | ||||
| 	> .stream | ||||
| 		display -webkit-flex | ||||
| 		display -moz-flex | ||||
| 		display -ms-flex | ||||
| 		display flex | ||||
| 		justify-content center | ||||
| 		flex-wrap wrap | ||||
|   | ||||
| @@ -9,11 +9,11 @@ | ||||
| 		</p> | ||||
| 	</div> | ||||
| 	<div class="action-form"> | ||||
| 		<button class="mute ui" @click="user.isMuted ? unmute() : mute()" v-if="$store.state.i.id != user.id"> | ||||
| 		<ui-button @click="user.isMuted ? unmute() : mute()" v-if="$store.state.i.id != user.id"> | ||||
| 			<span v-if="user.isMuted">%fa:eye% %i18n:@unmute%</span> | ||||
| 			<span v-if="!user.isMuted">%fa:eye-slash% %i18n:@mute%</span> | ||||
| 		</button> | ||||
| 		<button class="mute ui" @click="list">%fa:list% %i18n:@push-to-a-list%</button> | ||||
| 		</ui-button> | ||||
| 		<ui-button @click="list">%fa:list% %i18n:@push-to-a-list%</ui-button> | ||||
| 	</div> | ||||
| </div> | ||||
| </template> | ||||
|   | ||||
| @@ -2,7 +2,7 @@ | ||||
| <mk-ui> | ||||
| 	<div class="xygkxeaeontfaokvqmiblezmhvhostak" v-if="!fetching"> | ||||
| 		<div class="is-suspended" v-if="user.isSuspended">%fa:exclamation-triangle% %i18n:@is-suspended%</div> | ||||
| 		<div class="is-remote" v-if="user.host != null">%fa:exclamation-triangle% %i18n:@is-remote%<a :href="user.url || user.uri" target="_blank">%i18n:@view-remote%</a></div> | ||||
| 		<div class="is-remote" v-if="user.host != null">%fa:exclamation-triangle% %i18n:common.is-remote-user%<a :href="user.url || user.uri" target="_blank">%i18n:common.view-on-remote%</a></div> | ||||
| 		<main> | ||||
| 			<div class="main"> | ||||
| 				<x-header :user="user"/> | ||||
|   | ||||
| @@ -1,12 +1,12 @@ | ||||
| <template> | ||||
| <mk-ui> | ||||
| 	<b-card header="アプリを管理"> | ||||
| 		<b-button to="/app/new" variant="primary">アプリ作成</b-button> | ||||
| 	<b-card header="%i18n:@manage-apps%"> | ||||
| 		<b-button to="/app/new" variant="primary">%i18n:@create-app%</b-button> | ||||
| 		<hr> | ||||
| 		<div class="apps"> | ||||
| 			<p v-if="fetching">読み込み中</p> | ||||
| 			<p v-if="fetching">%i18n:common.loading%</p> | ||||
| 			<template v-if="!fetching"> | ||||
| 				<b-alert v-if="apps.length == 0">アプリなし</b-alert> | ||||
| 				<b-alert v-if="apps.length == 0">%i18n:@app-missing%</b-alert> | ||||
| 				<b-list-group v-else> | ||||
| 					<b-list-group-item v-for="app in apps" :key="app.id" :to="`/app/${app.id}`"> | ||||
| 						{{ app.name }} | ||||
|   | ||||
| @@ -1,34 +1,34 @@ | ||||
| <template> | ||||
| <mk-ui> | ||||
| 	<b-card header="アプリケーションの作成"> | ||||
| 	<b-card header="%i18n:@create-app%"> | ||||
| 		<b-form @submit.prevent="onSubmit" autocomplete="off"> | ||||
| 			<b-form-group label="アプリケーション名" description="あなたのアプリの名称。"> | ||||
| 				<b-form-input v-model="name" type="text" placeholder="ex) Misskey for iOS" autocomplete="off" required/> | ||||
| 			<b-form-group label="%i18n:@app-name%" description="%i18n:@app-name-desc%"> | ||||
| 				<b-form-input v-model="name" type="text" placeholder="%i18n:@app-name-ex%" autocomplete="off" required/> | ||||
| 			</b-form-group> | ||||
| 			<b-form-group label="アプリの概要" description="あなたのアプリの簡単な説明や紹介。"> | ||||
| 				<b-textarea v-model="description" placeholder="ex) Misskey iOSクライアント。" autocomplete="off" required></b-textarea> | ||||
| 			<b-form-group label="%i18n:@app-overview%" description="%i18n:@app-desc%"> | ||||
| 				<b-textarea v-model="description" placeholder="%i18n:@app-desc-ex%" autocomplete="off" required></b-textarea> | ||||
| 			</b-form-group> | ||||
| 			<b-form-group label="コールバックURL (オプション)" description="ユーザーが認証フォームで認証した際にリダイレクトするURLを設定できます。"> | ||||
| 			<b-form-group label="%i18n:@callback-url%" description="%i18n:@callback-url-desc%"> | ||||
| 				<b-input v-model="cb" type="url" placeholder="ex) https://your.app.example.com/callback.php" autocomplete="off"/> | ||||
| 			</b-form-group> | ||||
| 			<b-card header="権限"> | ||||
| 				<b-form-group description="ここで要求した機能だけがAPIからアクセスできます。"> | ||||
| 					<b-alert show variant="warning">%fa:exclamation-triangle%アプリ作成後も変更できますが、新たな権限を付与する場合、その時点で関連付けられているユーザーキーはすべて無効になります。</b-alert> | ||||
| 			<b-card header="%i18n:@authority%"> | ||||
| 				<b-form-group description="%i18n:@authority-desc%"> | ||||
| 					<b-alert show variant="warning">%fa:exclamation-triangle% %i18n:@authority-warning%</b-alert> | ||||
| 					<b-form-checkbox-group v-model="permission" stacked> | ||||
| 						<b-form-checkbox value="account-read">アカウントの情報を見る。</b-form-checkbox> | ||||
| 						<b-form-checkbox value="account-write">アカウントの情報を操作する。</b-form-checkbox> | ||||
| 						<b-form-checkbox value="note-write">投稿する。</b-form-checkbox> | ||||
| 						<b-form-checkbox value="reaction-write">リアクションしたりリアクションをキャンセルする。</b-form-checkbox> | ||||
| 						<b-form-checkbox value="following-write">フォローしたりフォロー解除する。</b-form-checkbox> | ||||
| 						<b-form-checkbox value="drive-read">ドライブを見る。</b-form-checkbox> | ||||
| 						<b-form-checkbox value="drive-write">ドライブを操作する。</b-form-checkbox> | ||||
| 						<b-form-checkbox value="notification-read">通知を見る。</b-form-checkbox> | ||||
| 						<b-form-checkbox value="notification-write">通知を操作する。</b-form-checkbox> | ||||
| 						<b-form-checkbox value="account-read">%i18n:@account-read%</b-form-checkbox> | ||||
| 						<b-form-checkbox value="account-write">%i18n:@account-write%</b-form-checkbox> | ||||
| 						<b-form-checkbox value="note-write">%i18n:@note-write%</b-form-checkbox> | ||||
| 						<b-form-checkbox value="reaction-write">%i18n:@reaction-write%</b-form-checkbox> | ||||
| 						<b-form-checkbox value="following-write">%i18n:@following-write%</b-form-checkbox> | ||||
| 						<b-form-checkbox value="drive-read">%i18n:@drive-read%</b-form-checkbox> | ||||
| 						<b-form-checkbox value="drive-write">%i18n:@drive-write%</b-form-checkbox> | ||||
| 						<b-form-checkbox value="notification-read">%i18n:@notification-read%</b-form-checkbox> | ||||
| 						<b-form-checkbox value="notification-write">%i18n:@notification-write%</b-form-checkbox> | ||||
| 					</b-form-checkbox-group> | ||||
| 				</b-form-group> | ||||
| 			</b-card> | ||||
| 			<hr> | ||||
| 			<b-button type="submit" variant="primary">アプリ作成</b-button> | ||||
| 			<b-button type="submit" variant="primary">%i18n:@create-app%</b-button> | ||||
| 		</b-form> | ||||
| 	</b-card> | ||||
| </mk-ui> | ||||
| @@ -56,7 +56,7 @@ export default Vue.extend({ | ||||
| 			}).then(() => { | ||||
| 				location.href = '/dev/apps'; | ||||
| 			}).catch(() => { | ||||
| 				alert('アプリの作成に失敗しました。再度お試しください。'); | ||||
| 				alert('%i18n:common.dev.failed-to-create%'); | ||||
| 			}); | ||||
| 		} | ||||
| 	} | ||||
|   | ||||
| @@ -148,6 +148,31 @@ export default (callback: (launch: (router: VueRouter, api?: (os: MiOS) => API) | ||||
| 			}); | ||||
| 			//#endregion | ||||
|  | ||||
| 			// Navigation hook | ||||
| 			router.beforeEach((to, from, next) => { | ||||
| 				if (os.store.state.navHook) { | ||||
| 					if (os.store.state.navHook(to)) { | ||||
| 						next(false); | ||||
| 					} else { | ||||
| 						next(); | ||||
| 					} | ||||
| 				} else { | ||||
| 					next(); | ||||
| 				} | ||||
| 			}); | ||||
|  | ||||
| 			document.addEventListener('visibilitychange', () => { | ||||
| 				if (!document.hidden) { | ||||
| 					os.store.commit('clearBehindNotes'); | ||||
| 				} | ||||
| 			}, false); | ||||
|  | ||||
| 			window.addEventListener('scroll', () => { | ||||
| 				if (window.scrollY <= 8) { | ||||
| 					os.store.commit('clearBehindNotes'); | ||||
| 				} | ||||
| 			}, { passive: true }); | ||||
|  | ||||
| 			Vue.mixin({ | ||||
| 				data() { | ||||
| 					return { | ||||
| @@ -197,15 +222,15 @@ function panic(e) { | ||||
| 	document.documentElement.style.background = '#1269e2'; | ||||
| 	document.body.innerHTML = | ||||
| 		'<div id="error">' | ||||
| 			+ '<h1>:( 致命的な問題が発生しました。</h1>' | ||||
| 			+ '<p>お使いのブラウザ(またはOS)のバージョンを更新すると解決する可能性があります。</p>' | ||||
| 			+ '<h1>%i18n.common.BSoD.fatal-error%</h1>' | ||||
| 			+ '<p>%i18n.common.BSoD.update-browser-os%</p>' | ||||
| 			+ '<hr>' | ||||
| 			+ `<p>エラーコード: ${e.toString()}</p>` | ||||
| 			+ `<p>ブラウザ バージョン: ${navigator.userAgent}</p>` | ||||
| 			+ `<p>クライアント バージョン: ${version}</p>` | ||||
| 			+ `<p>%i18n.common.BSoD.error-code%: ${e.toString()}</p>` | ||||
| 			+ `<p>%i18n.common.BSoD.browser-version%: ${navigator.userAgent}</p>` | ||||
| 			+ `<p>%i18n.common.BSoD.client-version%: ${version}</p>` | ||||
| 			+ '<hr>' | ||||
| 			+ '<p>問題が解決しない場合は、上記の情報をお書き添えの上 syuilotan@yahoo.co.jp までご連絡ください。</p>' | ||||
| 			+ '<p>Thank you for using Misskey.</p>' | ||||
| 			+ '<p>%i18n.common.BSoD.email-support%</p>' | ||||
| 			+ '<p>%i18n.common.BSoD.thanks%</p>' | ||||
| 		+ '</div>'; | ||||
|  | ||||
| 	// TODO: Report the bug | ||||
|   | ||||
| @@ -244,10 +244,10 @@ export default class MiOS extends EventEmitter { | ||||
| 					this.store.dispatch('login', me); | ||||
| 					fetched(); | ||||
| 				} else { | ||||
| 					this.initStream(); | ||||
|  | ||||
| 					// Finish init | ||||
| 					callback(); | ||||
|  | ||||
| 					this.initStream(); | ||||
| 				} | ||||
| 			}); | ||||
| 		} | ||||
|   | ||||
| @@ -103,11 +103,11 @@ export default Vue.extend({ | ||||
| 	mounted() { | ||||
| 		this.connection = (this as any).os.stream.useSharedConnection('drive'); | ||||
|  | ||||
| 		this.connection.on('file_created', this.onStreamDriveFileCreated); | ||||
| 		this.connection.on('file_updated', this.onStreamDriveFileUpdated); | ||||
| 		this.connection.on('file_deleted', this.onStreamDriveFileDeleted); | ||||
| 		this.connection.on('folder_created', this.onStreamDriveFolderCreated); | ||||
| 		this.connection.on('folder_updated', this.onStreamDriveFolderUpdated); | ||||
| 		this.connection.on('fileCreated', this.onStreamDriveFileCreated); | ||||
| 		this.connection.on('fileUpdated', this.onStreamDriveFileUpdated); | ||||
| 		this.connection.on('fileDeleted', this.onStreamDriveFileDeleted); | ||||
| 		this.connection.on('folderCreated', this.onStreamDriveFolderCreated); | ||||
| 		this.connection.on('folderUpdated', this.onStreamDriveFolderUpdated); | ||||
|  | ||||
| 		if (this.initFolder) { | ||||
| 			this.cd(this.initFolder, true); | ||||
|   | ||||
| @@ -31,7 +31,7 @@ | ||||
| 						<span v-if="appearNote.isHidden" style="opacity: 0.5">(%i18n:@private%)</span> | ||||
| 						<a class="reply" v-if="appearNote.reply">%fa:reply%</a> | ||||
| 						<misskey-flavored-markdown v-if="appearNote.text" :text="appearNote.text" :i="$store.state.i" :class="$style.text"/> | ||||
| 						<a class="rp" v-if="appearNote.renote != null">RP:</a> | ||||
| 						<a class="rp" v-if="appearNote.renote != null">RN:</a> | ||||
| 					</div> | ||||
| 					<div class="files" v-if="appearNote.files.length > 0"> | ||||
| 						<mk-media-list :media-list="appearNote.files"/> | ||||
|   | ||||
| @@ -37,7 +37,6 @@ | ||||
|  | ||||
| <script lang="ts"> | ||||
| import Vue from 'vue'; | ||||
| import getNoteSummary from '../../../../../misc/get-note-summary'; | ||||
|  | ||||
| const displayLimit = 30; | ||||
|  | ||||
| @@ -54,7 +53,6 @@ export default Vue.extend({ | ||||
| 			requestInitPromise: null as () => Promise<any[]>, | ||||
| 			notes: [], | ||||
| 			queue: [], | ||||
| 			unreadCount: 0, | ||||
| 			fetching: true, | ||||
| 			moreFetching: false | ||||
| 		}; | ||||
| @@ -83,12 +81,10 @@ export default Vue.extend({ | ||||
| 	}, | ||||
|  | ||||
| 	mounted() { | ||||
| 		document.addEventListener('visibilitychange', this.onVisibilitychange, false); | ||||
| 		window.addEventListener('scroll', this.onScroll, { passive: true }); | ||||
| 	}, | ||||
|  | ||||
| 	beforeDestroy() { | ||||
| 		document.removeEventListener('visibilitychange', this.onVisibilitychange); | ||||
| 		window.removeEventListener('scroll', this.onScroll); | ||||
| 	}, | ||||
|  | ||||
| @@ -146,10 +142,9 @@ export default Vue.extend({ | ||||
| 			} | ||||
| 			//#endregion | ||||
|  | ||||
| 			// 投稿が自分のものではないかつ、タブが非表示またはスクロール位置が最上部ではないならタイトルで通知 | ||||
| 			if ((document.hidden || !this.isScrollTop()) && note.userId !== this.$store.state.i.id) { | ||||
| 				this.unreadCount++; | ||||
| 				document.title = `(${this.unreadCount}) ${getNoteSummary(note)}`; | ||||
| 			// タブが非表示またはスクロール位置が最上部ではないならタイトルで通知 | ||||
| 			if (document.hidden || !this.isScrollTop()) { | ||||
| 				this.$store.commit('pushBehindNote', note); | ||||
| 			} | ||||
|  | ||||
| 			if (this.isScrollTop()) { | ||||
| @@ -187,21 +182,9 @@ export default Vue.extend({ | ||||
| 			this.moreFetching = false; | ||||
| 		}, | ||||
|  | ||||
| 		clearNotification() { | ||||
| 			this.unreadCount = 0; | ||||
| 			document.title = (this as any).os.instanceName; | ||||
| 		}, | ||||
|  | ||||
| 		onVisibilitychange() { | ||||
| 			if (!document.hidden) { | ||||
| 				this.clearNotification(); | ||||
| 			} | ||||
| 		}, | ||||
|  | ||||
| 		onScroll() { | ||||
| 			if (this.isScrollTop()) { | ||||
| 				this.releaseQueue(); | ||||
| 				this.clearNotification(); | ||||
| 			} | ||||
|  | ||||
| 			if (this.$store.state.settings.fetchOnScroll !== false) { | ||||
|   | ||||
| @@ -4,7 +4,7 @@ | ||||
| 		<header> | ||||
| 			<button class="cancel" @click="cancel">%fa:times%</button> | ||||
| 			<div> | ||||
| 				<span class="text-count" :class="{ over: trimmedLength(text) > 1000 }">{{ 1000 - trimmedLength(text) }}</span> | ||||
| 				<span class="text-count" :class="{ over: trimmedLength(text) > this.maxNoteTextLength }">{{ this.maxNoteTextLength - trimmedLength(text) }}</span> | ||||
| 				<span class="geo" v-if="geo">%fa:map-marker-alt%</span> | ||||
| 				<button class="submit" :disabled="!canPost" @click="post">{{ submitText }}</button> | ||||
| 			</div> | ||||
| @@ -102,10 +102,17 @@ export default Vue.extend({ | ||||
| 			visibleUsers: [], | ||||
| 			useCw: false, | ||||
| 			cw: null, | ||||
| 			recentHashtags: JSON.parse(localStorage.getItem('hashtags') || '[]') | ||||
| 			recentHashtags: JSON.parse(localStorage.getItem('hashtags') || '[]'), | ||||
| 			maxNoteTextLength: 1000 | ||||
| 		}; | ||||
| 	}, | ||||
|  | ||||
| 	created() { | ||||
| 		(this as any).os.getMeta().then(meta => { | ||||
| 			this.maxNoteTextLength = meta.maxNoteTextLength; | ||||
| 		}); | ||||
| 	}, | ||||
|  | ||||
| 	computed: { | ||||
| 		draftId(): string { | ||||
| 			return this.renote | ||||
| @@ -144,7 +151,7 @@ export default Vue.extend({ | ||||
| 		canPost(): boolean { | ||||
| 			return !this.posting && | ||||
| 				(1 <= this.text.length || 1 <= this.files.length || this.poll || this.renote) && | ||||
| 				(this.text.trim().length <= 1000); | ||||
| 				(this.text.trim().length <= this.maxNoteTextLength); | ||||
| 		} | ||||
| 	}, | ||||
|  | ||||
|   | ||||
| @@ -5,7 +5,7 @@ | ||||
| 		<span v-if="note.deletedAt" style="opacity: 0.5">(%i18n:@deleted%)</span> | ||||
| 		<a class="reply" v-if="note.replyId">%fa:reply%</a> | ||||
| 		<misskey-flavored-markdown v-if="note.text" :text="note.text" :i="$store.state.i"/> | ||||
| 		<a class="rp" v-if="note.renoteId">RP: ...</a> | ||||
| 		<a class="rp" v-if="note.renoteId">RN: ...</a> | ||||
| 	</div> | ||||
| 	<details v-if="note.files.length > 0"> | ||||
| 		<summary>({{ '%i18n:@media-count%'.replace('{}', note.files.length) }})</summary> | ||||
|   | ||||
| @@ -5,7 +5,7 @@ | ||||
| 		<div class="signin-as" v-html="'%i18n:@signed-in-as%'.replace('{}', `<b>${name}</b>`)"></div> | ||||
|  | ||||
| 		<div> | ||||
| 			<x-profile/> | ||||
| 			<mk-profile-editor/> | ||||
|  | ||||
| 			<ui-card> | ||||
| 				<div slot="title">%fa:palette% %i18n:@theme%</div> | ||||
| @@ -148,13 +148,7 @@ import Vue from 'vue'; | ||||
| import { apiUrl, version, codename, langs } from '../../../config'; | ||||
| import checkForUpdate from '../../../common/scripts/check-for-update'; | ||||
|  | ||||
| import XProfile from './settings/settings.profile.vue'; | ||||
|  | ||||
| export default Vue.extend({ | ||||
| 	components: { | ||||
| 		XProfile | ||||
| 	}, | ||||
|  | ||||
| 	data() { | ||||
| 		return { | ||||
| 			apiUrl, | ||||
|   | ||||
| @@ -3,7 +3,7 @@ | ||||
| 	<template slot="header" v-if="!fetching"><img :src="user.avatarUrl" alt="">{{ user | userName }}</template> | ||||
| 	<main v-if="!fetching"> | ||||
| 		<div class="is-suspended" v-if="user.isSuspended"><p>%fa:exclamation-triangle% %i18n:@is-suspended%</p></div> | ||||
| 		<div class="is-remote" v-if="user.host != null"><p>%fa:exclamation-triangle% %i18n:@is-remote%<a :href="user.url || user.uri" target="_blank">%i18n:@view-remote%</a></p></div> | ||||
| 		<div class="is-remote" v-if="user.host != null"><p>%fa:exclamation-triangle% %i18n:common.is-remote-user%<a :href="user.url || user.uri" target="_blank">%i18n:common.view-on-remote%</a></p></div> | ||||
| 		<header> | ||||
| 			<div class="banner" :style="style"></div> | ||||
| 			<div class="body"> | ||||
|   | ||||
| @@ -5,11 +5,13 @@ import * as nestedProperty from 'nested-property'; | ||||
| import MiOS from './mios'; | ||||
| import { hostname } from './config'; | ||||
| import { erase } from '../../prelude/array'; | ||||
| import getNoteSummary from '../../misc/get-note-summary'; | ||||
|  | ||||
| const defaultSettings = { | ||||
| 	home: null, | ||||
| 	mobileHome: [], | ||||
| 	deck: null, | ||||
| 	deckNav: true, | ||||
| 	tagTimelines: [], | ||||
| 	fetchOnScroll: true, | ||||
| 	showMaps: true, | ||||
| @@ -57,7 +59,10 @@ const defaultDeviceSettings = { | ||||
| 	alwaysShowNsfw: false, | ||||
| 	postStyle: 'standard', | ||||
| 	navbar: 'top', | ||||
| 	mobileNotificationPosition: 'bottom' | ||||
| 	deckColumnAlign: 'center', | ||||
| 	mobileNotificationPosition: 'bottom', | ||||
| 	deckTemporaryColumn: null, | ||||
| 	deckDefault: false | ||||
| }; | ||||
|  | ||||
| export default (os: MiOS) => new Vuex.Store({ | ||||
| @@ -68,7 +73,9 @@ export default (os: MiOS) => new Vuex.Store({ | ||||
| 	state: { | ||||
| 		i: null, | ||||
| 		indicate: false, | ||||
| 		uiHeaderHeight: 0 | ||||
| 		uiHeaderHeight: 0, | ||||
| 		navHook: null, | ||||
| 		behindNotes: [] | ||||
| 	}, | ||||
|  | ||||
| 	getters: { | ||||
| @@ -90,6 +97,22 @@ export default (os: MiOS) => new Vuex.Store({ | ||||
|  | ||||
| 		setUiHeaderHeight(state, height) { | ||||
| 			state.uiHeaderHeight = height; | ||||
| 		}, | ||||
|  | ||||
| 		navHook(state, callback) { | ||||
| 			state.navHook = callback; | ||||
| 		}, | ||||
|  | ||||
| 		pushBehindNote(state, note) { | ||||
| 			if (note.userId === state.i.id) return; | ||||
| 			if (state.behindNotes.some(n => n.id === note.id)) return; | ||||
| 			state.behindNotes.push(note); | ||||
| 			document.title = `(${state.behindNotes.length}) ${getNoteSummary(note)}`; | ||||
| 		}, | ||||
|  | ||||
| 		clearBehindNotes(state) { | ||||
| 			state.behindNotes = []; | ||||
| 			document.title = os.instanceName; | ||||
| 		} | ||||
| 	}, | ||||
|  | ||||
|   | ||||
| @@ -174,6 +174,7 @@ | ||||
| 		desktopSettingsNavItemHover: ':lighten<10<$text', | ||||
|  | ||||
| 		deckAcrylicColumnBg: 'rgba(0, 0, 0, 0.25)', | ||||
| 		deckColumnBg: ':darken<3<@face', | ||||
|  | ||||
| 		mobileHeaderBg: ':lighten<5<$secondary', | ||||
| 		mobileHeaderFg: '$text', | ||||
|   | ||||
| @@ -174,6 +174,7 @@ | ||||
| 		desktopSettingsNavItemHover: ':darken<10<$text', | ||||
|  | ||||
| 		deckAcrylicColumnBg: 'rgba(0, 0, 0, 0.1)', | ||||
| 		deckColumnBg: ':darken<4<@face', | ||||
|  | ||||
| 		mobileHeaderBg: ':lighten<5<$secondary', | ||||
| 		mobileHeaderFg: '$text', | ||||
|   | ||||
| @@ -49,6 +49,8 @@ export default function load() { | ||||
| 	if (config.localDriveCapacityMb == null) config.localDriveCapacityMb = 256; | ||||
| 	if (config.remoteDriveCapacityMb == null) config.remoteDriveCapacityMb = 8; | ||||
|  | ||||
| 	if (config.maxNoteTextLength == null) config.maxNoteTextLength = 1000; | ||||
|  | ||||
| 	if (config.name == null) config.name = 'Misskey'; | ||||
|  | ||||
| 	return Object.assign(config, mixin); | ||||
|   | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user