Compare commits
	
		
			346 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | ae36bf301a | ||
|   | 6a5a9de795 | ||
|   | f0abc46429 | ||
|   | 9fd4f5ee0a | ||
|   | 5e202c3def | ||
|   | 48223c1c76 | ||
|   | dddf7834cc | ||
|   | 66ef30b2cc | ||
|   | f802fe57b9 | ||
|   | ead884ce89 | ||
| ![greenkeeper[bot]](/assets/img/avatar_default.png)  | 6a87e9f690 | ||
| ![greenkeeper[bot]](/assets/img/avatar_default.png)  | 5b943722fb | ||
|   | 4d92b14308 | ||
|   | 167c96d14e | ||
|   | 8a42373753 | ||
|   | c1751a9b84 | ||
|   | 4e11da98d9 | ||
|   | 1b7d98c17e | ||
|   | 3038434712 | ||
|   | 117ab633a1 | ||
|   | e50fa4762d | ||
|   | aed1e839ba | ||
|   | 00f2974a2a | ||
| ![greenkeeper[bot]](/assets/img/avatar_default.png)  | 073c96af47 | ||
|   | 71da498364 | ||
|   | 8e9c11f160 | ||
| ![greenkeeper[bot]](/assets/img/avatar_default.png)  | 98f6b23249 | ||
|   | 89288d8e0d | ||
|   | 724121eeaa | ||
|   | edee95a5ca | ||
|   | 0c2361bf72 | ||
|   | 92f8dc48e3 | ||
|   | 06a0fff4b0 | ||
|   | d55e4621ac | ||
|   | bc6bda3714 | ||
|   | d3aafd3f13 | ||
|   | 1a508de1c4 | ||
|   | 768cc0aff5 | ||
|   | 67f4c1f429 | ||
|   | 2d4ceec0a5 | ||
|   | 3e2a0cd89a | ||
|   | d1f4f2f663 | ||
|   | 6e3bf26cad | ||
|   | 672377f116 | ||
|   | 80ee5afba7 | ||
|   | f55fcd3305 | ||
|   | 64fc14ade5 | ||
|   | 807f245657 | ||
| ![greenkeeper[bot]](/assets/img/avatar_default.png)  | 62f966dc27 | ||
|   | 09f97bf7a7 | ||
|   | 69460e494c | ||
| ![greenkeeper[bot]](/assets/img/avatar_default.png)  | 9bef723346 | ||
| ![greenkeeper[bot]](/assets/img/avatar_default.png)  | b99eabb2cf | ||
|   | 17be3f3d0f | ||
|   | 05fe2cb173 | ||
|   | 428be14c27 | ||
|   | a04fa8441e | ||
|   | 7bcfa84e1a | ||
|   | 1cc5986df3 | ||
|   | 7aa5d03875 | ||
|   | a59fbfac19 | ||
|   | 677f9ee8f6 | ||
|   | f4a16be2b4 | ||
|   | 46b967ee4a | ||
|   | 78568accd1 | ||
|   | e9f20a0fad | ||
|   | bbd9894e6b | ||
|   | f92745e381 | ||
|   | 2762b78bcc | ||
|   | 2d4ed2c8c2 | ||
|   | 2de8e8c358 | ||
|   | eb7b638db3 | ||
|   | 321e851b26 | ||
| ![greenkeeper[bot]](/assets/img/avatar_default.png)  | f8340be3bf | ||
|   | 02341ceb6e | ||
|   | 3dcdd7a5d7 | ||
|   | b721d049c6 | ||
|   | e518fff944 | ||
|   | 048128c7e1 | ||
|   | d3717449c2 | ||
|   | 04de6218d3 | ||
|   | 0082473d78 | ||
|   | 77baca8e6e | ||
|   | 6a7169630c | ||
|   | 6b2089e043 | ||
|   | 14ad3af30d | ||
|   | e7e6d833b7 | ||
|   | d1a9561135 | ||
| ![greenkeeper[bot]](/assets/img/avatar_default.png)  | c7bda6f908 | ||
|   | ef43721e32 | ||
| ![greenkeeper[bot]](/assets/img/avatar_default.png)  | ba6cd874aa | ||
|   | f283d2423f | ||
|   | c07f668f14 | ||
|   | 596524a63c | ||
|   | 975e4dd285 | ||
|   | 09b05c8552 | ||
|   | 530ee6f80e | ||
|   | 6ad31dca76 | ||
|   | d423f8ae57 | ||
|   | 8e5ce7f8e3 | ||
|   | 33dfc21e4b | ||
|   | 3266f3948a | ||
|   | 7259887124 | ||
|   | 800de03187 | ||
|   | 78ba305e5c | ||
|   | bfed1475bb | ||
|   | 3281d263c4 | ||
|   | a9a1798e3a | ||
| ![greenkeeper[bot]](/assets/img/avatar_default.png)  | 6806eafaed | ||
|   | 3e20ea5b2e | ||
|   | 3f30a69b8b | ||
|   | 2d2e16d9f6 | ||
|   | 9c32118b77 | ||
|   | ecf2eb4738 | ||
|   | 3d754ea7eb | ||
|   | f755f24560 | ||
|   | 699879d95d | ||
|   | 6677508ba7 | ||
|   | 58da32358b | ||
|   | 491bc75095 | ||
|   | b9eafeee3f | ||
|   | c56ff5d88d | ||
|   | f5dd83a44a | ||
|   | 9a295a85b1 | ||
|   | 8e06d93c31 | ||
|   | 1a42200137 | ||
|   | bbf33d2475 | ||
|   | 93203ebfd1 | ||
|   | 67053eeaa0 | ||
|   | 43baf4ad6a | ||
|   | 5b2a36e47b | ||
|   | 2a0862a24e | ||
|   | ce31027b2e | ||
|   | 3f66c77821 | ||
|   | bc713656ec | ||
|   | 46d89faebc | ||
|   | 7135c0e308 | ||
|   | 1962bfb4a5 | ||
|   | a1fca2550e | ||
|   | c17f99b7a5 | ||
|   | 7cd76d60c2 | ||
|   | fa7c8cfe5b | ||
|   | 05fb8d35af | ||
|   | eaa827e2d9 | ||
|   | f365ea4585 | ||
|   | 5d2e43ffb9 | ||
|   | e9a97ed99a | ||
|   | fe98102600 | ||
|   | aae8845664 | ||
|   | 81a4388ecc | ||
|   | be3ab026fd | ||
|   | f92f9d8cb0 | ||
|   | 08a59591ae | ||
|   | a09a244242 | ||
|   | 483a61d90d | ||
|   | 385fb7586b | ||
| ![greenkeeper[bot]](/assets/img/avatar_default.png)  | c624da70ef | ||
|   | 675668c395 | ||
| ![greenkeeper[bot]](/assets/img/avatar_default.png)  | bc9c7efe85 | ||
|   | 2488d40421 | ||
|   | bf7875bfaa | ||
|   | a84fa30774 | ||
|   | c19a763b3d | ||
|   | 0875460974 | ||
|   | f0b08d3936 | ||
|   | 16520c7b4c | ||
|   | 65549d06d9 | ||
|   | 52da66d550 | ||
|   | 251c3c3fe4 | ||
| ![greenkeeper[bot]](/assets/img/avatar_default.png)  | ce2d2a10c1 | ||
|   | 3b6d242ef6 | ||
|   | 0ebe801af4 | ||
|   | 05daa7ac7d | ||
|   | 990a583e5e | ||
|   | d9b02a18bf | ||
|   | 30aae79e5c | ||
|   | a149c121fb | ||
|   | 47f4b51207 | ||
|   | 79f4d886d0 | ||
|   | 2b556aba03 | ||
|   | 4f62043b0c | ||
|   | b1ae304c51 | ||
|   | 425bc032d0 | ||
|   | 0156b75bde | ||
|   | 8bc8fc58de | ||
|   | 9bf847b1fb | ||
|   | 0b078d203b | ||
|   | df59018b47 | ||
|   | b2681dcb5d | ||
|   | 46fa471636 | ||
|   | 5f2c441996 | ||
|   | a79cc42b26 | ||
|   | 739c993911 | ||
|   | cb180e00de | ||
|   | 4d46a61051 | ||
|   | 81969ea8b2 | ||
|   | ac474f3884 | ||
|   | a39aaf6eb1 | ||
|   | 68a7661f08 | ||
|   | ffcb2f755c | ||
| ![greenkeeper[bot]](/assets/img/avatar_default.png)  | 366e0d6bde | ||
|   | b3a3238e43 | ||
|   | 92828028db | ||
|   | bd97e315ff | ||
|   | 51083419f5 | ||
|   | b23bfd4d86 | ||
|   | 7de3e847bd | ||
|   | 0d1a541dba | ||
|   | 2717109fe2 | ||
|   | 60ca0626ce | ||
|   | 15dae0ae65 | ||
|   | 1c680118a0 | ||
|   | ad5efbba59 | ||
|   | 6dc7baa5e9 | ||
|   | c2b886e750 | ||
|   | edb61e52c5 | ||
|   | ded297b04c | ||
|   | 65e1d5978a | ||
|   | 86e76358b1 | ||
|   | 435e0257a4 | ||
|   | 1c45cc808b | ||
|   | ed27a2f963 | ||
|   | 1f53d1a149 | ||
|   | 8295f6d7a3 | ||
|   | b02f6341c9 | ||
|   | f6d577d411 | ||
|   | db3e73318e | ||
|   | 29c2071711 | ||
|   | 3acd524d09 | ||
|   | dae65cc123 | ||
|   | 695f154d87 | ||
|   | 59dca9a812 | ||
|   | b9f04f8f53 | ||
|   | 0985f14f18 | ||
|   | 56684dd7c3 | ||
|   | 47a5f3bc67 | ||
|   | 1c1e3009e9 | ||
|   | c7c3f6999b | ||
|   | fb4aa9bc1c | ||
|   | ef57f5907b | ||
|   | eff44f9cd1 | ||
|   | d7fa92d58f | ||
|   | 4e8033d5a4 | ||
|   | 8a207d8311 | ||
|   | 94ba9c8437 | ||
|   | 88c71c2998 | ||
|   | 7b6e55047f | ||
|   | 9d85d0bb08 | ||
|   | 27ac0bbc00 | ||
|   | affde9b4e2 | ||
|   | 88324b6dd9 | ||
|   | 9b95ffe6c6 | ||
|   | 6b137f8d69 | ||
|   | e78b2b0ab8 | ||
|   | 8b51428347 | ||
|   | b8d53a7b40 | ||
|   | b0d9e9caa2 | ||
|   | 1fc4ec8dc1 | ||
|   | a1e1e25800 | ||
|   | 3b020732ec | ||
|   | dcf92945fe | ||
|   | f9f33903d4 | ||
|   | d8bf06ab0f | ||
|   | 806dabe58b | ||
|   | a17b8c56d7 | ||
|   | 0eaaaba8f2 | ||
|   | f359d79d36 | ||
|   | 1d84000d94 | ||
|   | b70e22c150 | ||
|   | 0774ffe376 | ||
|   | 0096d7d8ac | ||
|   | 38db966b3d | ||
|   | cb7d313a66 | ||
|   | 91b7905f3f | ||
|   | 9a81fba992 | ||
|   | 43553d5c09 | ||
|   | e0ca8ce173 | ||
|   | 13624ea7c2 | ||
|   | 9502586c8b | ||
| ![greenkeeper[bot]](/assets/img/avatar_default.png)  | d6753f2cf2 | ||
|   | a60ae130c1 | ||
|   | dd88acd411 | ||
|   | b63fc1a9e5 | ||
|   | 17f143cfb2 | ||
|   | cf57d847d1 | ||
|   | 7c4c7bea14 | ||
|   | e5ec47fc75 | ||
|   | ad91dc2423 | ||
|   | 7acbe53948 | ||
|   | fe1b8ba0cb | ||
|   | b0a8a51b69 | ||
|   | c3ca21e610 | ||
|   | 4e7382b793 | ||
|   | 552ff4a044 | ||
|   | afb52a0cd5 | ||
|   | 1ac89b0f5b | ||
|   | 5039ca7ee1 | ||
|   | a48fd9ce18 | ||
|   | 58859c4811 | ||
|   | 5988fb3111 | ||
|   | 8dce821789 | ||
|   | 16fde0b507 | ||
|   | 9723662706 | ||
|   | df4415b4fe | ||
|   | f54529d46f | ||
|   | b772add064 | ||
|   | 231f2e77a4 | ||
|   | a000a9e607 | ||
|   | e8da15ab1e | ||
|   | e070ccb313 | ||
|   | 2b06579228 | ||
|   | 853c847ba1 | ||
|   | e852680b0a | ||
|   | 0b0ee915b3 | ||
|   | 516d1d093f | ||
|   | aee9c79c0f | ||
|   | 2d185becc3 | ||
|   | 67fff324b0 | ||
|   | f64b7fcabc | ||
|   | 4cefa16db6 | ||
|   | 22722379df | ||
|   | b2b83dc45d | ||
|   | ebf6f8bbfd | ||
|   | 3e1631d180 | ||
|   | 97cb3c8613 | ||
|   | 6dda3a5d8a | ||
|   | e50b0540f5 | ||
|   | 63b4aee9bd | ||
| ![greenkeeper[bot]](/assets/img/avatar_default.png)  | b70e9824ac | ||
| ![greenkeeper[bot]](/assets/img/avatar_default.png)  | 155d49e8ac | ||
| ![greenkeeper[bot]](/assets/img/avatar_default.png)  | 4ae10ab33d | ||
|   | 7124586eb1 | ||
|   | 74f6ed1851 | ||
|   | 1d9c88e9a1 | ||
|   | 8eb8243153 | ||
|   | b4967b862c | ||
|   | aee3517736 | ||
|   | 52ff8e84fa | ||
|   | 9bb6db649c | ||
|   | da99be9897 | ||
|   | 2d7ec8a471 | ||
|   | 4cbbfdad1a | ||
|   | 2924858311 | ||
|   | 85916bfea1 | ||
|   | 38ccd9e794 | ||
|   | c64b6be915 | 
| @@ -138,3 +138,6 @@ drive: | ||||
|  | ||||
| # Clustering | ||||
| # clusterLimit: 1 | ||||
|  | ||||
| # Summaly proxy | ||||
| # summalyProxy: "http://example.com" | ||||
|   | ||||
| @@ -57,6 +57,7 @@ Misskey is using Crowdin for l10n. | ||||
| <td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12731202/0995c46cdcb54153ab5f073f5869b70a/1?token-time=2145916800&token-hash=Yd60FK_SWfQO56SeiJpy1tDHOnCV4xdEywQe8gn5_Wo%3D" alt="negao"></td> | ||||
| <td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/13099460/43cecdbaa63a40d79bf50a96b9910b9d/1?token-time=2145916800&token-hash=d6P5MWHHsCMxUuBAEPAoVc5wLUR19mIhqAq7Ma9h9rI%3D" alt="ne_moni"></td> | ||||
| <td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12913507/f7181eacafe8469a93033d85f5969c29/1?token-time=2145916800&token-hash=f03BFb4S2FUx9YEt87TnEmifb4h33OywGBW2akQVtQY%3D" alt="Melilot"></td> | ||||
| <td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12999811/5f349fafcce44dd1824a8b1ebbec4564/1?token-time=2145916800&token-hash=DVrSdOqQq2dufgNgWZ3XMnEtl_ZAktr8Lhf2tbHKtoA%3D" alt="Axella"></td> | ||||
| <td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/3384329/8b713330cb27404ea6e9fac50ff96efe/1?token-time=2145916800&token-hash=0eu4-m1gTWA9PhptVZt6rdKcusqcD7RB87rJT23VVFI%3D" alt="べすれい"></td> | ||||
| <td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12021162/963128bb8d14476dbd8407943db8f31a/1?token-time=2145916800&token-hash=GgJ_NmUB6_nnRNLVGUWjV-WX91On7BOu59LKncYV9fE%3D" alt="gutfuckllc"></td> | ||||
| <td><img src="https://c8.patreon.com/2/100/12718187" alt="Peter G."></td> | ||||
| @@ -66,6 +67,7 @@ Misskey is using Crowdin for l10n. | ||||
| <td><a href="https://www.patreon.com/user?u=12731202">negao</a></td> | ||||
| <td><a href="https://www.patreon.com/user?u=13099460">ne_moni</a></td> | ||||
| <td><a href="https://www.patreon.com/user?u=12913507">Melilot</a></td> | ||||
| <td><a href="https://www.patreon.com/AxellaMC">Axella</a></td> | ||||
| <td><a href="https://www.patreon.com/user?u=3384329">べすれい</a></td> | ||||
| <td><a href="https://www.patreon.com/gutfuckllc">gutfuckllc</a></td> | ||||
| <td><a href="https://www.patreon.com/user?u=12718187">Peter G.</a></td> | ||||
| @@ -89,7 +91,7 @@ Misskey is using Crowdin for l10n. | ||||
| <td><a href="https://www.patreon.com/fujishan">fujishan</a></td> | ||||
| </tr></table> | ||||
|  | ||||
| **Last updated:** Wed, 22 Aug 2018 05:25:06 UTC | ||||
| **Last updated:** Sun, 26 Aug 2018 08:55:06 UTC | ||||
| <!-- PATREON_END --> | ||||
|  | ||||
| :four_leaf_clover: Copyright | ||||
|   | ||||
| @@ -1,40 +0,0 @@ | ||||
| const { default: User, deleteUser } = require('../built/models/user'); | ||||
| const { default: zip } = require('@prezzemolo/zip') | ||||
|  | ||||
| const migrate = async (user) => { | ||||
| 	try { | ||||
| 		await deleteUser(user._id); | ||||
| 		return true; | ||||
| 	} catch (e) { | ||||
| 		return false; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| async function main() { | ||||
| 	const count = await User.count({ | ||||
| 		uri: /#/ | ||||
| 	}); | ||||
|  | ||||
| 	const dop = 1 | ||||
| 	const idop = ((count - (count % dop)) / dop) + 1 | ||||
|  | ||||
| 	return zip( | ||||
| 		1, | ||||
| 		async (time) => { | ||||
| 			console.log(`${time} / ${idop}`) | ||||
| 			const doc = await User.find({ | ||||
| 				uri: /#/ | ||||
| 			}, { | ||||
| 				limit: dop, skip: time * dop | ||||
| 			}) | ||||
| 			return Promise.all(doc.map(migrate)) | ||||
| 		}, | ||||
| 		idop | ||||
| 	).then(a => { | ||||
| 		const rv = [] | ||||
| 		a.forEach(e => rv.push(...e)) | ||||
| 		return rv | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| main().then(console.dir).catch(console.error) | ||||
| @@ -58,7 +58,7 @@ common: | ||||
|     friday: "金曜日" | ||||
|     saturday: "土曜日" | ||||
|   reactions: | ||||
|     like: "ええやん" | ||||
|     like: "いいね" | ||||
|     love: "しゅき" | ||||
|     laugh: "笑" | ||||
|     hmm: "ふぅ~む" | ||||
| @@ -84,6 +84,7 @@ common: | ||||
|   my-token-regenerated: "あなたのトークンが更新されたのでサインアウトします。" | ||||
|   i-like-sushi: "私は(プリンよりむしろ)寿司が好き" | ||||
|   show-reversi-board-labels: "リバーシのボードの行と列のラベルを表示" | ||||
|   use-contrast-reversi-stones: "リバーシのアイコンにコントラストを付ける" | ||||
|   verified-user: "公式アカウント" | ||||
|   disable-animated-mfm: "投稿内の動きのあるテキストを無効にする" | ||||
|   reversi: | ||||
| @@ -410,6 +411,7 @@ desktop: | ||||
|   uploading-avatar: "新しいアバターをアップロードしています" | ||||
|   avatar-updated: "アバターを更新しました" | ||||
|   choose-avatar: "アバターにする画像を選択" | ||||
|   invalid-filetype: "この形式のファイルはサポートされていません" | ||||
| desktop/views/components/activity.chart.vue: | ||||
|   total: "Black ... Total" | ||||
|   notes: "Blue ... Notes" | ||||
| @@ -423,6 +425,24 @@ desktop/views/components/calendar.vue: | ||||
|   prev: "前の月" | ||||
|   next: "次の月" | ||||
|   go: "クリックして時間遡行" | ||||
| desktop/views/components/charts.vue: | ||||
|   title: "チャート" | ||||
|   per-day: "1日ごと" | ||||
|   per-hour: "1時間ごと" | ||||
|   notes: "投稿" | ||||
|   users: "ユーザー" | ||||
|   drive: "ドライブ" | ||||
|   charts: | ||||
|     notes: "投稿の増減 (統合)" | ||||
|     local-notes: "投稿の増減 (ローカル)" | ||||
|     remote-notes: "投稿の増減 (リモート)" | ||||
|     notes-total: "投稿の累計" | ||||
|     users: "ユーザーの増減" | ||||
|     users-total: "ユーザーの累計" | ||||
|     drive: "ドライブ使用量の増減" | ||||
|     drive-total: "ドライブ使用量の累計" | ||||
|     drive-files: "ドライブのファイル数の増減" | ||||
|     drive-files-total: "ドライブのファイル数の累計" | ||||
| desktop/views/components/choose-file-from-drive-window.vue: | ||||
|   choose-file: "ファイル選択中" | ||||
|   upload: "PCからドライブにファイルをアップロード" | ||||
| @@ -630,6 +650,7 @@ desktop/views/components/settings.vue: | ||||
|   gradient-window-header: "ウィンドウのタイトルバーにグラデーションを使用" | ||||
|   post-form-on-timeline: "タイムライン上部に投稿フォームを表示する" | ||||
|   suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する" | ||||
|   show-clock-on-header: "右上に時計を表示する" | ||||
|   show-reply-target: "リプライ先を表示する" | ||||
|   show-my-renotes: "自分の行ったRenoteをタイムラインに表示する" | ||||
|   show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する" | ||||
| @@ -754,6 +775,7 @@ desktop/views/components/ui.header.account.vue: | ||||
|   lists: "リスト" | ||||
|   follow-requests: "フォロー申請" | ||||
|   customize: "ホームのカスタマイズ" | ||||
|   admin: "管理" | ||||
|   settings: "設定" | ||||
|   signout: "サインアウト" | ||||
|   dark: "闇に飲まれる" | ||||
| @@ -799,8 +821,8 @@ desktop/views/pages/admin/admin.dashboard.vue: | ||||
|   dashboard: "ダッシュボード" | ||||
|   all-users: "全てのユーザー" | ||||
|   original-users: "このインスタンスのユーザー" | ||||
|   all-notes: "全てのノート" | ||||
|   original-notes: "このインスタンスのノート" | ||||
|   all-notes: "全ての投稿" | ||||
|   original-notes: "このインスタンスの投稿" | ||||
|   invite: "招待" | ||||
| desktop/views/pages/admin/admin.suspend-user.vue: | ||||
|   suspend-user: "ユーザーの凍結" | ||||
| @@ -818,18 +840,6 @@ desktop/views/pages/admin/admin.unverify-user.vue: | ||||
|   unverify-user: "ユーザーの公式アカウント解除" | ||||
|   unverify: "公式アカウントを解除する" | ||||
|   unverified: "公式アカウントを解除しました" | ||||
| desktop/views/pages/admin/admin.notes-chart.vue: | ||||
|   title: "投稿" | ||||
|   local: "ローカル" | ||||
|   remote: "リモート" | ||||
| desktop/views/pages/admin/admin.users-chart.vue: | ||||
|   title: "ユーザー" | ||||
|   local: "ローカル" | ||||
|   remote: "リモート" | ||||
| desktop/views/pages/admin/admin.drive-chart.vue: | ||||
|   title: "ドライブ" | ||||
|   local: "ローカル" | ||||
|   remote: "リモート" | ||||
| desktop/views/pages/deck/deck.tl-column.vue: | ||||
|   is-media-only: "メディア投稿のみ" | ||||
|   is-media-view: "メディアビュー" | ||||
| @@ -838,6 +848,11 @@ desktop/views/pages/deck/deck.note.vue: | ||||
|   reposted-by: "{}がRenote" | ||||
|   private: "この投稿は非公開です" | ||||
|   deleted: "この投稿は削除されました" | ||||
| desktop/views/pages/stats/stats.vue: | ||||
|   all-users: "全てのユーザー" | ||||
|   original-users: "このインスタンスのユーザー" | ||||
|   all-notes: "全ての投稿" | ||||
|   original-notes: "このインスタンスの投稿" | ||||
| desktop/views/pages/welcome.vue: | ||||
|   about: "詳しく..." | ||||
|   gotit: "わかった" | ||||
| @@ -1044,6 +1059,7 @@ mobile/views/components/ui.nav.vue: | ||||
|   game: "ゲーム" | ||||
|   darkmode: "ダークモード" | ||||
|   settings: "設定" | ||||
|   admin: "管理" | ||||
|   about: "Misskeyについて" | ||||
| mobile/views/components/user-timeline.vue: | ||||
|   no-notes: "このユーザーは投稿していないようです。" | ||||
| @@ -1161,6 +1177,8 @@ mobile/views/pages/settings.vue: | ||||
|   update-available-desc: "ページを再度読み込みすると更新が適用されます。" | ||||
|   settings: "設定" | ||||
|   signout: "サインアウト" | ||||
|   sound: "サウンド" | ||||
|   enableSounds: "サウンドを有効にする" | ||||
| mobile/views/pages/user.vue: | ||||
|   follows-you: "フォローされています" | ||||
|   following: "フォロー" | ||||
|   | ||||
| @@ -58,7 +58,7 @@ common: | ||||
|     friday: "金曜日" | ||||
|     saturday: "土曜日" | ||||
|   reactions: | ||||
|     like: "ええやん" | ||||
|     like: "いいね" | ||||
|     love: "Lieben" | ||||
|     laugh: "Lachen" | ||||
|     hmm: "Hmm...?" | ||||
| @@ -84,6 +84,7 @@ common: | ||||
|   my-token-regenerated: "Dein Token wurde generiert. Du wirst jetzt abgemeldet." | ||||
|   i-like-sushi: "私は(プリンよりむしろ)寿司が好き" | ||||
|   show-reversi-board-labels: "リバーシのボードの行と列のラベルを表示" | ||||
|   use-contrast-reversi-stones: "リバーシのアイコンにコントラストを付ける" | ||||
|   verified-user: "公式アカウント" | ||||
|   disable-animated-mfm: "投稿内の動きのあるテキストを無効にする" | ||||
|   reversi: | ||||
| @@ -410,6 +411,7 @@ desktop: | ||||
|   uploading-avatar: "新しいアバターをアップロードしています" | ||||
|   avatar-updated: "アバターを更新しました" | ||||
|   choose-avatar: "アバターにする画像を選択" | ||||
|   invalid-filetype: "この形式のファイルはサポートされていません" | ||||
| desktop/views/components/activity.chart.vue: | ||||
|   total: "Schwarz ... komplett" | ||||
|   notes: "Blau ... Hinweise" | ||||
| @@ -423,6 +425,24 @@ desktop/views/components/calendar.vue: | ||||
|   prev: "Vorheriger Monat" | ||||
|   next: "Nächster Monat" | ||||
|   go: "Klicke zur Navigation" | ||||
| desktop/views/components/charts.vue: | ||||
|   title: "チャート" | ||||
|   per-day: "1日ごと" | ||||
|   per-hour: "1時間ごと" | ||||
|   notes: "投稿" | ||||
|   users: "ユーザー" | ||||
|   drive: "ドライブ" | ||||
|   charts: | ||||
|     notes: "投稿の増減 (統合)" | ||||
|     local-notes: "投稿の増減 (ローカル)" | ||||
|     remote-notes: "投稿の増減 (リモート)" | ||||
|     notes-total: "投稿の累計" | ||||
|     users: "ユーザーの増減" | ||||
|     users-total: "ユーザーの累計" | ||||
|     drive: "ドライブ使用量の増減" | ||||
|     drive-total: "ドライブ使用量の累計" | ||||
|     drive-files: "ドライブのファイル数の増減" | ||||
|     drive-files-total: "ドライブのファイル数の累計" | ||||
| desktop/views/components/choose-file-from-drive-window.vue: | ||||
|   choose-file: "Datei auswählen" | ||||
|   upload: "Dateien von deinem PC hochladen" | ||||
| @@ -630,6 +650,7 @@ desktop/views/components/settings.vue: | ||||
|   gradient-window-header: "Übergang in Fensterköpfen" | ||||
|   post-form-on-timeline: "タイムライン上部に投稿フォームを表示する" | ||||
|   suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する" | ||||
|   show-clock-on-header: "右上に時計を表示する" | ||||
|   show-reply-target: "Zeige Antworten" | ||||
|   show-my-renotes: "Zeige meine Reposts auf der Zeitleiste" | ||||
|   show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する" | ||||
| @@ -754,6 +775,7 @@ desktop/views/components/ui.header.account.vue: | ||||
|   lists: "Listen" | ||||
|   follow-requests: "フォロー申請" | ||||
|   customize: "ホームのカスタマイズ" | ||||
|   admin: "管理" | ||||
|   settings: "Einstellungen" | ||||
|   signout: "Ausloggen" | ||||
|   dark: "Verdunkeln" | ||||
| @@ -799,8 +821,8 @@ desktop/views/pages/admin/admin.dashboard.vue: | ||||
|   dashboard: "ダッシュボード" | ||||
|   all-users: "全てのユーザー" | ||||
|   original-users: "このインスタンスのユーザー" | ||||
|   all-notes: "全てのノート" | ||||
|   original-notes: "このインスタンスのノート" | ||||
|   all-notes: "全ての投稿" | ||||
|   original-notes: "このインスタンスの投稿" | ||||
|   invite: "招待" | ||||
| desktop/views/pages/admin/admin.suspend-user.vue: | ||||
|   suspend-user: "ユーザーの凍結" | ||||
| @@ -818,18 +840,6 @@ desktop/views/pages/admin/admin.unverify-user.vue: | ||||
|   unverify-user: "ユーザーの公式アカウント解除" | ||||
|   unverify: "公式アカウントを解除する" | ||||
|   unverified: "公式アカウントを解除しました" | ||||
| desktop/views/pages/admin/admin.notes-chart.vue: | ||||
|   title: "投稿" | ||||
|   local: "ローカル" | ||||
|   remote: "リモート" | ||||
| desktop/views/pages/admin/admin.users-chart.vue: | ||||
|   title: "ユーザー" | ||||
|   local: "ローカル" | ||||
|   remote: "リモート" | ||||
| desktop/views/pages/admin/admin.drive-chart.vue: | ||||
|   title: "ドライブ" | ||||
|   local: "ローカル" | ||||
|   remote: "リモート" | ||||
| desktop/views/pages/deck/deck.tl-column.vue: | ||||
|   is-media-only: "メディア投稿のみ" | ||||
|   is-media-view: "メディアビュー" | ||||
| @@ -838,6 +848,11 @@ desktop/views/pages/deck/deck.note.vue: | ||||
|   reposted-by: "{}がRenote" | ||||
|   private: "この投稿は非公開です" | ||||
|   deleted: "この投稿は削除されました" | ||||
| desktop/views/pages/stats/stats.vue: | ||||
|   all-users: "全てのユーザー" | ||||
|   original-users: "このインスタンスのユーザー" | ||||
|   all-notes: "全ての投稿" | ||||
|   original-notes: "このインスタンスの投稿" | ||||
| desktop/views/pages/welcome.vue: | ||||
|   about: "詳しく..." | ||||
|   gotit: "わかった" | ||||
| @@ -1044,6 +1059,7 @@ mobile/views/components/ui.nav.vue: | ||||
|   game: "ゲーム" | ||||
|   darkmode: "ダークモード" | ||||
|   settings: "設定" | ||||
|   admin: "管理" | ||||
|   about: "Misskeyについて" | ||||
| mobile/views/components/user-timeline.vue: | ||||
|   no-notes: "このユーザーは投稿していないようです。" | ||||
| @@ -1161,6 +1177,8 @@ mobile/views/pages/settings.vue: | ||||
|   update-available-desc: "ページを再度読み込みすると更新が適用されます。" | ||||
|   settings: "設定" | ||||
|   signout: "サインアウト" | ||||
|   sound: "サウンド" | ||||
|   enableSounds: "サウンドを有効にする" | ||||
| mobile/views/pages/user.vue: | ||||
|   follows-you: "フォローされています" | ||||
|   following: "フォロー" | ||||
|   | ||||
| @@ -84,6 +84,7 @@ common: | ||||
|   my-token-regenerated: "Your token has been regenerated, so you will be signed out." | ||||
|   i-like-sushi: "I prefer sushi rather than pudding" | ||||
|   show-reversi-board-labels: "Show row and column labels in Reversi" | ||||
|   use-contrast-reversi-stones: "Make the stone color clear" | ||||
|   verified-user: "Verified account" | ||||
|   disable-animated-mfm: "Disable animated texts in a post" | ||||
|   reversi: | ||||
| @@ -410,6 +411,7 @@ desktop: | ||||
|   uploading-avatar: "Uploading a new avatar" | ||||
|   avatar-updated: "Successfully updated the avatar" | ||||
|   choose-avatar: "Select an image for the avatar" | ||||
|   invalid-filetype: "This filetype is not acceptable here" | ||||
| desktop/views/components/activity.chart.vue: | ||||
|   total: "Black ... Total" | ||||
|   notes: "Blue ... Notes" | ||||
| @@ -423,6 +425,24 @@ desktop/views/components/calendar.vue: | ||||
|   prev: "Previous month" | ||||
|   next: "Next month" | ||||
|   go: "Click to navigate" | ||||
| desktop/views/components/charts.vue: | ||||
|   title: "Charts" | ||||
|   per-day: "per Day" | ||||
|   per-hour: "per Hour" | ||||
|   notes: "Posts" | ||||
|   users: "Users" | ||||
|   drive: "Drive" | ||||
|   charts: | ||||
|     notes: "The number of posts: increase/decrease (Combined)" | ||||
|     local-notes: "The number of posts: increase/decrease (Local)" | ||||
|     remote-notes: "The number of posts: increase/decrease (Remote)" | ||||
|     notes-total: "The number of posts: cumulative total" | ||||
|     users: "The number of users: increase/decrease" | ||||
|     users-total: "The number of users: cumulative total" | ||||
|     drive: "Capacity used as the storage: increase/decrease" | ||||
|     drive-total: "Capacity used as the storage: cumulative total" | ||||
|     drive-files: "The number of files on the storage: increase/decrease" | ||||
|     drive-files-total: "The number of files on the storage: cumulative total" | ||||
| desktop/views/components/choose-file-from-drive-window.vue: | ||||
|   choose-file: "Choose files" | ||||
|   upload: "Upload files from your device" | ||||
| @@ -630,6 +650,7 @@ desktop/views/components/settings.vue: | ||||
|   gradient-window-header: "Use gradients on window headers" | ||||
|   post-form-on-timeline: "Display post form at the top of the timeline" | ||||
|   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" | ||||
|   show-my-renotes: "Show my renotes in the timeline" | ||||
|   show-renoted-my-notes: "Show renoted my posts in timelines" | ||||
| @@ -754,6 +775,7 @@ desktop/views/components/ui.header.account.vue: | ||||
|   lists: "Lists" | ||||
|   follow-requests: "Follow requests" | ||||
|   customize: "Customize home layout" | ||||
|   admin: "Admin" | ||||
|   settings: "Settings" | ||||
|   signout: "Sign out" | ||||
|   dark: "Submerge in dark" | ||||
| @@ -799,7 +821,7 @@ desktop/views/pages/admin/admin.dashboard.vue: | ||||
|   dashboard: "Dashboard" | ||||
|   all-users: "All Users" | ||||
|   original-users: "Users on this instance" | ||||
|   all-notes: "All Posts" | ||||
|   all-notes: "All the posts" | ||||
|   original-notes: "Posts on this instance" | ||||
|   invite: "Invite" | ||||
| desktop/views/pages/admin/admin.suspend-user.vue: | ||||
| @@ -818,18 +840,6 @@ 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.notes-chart.vue: | ||||
|   title: "Posts" | ||||
|   local: "Local" | ||||
|   remote: "Remote" | ||||
| desktop/views/pages/admin/admin.users-chart.vue: | ||||
|   title: "Users" | ||||
|   local: "Local" | ||||
|   remote: "Remote" | ||||
| desktop/views/pages/admin/admin.drive-chart.vue: | ||||
|   title: "Drive" | ||||
|   local: "Local" | ||||
|   remote: "Remote" | ||||
| desktop/views/pages/deck/deck.tl-column.vue: | ||||
|   is-media-only: "Only media posts" | ||||
|   is-media-view: "Media view" | ||||
| @@ -838,6 +848,11 @@ 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/stats/stats.vue: | ||||
|   all-users: "All Users" | ||||
|   original-users: "Users on this instance" | ||||
|   all-notes: "All the posts" | ||||
|   original-notes: "Posts on this instance" | ||||
| desktop/views/pages/welcome.vue: | ||||
|   about: "More details..." | ||||
|   gotit: "Got it!" | ||||
| @@ -1044,6 +1059,7 @@ mobile/views/components/ui.nav.vue: | ||||
|   game: "Games" | ||||
|   darkmode: "Dark theme" | ||||
|   settings: "Settings" | ||||
|   admin: "Admin" | ||||
|   about: "About Misskey" | ||||
| mobile/views/components/user-timeline.vue: | ||||
|   no-notes: "It seems this user hasn't posted anything yet." | ||||
| @@ -1057,7 +1073,7 @@ mobile/views/pages/favorites.vue: | ||||
|   title: "Favorites" | ||||
| mobile/views/pages/user-lists.vue: | ||||
|   title: "Lists" | ||||
|   enter-list-name: "Enter list name" | ||||
|   enter-list-name: "Enter a name of the list to make" | ||||
| mobile/views/pages/drive.vue: | ||||
|   drive: "Drive" | ||||
|   more: "Load more" | ||||
| @@ -1161,6 +1177,8 @@ mobile/views/pages/settings.vue: | ||||
|   update-available-desc: "Updates will be applied after reloading the page" | ||||
|   settings: "Settings" | ||||
|   signout: "Sign out" | ||||
|   sound: "Sounds" | ||||
|   enableSounds: "Enable sounds" | ||||
| mobile/views/pages/user.vue: | ||||
|   follows-you: "Follows you" | ||||
|   following: "Following" | ||||
|   | ||||
| @@ -58,7 +58,7 @@ common: | ||||
|     friday: "Viernes" | ||||
|     saturday: "Sábado" | ||||
|   reactions: | ||||
|     like: "ええやん" | ||||
|     like: "いいね" | ||||
|     love: "amor" | ||||
|     laugh: "risa" | ||||
|     hmm: "hmm" | ||||
| @@ -84,6 +84,7 @@ common: | ||||
|   my-token-regenerated: "Tu token se ha regenerado vas a ser desconectado." | ||||
|   i-like-sushi: "Prefiero sushi a pudín" | ||||
|   show-reversi-board-labels: "Mostrar etiquetas de filas y columnas en Reversi" | ||||
|   use-contrast-reversi-stones: "リバーシのアイコンにコントラストを付ける" | ||||
|   verified-user: "公式アカウント" | ||||
|   disable-animated-mfm: "Desactivar texto animado en una publicación" | ||||
|   reversi: | ||||
| @@ -410,6 +411,7 @@ desktop: | ||||
|   uploading-avatar: "Cargando un nuevo avatar" | ||||
|   avatar-updated: "Avatar actualizado" | ||||
|   choose-avatar: "Escoge una imagen de avatar" | ||||
|   invalid-filetype: "この形式のファイルはサポートされていません" | ||||
| desktop/views/components/activity.chart.vue: | ||||
|   total: "Negro ... Total" | ||||
|   notes: "Azul ... Notas" | ||||
| @@ -423,6 +425,24 @@ desktop/views/components/calendar.vue: | ||||
|   prev: "Mes anterior" | ||||
|   next: "Próximo mes" | ||||
|   go: "Click para navegar" | ||||
| desktop/views/components/charts.vue: | ||||
|   title: "チャート" | ||||
|   per-day: "1日ごと" | ||||
|   per-hour: "1時間ごと" | ||||
|   notes: "投稿" | ||||
|   users: "ユーザー" | ||||
|   drive: "ドライブ" | ||||
|   charts: | ||||
|     notes: "投稿の増減 (統合)" | ||||
|     local-notes: "投稿の増減 (ローカル)" | ||||
|     remote-notes: "投稿の増減 (リモート)" | ||||
|     notes-total: "投稿の累計" | ||||
|     users: "ユーザーの増減" | ||||
|     users-total: "ユーザーの累計" | ||||
|     drive: "ドライブ使用量の増減" | ||||
|     drive-total: "ドライブ使用量の累計" | ||||
|     drive-files: "ドライブのファイル数の増減" | ||||
|     drive-files-total: "ドライブのファイル数の累計" | ||||
| desktop/views/components/choose-file-from-drive-window.vue: | ||||
|   choose-file: "Escoger archivos" | ||||
|   upload: "Cargar archivos de tu dispositivo" | ||||
| @@ -630,6 +650,7 @@ desktop/views/components/settings.vue: | ||||
|   gradient-window-header: "Usar degradados en las cabeceras de las páginas" | ||||
|   post-form-on-timeline: "Mostrar el formulario de las entradas encima de la línea de tiempo" | ||||
|   suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する" | ||||
|   show-clock-on-header: "右上に時計を表示する" | ||||
|   show-reply-target: "リプライ先を表示する" | ||||
|   show-my-renotes: "自分の行ったRenoteをタイムラインに表示する" | ||||
|   show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する" | ||||
| @@ -754,6 +775,7 @@ desktop/views/components/ui.header.account.vue: | ||||
|   lists: "リスト" | ||||
|   follow-requests: "フォロー申請" | ||||
|   customize: "ホームのカスタマイズ" | ||||
|   admin: "管理" | ||||
|   settings: "設定" | ||||
|   signout: "サインアウト" | ||||
|   dark: "闇に飲まれる" | ||||
| @@ -799,8 +821,8 @@ desktop/views/pages/admin/admin.dashboard.vue: | ||||
|   dashboard: "ダッシュボード" | ||||
|   all-users: "全てのユーザー" | ||||
|   original-users: "このインスタンスのユーザー" | ||||
|   all-notes: "全てのノート" | ||||
|   original-notes: "このインスタンスのノート" | ||||
|   all-notes: "全ての投稿" | ||||
|   original-notes: "このインスタンスの投稿" | ||||
|   invite: "招待" | ||||
| desktop/views/pages/admin/admin.suspend-user.vue: | ||||
|   suspend-user: "ユーザーの凍結" | ||||
| @@ -818,18 +840,6 @@ desktop/views/pages/admin/admin.unverify-user.vue: | ||||
|   unverify-user: "ユーザーの公式アカウント解除" | ||||
|   unverify: "公式アカウントを解除する" | ||||
|   unverified: "公式アカウントを解除しました" | ||||
| desktop/views/pages/admin/admin.notes-chart.vue: | ||||
|   title: "投稿" | ||||
|   local: "ローカル" | ||||
|   remote: "リモート" | ||||
| desktop/views/pages/admin/admin.users-chart.vue: | ||||
|   title: "ユーザー" | ||||
|   local: "ローカル" | ||||
|   remote: "リモート" | ||||
| desktop/views/pages/admin/admin.drive-chart.vue: | ||||
|   title: "ドライブ" | ||||
|   local: "ローカル" | ||||
|   remote: "リモート" | ||||
| desktop/views/pages/deck/deck.tl-column.vue: | ||||
|   is-media-only: "メディア投稿のみ" | ||||
|   is-media-view: "メディアビュー" | ||||
| @@ -838,6 +848,11 @@ desktop/views/pages/deck/deck.note.vue: | ||||
|   reposted-by: "{}がRenote" | ||||
|   private: "この投稿は非公開です" | ||||
|   deleted: "この投稿は削除されました" | ||||
| desktop/views/pages/stats/stats.vue: | ||||
|   all-users: "全てのユーザー" | ||||
|   original-users: "このインスタンスのユーザー" | ||||
|   all-notes: "全ての投稿" | ||||
|   original-notes: "このインスタンスの投稿" | ||||
| desktop/views/pages/welcome.vue: | ||||
|   about: "詳しく..." | ||||
|   gotit: "わかった" | ||||
| @@ -1044,6 +1059,7 @@ mobile/views/components/ui.nav.vue: | ||||
|   game: "ゲーム" | ||||
|   darkmode: "ダークモード" | ||||
|   settings: "設定" | ||||
|   admin: "管理" | ||||
|   about: "Misskeyについて" | ||||
| mobile/views/components/user-timeline.vue: | ||||
|   no-notes: "このユーザーは投稿していないようです。" | ||||
| @@ -1161,6 +1177,8 @@ mobile/views/pages/settings.vue: | ||||
|   update-available-desc: "ページを再度読み込みすると更新が適用されます。" | ||||
|   settings: "設定" | ||||
|   signout: "サインアウト" | ||||
|   sound: "サウンド" | ||||
|   enableSounds: "サウンドを有効にする" | ||||
| mobile/views/pages/user.vue: | ||||
|   follows-you: "フォローされています" | ||||
|   following: "フォロー" | ||||
|   | ||||
| @@ -58,10 +58,10 @@ common: | ||||
|     friday: "Vendredi" | ||||
|     saturday: "Samedi" | ||||
|   reactions: | ||||
|     like: "ええやん" | ||||
|     like: "J'aime" | ||||
|     love: "Adore" | ||||
|     laugh: "Rire" | ||||
|     hmm: "Hmm ... ?" | ||||
|     hmm: "Hmm … ?" | ||||
|     surprise: "Wow" | ||||
|     congrats: "Félicitations !" | ||||
|     angry: "En colère" | ||||
| @@ -69,10 +69,10 @@ common: | ||||
|     rip: "RIP" | ||||
|     pudding: "Pudding" | ||||
|   note-placeholders: | ||||
|     a: "Que faites vous maintenant ?" | ||||
|     a: "Que faites-vous maintenant ?" | ||||
|     b: "Quoi de neuf ?" | ||||
|     c: "Qu'avez-vous en tête ?" | ||||
|     d: "Voulez-vous exprimer quelque chose ?" | ||||
|     d: "Désirez-vous publier quelques mots ?" | ||||
|     e: "Écrivez ici" | ||||
|     f: "En attente de vos écrits" | ||||
|   search: "Recherche" | ||||
| @@ -84,6 +84,7 @@ common: | ||||
|   my-token-regenerated: "Votre token 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: "リバーシのアイコンにコントラストを付ける" | ||||
|   verified-user: "Compte vérifié" | ||||
|   disable-animated-mfm: "Désactiver les textes animés dans les publications" | ||||
|   reversi: | ||||
| @@ -230,7 +231,7 @@ common/views/components/connect-failed.troubleshooter.vue: | ||||
|   flush: "Vider le cache" | ||||
|   set-version: "Choisissez une version" | ||||
| common/views/components/messaging.vue: | ||||
|   search-user: "Trouver un·e utilisateur·rice" | ||||
|   search-user: "Trouver un·e utilisateur·trice" | ||||
|   you: "Vous" | ||||
|   no-history: "Pas d'historique" | ||||
| common/views/components/messaging-room.vue: | ||||
| @@ -378,7 +379,7 @@ common/views/widgets/tips.vue: | ||||
|   tips-line3: "Vous pouvez glisser et déposer des fichiers sur la fenêtre de la note" | ||||
|   tips-line4: "Vous pouvez coller des images à partir du presse-papier sur la fenêtre de la note" | ||||
|   tips-line5: "Vous pouvez téléverser des fichiers sur le Drive en faisant un glisser-déposer" | ||||
|   tips-line6: "ドライブでファイルをドラッグしてフォルダ移動できます" | ||||
|   tips-line6: "Vous pouvez déplacer un dossier en le glissant dans le Drive" | ||||
|   tips-line7: "ドライブでフォルダをドラッグしてフォルダ移動できます" | ||||
|   tips-line8: "Vous pouvez personnaliser l'Accueil via les paramètres" | ||||
|   tips-line9: "Misskey est sous licence AGPLv3" | ||||
| @@ -410,6 +411,7 @@ desktop: | ||||
|   uploading-avatar: "Téléversement du nouvel avatar" | ||||
|   avatar-updated: "L'avatar est mis à jour" | ||||
|   choose-avatar: "Choisir un avatar" | ||||
|   invalid-filetype: "この形式のファイルはサポートされていません" | ||||
| desktop/views/components/activity.chart.vue: | ||||
|   total: "Noirs ... Total" | ||||
|   notes: "Bleu ... Notes" | ||||
| @@ -423,6 +425,24 @@ desktop/views/components/calendar.vue: | ||||
|   prev: "Mois dernier" | ||||
|   next: "Mois prochain" | ||||
|   go: "Cliquez pour naviguer" | ||||
| desktop/views/components/charts.vue: | ||||
|   title: "Graphiques" | ||||
|   per-day: "par jour" | ||||
|   per-hour: "par heure" | ||||
|   notes: "Publications" | ||||
|   users: "Utilisateurs" | ||||
|   drive: "Drive" | ||||
|   charts: | ||||
|     notes: "投稿の増減 (統合)" | ||||
|     local-notes: "投稿の増減 (ローカル)" | ||||
|     remote-notes: "投稿の増減 (リモート)" | ||||
|     notes-total: "投稿の累計" | ||||
|     users: "ユーザーの増減" | ||||
|     users-total: "ユーザーの累計" | ||||
|     drive: "ドライブ使用量の増減" | ||||
|     drive-total: "ドライブ使用量の累計" | ||||
|     drive-files: "ドライブのファイル数の増減" | ||||
|     drive-files-total: "ドライブのファイル数の累計" | ||||
| desktop/views/components/choose-file-from-drive-window.vue: | ||||
|   choose-file: "Sélection de fichiers" | ||||
|   upload: "Téléverser des fichiers à partir de votre ordinateur" | ||||
| @@ -512,7 +532,7 @@ desktop/views/components/following.vue: | ||||
|   empty: "Vous ne suivez aucun compte." | ||||
| desktop/views/components/friends-maker.vue: | ||||
|   title: "Utilisateurs recommandés :" | ||||
|   empty: "Impossible de trouver des utilisateurs à recommander." | ||||
|   empty: "Impossible de trouver des utilisateurs·trices à recommander." | ||||
|   fetching: "Chargement" | ||||
|   refresh: "Plus" | ||||
|   close: "Fermer" | ||||
| @@ -629,7 +649,8 @@ desktop/views/components/settings.vue: | ||||
|   circle-icons: "Utiliser des icônes circulaires" | ||||
|   gradient-window-header: "Utiliser les dégradés sur la barre de titre de la fenêtre" | ||||
|   post-form-on-timeline: "タイムライン上部に投稿フォームを表示する" | ||||
|   suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する" | ||||
|   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" | ||||
|   show-my-renotes: "Afficher mes republications dans le fil" | ||||
|   show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する" | ||||
| @@ -754,6 +775,7 @@ desktop/views/components/ui.header.account.vue: | ||||
|   lists: "Listes" | ||||
|   follow-requests: "Demandes de suivi" | ||||
|   customize: "Personnaliser l'Accueil" | ||||
|   admin: "Admin" | ||||
|   settings: "Réglages" | ||||
|   signout: "Déconnexion" | ||||
|   dark: "Fall in dark" | ||||
| @@ -791,14 +813,14 @@ desktop/views/components/window.vue: | ||||
|   popout: "ポップアウト" | ||||
|   close: "Fermer" | ||||
| desktop/views/pages/admin/admin.vue: | ||||
|   dashboard: "ダッシュボード" | ||||
|   dashboard: "Tableau de bord" | ||||
|   drive: "Drive" | ||||
|   users: "Utilisateur·rice·s" | ||||
|   update: "Mises à jour" | ||||
| desktop/views/pages/admin/admin.dashboard.vue: | ||||
|   dashboard: "ダッシュボード" | ||||
|   all-users: "Tou·te·s les utilisateur·rice·s" | ||||
|   original-users: "Utilisateur·rice·s sur cette instance" | ||||
|   dashboard: "Tableau de bord" | ||||
|   all-users: "Toutes les utilisateurrices" | ||||
|   original-users: "Utilisateurrices sur cette instance" | ||||
|   all-notes: "Toutes les publications" | ||||
|   original-notes: "Publication sur cette instance" | ||||
|   invite: "Invitation" | ||||
| @@ -811,25 +833,13 @@ desktop/views/pages/admin/admin.unsuspend-user.vue: | ||||
|   unsuspend: "Suspension levée" | ||||
|   unsuspended: "La suspension de l’utilisateur·rice a été levée avec succès" | ||||
| desktop/views/pages/admin/admin.verify-user.vue: | ||||
|   verify-user: "ユーザーの公式アカウント設定" | ||||
|   verify-user: "Paramètres de vérification du compte utilisateur" | ||||
|   verify: "Vérification du compte" | ||||
|   verified: "Le compte a été vérifié" | ||||
| desktop/views/pages/admin/admin.unverify-user.vue: | ||||
|   unverify-user: "ユーザーの公式アカウント解除" | ||||
|   unverify: "公式アカウントを解除する" | ||||
|   unverified: "公式アカウントを解除しました" | ||||
| desktop/views/pages/admin/admin.notes-chart.vue: | ||||
|   title: "投稿" | ||||
|   local: "ローカル" | ||||
|   remote: "リモート" | ||||
| desktop/views/pages/admin/admin.users-chart.vue: | ||||
|   title: "ユーザー" | ||||
|   local: "ローカル" | ||||
|   remote: "リモート" | ||||
| desktop/views/pages/admin/admin.drive-chart.vue: | ||||
|   title: "ドライブ" | ||||
|   local: "ローカル" | ||||
|   remote: "リモート" | ||||
|   unverify: "Ôter la vérification du compte" | ||||
|   unverified: "Ce compte n'est pas vérifié" | ||||
| desktop/views/pages/deck/deck.tl-column.vue: | ||||
|   is-media-only: "Les publications médias uniquement" | ||||
|   is-media-view: "Vue média" | ||||
| @@ -838,6 +848,11 @@ 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/stats/stats.vue: | ||||
|   all-users: "Toutes les utilisateurrices" | ||||
|   original-users: "Utilisateurrices sur cette instance" | ||||
|   all-notes: "Toutes les publications" | ||||
|   original-notes: "Publication sur cette instance" | ||||
| desktop/views/pages/welcome.vue: | ||||
|   about: "à propos" | ||||
|   gotit: "J'ai compris !" | ||||
| @@ -977,7 +992,7 @@ mobile/views/components/follow-button.vue: | ||||
|   follow-request: "Demande d'abonnement" | ||||
| mobile/views/components/friends-maker.vue: | ||||
|   title: "Abonnez-vous aux utilisateurs" | ||||
|   empty: "Impossible de trouver des utilisateurs à recommander." | ||||
|   empty: "Impossible de trouver des utilisateurs·trices à recommander." | ||||
|   fetching: "Chargement" | ||||
|   refresh: "Voir plus" | ||||
|   close: "Fermer" | ||||
| @@ -1044,6 +1059,7 @@ mobile/views/components/ui.nav.vue: | ||||
|   game: "Jeux" | ||||
|   darkmode: "Mode nuit" | ||||
|   settings: "Réglages" | ||||
|   admin: "Admin" | ||||
|   about: "À propose de Misskey" | ||||
| mobile/views/components/user-timeline.vue: | ||||
|   no-notes: "Cette utilisateur semble n'avoir rien poster pour le moment" | ||||
| @@ -1161,6 +1177,8 @@ mobile/views/pages/settings.vue: | ||||
|   update-available-desc: "Les mises à jour seront appliquées une fois la page est rechargée." | ||||
|   settings: "Réglages" | ||||
|   signout: "Déconnexion" | ||||
|   sound: "Sons" | ||||
|   enableSounds: "Activer le son" | ||||
| mobile/views/pages/user.vue: | ||||
|   follows-you: "vous suit" | ||||
|   following: "Abonnements" | ||||
|   | ||||
| @@ -58,7 +58,7 @@ common: | ||||
|     friday: "金曜日" | ||||
|     saturday: "土曜日" | ||||
|   reactions: | ||||
|     like: "ええやん" | ||||
|     like: "いいね" | ||||
|     love: "しゅき" | ||||
|     laugh: "笑" | ||||
|     hmm: "ふぅ~む" | ||||
| @@ -84,6 +84,7 @@ common: | ||||
|   my-token-regenerated: "あなたのトークンが更新されたのでサインアウトします。" | ||||
|   i-like-sushi: "私は(プリンよりむしろ)寿司が好き" | ||||
|   show-reversi-board-labels: "リバーシのボードの行と列のラベルを表示" | ||||
|   use-contrast-reversi-stones: "リバーシのアイコンにコントラストを付ける" | ||||
|   verified-user: "公式アカウント" | ||||
|   disable-animated-mfm: "投稿内の動きのあるテキストを無効にする" | ||||
|   reversi: | ||||
| @@ -410,6 +411,7 @@ desktop: | ||||
|   uploading-avatar: "新しいアバターをアップロードしています" | ||||
|   avatar-updated: "アバターを更新しました" | ||||
|   choose-avatar: "アバターにする画像を選択" | ||||
|   invalid-filetype: "この形式のファイルはサポートされていません" | ||||
| desktop/views/components/activity.chart.vue: | ||||
|   total: "Black ... Total" | ||||
|   notes: "Blue ... Notes" | ||||
| @@ -423,6 +425,24 @@ desktop/views/components/calendar.vue: | ||||
|   prev: "前の月" | ||||
|   next: "次の月" | ||||
|   go: "クリックして時間遡行" | ||||
| desktop/views/components/charts.vue: | ||||
|   title: "チャート" | ||||
|   per-day: "1日ごと" | ||||
|   per-hour: "1時間ごと" | ||||
|   notes: "投稿" | ||||
|   users: "ユーザー" | ||||
|   drive: "ドライブ" | ||||
|   charts: | ||||
|     notes: "投稿の増減 (統合)" | ||||
|     local-notes: "投稿の増減 (ローカル)" | ||||
|     remote-notes: "投稿の増減 (リモート)" | ||||
|     notes-total: "投稿の累計" | ||||
|     users: "ユーザーの増減" | ||||
|     users-total: "ユーザーの累計" | ||||
|     drive: "ドライブ使用量の増減" | ||||
|     drive-total: "ドライブ使用量の累計" | ||||
|     drive-files: "ドライブのファイル数の増減" | ||||
|     drive-files-total: "ドライブのファイル数の累計" | ||||
| desktop/views/components/choose-file-from-drive-window.vue: | ||||
|   choose-file: "ファイル選択中" | ||||
|   upload: "PCからドライブにファイルをアップロード" | ||||
| @@ -630,6 +650,7 @@ desktop/views/components/settings.vue: | ||||
|   gradient-window-header: "ウィンドウのタイトルバーにグラデーションを使用" | ||||
|   post-form-on-timeline: "タイムライン上部に投稿フォームを表示する" | ||||
|   suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する" | ||||
|   show-clock-on-header: "右上に時計を表示する" | ||||
|   show-reply-target: "リプライ先を表示する" | ||||
|   show-my-renotes: "自分の行ったRenoteをタイムラインに表示する" | ||||
|   show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する" | ||||
| @@ -754,6 +775,7 @@ desktop/views/components/ui.header.account.vue: | ||||
|   lists: "リスト" | ||||
|   follow-requests: "フォロー申請" | ||||
|   customize: "ホームのカスタマイズ" | ||||
|   admin: "管理" | ||||
|   settings: "設定" | ||||
|   signout: "サインアウト" | ||||
|   dark: "闇に飲まれる" | ||||
| @@ -799,8 +821,8 @@ desktop/views/pages/admin/admin.dashboard.vue: | ||||
|   dashboard: "ダッシュボード" | ||||
|   all-users: "全てのユーザー" | ||||
|   original-users: "このインスタンスのユーザー" | ||||
|   all-notes: "全てのノート" | ||||
|   original-notes: "このインスタンスのノート" | ||||
|   all-notes: "全ての投稿" | ||||
|   original-notes: "このインスタンスの投稿" | ||||
|   invite: "招待" | ||||
| desktop/views/pages/admin/admin.suspend-user.vue: | ||||
|   suspend-user: "ユーザーの凍結" | ||||
| @@ -818,18 +840,6 @@ desktop/views/pages/admin/admin.unverify-user.vue: | ||||
|   unverify-user: "ユーザーの公式アカウント解除" | ||||
|   unverify: "公式アカウントを解除する" | ||||
|   unverified: "公式アカウントを解除しました" | ||||
| desktop/views/pages/admin/admin.notes-chart.vue: | ||||
|   title: "投稿" | ||||
|   local: "ローカル" | ||||
|   remote: "リモート" | ||||
| desktop/views/pages/admin/admin.users-chart.vue: | ||||
|   title: "ユーザー" | ||||
|   local: "ローカル" | ||||
|   remote: "リモート" | ||||
| desktop/views/pages/admin/admin.drive-chart.vue: | ||||
|   title: "ドライブ" | ||||
|   local: "ローカル" | ||||
|   remote: "リモート" | ||||
| desktop/views/pages/deck/deck.tl-column.vue: | ||||
|   is-media-only: "メディア投稿のみ" | ||||
|   is-media-view: "メディアビュー" | ||||
| @@ -838,6 +848,11 @@ desktop/views/pages/deck/deck.note.vue: | ||||
|   reposted-by: "{}がRenote" | ||||
|   private: "この投稿は非公開です" | ||||
|   deleted: "この投稿は削除されました" | ||||
| desktop/views/pages/stats/stats.vue: | ||||
|   all-users: "全てのユーザー" | ||||
|   original-users: "このインスタンスのユーザー" | ||||
|   all-notes: "全ての投稿" | ||||
|   original-notes: "このインスタンスの投稿" | ||||
| desktop/views/pages/welcome.vue: | ||||
|   about: "詳しく..." | ||||
|   gotit: "わかった" | ||||
| @@ -1044,6 +1059,7 @@ mobile/views/components/ui.nav.vue: | ||||
|   game: "ゲーム" | ||||
|   darkmode: "ダークモード" | ||||
|   settings: "設定" | ||||
|   admin: "管理" | ||||
|   about: "Misskeyについて" | ||||
| mobile/views/components/user-timeline.vue: | ||||
|   no-notes: "このユーザーは投稿していないようです。" | ||||
| @@ -1161,6 +1177,8 @@ mobile/views/pages/settings.vue: | ||||
|   update-available-desc: "ページを再度読み込みすると更新が適用されます。" | ||||
|   settings: "設定" | ||||
|   signout: "サインアウト" | ||||
|   sound: "サウンド" | ||||
|   enableSounds: "サウンドを有効にする" | ||||
| mobile/views/pages/user.vue: | ||||
|   follows-you: "フォローされています" | ||||
|   following: "フォロー" | ||||
|   | ||||
| @@ -94,6 +94,8 @@ common: | ||||
|   verified-user: "公式アカウント" | ||||
|   disable-animated-mfm: "投稿内の動きのあるテキストを無効にする" | ||||
|  | ||||
|   do-not-use-in-production: 'これは開発ビルドです。本番環境で使用しないでください。' | ||||
|  | ||||
|   reversi: | ||||
|     drawn: "引き分け" | ||||
|     my-turn: "あなたのターンです" | ||||
| @@ -456,6 +458,7 @@ desktop: | ||||
|   uploading-avatar: "新しいアバターをアップロードしています" | ||||
|   avatar-updated: "アバターを更新しました" | ||||
|   choose-avatar: "アバターにする画像を選択" | ||||
|   invalid-filetype: "この形式のファイルはサポートされていません" | ||||
|  | ||||
| desktop/views/components/activity.chart.vue: | ||||
|   total: "Black ... Total" | ||||
| @@ -473,6 +476,25 @@ desktop/views/components/calendar.vue: | ||||
|   next: "次の月" | ||||
|   go: "クリックして時間遡行" | ||||
|  | ||||
| desktop/views/components/charts.vue: | ||||
|   title: "チャート" | ||||
|   per-day: "1日ごと" | ||||
|   per-hour: "1時間ごと" | ||||
|   notes: "投稿" | ||||
|   users: "ユーザー" | ||||
|   drive: "ドライブ" | ||||
|   charts: | ||||
|     notes: "投稿の増減 (統合)" | ||||
|     local-notes: "投稿の増減 (ローカル)" | ||||
|     remote-notes: "投稿の増減 (リモート)" | ||||
|     notes-total: "投稿の累計" | ||||
|     users: "ユーザーの増減" | ||||
|     users-total: "ユーザーの累計" | ||||
|     drive: "ドライブ使用量の増減" | ||||
|     drive-total: "ドライブ使用量の累計" | ||||
|     drive-files: "ドライブのファイル数の増減" | ||||
|     drive-files-total: "ドライブのファイル数の累計" | ||||
|  | ||||
| desktop/views/components/choose-file-from-drive-window.vue: | ||||
|   choose-file: "ファイル選択中" | ||||
|   upload: "PCからドライブにファイルをアップロード" | ||||
| @@ -713,6 +735,7 @@ desktop/views/components/settings.vue: | ||||
|   gradient-window-header: "ウィンドウのタイトルバーにグラデーションを使用" | ||||
|   post-form-on-timeline: "タイムライン上部に投稿フォームを表示する" | ||||
|   suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する" | ||||
|   show-clock-on-header: "右上に時計を表示する" | ||||
|   show-reply-target: "リプライ先を表示する" | ||||
|   show-my-renotes: "自分の行ったRenoteをタイムラインに表示する" | ||||
|   show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する" | ||||
| @@ -915,8 +938,8 @@ desktop/views/pages/admin/admin.dashboard.vue: | ||||
|   dashboard: "ダッシュボード" | ||||
|   all-users: "全てのユーザー" | ||||
|   original-users: "このインスタンスのユーザー" | ||||
|   all-notes: "全てのノート" | ||||
|   original-notes: "このインスタンスのノート" | ||||
|   all-notes: "全ての投稿" | ||||
|   original-notes: "このインスタンスの投稿" | ||||
|   invite: "招待" | ||||
|  | ||||
| desktop/views/pages/admin/admin.suspend-user.vue: | ||||
| @@ -939,30 +962,6 @@ desktop/views/pages/admin/admin.unverify-user.vue: | ||||
|   unverify: "公式アカウントを解除する" | ||||
|   unverified: "公式アカウントを解除しました" | ||||
|  | ||||
| desktop/views/pages/admin/admin.chart.vue: | ||||
|   title: "チャート" | ||||
|   per-day: "1日ごと" | ||||
|   per-hour: "1時間ごと" | ||||
|   notes: "投稿" | ||||
|   users: "ユーザー" | ||||
|   drive: "ドライブ" | ||||
|   local-notes: "ローカルの投稿の増減" | ||||
|   remote-notes: "リモートの投稿の増減" | ||||
|   local-notes-total: "ローカルの投稿の累計" | ||||
|   remote-notes-total: "リモートの投稿の累計" | ||||
|   local-users: "ローカルのユーザーの増減" | ||||
|   remote-users: "リモートのユーザーの増減" | ||||
|   local-users-total: "ローカルのユーザーの累計" | ||||
|   remote-users-total: "リモートのユーザーの累計" | ||||
|   local-drive: "ローカルのドライブ使用量の増減" | ||||
|   remote-drive: "リモートのドライブ使用量の増減" | ||||
|   local-drive-total: "ローカルのドライブ使用量の累計" | ||||
|   remote-drive-total: "リモートのドライブ使用量の累計" | ||||
|   local-drive-files: "ローカルのドライブのファイル数の増減" | ||||
|   remote-drive-files: "リモートのドライブのファイル数の増減" | ||||
|   local-drive-files-total: "ローカルのドライブのファイル数の累計" | ||||
|   remote-drive-files-total: "リモートのドライブのファイル数の累計" | ||||
|  | ||||
| desktop/views/pages/deck/deck.tl-column.vue: | ||||
|   is-media-only: "メディア投稿のみ" | ||||
|   is-media-view: "メディアビュー" | ||||
| @@ -973,6 +972,12 @@ desktop/views/pages/deck/deck.note.vue: | ||||
|   private: "この投稿は非公開です" | ||||
|   deleted: "この投稿は削除されました" | ||||
|  | ||||
| desktop/views/pages/stats/stats.vue: | ||||
|   all-users: "全てのユーザー" | ||||
|   original-users: "このインスタンスのユーザー" | ||||
|   all-notes: "全ての投稿" | ||||
|   original-notes: "このインスタンスの投稿" | ||||
|  | ||||
| desktop/views/pages/welcome.vue: | ||||
|   about: "詳しく..." | ||||
|   gotit: "わかった" | ||||
| @@ -1366,6 +1371,8 @@ mobile/views/pages/settings.vue: | ||||
|   update-available-desc: "ページを再度読み込みすると更新が適用されます。" | ||||
|   settings: "設定" | ||||
|   signout: "サインアウト" | ||||
|   sound: "サウンド" | ||||
|   enableSounds: "サウンドを有効にする" | ||||
|  | ||||
| mobile/views/pages/user.vue: | ||||
|   follows-you: "フォローされています" | ||||
|   | ||||
| @@ -84,6 +84,7 @@ common: | ||||
|   my-token-regenerated: "あんさんのトークンが更新されたらしいわ。すまんがとりあえずサインアウトすんで。" | ||||
|   i-like-sushi: "寿司(のほうがプリンよりむしろ)ウマい、タコ焼きはあらへんけど。" | ||||
|   show-reversi-board-labels: "リバーシのボードの行と列のラベルを表示や!" | ||||
|   use-contrast-reversi-stones: "リバーシのアイコンにコントラストをつけんで!" | ||||
|   verified-user: "アメちゃん付きアカウント" | ||||
|   disable-animated-mfm: "投稿内のちょろちょろ動いてんのを止める" | ||||
|   reversi: | ||||
| @@ -190,25 +191,25 @@ common/views/components/games/reversi/reversi.index.vue: | ||||
| common/views/components/games/reversi/reversi.room.vue: | ||||
|   settings-of-the-game: "ゲームの設定" | ||||
|   choose-map: "マップを選択" | ||||
|   random: "ランダム" | ||||
|   random: "いんじゃんほい" | ||||
|   black-or-white: "先手/後手" | ||||
|   black-is: "{}が黒" | ||||
|   black-is: "{}が黒や" | ||||
|   rules: "ルール" | ||||
|   is-llotheo: "石の少ない方が勝ち(ロセオ)" | ||||
|   is-llotheo: "石の少ない方が勝ちや!(ロセオ)" | ||||
|   looped-map: "ループマップ" | ||||
|   can-put-everywhere: "どこでも置けるモード" | ||||
|   can-put-everywhere: "どこに置いてもええモード" | ||||
|   settings-of-the-bot: "Botの設定" | ||||
|   this-game-is-started-soon: "ゲームは数秒後に開始されます" | ||||
|   waiting-for-other: "相手の準備が完了するのを待っています" | ||||
|   waiting-for-me: "あなたの準備が完了するのを待っています" | ||||
|   this-game-is-started-soon: "ゲームは数秒後に開始されんで" | ||||
|   waiting-for-other: "相手の準備が完了すんのを待ってんで" | ||||
|   waiting-for-me: "あんさんの準備が完了すんのを待ってんで" | ||||
|   waiting-for-both: "準備中" | ||||
|   cancel: "やめとくわ" | ||||
|   ready: "準備完了" | ||||
|   cancel-ready: "準備続行" | ||||
| common/views/components/connect-failed.vue: | ||||
|   title: "サーバーに接続できません" | ||||
|   description: "インターネット回線に問題があるか、サーバーがダウンまたはメンテナンスしている可能性があります。しばらくしてから{再度お試し}ください。" | ||||
|   thanks: "いつもMisskeyをご利用いただきありがとうございます。" | ||||
|   title: "サーバーに接続でけへんわ" | ||||
|   description: "インターネット回線に問題が起きとるか、サーバーがダウンまたはメンテナンスしとるっぽいわ。知らんけど。とりあえずあとで{再試行}してや。" | ||||
|   thanks: "いつもMisskeyをつこてくれてほんまありがとな。" | ||||
|   troubleshoot: "トラブルシュート" | ||||
| common/views/components/connect-failed.troubleshooter.vue: | ||||
|   title: "トラブルシューティング" | ||||
| @@ -218,99 +219,99 @@ common/views/components/connect-failed.troubleshooter.vue: | ||||
|   checking-internet: "インターネット接続を確認中" | ||||
|   server: "サーバー接続" | ||||
|   checking-server: "サーバー接続を確認中" | ||||
|   finding: "問題を調べています" | ||||
|   no-network: "ネットワークに接続されていません" | ||||
|   no-network-desc: "お使いのPCのネットワーク接続が正常か確認してください。" | ||||
|   no-internet: "インターネットに接続されていません" | ||||
|   no-internet-desc: "ネットワークには接続されていますが、インターネットには接続されていないようです。お使いのPCのインターネット接続が正常か確認してください。" | ||||
|   no-server: "Misskeyのサーバーに接続できません" | ||||
|   no-server-desc: "お使いのPCのインターネット接続は正常ですが、Misskeyのサーバーには接続できませんでした。サーバーがダウンまたはメンテナンスしている可能性があるので、しばらくしてから再度御アクセスください。" | ||||
|   success: "Misskeyのサーバーに接続できました" | ||||
|   success-desc: "正常に接続できるようです。ページを再度読み込みしてください。" | ||||
|   finding: "問題を調べとるで" | ||||
|   no-network: "ネットワークに接続されとらんで" | ||||
|   no-network-desc: "つこてるPCのネットワーク接続が正常か確認してや。" | ||||
|   no-internet: "インターネットに接続されとらんで" | ||||
|   no-internet-desc: "ネットワークには接続されとるけど、インターネットには接続されとらんようやわ。つこてるPCのインターネット接続が正常か確認してや。" | ||||
|   no-server: "Misskeyのサーバーに接続でけへんわ" | ||||
|   no-server-desc: "つこてるPCのインターネット接続は正常やけど、Misskeyのサーバーにはつながらんわ。多分サーバーがダウンまたはメンテナンスしとるわ、知らんけど。すまんけどしばらくしてから再度アクセスしてみてや。" | ||||
|   success: "Misskeyのサーバーに接続できたわ" | ||||
|   success-desc: "正常に接続できるようやわ。ページを再度読み込みしてな。" | ||||
|   flush: "キャッシュの削除" | ||||
|   set-version: "バージョン指定" | ||||
| common/views/components/messaging.vue: | ||||
|   search-user: "ユーザーを探す" | ||||
|   you: "あなた" | ||||
|   no-history: "履歴はありません" | ||||
|   you: "あんさん" | ||||
|   no-history: "履歴はあらへんで" | ||||
| common/views/components/messaging-room.vue: | ||||
|   empty: "このユーザーと話したことはありません" | ||||
|   empty: "このユーザーと話したことはあらへんで" | ||||
|   more: "もっと読む" | ||||
|   no-history: "これより過去の履歴はありません" | ||||
|   no-history: "これより過去の履歴はあらへんで" | ||||
|   resize-form: "ドラッグしてフォームの広さを調整" | ||||
|   new-message: "新しいメッセージがあります" | ||||
|   only-one-file-attached: "メッセージに添付できるのはひとつのファイルのみです" | ||||
|   new-message: "新しいメッセージがあるで" | ||||
|   only-one-file-attached: "メッセージに添付できんのはひとつのファイルのみやで" | ||||
| common/views/components/messaging-room.form.vue: | ||||
|   input-message-here: "ここにメッセージを入力" | ||||
|   input-message-here: "ここにメッセージ書いてや" | ||||
|   send: "送信" | ||||
|   attach-from-local: "PCからファイルを添付する" | ||||
|   attach-from-drive: "ドライブからファイルを添付する" | ||||
|   only-one-file-attached: "メッセージに添付できるのはひとつのファイルのみです" | ||||
|   only-one-file-attached: "メッセージに添付できんのはひとつのファイルのみやで" | ||||
| common/views/components/messaging-room.message.vue: | ||||
|   is-read: "既読" | ||||
|   deleted: "このメッセージは削除されました" | ||||
|   deleted: "このメッセージは削除されたわ" | ||||
| common/views/components/nav.vue: | ||||
|   about: "Misskeyについて" | ||||
|   stats: "統計" | ||||
|   status: "ステータス" | ||||
|   wiki: "Wiki" | ||||
|   donors: "ドナー" | ||||
|   donors: "支援者" | ||||
|   repository: "リポジトリ" | ||||
|   develop: "開発者" | ||||
|   feedback: "フィードバック" | ||||
| common/views/components/note-menu.vue: | ||||
|   favorite: "お気に入り" | ||||
|   pin: "ピン留め" | ||||
|   delete: "削除" | ||||
|   delete-confirm: "この投稿を削除しますか?" | ||||
|   delete: "ほかす" | ||||
|   delete-confirm: "この投稿を削除してもええか?" | ||||
|   remote: "投稿元で見る" | ||||
| common/views/components/poll.vue: | ||||
|   vote-to: "「{}」に投票する" | ||||
|   vote-to: "「{}」に投票や!" | ||||
|   vote-count: "{}票" | ||||
|   total-users: "{}人が投票" | ||||
|   vote: "投票する" | ||||
|   show-result: "結果を見る" | ||||
|   voted: "投票済み" | ||||
|   vote: "投票するで" | ||||
|   show-result: "結果を見よか" | ||||
|   voted: "投票済みや" | ||||
| common/views/components/poll-editor.vue: | ||||
|   no-only-one-choice: "アンケートには、選択肢が最低2つ必要です" | ||||
|   no-only-one-choice: "選択肢が最低2つ必要やで" | ||||
|   choice-n: "選択肢{}" | ||||
|   remove: "この選択肢を削除" | ||||
|   remove: "この選択肢を消すで" | ||||
|   add: "+選択肢を追加" | ||||
|   destroy: "アンケートを破棄" | ||||
|   destroy: "アンケートをほかそ" | ||||
| common/views/components/reaction-picker.vue: | ||||
|   choose-reaction: "リアクションを選択" | ||||
| common/views/components/signin.vue: | ||||
|   username: "ユーザー名" | ||||
|   password: "パスワード" | ||||
|   token: "トークン" | ||||
|   signing-in: "やってます..." | ||||
|   signing-in: "サインイン中や..." | ||||
|   signin: "サインイン" | ||||
|   or: "または" | ||||
|   signin-with-twitter: "Twitterでログイン" | ||||
|   login-failed: "ログインできませんでした。ユーザー名とパスワードを確認してください。" | ||||
|   signin-with-twitter: "Twitterでサインイン" | ||||
|   login-failed: "なんかログインできんかったわ。ユーザー名とパスワードとかを確認してや。" | ||||
| common/views/components/signup.vue: | ||||
|   invitation-code: "招待コード" | ||||
|   invitation-info: "招待コードをお持ちでない方は、<a href=\"{}\">管理者</a>までご連絡ください。" | ||||
|   username: "ユーザー名" | ||||
|   checking: "確認しています..." | ||||
|   available: "利用できます" | ||||
|   unavailable: "既に利用されています" | ||||
|   checking: "確認中や…" | ||||
|   available: "使えるで" | ||||
|   unavailable: "もう使われとるで" | ||||
|   error: "通信エラー" | ||||
|   invalid-format: "a~z、A~Z、0~9、_が使えます" | ||||
|   invalid-format: "a~z、A~Z、0~9、_が使えるで" | ||||
|   too-short: "1文字以上でお願いします!" | ||||
|   too-long: "20文字以内でお願いします" | ||||
|   password: "パスワード" | ||||
|   password-placeholder: "8文字以上を推奨します" | ||||
|   weak-password: "弱いパスワード" | ||||
|   normal-password: "まあまあのパスワード" | ||||
|   strong-password: "強いパスワード" | ||||
|   retype: "再入力" | ||||
|   retype-placeholder: "確認のため再入力してください" | ||||
|   password-matched: "確認されました" | ||||
|   password-not-matched: "一致していません" | ||||
|   weak-password: "へぼいパスワード" | ||||
|   normal-password: "ぼちぼちなパスワード" | ||||
|   strong-password: "良さげなパスワード" | ||||
|   retype: "もっかい入力頼むで" | ||||
|   retype-placeholder: "確認のためもっぺん入力してや" | ||||
|   password-matched: "一致しとるで" | ||||
|   password-not-matched: "一致しとらんで" | ||||
|   recaptcha: "認証" | ||||
|   create: "アカウント作成" | ||||
|   some-error: "何らかの原因によりアカウントの作成に失敗しました。再度お試しください。" | ||||
|   some-error: "何かよう分からんけど、アカウントの作成に失敗してしもたわ。すまんがもっぺん試してくれへんか?" | ||||
| common/views/components/special-message.vue: | ||||
|   new-year: "Happy New Year!" | ||||
|   christmas: "Merry Christmas!" | ||||
| @@ -319,8 +320,8 @@ common/views/components/stream-indicator.vue: | ||||
|   reconnecting: "再接続中" | ||||
|   connected: "接続完了" | ||||
| common/views/components/twitter-setting.vue: | ||||
|   description: "お使いのTwitterアカウントをお使いのMisskeyアカウントに接続しておくと、プロフィールでTwitterアカウント情報が表示されるようになったり、Twitterを用いた便利なサインインを利用できるようになります。" | ||||
|   connected-to: "次のTwitterアカウントに接続されています" | ||||
|   description: "あんさんがつことるTwitterアカウントをMisskeyアカウントに接続しとくと、あんさんのプロフィールにTwitterアカウント情報が表示されるようになったり、Twitterをつこた便利なサインインが使えるようになったりすんで。" | ||||
|   connected-to: "次のTwitterアカウントに接続されとるで" | ||||
|   detail: "詳細..." | ||||
|   reconnect: "再接続する" | ||||
|   connect: "Twitterと接続する" | ||||
| @@ -338,7 +339,7 @@ common/views/components/visibility-chooser.vue: | ||||
|   private: "非公開" | ||||
| common/views/widgets/broadcast.vue: | ||||
|   fetching: "確認中" | ||||
|   no-broadcasts: "お知らせはありません" | ||||
|   no-broadcasts: "お知らせはあらへんで" | ||||
|   have-a-nice-day: "良い一日を!" | ||||
|   next: "次" | ||||
| common/views/widgets/calendar.vue: | ||||
| @@ -350,17 +351,17 @@ common/views/widgets/calendar.vue: | ||||
|   this-year: "今年:" | ||||
| common/views/widgets/donation.vue: | ||||
|   title: "寄付のお願い" | ||||
|   text: "Misskeyの運営にはドメイン、サーバー等のコストが掛かります。Misskeyは広告を掲載したりしないため、収入を皆様からの寄付に頼っています。もしご興味があれば、{}までご連絡ください。ご協力ありがとうございます。" | ||||
|   text: "Misskeyの運営にはドメイン、サーバー等のコストが掛かるんや。Misskeyは広告を掲載したりせんから、収入を皆様からの寄付に頼ってますねん。もし興味があるなら、{}までご連絡よろしゅう頼んます。ご協力おおきに。" | ||||
| common/views/widgets/photo-stream.vue: | ||||
|   title: "フォトストリーム" | ||||
|   no-photos: "写真はありません" | ||||
|   no-photos: "写真はあらへんで" | ||||
| common/views/widgets/posts-monitor.vue: | ||||
|   title: "投稿チャート" | ||||
|   toggle: "表示を切り替え" | ||||
| common/views/widgets/hashtags.vue: | ||||
|   title: "ハッシュタグ" | ||||
|   count: "{}人が投稿" | ||||
|   empty: "トレンドなし" | ||||
|   empty: "流行は自分で作るんや" | ||||
| common/views/widgets/server.vue: | ||||
|   title: "サーバー情報" | ||||
|   toggle: "表示を切り替え" | ||||
| @@ -369,30 +370,30 @@ common/views/widgets/memo.vue: | ||||
|   memo: "ここに書いて!" | ||||
|   save: "保存" | ||||
| common/views/widgets/slideshow.vue: | ||||
|   folder-customize-mode: "フォルダを指定するには、カスタマイズモードを終了してください" | ||||
|   folder-customize-mode: "フォルダを指定するんやったら、一旦カスタマイズモードを終了してや" | ||||
|   folder: "クリックしてフォルダを指定してください" | ||||
|   no-image: "このフォルダには画像がありません" | ||||
| common/views/widgets/tips.vue: | ||||
|   tips-line1: "<kbd>t</kbd>でタイムラインにフォーカスできます" | ||||
|   tips-line2: "<kbd>p</kbd>または<kbd>n</kbd>で投稿フォームを開きます" | ||||
|   tips-line3: "投稿フォームにはファイルをドラッグ&ドロップできます" | ||||
|   tips-line4: "投稿フォームにクリップボードにある画像データをペーストできます" | ||||
|   tips-line5: "ドライブにファイルをドラッグ&ドロップしてアップロードできます" | ||||
|   tips-line6: "ドライブでファイルをドラッグしてフォルダ移動できます" | ||||
|   tips-line7: "ドライブでフォルダをドラッグしてフォルダ移動できます" | ||||
|   tips-line8: "ホームは設定からカスタマイズできます" | ||||
|   tips-line9: "MisskeyはAGPLv3です" | ||||
|   tips-line10: "タイムマシンウィジェットを利用すると、簡単に過去のタイムラインに遡れます" | ||||
|   tips-line11: "投稿の ... をクリックして、投稿をユーザーページにピン留めできます" | ||||
|   tips-line13: "投稿に添付したファイルは全てドライブに保存されます" | ||||
|   tips-line14: "ホームのカスタマイズ中、ウィジェットを右クリックしてデザインを変更できます" | ||||
|   tips-line17: "「**」でテキストを囲むと**強調表示**されます" | ||||
|   tips-line19: "いくつかのウィンドウはブラウザの外に切り離すことができます" | ||||
|   tips-line20: "カレンダーウィジェットのパーセンテージは、経過の割合を示しています" | ||||
|   tips-line21: "APIを利用してbotの開発なども行えます" | ||||
|   tips-line1: "<kbd>t</kbd>でタイムラインにフォーカスできんで" | ||||
|   tips-line2: "<kbd>p</kbd>または<kbd>n</kbd>で投稿フォームを開くで" | ||||
|   tips-line3: "投稿フォームにはファイルをドラッグ&ドロップできんで" | ||||
|   tips-line4: "投稿フォームにクリップボードにおる画像データをペーストできんで" | ||||
|   tips-line5: "ドライブにファイルをドラッグ&ドロップしてアップロードできんで" | ||||
|   tips-line6: "ドライブやと、ファイルをドラッグしてフォルダ移動できんで" | ||||
|   tips-line7: "ドライブやと、フォルダをドラッグしてフォルダ移動できんで" | ||||
|   tips-line8: "ホームは設定からカスタマイズできんで" | ||||
|   tips-line9: "MisskeyはAGPLv3やで" | ||||
|   tips-line10: "タイムマシンウィジェットを利用すると、簡単に過去のタイムラインに遡れんで" | ||||
|   tips-line11: "投稿の ... をクリックして、ピン留めから投稿をユーザーページにピン留めできんで" | ||||
|   tips-line13: "投稿に添付したファイルは全てドライブに保存されんで" | ||||
|   tips-line14: "ホームのカスタマイズ中、ウィジェットを右クリックしてデザインを変更できんで" | ||||
|   tips-line17: "「**」でテキストを囲ったると**強調表示**されんで" | ||||
|   tips-line19: "いくつかのウィンドウはブラウザの外に切り離すことができんで" | ||||
|   tips-line20: "カレンダーウィジェットのパーセンテージは、経過の割合を示してんねん" | ||||
|   tips-line21: "APIをつこてbotの開発なども行えるで" | ||||
|   tips-line23: "まゆかわいいよまゆ" | ||||
|   tips-line24: "Misskeyは2014年にサービスを開始しました" | ||||
|   tips-line25: "対応ブラウザではMisskeyを開いていなくても通知を受け取れます" | ||||
|   tips-line24: "Misskeyは2014年にサービスを開始したんよ" | ||||
|   tips-line25: "対応ブラウザやったらMisskeyを開いとらんでも通知を受け取れんで" | ||||
| common/views/pages/follow.vue: | ||||
|   signed-in-as: "{}としてサインイン中" | ||||
|   following: "フォロー中" | ||||
| @@ -402,14 +403,15 @@ common/views/pages/follow.vue: | ||||
| desktop: | ||||
|   banner-crop-title: "バナーとして表示する部分を選択" | ||||
|   banner: "バナー" | ||||
|   uploading-banner: "新しいバナーをアップロードしています" | ||||
|   banner-updated: "バナーを更新しました" | ||||
|   uploading-banner: "新しいバナーをアップロードしとるで" | ||||
|   banner-updated: "バナーを更新したで" | ||||
|   choose-banner: "バナーにする画像を選択" | ||||
|   avatar-crop-title: "アバターとして表示する部分を選択" | ||||
|   avatar: "アバター" | ||||
|   uploading-avatar: "新しいアバターをアップロードしています" | ||||
|   avatar-updated: "アバターを更新しました" | ||||
|   choose-avatar: "アバターにする画像を選択" | ||||
|   invalid-filetype: "この形式のファイルはサポートされていません" | ||||
| desktop/views/components/activity.chart.vue: | ||||
|   total: "Black ... Total" | ||||
|   notes: "Blue ... Notes" | ||||
| @@ -419,10 +421,28 @@ desktop/views/components/activity.vue: | ||||
|   title: "アクティビティ" | ||||
|   toggle: "表示を切り替え" | ||||
| desktop/views/components/calendar.vue: | ||||
|   title: "{1}年 {2}月" | ||||
|   title: "{1}年 {2} 月" | ||||
|   prev: "前の月" | ||||
|   next: "次の月" | ||||
|   go: "クリックして時間遡行" | ||||
|   go: "クリックしてタイムリープ" | ||||
| desktop/views/components/charts.vue: | ||||
|   title: "チャート" | ||||
|   per-day: "1日ごと" | ||||
|   per-hour: "1時間ごと" | ||||
|   notes: "投稿" | ||||
|   users: "ユーザー" | ||||
|   drive: "ドライブ" | ||||
|   charts: | ||||
|     notes: "投稿の増減 (統合)" | ||||
|     local-notes: "投稿の増減 (ローカル)" | ||||
|     remote-notes: "投稿の増減 (リモート)" | ||||
|     notes-total: "投稿の累計" | ||||
|     users: "ユーザーの増減" | ||||
|     users-total: "ユーザーの累計" | ||||
|     drive: "ドライブ使用量の増減" | ||||
|     drive-total: "ドライブ使用量の累計" | ||||
|     drive-files: "ドライブのファイル数の増減" | ||||
|     drive-files-total: "ドライブのファイル数の累計" | ||||
| desktop/views/components/choose-file-from-drive-window.vue: | ||||
|   choose-file: "ファイル選択中" | ||||
|   upload: "PCからドライブにファイルをアップロード" | ||||
| @@ -445,7 +465,7 @@ desktop/views/components/drive.file.vue: | ||||
|   banner: "バナー" | ||||
|   nsfw: "閲覧注意" | ||||
|   contextmenu: | ||||
|     rename: "名前を変更" | ||||
|     rename: "名前を変えるで" | ||||
|     mark-as-sensitive: "閲覧注意に設定" | ||||
|     unmark-as-sensitive: "閲覧注意を解除" | ||||
|     copy-url: "URLをコピー" | ||||
| @@ -456,26 +476,26 @@ desktop/views/components/drive.file.vue: | ||||
|     open-in-app: "アプリで開く" | ||||
|     add-app: "アプリを追加" | ||||
|     rename-file: "ファイル名の変更" | ||||
|     input-new-file-name: "新しいファイル名を入力してください" | ||||
|     copied: "コピー完了" | ||||
|     input-new-file-name: "新しいファイル名を入力してや" | ||||
|     copied: "コピー完了や" | ||||
|     copied-url-to-clipboard: "URLをクリップボードにコピーしました" | ||||
| desktop/views/components/drive.folder.vue: | ||||
|   unable-to-process: "操作を完了できません" | ||||
|   circular-reference-detected: "移動先のフォルダーは、移動するフォルダーのサブフォルダーです。" | ||||
|   unhandled-error: "不明なエラー" | ||||
|   unhandled-error: "ようわからん" | ||||
|   contextmenu: | ||||
|     move-to-this-folder: "このフォルダへ移動" | ||||
|     show-in-new-window: "新しいウィンドウで表示" | ||||
|     rename: "名前を変更" | ||||
|     rename-folder: "フォルダ名の変更" | ||||
|     input-new-folder-name: "新しいフォルダ名を入力してください" | ||||
|     rename: "名前を変えるで" | ||||
|     rename-folder: "フォルダ名を変えるで" | ||||
|     input-new-folder-name: "新しいフォルダ名を入力してや" | ||||
| desktop/views/components/drive.nav-folder.vue: | ||||
|   drive: "ドライブ" | ||||
| desktop/views/components/drive.vue: | ||||
|   search: "検索" | ||||
|   load-more: "もっと読み込む" | ||||
|   empty-draghover: "ドロップですか?いいですよ、ボクはカワイイですからね" | ||||
|   empty-drive: "ドライブには何もありません。" | ||||
|   empty-drive: "ドライブには何もあらへんで。" | ||||
|   empty-drive-description: "右クリックして「ファイルをアップロード」を選んだり、ファイルをドラッグ&ドロップすることでもアップロードできます。" | ||||
|   empty-folder: "このフォルダーは空です" | ||||
|   unable-to-process: "操作を完了できません" | ||||
| @@ -492,11 +512,11 @@ desktop/views/components/drive.vue: | ||||
|     upload: "ファイルをアップロード" | ||||
|     url-upload: "URLからアップロード" | ||||
| desktop/views/components/media-image.vue: | ||||
|   sensitive: "閲覧注意" | ||||
|   click-to-show: "クリックして表示" | ||||
|   sensitive: "ちょっと見せられへんわ" | ||||
|   click-to-show: "クリックして見せるで" | ||||
| desktop/views/components/media-video.vue: | ||||
|   sensitive: "閲覧注意" | ||||
|   click-to-show: "クリックして表示" | ||||
|   sensitive: "ちょっと見せられへんわ" | ||||
|   click-to-show: "クリックして見せるで" | ||||
| desktop/views/components/follow-button.vue: | ||||
|   following: "フォロー中" | ||||
|   follow: "フォロー" | ||||
| @@ -517,7 +537,7 @@ desktop/views/components/friends-maker.vue: | ||||
|   refresh: "もっと見る" | ||||
|   close: "閉じる" | ||||
| desktop/views/components/game-window.vue: | ||||
|   game: "リバーシ" | ||||
|   game: "ゲーム" | ||||
| desktop/views/components/home.vue: | ||||
|   done: "完了" | ||||
|   add-widget: "ウィジェットを追加:" | ||||
| @@ -556,32 +576,32 @@ desktop/views/components/notifications.vue: | ||||
|   empty: "ありません!" | ||||
| desktop/views/components/post-form.vue: | ||||
|   add-visible-user: "+ユーザーを追加" | ||||
|   attach-location-information: "位置情報を添付する" | ||||
|   attach-location-information: "いる場所くっつけるで" | ||||
|   hide-contents: "内容を隠す" | ||||
|   reply-placeholder: "この投稿への返信..." | ||||
|   quote-placeholder: "この投稿を引用..." | ||||
|   submit: "投稿" | ||||
|   reply: "返信" | ||||
|   renote: "Renote" | ||||
|   posted: "投稿しました!" | ||||
|   replied: "返信しました!" | ||||
|   posted: "投稿したで!" | ||||
|   replied: "返信したで!" | ||||
|   reposted: "Renoteしました!" | ||||
|   note-failed: "投稿に失敗しました" | ||||
|   reply-failed: "返信に失敗しました" | ||||
|   note-failed: "投稿に失敗したで" | ||||
|   reply-failed: "返信に失敗したで" | ||||
|   renote-failed: "Renoteに失敗しました" | ||||
|   posting: "投稿中" | ||||
|   attach-media-from-local: "PCからメディアを添付" | ||||
|   attach-media-from-drive: "ドライブからメディアを添付" | ||||
|   attach-cancel: "添付取り消し" | ||||
|   attach-cancel: "くっつけるのやめよか" | ||||
|   insert-a-kao: "v('ω')v" | ||||
|   create-poll: "アンケートを作成" | ||||
|   text-remain: "残り{}文字" | ||||
|   recent-tags: "最近" | ||||
|   recent-tags: "最近のタグ" | ||||
|   click-to-tagging: "クリックでタグ付け" | ||||
|   visibility: "公開範囲" | ||||
|   geolocation-alert: "お使いの端末は位置情報に対応していません" | ||||
|   geolocation-alert: "あんさんのつことる端末は位置情報に対応しとらんみたいやわ、知らんけど。" | ||||
|   error: "エラー" | ||||
|   enter-username: "ユーザー名を入力してください" | ||||
|   enter-username: "ユーザー名を入力してや" | ||||
|   annotations: "内容への注釈 (オプション)" | ||||
| desktop/views/components/post-form-window.vue: | ||||
|   note: "新規投稿" | ||||
| @@ -620,7 +640,7 @@ desktop/views/components/settings.vue: | ||||
|   auto-popout-desc: "ウィンドウが開かれるとき、ポップアウト(ブラウザ外に切り離す)可能なら自動でポップアウトします。この設定はブラウザに記憶されます。" | ||||
|   advanced: "詳細設定" | ||||
|   api-via-stream: "ストリームを経由したAPIリクエスト" | ||||
|   api-via-stream-desc: "この設定をオンにすると、websocket接続を経由してAPIリクエストが行われます(パフォーマンス向上が期待できます)。オフにすると、ネイティブの fetch APIが利用されます。この設定はこのデバイスのみ有効です。" | ||||
|   api-via-stream-desc: "この設定をオンにすると、WebSocket接続を経由してAPIリクエストが行われんで(パフォーマンス向上するかも、知らんけど)。オフにすると、ネイティブの fetch API が利用されるで。この設定はこのデバイスのみ有効やで。" | ||||
|   display: "デザインと表示" | ||||
|   customize: "ホームをカスタマイズ" | ||||
|   choose-wallpaper: "壁紙を選択" | ||||
| @@ -630,6 +650,7 @@ desktop/views/components/settings.vue: | ||||
|   gradient-window-header: "ウィンドウのタイトルバーにグラデーションを使用" | ||||
|   post-form-on-timeline: "タイムライン上部に投稿フォームを表示する" | ||||
|   suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する" | ||||
|   show-clock-on-header: "右上に時計を表示する" | ||||
|   show-reply-target: "リプライ先を表示する" | ||||
|   show-my-renotes: "自分の行ったRenoteをタイムラインに表示する" | ||||
|   show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する" | ||||
| @@ -667,9 +688,9 @@ desktop/views/components/settings.vue: | ||||
|   prevent-update: "アップデートを延期する(非推奨)" | ||||
|   prevent-update-desc: "この設定をオンにしてもアップデートが反映される場合があります。この設定はこのデバイスのみ有効です。" | ||||
|   no-updates: "利用可能な更新はありません" | ||||
|   no-updates-desc: "お使いのMisskeyは最新です。" | ||||
|   update-available: "新しいバージョンが利用可能です" | ||||
|   update-available-desc: "ページを再度読み込みすると更新が適用されます。" | ||||
|   no-updates-desc: "つこてるMisskeyは最新や!" | ||||
|   update-available: "新しいバージョンが利用可能や" | ||||
|   update-available-desc: "ページを再度読み込みすると更新が適用されるで。" | ||||
|   advanced-settings: "高度な設定" | ||||
|   debug-mode: "デバッグモードを有効にする" | ||||
|   debug-mode-desc: "この設定はブラウザに記憶されます。" | ||||
| @@ -688,28 +709,28 @@ desktop/views/components/settings.2fa.vue: | ||||
|   unregister: "設定を解除" | ||||
|   unregistered: "二段階認証が無効になりました。" | ||||
|   enter-password: "パスワードを入力してください" | ||||
|   authenticator: "まず、Google Authenticatorをお使いのデバイスにインストールします:" | ||||
|   howtoinstall: "インストール方法はこちら" | ||||
|   scan: "次に、表示されているQRコードをスキャンします:" | ||||
|   done: "お使いのデバイスに表示されているトークンを入力して完了します:" | ||||
|   submit: "完了" | ||||
|   success: "設定が完了しました!" | ||||
|   failed: "設定に失敗しました。トークンに誤りがないかご確認ください。" | ||||
|   info: "次回サインインからは、同様にパスワードに加えてデバイスに表示されているトークンを入力します。" | ||||
|   authenticator: "まず、Google Authenticatorとかのをつこてるデバイスにインストールしてや:" | ||||
|   howtoinstall: "インストール方法はここやで" | ||||
|   scan: "んで、ここに出とるQRコードをスキャンしてな:" | ||||
|   done: "最後にデバイスに表示されとるトークンを入力してな:" | ||||
|   submit: "送信" | ||||
|   success: "設定が完了したで!" | ||||
|   failed: "なんか設定に失敗したで。トークンを間違えとらんか確認してや。" | ||||
|   info: "次のサインインからは、パスワードに加えてデバイスに出とるトークンを入力してな。" | ||||
| desktop/views/components/settings.api.vue: | ||||
|   intro: "APIを利用するには、上記のトークンを「i」というキーでパラメータに付加してリクエストします。" | ||||
|   caution: "アカウントを不正利用される可能性があるため、このトークンは第三者に教えないでください(アプリなどにも入力しないでください)。" | ||||
|   regeneration-of-token: "万が一このトークンが漏れたりその可能性がある場合はトークンを再生成できます。" | ||||
|   intro: "APIを利用するには、上記のトークンを「i」っちゅうキーでパラメータに付加してリクエストしてや。" | ||||
|   caution: "アカウントを不正利用されるかも知れんから、このトークンは第三者に教えたらあかんで(アプリなどにも入力しんといてな)。" | ||||
|   regeneration-of-token: "万が一このトークンが漏れたとかその可能性があったらトークンを再生成できるで。" | ||||
|   regenerate-token: "トークンを再生成" | ||||
|   token: "Token:" | ||||
|   enter-password: "パスワードを入力してください" | ||||
|   token: "トークン:" | ||||
|   enter-password: "パスワードを入力してや" | ||||
| desktop/views/components/settings.apps.vue: | ||||
|   no-apps: "連携しているアプリケーションはありません" | ||||
|   no-apps: "連携しているアプリケーションはあらへんで" | ||||
| desktop/views/components/settings.drive.vue: | ||||
|   max: "中" | ||||
|   in-use: "使用中" | ||||
| desktop/views/components/settings.mute.vue: | ||||
|   no-users: "ミュートしているユーザーはいません" | ||||
|   no-users: "ミュートしているユーザーはおらんで" | ||||
| desktop/views/components/settings.password.vue: | ||||
|   reset: "パスワードを変更する" | ||||
|   enter-current-password: "現在のパスワードを入力してください" | ||||
| @@ -745,7 +766,7 @@ desktop/views/components/timeline.vue: | ||||
|   global: "グローバル" | ||||
|   list: "リスト" | ||||
| desktop/views/components/ui.header.vue: | ||||
|   welcome-back: "おかえりなさい、" | ||||
|   welcome-back: "おかえり、" | ||||
|   adjective: "さん" | ||||
| desktop/views/components/ui.header.account.vue: | ||||
|   profile: "プロフィール" | ||||
| @@ -753,7 +774,8 @@ desktop/views/components/ui.header.account.vue: | ||||
|   favorites: "お気に入り" | ||||
|   lists: "リスト" | ||||
|   follow-requests: "フォロー申請" | ||||
|   customize: "ホームのカスタマイズ" | ||||
|   customize: "ホームをカスタマイズ" | ||||
|   admin: "管理" | ||||
|   settings: "設定" | ||||
|   signout: "サインアウト" | ||||
|   dark: "闇に飲まれる" | ||||
| @@ -774,7 +796,7 @@ desktop/views/components/received-follow-requests-window.vue: | ||||
|   reject: "拒否" | ||||
| desktop/views/components/user-lists-window.vue: | ||||
|   title: "リスト" | ||||
|   create-list: "リストを作成" | ||||
|   create-list: "新しいリストを作成" | ||||
|   list-name: "リスト名" | ||||
| desktop/views/components/user-preview.vue: | ||||
|   notes: "投稿" | ||||
| @@ -799,8 +821,8 @@ desktop/views/pages/admin/admin.dashboard.vue: | ||||
|   dashboard: "ダッシュボード" | ||||
|   all-users: "全てのユーザー" | ||||
|   original-users: "このインスタンスのユーザー" | ||||
|   all-notes: "全てのノート" | ||||
|   original-notes: "このインスタンスのノート" | ||||
|   all-notes: "全ての投稿" | ||||
|   original-notes: "このインスタンスの投稿" | ||||
|   invite: "招待" | ||||
| desktop/views/pages/admin/admin.suspend-user.vue: | ||||
|   suspend-user: "ユーザーの凍結" | ||||
| @@ -809,27 +831,15 @@ desktop/views/pages/admin/admin.suspend-user.vue: | ||||
| desktop/views/pages/admin/admin.unsuspend-user.vue: | ||||
|   unsuspend-user: "ユーザーの凍結の解除" | ||||
|   unsuspend: "凍結の解除" | ||||
|   unsuspended: "凍結を解除しました" | ||||
|   unsuspended: "凍結を解除したで" | ||||
| desktop/views/pages/admin/admin.verify-user.vue: | ||||
|   verify-user: "ユーザーの公式アカウント設定" | ||||
|   verify: "公式アカウントにする" | ||||
|   verified: "公式アカウントにしました" | ||||
|   verified: "公式アカウントにしたで" | ||||
| desktop/views/pages/admin/admin.unverify-user.vue: | ||||
|   unverify-user: "ユーザーの公式アカウント解除" | ||||
|   unverify: "公式アカウントを解除する" | ||||
|   unverified: "公式アカウントを解除しました" | ||||
| desktop/views/pages/admin/admin.notes-chart.vue: | ||||
|   title: "投稿" | ||||
|   local: "ローカル" | ||||
|   remote: "リモート" | ||||
| desktop/views/pages/admin/admin.users-chart.vue: | ||||
|   title: "ユーザー" | ||||
|   local: "ローカル" | ||||
|   remote: "リモート" | ||||
| desktop/views/pages/admin/admin.drive-chart.vue: | ||||
|   title: "ドライブ" | ||||
|   local: "ローカル" | ||||
|   remote: "リモート" | ||||
| desktop/views/pages/deck/deck.tl-column.vue: | ||||
|   is-media-only: "メディア投稿のみ" | ||||
|   is-media-view: "メディアビュー" | ||||
| @@ -838,21 +848,26 @@ desktop/views/pages/deck/deck.note.vue: | ||||
|   reposted-by: "{}がRenote" | ||||
|   private: "この投稿は非公開です" | ||||
|   deleted: "この投稿は削除されました" | ||||
| desktop/views/pages/stats/stats.vue: | ||||
|   all-users: "全てのユーザー" | ||||
|   original-users: "このインスタンスのユーザー" | ||||
|   all-notes: "全ての投稿" | ||||
|   original-notes: "このインスタンスの投稿" | ||||
| desktop/views/pages/welcome.vue: | ||||
|   about: "詳しく..." | ||||
|   gotit: "わかった" | ||||
|   signin: "ログイン" | ||||
|   signup: "新規登録" | ||||
|   signin-button: "やってる" | ||||
|   signup-button: "やる" | ||||
|   signin: "サインイン" | ||||
|   signup: "サインアップ" | ||||
|   signin-button: "サインイン中…" | ||||
|   signup-button: "サインアップ" | ||||
|   timeline: "タイムライン" | ||||
|   powered-by-misskey: "Powered by <b>Misskey</b>." | ||||
| desktop/views/pages/drive.vue: | ||||
|   title: "Misskey Drive" | ||||
|   title: "ドライブ" | ||||
| desktop/views/pages/favorites.vue: | ||||
|   more: "さらに読み込む" | ||||
|   more: "もっと読み込んでくで" | ||||
| desktop/views/pages/home-customize.vue: | ||||
|   title: "ホームのカスタマイズ" | ||||
|   title: "ホームをカスタマイズ" | ||||
| desktop/views/pages/note.vue: | ||||
|   prev: "前の投稿" | ||||
|   next: "次の投稿" | ||||
| @@ -887,19 +902,19 @@ desktop/views/pages/user/user.vue: | ||||
| desktop/views/pages/user/user.home.vue: | ||||
|   last-used-at: "最終アクセス" | ||||
| desktop/views/pages/user/user.photos.vue: | ||||
|   title: "フォト" | ||||
|   title: "写真" | ||||
|   loading: "読み込み中" | ||||
|   no-photos: "写真はありません" | ||||
|   no-photos: "写真はあらへんで" | ||||
| desktop/views/pages/user/user.profile.vue: | ||||
|   follows-you: "フォローされています" | ||||
|   follows-you: "フォローされとるで" | ||||
|   stalk: "ストークする" | ||||
|   stalking: "ストーキングしています" | ||||
|   stalking: "ストーキングしとるで" | ||||
|   unstalk: "ストーク解除" | ||||
|   mute: "ミュートする" | ||||
|   muted: "ミュートしています" | ||||
|   muted: "ミュートしとるで" | ||||
|   unmute: "ミュート解除" | ||||
|   push-to-a-list: "リストに追加" | ||||
|   list-pushed: "{user}を{list}に追加しました。" | ||||
|   list-pushed: "{user}を{list}に追加したで。" | ||||
| desktop/views/pages/user/user.header.vue: | ||||
|   posts: "投稿" | ||||
|   following: "フォロー" | ||||
| @@ -918,7 +933,7 @@ desktop/views/widgets/notifications.vue: | ||||
| desktop/views/widgets/polls.vue: | ||||
|   title: "アンケート" | ||||
|   refresh: "他を見る" | ||||
|   nothing: "ありません!" | ||||
|   nothing: "あらへん!" | ||||
| desktop/views/widgets/post-form.vue: | ||||
|   title: "投稿" | ||||
|   note: "投稿" | ||||
| @@ -940,7 +955,7 @@ mobile/views/components/drive.vue: | ||||
|   count-separator: "、" | ||||
|   file-count: "ファイル" | ||||
|   load-more: "もっと読み込む" | ||||
|   nothing-in-drive: "ドライブには何もありません" | ||||
|   nothing-in-drive: "ドライブには何もあらへんで。" | ||||
|   folder-is-empty: "このフォルダは空です" | ||||
|   prompt: "何をしますか?(数字を入力してください): <1 → ファイルをアップロード | 2 → ファイルをURLでアップロード | 3 → フォルダ作成 | 4 → このフォルダ名を変更 | 5 → このフォルダを移動 | 6 → このフォルダを削除>" | ||||
|   deletion-alert: "ごめんなさい!フォルダの削除は未実装です...。" | ||||
| @@ -1017,9 +1032,9 @@ mobile/views/components/post-form.vue: | ||||
|   quote-placeholder: "この投稿を引用... (オプション)" | ||||
|   reply-placeholder: "この投稿への返信..." | ||||
|   cw-placeholder: "内容への注釈 (オプション)" | ||||
|   location-alert: "お使いの端末は位置情報に対応していません" | ||||
|   location-alert: "あんさんのつことる端末は位置情報に対応しとらんみたいやわ、知らんけど。" | ||||
|   error: "エラー" | ||||
|   username-prompt: "ユーザー名を入力してください" | ||||
|   username-prompt: "ユーザー名を入力してや" | ||||
| mobile/views/components/sub-note-content.vue: | ||||
|   private: "この投稿は非公開です" | ||||
|   deleted: "この投稿は削除されました" | ||||
| @@ -1044,6 +1059,7 @@ mobile/views/components/ui.nav.vue: | ||||
|   game: "ゲーム" | ||||
|   darkmode: "ダークモード" | ||||
|   settings: "設定" | ||||
|   admin: "管理" | ||||
|   about: "Misskeyについて" | ||||
| mobile/views/components/user-timeline.vue: | ||||
|   no-notes: "このユーザーは投稿していないようです。" | ||||
| @@ -1057,7 +1073,7 @@ mobile/views/pages/favorites.vue: | ||||
|   title: "お気に入り" | ||||
| mobile/views/pages/user-lists.vue: | ||||
|   title: "リスト" | ||||
|   enter-list-name: "リスト名を入力してください" | ||||
|   enter-list-name: "リスト名を入力してや" | ||||
| mobile/views/pages/drive.vue: | ||||
|   drive: "ドライブ" | ||||
|   more: "もっと見る" | ||||
| @@ -1073,7 +1089,7 @@ mobile/views/pages/home.vue: | ||||
|   hybrid: "ソーシャル" | ||||
|   global: "グローバル" | ||||
| mobile/views/pages/tag.vue: | ||||
|   no-posts-found: "ハッシュタグ「{}」が付けられた投稿は見つかりませんでした。" | ||||
|   no-posts-found: "ハッシュタグ「{}」が付けられた投稿はあらへんで。" | ||||
| mobile/views/pages/welcome.vue: | ||||
|   signup: "新規登録" | ||||
| mobile/views/pages/widgets.vue: | ||||
| @@ -1140,7 +1156,7 @@ mobile/views/pages/settings.vue: | ||||
|   show-local-renotes: "ローカルの投稿のRenoteを表示する" | ||||
|   post-style: "投稿の表示スタイル" | ||||
|   post-style-standard: "標準" | ||||
|   post-style-smart: "スマート" | ||||
|   post-style-smart: "べっぴんさん" | ||||
|   behavior: "動作" | ||||
|   fetch-on-scroll: "スクロールで自動読み込み" | ||||
|   disable-via-mobile: "「モバイルからの投稿」フラグを付けない" | ||||
| @@ -1161,6 +1177,8 @@ mobile/views/pages/settings.vue: | ||||
|   update-available-desc: "ページを再度読み込みすると更新が適用されます。" | ||||
|   settings: "設定" | ||||
|   signout: "サインアウト" | ||||
|   sound: "サウンド" | ||||
|   enableSounds: "サウンドを有効にする" | ||||
| mobile/views/pages/user.vue: | ||||
|   follows-you: "フォローされています" | ||||
|   following: "フォロー" | ||||
|   | ||||
| @@ -58,7 +58,7 @@ common: | ||||
|     friday: "금요일" | ||||
|     saturday: "토요일" | ||||
|   reactions: | ||||
|     like: "ええやん" | ||||
|     like: "いいね" | ||||
|     love: "좋아" | ||||
|     laugh: "크크" | ||||
|     hmm: "음..." | ||||
| @@ -84,6 +84,7 @@ common: | ||||
|   my-token-regenerated: "당신의 토큰이 업데이트되어 있기 때문에 로그 아웃합니다." | ||||
|   i-like-sushi: "나는(푸딩보다 오히려)스시가 좋아" | ||||
|   show-reversi-board-labels: "리버시 보드의 행과 열 레이블을 표시" | ||||
|   use-contrast-reversi-stones: "リバーシのアイコンにコントラストを付ける" | ||||
|   verified-user: "公式アカウント" | ||||
|   disable-animated-mfm: "게시물의 문자 애니메이션을 비활성화 할" | ||||
|   reversi: | ||||
| @@ -410,6 +411,7 @@ desktop: | ||||
|   uploading-avatar: "新しいアバターをアップロードしています" | ||||
|   avatar-updated: "アバターを更新しました" | ||||
|   choose-avatar: "アバターにする画像を選択" | ||||
|   invalid-filetype: "この形式のファイルはサポートされていません" | ||||
| desktop/views/components/activity.chart.vue: | ||||
|   total: "Black ... Total" | ||||
|   notes: "Blue ... Notes" | ||||
| @@ -423,6 +425,24 @@ desktop/views/components/calendar.vue: | ||||
|   prev: "前の月" | ||||
|   next: "次の月" | ||||
|   go: "クリックして時間遡行" | ||||
| desktop/views/components/charts.vue: | ||||
|   title: "チャート" | ||||
|   per-day: "1日ごと" | ||||
|   per-hour: "1時間ごと" | ||||
|   notes: "投稿" | ||||
|   users: "ユーザー" | ||||
|   drive: "ドライブ" | ||||
|   charts: | ||||
|     notes: "投稿の増減 (統合)" | ||||
|     local-notes: "投稿の増減 (ローカル)" | ||||
|     remote-notes: "投稿の増減 (リモート)" | ||||
|     notes-total: "投稿の累計" | ||||
|     users: "ユーザーの増減" | ||||
|     users-total: "ユーザーの累計" | ||||
|     drive: "ドライブ使用量の増減" | ||||
|     drive-total: "ドライブ使用量の累計" | ||||
|     drive-files: "ドライブのファイル数の増減" | ||||
|     drive-files-total: "ドライブのファイル数の累計" | ||||
| desktop/views/components/choose-file-from-drive-window.vue: | ||||
|   choose-file: "ファイル選択中" | ||||
|   upload: "PCからドライブにファイルをアップロード" | ||||
| @@ -630,6 +650,7 @@ desktop/views/components/settings.vue: | ||||
|   gradient-window-header: "ウィンドウのタイトルバーにグラデーションを使用" | ||||
|   post-form-on-timeline: "タイムライン上部に投稿フォームを表示する" | ||||
|   suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する" | ||||
|   show-clock-on-header: "右上に時計を表示する" | ||||
|   show-reply-target: "リプライ先を表示する" | ||||
|   show-my-renotes: "自分の行ったRenoteをタイムラインに表示する" | ||||
|   show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する" | ||||
| @@ -754,6 +775,7 @@ desktop/views/components/ui.header.account.vue: | ||||
|   lists: "リスト" | ||||
|   follow-requests: "フォロー申請" | ||||
|   customize: "ホームのカスタマイズ" | ||||
|   admin: "管理" | ||||
|   settings: "設定" | ||||
|   signout: "サインアウト" | ||||
|   dark: "闇に飲まれる" | ||||
| @@ -799,8 +821,8 @@ desktop/views/pages/admin/admin.dashboard.vue: | ||||
|   dashboard: "ダッシュボード" | ||||
|   all-users: "全てのユーザー" | ||||
|   original-users: "このインスタンスのユーザー" | ||||
|   all-notes: "全てのノート" | ||||
|   original-notes: "このインスタンスのノート" | ||||
|   all-notes: "全ての投稿" | ||||
|   original-notes: "このインスタンスの投稿" | ||||
|   invite: "招待" | ||||
| desktop/views/pages/admin/admin.suspend-user.vue: | ||||
|   suspend-user: "ユーザーの凍結" | ||||
| @@ -818,18 +840,6 @@ desktop/views/pages/admin/admin.unverify-user.vue: | ||||
|   unverify-user: "ユーザーの公式アカウント解除" | ||||
|   unverify: "公式アカウントを解除する" | ||||
|   unverified: "公式アカウントを解除しました" | ||||
| desktop/views/pages/admin/admin.notes-chart.vue: | ||||
|   title: "投稿" | ||||
|   local: "ローカル" | ||||
|   remote: "リモート" | ||||
| desktop/views/pages/admin/admin.users-chart.vue: | ||||
|   title: "ユーザー" | ||||
|   local: "ローカル" | ||||
|   remote: "リモート" | ||||
| desktop/views/pages/admin/admin.drive-chart.vue: | ||||
|   title: "ドライブ" | ||||
|   local: "ローカル" | ||||
|   remote: "リモート" | ||||
| desktop/views/pages/deck/deck.tl-column.vue: | ||||
|   is-media-only: "メディア投稿のみ" | ||||
|   is-media-view: "メディアビュー" | ||||
| @@ -838,6 +848,11 @@ desktop/views/pages/deck/deck.note.vue: | ||||
|   reposted-by: "{}がRenote" | ||||
|   private: "この投稿は非公開です" | ||||
|   deleted: "この投稿は削除されました" | ||||
| desktop/views/pages/stats/stats.vue: | ||||
|   all-users: "全てのユーザー" | ||||
|   original-users: "このインスタンスのユーザー" | ||||
|   all-notes: "全ての投稿" | ||||
|   original-notes: "このインスタンスの投稿" | ||||
| desktop/views/pages/welcome.vue: | ||||
|   about: "詳しく..." | ||||
|   gotit: "わかった" | ||||
| @@ -1044,6 +1059,7 @@ mobile/views/components/ui.nav.vue: | ||||
|   game: "ゲーム" | ||||
|   darkmode: "ダークモード" | ||||
|   settings: "設定" | ||||
|   admin: "管理" | ||||
|   about: "Misskeyについて" | ||||
| mobile/views/components/user-timeline.vue: | ||||
|   no-notes: "このユーザーは投稿していないようです。" | ||||
| @@ -1161,6 +1177,8 @@ mobile/views/pages/settings.vue: | ||||
|   update-available-desc: "ページを再度読み込みすると更新が適用されます。" | ||||
|   settings: "設定" | ||||
|   signout: "サインアウト" | ||||
|   sound: "サウンド" | ||||
|   enableSounds: "サウンドを有効にする" | ||||
| mobile/views/pages/user.vue: | ||||
|   follows-you: "フォローされています" | ||||
|   following: "フォロー" | ||||
|   | ||||
| @@ -58,7 +58,7 @@ common: | ||||
|     friday: "Piątek" | ||||
|     saturday: "Sobota" | ||||
|   reactions: | ||||
|     like: "ええやん" | ||||
|     like: "いいね" | ||||
|     love: "Kocham" | ||||
|     laugh: "Śmieszne" | ||||
|     hmm: "Hmm…?" | ||||
| @@ -84,6 +84,7 @@ common: | ||||
|   my-token-regenerated: "Twój token został wygenerowany. Zostaniesz wylogowany." | ||||
|   i-like-sushi: "Wolę sushi od puddingu" | ||||
|   show-reversi-board-labels: "Pokazuj podpisy wierszy i kolumn w Reversi" | ||||
|   use-contrast-reversi-stones: "リバーシのアイコンにコントラストを付ける" | ||||
|   verified-user: "公式アカウント" | ||||
|   disable-animated-mfm: "Wyłącz animowany tekst we wpisach" | ||||
|   reversi: | ||||
| @@ -410,6 +411,7 @@ desktop: | ||||
|   uploading-avatar: "Wysyłanie awatara" | ||||
|   avatar-updated: "Wysłano awatar" | ||||
|   choose-avatar: "Wybierz awatar" | ||||
|   invalid-filetype: "この形式のファイルはサポートされていません" | ||||
| desktop/views/components/activity.chart.vue: | ||||
|   total: "Czarny … Łącznie" | ||||
|   notes: "Niebieski … Wpisy" | ||||
| @@ -423,6 +425,24 @@ desktop/views/components/calendar.vue: | ||||
|   prev: "Poprzedni miesiąc" | ||||
|   next: "Następny miesiąc" | ||||
|   go: "Naciśnij, aby przejść" | ||||
| desktop/views/components/charts.vue: | ||||
|   title: "チャート" | ||||
|   per-day: "1日ごと" | ||||
|   per-hour: "1時間ごと" | ||||
|   notes: "投稿" | ||||
|   users: "ユーザー" | ||||
|   drive: "ドライブ" | ||||
|   charts: | ||||
|     notes: "投稿の増減 (統合)" | ||||
|     local-notes: "投稿の増減 (ローカル)" | ||||
|     remote-notes: "投稿の増減 (リモート)" | ||||
|     notes-total: "投稿の累計" | ||||
|     users: "ユーザーの増減" | ||||
|     users-total: "ユーザーの累計" | ||||
|     drive: "ドライブ使用量の増減" | ||||
|     drive-total: "ドライブ使用量の累計" | ||||
|     drive-files: "ドライブのファイル数の増減" | ||||
|     drive-files-total: "ドライブのファイル数の累計" | ||||
| desktop/views/components/choose-file-from-drive-window.vue: | ||||
|   choose-file: "Wybierz plik" | ||||
|   upload: "Wyślij pliki z Twojego komputera" | ||||
| @@ -630,6 +650,7 @@ desktop/views/components/settings.vue: | ||||
|   gradient-window-header: "Używaj gradientów na pasku tytułu okna" | ||||
|   post-form-on-timeline: "Wyświetlaj formularz tworzenia wpisu w górnej części osi czasu" | ||||
|   suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する" | ||||
|   show-clock-on-header: "右上に時計を表示する" | ||||
|   show-reply-target: "Pokazuj cel odpowiedzi" | ||||
|   show-my-renotes: "Pokazuj moje udostępnienia na osi czasu" | ||||
|   show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する" | ||||
| @@ -754,6 +775,7 @@ desktop/views/components/ui.header.account.vue: | ||||
|   lists: "Listy" | ||||
|   follow-requests: "Prośby o śledzenie" | ||||
|   customize: "Dostosuj stronę główną" | ||||
|   admin: "管理" | ||||
|   settings: "Ustawienia" | ||||
|   signout: "Wyloguj się" | ||||
|   dark: "Sprowadź ciemność" | ||||
| @@ -799,8 +821,8 @@ desktop/views/pages/admin/admin.dashboard.vue: | ||||
|   dashboard: "ダッシュボード" | ||||
|   all-users: "全てのユーザー" | ||||
|   original-users: "このインスタンスのユーザー" | ||||
|   all-notes: "全てのノート" | ||||
|   original-notes: "このインスタンスのノート" | ||||
|   all-notes: "全ての投稿" | ||||
|   original-notes: "このインスタンスの投稿" | ||||
|   invite: "招待" | ||||
| desktop/views/pages/admin/admin.suspend-user.vue: | ||||
|   suspend-user: "ユーザーの凍結" | ||||
| @@ -818,18 +840,6 @@ desktop/views/pages/admin/admin.unverify-user.vue: | ||||
|   unverify-user: "ユーザーの公式アカウント解除" | ||||
|   unverify: "公式アカウントを解除する" | ||||
|   unverified: "公式アカウントを解除しました" | ||||
| desktop/views/pages/admin/admin.notes-chart.vue: | ||||
|   title: "投稿" | ||||
|   local: "ローカル" | ||||
|   remote: "リモート" | ||||
| desktop/views/pages/admin/admin.users-chart.vue: | ||||
|   title: "ユーザー" | ||||
|   local: "ローカル" | ||||
|   remote: "リモート" | ||||
| desktop/views/pages/admin/admin.drive-chart.vue: | ||||
|   title: "ドライブ" | ||||
|   local: "ローカル" | ||||
|   remote: "リモート" | ||||
| desktop/views/pages/deck/deck.tl-column.vue: | ||||
|   is-media-only: "Tylko wpisy z zawartością multimedialną" | ||||
|   is-media-view: "Widok multimediów" | ||||
| @@ -838,6 +848,11 @@ 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/stats/stats.vue: | ||||
|   all-users: "全てのユーザー" | ||||
|   original-users: "このインスタンスのユーザー" | ||||
|   all-notes: "全ての投稿" | ||||
|   original-notes: "このインスタンスの投稿" | ||||
| desktop/views/pages/welcome.vue: | ||||
|   about: "O Misskey" | ||||
|   gotit: "Rozumiem!" | ||||
| @@ -1044,6 +1059,7 @@ mobile/views/components/ui.nav.vue: | ||||
|   game: "Gry" | ||||
|   darkmode: "Tryb ciemny" | ||||
|   settings: "Ustawienia" | ||||
|   admin: "管理" | ||||
|   about: "O Misskey" | ||||
| mobile/views/components/user-timeline.vue: | ||||
|   no-notes: "Wygląda na to, że ten użytkownik nie opublikował jeszcze niczego" | ||||
| @@ -1161,6 +1177,8 @@ mobile/views/pages/settings.vue: | ||||
|   update-available-desc: "Odśwież stronę, aby zastosować aktualizację." | ||||
|   settings: "Ustawienia" | ||||
|   signout: "Wyloguj" | ||||
|   sound: "サウンド" | ||||
|   enableSounds: "サウンドを有効にする" | ||||
| mobile/views/pages/user.vue: | ||||
|   follows-you: "Śledzi Cię" | ||||
|   following: "Śledzeni" | ||||
|   | ||||
| @@ -58,7 +58,7 @@ common: | ||||
|     friday: "sexta" | ||||
|     saturday: "sábado" | ||||
|   reactions: | ||||
|     like: "Legal..." | ||||
|     like: "Curtir" | ||||
|     love: "Amei" | ||||
|     laugh: "Riso" | ||||
|     hmm: "Hmm...?" | ||||
| @@ -81,9 +81,10 @@ common: | ||||
|   ok: "OK" | ||||
|   update-available-title: "Atualização disponível" | ||||
|   update-available: "Uma nova versão de Misskey está disponível ({newer}). A versão atual é {current}. Recarregue a página para atualizar." | ||||
|   my-token-regenerated: "あなたのトークンが更新されたのでサインアウトします。" | ||||
|   my-token-regenerated: "Seu token foi recriado, portanto você foi deslogado." | ||||
|   i-like-sushi: "Eu prefiro sushi a pudim" | ||||
|   show-reversi-board-labels: "Mostrar etiquetas de colunas e linhas no Reversi" | ||||
|   use-contrast-reversi-stones: "リバーシのアイコンにコントラストを付ける" | ||||
|   verified-user: "Conta verificada" | ||||
|   disable-animated-mfm: "Desativar texto animado nas publicações" | ||||
|   reversi: | ||||
| @@ -96,7 +97,7 @@ common: | ||||
|     black: "Pretas" | ||||
|     white: "Brancas" | ||||
|     total: "Total" | ||||
|     this-turn: "{}ターン目" | ||||
|     this-turn: "Turno de {}" | ||||
|   widgets: | ||||
|     analog-clock: "Relógio analógico" | ||||
|     profile: "Perfil" | ||||
| @@ -105,16 +106,16 @@ common: | ||||
|     activity: "Atividade" | ||||
|     rss: "Leitor de RSS" | ||||
|     memo: "Nota adesiva" | ||||
|     trends: "トレンド" | ||||
|     trends: "Tendências" | ||||
|     photo-stream: "フォトストリーム" | ||||
|     posts-monitor: "投稿チャート" | ||||
|     posts-monitor: "Gráfico de publicações" | ||||
|     slideshow: "スライドショー" | ||||
|     version: "Versão" | ||||
|     broadcast: "ブロードキャスト" | ||||
|     notifications: "Notificações" | ||||
|     users: "Usuário sugeridos" | ||||
|     polls: "Enquetes" | ||||
|     post-form: "投稿フォーム" | ||||
|     post-form: "Formulário de publicação" | ||||
|     messaging: "Mensagens" | ||||
|     server: "Informações do servidor" | ||||
|     donation: "Doações" | ||||
| @@ -134,10 +135,10 @@ common: | ||||
|     swap-up: "Mover para cima" | ||||
|     swap-down: "Mover para baixo" | ||||
|     remove: "Remover" | ||||
|     add-column: "カラムを追加" | ||||
|     add-column: "Adicionar coluna" | ||||
|     rename: "Renomear" | ||||
|     stack-left: "左に重ねる" | ||||
|     pop-right: "右に出す" | ||||
|     pop-right: "Acoplar à direita" | ||||
| 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:" | ||||
| @@ -150,18 +151,18 @@ auth/views/form.vue: | ||||
|   drive-write: "ドライブを操作する。" | ||||
|   notification-read: "通知を見る。" | ||||
|   notification-write: "通知を操作する。" | ||||
|   cancel: "キャンセル" | ||||
|   accept: "アクセスを許可" | ||||
|   cancel: "Cancelar" | ||||
|   accept: "Permitir acesso" | ||||
| auth/views/index.vue: | ||||
|   loading: "読み込み中" | ||||
|   loading: "Carregando" | ||||
|   denied: "アプリケーションの連携をキャンセルしました。" | ||||
|   denied-paragraph: "このアプリがあなたのアカウントにアクセスすることはありません。" | ||||
|   already-authorized: "このアプリは既に連携済みです" | ||||
|   allowed: "アプリケーションの連携を許可しました" | ||||
|   callback-url: "アプリケーションに戻っています" | ||||
|   please-go-back: "アプリケーションに戻って、やっていってください。" | ||||
|   error: "セッションが存在しません。" | ||||
|   sign-in: "サインインしてください" | ||||
|   already-authorized: "Este aplicativo já foi autorizado" | ||||
|   allowed: "Aplicativos com acesso autorizado" | ||||
|   callback-url: "Voltando ao aplicativo" | ||||
|   please-go-back: "Por favor, volte ao aplicativo." | ||||
|   error: "A sessão não existe." | ||||
|   sign-in: "Por favor, entre." | ||||
| common/views/components/games/reversi/reversi.vue: | ||||
|   matching: | ||||
|     waiting-for: "{}を待っています" | ||||
| @@ -175,17 +176,17 @@ common/views/components/games/reversi/reversi.game.vue: | ||||
| common/views/components/games/reversi/reversi.index.vue: | ||||
|   title: "Misskey Reversi" | ||||
|   sub-title: "他のMisskeyユーザーとリバーシで対戦しよう" | ||||
|   invite: "招待" | ||||
|   rule: "遊び方" | ||||
|   invite: "Convidar" | ||||
|   rule: "Como jogar" | ||||
|   rule-desc: "リバーシは、相手と交互に石をボードに置いて、相手の石を挟んで自分の色に変えてゆき、最終的に残った石が多い方が勝ちというボードゲームです。" | ||||
|   mode-invite: "招待" | ||||
|   mode-invite-desc: "指定したユーザーと対戦するモードです。" | ||||
|   invitations: "対局の招待があります!" | ||||
|   my-games: "自分の対局" | ||||
|   all-games: "みんなの対局" | ||||
|   enter-username: "ユーザー名を入力してください" | ||||
|   mode-invite: "Convidar" | ||||
|   mode-invite-desc: "Convidar um usuário para jogar" | ||||
|   invitations: "Você foi convidado!" | ||||
|   my-games: "Meu jogo" | ||||
|   all-games: "Todos os jogos" | ||||
|   enter-username: "Digite o nome de usuário." | ||||
|   game-state: | ||||
|     ended: "終了" | ||||
|     ended: "Terminado" | ||||
|     playing: "進行中" | ||||
| common/views/components/games/reversi/reversi.room.vue: | ||||
|   settings-of-the-game: "ゲームの設定" | ||||
| @@ -227,11 +228,11 @@ common/views/components/connect-failed.troubleshooter.vue: | ||||
|   no-server-desc: "お使いのPCのインターネット接続は正常ですが、Misskeyのサーバーには接続できませんでした。サーバーがダウンまたはメンテナンスしている可能性があるので、しばらくしてから再度御アクセスください。" | ||||
|   success: "Misskeyのサーバーに接続できました" | ||||
|   success-desc: "正常に接続できるようです。ページを再度読み込みしてください。" | ||||
|   flush: "キャッシュの削除" | ||||
|   flush: "Limpar o cache" | ||||
|   set-version: "バージョン指定" | ||||
| common/views/components/messaging.vue: | ||||
|   search-user: "ユーザーを探す" | ||||
|   you: "あなた" | ||||
|   you: "Você" | ||||
|   no-history: "履歴はありません" | ||||
| common/views/components/messaging-room.vue: | ||||
|   empty: "このユーザーと話したことはありません" | ||||
| @@ -410,6 +411,7 @@ desktop: | ||||
|   uploading-avatar: "新しいアバターをアップロードしています" | ||||
|   avatar-updated: "アバターを更新しました" | ||||
|   choose-avatar: "アバターにする画像を選択" | ||||
|   invalid-filetype: "この形式のファイルはサポートされていません" | ||||
| desktop/views/components/activity.chart.vue: | ||||
|   total: "Black ... Total" | ||||
|   notes: "Blue ... Notes" | ||||
| @@ -423,6 +425,24 @@ desktop/views/components/calendar.vue: | ||||
|   prev: "前の月" | ||||
|   next: "次の月" | ||||
|   go: "クリックして時間遡行" | ||||
| desktop/views/components/charts.vue: | ||||
|   title: "チャート" | ||||
|   per-day: "1日ごと" | ||||
|   per-hour: "1時間ごと" | ||||
|   notes: "投稿" | ||||
|   users: "ユーザー" | ||||
|   drive: "ドライブ" | ||||
|   charts: | ||||
|     notes: "投稿の増減 (統合)" | ||||
|     local-notes: "投稿の増減 (ローカル)" | ||||
|     remote-notes: "投稿の増減 (リモート)" | ||||
|     notes-total: "投稿の累計" | ||||
|     users: "ユーザーの増減" | ||||
|     users-total: "ユーザーの累計" | ||||
|     drive: "ドライブ使用量の増減" | ||||
|     drive-total: "ドライブ使用量の累計" | ||||
|     drive-files: "ドライブのファイル数の増減" | ||||
|     drive-files-total: "ドライブのファイル数の累計" | ||||
| desktop/views/components/choose-file-from-drive-window.vue: | ||||
|   choose-file: "ファイル選択中" | ||||
|   upload: "PCからドライブにファイルをアップロード" | ||||
| @@ -630,6 +650,7 @@ desktop/views/components/settings.vue: | ||||
|   gradient-window-header: "ウィンドウのタイトルバーにグラデーションを使用" | ||||
|   post-form-on-timeline: "タイムライン上部に投稿フォームを表示する" | ||||
|   suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する" | ||||
|   show-clock-on-header: "右上に時計を表示する" | ||||
|   show-reply-target: "リプライ先を表示する" | ||||
|   show-my-renotes: "自分の行ったRenoteをタイムラインに表示する" | ||||
|   show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する" | ||||
| @@ -754,6 +775,7 @@ desktop/views/components/ui.header.account.vue: | ||||
|   lists: "リスト" | ||||
|   follow-requests: "フォロー申請" | ||||
|   customize: "ホームのカスタマイズ" | ||||
|   admin: "管理" | ||||
|   settings: "設定" | ||||
|   signout: "サインアウト" | ||||
|   dark: "闇に飲まれる" | ||||
| @@ -799,8 +821,8 @@ desktop/views/pages/admin/admin.dashboard.vue: | ||||
|   dashboard: "ダッシュボード" | ||||
|   all-users: "Todos os usuários" | ||||
|   original-users: "このインスタンスのユーザー" | ||||
|   all-notes: "Todas as notas" | ||||
|   original-notes: "このインスタンスのノート" | ||||
|   all-notes: "全ての投稿" | ||||
|   original-notes: "このインスタンスの投稿" | ||||
|   invite: "招待" | ||||
| desktop/views/pages/admin/admin.suspend-user.vue: | ||||
|   suspend-user: "ユーザーの凍結" | ||||
| @@ -818,18 +840,6 @@ desktop/views/pages/admin/admin.unverify-user.vue: | ||||
|   unverify-user: "ユーザーの公式アカウント解除" | ||||
|   unverify: "公式アカウントを解除する" | ||||
|   unverified: "公式アカウントを解除しました" | ||||
| desktop/views/pages/admin/admin.notes-chart.vue: | ||||
|   title: "投稿" | ||||
|   local: "ローカル" | ||||
|   remote: "リモート" | ||||
| desktop/views/pages/admin/admin.users-chart.vue: | ||||
|   title: "ユーザー" | ||||
|   local: "ローカル" | ||||
|   remote: "リモート" | ||||
| desktop/views/pages/admin/admin.drive-chart.vue: | ||||
|   title: "ドライブ" | ||||
|   local: "ローカル" | ||||
|   remote: "リモート" | ||||
| desktop/views/pages/deck/deck.tl-column.vue: | ||||
|   is-media-only: "メディア投稿のみ" | ||||
|   is-media-view: "メディアビュー" | ||||
| @@ -838,6 +848,11 @@ desktop/views/pages/deck/deck.note.vue: | ||||
|   reposted-by: "{}がRenote" | ||||
|   private: "この投稿は非公開です" | ||||
|   deleted: "この投稿は削除されました" | ||||
| desktop/views/pages/stats/stats.vue: | ||||
|   all-users: "全てのユーザー" | ||||
|   original-users: "このインスタンスのユーザー" | ||||
|   all-notes: "全ての投稿" | ||||
|   original-notes: "このインスタンスの投稿" | ||||
| desktop/views/pages/welcome.vue: | ||||
|   about: "詳しく..." | ||||
|   gotit: "わかった" | ||||
| @@ -1044,6 +1059,7 @@ mobile/views/components/ui.nav.vue: | ||||
|   game: "ゲーム" | ||||
|   darkmode: "ダークモード" | ||||
|   settings: "設定" | ||||
|   admin: "管理" | ||||
|   about: "Misskeyについて" | ||||
| mobile/views/components/user-timeline.vue: | ||||
|   no-notes: "このユーザーは投稿していないようです。" | ||||
| @@ -1161,6 +1177,8 @@ mobile/views/pages/settings.vue: | ||||
|   update-available-desc: "ページを再度読み込みすると更新が適用されます。" | ||||
|   settings: "設定" | ||||
|   signout: "サインアウト" | ||||
|   sound: "サウンド" | ||||
|   enableSounds: "サウンドを有効にする" | ||||
| mobile/views/pages/user.vue: | ||||
|   follows-you: "フォローされています" | ||||
|   following: "フォロー" | ||||
|   | ||||
| @@ -58,7 +58,7 @@ common: | ||||
|     friday: "金曜日" | ||||
|     saturday: "土曜日" | ||||
|   reactions: | ||||
|     like: "ええやん" | ||||
|     like: "いいね" | ||||
|     love: "しゅき" | ||||
|     laugh: "笑" | ||||
|     hmm: "ふぅ~む" | ||||
| @@ -84,6 +84,7 @@ common: | ||||
|   my-token-regenerated: "あなたのトークンが更新されたのでサインアウトします。" | ||||
|   i-like-sushi: "私は(プリンよりむしろ)寿司が好き" | ||||
|   show-reversi-board-labels: "リバーシのボードの行と列のラベルを表示" | ||||
|   use-contrast-reversi-stones: "リバーシのアイコンにコントラストを付ける" | ||||
|   verified-user: "公式アカウント" | ||||
|   disable-animated-mfm: "投稿内の動きのあるテキストを無効にする" | ||||
|   reversi: | ||||
| @@ -410,6 +411,7 @@ desktop: | ||||
|   uploading-avatar: "新しいアバターをアップロードしています" | ||||
|   avatar-updated: "アバターを更新しました" | ||||
|   choose-avatar: "アバターにする画像を選択" | ||||
|   invalid-filetype: "この形式のファイルはサポートされていません" | ||||
| desktop/views/components/activity.chart.vue: | ||||
|   total: "Black ... Total" | ||||
|   notes: "Blue ... Notes" | ||||
| @@ -423,6 +425,24 @@ desktop/views/components/calendar.vue: | ||||
|   prev: "前の月" | ||||
|   next: "次の月" | ||||
|   go: "クリックして時間遡行" | ||||
| desktop/views/components/charts.vue: | ||||
|   title: "チャート" | ||||
|   per-day: "1日ごと" | ||||
|   per-hour: "1時間ごと" | ||||
|   notes: "投稿" | ||||
|   users: "ユーザー" | ||||
|   drive: "ドライブ" | ||||
|   charts: | ||||
|     notes: "投稿の増減 (統合)" | ||||
|     local-notes: "投稿の増減 (ローカル)" | ||||
|     remote-notes: "投稿の増減 (リモート)" | ||||
|     notes-total: "投稿の累計" | ||||
|     users: "ユーザーの増減" | ||||
|     users-total: "ユーザーの累計" | ||||
|     drive: "ドライブ使用量の増減" | ||||
|     drive-total: "ドライブ使用量の累計" | ||||
|     drive-files: "ドライブのファイル数の増減" | ||||
|     drive-files-total: "ドライブのファイル数の累計" | ||||
| desktop/views/components/choose-file-from-drive-window.vue: | ||||
|   choose-file: "ファイル選択中" | ||||
|   upload: "PCからドライブにファイルをアップロード" | ||||
| @@ -630,6 +650,7 @@ desktop/views/components/settings.vue: | ||||
|   gradient-window-header: "ウィンドウのタイトルバーにグラデーションを使用" | ||||
|   post-form-on-timeline: "タイムライン上部に投稿フォームを表示する" | ||||
|   suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する" | ||||
|   show-clock-on-header: "右上に時計を表示する" | ||||
|   show-reply-target: "リプライ先を表示する" | ||||
|   show-my-renotes: "自分の行ったRenoteをタイムラインに表示する" | ||||
|   show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する" | ||||
| @@ -754,6 +775,7 @@ desktop/views/components/ui.header.account.vue: | ||||
|   lists: "リスト" | ||||
|   follow-requests: "フォロー申請" | ||||
|   customize: "ホームのカスタマイズ" | ||||
|   admin: "管理" | ||||
|   settings: "設定" | ||||
|   signout: "サインアウト" | ||||
|   dark: "闇に飲まれる" | ||||
| @@ -799,8 +821,8 @@ desktop/views/pages/admin/admin.dashboard.vue: | ||||
|   dashboard: "ダッシュボード" | ||||
|   all-users: "全てのユーザー" | ||||
|   original-users: "このインスタンスのユーザー" | ||||
|   all-notes: "全てのノート" | ||||
|   original-notes: "このインスタンスのノート" | ||||
|   all-notes: "全ての投稿" | ||||
|   original-notes: "このインスタンスの投稿" | ||||
|   invite: "招待" | ||||
| desktop/views/pages/admin/admin.suspend-user.vue: | ||||
|   suspend-user: "ユーザーの凍結" | ||||
| @@ -818,18 +840,6 @@ desktop/views/pages/admin/admin.unverify-user.vue: | ||||
|   unverify-user: "ユーザーの公式アカウント解除" | ||||
|   unverify: "公式アカウントを解除する" | ||||
|   unverified: "公式アカウントを解除しました" | ||||
| desktop/views/pages/admin/admin.notes-chart.vue: | ||||
|   title: "投稿" | ||||
|   local: "ローカル" | ||||
|   remote: "リモート" | ||||
| desktop/views/pages/admin/admin.users-chart.vue: | ||||
|   title: "ユーザー" | ||||
|   local: "ローカル" | ||||
|   remote: "リモート" | ||||
| desktop/views/pages/admin/admin.drive-chart.vue: | ||||
|   title: "ドライブ" | ||||
|   local: "ローカル" | ||||
|   remote: "リモート" | ||||
| desktop/views/pages/deck/deck.tl-column.vue: | ||||
|   is-media-only: "メディア投稿のみ" | ||||
|   is-media-view: "メディアビュー" | ||||
| @@ -838,6 +848,11 @@ desktop/views/pages/deck/deck.note.vue: | ||||
|   reposted-by: "{}がRenote" | ||||
|   private: "この投稿は非公開です" | ||||
|   deleted: "この投稿は削除されました" | ||||
| desktop/views/pages/stats/stats.vue: | ||||
|   all-users: "全てのユーザー" | ||||
|   original-users: "このインスタンスのユーザー" | ||||
|   all-notes: "全ての投稿" | ||||
|   original-notes: "このインスタンスの投稿" | ||||
| desktop/views/pages/welcome.vue: | ||||
|   about: "詳しく..." | ||||
|   gotit: "わかった" | ||||
| @@ -1044,6 +1059,7 @@ mobile/views/components/ui.nav.vue: | ||||
|   game: "ゲーム" | ||||
|   darkmode: "ダークモード" | ||||
|   settings: "設定" | ||||
|   admin: "管理" | ||||
|   about: "Misskeyについて" | ||||
| mobile/views/components/user-timeline.vue: | ||||
|   no-notes: "このユーザーは投稿していないようです。" | ||||
| @@ -1161,6 +1177,8 @@ mobile/views/pages/settings.vue: | ||||
|   update-available-desc: "ページを再度読み込みすると更新が適用されます。" | ||||
|   settings: "設定" | ||||
|   signout: "サインアウト" | ||||
|   sound: "サウンド" | ||||
|   enableSounds: "サウンドを有効にする" | ||||
| mobile/views/pages/user.vue: | ||||
|   follows-you: "フォローされています" | ||||
|   following: "フォロー" | ||||
|   | ||||
| @@ -58,7 +58,7 @@ common: | ||||
|     friday: "金曜日" | ||||
|     saturday: "土曜日" | ||||
|   reactions: | ||||
|     like: "ええやん" | ||||
|     like: "いいね" | ||||
|     love: "しゅき" | ||||
|     laugh: "笑" | ||||
|     hmm: "ふぅ~む" | ||||
| @@ -84,6 +84,7 @@ common: | ||||
|   my-token-regenerated: "あなたのトークンが更新されたのでサインアウトします。" | ||||
|   i-like-sushi: "私は(プリンよりむしろ)寿司が好き" | ||||
|   show-reversi-board-labels: "リバーシのボードの行と列のラベルを表示" | ||||
|   use-contrast-reversi-stones: "リバーシのアイコンにコントラストを付ける" | ||||
|   verified-user: "公式アカウント" | ||||
|   disable-animated-mfm: "投稿内の動きのあるテキストを無効にする" | ||||
|   reversi: | ||||
| @@ -410,6 +411,7 @@ desktop: | ||||
|   uploading-avatar: "新しいアバターをアップロードしています" | ||||
|   avatar-updated: "アバターを更新しました" | ||||
|   choose-avatar: "アバターにする画像を選択" | ||||
|   invalid-filetype: "この形式のファイルはサポートされていません" | ||||
| desktop/views/components/activity.chart.vue: | ||||
|   total: "Black ... Total" | ||||
|   notes: "Blue ... Notes" | ||||
| @@ -423,6 +425,24 @@ desktop/views/components/calendar.vue: | ||||
|   prev: "前の月" | ||||
|   next: "次の月" | ||||
|   go: "クリックして時間遡行" | ||||
| desktop/views/components/charts.vue: | ||||
|   title: "チャート" | ||||
|   per-day: "1日ごと" | ||||
|   per-hour: "1時間ごと" | ||||
|   notes: "投稿" | ||||
|   users: "ユーザー" | ||||
|   drive: "ドライブ" | ||||
|   charts: | ||||
|     notes: "投稿の増減 (統合)" | ||||
|     local-notes: "投稿の増減 (ローカル)" | ||||
|     remote-notes: "投稿の増減 (リモート)" | ||||
|     notes-total: "投稿の累計" | ||||
|     users: "ユーザーの増減" | ||||
|     users-total: "ユーザーの累計" | ||||
|     drive: "ドライブ使用量の増減" | ||||
|     drive-total: "ドライブ使用量の累計" | ||||
|     drive-files: "ドライブのファイル数の増減" | ||||
|     drive-files-total: "ドライブのファイル数の累計" | ||||
| desktop/views/components/choose-file-from-drive-window.vue: | ||||
|   choose-file: "ファイル選択中" | ||||
|   upload: "PCからドライブにファイルをアップロード" | ||||
| @@ -630,6 +650,7 @@ desktop/views/components/settings.vue: | ||||
|   gradient-window-header: "ウィンドウのタイトルバーにグラデーションを使用" | ||||
|   post-form-on-timeline: "タイムライン上部に投稿フォームを表示する" | ||||
|   suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する" | ||||
|   show-clock-on-header: "右上に時計を表示する" | ||||
|   show-reply-target: "リプライ先を表示する" | ||||
|   show-my-renotes: "自分の行ったRenoteをタイムラインに表示する" | ||||
|   show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する" | ||||
| @@ -754,6 +775,7 @@ desktop/views/components/ui.header.account.vue: | ||||
|   lists: "リスト" | ||||
|   follow-requests: "フォロー申請" | ||||
|   customize: "ホームのカスタマイズ" | ||||
|   admin: "管理" | ||||
|   settings: "設定" | ||||
|   signout: "サインアウト" | ||||
|   dark: "闇に飲まれる" | ||||
| @@ -799,8 +821,8 @@ desktop/views/pages/admin/admin.dashboard.vue: | ||||
|   dashboard: "ダッシュボード" | ||||
|   all-users: "全てのユーザー" | ||||
|   original-users: "このインスタンスのユーザー" | ||||
|   all-notes: "全てのノート" | ||||
|   original-notes: "このインスタンスのノート" | ||||
|   all-notes: "全ての投稿" | ||||
|   original-notes: "このインスタンスの投稿" | ||||
|   invite: "招待" | ||||
| desktop/views/pages/admin/admin.suspend-user.vue: | ||||
|   suspend-user: "ユーザーの凍結" | ||||
| @@ -818,18 +840,6 @@ desktop/views/pages/admin/admin.unverify-user.vue: | ||||
|   unverify-user: "ユーザーの公式アカウント解除" | ||||
|   unverify: "公式アカウントを解除する" | ||||
|   unverified: "公式アカウントを解除しました" | ||||
| desktop/views/pages/admin/admin.notes-chart.vue: | ||||
|   title: "投稿" | ||||
|   local: "ローカル" | ||||
|   remote: "リモート" | ||||
| desktop/views/pages/admin/admin.users-chart.vue: | ||||
|   title: "ユーザー" | ||||
|   local: "ローカル" | ||||
|   remote: "リモート" | ||||
| desktop/views/pages/admin/admin.drive-chart.vue: | ||||
|   title: "ドライブ" | ||||
|   local: "ローカル" | ||||
|   remote: "リモート" | ||||
| desktop/views/pages/deck/deck.tl-column.vue: | ||||
|   is-media-only: "メディア投稿のみ" | ||||
|   is-media-view: "メディアビュー" | ||||
| @@ -838,6 +848,11 @@ desktop/views/pages/deck/deck.note.vue: | ||||
|   reposted-by: "{}がRenote" | ||||
|   private: "この投稿は非公開です" | ||||
|   deleted: "この投稿は削除されました" | ||||
| desktop/views/pages/stats/stats.vue: | ||||
|   all-users: "全てのユーザー" | ||||
|   original-users: "このインスタンスのユーザー" | ||||
|   all-notes: "全ての投稿" | ||||
|   original-notes: "このインスタンスの投稿" | ||||
| desktop/views/pages/welcome.vue: | ||||
|   about: "詳しく..." | ||||
|   gotit: "わかった" | ||||
| @@ -1044,6 +1059,7 @@ mobile/views/components/ui.nav.vue: | ||||
|   game: "ゲーム" | ||||
|   darkmode: "ダークモード" | ||||
|   settings: "設定" | ||||
|   admin: "管理" | ||||
|   about: "Misskeyについて" | ||||
| mobile/views/components/user-timeline.vue: | ||||
|   no-notes: "このユーザーは投稿していないようです。" | ||||
| @@ -1161,6 +1177,8 @@ mobile/views/pages/settings.vue: | ||||
|   update-available-desc: "ページを再度読み込みすると更新が適用されます。" | ||||
|   settings: "設定" | ||||
|   signout: "サインアウト" | ||||
|   sound: "サウンド" | ||||
|   enableSounds: "サウンドを有効にする" | ||||
| mobile/views/pages/user.vue: | ||||
|   follows-you: "フォローされています" | ||||
|   following: "フォロー" | ||||
|   | ||||
							
								
								
									
										28
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										28
									
								
								package.json
									
									
									
									
									
								
							| @@ -1,8 +1,8 @@ | ||||
| { | ||||
| 	"name": "misskey", | ||||
| 	"author": "syuilo <i@syuilo.com>", | ||||
| 	"version": "8.7.0", | ||||
| 	"clientVersion": "1.0.8840", | ||||
| 	"version": "8.16.0", | ||||
| 	"clientVersion": "1.0.9191", | ||||
| 	"codename": "nighthike", | ||||
| 	"main": "./built/index.js", | ||||
| 	"private": true, | ||||
| @@ -32,7 +32,7 @@ | ||||
| 		"@types/debug": "0.0.30", | ||||
| 		"@types/deep-equal": "1.0.1", | ||||
| 		"@types/double-ended-queue": "2.1.0", | ||||
| 		"@types/elasticsearch": "5.0.25", | ||||
| 		"@types/elasticsearch": "5.0.26", | ||||
| 		"@types/file-type": "5.2.1", | ||||
| 		"@types/gulp": "3.8.36", | ||||
| 		"@types/gulp-htmlmin": "1.3.32", | ||||
| @@ -60,7 +60,7 @@ | ||||
| 		"@types/mocha": "5.2.3", | ||||
| 		"@types/mongodb": "3.1.4", | ||||
| 		"@types/ms": "0.7.30", | ||||
| 		"@types/node": "10.7.1", | ||||
| 		"@types/node": "10.9.3", | ||||
| 		"@types/portscanner": "2.1.0", | ||||
| 		"@types/pug": "2.0.4", | ||||
| 		"@types/qrcode": "1.2.0", | ||||
| @@ -70,16 +70,16 @@ | ||||
| 		"@types/request-promise-native": "1.0.15", | ||||
| 		"@types/rimraf": "2.0.2", | ||||
| 		"@types/seedrandom": "2.4.27", | ||||
| 		"@types/sharp": "0.17.9", | ||||
| 		"@types/sharp": "0.17.10", | ||||
| 		"@types/showdown": "1.7.5", | ||||
| 		"@types/single-line-log": "1.1.0", | ||||
| 		"@types/speakeasy": "2.0.2", | ||||
| 		"@types/systeminformation": "3.23.0", | ||||
| 		"@types/tmp": "0.0.33", | ||||
| 		"@types/uuid": "3.4.3", | ||||
| 		"@types/webpack": "4.4.10", | ||||
| 		"@types/uuid": "3.4.4", | ||||
| 		"@types/webpack": "4.4.11", | ||||
| 		"@types/webpack-stream": "3.2.10", | ||||
| 		"@types/websocket": "0.0.39", | ||||
| 		"@types/websocket": "0.0.40", | ||||
| 		"@types/ws": "6.0.0", | ||||
| 		"animejs": "2.2.0", | ||||
| 		"autosize": "4.0.2", | ||||
| @@ -158,7 +158,7 @@ | ||||
| 		"mongodb": "3.1.1", | ||||
| 		"monk": "6.0.6", | ||||
| 		"ms": "2.1.1", | ||||
| 		"nan": "2.10.0", | ||||
| 		"nan": "2.11.0", | ||||
| 		"nested-property": "0.0.7", | ||||
| 		"node-sass": "4.9.3", | ||||
| 		"node-sass-json-importer": "3.3.1", | ||||
| @@ -190,11 +190,11 @@ | ||||
| 		"single-line-log": "1.1.2", | ||||
| 		"speakeasy": "2.0.0", | ||||
| 		"stringz": "1.0.0", | ||||
| 		"style-loader": "0.22.1", | ||||
| 		"style-loader": "0.23.0", | ||||
| 		"stylus": "0.54.5", | ||||
| 		"stylus-loader": "3.0.2", | ||||
| 		"summaly": "2.1.4", | ||||
| 		"systeminformation": "3.42.9", | ||||
| 		"summaly": "2.2.0", | ||||
| 		"systeminformation": "3.44.2", | ||||
| 		"syuilo-password-strength": "0.0.1", | ||||
| 		"textarea-caret": "3.1.0", | ||||
| 		"tmp": "0.0.33", | ||||
| @@ -210,9 +210,9 @@ | ||||
| 		"vue": "2.5.17", | ||||
| 		"vue-chartjs": "3.4.0", | ||||
| 		"vue-cropperjs": "2.2.1", | ||||
| 		"vue-js-modal": "1.3.18", | ||||
| 		"vue-js-modal": "1.3.24", | ||||
| 		"vue-json-tree-view": "2.1.4", | ||||
| 		"vue-loader": "15.4.0", | ||||
| 		"vue-loader": "15.4.1", | ||||
| 		"vue-router": "3.0.1", | ||||
| 		"vue-style-loader": "4.1.2", | ||||
| 		"vue-template-compiler": "2.5.17", | ||||
|   | ||||
| @@ -51,8 +51,9 @@ | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (settings) { | ||||
| 		if (settings.device.lang) lang = settings.device.lang; | ||||
| 	if (settings && settings.device.lang && | ||||
| 		LANGS.includes(settings.device.lang)) { | ||||
| 		lang = settings.device.lang; | ||||
| 	} | ||||
| 	//#endregion | ||||
|  | ||||
|   | ||||
| @@ -26,8 +26,8 @@ export default Vue.extend({ | ||||
| 	}, | ||||
| 	created() { | ||||
| 		(this as any).os.getMeta().then(meta => { | ||||
| 			if (meta.repositoryUrl) this.repositoryUrl = meta.repositoryUrl; | ||||
| 			if (meta.feedbackUrl) this.feedbackUrl = meta.feedbackUrl; | ||||
| 			if (meta.maintainer.repository_url) this.repositoryUrl = meta.maintainer.repository_url; | ||||
| 			if (meta.maintainer.feedback_url) this.feedbackUrl = meta.maintainer.feedback_url; | ||||
| 		}); | ||||
| 	} | ||||
| }); | ||||
|   | ||||
| @@ -28,69 +28,8 @@ | ||||
| import Vue from 'vue'; | ||||
| import { url as misskeyUrl } from '../../../config'; | ||||
|  | ||||
| export default Vue.extend({ | ||||
| 	props: { | ||||
| 		url: { | ||||
| 			type: String, | ||||
| 			require: true | ||||
| 		}, | ||||
| 		detail: { | ||||
| 			type: Boolean, | ||||
| 			required: false, | ||||
| 			default: false | ||||
| 		} | ||||
| 	}, | ||||
| 	data() { | ||||
| 		return { | ||||
| 			fetching: true, | ||||
| 			title: null, | ||||
| 			description: null, | ||||
| 			thumbnail: null, | ||||
| 			icon: null, | ||||
| 			sitename: null, | ||||
| 			player: { | ||||
| 				url: null, | ||||
| 				width: null, | ||||
| 				height: null | ||||
| 			}, | ||||
| 			tweetUrl: null, | ||||
| 			misskeyUrl | ||||
| 		}; | ||||
| 	}, | ||||
| 	created() { | ||||
| 		const url = new URL(this.url); | ||||
|  | ||||
| 		if (this.detail && url.hostname == 'twitter.com' && /^\/.+\/status(es)?\/\d+/.test(url.pathname)) { | ||||
| 			this.tweetUrl = url; | ||||
| 			const twttr = (window as any).twttr || {}; | ||||
| 			const loadTweet = () => twttr.widgets.load(this.$refs.tweet); | ||||
|  | ||||
| 			if (twttr.widgets) { | ||||
| 				Vue.nextTick(loadTweet); | ||||
| 			} else { | ||||
| 				const wjsId = 'twitter-wjs'; | ||||
| 				if (!document.getElementById(wjsId)) { | ||||
| 					const head = document.getElementsByTagName('head')[0]; | ||||
| 					const script = document.createElement('script'); | ||||
| 					script.setAttribute('id', wjsId); | ||||
| 					script.setAttribute('src', 'https://platform.twitter.com/widgets.js'); | ||||
| 					head.appendChild(script); | ||||
| 				} | ||||
| 				twttr.ready = loadTweet; | ||||
| 				(window as any).twttr = twttr; | ||||
| 			} | ||||
| 			return; | ||||
| 		} | ||||
| 		fetch('/url?url=' + encodeURIComponent(this.url)).then(res => { | ||||
| 			res.json().then(info => { | ||||
| 				if (info.url != null) { | ||||
| 					this.title = info.title; | ||||
| 					this.description = info.description; | ||||
| 					this.thumbnail = info.thumbnail; | ||||
| 					this.icon = info.icon; | ||||
| 					this.sitename = info.sitename; | ||||
| 					this.fetching = false; | ||||
| 					if ([ // THIS IS THE WHITELIST FOR THE EMBED PLAYER | ||||
| // THIS IS THE WHITELIST FOR THE EMBED PLAYER | ||||
| const whiteList = [ | ||||
| 	'afreecatv.com', | ||||
| 	'aparat.com', | ||||
| 	'applemusic.com', | ||||
| @@ -166,12 +105,80 @@ export default Vue.extend({ | ||||
| 	'web.tv', | ||||
| 	'youtube.com', | ||||
| 	'youtu.be' | ||||
| 					].some(x => x == url.hostname || url.hostname.endsWith(`.${x}`))) | ||||
| ]; | ||||
|  | ||||
| export default Vue.extend({ | ||||
| 	props: { | ||||
| 		url: { | ||||
| 			type: String, | ||||
| 			require: true | ||||
| 		}, | ||||
|  | ||||
| 		detail: { | ||||
| 			type: Boolean, | ||||
| 			required: false, | ||||
| 			default: false | ||||
| 		} | ||||
| 	}, | ||||
|  | ||||
| 	data() { | ||||
| 		return { | ||||
| 			fetching: true, | ||||
| 			title: null, | ||||
| 			description: null, | ||||
| 			thumbnail: null, | ||||
| 			icon: null, | ||||
| 			sitename: null, | ||||
| 			player: { | ||||
| 				url: null, | ||||
| 				width: null, | ||||
| 				height: null | ||||
| 			}, | ||||
| 			tweetUrl: null, | ||||
| 			misskeyUrl | ||||
| 		}; | ||||
| 	}, | ||||
|  | ||||
| 	created() { | ||||
| 		const url = new URL(this.url); | ||||
|  | ||||
| 		if (this.detail && url.hostname == 'twitter.com' && /^\/.+\/status(es)?\/\d+/.test(url.pathname)) { | ||||
| 			this.tweetUrl = url; | ||||
| 			const twttr = (window as any).twttr || {}; | ||||
| 			const loadTweet = () => twttr.widgets.load(this.$refs.tweet); | ||||
|  | ||||
| 			if (twttr.widgets) { | ||||
| 				Vue.nextTick(loadTweet); | ||||
| 			} else { | ||||
| 				const wjsId = 'twitter-wjs'; | ||||
| 				if (!document.getElementById(wjsId)) { | ||||
| 					const head = document.getElementsByTagName('head')[0]; | ||||
| 					const script = document.createElement('script'); | ||||
| 					script.setAttribute('id', wjsId); | ||||
| 					script.setAttribute('src', 'https://platform.twitter.com/widgets.js'); | ||||
| 					head.appendChild(script); | ||||
| 				} | ||||
| 				twttr.ready = loadTweet; | ||||
| 				(window as any).twttr = twttr; | ||||
| 			} | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
| 		fetch('/url?url=' + encodeURIComponent(this.url)).then(res => { | ||||
| 			res.json().then(info => { | ||||
| 				if (info.url == null) return; | ||||
| 				this.title = info.title; | ||||
| 				this.description = info.description; | ||||
| 				this.thumbnail = info.thumbnail; | ||||
| 				this.icon = info.icon; | ||||
| 				this.sitename = info.sitename; | ||||
| 				this.fetching = false; | ||||
| 				if (whiteList.some(x => x == url.hostname || url.hostname.endsWith(`.${x}`))) { | ||||
| 					this.player = info.player; | ||||
| 				}	// info.url | ||||
| 			})	// json | ||||
| 		});	// fetch | ||||
| 	}	// created | ||||
| 				} | ||||
| 			}) | ||||
| 		}); | ||||
| 	} | ||||
| }); | ||||
| </script> | ||||
|  | ||||
|   | ||||
| @@ -2,9 +2,9 @@ | ||||
| <div class="mkw-donation" :data-mobile="platform == 'mobile'"> | ||||
| 	<article> | ||||
| 		<h1>%fa:heart%%i18n:@title%</h1> | ||||
| 		<p> | ||||
| 		<p v-if="meta"> | ||||
| 			{{ '%i18n:@text%'.substr(0, '%i18n:@text%'.indexOf('{')) }} | ||||
| 			<a href="https://syuilo.com">@syuilo</a> | ||||
| 			<a :href="meta.maintainer.url">{{ meta.maintainer.name }}</a> | ||||
| 			{{ '%i18n:@text%'.substr('%i18n:@text%'.indexOf('}') + 1) }} | ||||
| 		</p> | ||||
| 	</article> | ||||
| @@ -15,6 +15,17 @@ | ||||
| import define from '../../../common/define-widget'; | ||||
| export default define({ | ||||
| 	name: 'donation' | ||||
| }).extend({ | ||||
| 	data() { | ||||
| 		return { | ||||
| 			meta: null | ||||
| 		}; | ||||
| 	}, | ||||
| 	created() { | ||||
| 		(this as any).os.getMeta().then(meta => { | ||||
| 			this.meta = meta; | ||||
| 		}); | ||||
| 	} | ||||
| }); | ||||
| </script> | ||||
|  | ||||
|   | ||||
| @@ -4,6 +4,7 @@ declare const _THEME_COLOR_: string; | ||||
| declare const _COPYRIGHT_: string; | ||||
| declare const _VERSION_: string; | ||||
| declare const _CODENAME_: string; | ||||
| declare const _ENV_: string; | ||||
|  | ||||
| const address = new URL(location.href); | ||||
|  | ||||
| @@ -18,3 +19,4 @@ export const themeColor = _THEME_COLOR_; | ||||
| export const copyright = _COPYRIGHT_; | ||||
| export const version = _VERSION_; | ||||
| export const codename = _CODENAME_; | ||||
| export const env = _ENV_; | ||||
|   | ||||
| @@ -3,8 +3,21 @@ import { apiUrl } from '../../config'; | ||||
| import CropWindow from '../views/components/crop-window.vue'; | ||||
| import ProgressDialog from '../views/components/progress-dialog.vue'; | ||||
|  | ||||
| export default (os: OS) => (cb, file = null) => { | ||||
| 	const fileSelected = file => { | ||||
| export default (os: OS) => { | ||||
|  | ||||
| 	const cropImage = file => new Promise((resolve, reject) => { | ||||
|  | ||||
| 		const regex = RegExp('\.(jpg|jpeg|png|gif|webp|bmp|tiff)$'); | ||||
| 		if (!regex.test(file.name) ) { | ||||
| 			os.apis.dialog({ | ||||
| 				title: '%fa:info-circle% %i18n:desktop.invalid-filetype%', | ||||
| 				text: null, | ||||
| 				actions: [{ | ||||
| 					text: '%i18n:common.got-it%' | ||||
| 				}] | ||||
| 			}); | ||||
| 			reject(); | ||||
| 		} | ||||
|  | ||||
| 		const w = os.new(CropWindow, { | ||||
| 			image: file, | ||||
| @@ -19,27 +32,29 @@ export default (os: OS) => (cb, file = null) => { | ||||
|  | ||||
| 			os.api('drive/folders/find', { | ||||
| 				name: '%i18n:desktop.avatar%' | ||||
| 			}).then(iconFolder => { | ||||
| 				if (iconFolder.length === 0) { | ||||
| 			}).then(avatarFolder => { | ||||
| 				if (avatarFolder.length === 0) { | ||||
| 					os.api('drive/folders/create', { | ||||
| 						name: '%i18n:desktop.avatar%' | ||||
| 					}).then(iconFolder => { | ||||
| 						upload(data, iconFolder); | ||||
| 						resolve(upload(data, iconFolder)); | ||||
| 					}); | ||||
| 				} else { | ||||
| 					upload(data, iconFolder[0]); | ||||
| 					resolve(upload(data, avatarFolder[0])); | ||||
| 				} | ||||
| 			}); | ||||
| 		}); | ||||
|  | ||||
| 		w.$once('skipped', () => { | ||||
| 			set(file); | ||||
| 			resolve(file); | ||||
| 		}); | ||||
|  | ||||
| 		document.body.appendChild(w.$el); | ||||
| 	}; | ||||
| 		w.$once('cancelled', reject); | ||||
|  | ||||
| 	const upload = (data, folder) => { | ||||
| 		document.body.appendChild(w.$el); | ||||
| 	}); | ||||
|  | ||||
| 	const upload = (data, folder) => new Promise((resolve, reject) => { | ||||
| 		const dialog = os.new(ProgressDialog, { | ||||
| 			title: '%i18n:desktop.uploading-avatar%' | ||||
| 		}); | ||||
| @@ -52,18 +67,19 @@ export default (os: OS) => (cb, file = null) => { | ||||
| 		xhr.onload = e => { | ||||
| 			const file = JSON.parse((e.target as any).response); | ||||
| 			(dialog as any).close(); | ||||
| 			set(file); | ||||
| 			resolve(file); | ||||
| 		}; | ||||
| 		xhr.onerror = reject; | ||||
|  | ||||
| 		xhr.upload.onprogress = e => { | ||||
| 			if (e.lengthComputable) (dialog as any).update(e.loaded, e.total); | ||||
| 		}; | ||||
|  | ||||
| 		xhr.send(data); | ||||
| 	}; | ||||
| 	}); | ||||
|  | ||||
| 	const set = file => { | ||||
| 		os.api('i/update', { | ||||
| 	const setAvatar = file => { | ||||
| 		return os.api('i/update', { | ||||
| 			avatarId: file.id | ||||
| 		}).then(i => { | ||||
| 			os.store.commit('updateIKeyValue', { | ||||
| @@ -83,18 +99,21 @@ export default (os: OS) => (cb, file = null) => { | ||||
| 				}] | ||||
| 			}); | ||||
|  | ||||
| 			if (cb) cb(i); | ||||
| 			return i; | ||||
| 		}); | ||||
| 	}; | ||||
|  | ||||
| 	if (file) { | ||||
| 		fileSelected(file); | ||||
| 	} else { | ||||
| 		os.apis.chooseDriveFile({ | ||||
| 	return (file = null) => { | ||||
| 		const selectedFile = file | ||||
| 			? Promise.resolve(file) | ||||
| 			: os.apis.chooseDriveFile({ | ||||
| 				multiple: false, | ||||
| 				title: '%fa:image% %i18n:desktop.choose-avatar%' | ||||
| 		}).then(file => { | ||||
| 			fileSelected(file); | ||||
| 			}); | ||||
| 	} | ||||
|  | ||||
| 		return selectedFile | ||||
| 			.then(cropImage) | ||||
| 			.then(setAvatar) | ||||
| 			.catch(err => err && console.warn(err)); | ||||
| 	}; | ||||
| }; | ||||
|   | ||||
| @@ -6,6 +6,19 @@ import ProgressDialog from '../views/components/progress-dialog.vue'; | ||||
| export default (os: OS) => { | ||||
|  | ||||
| 	const cropImage = file => new Promise((resolve, reject) => { | ||||
|  | ||||
| 		const regex = RegExp('\.(jpg|jpeg|png|gif|webp|bmp|tiff)$'); | ||||
| 		if (!regex.test(file.name) ) { | ||||
| 			os.apis.dialog({ | ||||
| 				title: '%fa:info-circle% %i18n:desktop.invalid-filetype%', | ||||
| 				text: null, | ||||
| 				actions: [{ | ||||
| 					text: '%i18n:common.got-it%' | ||||
| 				}] | ||||
| 			}); | ||||
| 			reject(); | ||||
| 		} | ||||
|  | ||||
| 		const w = os.new(CropWindow, { | ||||
| 			image: file, | ||||
| 			title: '%i18n:desktop.banner-crop-title%', | ||||
|   | ||||
| @@ -25,6 +25,7 @@ import updateBanner from './api/update-banner'; | ||||
| import MkIndex from './views/pages/index.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'; | ||||
| import MkUser from './views/pages/user/user.vue'; | ||||
| import MkFavorites from './views/pages/favorites.vue'; | ||||
| import MkSelectDrive from './views/pages/selectdrive.vue'; | ||||
| @@ -57,6 +58,7 @@ init(async (launch) => { | ||||
| 			{ path: '/', name: 'index', component: MkIndex }, | ||||
| 			{ path: '/deck', name: 'deck', component: MkDeck }, | ||||
| 			{ path: '/admin', name: 'admin', component: MkAdmin }, | ||||
| 			{ path: '/stats', name: 'stats', component: MkStats }, | ||||
| 			{ path: '/i/customize-home', component: MkHomeCustomize }, | ||||
| 			{ path: '/i/favorites', component: MkFavorites }, | ||||
| 			{ path: '/i/messaging/:user', component: MkMessagingRoom }, | ||||
| @@ -94,7 +96,7 @@ init(async (launch) => { | ||||
| 	/** | ||||
| 	 * Init Notification | ||||
| 	 */ | ||||
| 	if ('Notification' in window) { | ||||
| 	if ('Notification' in window && os.store.getters.isSignedIn) { | ||||
| 		// 許可を得ていなかったらリクエスト | ||||
| 		if ((Notification as any).permission == 'default') { | ||||
| 			await Notification.requestPermission(); | ||||
|   | ||||
							
								
								
									
										587
									
								
								src/client/app/desktop/views/components/charts.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										587
									
								
								src/client/app/desktop/views/components/charts.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,587 @@ | ||||
| <template> | ||||
| <div class="gkgckalzgidaygcxnugepioremxvxvpt"> | ||||
| 	<header> | ||||
| 		<b>%i18n:@title%:</b> | ||||
| 		<select v-model="chartType"> | ||||
| 			<optgroup label="%i18n:@users%"> | ||||
| 				<option value="users">%i18n:@charts.users%</option> | ||||
| 				<option value="users-total">%i18n:@charts.users-total%</option> | ||||
| 			</optgroup> | ||||
| 			<optgroup label="%i18n:@notes%"> | ||||
| 				<option value="notes">%i18n:@charts.notes%</option> | ||||
| 				<option value="local-notes">%i18n:@charts.local-notes%</option> | ||||
| 				<option value="remote-notes">%i18n:@charts.remote-notes%</option> | ||||
| 				<option value="notes-total">%i18n:@charts.notes-total%</option> | ||||
| 			</optgroup> | ||||
| 			<optgroup label="%i18n:@drive%"> | ||||
| 				<option value="drive-files">%i18n:@charts.drive-files%</option> | ||||
| 				<option value="drive-files-total">%i18n:@charts.drive-files-total%</option> | ||||
| 				<option value="drive">%i18n:@charts.drive%</option> | ||||
| 				<option value="drive-total">%i18n:@charts.drive-total%</option> | ||||
| 			</optgroup> | ||||
| 		</select> | ||||
| 		<div> | ||||
| 			<span @click="span = 'day'" :class="{ active: span == 'day' }">%i18n:@per-day%</span> | <span @click="span = 'hour'" :class="{ active: span == 'hour' }">%i18n:@per-hour%</span> | ||||
| 		</div> | ||||
| 	</header> | ||||
| 	<div> | ||||
| 		<x-chart v-if="chart" :data="data[0]" :opts="data[1]"/> | ||||
| 	</div> | ||||
| </div> | ||||
| </template> | ||||
|  | ||||
| <script lang="ts"> | ||||
| import Vue from 'vue'; | ||||
| import XChart from './charts.chart.ts'; | ||||
|  | ||||
| const colors = { | ||||
| 	local: 'rgb(246, 88, 79)', | ||||
| 	remote: 'rgb(65, 221, 222)', | ||||
|  | ||||
| 	localPlus: 'rgb(52, 178, 118)', | ||||
| 	remotePlus: 'rgb(158, 255, 209)', | ||||
| 	localMinus: 'rgb(255, 97, 74)', | ||||
| 	remoteMinus: 'rgb(255, 149, 134)' | ||||
| }; | ||||
|  | ||||
| const rgba = (color: string): string => { | ||||
| 	return color.replace('rgb', 'rgba').replace(')', ', 0.1)'); | ||||
| }; | ||||
|  | ||||
| export default Vue.extend({ | ||||
| 	components: { | ||||
| 		XChart | ||||
| 	}, | ||||
|  | ||||
| 	data() { | ||||
| 		return { | ||||
| 			chart: null, | ||||
| 			chartType: 'notes', | ||||
| 			span: 'hour' | ||||
| 		}; | ||||
| 	}, | ||||
|  | ||||
| 	computed: { | ||||
| 		data(): any { | ||||
| 			if (this.chart == null) return null; | ||||
| 			switch (this.chartType) { | ||||
| 				case 'users': return this.usersChart(false); | ||||
| 				case 'users-total': return this.usersChart(true); | ||||
| 				case 'notes': return this.notesChart('combined'); | ||||
| 				case 'local-notes': return this.notesChart('local'); | ||||
| 				case 'remote-notes': return this.notesChart('remote'); | ||||
| 				case 'notes-total': return this.notesTotalChart(); | ||||
| 				case 'drive': return this.driveChart(); | ||||
| 				case 'drive-total': return this.driveTotalChart(); | ||||
| 				case 'drive-files': return this.driveFilesChart(); | ||||
| 				case 'drive-files-total': return this.driveFilesTotalChart(); | ||||
| 			} | ||||
| 		}, | ||||
|  | ||||
| 		stats(): any[] { | ||||
| 			return ( | ||||
| 				this.span == 'day' ? this.chart.perDay : | ||||
| 				this.span == 'hour' ? this.chart.perHour : | ||||
| 				null | ||||
| 			); | ||||
| 		} | ||||
| 	}, | ||||
|  | ||||
| 	created() { | ||||
| 		(this as any).api('chart', { | ||||
| 			limit: 32 | ||||
| 		}).then(chart => { | ||||
| 			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) | ||||
| 			})); | ||||
|  | ||||
| 			return [{ | ||||
| 				datasets: [{ | ||||
| 					label: 'All', | ||||
| 					fill: false, | ||||
| 					borderColor: '#555', | ||||
| 					borderWidth: 2, | ||||
| 					borderDash: [4, 4], | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.all })) | ||||
| 				}, { | ||||
| 					label: 'Renotes', | ||||
| 					fill: true, | ||||
| 					backgroundColor: 'rgba(161, 222, 65, 0.1)', | ||||
| 					borderColor: '#a1de41', | ||||
| 					borderWidth: 2, | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.renote })) | ||||
| 				}, { | ||||
| 					label: 'Replies', | ||||
| 					fill: true, | ||||
| 					backgroundColor: 'rgba(247, 121, 108, 0.1)', | ||||
| 					borderColor: '#f7796c', | ||||
| 					borderWidth: 2, | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.reply })) | ||||
| 				}, { | ||||
| 					label: 'Normal', | ||||
| 					fill: true, | ||||
| 					backgroundColor: 'rgba(65, 221, 222, 0.1)', | ||||
| 					borderColor: '#41ddde', | ||||
| 					borderWidth: 2, | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.normal })) | ||||
| 				}] | ||||
| 			}, { | ||||
| 				scales: { | ||||
| 					yAxes: [{ | ||||
| 						ticks: { | ||||
| 							callback: value => { | ||||
| 								return Vue.filter('number')(value); | ||||
| 							} | ||||
| 						} | ||||
| 					}] | ||||
| 				}, | ||||
| 				tooltips: { | ||||
| 					callbacks: { | ||||
| 						label: (tooltipItem, data) => { | ||||
| 							const label = data.datasets[tooltipItem.datasetIndex].label || ''; | ||||
| 							return `${label}: ${Vue.filter('number')(tooltipItem.yLabel)}`; | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 			}]; | ||||
| 		}, | ||||
|  | ||||
| 		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', | ||||
| 					fill: false, | ||||
| 					borderColor: '#555', | ||||
| 					borderWidth: 2, | ||||
| 					borderDash: [4, 4], | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.remoteCount + x.localCount })) | ||||
| 				}, { | ||||
| 					label: 'Local', | ||||
| 					fill: true, | ||||
| 					backgroundColor: rgba(colors.local), | ||||
| 					borderColor: colors.local, | ||||
| 					borderWidth: 2, | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.localCount })) | ||||
| 				}, { | ||||
| 					label: 'Remote', | ||||
| 					fill: true, | ||||
| 					backgroundColor: rgba(colors.remote), | ||||
| 					borderColor: colors.remote, | ||||
| 					borderWidth: 2, | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.remoteCount })) | ||||
| 				}] | ||||
| 			}, { | ||||
| 				scales: { | ||||
| 					yAxes: [{ | ||||
| 						ticks: { | ||||
| 							callback: value => { | ||||
| 								return Vue.filter('number')(value); | ||||
| 							} | ||||
| 						} | ||||
| 					}] | ||||
| 				}, | ||||
| 				tooltips: { | ||||
| 					callbacks: { | ||||
| 						label: (tooltipItem, data) => { | ||||
| 							const label = data.datasets[tooltipItem.datasetIndex].label || ''; | ||||
| 							return `${label}: ${Vue.filter('number')(tooltipItem.yLabel)}`; | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 			}]; | ||||
| 		}, | ||||
|  | ||||
| 		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', | ||||
| 					fill: false, | ||||
| 					borderColor: '#555', | ||||
| 					borderWidth: 2, | ||||
| 					borderDash: [4, 4], | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.remoteCount + x.localCount })) | ||||
| 				}, { | ||||
| 					label: 'Local', | ||||
| 					fill: true, | ||||
| 					backgroundColor: rgba(colors.local), | ||||
| 					borderColor: colors.local, | ||||
| 					borderWidth: 2, | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.localCount })) | ||||
| 				}, { | ||||
| 					label: 'Remote', | ||||
| 					fill: true, | ||||
| 					backgroundColor: rgba(colors.remote), | ||||
| 					borderColor: colors.remote, | ||||
| 					borderWidth: 2, | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.remoteCount })) | ||||
| 				}] | ||||
| 			}, { | ||||
| 				scales: { | ||||
| 					yAxes: [{ | ||||
| 						ticks: { | ||||
| 							callback: value => { | ||||
| 								return Vue.filter('number')(value); | ||||
| 							} | ||||
| 						} | ||||
| 					}] | ||||
| 				}, | ||||
| 				tooltips: { | ||||
| 					callbacks: { | ||||
| 						label: (tooltipItem, data) => { | ||||
| 							const label = data.datasets[tooltipItem.datasetIndex].label || ''; | ||||
| 							return `${label}: ${Vue.filter('number')(tooltipItem.yLabel)}`; | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 			}]; | ||||
| 		}, | ||||
|  | ||||
| 		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', | ||||
| 					fill: false, | ||||
| 					borderColor: '#555', | ||||
| 					borderWidth: 2, | ||||
| 					borderDash: [4, 4], | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.localInc + x.localDec + x.remoteInc + x.remoteDec })) | ||||
| 				}, { | ||||
| 					label: 'Local +', | ||||
| 					fill: true, | ||||
| 					backgroundColor: rgba(colors.localPlus), | ||||
| 					borderColor: colors.localPlus, | ||||
| 					borderWidth: 2, | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.localInc })) | ||||
| 				}, { | ||||
| 					label: 'Local -', | ||||
| 					fill: true, | ||||
| 					backgroundColor: rgba(colors.localMinus), | ||||
| 					borderColor: colors.localMinus, | ||||
| 					borderWidth: 2, | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.localDec })) | ||||
| 				}, { | ||||
| 					label: 'Remote +', | ||||
| 					fill: true, | ||||
| 					backgroundColor: rgba(colors.remotePlus), | ||||
| 					borderColor: colors.remotePlus, | ||||
| 					borderWidth: 2, | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.remoteInc })) | ||||
| 				}, { | ||||
| 					label: 'Remote -', | ||||
| 					fill: true, | ||||
| 					backgroundColor: rgba(colors.remoteMinus), | ||||
| 					borderColor: colors.remoteMinus, | ||||
| 					borderWidth: 2, | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.remoteDec })) | ||||
| 				}] | ||||
| 			}, { | ||||
| 				scales: { | ||||
| 					yAxes: [{ | ||||
| 						ticks: { | ||||
| 							callback: value => { | ||||
| 								return Vue.filter('bytes')(value, 1); | ||||
| 							} | ||||
| 						} | ||||
| 					}] | ||||
| 				}, | ||||
| 				tooltips: { | ||||
| 					callbacks: { | ||||
| 						label: (tooltipItem, data) => { | ||||
| 							const label = data.datasets[tooltipItem.datasetIndex].label || ''; | ||||
| 							return `${label}: ${Vue.filter('bytes')(tooltipItem.yLabel, 1)}`; | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 			}]; | ||||
| 		}, | ||||
|  | ||||
| 		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', | ||||
| 					fill: false, | ||||
| 					borderColor: '#555', | ||||
| 					borderWidth: 2, | ||||
| 					borderDash: [4, 4], | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.remoteSize + x.localSize })) | ||||
| 				}, { | ||||
| 					label: 'Local', | ||||
| 					fill: true, | ||||
| 					backgroundColor: rgba(colors.local), | ||||
| 					borderColor: colors.local, | ||||
| 					borderWidth: 2, | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.localSize })) | ||||
| 				}, { | ||||
| 					label: 'Remote', | ||||
| 					fill: true, | ||||
| 					backgroundColor: rgba(colors.remote), | ||||
| 					borderColor: colors.remote, | ||||
| 					borderWidth: 2, | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.remoteSize })) | ||||
| 				}] | ||||
| 			}, { | ||||
| 				scales: { | ||||
| 					yAxes: [{ | ||||
| 						ticks: { | ||||
| 							callback: value => { | ||||
| 								return Vue.filter('bytes')(value, 1); | ||||
| 							} | ||||
| 						} | ||||
| 					}] | ||||
| 				}, | ||||
| 				tooltips: { | ||||
| 					callbacks: { | ||||
| 						label: (tooltipItem, data) => { | ||||
| 							const label = data.datasets[tooltipItem.datasetIndex].label || ''; | ||||
| 							return `${label}: ${Vue.filter('bytes')(tooltipItem.yLabel, 1)}`; | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 			}]; | ||||
| 		}, | ||||
|  | ||||
| 		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', | ||||
| 					fill: false, | ||||
| 					borderColor: '#555', | ||||
| 					borderWidth: 2, | ||||
| 					borderDash: [4, 4], | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.localInc + x.localDec + x.remoteInc + x.remoteDec })) | ||||
| 				}, { | ||||
| 					label: 'Local +', | ||||
| 					fill: true, | ||||
| 					backgroundColor: rgba(colors.localPlus), | ||||
| 					borderColor: colors.localPlus, | ||||
| 					borderWidth: 2, | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.localInc })) | ||||
| 				}, { | ||||
| 					label: 'Local -', | ||||
| 					fill: true, | ||||
| 					backgroundColor: rgba(colors.localMinus), | ||||
| 					borderColor: colors.localMinus, | ||||
| 					borderWidth: 2, | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.localDec })) | ||||
| 				}, { | ||||
| 					label: 'Remote +', | ||||
| 					fill: true, | ||||
| 					backgroundColor: rgba(colors.remotePlus), | ||||
| 					borderColor: colors.remotePlus, | ||||
| 					borderWidth: 2, | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.remoteInc })) | ||||
| 				}, { | ||||
| 					label: 'Remote -', | ||||
| 					fill: true, | ||||
| 					backgroundColor: rgba(colors.remoteMinus), | ||||
| 					borderColor: colors.remoteMinus, | ||||
| 					borderWidth: 2, | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.remoteDec })) | ||||
| 				}] | ||||
| 			}, { | ||||
| 				scales: { | ||||
| 					yAxes: [{ | ||||
| 						ticks: { | ||||
| 							callback: value => { | ||||
| 								return Vue.filter('number')(value); | ||||
| 							} | ||||
| 						} | ||||
| 					}] | ||||
| 				}, | ||||
| 				tooltips: { | ||||
| 					callbacks: { | ||||
| 						label: (tooltipItem, data) => { | ||||
| 							const label = data.datasets[tooltipItem.datasetIndex].label || ''; | ||||
| 							return `${label}: ${Vue.filter('number')(tooltipItem.yLabel)}`; | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 			}]; | ||||
| 		}, | ||||
|  | ||||
| 		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', | ||||
| 					fill: false, | ||||
| 					borderColor: '#555', | ||||
| 					borderWidth: 2, | ||||
| 					borderDash: [4, 4], | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.localCount + x.remoteCount })) | ||||
| 				}, { | ||||
| 					label: 'Local', | ||||
| 					fill: true, | ||||
| 					backgroundColor: rgba(colors.local), | ||||
| 					borderColor: colors.local, | ||||
| 					borderWidth: 2, | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.localCount })) | ||||
| 				}, { | ||||
| 					label: 'Remote', | ||||
| 					fill: true, | ||||
| 					backgroundColor: rgba(colors.remote), | ||||
| 					borderColor: colors.remote, | ||||
| 					borderWidth: 2, | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.remoteCount })) | ||||
| 				}] | ||||
| 			}, { | ||||
| 				scales: { | ||||
| 					yAxes: [{ | ||||
| 						ticks: { | ||||
| 							callback: value => { | ||||
| 								return Vue.filter('number')(value); | ||||
| 							} | ||||
| 						} | ||||
| 					}] | ||||
| 				}, | ||||
| 				tooltips: { | ||||
| 					callbacks: { | ||||
| 						label: (tooltipItem, data) => { | ||||
| 							const label = data.datasets[tooltipItem.datasetIndex].label || ''; | ||||
| 							return `${label}: ${Vue.filter('number')(tooltipItem.yLabel)}`; | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 			}]; | ||||
| 		} | ||||
| 	} | ||||
| }); | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| @import '~const.styl' | ||||
|  | ||||
| .gkgckalzgidaygcxnugepioremxvxvpt | ||||
| 	padding 32px | ||||
| 	background #fff | ||||
| 	box-shadow 0 2px 8px rgba(#000, 0.1) | ||||
|  | ||||
| 	* | ||||
| 		user-select none | ||||
|  | ||||
| 	> header | ||||
| 		display flex | ||||
| 		margin 0 0 1em 0 | ||||
| 		padding 0 0 8px 0 | ||||
| 		font-size 1em | ||||
| 		color #555 | ||||
| 		border-bottom solid 1px #eee | ||||
|  | ||||
| 		> b | ||||
| 			margin-right 8px | ||||
|  | ||||
| 		> *:last-child | ||||
| 			margin-left auto | ||||
|  | ||||
| 			* | ||||
| 				&:not(.active) | ||||
| 					color $theme-color | ||||
| 					cursor pointer | ||||
|  | ||||
| 	> div | ||||
| 		> * | ||||
| 			display block | ||||
| 			height 320px | ||||
|  | ||||
| </style> | ||||
| @@ -47,7 +47,7 @@ | ||||
| 			</div> | ||||
| 			<mk-poll v-if="p.poll" :note="p"/> | ||||
| 			<mk-url-preview v-for="url in urls" :url="url" :key="url" :detail="true"/> | ||||
| 			<a class="location" v-if="p.geo" :href="`http://maps.google.com/maps?q=${p.geo.coordinates[1]},${p.geo.coordinates[0]}`" target="_blank">%fa:map-marker-alt% %i18n:@location%</a> | ||||
| 			<a class="location" v-if="p.geo" :href="`https://maps.google.com/maps?q=${p.geo.coordinates[1]},${p.geo.coordinates[0]}`" target="_blank">%fa:map-marker-alt% %i18n:@location%</a> | ||||
| 			<div class="map" v-if="p.geo" ref="map"></div> | ||||
| 			<div class="renote" v-if="p.renote"> | ||||
| 				<mk-note-preview :note="p.renote"/> | ||||
|   | ||||
| @@ -32,7 +32,7 @@ | ||||
| 						<mk-media-list :media-list="p.media"/> | ||||
| 					</div> | ||||
| 					<mk-poll v-if="p.poll" :note="p" ref="pollViewer"/> | ||||
| 					<a class="location" v-if="p.geo" :href="`http://maps.google.com/maps?q=${p.geo.coordinates[1]},${p.geo.coordinates[0]}`" target="_blank">%fa:map-marker-alt% 位置情報</a> | ||||
| 					<a class="location" v-if="p.geo" :href="`https://maps.google.com/maps?q=${p.geo.coordinates[1]},${p.geo.coordinates[0]}`" target="_blank">%fa:map-marker-alt% 位置情報</a> | ||||
| 					<div class="map" v-if="p.geo" ref="map"></div> | ||||
| 					<div class="renote" v-if="p.renote"> | ||||
| 						<mk-note-preview :note="p.renote"/> | ||||
|   | ||||
| @@ -49,6 +49,7 @@ | ||||
| 			</div> | ||||
| 			<mk-switch v-model="$store.state.settings.showPostFormOnTopOfTl" @change="onChangeShowPostFormOnTopOfTl" text="%i18n:@post-form-on-timeline%"/> | ||||
| 			<mk-switch v-model="$store.state.settings.suggestRecentHashtags" @change="onChangeSuggestRecentHashtags" text="%i18n:@suggest-recent-hashtags%"/> | ||||
| 			<mk-switch v-model="$store.state.settings.showClockOnHeader" @change="onChangeShowClockOnHeader" text="%i18n:@show-clock-on-header%"/> | ||||
| 			<mk-switch v-model="$store.state.settings.showReplyTarget" @change="onChangeShowReplyTarget" text="%i18n:@show-reply-target%"/> | ||||
| 			<mk-switch v-model="$store.state.settings.showMyRenotes" @change="onChangeShowMyRenotes" text="%i18n:@show-my-renotes%"/> | ||||
| 			<mk-switch v-model="$store.state.settings.showRenotedMyNotes" @change="onChangeShowRenotedMyNotes" text="%i18n:@show-renoted-my-notes%"/> | ||||
| @@ -333,6 +334,12 @@ export default Vue.extend({ | ||||
| 				value: v | ||||
| 			}); | ||||
| 		}, | ||||
| 		onChangeShowClockOnHeader(v) { | ||||
| 			this.$store.dispatch('settings/set', { | ||||
| 				key: 'showClockOnHeader', | ||||
| 				value: v | ||||
| 			}); | ||||
| 		}, | ||||
| 		onChangeShowReplyTarget(v) { | ||||
| 			this.$store.dispatch('settings/set', { | ||||
| 				key: 'showReplyTarget', | ||||
|   | ||||
| @@ -11,7 +11,7 @@ | ||||
| 			<li class="deck" :class="{ active: $route.name == 'deck' }" @click="goToTop"> | ||||
| 				<router-link to="/deck"> | ||||
| 					%fa:columns% | ||||
| 					<p>%i18n:@deck% <small>(beta)</small></p> | ||||
| 					<p>%i18n:@deck%</p> | ||||
| 				</router-link> | ||||
| 			</li> | ||||
| 			<li class="messaging"> | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| <template> | ||||
| <div class="header"> | ||||
| 	<p class="warn" v-if="env != 'production'">%i18n:common.do-not-use-in-production%</p> | ||||
| 	<mk-special-message/> | ||||
| 	<div class="main" ref="main"> | ||||
| 		<div class="backdrop"></div> | ||||
| @@ -17,7 +18,7 @@ | ||||
| 					<x-account v-if="$store.getters.isSignedIn"/> | ||||
| 					<x-notifications v-if="$store.getters.isSignedIn"/> | ||||
| 					<x-post v-if="$store.getters.isSignedIn"/> | ||||
| 					<x-clock/> | ||||
| 					<x-clock v-if="$store.state.settings.showClockOnHeader"/> | ||||
| 				</div> | ||||
| 			</div> | ||||
| 		</div> | ||||
| @@ -28,6 +29,7 @@ | ||||
| <script lang="ts"> | ||||
| import Vue from 'vue'; | ||||
| import * as anime from 'animejs'; | ||||
| import { env } from '../../../config'; | ||||
|  | ||||
| import XNav from './ui.header.nav.vue'; | ||||
| import XSearch from './ui.header.search.vue'; | ||||
| @@ -43,7 +45,13 @@ export default Vue.extend({ | ||||
| 		XAccount, | ||||
| 		XNotifications, | ||||
| 		XPost, | ||||
| 		XClock, | ||||
| 		XClock | ||||
| 	}, | ||||
|  | ||||
| 	data() { | ||||
| 		return { | ||||
| 			env: env | ||||
| 		}; | ||||
| 	}, | ||||
|  | ||||
| 	mounted() { | ||||
| @@ -119,6 +127,15 @@ root(isDark) | ||||
| 	width 100% | ||||
| 	box-shadow 0 1px 1px rgba(#000, 0.075) | ||||
|  | ||||
| 	> .warn | ||||
| 		display block | ||||
| 		margin 0 | ||||
| 		padding 4px | ||||
| 		text-align center | ||||
| 		font-size 12px | ||||
| 		background #f00 | ||||
| 		color #fff | ||||
|  | ||||
| 	> .main | ||||
| 		height 48px | ||||
|  | ||||
|   | ||||
| @@ -48,7 +48,7 @@ export default Vue.extend({ | ||||
| 				this.open(); | ||||
| 			}); | ||||
| 		} else { | ||||
| 			const query = this.user[0] == '@' ? | ||||
| 			const query = this.user.startsWith('@') ? | ||||
| 				parseAcct(this.user.substr(1)) : | ||||
| 				{ userId: this.user }; | ||||
|  | ||||
|   | ||||
| @@ -1,267 +0,0 @@ | ||||
| <template> | ||||
| <div class="card gkgckalzgidaygcxnugepioremxvxvpt"> | ||||
| 	<header> | ||||
| 		<b>%i18n:@title%:</b> | ||||
| 		<select v-model="chartType"> | ||||
| 			<optgroup label="%i18n:@users%"> | ||||
| 				<option value="local-users">%i18n:@local-users%</option> | ||||
| 				<option value="remote-users">%i18n:@remote-users%</option> | ||||
| 				<option value="local-users-total">%i18n:@local-users-total%</option> | ||||
| 				<option value="remote-users-total">%i18n:@remote-users-total%</option> | ||||
| 			</optgroup> | ||||
| 			<optgroup label="%i18n:@notes%"> | ||||
| 				<option value="local-notes">%i18n:@local-notes%</option> | ||||
| 				<option value="remote-notes">%i18n:@remote-notes%</option> | ||||
| 				<option value="local-notes-total">%i18n:@local-notes-total%</option> | ||||
| 				<option value="remote-notes-total">%i18n:@remote-notes-total%</option> | ||||
| 			</optgroup> | ||||
| 			<optgroup label="%i18n:@drive%"> | ||||
| 				<option value="local-drive-files">%i18n:@local-drive-files%</option> | ||||
| 				<option value="remote-drive-files">%i18n:@remote-drive-files%</option> | ||||
| 				<option value="local-drive-files-total">%i18n:@local-drive-files-total%</option> | ||||
| 				<option value="remote-drive-files-total">%i18n:@remote-drive-files-total%</option> | ||||
| 				<option value="local-drive">%i18n:@local-drive%</option> | ||||
| 				<option value="remote-drive">%i18n:@remote-drive%</option> | ||||
| 				<option value="local-drive-total">%i18n:@local-drive-total%</option> | ||||
| 				<option value="remote-drive-total">%i18n:@remote-drive-total%</option> | ||||
| 			</optgroup> | ||||
| 		</select> | ||||
| 		<div> | ||||
| 			<a @click="span = 'day'">%i18n:@per-day%</a> | <a @click="span = 'hour'">%i18n:@per-hour%</a> | ||||
| 		</div> | ||||
| 	</header> | ||||
| 	<div> | ||||
| 		<x-chart v-if="chart" :data="data[0]" :opts="data[1]"/> | ||||
| 	</div> | ||||
| </div> | ||||
| </template> | ||||
|  | ||||
| <script lang="ts"> | ||||
| import Vue from 'vue'; | ||||
| import XChart from './admin.chart.chart.ts'; | ||||
|  | ||||
| export default Vue.extend({ | ||||
| 	components: { | ||||
| 		XChart | ||||
| 	}, | ||||
| 	data() { | ||||
| 		return { | ||||
| 			chart: null, | ||||
| 			chartType: 'local-notes', | ||||
| 			span: 'hour' | ||||
| 		}; | ||||
| 	}, | ||||
| 	computed: { | ||||
| 		data(): any { | ||||
| 			if (this.chart == null) return null; | ||||
| 			switch (this.chartType) { | ||||
| 				case 'local-users': return this.usersChart(true, false); | ||||
| 				case 'remote-users': return this.usersChart(false, false); | ||||
| 				case 'local-users-total': return this.usersChart(true, true); | ||||
| 				case 'remote-users-total': return this.usersChart(false, true); | ||||
| 				case 'local-notes': return this.notesChart(true); | ||||
| 				case 'remote-notes': return this.notesChart(false); | ||||
| 				case 'local-notes-total': return this.notesTotalChart(true); | ||||
| 				case 'remote-notes-total': return this.notesTotalChart(false); | ||||
| 				case 'local-drive': return this.driveChart(true, false); | ||||
| 				case 'remote-drive': return this.driveChart(false, false); | ||||
| 				case 'local-drive-total': return this.driveChart(true, true); | ||||
| 				case 'remote-drive-total': return this.driveChart(false, true); | ||||
| 				case 'local-drive-files': return this.driveFilesChart(true, false); | ||||
| 				case 'remote-drive-files': return this.driveFilesChart(false, false); | ||||
| 				case 'local-drive-files-total': return this.driveFilesChart(true, true); | ||||
| 				case 'remote-drive-files-total': return this.driveFilesChart(false, true); | ||||
| 			} | ||||
| 		}, | ||||
| 		stats(): any[] { | ||||
| 			return ( | ||||
| 				this.span == 'day' ? this.chart.perDay : | ||||
| 				this.span == 'hour' ? this.chart.perHour : | ||||
| 				null | ||||
| 			); | ||||
| 		} | ||||
| 	}, | ||||
| 	created() { | ||||
| 		(this as any).api('chart').then(chart => { | ||||
| 			this.chart = chart; | ||||
| 		}); | ||||
| 	}, | ||||
| 	methods: { | ||||
| 		notesChart(local: boolean): any { | ||||
| 			const data = this.stats.slice().reverse().map(x => ({ | ||||
| 				date: new Date(x.date), | ||||
| 				normal: local ? x.notes.local.diffs.normal : x.notes.remote.diffs.normal, | ||||
| 				reply: local ? x.notes.local.diffs.reply : x.notes.remote.diffs.reply, | ||||
| 				renote: local ? x.notes.local.diffs.renote : x.notes.remote.diffs.renote, | ||||
| 				all: local ? x.notes.local.diff : x.notes.remote.diff | ||||
| 			})); | ||||
|  | ||||
| 			return [{ | ||||
| 				datasets: [{ | ||||
| 					label: 'All', | ||||
| 					fill: false, | ||||
| 					borderColor: '#555', | ||||
| 					borderWidth: 2, | ||||
| 					borderDash: [4, 4], | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.all })) | ||||
| 				}, { | ||||
| 					label: 'Normal', | ||||
| 					fill: true, | ||||
| 					backgroundColor: 'rgba(65, 221, 222, 0.1)', | ||||
| 					borderColor: '#41ddde', | ||||
| 					borderWidth: 2, | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.normal })) | ||||
| 				}, { | ||||
| 					label: 'Replies', | ||||
| 					fill: true, | ||||
| 					backgroundColor: 'rgba(247, 121, 108, 0.1)', | ||||
| 					borderColor: '#f7796c', | ||||
| 					borderWidth: 2, | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.reply })) | ||||
| 				}, { | ||||
| 					label: 'Renotes', | ||||
| 					fill: true, | ||||
| 					backgroundColor: 'rgba(161, 222, 65, 0.1)', | ||||
| 					borderColor: '#a1de41', | ||||
| 					borderWidth: 2, | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.renote })) | ||||
| 				}] | ||||
| 			}]; | ||||
| 		}, | ||||
|  | ||||
| 		notesTotalChart(local: boolean): any { | ||||
| 			const data = this.stats.slice().reverse().map(x => ({ | ||||
| 				date: new Date(x.date), | ||||
| 				count: local ? x.notes.local.total : x.notes.remote.total, | ||||
| 			})); | ||||
|  | ||||
| 			return [{ | ||||
| 				datasets: [{ | ||||
| 					label: local ? 'Local Notes' : 'Remote Notes', | ||||
| 					fill: true, | ||||
| 					backgroundColor: 'rgba(246, 88, 79, 0.1)', | ||||
| 					borderColor: '#f6584f', | ||||
| 					borderWidth: 2, | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.count })) | ||||
| 				}] | ||||
| 			}]; | ||||
| 		}, | ||||
|  | ||||
| 		usersChart(local: boolean, total: boolean): any { | ||||
| 			const data = this.stats.slice().reverse().map(x => ({ | ||||
| 				date: new Date(x.date), | ||||
| 				count: local ? | ||||
| 					total ? x.users.local.total : x.users.local.diff : | ||||
| 					total ? x.users.remote.total : x.users.remote.diff | ||||
| 			})); | ||||
|  | ||||
| 			return [{ | ||||
| 				datasets: [{ | ||||
| 					label: local ? 'Local Users' : 'Remote Users', | ||||
| 					fill: true, | ||||
| 					backgroundColor: 'rgba(246, 88, 79, 0.1)', | ||||
| 					borderColor: '#f6584f', | ||||
| 					borderWidth: 2, | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.count })) | ||||
| 				}] | ||||
| 			}]; | ||||
| 		}, | ||||
|  | ||||
| 		driveChart(local: boolean, total: boolean): any { | ||||
| 			const data = this.stats.slice().reverse().map(x => ({ | ||||
| 				date: new Date(x.date), | ||||
| 				size: local ? | ||||
| 					total ? x.drive.local.totalSize : x.drive.local.diffSize : | ||||
| 					total ? x.drive.remote.totalSize : x.drive.remote.diffSize | ||||
| 			})); | ||||
|  | ||||
| 			return [{ | ||||
| 				datasets: [{ | ||||
| 					label: local ? 'Local Drive Usage' : 'Remote Drive Usage', | ||||
| 					fill: true, | ||||
| 					backgroundColor: 'rgba(246, 88, 79, 0.1)', | ||||
| 					borderColor: '#f6584f', | ||||
| 					borderWidth: 2, | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.size })) | ||||
| 				}] | ||||
| 			}, { | ||||
| 				scales: { | ||||
| 					yAxes: [{ | ||||
| 						ticks: { | ||||
| 							callback: value => { | ||||
| 								return Vue.filter('bytes')(value); | ||||
| 							} | ||||
| 						} | ||||
| 					}] | ||||
| 				}, | ||||
| 				tooltips: { | ||||
| 					callbacks: { | ||||
| 						label: tooltipItem => { | ||||
| 							return Vue.filter('bytes')(tooltipItem.yLabel); | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 			}]; | ||||
| 		}, | ||||
|  | ||||
| 		driveFilesChart(local: boolean, total: boolean): any { | ||||
| 			const data = this.stats.slice().reverse().map(x => ({ | ||||
| 				date: new Date(x.date), | ||||
| 				count: local ? | ||||
| 					total ? x.drive.local.totalCount : x.drive.local.diffCount : | ||||
| 					total ? x.drive.remote.totalCount : x.drive.remote.diffCount | ||||
| 			})); | ||||
|  | ||||
| 			return [{ | ||||
| 				datasets: [{ | ||||
| 					label: local ? 'Local Drive Files' : 'Remote Drive Files', | ||||
| 					fill: true, | ||||
| 					backgroundColor: 'rgba(246, 88, 79, 0.1)', | ||||
| 					borderColor: '#f6584f', | ||||
| 					borderWidth: 2, | ||||
| 					pointBackgroundColor: '#fff', | ||||
| 					lineTension: 0, | ||||
| 					data: data.map(x => ({ t: x.date, y: x.count })) | ||||
| 				}] | ||||
| 			}]; | ||||
| 		}, | ||||
| 	} | ||||
| }); | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| @import '~const.styl' | ||||
|  | ||||
| .gkgckalzgidaygcxnugepioremxvxvpt | ||||
| 	* | ||||
| 		user-select none | ||||
|  | ||||
| 	> header | ||||
| 		display flex | ||||
|  | ||||
| 		> b | ||||
| 			margin-right 8px | ||||
|  | ||||
| 		> *:last-child | ||||
| 			margin-left auto | ||||
|  | ||||
| 	> div | ||||
| 		> * | ||||
| 			display block | ||||
| 			height 300px | ||||
|  | ||||
| </style> | ||||
| @@ -1,11 +1,11 @@ | ||||
| <template> | ||||
| <div class="obdskegsannmntldydackcpzezagxqfy card"> | ||||
| <div class="obdskegsannmntldydackcpzezagxqfy mk-admin-card"> | ||||
| 	<header>%i18n:@dashboard%</header> | ||||
| 	<div v-if="stats" class="stats"> | ||||
| 		<div><b>%fa:user% {{ stats.originalUsersCount | number }}</b><span>%i18n:@original-users%</span></div> | ||||
| 		<div><span>%fa:user% {{ stats.usersCount | number }}</span><span>%i18n:@all-users%</span></div> | ||||
| 		<div><b>%fa:pen% {{ stats.originalNotesCount | number }}</b><span>%i18n:@original-notes%</span></div> | ||||
| 		<div><span>%fa:pen% {{ stats.notesCount | number }}</span><span>%i18n:@all-notes%</span></div> | ||||
| 		<div><b>%fa:pencil-alt% {{ stats.originalNotesCount | number }}</b><span>%i18n:@original-notes%</span></div> | ||||
| 		<div><span>%fa:pencil-alt% {{ stats.notesCount | number }}</span><span>%i18n:@all-notes%</span></div> | ||||
| 	</div> | ||||
| 	<div class="cpu-memory"> | ||||
| 		<x-cpu-memory :connection="connection"/> | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| <template> | ||||
| <div class="card"> | ||||
| <div class="mk-admin-card"> | ||||
| 	<header>%i18n:@suspend-user%</header> | ||||
| 	<input v-model="username" type="text" class="ui"/> | ||||
| 	<button class="ui" @click="suspendUser" :disabled="suspending">%i18n:@suspend%</button> | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| <template> | ||||
| <div class="card"> | ||||
| <div class="mk-admin-card"> | ||||
| 	<header>%i18n:@unsuspend-user%</header> | ||||
| 	<input v-model="username" type="text" class="ui"/> | ||||
| 	<button class="ui" @click="unsuspendUser" :disabled="unsuspending">%i18n:@unsuspend%</button> | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| <template> | ||||
| <div class="card"> | ||||
| <div class="mk-admin-card"> | ||||
| 	<header>%i18n:@unverify-user%</header> | ||||
| 	<input v-model="username" type="text" class="ui"/> | ||||
| 	<button class="ui" @click="unverifyUser" :disabled="unverifying">%i18n:@unverify%</button> | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| <template> | ||||
| <div class="card"> | ||||
| <div class="mk-admin-card"> | ||||
| 	<header>%i18n:@verify-user%</header> | ||||
| 	<input v-model="username" type="text" class="ui"/> | ||||
| 	<button class="ui" @click="verifyUser" :disabled="verifying">%i18n:@verify%</button> | ||||
|   | ||||
| @@ -11,7 +11,7 @@ | ||||
| 	<main> | ||||
| 		<div v-show="page == 'dashboard'"> | ||||
| 			<x-dashboard/> | ||||
| 			<x-chart/> | ||||
| 			<x-charts/> | ||||
| 		</div> | ||||
| 		<div v-if="page == 'users'"> | ||||
| 			<x-suspend-user/> | ||||
| @@ -32,7 +32,7 @@ import XSuspendUser from "./admin.suspend-user.vue"; | ||||
| import XUnsuspendUser from "./admin.unsuspend-user.vue"; | ||||
| import XVerifyUser from "./admin.verify-user.vue"; | ||||
| import XUnverifyUser from "./admin.unverify-user.vue"; | ||||
| import XChart from "./admin.chart.vue"; | ||||
| import XCharts from "../../components/charts.vue"; | ||||
|  | ||||
| export default Vue.extend({ | ||||
| 	components: { | ||||
| @@ -41,12 +41,11 @@ export default Vue.extend({ | ||||
| 		XUnsuspendUser, | ||||
| 		XVerifyUser, | ||||
| 		XUnverifyUser, | ||||
| 		XChart | ||||
| 		XCharts | ||||
| 	}, | ||||
| 	data() { | ||||
| 		return { | ||||
| 			page: 'dashboard', | ||||
| 			chart: null | ||||
| 			page: 'dashboard' | ||||
| 		}; | ||||
| 	}, | ||||
| 	methods: { | ||||
| @@ -104,7 +103,7 @@ export default Vue.extend({ | ||||
| 			> div | ||||
| 				max-width 800px | ||||
|  | ||||
| .card | ||||
| .mk-admin-card | ||||
| 	padding 32px | ||||
| 	background #fff | ||||
| 	box-shadow 0 2px 8px rgba(#000, 0.1) | ||||
|   | ||||
| @@ -32,7 +32,7 @@ | ||||
| 						<mk-media-list :media-list="p.media"/> | ||||
| 					</div> | ||||
| 					<mk-poll v-if="p.poll" :note="p" ref="pollViewer"/> | ||||
| 					<a class="location" v-if="p.geo" :href="`http://maps.google.com/maps?q=${p.geo.coordinates[1]},${p.geo.coordinates[0]}`" target="_blank">%fa:map-marker-alt% %i18n:@location%</a> | ||||
| 					<a class="location" v-if="p.geo" :href="`https://maps.google.com/maps?q=${p.geo.coordinates[1]},${p.geo.coordinates[0]}`" target="_blank">%fa:map-marker-alt% %i18n:@location%</a> | ||||
| 					<div class="renote" v-if="p.renote"> | ||||
| 						<mk-note-preview :note="p.renote" :mini="true"/> | ||||
| 					</div> | ||||
|   | ||||
| @@ -16,7 +16,7 @@ import Vue from 'vue'; | ||||
| export default Vue.extend({ | ||||
| 	data() { | ||||
| 		return { | ||||
| 			name: (this as any).os.instanceName, | ||||
| 			name: null, | ||||
| 			posted: false, | ||||
| 			text: new URLSearchParams(location.search).get('text') | ||||
| 		}; | ||||
| @@ -25,6 +25,11 @@ export default Vue.extend({ | ||||
| 		close() { | ||||
| 			window.close(); | ||||
| 		} | ||||
| 	}, | ||||
| 	mounted() { | ||||
| 		(this as any).os.getMeta().then(meta => { | ||||
| 			this.name = meta.name; | ||||
| 		}); | ||||
| 	} | ||||
| }); | ||||
| </script> | ||||
|   | ||||
							
								
								
									
										64
									
								
								src/client/app/desktop/views/pages/stats/stats.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								src/client/app/desktop/views/pages/stats/stats.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,64 @@ | ||||
| <template> | ||||
| <div class="tcrwdhwpuxrwmcttxjcsehgpagpstqey"> | ||||
| 	<div v-if="stats" class="stats"> | ||||
| 		<div><b>%fa:user% {{ stats.originalUsersCount | number }}</b><span>%i18n:@original-users%</span></div> | ||||
| 		<div><span>%fa:user% {{ stats.usersCount | number }}</span><span>%i18n:@all-users%</span></div> | ||||
| 		<div><b>%fa:pencil-alt% {{ stats.originalNotesCount | number }}</b><span>%i18n:@original-notes%</span></div> | ||||
| 		<div><span>%fa:pencil-alt% {{ stats.notesCount | number }}</span><span>%i18n:@all-notes%</span></div> | ||||
| 	</div> | ||||
| 	<div> | ||||
| 		<x-charts/> | ||||
| 	</div> | ||||
| </div> | ||||
| </template> | ||||
|  | ||||
| <script lang="ts"> | ||||
| import Vue from "vue"; | ||||
| import XCharts from "../../components/charts.vue"; | ||||
|  | ||||
| export default Vue.extend({ | ||||
| 	components: { | ||||
| 		XCharts | ||||
| 	}, | ||||
| 	data() { | ||||
| 		return { | ||||
| 			stats: null | ||||
| 		}; | ||||
| 	}, | ||||
| 	created() { | ||||
| 		(this as any).api('stats').then(stats => { | ||||
| 			this.stats = stats; | ||||
| 		}); | ||||
| 	}, | ||||
| }); | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus"> | ||||
| @import '~const.styl' | ||||
|  | ||||
| .tcrwdhwpuxrwmcttxjcsehgpagpstqey | ||||
| 	width 100% | ||||
| 	padding 16px | ||||
|  | ||||
| 	> .stats | ||||
| 		display flex | ||||
| 		justify-content center | ||||
| 		margin-bottom 16px | ||||
| 		padding 32px | ||||
| 		background #fff | ||||
| 		box-shadow 0 2px 8px rgba(#000, 0.1) | ||||
|  | ||||
| 		> div | ||||
| 			flex 1 | ||||
| 			text-align center | ||||
|  | ||||
| 			> *:first-child | ||||
| 				display block | ||||
| 				color $theme-color | ||||
|  | ||||
| 			> *:last-child | ||||
| 				font-size 70% | ||||
|  | ||||
| 	> div | ||||
| 		max-width 850px | ||||
| </style> | ||||
| @@ -40,10 +40,12 @@ export default Vue.extend({ | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| root(isDark) | ||||
| .friends | ||||
| 	background #fff | ||||
| 	background isDark ? #282C37 : #fff | ||||
| 	border solid 1px rgba(#000, 0.075) | ||||
| 	border-radius 6px | ||||
| 	overflow hidden | ||||
|  | ||||
| 	> .title | ||||
| 		z-index 1 | ||||
| @@ -52,7 +54,8 @@ export default Vue.extend({ | ||||
| 		line-height 42px | ||||
| 		font-size 0.9em | ||||
| 		font-weight bold | ||||
| 		color #888 | ||||
| 		background isDark ? #313543 : inherit | ||||
| 		color isDark ? #e3e5e8 : #888 | ||||
| 		box-shadow 0 1px rgba(#000, 0.07) | ||||
|  | ||||
| 		> i | ||||
| @@ -70,7 +73,7 @@ export default Vue.extend({ | ||||
|  | ||||
| 	> .user | ||||
| 		padding 16px | ||||
| 		border-bottom solid 1px #eee | ||||
| 		border-bottom solid 1px isDark ? #21242f : #eee | ||||
|  | ||||
| 		&:last-child | ||||
| 			border-bottom none | ||||
| @@ -96,18 +99,24 @@ export default Vue.extend({ | ||||
| 				margin 0 | ||||
| 				font-size 16px | ||||
| 				line-height 24px | ||||
| 				color #555 | ||||
| 				color isDark ? #ccc : #555 | ||||
|  | ||||
| 			> .username | ||||
| 				display block | ||||
| 				margin 0 | ||||
| 				font-size 15px | ||||
| 				line-height 16px | ||||
| 				color #ccc | ||||
| 				color isDark ? #555 : #ccc | ||||
|  | ||||
| 		> .mk-follow-button | ||||
| 			position absolute | ||||
| 			top 16px | ||||
| 			right 16px | ||||
|  | ||||
| .friends[data-darkmode] | ||||
| 	root(true) | ||||
|  | ||||
| .friends:not([data-darkmode]) | ||||
| 	root(false) | ||||
|  | ||||
| </style> | ||||
|   | ||||
| @@ -39,10 +39,12 @@ export default Vue.extend({ | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| root(isDark) | ||||
| .photos | ||||
| 	background #fff | ||||
| 	background isDark ? #282C37 : #fff | ||||
| 	border solid 1px rgba(#000, 0.075) | ||||
| 	border-radius 6px | ||||
| 	overflow hidden | ||||
|  | ||||
| 	> .title | ||||
| 		z-index 1 | ||||
| @@ -51,7 +53,8 @@ export default Vue.extend({ | ||||
| 		line-height 42px | ||||
| 		font-size 0.9em | ||||
| 		font-weight bold | ||||
| 		color #888 | ||||
| 		background: isDark ? #313543 : inherit | ||||
| 		color isDark ? #e3e5e8 : #888 | ||||
| 		box-shadow 0 1px rgba(#000, 0.07) | ||||
|  | ||||
| 		> i | ||||
| @@ -85,4 +88,10 @@ export default Vue.extend({ | ||||
| 		> i | ||||
| 			margin-right 4px | ||||
|  | ||||
| .photos[data-darkmode] | ||||
| 	root(true) | ||||
|  | ||||
| .photos:not([data-darkmode]) | ||||
| 	root(false) | ||||
|  | ||||
| </style> | ||||
|   | ||||
| @@ -138,7 +138,7 @@ root(isDark) | ||||
| 				padding 16px | ||||
| 				font-size 12px | ||||
| 				color #aaa | ||||
| 				background #fff | ||||
| 				background isDark ? #21242f : #fff | ||||
| 				border solid 1px rgba(#000, 0.075) | ||||
| 				border-radius 6px | ||||
|  | ||||
|   | ||||
| @@ -19,8 +19,8 @@ import { version, codename, lang } from './config'; | ||||
|  | ||||
| let elementLocale; | ||||
| switch (lang) { | ||||
| 	case 'ja': elementLocale = ElementLocaleJa; break; | ||||
| 	case 'en': elementLocale = ElementLocaleEn; break; | ||||
| 	case 'ja-JP': elementLocale = ElementLocaleJa; break; | ||||
| 	case 'en-US': elementLocale = ElementLocaleEn; break; | ||||
| 	default: elementLocale = ElementLocaleEn; break; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -45,7 +45,7 @@ | ||||
| 			</div> | ||||
| 			<mk-poll v-if="p.poll" :note="p"/> | ||||
| 			<mk-url-preview v-for="url in urls" :url="url" :key="url" :detail="true"/> | ||||
| 			<a class="location" v-if="p.geo" :href="`http://maps.google.com/maps?q=${p.geo.coordinates[1]},${p.geo.coordinates[0]}`" target="_blank">%fa:map-marker-alt% %i18n:@location%</a> | ||||
| 			<a class="location" v-if="p.geo" :href="`https://maps.google.com/maps?q=${p.geo.coordinates[1]},${p.geo.coordinates[0]}`" target="_blank">%fa:map-marker-alt% %i18n:@location%</a> | ||||
| 			<div class="map" v-if="p.geo" ref="map"></div> | ||||
| 			<div class="renote" v-if="p.renote"> | ||||
| 				<mk-note-preview :note="p.renote"/> | ||||
|   | ||||
| @@ -33,7 +33,7 @@ | ||||
| 					</div> | ||||
| 					<mk-poll v-if="p.poll" :note="p" ref="pollViewer"/> | ||||
| 					<mk-url-preview v-for="url in urls" :url="url" :key="url"/> | ||||
| 					<a class="location" v-if="p.geo" :href="`http://maps.google.com/maps?q=${p.geo.coordinates[1]},${p.geo.coordinates[0]}`" target="_blank">%fa:map-marker-alt% %i18n:@location%</a> | ||||
| 					<a class="location" v-if="p.geo" :href="`https://maps.google.com/maps?q=${p.geo.coordinates[1]},${p.geo.coordinates[0]}`" target="_blank">%fa:map-marker-alt% %i18n:@location%</a> | ||||
| 					<div class="map" v-if="p.geo" ref="map"></div> | ||||
| 					<div class="renote" v-if="p.renote"> | ||||
| 						<mk-note-preview :note="p.renote"/> | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| <template> | ||||
| <div class="header"> | ||||
| <div class="header" ref="root"> | ||||
| 	<p class="warn" v-if="env != 'production'">%i18n:common.do-not-use-in-production%</p> | ||||
| 	<mk-special-message/> | ||||
| 	<div class="main" ref="main"> | ||||
| 		<div class="backdrop"></div> | ||||
| @@ -20,6 +21,7 @@ | ||||
| <script lang="ts"> | ||||
| import Vue from 'vue'; | ||||
| import * as anime from 'animejs'; | ||||
| import { env } from '../../../config'; | ||||
|  | ||||
| export default Vue.extend({ | ||||
| 	props: ['func'], | ||||
| @@ -27,7 +29,8 @@ export default Vue.extend({ | ||||
| 		return { | ||||
| 			hasGameInvitation: false, | ||||
| 			connection: null, | ||||
| 			connectionId: null | ||||
| 			connectionId: null, | ||||
| 			env: env | ||||
| 		}; | ||||
| 	}, | ||||
| 	computed: { | ||||
| @@ -39,7 +42,7 @@ export default Vue.extend({ | ||||
| 		} | ||||
| 	}, | ||||
| 	mounted() { | ||||
| 		this.$store.commit('setUiHeaderHeight', 48); | ||||
| 		this.$store.commit('setUiHeaderHeight', this.$refs.root.offsetHeight); | ||||
|  | ||||
| 		if (this.$store.getters.isSignedIn) { | ||||
| 			this.connection = (this as any).os.stream.getConnection(); | ||||
| @@ -133,6 +136,15 @@ root(isDark) | ||||
| 		height 3px | ||||
| 		background $theme-color | ||||
|  | ||||
| 	> .warn | ||||
| 		display block | ||||
| 		margin 0 | ||||
| 		padding 4px | ||||
| 		text-align center | ||||
| 		font-size 12px | ||||
| 		background #f00 | ||||
| 		color #fff | ||||
|  | ||||
| 	> .main | ||||
| 		color rgba(#fff, 0.9) | ||||
|  | ||||
|   | ||||
| @@ -31,7 +31,14 @@ export default Vue.extend({ | ||||
| 			connectionId: null | ||||
| 		}; | ||||
| 	}, | ||||
| 	watch: { | ||||
| 		'$store.state.uiHeaderHeight'() { | ||||
| 			this.$el.style.paddingTop = this.$store.state.uiHeaderHeight + 'px'; | ||||
| 		} | ||||
| 	}, | ||||
| 	mounted() { | ||||
| 		this.$el.style.paddingTop = this.$store.state.uiHeaderHeight + 'px'; | ||||
|  | ||||
| 		if (this.$store.getters.isSignedIn) { | ||||
| 			this.connection = (this as any).os.stream.getConnection(); | ||||
| 			this.connectionId = (this as any).os.stream.use(); | ||||
|   | ||||
| @@ -41,6 +41,12 @@ | ||||
| 				<ui-switch v-model="lightmode">%i18n:@i-am-under-limited-internet%</ui-switch> | ||||
| 			</ui-card> | ||||
|  | ||||
| 			<ui-card> | ||||
| 				<div slot="title">%fa:volume-up% %i18n:@sound%</div> | ||||
|  | ||||
| 				<ui-switch v-model="enableSounds">%i18n:@enable-sounds%</ui-switch> | ||||
| 			</ui-card> | ||||
|  | ||||
| 			<ui-card> | ||||
| 				<div slot="title">%fa:language% %i18n:@lang%</div> | ||||
|  | ||||
| @@ -142,6 +148,11 @@ export default Vue.extend({ | ||||
| 			get() { return this.$store.state.device.lang; }, | ||||
| 			set(value) { this.$store.commit('device/set', { key: 'lang', value }); } | ||||
| 		}, | ||||
|  | ||||
| 		enableSounds: { | ||||
| 			get() { return this.$store.state.device.enableSounds; }, | ||||
| 			set(value) { this.$store.commit('device/set', { key: 'enableSounds', value }); } | ||||
| 		}, | ||||
| 	}, | ||||
|  | ||||
| 	mounted() { | ||||
|   | ||||
| @@ -16,7 +16,7 @@ import Vue from 'vue'; | ||||
| export default Vue.extend({ | ||||
| 	data() { | ||||
| 		return { | ||||
| 			name: (this as any).os.instanceName, | ||||
| 			name: null, | ||||
| 			posted: false, | ||||
| 			text: new URLSearchParams(location.search).get('text') | ||||
| 		}; | ||||
| @@ -25,6 +25,11 @@ export default Vue.extend({ | ||||
| 		close() { | ||||
| 			window.close(); | ||||
| 		} | ||||
| 	}, | ||||
| 	mounted() { | ||||
| 		(this as any).os.getMeta().then(meta => { | ||||
| 			this.name = meta.name; | ||||
| 		}); | ||||
| 	} | ||||
| }); | ||||
| </script> | ||||
|   | ||||
| @@ -11,7 +11,7 @@ | ||||
| 					<a class="avatar"> | ||||
| 						<img :src="user.avatarUrl" alt="avatar"/> | ||||
| 					</a> | ||||
| 					<mk-mute-button v-if="$store.state.i.id != user.id" :user="user"/> | ||||
| 					<mk-mute-button v-if="$store.getters.isSignedIn && $store.state.i.id != user.id" :user="user"/> | ||||
| 					<mk-follow-button v-if="$store.getters.isSignedIn && $store.state.i.id != user.id" :user="user"/> | ||||
| 				</div> | ||||
| 				<div class="title"> | ||||
|   | ||||
| @@ -13,6 +13,7 @@ const defaultSettings = { | ||||
| 	showMaps: true, | ||||
| 	showPostFormOnTopOfTl: false, | ||||
| 	suggestRecentHashtags: true, | ||||
| 	showClockOnHeader: true, | ||||
| 	circleIcons: true, | ||||
| 	gradientWindowHeader: false, | ||||
| 	showReplyTarget: true, | ||||
|   | ||||
| @@ -53,5 +53,5 @@ export default function load() { | ||||
| } | ||||
|  | ||||
| function normalizeUrl(url: string) { | ||||
| 	return url[url.length - 1] === '/' ? url.substr(0, url.length - 1) : url; | ||||
| 	return url.endsWith('/') ? url.substr(0, url.length - 1) : url; | ||||
| } | ||||
|   | ||||
| @@ -62,6 +62,8 @@ export type Source = { | ||||
| 	 */ | ||||
| 	ghost?: string; | ||||
|  | ||||
| 	summalyProxy?: string; | ||||
|  | ||||
| 	accesslog?: string; | ||||
| 	twitter?: { | ||||
| 		consumer_key: string; | ||||
|   | ||||
| @@ -15,7 +15,7 @@ block main | ||||
| 		span.path= endpointUrl.path | ||||
|  | ||||
| 	if endpoint.desc | ||||
| 		p#desc= endpoint.desc[lang] || endpoint.desc['ja'] | ||||
| 		p#desc= endpoint.desc[lang] || endpoint.desc['ja-JP'] | ||||
|  | ||||
| 	if endpoint.requireCredential | ||||
| 		div.ui.info: p | ||||
|   | ||||
| @@ -1,90 +1,90 @@ | ||||
| name: "DriveFile" | ||||
|  | ||||
| desc: | ||||
|   ja: "ドライブのファイル。" | ||||
|   en: "A file of Drive." | ||||
|   ja-JP: "ドライブのファイル。" | ||||
|   en-US: "A file of Drive." | ||||
|  | ||||
| props: | ||||
|   id: | ||||
|     type: "id" | ||||
|     optional: false | ||||
|     desc: | ||||
|       ja: "ファイルID" | ||||
|       en: "The ID of this file" | ||||
|       ja-JP: "ファイルID" | ||||
|       en-US: "The ID of this file" | ||||
|  | ||||
|   createdAt: | ||||
|     type: "date" | ||||
|     optional: false | ||||
|     desc: | ||||
|       ja: "アップロード日時" | ||||
|       en: "The upload date of this file" | ||||
|       ja-JP: "アップロード日時" | ||||
|       en-US: "The upload date of this file" | ||||
|  | ||||
|   userId: | ||||
|     type: "id(User)" | ||||
|     optional: false | ||||
|     desc: | ||||
|       ja: "所有者ID" | ||||
|       en: "The ID of the owner of this file" | ||||
|       ja-JP: "所有者ID" | ||||
|       en-US: "The ID of the owner of this file" | ||||
|  | ||||
|   user: | ||||
|     type: "entity(User)" | ||||
|     optional: true | ||||
|     desc: | ||||
|       ja: "所有者" | ||||
|       en: "The owner of this file" | ||||
|       ja-JP: "所有者" | ||||
|       en-US: "The owner of this file" | ||||
|  | ||||
|   name: | ||||
|     type: "string" | ||||
|     optional: false | ||||
|     desc: | ||||
|       ja: "ファイル名" | ||||
|       en: "The name of this file" | ||||
|       ja-JP: "ファイル名" | ||||
|       en-US: "The name of this file" | ||||
|  | ||||
|   md5: | ||||
|     type: "string" | ||||
|     optional: false | ||||
|     desc: | ||||
|       ja: "ファイルのMD5ハッシュ値" | ||||
|       en: "The md5 hash value of this file" | ||||
|       ja-JP: "ファイルのMD5ハッシュ値" | ||||
|       en-US: "The md5 hash value of this file" | ||||
|  | ||||
|   type: | ||||
|     type: "string" | ||||
|     optional: false | ||||
|     desc: | ||||
|       ja: "ファイルの種類" | ||||
|       en: "The type of this file" | ||||
|       ja-JP: "ファイルの種類" | ||||
|       en-US: "The type of this file" | ||||
|  | ||||
|   datasize: | ||||
|     type: "number" | ||||
|     optional: false | ||||
|     desc: | ||||
|       ja: "ファイルサイズ(bytes)" | ||||
|       en: "The size of this file (bytes)" | ||||
|       ja-JP: "ファイルサイズ(bytes)" | ||||
|       en-US: "The size of this file (bytes)" | ||||
|  | ||||
|   url: | ||||
|     type: "string" | ||||
|     optional: false | ||||
|     desc: | ||||
|       ja: "ファイルのURL" | ||||
|       en: "The URL of this file" | ||||
|       ja-JP: "ファイルのURL" | ||||
|       en-US: "The URL of this file" | ||||
|  | ||||
|   folderId: | ||||
|     type: "id(DriveFolder)" | ||||
|     optional: true | ||||
|     desc: | ||||
|       ja: "フォルダID" | ||||
|       en: "The ID of the folder of this file" | ||||
|       ja-JP: "フォルダID" | ||||
|       en-US: "The ID of the folder of this file" | ||||
|  | ||||
|   folder: | ||||
|     type: "entity(DriveFolder)" | ||||
|     optional: true | ||||
|     desc: | ||||
|       ja: "フォルダ" | ||||
|       en: "The folder of this file" | ||||
|       ja-JP: "フォルダ" | ||||
|       en-US: "The folder of this file" | ||||
|  | ||||
|   isSensitive: | ||||
|     type: "boolean" | ||||
|     optional: true | ||||
|     desc: | ||||
|       ja: "このメディアが「閲覧注意」(NSFW)かどうか" | ||||
|       en: "Whether this media is NSFW" | ||||
|       ja-JP: "このメディアが「閲覧注意」(NSFW)かどうか" | ||||
|       en-US: "Whether this media is NSFW" | ||||
|   | ||||
| @@ -1,41 +1,41 @@ | ||||
| name: "DriveFolder" | ||||
|  | ||||
| desc: | ||||
|   ja: "ドライブのフォルダを表します。" | ||||
|   en: "A folder of Drive." | ||||
|   ja-JP: "ドライブのフォルダを表します。" | ||||
|   en-US: "A folder of Drive." | ||||
|  | ||||
| props: | ||||
|   id: | ||||
|     type: "id" | ||||
|     optional: false | ||||
|     desc: | ||||
|       ja: "フォルダID" | ||||
|       en: "The ID of this folder" | ||||
|       ja-JP: "フォルダID" | ||||
|       en-US: "The ID of this folder" | ||||
|  | ||||
|   createdAt: | ||||
|     type: "date" | ||||
|     optional: false | ||||
|     desc: | ||||
|       ja: "作成日時" | ||||
|       en: "The created date of this folder" | ||||
|       ja-JP: "作成日時" | ||||
|       en-US: "The created date of this folder" | ||||
|  | ||||
|   userId: | ||||
|     type: "id(User)" | ||||
|     optional: false | ||||
|     desc: | ||||
|       ja: "所有者ID" | ||||
|       en: "The ID of the owner of this folder" | ||||
|       ja-JP: "所有者ID" | ||||
|       en-US: "The ID of the owner of this folder" | ||||
|  | ||||
|   parentId: | ||||
|     type: "entity(DriveFolder)" | ||||
|     optional: false | ||||
|     desc: | ||||
|       ja: "親フォルダのID (ルートなら null)" | ||||
|       en: "The ID of parent folder" | ||||
|       ja-JP: "親フォルダのID (ルートなら null)" | ||||
|       en-US: "The ID of parent folder" | ||||
|  | ||||
|   name: | ||||
|     type: "string" | ||||
|     optional: false | ||||
|     desc: | ||||
|       ja: "フォルダ名" | ||||
|       en: "The name of this folder" | ||||
|       ja-JP: "フォルダ名" | ||||
|       en-US: "The name of this folder" | ||||
|   | ||||
| @@ -1,190 +1,190 @@ | ||||
| name: "Note" | ||||
|  | ||||
| desc: | ||||
|   ja: "投稿。" | ||||
|   en: "A note." | ||||
|   ja-JP: "投稿。" | ||||
|   en-US: "A note." | ||||
|  | ||||
| props: | ||||
|   id: | ||||
|     type: "id" | ||||
|     optional: false | ||||
|     desc: | ||||
|       ja: "投稿ID" | ||||
|       en: "The ID of this note" | ||||
|       ja-JP: "投稿ID" | ||||
|       en-US: "The ID of this note" | ||||
|  | ||||
|   createdAt: | ||||
|     type: "date" | ||||
|     optional: false | ||||
|     desc: | ||||
|       ja: "投稿日時" | ||||
|       en: "The posted date of this note" | ||||
|       ja-JP: "投稿日時" | ||||
|       en-US: "The posted date of this note" | ||||
|  | ||||
|   viaMobile: | ||||
|     type: "boolean" | ||||
|     optional: true | ||||
|     desc: | ||||
|       ja: "モバイル端末から投稿したか否か(自己申告であることに留意)" | ||||
|       en: "Whether this note sent via a mobile device" | ||||
|       ja-JP: "モバイル端末から投稿したか否か(自己申告であることに留意)" | ||||
|       en-US: "Whether this note sent via a mobile device" | ||||
|  | ||||
|   text: | ||||
|     type: "string" | ||||
|     optional: true | ||||
|     desc: | ||||
|       ja: "投稿の本文" | ||||
|       en: "The text of this note" | ||||
|       ja-JP: "投稿の本文" | ||||
|       en-US: "The text of this note" | ||||
|  | ||||
|   mediaIds: | ||||
|     type: "id(DriveFile)[]" | ||||
|     optional: true | ||||
|     desc: | ||||
|       ja: "添付されているメディアのID (なければレスポンスでは空配列)" | ||||
|       en: "The IDs of the attached media (empty array for response if no media is attached)" | ||||
|       ja-JP: "添付されているメディアのID (なければレスポンスでは空配列)" | ||||
|       en-US: "The IDs of the attached media (empty array for response if no media is attached)" | ||||
|  | ||||
|   media: | ||||
|     type: "entity(DriveFile)[]" | ||||
|     optional: true | ||||
|     desc: | ||||
|       ja: "添付されているメディア" | ||||
|       en: "The attached media" | ||||
|       ja-JP: "添付されているメディア" | ||||
|       en-US: "The attached media" | ||||
|  | ||||
|   userId: | ||||
|     type: "id(User)" | ||||
|     optional: false | ||||
|     desc: | ||||
|       ja: "投稿者ID" | ||||
|       en: "The ID of author of this note" | ||||
|       ja-JP: "投稿者ID" | ||||
|       en-US: "The ID of author of this note" | ||||
|  | ||||
|   user: | ||||
|     type: "entity(User)" | ||||
|     optional: true | ||||
|     desc: | ||||
|       ja: "投稿者" | ||||
|       en: "The author of this note" | ||||
|       ja-JP: "投稿者" | ||||
|       en-US: "The author of this note" | ||||
|  | ||||
|   myReaction: | ||||
|     type: "string" | ||||
|     optional: true | ||||
|     desc: | ||||
|       ja: "この投稿に対する自分の<a href='/docs/api/reactions'>リアクション</a>" | ||||
|       en: "The your <a href='/docs/api/reactions'>reaction</a> of this note" | ||||
|       ja-JP: "この投稿に対する自分の<a href='/docs/api/reactions'>リアクション</a>" | ||||
|       en-US: "The your <a href='/docs/api/reactions'>reaction</a> of this note" | ||||
|  | ||||
|   reactionCounts: | ||||
|     type: "object" | ||||
|     optional: false | ||||
|     desc: | ||||
|       ja: "<a href='/docs/api/reactions'>リアクション</a>をキーとし、この投稿に対するそのリアクションの数を値としたオブジェクト" | ||||
|       ja-JP: "<a href='/docs/api/reactions'>リアクション</a>をキーとし、この投稿に対するそのリアクションの数を値としたオブジェクト" | ||||
|  | ||||
|   replyId: | ||||
|     type: "id(Note)" | ||||
|     optional: true | ||||
|     desc: | ||||
|       ja: "返信した投稿のID" | ||||
|       en: "The ID of the replyed note" | ||||
|       ja-JP: "返信した投稿のID" | ||||
|       en-US: "The ID of the replyed note" | ||||
|  | ||||
|   reply: | ||||
|     type: "entity(Note)" | ||||
|     optional: true | ||||
|     desc: | ||||
|       ja: "返信した投稿" | ||||
|       en: "The replyed note" | ||||
|       ja-JP: "返信した投稿" | ||||
|       en-US: "The replyed note" | ||||
|  | ||||
|   renoteId: | ||||
|     type: "id(Note)" | ||||
|     optional: true | ||||
|     desc: | ||||
|       ja: "引用した投稿のID" | ||||
|       en: "The ID of the quoted note" | ||||
|       ja-JP: "引用した投稿のID" | ||||
|       en-US: "The ID of the quoted note" | ||||
|  | ||||
|   renote: | ||||
|     type: "entity(Note)" | ||||
|     optional: true | ||||
|     desc: | ||||
|       ja: "引用した投稿" | ||||
|       en: "The quoted note" | ||||
|       ja-JP: "引用した投稿" | ||||
|       en-US: "The quoted note" | ||||
|  | ||||
|   poll: | ||||
|     type: "object" | ||||
|     optional: true | ||||
|     desc: | ||||
|       ja: "投票" | ||||
|       en: "The poll" | ||||
|       ja-JP: "投票" | ||||
|       en-US: "The poll" | ||||
|  | ||||
|     props: | ||||
|       choices: | ||||
|         type: "object[]" | ||||
|         optional: false | ||||
|         desc: | ||||
|           ja: "投票の選択肢" | ||||
|           en: "The choices of this poll" | ||||
|           ja-JP: "投票の選択肢" | ||||
|           en-US: "The choices of this poll" | ||||
|  | ||||
|         props: | ||||
|           id: | ||||
|             type: "number" | ||||
|             optional: false | ||||
|             desc: | ||||
|               ja: "選択肢ID" | ||||
|               en: "The ID of this choice" | ||||
|               ja-JP: "選択肢ID" | ||||
|               en-US: "The ID of this choice" | ||||
|  | ||||
|           isVoted: | ||||
|             type: "boolean" | ||||
|             optional: true | ||||
|             desc: | ||||
|               ja: "自分がこの選択肢に投票したかどうか" | ||||
|               en: "Whether you voted to this choice" | ||||
|               ja-JP: "自分がこの選択肢に投票したかどうか" | ||||
|               en-US: "Whether you voted to this choice" | ||||
|  | ||||
|           text: | ||||
|             type: "string" | ||||
|             optional: false | ||||
|             desc: | ||||
|               ja: "選択肢本文" | ||||
|               en: "The text of this choice" | ||||
|               ja-JP: "選択肢本文" | ||||
|               en-US: "The text of this choice" | ||||
|  | ||||
|           votes: | ||||
|             type: "number" | ||||
|             optional: false | ||||
|             desc: | ||||
|               ja: "この選択肢に投票された数" | ||||
|               en: "The number voted for this choice" | ||||
|               ja-JP: "この選択肢に投票された数" | ||||
|               en-US: "The number voted for this choice" | ||||
|   geo: | ||||
|     type: "object" | ||||
|     optional: true | ||||
|     desc: | ||||
|       ja: "位置情報" | ||||
|       en: "Geo location" | ||||
|       ja-JP: "位置情報" | ||||
|       en-US: "Geo location" | ||||
|  | ||||
|     props: | ||||
|       coordinates: | ||||
|         type: "number[]" | ||||
|         optional: false | ||||
|         desc: | ||||
|           ja: "座標。最初に経度:-180〜180で表す。最後に緯度:-90〜90で表す。" | ||||
|           ja-JP: "座標。最初に経度:-180〜180で表す。最後に緯度:-90〜90で表す。" | ||||
|  | ||||
|       altitude: | ||||
|         type: "number" | ||||
|         optional: false | ||||
|         desc: | ||||
|           ja: "高度。メートル単位で表す。" | ||||
|           ja-JP: "高度。メートル単位で表す。" | ||||
|  | ||||
|       accuracy: | ||||
|         type: "number" | ||||
|         optional: false | ||||
|         desc: | ||||
|           ja: "緯度、経度の精度。メートル単位で表す。" | ||||
|           ja-JP: "緯度、経度の精度。メートル単位で表す。" | ||||
|  | ||||
|       altitudeAccuracy: | ||||
|         type: "number" | ||||
|         optional: false | ||||
|         desc: | ||||
|           ja: "高度の精度。メートル単位で表す。" | ||||
|           ja-JP: "高度の精度。メートル単位で表す。" | ||||
|  | ||||
|       heading: | ||||
|         type: "number" | ||||
|         optional: false | ||||
|         desc: | ||||
|           ja: "方角。0〜360の角度で表す。0が北、90が東、180が南、270が西。" | ||||
|           ja-JP: "方角。0〜360の角度で表す。0が北、90が東、180が南、270が西。" | ||||
|  | ||||
|       speed: | ||||
|         type: "number" | ||||
|         optional: false | ||||
|         desc: | ||||
|           ja: "速度。メートル / 秒数で表す。" | ||||
|           ja-JP: "速度。メートル / 秒数で表す。" | ||||
|   | ||||
| @@ -1,174 +1,174 @@ | ||||
| name: "User" | ||||
|  | ||||
| desc: | ||||
|   ja: "ユーザー。" | ||||
|   en: "A user." | ||||
|   ja-JP: "ユーザー。" | ||||
|   en-US: "A user." | ||||
|  | ||||
| props: | ||||
|   id: | ||||
|     type: "id" | ||||
|     optional: false | ||||
|     desc: | ||||
|       ja: "ユーザーID" | ||||
|       en: "The ID of this user" | ||||
|       ja-JP: "ユーザーID" | ||||
|       en-US: "The ID of this user" | ||||
|  | ||||
|   createdAt: | ||||
|     type: "date" | ||||
|     optional: false | ||||
|     desc: | ||||
|       ja: "アカウント作成日時" | ||||
|       en: "The registered date of this user" | ||||
|       ja-JP: "アカウント作成日時" | ||||
|       en-US: "The registered date of this user" | ||||
|  | ||||
|   username: | ||||
|     type: "string" | ||||
|     optional: false | ||||
|     desc: | ||||
|       ja: "ユーザー名" | ||||
|       en: "The username of this user" | ||||
|       ja-JP: "ユーザー名" | ||||
|       en-US: "The username of this user" | ||||
|  | ||||
|   description: | ||||
|     type: "string" | ||||
|     optional: false | ||||
|     desc: | ||||
|       ja: "アカウントの説明(自己紹介)" | ||||
|       en: "The description of this user" | ||||
|       ja-JP: "アカウントの説明(自己紹介)" | ||||
|       en-US: "The description of this user" | ||||
|  | ||||
|   avatarId: | ||||
|     type: "id(DriveFile)" | ||||
|     optional: true | ||||
|     desc: | ||||
|       ja: "アバターのID" | ||||
|       en: "The ID of the avatar of this user" | ||||
|       ja-JP: "アバターのID" | ||||
|       en-US: "The ID of the avatar of this user" | ||||
|  | ||||
|   avatarUrl: | ||||
|     type: "string" | ||||
|     optional: false | ||||
|     desc: | ||||
|       ja: "アバターのURL" | ||||
|       en: "The URL of the avatar of this user" | ||||
|       ja-JP: "アバターのURL" | ||||
|       en-US: "The URL of the avatar of this user" | ||||
|  | ||||
|   bannerId: | ||||
|     type: "id(DriveFile)" | ||||
|     optional: true | ||||
|     desc: | ||||
|       ja: "バナーのID" | ||||
|       en: "The ID of the banner of this user" | ||||
|       ja-JP: "バナーのID" | ||||
|       en-US: "The ID of the banner of this user" | ||||
|  | ||||
|   bannerUrl: | ||||
|     type: "string" | ||||
|     optional: false | ||||
|     desc: | ||||
|       ja: "バナーのURL" | ||||
|       en: "The URL of the banner of this user" | ||||
|       ja-JP: "バナーのURL" | ||||
|       en-US: "The URL of the banner of this user" | ||||
|  | ||||
|   followersCount: | ||||
|     type: "number" | ||||
|     optional: false | ||||
|     desc: | ||||
|       ja: "フォロワーの数" | ||||
|       en: "The number of the followers for this user" | ||||
|       ja-JP: "フォロワーの数" | ||||
|       en-US: "The number of the followers for this user" | ||||
|  | ||||
|   followingCount: | ||||
|     type: "number" | ||||
|     optional: false | ||||
|     desc: | ||||
|       ja: "フォローしているユーザーの数" | ||||
|       en: "The number of the following users for this user" | ||||
|       ja-JP: "フォローしているユーザーの数" | ||||
|       en-US: "The number of the following users for this user" | ||||
|  | ||||
|   isFollowing: | ||||
|     type: "boolean" | ||||
|     optional: true | ||||
|     desc: | ||||
|       ja: "自分がこのユーザーをフォローしているか" | ||||
|       ja-JP: "自分がこのユーザーをフォローしているか" | ||||
|  | ||||
|   isFollowed: | ||||
|     type: "boolean" | ||||
|     optional: true | ||||
|     desc: | ||||
|       ja: "自分がこのユーザーにフォローされているか" | ||||
|       ja-JP: "自分がこのユーザーにフォローされているか" | ||||
|  | ||||
|   isMuted: | ||||
|     type: "boolean" | ||||
|     optional: true | ||||
|     desc: | ||||
|       ja: "自分がこのユーザーをミュートしているか" | ||||
|       en: "Whether you muted this user" | ||||
|       ja-JP: "自分がこのユーザーをミュートしているか" | ||||
|       en-US: "Whether you muted this user" | ||||
|  | ||||
|   notesCount: | ||||
|     type: "number" | ||||
|     optional: false | ||||
|     desc: | ||||
|       ja: "投稿の数" | ||||
|       en: "The number of the notes of this user" | ||||
|       ja-JP: "投稿の数" | ||||
|       en-US: "The number of the notes of this user" | ||||
|  | ||||
|   pinnedNote: | ||||
|     type: "entity(Note)" | ||||
|     optional: true | ||||
|     desc: | ||||
|       ja: "ピン留めされた投稿" | ||||
|       en: "The pinned note of this user" | ||||
|       ja-JP: "ピン留めされた投稿" | ||||
|       en-US: "The pinned note of this user" | ||||
|  | ||||
|   pinnedNoteId: | ||||
|     type: "id(Note)" | ||||
|     optional: true | ||||
|     desc: | ||||
|       ja: "ピン留めされた投稿のID" | ||||
|       en: "The ID of the pinned note of this user" | ||||
|       ja-JP: "ピン留めされた投稿のID" | ||||
|       en-US: "The ID of the pinned note of this user" | ||||
|  | ||||
|   host: | ||||
|     type: "string | null" | ||||
|     optional: false | ||||
|     desc: | ||||
|       ja: "ホスト (例: example.com:3000)" | ||||
|       en: "Host (e.g. example.com:3000)" | ||||
|       ja-JP: "ホスト (例: example.com:3000)" | ||||
|       en-US: "Host (e.g. example.com:3000)" | ||||
|  | ||||
|   twitter: | ||||
|     type: "object" | ||||
|     optional: true | ||||
|     desc: | ||||
|       ja: "連携されているTwitterアカウント情報" | ||||
|       en: "The info of the connected twitter account of this user" | ||||
|       ja-JP: "連携されているTwitterアカウント情報" | ||||
|       en-US: "The info of the connected twitter account of this user" | ||||
|  | ||||
|     props: | ||||
|       userId: | ||||
|         type: "string" | ||||
|         optional: false | ||||
|         desc: | ||||
|           ja: "ユーザーID" | ||||
|           en: "The user ID" | ||||
|           ja-JP: "ユーザーID" | ||||
|           en-US: "The user ID" | ||||
|  | ||||
|       screenName: | ||||
|         type: "string" | ||||
|         optional: false | ||||
|         desc: | ||||
|           ja: "ユーザー名" | ||||
|           en: "The screen name of this user" | ||||
|           ja-JP: "ユーザー名" | ||||
|           en-US: "The screen name of this user" | ||||
|  | ||||
|   isBot: | ||||
|     type: "boolean" | ||||
|     optional: true | ||||
|     desc: | ||||
|       ja: "botか否か(自己申告であることに留意)" | ||||
|       en: "Whether is bot or not" | ||||
|       ja-JP: "botか否か(自己申告であることに留意)" | ||||
|       en-US: "Whether is bot or not" | ||||
|  | ||||
|   profile: | ||||
|     type: "object" | ||||
|     optional: false | ||||
|     desc: | ||||
|       ja: "プロフィール" | ||||
|       en: "The profile of this user" | ||||
|       ja-JP: "プロフィール" | ||||
|       en-US: "The profile of this user" | ||||
|  | ||||
|     props: | ||||
|       location: | ||||
|         type: "string" | ||||
|         optional: true | ||||
|         desc: | ||||
|           ja: "場所" | ||||
|           en: "The location of this user" | ||||
|           ja-JP: "場所" | ||||
|           en-US: "The location of this user" | ||||
|  | ||||
|       birthday: | ||||
|         type: "string" | ||||
|         optional: true | ||||
|         desc: | ||||
|           ja: "誕生日 (YYYY-MM-DD)" | ||||
|           en: "The birthday of this user (YYYY-MM-DD)" | ||||
|           ja-JP: "誕生日 (YYYY-MM-DD)" | ||||
|           en-US: "The birthday of this user (YYYY-MM-DD)" | ||||
|   | ||||
| @@ -7,7 +7,7 @@ block meta | ||||
| block main | ||||
| 	h1= name | ||||
|  | ||||
| 	p#desc= desc[lang] || desc['ja'] | ||||
| 	p#desc= desc[lang] || desc['ja-JP'] | ||||
|  | ||||
| 	section | ||||
| 		h2= i18n('docs.api.entities.properties') | ||||
|   | ||||
| @@ -31,4 +31,4 @@ mixin propTable(props) | ||||
| 					td.name= prop.name | ||||
| 					td.type | ||||
| 						+type(prop) | ||||
| 					td.desc!= prop.desc ? prop.desc[lang] || prop.desc['ja'] : null | ||||
| 					td.desc!= prop.desc ? prop.desc[lang] || prop.desc['ja-JP'] : null | ||||
|   | ||||
| @@ -16,7 +16,7 @@ html(lang= lang) | ||||
| 		nav | ||||
| 			ul | ||||
| 				each doc in docs | ||||
| 					li: a(href=`/docs/${lang}/${doc.name}`)= doc.title[lang] || doc.title['ja'] | ||||
| 					li: a(href=`/docs/${lang}/${doc.name}`)= doc.title[lang] || doc.title['ja-JP'] | ||||
| 			section | ||||
| 				h2 API | ||||
| 				ul | ||||
|   | ||||
| @@ -197,7 +197,7 @@ const elements: Element[] = [ | ||||
|  | ||||
| 		if (thisIsNotARegexp) return null; | ||||
| 		if (regexp == '') return null; | ||||
| 		if (regexp[0] == ' ' && regexp[regexp.length - 1] == ' ') return null; | ||||
| 		if (regexp.startsWith(' ') && regexp.endsWith(' ')) return null; | ||||
|  | ||||
| 		return { | ||||
| 			html: `<span class="regexp">/${escape(regexp)}/</span>`, | ||||
|   | ||||
| @@ -10,7 +10,7 @@ export type TextElementHashtag = { | ||||
|  | ||||
| export default function(text: string, i: number) { | ||||
| 	if (!(/^\s#[^\s]+/.test(text) || (i == 0 && /^#[^\s]+/.test(text)))) return null; | ||||
| 	const isHead = text[0] == '#'; | ||||
| 	const isHead = text.startsWith('#'); | ||||
| 	const hashtag = text.match(/^\s?#[^\s]+/)[0]; | ||||
| 	const res: any[] = !isHead ? [{ | ||||
| 		type: 'text', | ||||
|   | ||||
| @@ -13,7 +13,7 @@ export type TextElementLink = { | ||||
| export default function(text: string) { | ||||
| 	const match = text.match(/^\??\[([^\[\]]+?)\]\((https?:\/\/[\w\/:%#@\$&\?!\(\)\[\]~\.=\+\-]+?)\)/); | ||||
| 	if (!match) return null; | ||||
| 	const silent = text[0] == '?'; | ||||
| 	const silent = text.startsWith('?'); | ||||
| 	const link = match[0]; | ||||
| 	const title = match[1]; | ||||
| 	const url = match[2]; | ||||
|   | ||||
| @@ -25,9 +25,9 @@ export const replacement = (match: string, key: string) => { | ||||
| 				arg == 'S' ? 'fas' : | ||||
| 				arg == 'B' ? 'fab' : | ||||
| 				''; | ||||
| 		} else if (arg[0] == '.') { | ||||
| 		} else if (arg.startsWith('.')) { | ||||
| 			classes.push('fa-' + arg.substr(1)); | ||||
| 		} else if (arg[0] == '-') { | ||||
| 		} else if (arg.startsWith('-')) { | ||||
| 			transform = arg.substr(1).split('|').join(' '); | ||||
| 		} else { | ||||
| 			name = arg; | ||||
|   | ||||
| @@ -2,14 +2,21 @@ import * as mongo from 'mongodb'; | ||||
| import db from '../db/mongodb'; | ||||
|  | ||||
| const Stats = db.get<IStats>('stats'); | ||||
| Stats.createIndex({ date: -1 }, { unique: true }); | ||||
| Stats.dropIndex({ date: -1 }); // 後方互換性のため | ||||
| Stats.createIndex({ span: -1, date: -1 }, { unique: true }); | ||||
| export default Stats; | ||||
|  | ||||
| export interface IStats { | ||||
| 	_id: mongo.ObjectID; | ||||
|  | ||||
| 	/** | ||||
| 	 * 集計日時 | ||||
| 	 */ | ||||
| 	date: Date; | ||||
|  | ||||
| 	/** | ||||
| 	 * 集計期間 | ||||
| 	 */ | ||||
| 	span: 'day' | 'hour'; | ||||
|  | ||||
| 	/** | ||||
| @@ -18,26 +25,36 @@ export interface IStats { | ||||
| 	users: { | ||||
| 		local: { | ||||
| 			/** | ||||
| 			 * この日時点での、ローカルのユーザーの総計 | ||||
| 			 * 集計期間時点での、全ユーザー数 (ローカル) | ||||
| 			 */ | ||||
| 			total: number; | ||||
|  | ||||
| 			/** | ||||
| 			 * ローカルのユーザー数の前日比 | ||||
| 			 * 増加したユーザー数 (ローカル) | ||||
| 			 */ | ||||
| 			diff: number; | ||||
| 			inc: number; | ||||
|  | ||||
| 			/** | ||||
| 			 * 減少したユーザー数 (ローカル) | ||||
| 			 */ | ||||
| 			dec: number; | ||||
| 		}; | ||||
|  | ||||
| 		remote: { | ||||
| 			/** | ||||
| 			 * この日時点での、リモートのユーザーの総計 | ||||
| 			 * 集計期間時点での、全ユーザー数 (リモート) | ||||
| 			 */ | ||||
| 			total: number; | ||||
|  | ||||
| 			/** | ||||
| 			 * リモートのユーザー数の前日比 | ||||
| 			 * 増加したユーザー数 (リモート) | ||||
| 			 */ | ||||
| 			diff: number; | ||||
| 			inc: number; | ||||
|  | ||||
| 			/** | ||||
| 			 * 減少したユーザー数 (リモート) | ||||
| 			 */ | ||||
| 			dec: number; | ||||
| 		}; | ||||
| 	}; | ||||
|  | ||||
| @@ -47,28 +64,33 @@ export interface IStats { | ||||
| 	notes: { | ||||
| 		local: { | ||||
| 			/** | ||||
| 			 * この日時点での、ローカルの投稿の総計 | ||||
| 			 * 集計期間時点での、全投稿数 (ローカル) | ||||
| 			 */ | ||||
| 			total: number; | ||||
|  | ||||
| 			/** | ||||
| 			 * ローカルの投稿数の前日比 | ||||
| 			 * 増加した投稿数 (ローカル) | ||||
| 			 */ | ||||
| 			diff: number; | ||||
| 			inc: number; | ||||
|  | ||||
| 			/** | ||||
| 			 * 減少した投稿数 (ローカル) | ||||
| 			 */ | ||||
| 			dec: number; | ||||
|  | ||||
| 			diffs: { | ||||
| 				/** | ||||
| 				 * ローカルの通常の投稿数の前日比 | ||||
| 				 * 通常の投稿数の差分 (ローカル) | ||||
| 				 */ | ||||
| 				normal: number; | ||||
|  | ||||
| 				/** | ||||
| 				 * ローカルのリプライの投稿数の前日比 | ||||
| 				 * リプライの投稿数の差分 (ローカル) | ||||
| 				 */ | ||||
| 				reply: number; | ||||
|  | ||||
| 				/** | ||||
| 				 * ローカルのRenoteの投稿数の前日比 | ||||
| 				 * Renoteの投稿数の差分 (ローカル) | ||||
| 				 */ | ||||
| 				renote: number; | ||||
| 			}; | ||||
| @@ -76,28 +98,33 @@ export interface IStats { | ||||
|  | ||||
| 		remote: { | ||||
| 			/** | ||||
| 			 * この日時点での、リモートの投稿の総計 | ||||
| 			 * 集計期間時点での、全投稿数 (リモート) | ||||
| 			 */ | ||||
| 			total: number; | ||||
|  | ||||
| 			/** | ||||
| 			 * リモートの投稿数の前日比 | ||||
| 			 * 増加した投稿数 (リモート) | ||||
| 			 */ | ||||
| 			diff: number; | ||||
| 			inc: number; | ||||
|  | ||||
| 			/** | ||||
| 			 * 減少した投稿数 (リモート) | ||||
| 			 */ | ||||
| 			dec: number; | ||||
|  | ||||
| 			diffs: { | ||||
| 				/** | ||||
| 				 * リモートの通常の投稿数の前日比 | ||||
| 				 * 通常の投稿数の差分 (リモート) | ||||
| 				 */ | ||||
| 				normal: number; | ||||
|  | ||||
| 				/** | ||||
| 				 * リモートのリプライの投稿数の前日比 | ||||
| 				 * リプライの投稿数の差分 (リモート) | ||||
| 				 */ | ||||
| 				reply: number; | ||||
|  | ||||
| 				/** | ||||
| 				 * リモートのRenoteの投稿数の前日比 | ||||
| 				 * Renoteの投稿数の差分 (リモート) | ||||
| 				 */ | ||||
| 				renote: number; | ||||
| 			}; | ||||
| @@ -110,46 +137,66 @@ export interface IStats { | ||||
| 	drive: { | ||||
| 		local: { | ||||
| 			/** | ||||
| 			 * この日時点での、ローカルのドライブファイル数の総計 | ||||
| 			 * 集計期間時点での、全ドライブファイル数 (ローカル) | ||||
| 			 */ | ||||
| 			totalCount: number; | ||||
|  | ||||
| 			/** | ||||
| 			 * この日時点での、ローカルのドライブファイルサイズの総計 | ||||
| 			 * 集計期間時点での、全ドライブファイルの合計サイズ (ローカル) | ||||
| 			 */ | ||||
| 			totalSize: number; | ||||
|  | ||||
| 			/** | ||||
| 			 * ローカルのドライブファイル数の前日比 | ||||
| 			 * 増加したドライブファイル数 (ローカル) | ||||
| 			 */ | ||||
| 			diffCount: number; | ||||
| 			incCount: number; | ||||
|  | ||||
| 			/** | ||||
| 			 * ローカルのドライブファイルサイズの前日比 | ||||
| 			 * 増加したドライブ使用量 (ローカル) | ||||
| 			 */ | ||||
| 			diffSize: number; | ||||
| 			incSize: number; | ||||
|  | ||||
| 			/** | ||||
| 			 * 減少したドライブファイル数 (ローカル) | ||||
| 			 */ | ||||
| 			decCount: number; | ||||
|  | ||||
| 			/** | ||||
| 			 * 減少したドライブ使用量 (ローカル) | ||||
| 			 */ | ||||
| 			decSize: number; | ||||
| 		}; | ||||
|  | ||||
| 		remote: { | ||||
| 			/** | ||||
| 			 * この日時点での、リモートのドライブファイル数の総計 | ||||
| 			 * 集計期間時点での、全ドライブファイル数 (リモート) | ||||
| 			 */ | ||||
| 			totalCount: number; | ||||
|  | ||||
| 			/** | ||||
| 			 * この日時点での、リモートのドライブファイルサイズの総計 | ||||
| 			 * 集計期間時点での、全ドライブファイルの合計サイズ (リモート) | ||||
| 			 */ | ||||
| 			totalSize: number; | ||||
|  | ||||
| 			/** | ||||
| 			 * リモートのドライブファイル数の前日比 | ||||
| 			 * 増加したドライブファイル数 (リモート) | ||||
| 			 */ | ||||
| 			diffCount: number; | ||||
| 			incCount: number; | ||||
|  | ||||
| 			/** | ||||
| 			 * リモートのドライブファイルサイズの前日比 | ||||
| 			 * 増加したドライブ使用量 (リモート) | ||||
| 			 */ | ||||
| 			diffSize: number; | ||||
| 			incSize: number; | ||||
|  | ||||
| 			/** | ||||
| 			 * 減少したドライブファイル数 (リモート) | ||||
| 			 */ | ||||
| 			decCount: number; | ||||
|  | ||||
| 			/** | ||||
| 			 * 減少したドライブ使用量 (リモート) | ||||
| 			 */ | ||||
| 			decSize: number; | ||||
| 		}; | ||||
| 	}; | ||||
| } | ||||
|   | ||||
| @@ -6,6 +6,8 @@ import parseAcct from '../../../misc/acct/parse'; | ||||
| import User, { IRemoteUser } from '../../../models/user'; | ||||
| import perform from '../../../remote/activitypub/perform'; | ||||
| import { resolvePerson } from '../../../remote/activitypub/models/person'; | ||||
| import { toUnicode } from 'punycode'; | ||||
| import { URL } from 'url'; | ||||
|  | ||||
| const log = debug('misskey:queue:inbox'); | ||||
|  | ||||
| @@ -32,6 +34,15 @@ export default async (job: bq.Job, done: any): Promise<void> => { | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
| 		// アクティビティ内のホストの検証 | ||||
| 		try { | ||||
| 			ValidateActivity(activity, host); | ||||
| 		} catch (e) { | ||||
| 			console.warn(e); | ||||
| 			done(); | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
| 		user = await User.findOne({ usernameLower: username, host: host.toLowerCase() }) as IRemoteUser; | ||||
|  | ||||
| 		// アクティビティを送信してきたユーザーがまだMisskeyサーバーに登録されていなかったら登録する | ||||
| @@ -39,6 +50,16 @@ export default async (job: bq.Job, done: any): Promise<void> => { | ||||
| 			user = await resolvePerson(activity.actor) as IRemoteUser; | ||||
| 		} | ||||
| 	} else { | ||||
| 		// アクティビティ内のホストの検証 | ||||
| 		const host = toUnicode(new URL(signature.keyId).hostname.toLowerCase()); | ||||
| 		try { | ||||
| 			ValidateActivity(activity, host); | ||||
| 		} catch (e) { | ||||
| 			console.warn(e); | ||||
| 			done(); | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
| 		user = await User.findOne({ | ||||
| 			host: { $ne: null }, | ||||
| 			'publicKey.id': signature.keyId | ||||
| @@ -46,7 +67,7 @@ export default async (job: bq.Job, done: any): Promise<void> => { | ||||
|  | ||||
| 		// アクティビティを送信してきたユーザーがまだMisskeyサーバーに登録されていなかったら登録する | ||||
| 		if (user === null) { | ||||
| 			user = await resolvePerson(signature.keyId) as IRemoteUser; | ||||
| 			user = await resolvePerson(activity.actor) as IRemoteUser; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @@ -69,3 +90,37 @@ export default async (job: bq.Job, done: any): Promise<void> => { | ||||
| 		done(e); | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * Validate host in activity | ||||
|  * @param activity Activity | ||||
|  * @param host Expect host | ||||
|  */ | ||||
| function ValidateActivity(activity: any, host: string) { | ||||
| 	// id (if exists) | ||||
| 	if (typeof activity.id === 'string') { | ||||
| 		const uriHost = toUnicode(new URL(activity.id).hostname.toLowerCase()); | ||||
| 		if (host !== uriHost) throw new Error('activity.id has different host'); | ||||
| 	} | ||||
|  | ||||
| 	// actor (if exists) | ||||
| 	if (typeof activity.actor === 'string') { | ||||
| 		const uriHost = toUnicode(new URL(activity.actor).hostname.toLowerCase()); | ||||
| 		if (host !== uriHost) throw new Error('activity.actor has different host'); | ||||
| 	} | ||||
|  | ||||
| 	// For Create activity | ||||
| 	if (activity.type === 'Create' && activity.object) { | ||||
| 		// object.id (if exists) | ||||
| 		if (typeof activity.object.id === 'string') { | ||||
| 			const uriHost = toUnicode(new URL(activity.object.id).hostname.toLowerCase()); | ||||
| 			if (host !== uriHost) throw new Error('activity.object.id has different host'); | ||||
| 		} | ||||
|  | ||||
| 		// object.attributedTo (if exists) | ||||
| 		if (typeof activity.object.attributedTo === 'string') { | ||||
| 			const uriHost = toUnicode(new URL(activity.object.attributedTo).hostname.toLowerCase()); | ||||
| 			if (host !== uriHost) throw new Error('activity.object.attributedTo has different host'); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -131,5 +131,7 @@ export async function resolveNote(value: string | IObject, resolver?: Resolver): | ||||
| 	//#endregion | ||||
|  | ||||
| 	// リモートサーバーからフェッチしてきて登録 | ||||
| 	return await createNote(value, resolver); | ||||
| 	// ここでuriの代わりに添付されてきたNote Objectが指定されていると、サーバーフェッチを経ずにノートが生成されるが | ||||
| 	// 添付されてきたNote Objectは偽装されている可能性があるため、常にuriを指定してサーバーフェッチを行う。 | ||||
| 	return await createNote(uri, resolver); | ||||
| } | ||||
|   | ||||
| @@ -4,18 +4,25 @@ import * as debug from 'debug'; | ||||
|  | ||||
| import config from '../../../config'; | ||||
| import User, { validateUsername, isValidName, IUser, IRemoteUser } from '../../../models/user'; | ||||
| import webFinger from '../../webfinger'; | ||||
| import Resolver from '../resolver'; | ||||
| import { resolveImage } from './image'; | ||||
| import { isCollectionOrOrderedCollection, IObject, IPerson } from '../type'; | ||||
| import { isCollectionOrOrderedCollection, IPerson } from '../type'; | ||||
| import { IDriveFile } from '../../../models/drive-file'; | ||||
| import Meta from '../../../models/meta'; | ||||
| import htmlToMFM from '../../../mfm/html-to-mfm'; | ||||
| import { updateUserStats } from '../../../services/update-chart'; | ||||
| import { URL } from 'url'; | ||||
|  | ||||
| const log = debug('misskey:activitypub'); | ||||
|  | ||||
| function validatePerson(x: any) { | ||||
| /** | ||||
|  * Validate Person object | ||||
|  * @param x Fetched person object | ||||
|  * @param uri Fetch target URI | ||||
|  */ | ||||
| function validatePerson(x: any, uri: string) { | ||||
| 	const expectHost = toUnicode(new URL(uri).hostname.toLowerCase()); | ||||
|  | ||||
| 	if (x == null) { | ||||
| 		return new Error('invalid person: object is null'); | ||||
| 	} | ||||
| @@ -40,6 +47,24 @@ function validatePerson(x: any) { | ||||
| 		return new Error('invalid person: invalid name'); | ||||
| 	} | ||||
|  | ||||
| 	if (typeof x.id !== 'string') { | ||||
| 		return new Error('invalid person: id is not a string'); | ||||
| 	} | ||||
|  | ||||
| 	const idHost = toUnicode(new URL(x.id).hostname.toLowerCase()); | ||||
| 	if (idHost !== expectHost) { | ||||
| 		return new Error('invalid person: id has different host'); | ||||
| 	} | ||||
|  | ||||
| 	if (typeof x.publicKey.id !== 'string') { | ||||
| 		return new Error('invalid person: publicKey.id is not a string'); | ||||
| 	} | ||||
|  | ||||
| 	const publicKeyIdHost = toUnicode(new URL(x.publicKey.id).hostname.toLowerCase()); | ||||
| 	if (publicKeyIdHost !== expectHost) { | ||||
| 		return new Error('invalid person: publicKey.id has different host'); | ||||
| 	} | ||||
|  | ||||
| 	return null; | ||||
| } | ||||
|  | ||||
| @@ -48,8 +73,8 @@ function validatePerson(x: any) { | ||||
|  * | ||||
|  * Misskeyに対象のPersonが登録されていればそれを返します。 | ||||
|  */ | ||||
| export async function fetchPerson(value: string | IObject, resolver?: Resolver): Promise<IUser> { | ||||
| 	const uri = typeof value == 'string' ? value : value.id; | ||||
| export async function fetchPerson(uri: string, resolver?: Resolver): Promise<IUser> { | ||||
| 	if (typeof uri !== 'string') throw 'uri is not string'; | ||||
|  | ||||
| 	// URIがこのサーバーを指しているならデータベースからフェッチ | ||||
| 	if (uri.startsWith(config.url + '/')) { | ||||
| @@ -71,12 +96,14 @@ export async function fetchPerson(value: string | IObject, resolver?: Resolver): | ||||
| /** | ||||
|  * Personを作成します。 | ||||
|  */ | ||||
| export async function createPerson(value: any, resolver?: Resolver): Promise<IUser> { | ||||
| export async function createPerson(uri: string, resolver?: Resolver): Promise<IUser> { | ||||
| 	if (typeof uri !== 'string') throw 'uri is not string'; | ||||
|  | ||||
| 	if (resolver == null) resolver = new Resolver(); | ||||
|  | ||||
| 	const object = await resolver.resolve(value) as any; | ||||
| 	const object = await resolver.resolve(uri) as any; | ||||
|  | ||||
| 	const err = validatePerson(object); | ||||
| 	const err = validatePerson(object, uri); | ||||
|  | ||||
| 	if (err) { | ||||
| 		throw err; | ||||
| @@ -86,7 +113,7 @@ export async function createPerson(value: any, resolver?: Resolver): Promise<IUs | ||||
|  | ||||
| 	log(`Creating the Person: ${person.id}`); | ||||
|  | ||||
| 	const [followersCount = 0, followingCount = 0, notesCount = 0, finger] = await Promise.all([ | ||||
| 	const [followersCount = 0, followingCount = 0, notesCount = 0] = await Promise.all([ | ||||
| 		resolver.resolve(person.followers).then( | ||||
| 			resolved => isCollectionOrOrderedCollection(resolved) ? resolved.totalItems : undefined, | ||||
| 			() => undefined | ||||
| @@ -98,11 +125,10 @@ export async function createPerson(value: any, resolver?: Resolver): Promise<IUs | ||||
| 		resolver.resolve(person.outbox).then( | ||||
| 			resolved => isCollectionOrOrderedCollection(resolved) ? resolved.totalItems : undefined, | ||||
| 			() => undefined | ||||
| 		), | ||||
| 		webFinger(person.id) | ||||
| 		) | ||||
| 	]); | ||||
|  | ||||
| 	const host = toUnicode(finger.subject.replace(/^.*?@/, '')).toLowerCase(); | ||||
| 	const host = toUnicode(new URL(object.id).hostname.toLowerCase()); | ||||
|  | ||||
| 	const isBot = object.type == 'Service'; | ||||
|  | ||||
| @@ -166,8 +192,8 @@ export async function createPerson(value: any, resolver?: Resolver): Promise<IUs | ||||
|  | ||||
| 	const avatarId = avatar ? avatar._id : null; | ||||
| 	const bannerId = banner ? banner._id : null; | ||||
| 	const avatarUrl = avatar && avatar.metadata.url ? avatar.metadata.url : null; | ||||
| 	const bannerUrl = banner && banner.metadata.url ? banner.metadata.url : null; | ||||
| 	const avatarUrl = (avatar && avatar.metadata.thumbnailUrl) ? avatar.metadata.thumbnailUrl : (avatar && avatar.metadata.url) ? avatar.metadata.url : null; | ||||
| 	const bannerUrl = (banner && banner.metadata.url) ? banner.metadata.url : null; | ||||
|  | ||||
| 	await User.update({ _id: user._id }, { | ||||
| 		$set: { | ||||
| @@ -192,8 +218,8 @@ export async function createPerson(value: any, resolver?: Resolver): Promise<IUs | ||||
|  * | ||||
|  * Misskeyに対象のPersonが登録されていなければ無視します。 | ||||
|  */ | ||||
| export async function updatePerson(value: string | IObject, resolver?: Resolver): Promise<void> { | ||||
| 	const uri = typeof value == 'string' ? value : value.id; | ||||
| export async function updatePerson(uri: string, resolver?: Resolver): Promise<void> { | ||||
| 	if (typeof uri !== 'string') throw 'uri is not string'; | ||||
|  | ||||
| 	// URIがこのサーバーを指しているならスキップ | ||||
| 	if (uri.startsWith(config.url + '/')) { | ||||
| @@ -210,9 +236,9 @@ export async function updatePerson(value: string | IObject, resolver?: Resolver) | ||||
|  | ||||
| 	if (resolver == null) resolver = new Resolver(); | ||||
|  | ||||
| 	const object = await resolver.resolve(value) as any; | ||||
| 	const object = await resolver.resolve(uri) as any; | ||||
|  | ||||
| 	const err = validatePerson(object); | ||||
| 	const err = validatePerson(object, uri); | ||||
|  | ||||
| 	if (err) { | ||||
| 		throw err; | ||||
| @@ -255,7 +281,7 @@ export async function updatePerson(value: string | IObject, resolver?: Resolver) | ||||
| 			sharedInbox: person.sharedInbox, | ||||
| 			avatarId: avatar ? avatar._id : null, | ||||
| 			bannerId: banner ? banner._id : null, | ||||
| 			avatarUrl: avatar && avatar.metadata.url ? avatar.metadata.url : null, | ||||
| 			avatarUrl: (avatar && avatar.metadata.thumbnailUrl) ? avatar.metadata.thumbnailUrl : (avatar && avatar.metadata.url) ? avatar.metadata.url : null, | ||||
| 			bannerUrl: banner && banner.metadata.url ? banner.metadata.url : null, | ||||
| 			description: htmlToMFM(person.summary), | ||||
| 			followersCount, | ||||
| @@ -275,8 +301,8 @@ export async function updatePerson(value: string | IObject, resolver?: Resolver) | ||||
|  * Misskeyに対象のPersonが登録されていればそれを返し、そうでなければ | ||||
|  * リモートサーバーからフェッチしてMisskeyに登録しそれを返します。 | ||||
|  */ | ||||
| export async function resolvePerson(value: string | IObject, verifier?: string): Promise<IUser> { | ||||
| 	const uri = typeof value == 'string' ? value : value.id; | ||||
| export async function resolvePerson(uri: string, verifier?: string): Promise<IUser> { | ||||
| 	if (typeof uri !== 'string') throw 'uri is not string'; | ||||
|  | ||||
| 	//#region このサーバーに既に登録されていたらそれを返す | ||||
| 	const exist = await fetchPerson(uri); | ||||
| @@ -287,5 +313,5 @@ export async function resolvePerson(value: string | IObject, verifier?: string): | ||||
| 	//#endregion | ||||
|  | ||||
| 	// リモートサーバーからフェッチしてきて登録 | ||||
| 	return await createPerson(value); | ||||
| 	return await createPerson(uri); | ||||
| } | ||||
|   | ||||
| @@ -6,6 +6,7 @@ export default (object: any, note: INote) => { | ||||
|  | ||||
| 	return { | ||||
| 		id: `${config.url}/notes/${note._id}`, | ||||
| 		actor: `${config.url}/users/${note.userId}`, | ||||
| 		type: 'Announce', | ||||
| 		published: note.createdAt.toISOString(), | ||||
| 		to: ['https://www.w3.org/ns/activitystreams#Public'], | ||||
|   | ||||
| @@ -1,4 +1,17 @@ | ||||
| export default (object: any) => ({ | ||||
| import config from '../../../config'; | ||||
| import { INote } from '../../../models/note'; | ||||
|  | ||||
| export default (object: any, note: INote) => { | ||||
| 	const activity = { | ||||
| 		id: `${config.url}/notes/${note._id}/activity`, | ||||
| 		actor: `${config.url}/users/${note.userId}`, | ||||
| 		type: 'Create', | ||||
| 		published: note.createdAt.toISOString(), | ||||
| 		object | ||||
| }); | ||||
| 	} as any; | ||||
|  | ||||
| 	if (object.to) activity.to = object.to; | ||||
| 	if (object.cc) activity.cc = object.cc; | ||||
|  | ||||
| 	return activity; | ||||
| }; | ||||
|   | ||||
| @@ -1,4 +1,8 @@ | ||||
| export default (object: any) => ({ | ||||
| import config from '../../../config'; | ||||
| import { ILocalUser } from "../../../models/user"; | ||||
|  | ||||
| export default (object: any, user: ILocalUser) => ({ | ||||
| 	type: 'Delete', | ||||
| 	actor: `${config.url}/users/${user._id}`, | ||||
| 	object | ||||
| }); | ||||
|   | ||||
| @@ -1,7 +1,16 @@ | ||||
| export default (x: any) => Object.assign({ | ||||
| import config from '../../../config'; | ||||
| import * as uuid from 'uuid'; | ||||
|  | ||||
| export default (x: any) => { | ||||
| 	if (x !== null && typeof x === 'object' && x.id == null) { | ||||
| 		x.id = `${config.url}/${uuid.v4()}`; | ||||
| 	} | ||||
|  | ||||
| 	return Object.assign({ | ||||
| 		'@context': [ | ||||
| 			'https://www.w3.org/ns/activitystreams', | ||||
| 			'https://w3id.org/security/v1', | ||||
| 			{ Hashtag: 'as:Hashtag' } | ||||
| 		] | ||||
| }, x); | ||||
| 	}, x); | ||||
| }; | ||||
|   | ||||
| @@ -1,4 +1,8 @@ | ||||
| export default (object: any) => ({ | ||||
| import config from '../../../config'; | ||||
| import { ILocalUser, IUser } from "../../../models/user"; | ||||
|  | ||||
| export default (object: any, user: ILocalUser | IUser) => ({ | ||||
| 	type: 'Undo', | ||||
| 	actor: `${config.url}/users/${user._id}`, | ||||
| 	object | ||||
| }); | ||||
|   | ||||
| @@ -2,6 +2,7 @@ import { request } from 'https'; | ||||
| const { sign } = require('http-signature'); | ||||
| import { URL } from 'url'; | ||||
| import * as debug from 'debug'; | ||||
| const crypto = require('crypto'); | ||||
|  | ||||
| import config from '../../config'; | ||||
| import { ILocalUser } from '../../models/user'; | ||||
| @@ -13,12 +14,22 @@ export default (user: ILocalUser, url: string, object: any) => new Promise((reso | ||||
|  | ||||
| 	const { protocol, hostname, port, pathname, search } = new URL(url); | ||||
|  | ||||
| 	const data = JSON.stringify(object); | ||||
|  | ||||
| 	const sha256 = crypto.createHash('sha256'); | ||||
| 	sha256.update(data); | ||||
| 	const hash = sha256.digest('base64'); | ||||
|  | ||||
| 	const req = request({ | ||||
| 		protocol, | ||||
| 		hostname, | ||||
| 		port, | ||||
| 		method: 'POST', | ||||
| 		path: pathname + search, | ||||
| 		headers: { | ||||
| 			'Content-Type': 'application/activity+json', | ||||
| 			'Digest': `SHA-256=${hash}` | ||||
| 		} | ||||
| 	}, res => { | ||||
| 		log(`${url} --> ${res.statusCode}`); | ||||
|  | ||||
| @@ -32,7 +43,8 @@ export default (user: ILocalUser, url: string, object: any) => new Promise((reso | ||||
| 	sign(req, { | ||||
| 		authorizationHeaderName: 'Signature', | ||||
| 		key: user.keypair, | ||||
| 		keyId: `acct:${user.username}@${config.host}` | ||||
| 		keyId: `${config.url}/users/${user._id}/publickey`, | ||||
| 		headers: ['date', 'host', 'digest'] | ||||
| 	}); | ||||
|  | ||||
| 	// Signature: Signature ... => Signature: ... | ||||
| @@ -40,5 +52,5 @@ export default (user: ILocalUser, url: string, object: any) => new Promise((reso | ||||
| 	sig = sig.replace(/^Signature /, ''); | ||||
| 	req.setHeader('Signature', sig); | ||||
|  | ||||
| 	req.end(JSON.stringify(object)); | ||||
| 	req.end(data); | ||||
| }); | ||||
|   | ||||
| @@ -25,7 +25,7 @@ function inbox(ctx: Router.IRouterContext) { | ||||
| 	ctx.req.headers.authorization = 'Signature ' + ctx.req.headers.signature; | ||||
|  | ||||
| 	try { | ||||
| 		signature = httpSignature.parseRequest(ctx.req); | ||||
| 		signature = httpSignature.parseRequest(ctx.req, { 'headers': [] }); | ||||
| 	} catch (e) { | ||||
| 		ctx.status = 401; | ||||
| 		return; | ||||
|   | ||||
| @@ -1 +1 @@ | ||||
| export default (token: string) => token[0] == '!'; | ||||
| export default (token: string) => token.startsWith('!'); | ||||
|   | ||||
| @@ -3,7 +3,7 @@ import RegistrationTicket from '../../../../models/registration-tickets'; | ||||
|  | ||||
| export const meta = { | ||||
| 	desc: { | ||||
| 		ja: '招待コードを発行します。' | ||||
| 		'ja-JP': '招待コードを発行します。' | ||||
| 	}, | ||||
|  | ||||
| 	requireCredential: true, | ||||
|   | ||||
| @@ -5,8 +5,8 @@ import User from '../../../../models/user'; | ||||
|  | ||||
| export const meta = { | ||||
| 	desc: { | ||||
| 		ja: '指定したユーザーを凍結します。', | ||||
| 		en: 'Suspend a user.' | ||||
| 		'ja-JP': '指定したユーザーを凍結します。', | ||||
| 		'en-US': 'Suspend a user.' | ||||
| 	}, | ||||
|  | ||||
| 	requireCredential: true, | ||||
| @@ -15,8 +15,8 @@ export const meta = { | ||||
| 	params: { | ||||
| 		userId: $.type(ID).note({ | ||||
| 			desc: { | ||||
| 				ja: '対象のユーザーID', | ||||
| 				en: 'The user ID which you want to suspend' | ||||
| 				'ja-JP': '対象のユーザーID', | ||||
| 				'en-US': 'The user ID which you want to suspend' | ||||
| 			} | ||||
| 		}), | ||||
| 	} | ||||
|   | ||||
| @@ -5,8 +5,8 @@ import User from '../../../../models/user'; | ||||
|  | ||||
| export const meta = { | ||||
| 	desc: { | ||||
| 		ja: '指定したユーザーの凍結を解除します。', | ||||
| 		en: 'Unsuspend a user.' | ||||
| 		'ja-JP': '指定したユーザーの凍結を解除します。', | ||||
| 		'en-US': 'Unsuspend a user.' | ||||
| 	}, | ||||
|  | ||||
| 	requireCredential: true, | ||||
| @@ -15,8 +15,8 @@ export const meta = { | ||||
| 	params: { | ||||
| 		userId: $.type(ID).note({ | ||||
| 			desc: { | ||||
| 				ja: '対象のユーザーID', | ||||
| 				en: 'The user ID which you want to unsuspend' | ||||
| 				'ja-JP': '対象のユーザーID', | ||||
| 				'en-US': 'The user ID which you want to unsuspend' | ||||
| 			} | ||||
| 		}), | ||||
| 	} | ||||
|   | ||||
| @@ -5,8 +5,8 @@ import User from '../../../../models/user'; | ||||
|  | ||||
| export const meta = { | ||||
| 	desc: { | ||||
| 		ja: '指定したユーザーの公式アカウントを解除します。', | ||||
| 		en: 'Mark a user as unverified.' | ||||
| 		'ja-JP': '指定したユーザーの公式アカウントを解除します。', | ||||
| 		'en-US': 'Mark a user as unverified.' | ||||
| 	}, | ||||
|  | ||||
| 	requireCredential: true, | ||||
| @@ -15,8 +15,8 @@ export const meta = { | ||||
| 	params: { | ||||
| 		userId: $.type(ID).note({ | ||||
| 			desc: { | ||||
| 				ja: '対象のユーザーID', | ||||
| 				en: 'The user ID which you want to unverify' | ||||
| 				'ja-JP': '対象のユーザーID', | ||||
| 				'en-US': 'The user ID which you want to unverify' | ||||
| 			} | ||||
| 		}), | ||||
| 	} | ||||
|   | ||||
| @@ -4,7 +4,7 @@ import getParams from '../../get-params'; | ||||
|  | ||||
| export const meta = { | ||||
| 	desc: { | ||||
| 		ja: 'インスタンスの設定を更新します。' | ||||
| 		'ja-JP': 'インスタンスの設定を更新します。' | ||||
| 	}, | ||||
|  | ||||
| 	requireCredential: true, | ||||
| @@ -13,7 +13,7 @@ export const meta = { | ||||
| 	params: { | ||||
| 		disableRegistration: $.bool.optional.nullable.note({ | ||||
| 			desc: { | ||||
| 				ja: '招待制か否か' | ||||
| 				'ja-JP': '招待制か否か' | ||||
| 			} | ||||
| 		}), | ||||
| 	} | ||||
|   | ||||
| @@ -5,8 +5,8 @@ import User from '../../../../models/user'; | ||||
|  | ||||
| export const meta = { | ||||
| 	desc: { | ||||
| 		ja: '指定したユーザーを公式アカウントにします。', | ||||
| 		en: 'Mark a user as verified.' | ||||
| 		'ja-JP': '指定したユーザーを公式アカウントにします。', | ||||
| 		'en-US': 'Mark a user as verified.' | ||||
| 	}, | ||||
|  | ||||
| 	requireCredential: true, | ||||
| @@ -15,8 +15,8 @@ export const meta = { | ||||
| 	params: { | ||||
| 		userId: $.type(ID).note({ | ||||
| 			desc: { | ||||
| 				ja: '対象のユーザーID', | ||||
| 				en: 'The user ID which you want to verify' | ||||
| 				'ja-JP': '対象のユーザーID', | ||||
| 				'en-US': 'The user ID which you want to verify' | ||||
| 			} | ||||
| 		}), | ||||
| 	} | ||||
|   | ||||
| @@ -1,13 +1,71 @@ | ||||
| import $ from 'cafy'; | ||||
| import Stats, { IStats } from '../../../models/stats'; | ||||
| import getParams from '../get-params'; | ||||
|  | ||||
| type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>; | ||||
|  | ||||
| function migrateStats(stats: IStats[]) { | ||||
| 	stats.forEach(stat => { | ||||
| 		const isOldData = | ||||
| 			stat.users.local.inc == null || | ||||
| 			stat.users.local.dec == null || | ||||
| 			stat.users.remote.inc == null || | ||||
| 			stat.users.remote.dec == null || | ||||
| 			stat.notes.local.inc == null || | ||||
| 			stat.notes.local.dec == null || | ||||
| 			stat.notes.remote.inc == null || | ||||
| 			stat.notes.remote.dec == null || | ||||
| 			stat.drive.local.incCount == null || | ||||
| 			stat.drive.local.decCount == null || | ||||
| 			stat.drive.local.incSize == null || | ||||
| 			stat.drive.local.decSize == null || | ||||
| 			stat.drive.remote.incCount == null || | ||||
| 			stat.drive.remote.decCount == null || | ||||
| 			stat.drive.remote.incSize == null || | ||||
| 			stat.drive.remote.decSize == null; | ||||
|  | ||||
| 		if (!isOldData) return; | ||||
|  | ||||
| 		stat.users.local.inc = (stat as any).users.local.diff; | ||||
| 		stat.users.local.dec = 0; | ||||
| 		stat.users.remote.inc = (stat as any).users.remote.diff; | ||||
| 		stat.users.remote.dec = 0; | ||||
| 		stat.notes.local.inc = (stat as any).notes.local.diff; | ||||
| 		stat.notes.local.dec = 0; | ||||
| 		stat.notes.remote.inc = (stat as any).notes.remote.diff; | ||||
| 		stat.notes.remote.dec = 0; | ||||
| 		stat.drive.local.incCount = (stat as any).drive.local.diffCount; | ||||
| 		stat.drive.local.decCount = 0; | ||||
| 		stat.drive.local.incSize = (stat as any).drive.local.diffSize; | ||||
| 		stat.drive.local.decSize = 0; | ||||
| 		stat.drive.remote.incCount = (stat as any).drive.remote.diffCount; | ||||
| 		stat.drive.remote.decCount = 0; | ||||
| 		stat.drive.remote.incSize = (stat as any).drive.remote.diffSize; | ||||
| 		stat.drive.remote.decSize = 0; | ||||
| 	}); | ||||
| } | ||||
|  | ||||
| export const meta = { | ||||
| 	desc: { | ||||
| 		'ja-JP': 'インスタンスの統計を取得します。' | ||||
| 	}, | ||||
|  | ||||
| 	params: { | ||||
| 		limit: $.num.optional.range(1, 100).note({ | ||||
| 			default: 30, | ||||
| 			desc: { | ||||
| 				'ja-JP': '最大数' | ||||
| 			} | ||||
| 		}), | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| export default (params: any) => new Promise(async (res, rej) => { | ||||
| 	const daysRange = 90; | ||||
| 	const hoursRange = 24; | ||||
| 	const [ps, psErr] = getParams(meta, params); | ||||
| 	if (psErr) throw psErr; | ||||
|  | ||||
| 	const daysRange = ps.limit; | ||||
| 	const hoursRange = ps.limit; | ||||
|  | ||||
| 	const now = new Date(); | ||||
| 	const y = now.getFullYear(); | ||||
| @@ -44,6 +102,10 @@ export default (params: any) => new Promise(async (res, rej) => { | ||||
| 		}), | ||||
| 	]); | ||||
|  | ||||
| 	// 後方互換性のため | ||||
| 	migrateStats(statsPerDay); | ||||
| 	migrateStats(statsPerHour); | ||||
|  | ||||
| 	const format = (src: IStats[], span: 'day' | 'hour') => { | ||||
| 		const chart: Array<Omit<Omit<IStats, '_id'>, 'span'>> = []; | ||||
|  | ||||
| @@ -65,26 +127,81 @@ export default (params: any) => new Promise(async (res, rej) => { | ||||
| 			} else { // 隙間埋め | ||||
| 				const mostRecent = src.find(s => s.date.getTime() < current.getTime()); | ||||
| 				if (mostRecent) { | ||||
| 					chart.unshift(Object.assign({}, mostRecent, { | ||||
| 						date: current | ||||
| 					})); | ||||
| 					chart.unshift({ | ||||
| 						date: current, | ||||
| 						users: { | ||||
| 							local: { | ||||
| 								total: mostRecent.users.local.total, | ||||
| 								inc: 0, | ||||
| 								dec: 0 | ||||
| 							}, | ||||
| 							remote: { | ||||
| 								total: mostRecent.users.remote.total, | ||||
| 								inc: 0, | ||||
| 								dec: 0 | ||||
| 							} | ||||
| 						}, | ||||
| 						notes: { | ||||
| 							local: { | ||||
| 								total: mostRecent.notes.local.total, | ||||
| 								inc: 0, | ||||
| 								dec: 0, | ||||
| 								diffs: { | ||||
| 									normal: 0, | ||||
| 									reply: 0, | ||||
| 									renote: 0 | ||||
| 								} | ||||
| 							}, | ||||
| 							remote: { | ||||
| 								total: mostRecent.notes.remote.total, | ||||
| 								inc: 0, | ||||
| 								dec: 0, | ||||
| 								diffs: { | ||||
| 									normal: 0, | ||||
| 									reply: 0, | ||||
| 									renote: 0 | ||||
| 								} | ||||
| 							} | ||||
| 						}, | ||||
| 						drive: { | ||||
| 							local: { | ||||
| 								totalCount: mostRecent.drive.local.totalCount, | ||||
| 								totalSize: mostRecent.drive.local.totalSize, | ||||
| 								incCount: 0, | ||||
| 								incSize: 0, | ||||
| 								decCount: 0, | ||||
| 								decSize: 0 | ||||
| 							}, | ||||
| 							remote: { | ||||
| 								totalCount: mostRecent.drive.remote.totalCount, | ||||
| 								totalSize: mostRecent.drive.remote.totalSize, | ||||
| 								incCount: 0, | ||||
| 								incSize: 0, | ||||
| 								decCount: 0, | ||||
| 								decSize: 0 | ||||
| 							} | ||||
| 						} | ||||
| 					}); | ||||
| 				} else { | ||||
| 					chart.unshift({ | ||||
| 						date: current, | ||||
| 						users: { | ||||
| 							local: { | ||||
| 								total: 0, | ||||
| 								diff: 0 | ||||
| 								inc: 0, | ||||
| 								dec: 0 | ||||
| 							}, | ||||
| 							remote: { | ||||
| 								total: 0, | ||||
| 								diff: 0 | ||||
| 								inc: 0, | ||||
| 								dec: 0 | ||||
| 							} | ||||
| 						}, | ||||
| 						notes: { | ||||
| 							local: { | ||||
| 								total: 0, | ||||
| 								diff: 0, | ||||
| 								inc: 0, | ||||
| 								dec: 0, | ||||
| 								diffs: { | ||||
| 									normal: 0, | ||||
| 									reply: 0, | ||||
| @@ -93,7 +210,8 @@ export default (params: any) => new Promise(async (res, rej) => { | ||||
| 							}, | ||||
| 							remote: { | ||||
| 								total: 0, | ||||
| 								diff: 0, | ||||
| 								inc: 0, | ||||
| 								dec: 0, | ||||
| 								diffs: { | ||||
| 									normal: 0, | ||||
| 									reply: 0, | ||||
| @@ -105,14 +223,18 @@ export default (params: any) => new Promise(async (res, rej) => { | ||||
| 							local: { | ||||
| 								totalCount: 0, | ||||
| 								totalSize: 0, | ||||
| 								diffCount: 0, | ||||
| 								diffSize: 0 | ||||
| 								incCount: 0, | ||||
| 								incSize: 0, | ||||
| 								decCount: 0, | ||||
| 								decSize: 0 | ||||
| 							}, | ||||
| 							remote: { | ||||
| 								totalCount: 0, | ||||
| 								totalSize: 0, | ||||
| 								diffCount: 0, | ||||
| 								diffSize: 0 | ||||
| 								incCount: 0, | ||||
| 								incSize: 0, | ||||
| 								decCount: 0, | ||||
| 								decSize: 0 | ||||
| 							} | ||||
| 						} | ||||
| 					}); | ||||
|   | ||||
| @@ -4,8 +4,8 @@ import config from '../../../config'; | ||||
|  | ||||
| export const meta = { | ||||
| 	desc: { | ||||
| 		ja: 'ドライブの情報を取得します。', | ||||
| 		en: 'Get drive information.' | ||||
| 		'ja-JP': 'ドライブの情報を取得します。', | ||||
| 		'en-US': 'Get drive information.' | ||||
| 	}, | ||||
|  | ||||
| 	requireCredential: true, | ||||
|   | ||||
| @@ -4,8 +4,8 @@ import { ILocalUser } from '../../../../models/user'; | ||||
|  | ||||
| export const meta = { | ||||
| 	desc: { | ||||
| 		ja: 'ドライブのファイル一覧を取得します。', | ||||
| 		en: 'Get files of drive.' | ||||
| 		'ja-JP': 'ドライブのファイル一覧を取得します。', | ||||
| 		'en-US': 'Get files of drive.' | ||||
| 	}, | ||||
|  | ||||
| 	requireCredential: true, | ||||
|   | ||||
| @@ -8,8 +8,8 @@ import getParams from '../../../get-params'; | ||||
|  | ||||
| export const meta = { | ||||
| 	desc: { | ||||
| 		ja: 'ドライブにファイルをアップロードします。', | ||||
| 		en: 'Upload a file to drive.' | ||||
| 		'ja-JP': 'ドライブにファイルをアップロードします。', | ||||
| 		'en-US': 'Upload a file to drive.' | ||||
| 	}, | ||||
|  | ||||
| 	requireCredential: true, | ||||
| @@ -27,15 +27,15 @@ export const meta = { | ||||
| 		folderId: $.type(ID).optional.nullable.note({ | ||||
| 			default: null, | ||||
| 			desc: { | ||||
| 				ja: 'フォルダID' | ||||
| 				'ja-JP': 'フォルダID' | ||||
| 			} | ||||
| 		}), | ||||
|  | ||||
| 		isSensitive: $.bool.optional.note({ | ||||
| 			default: false, | ||||
| 			desc: { | ||||
| 				ja: 'このメディアが「閲覧注意」(NSFW)かどうか', | ||||
| 				en: 'Whether this media is NSFW' | ||||
| 				'ja-JP': 'このメディアが「閲覧注意」(NSFW)かどうか', | ||||
| 				'en-US': 'Whether this media is NSFW' | ||||
| 			} | ||||
| 		}) | ||||
| 	} | ||||
|   | ||||
| @@ -6,8 +6,8 @@ import { ILocalUser } from '../../../../../models/user'; | ||||
|  | ||||
| export const meta = { | ||||
| 	desc: { | ||||
| 		ja: 'ドライブのファイルを削除します。', | ||||
| 		en: 'Delete a file of drive.' | ||||
| 		'ja-JP': 'ドライブのファイルを削除します。', | ||||
| 		'en-US': 'Delete a file of drive.' | ||||
| 	}, | ||||
|  | ||||
| 	requireCredential: true, | ||||
|   | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user