Merge pull request #25 from Xeltica/2.0

Misskey Tools 2.0
This commit is contained in:
Ebise Lutica 2021-10-11 20:38:29 +09:00 committed by GitHub
commit 81c2dcb35a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
141 changed files with 10852 additions and 1893 deletions

9
.editorconfig Normal file
View File

@ -0,0 +1,9 @@
root = true
[*.{ts,tsx,js,json,pug}]
indent_style = tab
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
indent_size = 2

View File

@ -18,11 +18,10 @@ module.exports = {
'rules': {
'indent': [
'error',
'tab'
],
'linebreak-style': [
'error',
'unix'
'tab',
{
'SwitchCase': 1,
}
],
'quotes': [
'error',

3
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"typescript.tsdk": "node_modules\\typescript\\lib"
}

8
CHANGELOG.md Normal file
View File

@ -0,0 +1,8 @@
## 2.0
* デザイン面・機能面での大幅な作り直し
## 1.5.1
* インスタンスの接続エラーにより後続処理が行えなくなる重大な不具合を修正
* 全員分の算出が終わるまで、ランキングを非表示に

View File

@ -1,5 +1,5 @@
Misshaialert
Copyright (C) 2020 Xeltica
Misskey Tools
Copyright (C) 2020-2021 Xeltica
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as

View File

@ -1,10 +1,12 @@
# みす廃あらーと
# Misskey Tools (aka みす廃あらーと)
みす廃あらーとは、Misskeyでのート、フォロー、フォロワーの数および前日比を毎日0時にートするサービスです。
Misskey Toolsは、Misskeyのために設計された、様々な機能を取り揃えたアカウント管理ツールです。
以前は「みす廃あらーと」という、Misskeyでのート、フォロー、フォロワーの数および前日比を毎日0時にートするサービスとして開発されていましたが、現在様々な機能に対応したオールインワンツールとして開発中です。
## 対応
Misskey v10 以降および互換性のあるサーバー
Misskey v10 以降およびGroundpolis, MeisskeyなどのMisskeyと互換性のあるサーバー
## ビルド
@ -19,9 +21,14 @@ yarn build
yarn start
# デバッグ用に起動
yarn watch
yarn dev
```
## LICENSE
[AGPL 3.0](LICENSE)
[AGPL 3.0](LICENSE)
## Conrtibutors
- @Xeltica (Main Developer)
- @4ioskd (English initial Translator)

View File

@ -1,6 +1,6 @@
{
"port": 4000,
"url": "https://misshaialert.com",
"url": "https://misskey.tools",
"db": {
"host": "localhost",
"port": 5432,
@ -8,5 +8,9 @@
"pass": "pass",
"db": "misshaialert",
"extra": {}
},
"admin": {
"username": "your_user_name",
"host": "your-instance-host"
}
}
}

4
crowdin.yml Normal file
View File

@ -0,0 +1,4 @@
files:
- source: /src/frontend/langs/ja-JP.json
translation: /src/frontend/langs/%locale%.json
update_option: update_as_unapproved

View File

@ -0,0 +1,14 @@
import {MigrationInterface, QueryRunner} from 'typeorm';
export class Announcement1633841235323 implements MigrationInterface {
name = 'Announcement1633841235323'
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query('CREATE TABLE "announcement" ("id" SERIAL NOT NULL, "createdAt" TIMESTAMP NOT NULL, "title" character varying(128) NOT NULL, "body" character varying(8192) NOT NULL, "like" integer NOT NULL DEFAULT 0, CONSTRAINT "PK_e0ef0550174fd1099a308fd18a0" PRIMARY KEY ("id"))');
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query('DROP TABLE "announcement"');
}
}

View File

@ -1,5 +1,10 @@
{
"watch": ["src", ["styles"]],
"ext": "ts,pug,scss",
"exec": "run-s build start"
}
"watch": [
"src"
],
"ignore": [
"src/frontend/*"
],
"ext": "ts,tsx,pug,scss",
"exec": "run-s build:backend start"
}

View File

@ -1,6 +1,6 @@
const fs = require('fs');
const entities = require('./built/services/db').entities;
const entities = require('./built/backend/services/db').entities;
const config = Object.freeze(JSON.parse(fs.readFileSync(__dirname + '/config.json', 'utf-8')));
@ -17,4 +17,4 @@ module.exports = {
cli: {
migrationsDir: 'migration'
}
};
};

View File

@ -1,69 +1,107 @@
{
"name": "misshaialert",
"version": "1.5.1",
"description": "",
"main": "built/app.js",
"author": "Xeltica",
"private": true,
"scripts": {
"tsc": "tsc",
"start": "node built/app.js",
"lint": "eslint src/index.ts",
"lint:fix": "eslint --fix src/index.ts",
"build:views": "copyfiles -u 1 src/views/*.pug ./built/",
"clean": "rimraf built",
"build:scripts": "tsc",
"build:styles": "sass styles/:built/assets",
"build": "run-p build:*",
"migrate": "ts-node --project ./tsconfig.migration.json ./node_modules/typeorm/cli.js migration:run",
"migrate:revert": "ts-node --project ./tsconfig.migration.json ./node_modules/typeorm/cli.js migration:revert",
"dev": "nodemon"
},
"dependencies": {
"@types/koa-bodyparser": "^4.3.0",
"@types/koa-mount": "^4.0.0",
"@types/koa-multer": "^1.0.0",
"@types/koa-static": "^4.0.1",
"@types/node-cron": "^2.0.3",
"@types/uuid": "^8.0.0",
"axios": "^0.21.2",
"dayjs": "^1.10.2",
"delay": "^4.4.0",
"koa": "^2.13.0",
"koa-bodyparser": "^4.3.0",
"koa-mount": "^4.0.0",
"koa-multer": "^1.0.2",
"koa-router": "^9.1.0",
"koa-session": "^6.0.0",
"koa-static": "^5.0.0",
"koa-views": "^6.3.0",
"node-cron": "^2.0.3",
"pg": "^8.3.0",
"pug": "^3.0.1",
"reflect-metadata": "^0.1.10",
"rndstr": "^1.0.0",
"sass": "^1.26.10",
"typeorm": "0.2.25",
"typescript": "^3.9.7",
"uuid": "^8.3.0"
},
"devDependencies": {
"@types/axios": "^0.14.0",
"@types/koa": "^2.11.3",
"@types/koa-router": "^7.4.1",
"@types/koa-session": "^5.10.2",
"@types/koa-views": "^2.0.4",
"@types/node": "^8.0.29",
"@typescript-eslint/eslint-plugin": "^3.7.0",
"@typescript-eslint/parser": "^3.7.0",
"copyfiles": "^2.3.0",
"eslint": "^7.5.0",
"eslint-config-prettier": "^6.11.0",
"eslint-plugin-prettier": "^3.1.4",
"nodemon": "^2.0.4",
"npm-run-all": "^4.1.5",
"prettier": "^2.0.5",
"rimraf": "^3.0.2",
"ts-node": "3.3.0"
}
"name": "misskey-tools",
"version": "2.0.0",
"description": "",
"main": "built/app.js",
"author": "Xeltica",
"private": true,
"scripts": {
"build": "run-p build:*",
"build:frontend": "webpack",
"build:backend": "run-p build:backend-source build:views build:styles",
"build:backend-source": "tsc",
"build:views": "copyfiles -u 1 src/backend/views/*.pug ./built/",
"build:styles": "sass styles/:built/assets",
"start": "node built/app.js",
"dev": "run-p dev:*",
"dev:backend": "nodemon",
"dev:frontend": "webpack --watch",
"clean": "rimraf built",
"tsc": "tsc",
"lint": "eslint --ext .ts,.tsx src",
"lint:fix": "eslint --fix --ext .ts,.tsx src",
"migrate": "ts-node --project ./tsconfig.migration.json ./node_modules/typeorm/cli.js migration:run",
"migrate:revert": "ts-node --project ./tsconfig.migration.json ./node_modules/typeorm/cli.js migration:revert"
},
"dependencies": {
"@babel/preset-react": "^7.14.5",
"@reduxjs/toolkit": "^1.6.1",
"@types/insert-text-at-cursor": "^0.3.0",
"@types/koa-bodyparser": "^4.3.0",
"@types/koa-multer": "^1.0.0",
"@types/koa-send": "^4.1.3",
"@types/ms": "^0.7.31",
"@types/node-cron": "^2.0.3",
"@types/object.pick": "^1.3.1",
"@types/react": "^17.0.19",
"@types/react-dom": "^17.0.9",
"@types/react-router-dom": "^5.1.8",
"@types/styled-components": "^5.1.13",
"@types/uuid": "^8.0.0",
"axios": "^0.19.2",
"class-transformer": "^0.4.0",
"class-validator": "^0.13.1",
"css-loader": "^6.2.0",
"dayjs": "^1.10.7",
"delay": "^4.4.0",
"fibers": "^5.0.0",
"i18next": "^20.6.1",
"i18next-browser-languagedetector": "^6.1.2",
"insert-text-at-cursor": "^0.3.0",
"json5-loader": "^4.0.1",
"koa": "^2.13.0",
"koa-bodyparser": "^4.3.0",
"koa-multer": "^1.0.2",
"koa-router": "^9.1.0",
"koa-send": "^5.0.1",
"koa-session": "^6.0.0",
"koa-views": "^6.3.0",
"misskey-js": "^0.0.6",
"ms": "^2.1.3",
"node-cron": "^2.0.3",
"object.pick": "^1.3.0",
"pg": "^8.3.0",
"pug": "^3.0.0",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-i18next": "^11.12.0",
"react-modal-hook": "^3.0.0",
"react-redux": "^7.2.4",
"react-router-dom": "^5.2.1",
"reflect-metadata": "^0.1.13",
"rndstr": "^1.0.0",
"routing-controllers": "^0.9.0",
"sass": "^1.38.2",
"sass-loader": "^12.1.0",
"style-loader": "^3.2.1",
"styled-components": "^5.3.1",
"ts-loader": "^9.2.5",
"tsc-alias": "^1.3.9",
"tsconfig-paths-webpack-plugin": "^3.5.1",
"typeorm": "0.2.25",
"typescript": "^4.4.2",
"uuid": "^8.3.0",
"webpack": "^5.51.1",
"webpack-cli": "^4.8.0",
"xeltica-ui": "xeltica/ui"
},
"devDependencies": {
"@types/axios": "^0.14.0",
"@types/koa": "^2.11.3",
"@types/koa-router": "^7.4.1",
"@types/koa-session": "^5.10.2",
"@types/koa-views": "^2.0.4",
"@types/node": "^8.0.29",
"@typescript-eslint/eslint-plugin": "^4.30.0",
"@typescript-eslint/parser": "^4.30.0",
"copyfiles": "^2.3.0",
"eslint": "^7.32.0",
"eslint-config-prettier": "^6.11.0",
"eslint-plugin-prettier": "^3.1.4",
"nodemon": "^2.0.4",
"npm-run-all": "^4.1.5",
"prettier": "^2.0.5",
"rimraf": "^3.0.2",
"ts-node": "3.3.0"
}
}

View File

@ -1,8 +1,8 @@
import { initDb } from './services/db';
import { initDb } from './backend/services/db';
import 'reflect-metadata';
(async () => {
await initDb();
(await import('./services/worker')).default();
(await import('./server/server')).default();
})();
(await import('./backend/services/worker')).default();
(await import('./backend/server')).default();
})();

9
src/backend/const.ts Normal file
View File

@ -0,0 +1,9 @@
export default {
version: '2.0.0',
changelog: [
'インスタンスの接続エラーにより後続処理が行えなくなる重大な不具合を修正',
'全員分の算出が終わるまで、ランキングを非表示に',
],
};
export const defaultTemplate = '昨日のMisskeyの活動は\n\nート: {notesCount}({notesDelta})\nフォロー : {followingCount}({followingDelta})\nフォロワー :{followersCount}({followersDelta})\n\nでした。\n{url}';

View File

@ -0,0 +1,18 @@
/**
* API
* @author Xeltica
*/
import { Get, JsonController } from 'routing-controllers';
import { config } from '../../config';
@JsonController('/admin')
export class AdminController {
@Get() getAdmin() {
const { username, host } = config.admin;
return {
username, host,
acct: `@${username}@${host}`,
};
}
}

View File

@ -0,0 +1,104 @@
/**
* API
* @author Xeltica
*/
import { BadRequestError, Body, CurrentUser, Delete, Get, JsonController, NotFoundError, OnUndefined, Param, Post, Put } from 'routing-controllers';
import { IUser } from '../../common/types/user';
import { Announcements } from '../models';
import { AnnounceCreate } from './body/announce-create';
import { AnnounceUpdate } from './body/announce-update';
import { IdProp } from './body/id-prop';
@JsonController('/announcements')
export class AdminController {
@Get() get() {
const query = Announcements.createQueryBuilder('announcement')
.orderBy('"announcement"."createdAt"', 'DESC');
return query.getMany();
}
@OnUndefined(204)
@Post() async post(@CurrentUser({ required: true }) user: IUser, @Body({required: true}) {title, body}: AnnounceCreate) {
if (!user.isAdmin) {
throw new BadRequestError('Not an Admin');
}
if (!title || !body) {
throw new BadRequestError();
}
await Announcements.insert({
createdAt: new Date(),
title,
body,
});
}
@OnUndefined(204)
@Put() async update(@CurrentUser({ required: true }) user: IUser, @Body() {id, title, body}: AnnounceUpdate) {
if (!user.isAdmin) {
throw new BadRequestError('Not an Admin');
}
if (!id || !title || !body) {
throw new BadRequestError();
}
if (!(await Announcements.findOne(id))) {
throw new NotFoundError();
}
await Announcements.update(id, {
title,
body,
});
}
@OnUndefined(204)
@Post('/like/:id') async like(@CurrentUser({ required: true }) user: IUser, @Param('id') id: string) {
if (!user.isAdmin) {
throw new BadRequestError('Not an Admin');
}
const idNumber = Number(id);
if (isNaN(idNumber)) {
throw new NotFoundError();
}
if (!id) {
throw new BadRequestError();
}
const announcement = await Announcements.findOne(Number(idNumber));
if (!announcement) {
throw new NotFoundError();
}
await Announcements.update(id, {
like: announcement.like + 1,
});
return announcement.like + 1;
}
@Delete() async delete(@CurrentUser({ required: true }) user: IUser, @Body() {id}: IdProp) {
if (!user.isAdmin) {
throw new BadRequestError('Not an Admin');
}
if (!id) {
throw new BadRequestError();
}
await Announcements.delete(id);
}
@Get('/:id') async getDetail(@Param('id') id: string) {
const idNumber = Number(id);
if (isNaN(idNumber)) {
throw new NotFoundError();
}
const announcement = await Announcements.findOne(idNumber);
if (!announcement) {
throw new NotFoundError();
}
return announcement;
}
}

View File

@ -0,0 +1,4 @@
export class AnnounceCreate {
title: string;
body: string;
}

View File

@ -0,0 +1,5 @@
export class AnnounceUpdate {
id: number;
title: string;
body: string;
}

View File

@ -0,0 +1,3 @@
export class IdProp {
id: number;
}

View File

@ -0,0 +1,22 @@
import { IsIn, IsOptional } from 'class-validator';
import { AlertMode, alertModes } from '../../../common/types/alert-mode';
import { visibilities, Visibility } from '../../../common/types/visibility';
export class UserSetting {
@IsIn(alertModes)
@IsOptional()
alertMode?: AlertMode;
@IsIn(visibilities)
@IsOptional()
visibility?: Visibility;
@IsOptional()
localOnly?: boolean;
@IsOptional()
remoteFollowersOnly?: boolean;
@IsOptional()
template?: string;
}

View File

@ -0,0 +1,15 @@
/**
* API
* @author Xeltica
*/
import { Get, JsonController } from 'routing-controllers';
@JsonController('/meta')
export class MetaController {
@Get() get() {
return {
honi: 'ほに',
};
}
}

View File

@ -0,0 +1,37 @@
/**
* API
* @author Xeltica
*/
import { Get, JsonController, QueryParam } from 'routing-controllers';
import { getRanking } from '../functions/ranking';
import { getUserCount } from '../functions/users';
import { getState } from '../store';
@JsonController('/ranking')
export class RankingController {
@Get()
async get(@QueryParam('limit', { required: false }) limit?: string) {
return this.getResponse(getState().nowCalculating, limit ? Number(limit) : undefined);
}
/**
* DBに問い合わせてランキングを取得する
* @param isCalculating
* @param limit
* @returns
*/
private async getResponse(isCalculating: boolean, limit?: number) {
const ranking = isCalculating ? [] : (await getRanking(limit)).map((u) => ({
id: u.id,
username: u.username,
host: u.host,
rating: u.rating,
}));
return {
isCalculating,
userCount: await getUserCount(),
ranking,
};
}
}

View File

@ -0,0 +1,48 @@
/**
* API
* @author Xeltica
*/
import { Body, CurrentUser, Delete, Get, JsonController, OnUndefined, Post, Put } from 'routing-controllers';
import { DeepPartial } from 'typeorm';
import { getScores } from '../functions/get-scores';
import { deleteUser, updateUser } from '../functions/users';
import { User } from '../models/entities/user';
import { sendAlert } from '../services/send-alert';
import { UserSetting } from './body/user-setting';
@JsonController('/session')
export class SessionController {
@Get() get(@CurrentUser({ required: true }) user: User) {
return user;
}
@Get('/score')
async getScore(@CurrentUser({ required: true }) user: User) {
return getScores(user);
}
@OnUndefined(204)
@Put() async updateSetting(@CurrentUser({ required: true }) user: User, @Body() setting: UserSetting) {
const s: DeepPartial<User> = {};
if (setting.alertMode != null) s.alertMode = setting.alertMode;
if (setting.visibility != null) s.visibility = setting.visibility;
if (setting.localOnly != null) s.localOnly = setting.localOnly;
if (setting.remoteFollowersOnly != null) s.remoteFollowersOnly = setting.remoteFollowersOnly;
if (setting.template !== undefined) s.template = setting.template;
if (Object.keys(s).length === 0) return;
await updateUser(user.username, user.host, s);
}
@OnUndefined(204)
@Post('/alert') async testAlert(@CurrentUser({ required: true }) user: User) {
await sendAlert(user);
}
@OnUndefined(204)
@Delete() async delete(@CurrentUser({ required: true }) user: User) {
await deleteUser(user.username, user.host);
}
}

7
src/backend/die.ts Normal file
View File

@ -0,0 +1,7 @@
import { Context } from 'koa';
import { ErrorCode } from '../common/types/error-code';
export const die = (ctx: Context, error: ErrorCode = 'other', status = 400): Promise<void> => {
ctx.status = status;
return ctx.render('frontend', { error });
};

View File

@ -1,7 +1,10 @@
import rndstr from 'rndstr';
import { UsedToken } from '../models/entities/usedToken';
import { UsedToken } from '../models/entities/used-token';
import { UsedTokens } from '../models';
/**
*
*/
export const genToken = async (): Promise<string> => {
let used: UsedToken | undefined = undefined;
let token: string;
@ -10,4 +13,4 @@ export const genToken = async (): Promise<string> => {
used = await UsedTokens.findOne({ token });
} while (used !== undefined);
return token;
};
};

View File

@ -1,9 +1,15 @@
import { User } from '../models/entities/user';
import { Score } from '../types/Score';
import { Score } from '../../common/types/score';
import { api } from '../services/misskey';
import { toSignedString } from './to-signed-string';
import { toSignedString } from '../../common/functions/to-signed-string';
/**
*
* @param user
* @returns
*/
export const getScores = async (user: User): Promise<Score> => {
// TODO 毎回取ってくるのも微妙なので、ある程度キャッシュしたいかも
const miUser = await api<Record<string, number>>(user.host, 'users/show', { username: user.username }, user.token);
if (miUser.error) {
throw miUser.error;
@ -16,4 +22,4 @@ export const getScores = async (user: User): Promise<Score> => {
followingDelta: toSignedString(miUser.followingCount - user.prevFollowingCount),
followersDelta: toSignedString(miUser.followersCount - user.prevFollowersCount),
};
};
};

View File

@ -1,14 +1,19 @@
import { Users } from '../models';
import { User } from '../models/entities/user';
/**
*
* @param limit
* @returns
*/
export const getRanking = async (limit: number | null = 10): Promise<User[]> => {
const query = Users.createQueryBuilder('user')
.where('"user"."bannedFromRanking" IS NOT TRUE')
.orderBy('"user".rating', 'DESC');
if (limit !== null) {
query.limit(limit);
}
return await query.getMany();
};
};

View File

@ -4,6 +4,11 @@ import { User } from '../models/entities/user';
import { updateUser } from './users';
import { MiUser } from './update-score';
/**
*
* @param user
* @param miUser Misskeyのユーザー
*/
export const updateRating = async (user: User, miUser: MiUser): Promise<void> => {
const elapsedDays = dayjs().diff(dayjs(miUser.createdAt), 'd') + 1;
await updateUser(user.username, user.host, {

View File

@ -1,6 +1,9 @@
import { User } from '../models/entities/user';
import { updateUser } from './users';
/**
* Misskeyのユーザーモデル
*/
export type MiUser = {
notesCount: number,
followingCount: number,
@ -8,10 +11,15 @@ export type MiUser = {
createdAt: string,
};
export const updateScore = async (user: User, miUser: MiUser): Promise<void> => {
/**
*
* @param user
* @param miUser Misskeyのユーザー
*/
export const updateScore = async (user: User, miUser: MiUser): Promise<void> => {
await updateUser(user.username, user.host, {
prevNotesCount: miUser.notesCount ?? 0,
prevFollowingCount: miUser.followingCount ?? 0,
prevFollowersCount: miUser.followersCount ?? 0,
});
};
};

View File

@ -0,0 +1,95 @@
import { User } from '../models/entities/user';
import { Users } from '../models';
import { DeepPartial } from 'typeorm';
import { genToken } from './gen-token';
import { IUser } from '../../common/types/user';
import { config } from '../../config';
/**
* IUser
*/
const packUser = (user: User | undefined): IUser | undefined => {
if (!user) return undefined;
const { username: adminName, host: adminHost } = config.admin;
return {
...user,
isAdmin: adminName === user.username && adminHost === user.host,
};
};
/**
*
* @param username
* @param host
* @returns
*/
export const getUser = (username: string, host: string): Promise<IUser | undefined> => {
return Users.findOne({ username, host }).then(packUser);
};
/**
*
* @param user
* @returns
*/
export const updateUsersToolsToken = async (user: User | User['id']): Promise<string> => {
const u = typeof user === 'number'
? user
: user.id;
const misshaiToken = await genToken();
Users.update(u, { misshaiToken });
return misshaiToken;
};
/**
*
* @param token
* @returns
*/
export const getUserByToolsToken = (token: string): Promise<IUser | undefined> => {
return Users.findOne({ misshaiToken: token }).then(packUser);
};
/**
*
* @param username
* @param host
* @param token
*/
export const upsertUser = async (username: string, host: string, token: string): Promise<void> => {
const u = await getUser(username, host);
if (u) {
await Users.update(u.id, { token });
} else {
await Users.insert({ username, host, token });
}
};
/**
*
* @param username
* @param host
* @param record
*/
export const updateUser = async (username: string, host: string, record: DeepPartial<User>): Promise<void> => {
await Users.update({ username, host }, record);
};
/**
*
* @param username
* @param host
*/
export const deleteUser = async (username: string, host: string): Promise<void> => {
await Users.delete({ username, host });
};
/**
*
* @returns
*/
export const getUserCount = (): Promise<number> => {
return Users.count();
};

View File

@ -0,0 +1,31 @@
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
import { IAnnouncement } from '../../../common/types/announcement';
@Entity()
export class Announcement implements IAnnouncement {
@PrimaryGeneratedColumn()
public id: number;
@Column({
type: 'timestamp without time zone',
})
public createdAt: Date;
@Column({
type: 'varchar',
length: 128,
})
public title: string;
@Column({
type: 'varchar',
length: 8192,
})
public body: string;
@Column({
type: 'integer',
default: 0,
})
public like: number;
}

View File

@ -1,10 +1,11 @@
import { Entity, Column, PrimaryGeneratedColumn, Index } from 'typeorm';
import { AlertMode, alertModes } from '../../types/AlertMode';
import { visibilities, Visibility } from '../../types/Visibility';
import { AlertMode, alertModes } from '../../../common/types/alert-mode';
import { visibilities, Visibility } from '../../../common/types/visibility';
import { IUser } from '../../../common/types/user';
@Entity()
@Index([ 'username', 'host' ], { unique: true })
export class User {
@Index(['username', 'host'], { unique: true })
export class User implements IUser {
@PrimaryGeneratedColumn()
public id: number;
@ -97,4 +98,4 @@ export class User {
default: false,
})
public bannedFromRanking: boolean;
}
}

View File

@ -0,0 +1,8 @@
import { User } from './entities/user';
import { UsedToken } from './entities/used-token';
import { getRepository } from 'typeorm';
import { Announcement } from './entities/announcement';
export const Users = getRepository(User);
export const UsedTokens = getRepository(UsedToken);
export const Announcements = getRepository(Announcement);

9
src/backend/render.ts Normal file
View File

@ -0,0 +1,9 @@
import views from 'koa-views';
import constant from './const';
export const render = views(__dirname + '/views', {
extension: 'pug', options: {
...constant,
}
});

164
src/backend/router.ts Normal file
View File

@ -0,0 +1,164 @@
import { Context, DefaultState } from 'koa';
import Router from 'koa-router';
import axios from 'axios';
import crypto from 'crypto';
import koaSend from 'koa-send';
import { v4 as uuid } from 'uuid';
import ms from 'ms';
import { config } from '../config';
import { upsertUser, getUser, updateUser, updateUsersToolsToken } from './functions/users';
import { api } from './services/misskey';
import { die } from './die';
export const router = new Router<DefaultState, Context>();
const sessionHostCache: Record<string, string> = {};
const tokenSecretCache: Record<string, string> = {};
router.get('/login', async ctx => {
let host = ctx.query.host as string | undefined;
if (!host) {
await die(ctx, 'invalidParamater');
return;
}
const meta = await api<{ name: string, uri: string, version: string, features: Record<string, boolean | undefined> }>(host, 'meta', {});
if (typeof meta !== 'object') {
await die(ctx, 'other');
return;
}
if (meta.version.includes('hitori')) {
await die(ctx, 'hitorisskeyIsDenied');
return;
}
// ホスト名の正規化
host = meta.uri.replace(/^https?:\/\//, '');
const name = 'みす廃あらーと';
const description = 'ついついノートしすぎていませんか?';
const permission = ['write:notes', 'write:notifications'];
if (meta.features.miauth) {
// MiAuthを使用する
const callback = encodeURI(`${config.url}/miauth`);
const session = uuid();
const url = `https://${host}/miauth/${session}?name=${encodeURI(name)}&callback=${encodeURI(callback)}&permission=${encodeURI(permission.join(','))}`;
sessionHostCache[session] = host;
ctx.redirect(url);
} else {
// 旧型認証を使用する
const callbackUrl = encodeURI(`${config.url}/legacy-auth`);
const { secret } = await api<{ secret: string }>(host, 'app/create', {
name, description, permission, callbackUrl,
});
const { token, url } = await api<{ token: string, url: string }>(host, 'auth/session/generate', {
appSecret: secret
});
sessionHostCache[token] = host;
tokenSecretCache[token] = secret;
ctx.redirect(url);
}
});
router.get('/teapot', async ctx => {
await die(ctx, 'teapot', 418);
});
router.get('/miauth', async ctx => {
const session = ctx.query.session as string | undefined;
if (!session) {
await die(ctx, 'sessionRequired');
return;
}
const host = sessionHostCache[session];
delete sessionHostCache[session];
if (!host) {
await die(ctx);
return;
}
const url = `https://${host}/api/miauth/${session}/check`;
const { token, user } = (await axios.post(url)).data;
if (!token || !user) {
await die(ctx);
return;
}
await login(ctx, user, host, token);
});
router.get('/legacy-auth', async ctx => {
const token = ctx.query.token as string | undefined;
if (!token) {
await die(ctx, 'tokenRequired');
return;
}
const host = sessionHostCache[token];
delete sessionHostCache[token];
if (!host) {
await die(ctx);
return;
}
const appSecret = tokenSecretCache[token];
delete tokenSecretCache[token];
if (!appSecret) {
await die(ctx);
return;
}
const { accessToken, user } = await api<{ accessToken: string, user: Record<string, unknown> }>(host, 'auth/session/userkey', {
appSecret, token,
});
const i = crypto.createHash('sha256').update(accessToken + appSecret, 'utf8').digest('hex');
await login(ctx, user, host, i);
});
router.get('/assets/(.*)', async ctx => {
await koaSend(ctx as any, ctx.path.replace('/assets/', ''), {
root: `${__dirname}/../assets/`,
maxage: process.env.NODE_ENV !== 'production' ? 0 : ms('7 days'),
});
});
router.get('/api(.*)', async (ctx, next) => {
next();
});
router.get('(.*)', async (ctx) => {
await ctx.render('frontend');
});
async function login(ctx: Context, user: Record<string, unknown>, host: string, token: string) {
const isNewcomer = !(await getUser(user.username as string, host));
await upsertUser(user.username as string, host, token);
const u = await getUser(user.username as string, host);
if (!u) {
await die(ctx);
return;
}
if (isNewcomer) {
await updateUser(u.username, u.host, {
prevNotesCount: user.notesCount as number ?? 0,
prevFollowingCount: user.followingCount as number ?? 0,
prevFollowersCount: user.followersCount as number ?? 0,
});
}
const toolsToken = await updateUsersToolsToken(u);
await ctx.render('frontend', { token: toolsToken });
}

45
src/backend/server.ts Normal file
View File

@ -0,0 +1,45 @@
import Koa from 'koa';
import bodyParser from 'koa-bodyparser';
import { Action, useKoaServer } from 'routing-controllers';
import constant from './const';
import { config } from '../config';
import { render } from './render';
import { router } from './router';
import { getUserByToolsToken } from './functions/users';
import 'reflect-metadata';
export default (): void => {
const app = new Koa();
console.log('Misskey Tools v' + constant.version);
console.log('Initializing DB connection...');
app.use(render);
app.use(bodyParser());
useKoaServer(app, {
controllers: [__dirname + '/controllers/**/*{.ts,.js}'],
routePrefix: '/api/v1',
classTransformer: true,
validation: true,
currentUserChecker: async ({ request }: Action) => {
const { authorization } = request.header;
if (!authorization || !authorization.startsWith('Bearer ')) return null;
const token = authorization.split(' ')[1].trim();
const user = await getUserByToolsToken(token);
return user;
},
});
app.use(router.routes());
app.use(router.allowedMethods());
console.log(`listening port ${config.port}...`);
console.log('App launched!');
app.listen(config.port || 3000);
};

View File

@ -1,14 +1,22 @@
import { getConnection, createConnection, Connection } from 'typeorm';
import { config } from '../config';
import { config } from '../../config';
import { User } from '../models/entities/user';
import { UsedToken } from '../models/entities/usedToken';
import { UsedToken } from '../models/entities/used-token';
import { Announcement } from '../models/entities/announcement';
export const entities = [
User,
UsedToken,
Announcement,
];
/**
*
* @param force
* @returns DBコネクション
*/
export const initDb = async (force = false): Promise<Connection> => {
// forceがtrueでない限り、既に接続が存在する場合はそれを返す
if (!force) {
try {
const conn = getConnection();
@ -19,6 +27,7 @@ export const initDb = async (force = false): Promise<Connection> => {
}
}
// 接続がないか、forceがtrueの場合は新規作成する
return createConnection({
type: 'postgres',
host: config.db.host,
@ -29,4 +38,4 @@ export const initDb = async (force = false): Promise<Connection> => {
extra: config.db.extra,
entities,
});
};
};

View File

@ -1,12 +1,14 @@
import axios from 'axios';
import _const from '../const';
export const ua = `Mozilla/5.0 misshaialertBot/${_const.version} +https://github.com/Xeltica/misshaialert Node/${process.version}`;
export const ua = `Mozilla/5.0 MisskeyTools/${_const.version} +https://github.com/Xeltica/MisskeyTools Node/${process.version}`;
axios.defaults.headers['User-Agent'] = ua;
axios.defaults.validateStatus = (stat) => stat < 500;
/**
* Misskey APIを呼び出す
*/
export const api = <T = Record<string, unknown>>(host: string, endpoint: string, arg: Record<string, unknown>, i?: string): Promise<T> => {
const a = { ...arg };
if (i) {
@ -15,6 +17,12 @@ export const api = <T = Record<string, unknown>>(host: string, endpoint: string,
return axios.post<T>(`https://${host}/api/${endpoint}`, a).then(res => res.data);
};
/**
*
* @param host
* @param i
* @returns truefalse
*/
export const apiAvailable = async (host: string, i: string): Promise<boolean> => {
try {
const res = await api(host, 'i', {}, i);
@ -22,4 +30,4 @@ export const apiAvailable = async (host: string, i: string): Promise<boolean> =>
} catch {
return false;
}
};
};

View File

@ -0,0 +1,55 @@
import { User } from '../models/entities/user';
import { format } from '../../common/functions/format';
import { getScores } from '../functions/get-scores';
import { api } from './misskey';
/**
*
* @param user
*/
export const sendAlert = async (user: User) => {
const text = format(await getScores(user), user);
switch (user.alertMode) {
case 'note':
await sendNoteAlert(text, user);
break;
case 'notification':
await sendNotificationAlert(text, user);
break;
}
};
/**
*
* @param text
* @param user
*/
const sendNoteAlert = async (text: string, user: User) => {
const res = await api<Record<string, unknown>>(user.host, 'notes/create', {
text,
visibility: user.visibility,
localOnly: user.localOnly,
remoteFollowersOnly: user.remoteFollowersOnly,
}, user.token);
if (res.error) {
throw res.error || res;
}
};
/**
*
* @param text
* @param user
*/
const sendNotificationAlert = async (text: string, user: User) => {
const res = await api(user.host, 'notifications/create', {
header: 'みす廃あらーと',
icon: 'https://i.imgur.com/B991yTl.png',
body: text,
}, user.token);
if (res.error) {
throw res.error || res;
}
};

View File

@ -0,0 +1,64 @@
import cron from 'node-cron';
import delay from 'delay';
import { Not } from 'typeorm';
import { deleteUser } from '../functions/users';
import { MiUser, updateScore } from '../functions/update-score';
import { updateRating } from '../functions/update-rating';
import { AlertMode } from '../../common/types/alert-mode';
import { Users } from '../models';
import { sendAlert } from './send-alert';
import { api } from './misskey';
import * as Store from '../store';
import { User } from '../models/entities/user';
export default (): void => {
cron.schedule('0 0 0 * * *', async () => {
Store.dispatch({ nowCalculating: true });
const users = await Users.find({ alertMode: Not<AlertMode>('nothing') });
for (const user of users) {
await update(user).catch(e => handleError(user, e));
if (user.alertMode === 'note') {
return delay(3000);
}
}
Store.dispatch({ nowCalculating: false });
});
};
/**
*
* @param user
*/
const update = async (user: User) => {
const miUser = await api<MiUser & { error: unknown }>(user.host, 'users/show', { username: user.username }, user.token);
if (miUser.error) throw miUser.error;
await updateRating(user, miUser);
await sendAlert(user);
await updateScore(user, miUser);
};
/**
*
* @param user
* @param e ErrorだったりObjectだったりするのでanyだけど
*/
const handleError = async (user: User, e: any) => {
if (e.code) {
if (e.code === 'NO_SUCH_USER' || e.code === 'AUTHENTICATION_FAILED') {
// ユーザーが削除されている場合、レコードからも消してとりやめ
console.info(`${user.username}@${user.host} is deleted, so delete this user from the system`);
await deleteUser(user.username, user.host);
} else {
console.error(`Misskey Error: ${JSON.stringify(e)}`);
}
} else {
// おそらく通信エラー
console.error(`Unknown error: ${e.name} ${e.message}`);
}
};

View File

@ -2,21 +2,35 @@
// getStateを介してステートを取得し、dispatchによって更新する
// stateを直接編集できないようになっている
/**
*
*/
const defaultState: State = {
nowCalculating: false,
};
let _state: Readonly<State> = defaultState;
/**
*
*/
export type State = {
nowCalculating: boolean,
};
export const getState = () => Object.freeze({..._state});
/**
*
* @returns
*/
export const getState = () => Object.freeze({ ..._state });
/**
*
* @param mutation
*/
export const dispatch = (mutation: Partial<State>) => {
_state = {
..._state,
...mutation,
};
};
};

View File

@ -0,0 +1,48 @@
doctype html
html
head
meta(charset="UTF-8")
meta(name="viewport", content="width=device-width, initial-scale=1.0")
block meta
- const title = 'Misskey Tools'
- const desc = '✨Misskey での1日のート数、フォロー数、フォロワー数をカウントし、深夜0時にお知らせする便利サービスです。';
title= title
meta(name='description' content=desc)
meta(property='og:title' content=title)
meta(property='og:description' content=desc)
meta(property='og:type' content='website')
meta(name='twitter:card' content='summary')
meta(name='twitter:site' content='@Xeltica')
meta(name='twitter:creator' content='@Xeltica')
link(rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.5.0/font/bootstrap-icons.css")
style.
.loading {
display: flex;
position: fixed;
inset: 0;
background: #222;
color: #fff;
font-size: 16px;
align-items: center;
justify-content: center;
}
body
#app: .loading Loading...
if token
script.
const token = '#{token}';
const previousToken = localStorage.getItem('token');
const accounts = JSON.parse(localStorage.getItem('accounts') || '[]');
if (previousToken && !accounts.includes(previousToken)) {
accounts.push(previousToken);
}
localStorage.setItem('accounts', JSON.stringify(accounts));
localStorage.setItem('token', token);
history.replaceState(null, null, '/');
if error
script.
window.__misshaialert = { error: '#{error}' };
script(src=`/assets/fe.${version}.js` async defer)

View File

@ -1,67 +1,60 @@
import { config } from '../config';
import { User } from '../models/entities/user';
import { Score } from '../types/Score';
export const defaultTemplate = `昨日のMisskeyの活動は
: {notesCount}({notesDelta})
: {followingCount}({followingDelta})
:{followersCount}({followersDelta})
{url}`;
import { config } from '../../config';
import { Score } from '../types/score';
import { defaultTemplate } from '../../backend/const';
import { IUser } from '../types/user';
/**
*
*/
export type Variable = {
description?: string;
replace?: string | ((score: Score, user: User) => string);
replace?: string | ((score: Score, user: IUser) => string);
};
/**
*
*/
export const variables: Record<string, Variable> = {
notesCount: {
description: 'ノート数',
replace: (score) => String(score.notesCount),
},
followingCount: {
description: 'フォロー数',
replace: (score) => String(score.followingCount),
},
followersCount: {
description: 'フォロワー数',
replace: (score) => String(score.followersCount),
},
notesDelta: {
description: '昨日とのノート数の差',
replace: (score) => String(score.notesDelta),
},
followingDelta: {
description: '昨日とのフォロー数の差',
replace: (score) => String(score.followingDelta),
},
followersDelta: {
description: '昨日とのフォロワー数の差',
replace: (score) => String(score.followersDelta),
},
url: {
description: 'みす廃アラートのURL',
replace: config.url,
},
username: {
description: 'ユーザー名',
replace: (_, user) => String(user.username),
},
host: {
description: '所属するインスタンスのホスト名',
replace: (_, user) => String(user.host),
},
rating: {
description: 'みす廃レート',
replace: (_, user) => String(user.rating),
},
};
const variableRegex = /\{([a-zA-Z0-9_]+?)\}/g;
export const format = (score: Score, user: User): string => {
/**
*
* @param score
* @param user
* @returns
*/
export const format = (score: Score, user: IUser): string => {
const template = user.template || defaultTemplate;
return template.replace(variableRegex, (m, name) => {
const v = variables[name];

View File

@ -0,0 +1,6 @@
/**
*
* @param num
* @returns
*/
export const toSignedString = (num: number): string => num < 0 ? num.toString() : '+' + num;

View File

@ -4,4 +4,4 @@ export const alertModes = [
'nothing'
] as const;
export type AlertMode = typeof alertModes[number];
export type AlertMode = typeof alertModes[number];

View File

@ -0,0 +1,7 @@
export interface IAnnouncement {
id: number;
createdAt: Date;
title: string;
body: string;
like: number;
}

View File

@ -0,0 +1,11 @@
export const errorCodes = [
'hitorisskeyIsDenied',
'teapot',
'sessionRequired',
'tokenRequired',
'invalidParamater',
'notAuthorized',
'other',
] as const;
export type ErrorCode = typeof errorCodes[number];

View File

@ -1,9 +1,9 @@
export type Score = {
export interface Score {
notesCount: number;
followingCount: number;
followersCount: number;
notesDelta: string;
followingDelta: string;
followersDelta: string;
};
}

23
src/common/types/user.ts Normal file
View File

@ -0,0 +1,23 @@
import { AlertMode } from './alert-mode';
import { Visibility } from './visibility';
export interface IUser {
id: number;
username: string;
host: string;
token: string;
misshaiToken: string;
prevNotesCount: number;
prevFollowingCount: number;
prevFollowersCount: number;
alertMode: AlertMode;
visibility: Visibility;
localOnly: boolean;
remoteFollowersOnly: boolean;
template: string | null;
prevRating: number;
rating: number;
bannedFromRanking: boolean;
isAdmin?: boolean;
}

View File

@ -1,7 +0,0 @@
export default {
version: '1.5.1',
changelog: [
'インスタンスの接続エラーにより後続処理が行えなくなる重大な不具合を修正',
'全員分の算出が終わるまで、ランキングを非表示に',
],
};

85
src/frontend/App.tsx Normal file
View File

@ -0,0 +1,85 @@
import React from 'react';
import { BrowserRouter, Link, Route, Switch, useLocation } from 'react-router-dom';
import { Provider } from 'react-redux';
import { useTranslation } from 'react-i18next';
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import { IndexPage } from './pages';
import { RankingPage } from './pages/ranking';
import { Header } from './components/Header';
import { TermPage } from './pages/term';
import { store } from './store';
import { ModalComponent } from './Modal';
import { useTheme } from './misc/theme';
import { getBrowserLanguage, resources } from './langs';
import { LOCALSTORAGE_KEY_LANG } from './const';
import 'xeltica-ui/dist/css/xeltica-ui.min.css';
import './style.scss';
import { AnnouncementPage } from './pages/announcement';
document.body.classList.add('dark');
if (!localStorage[LOCALSTORAGE_KEY_LANG]) {
localStorage[LOCALSTORAGE_KEY_LANG] = getBrowserLanguage();
}
i18n
.use(initReactI18next)
.init({
resources,
lng: localStorage[LOCALSTORAGE_KEY_LANG],
interpolation: {
escapeValue: false // react already safes from xss
}
});
const AppInner : React.VFC = () => {
const $location = useLocation();
useTheme();
const {t} = useTranslation();
const error = (window as any).__misshaialert?.error;
return error ? (
<div className="container">
<Header hasTopLink />
<div className="xarticle">
<h1>{t('error')}</h1>
<p>{t('_error.sorry')}</p>
<p>
{t('_error.additionalInfo')}
{t(`_error.${error}`)}
</p>
<Link to="/" onClick={() => (window as any).__misshaialert.error = null}>{t('retry')}</Link>
</div>
</div>
) : (
<div className="container">
{$location.pathname !== '/' && <Header hasTopLink />}
<Switch>
<Route exact path="/" component={IndexPage} />
<Route exact path="/ranking" component={RankingPage} />
<Route exact path="/term" component={TermPage} />
<Route exact path="/announcements/:id" component={AnnouncementPage} />
</Switch>
<footer className="text-center pa-5">
<p>(C)2020-2021 Xeltica</p>
<p dangerouslySetInnerHTML={{__html: t('disclaimerForMisskeyHq')}} />
<p><Link to="/term">{t('termsOfService')}</Link></p>
</footer>
<ModalComponent />
</div>
);
};
export const App: React.VFC = () => (
<Provider store={store}>
<BrowserRouter>
<AppInner />
</BrowserRouter>
</Provider>
);

107
src/frontend/Modal.tsx Normal file
View File

@ -0,0 +1,107 @@
import React, { useCallback } from 'react';
import { useSelector } from './store';
import {
builtinDialogButtonNo,
builtinDialogButtonOk,
builtinDialogButtonYes,
DialogButton,
DialogButtonType,
DialogIcon,
ModalTypeDialog
} from './modal/dialog';
import { Modal } from './modal/modal';
import { useDispatch } from 'react-redux';
import { hideModal } from './store/slices/screen';
import { ModalTypeMenu } from './modal/menu';
const getButtons = (button: DialogButtonType): DialogButton[] => {
if (typeof button === 'object') return button;
switch (button) {
case 'ok': return [builtinDialogButtonOk];
case 'yesNo': return [builtinDialogButtonYes, builtinDialogButtonNo];
}
};
const dialogIconPattern: Record<DialogIcon, string> = {
error: 'bi bi-x-circle-fill text-danger',
info: 'bi bi-info-circle-fill text-primary',
question: 'bi bi-question-circle-fill text-primary',
warning: 'bi bi-exclamation-circle-fill text-warning',
};
const Dialog: React.VFC<{modal: ModalTypeDialog}> = ({modal}) => {
const buttons = getButtons(modal.buttons ?? 'ok');
const dispatch = useDispatch();
const onClickButton = useCallback((i: number) => {
dispatch(hideModal());
if (modal.onSelect) {
modal.onSelect(i);
}
}, [dispatch, modal]);
return (
<div className="card dialog text-center">
<div className="body">
{modal.icon && <div style={{fontSize: '2rem'}} className={dialogIconPattern[modal.icon]} />}
{modal.title && <h1>{modal.title}</h1>}
<p>{modal.message}</p>
<div className="hstack" style={{justifyContent: 'center'}}>
{
buttons.map((b, i) => (
<button className={`btn ${b.style}`} onClick={() => onClickButton(i)} key={i}>
{b.text}
</button>
))
}
</div>
</div>
</div>
);
};
const Menu: React.VFC<{modal: ModalTypeMenu}> = ({modal}) => {
const dispatch = useDispatch();
return (
<div className="modal-menu-wrapper menu shadow-2" style={{
transform: `translate(${modal.screenX}px, ${modal.screenY}px)`
}}>
{
modal.items.map((item, i) => (
<button className={`item ${item.disabled ? 'disabled' : ''} ${item.danger ? 'text-danger' : ''}`} onClick={() => {
dispatch(hideModal());
if (item.onClick) {
item.onClick();
}
}} key={i}>
{item.icon && <i className={item.icon} />}
{item.name}
</button>
))
}
</div>
);
};
const ModalInner = (modal: Modal) => {
switch (modal.type) {
case 'dialog': return <Dialog modal={modal} />;
case 'menu': return <Menu modal={modal} />;
}
};
export const ModalComponent: React.VFC = () => {
const shown = useSelector(state => state.screen.modalShown);
const modal = useSelector(state => state.screen.modal);
const dispatch = useDispatch();
if (!shown || !modal) return null;
return (
<div className={`modal fade ${modal.type === 'menu' ? 'top-left' : ''}`} onClick={() => dispatch(hideModal())}>
<div className="fade up" onClick={(e) => e.stopPropagation()}>
{ ModalInner(modal) }
</div>
</div>
);
};

View File

@ -0,0 +1,69 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
import { useDispatch } from 'react-redux';
import { LOCALSTORAGE_KEY_ACCOUNTS, LOCALSTORAGE_KEY_TOKEN } from '../const';
import { useGetSessionQuery } from '../services/session';
import { useSelector } from '../store';
import { setAccounts } from '../store/slices/screen';
import { LoginForm } from './LoginForm';
import { Skeleton } from './Skeleton';
export const AccountsPage: React.VFC = () => {
const {data} = useGetSessionQuery(undefined);
const {t} = useTranslation();
const dispatch = useDispatch();
const {accounts, accountTokens} = useSelector(state => state.screen);
const switchAccount = (token: string) => {
const newAccounts = accountTokens.filter(a => a !== token);
newAccounts.push(localStorage.getItem(LOCALSTORAGE_KEY_TOKEN) ?? '');
localStorage.setItem(LOCALSTORAGE_KEY_ACCOUNTS, JSON.stringify(newAccounts));
localStorage.setItem(LOCALSTORAGE_KEY_TOKEN, token);
location.reload();
};
return !data ? (
<div className="vstack">
<Skeleton />
<Skeleton />
<Skeleton />
</div>
) : (
<div className="fade vstack">
<div className="card">
<div className="body">
<h1>{t('_accounts.currentAccount')}</h1>
<p>@{data.username}@{data.host}</p>
</div>
</div>
<article className="card">
<div className="body">
<h1>{t('_accounts.switchAccount')}</h1>
<div className="menu large fluid mb-2">
{
accounts.length === accountTokens.length ? (
accounts.map(account => (
<button className="item fluid" style={{display: 'flex', flexDirection: 'row', alignItems: 'center'}} onClick={() => switchAccount(account.misshaiToken)}>
<i className="icon bi bi-chevron-right" />
@{account.username}@{account.host}
<button className="btn flat text-danger" style={{marginLeft: 'auto'}} onClick={e => {
const filteredAccounts = accounts.filter(ac => ac.id !== account.id);
dispatch(setAccounts(filteredAccounts));
e.stopPropagation();
}}>
<i className="bi bi-trash"/>
</button>
</button>
))
) : (
<div className="item">...</div>
)
}
</div>
<LoginForm />
</div>
</article>
</div>
);
};

View File

@ -0,0 +1,176 @@
import React, { useEffect, useState } from 'react';
import { LOCALSTORAGE_KEY_TOKEN } from '../const';
import { useGetSessionQuery } from '../services/session';
import { Skeleton } from './Skeleton';
import { IAnnouncement } from '../../common/types/announcement';
import { $delete, $get, $post, $put } from '../misc/api';
import { Card } from './Card';
export const AdminPage: React.VFC = () => {
const { data, error } = useGetSessionQuery(undefined);
const [announcements, setAnnouncements] = useState<IAnnouncement[]>([]);
const [selectedAnnouncement, selectAnnouncement] = useState<IAnnouncement | null>(null);
const [isAnnouncementsLoaded, setAnnouncementsLoaded] = useState(false);
const [isEditMode, setEditMode] = useState(false);
const [isDeleteMode, setDeleteMode] = useState(false);
const [draftTitle, setDraftTitle] = useState('');
const [draftBody, setDraftBody] = useState('');
const submitAnnouncement = async () => {
if (selectedAnnouncement) {
await $put('announcements', {
id: selectedAnnouncement.id,
title: draftTitle,
body: draftBody,
});
} else {
await $post('announcements', {
title: draftTitle,
body: draftBody,
});
}
selectAnnouncement(null);
setDraftTitle('');
setDraftBody('');
setEditMode(false);
fetchAll();
};
const deleteAnnouncement = ({id}: IAnnouncement) => {
$delete('announcements', {id}).then(() => {
fetchAll();
});
};
const fetchAll = () => {
setAnnouncements([]);
setAnnouncementsLoaded(false);
$get<IAnnouncement[]>('announcements').then(announcements => {
setAnnouncements(announcements ?? []);
setAnnouncementsLoaded(true);
});
};
/**
* Session APIのエラーハンドリング
* APIがエラーを返した =
*/
useEffect(() => {
if (error) {
console.error(error);
localStorage.removeItem(LOCALSTORAGE_KEY_TOKEN);
location.reload();
}
}, [error]);
/**
* Edit ModeがオンのときDelete Modeを無効化する
*/
useEffect(() => {
if (isEditMode) {
setDeleteMode(false);
}
}, [isEditMode]);
/**
*
*/
useEffect(() => {
fetchAll();
}, []);
useEffect(() => {
if (selectedAnnouncement) {
setDraftTitle(selectedAnnouncement.title);
setDraftBody(selectedAnnouncement.body);
} else {
setDraftTitle('');
setDraftBody('');
}
}, [selectedAnnouncement]);
return !data || !isAnnouncementsLoaded ? (
<div className="vstack">
<Skeleton width="100%" height="1rem" />
<Skeleton width="100%" height="1rem" />
<Skeleton width="100%" height="2rem" />
<Skeleton width="100%" height="160px" />
</div>
) : (
<div className="fade vstack">
{
!data.isAdmin ? (
<p>You are not an administrator and cannot open this page.</p>
) : (
<>
<article>
<h2>Announcements</h2>
{!isEditMode && (
<label className="input-switch mb-1">
<input type="checkbox" checked={isDeleteMode} onChange={e => setDeleteMode(e.target.checked)}/>
<div className="switch"></div>
<span>Delete Mode</span>
</label>
)}
<Card bodyClassName={isEditMode ? '' : 'px-0'}>
{ !isEditMode ? (
<>
{isDeleteMode && <div className="ml-2 text-danger">Click the item to delete.</div>}
<div className="large menu">
{announcements.map(a => (
<button className="item fluid" key={a.id} onClick={() => {
if (isDeleteMode) {
deleteAnnouncement(a);
} else {
selectAnnouncement(a);
setEditMode(true);
}
}}>
{isDeleteMode && <i className="icon bi bi-trash text-danger" />}
{a.title}
</button>
))}
{!isDeleteMode && (
<button className="item fluid" onClick={() => setEditMode(true)}>
<i className="icon bi bi-plus"/ >
Create New
</button>
)}
</div>
</>
) : (
<div className="vstack">
<label className="input-field">
Title
<input type="text" value={draftTitle} onChange={e => setDraftTitle(e.target.value)} />
</label>
<label className="input-field">
Body
<textarea className="input-field" value={draftBody} rows={10} onChange={e => setDraftBody(e.target.value)}/>
</label>
<div className="hstack" style={{justifyContent: 'flex-end'}}>
<button className="btn primary" onClick={submitAnnouncement} disabled={!draftTitle || !draftBody}>
Submit
</button>
<button className="btn" onClick={() => {
selectAnnouncement(null);
setEditMode(false);
}}>
Cancel
</button>
</div>
</div>
)}
</Card>
</article>
</>
)
}
</div>
);
};

View File

@ -0,0 +1,38 @@
import React, { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Link } from 'react-router-dom';
import { IAnnouncement } from '../../common/types/announcement';
import { $get } from '../misc/api';
import { Card } from './Card';
export const AnnouncementList: React.VFC = () => {
const [announcements, setAnnouncements] = useState<IAnnouncement[]>([]);
const {t} = useTranslation();
const fetchAllAnnouncements = () => {
setAnnouncements([]);
$get<IAnnouncement[]>('announcements').then(announcements => {
setAnnouncements(announcements ?? []);
});
};
useEffect(() => {
fetchAllAnnouncements();
}, []);
if (announcements.length === 0) return null;
return (
<Card>
<h1>{t('announcements')}</h1>
<div className="large menu fade">
{announcements.map(a => (
<Link className="item fluid" key={a.id} to={`/announcements/${a.id}`}>
{a.title}
</Link>
))}
</div>
</Card>
);
};

View File

@ -0,0 +1,16 @@
import React from 'react';
export type CardProps = {
className?: string;
bodyClassName?: string;
};
export const Card: React.FC<CardProps> = ({children, className, bodyClassName}) => {
return (
<div className={`card ${className}`}>
<div className={`body ${bodyClassName}`}>
{children}
</div>
</div>
);
};

View File

@ -0,0 +1,17 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
export const DeveloperInfo: React.VFC = () => {
const {t} = useTranslation();
return (
<>
<h1>{t('_developerInfo.title')}</h1>
<p>{t('_developerInfo.description')}</p>
<ul>
<li><a href="http://misskey.io/@ebi" target="_blank" rel="noopener noreferrer">@ebi@misskey.io</a></li>
<li><a href="http://groundpolis.app/@X" target="_blank" rel="noopener noreferrer">@X@groundpolis.app</a></li>
<li><a href="http://twitter.com/@adxlw" target="_blank" rel="noopener noreferrer">@adxlw@twitter.com</a></li>
</ul>
</>
);
};

View File

@ -0,0 +1,17 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
export type HashtagTimelineProps = {
hashtag: string;
};
export const HashtagTimeline: React.VFC<HashtagTimelineProps> = ({hashtag}) => {
const {t} = useTranslation();
return (
<>
<h1>{t('_timeline.title')}</h1>
<p>{t('_timeline.description', { hashtag })}</p>
<p>WIP</p>
</>
);
};

View File

@ -0,0 +1,25 @@
import React from 'react';
import { Link } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
export type HeaderProps = {
hasTopLink?: boolean;
};
const messageNumber = Math.floor(Math.random() * 6) + 1;
export const Header: React.FC<HeaderProps> = ({hasTopLink, children}) => {
const { t } = useTranslation();
return (
<header className={'xarticle card mt-5 mb-3'}>
<div className="body">
<h1 className="text-primary mb-0" style={{ fontSize: '2rem' }}>
{hasTopLink ? <Link to="/">{t('title')}</Link> : t('title')}
</h1>
<h2 className="text-dimmed ml-1">{t(`_welcomeMessage.pattern${messageNumber}`)}</h2>
{children}
</div>
</header>
);
};

View File

@ -0,0 +1,32 @@
import React, { useState } from 'react';
import { useTranslation } from 'react-i18next';
export const LoginForm: React.VFC = () => {
const [host, setHost] = useState('');
const {t} = useTranslation();
return (
<nav>
<div>
<strong>{t('instanceUrl')}</strong>
</div>
<div className="hgroup login-form">
<input
className="input-field"
type="text"
value={host}
onChange={(e) => setHost(e.target.value)}
required
/>
<button
className={!host ? 'btn' : 'btn primary'}
style={{ width: 128 }}
disabled={!host}
onClick={() => location.href = `//${location.host}/login?host=${encodeURIComponent(host)}`}
>
{t('login')}
</button>
</div>
</nav>
);
};

View File

@ -0,0 +1,314 @@
import insertTextAtCursor from 'insert-text-at-cursor';
import React, { useCallback, useEffect, useReducer, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useDispatch } from 'react-redux';
import { alertModes } from '../../common/types/alert-mode';
import { IUser } from '../../common/types/user';
import { Visibility } from '../../common/types/visibility';
import { LOCALSTORAGE_KEY_TOKEN } from '../const';
import { $post, $put } from '../misc/api';
import { useGetScoreQuery, useGetSessionQuery } from '../services/session';
import { showModal } from '../store/slices/screen';
import { AnnouncementList } from './AnnouncementList';
import { Card } from './Card';
import { Ranking } from './Ranking';
import { Skeleton } from './Skeleton';
const variables = [
'notesCount',
'followingCount',
'followersCount',
'notesDelta',
'followingDelta',
'followersDelta',
'url',
'username',
'host',
'rating',
] as const;
type SettingDraftType = Partial<Pick<IUser,
| 'alertMode'
| 'visibility'
| 'localOnly'
| 'remoteFollowersOnly'
| 'template'
>>;
type DraftReducer = React.Reducer<SettingDraftType, Partial<SettingDraftType>>;
export const MisshaiPage: React.VFC = () => {
const dispatch = useDispatch();
const [limit, setLimit] = useState<number | undefined>(10);
const session = useGetSessionQuery(undefined);
const data = session.data;
const score = useGetScoreQuery(undefined);
const {t} = useTranslation();
const [draft, dispatchDraft] = useReducer<DraftReducer>((state, action) => {
return { ...state, ...action };
}, {
alertMode: data?.alertMode ?? 'note',
visibility: data?.visibility ?? 'public',
localOnly: data?.localOnly ?? false,
remoteFollowersOnly: data?.remoteFollowersOnly ?? false,
template: data?.template ?? null,
});
const templateTextarea = useRef<HTMLTextAreaElement>(null);
const availableVisibilities: Visibility[] = [
'public',
'home',
'followers'
];
const updateSetting = useCallback((obj: SettingDraftType) => {
const previousDraft = draft;
dispatchDraft(obj);
return $put('session', obj)
.catch(e => {
dispatch(showModal({
type: 'dialog',
icon: 'error',
message: t('error'),
}));
dispatchDraft(previousDraft);
});
}, [draft]);
const updateSettingWithDialog = useCallback((obj: SettingDraftType) => {
updateSetting(obj)
.then(() => dispatch(showModal({
type: 'dialog',
icon: 'info',
message: t('saved'),
})));
}, [updateSetting]);
useEffect(() => {
if (data) {
dispatchDraft({
alertMode: data.alertMode,
visibility: data.visibility,
localOnly: data.localOnly,
remoteFollowersOnly: data.remoteFollowersOnly,
template: data.template,
});
}
}, [data]);
const onClickInsertVariables = useCallback<React.MouseEventHandler>((e) => {
dispatch(showModal({
type: 'menu',
screenX: e.clientX,
screenY: e.clientY,
items: variables.map(key => ({
name: t('_template._variables.' + key),
onClick: () => {
if (templateTextarea.current) {
insertTextAtCursor(templateTextarea.current, `{${key}}`);
}
},
})),
}));
}, [dispatch, t, variables, templateTextarea.current]);
const onClickInsertVariablesHelp = useCallback(() => {
dispatch(showModal({
type: 'dialog',
icon: 'info',
message: t('_template.insertVariablesHelp'),
}));
}, [dispatch, t]);
const onClickSendAlert = useCallback(() => {
dispatch(showModal({
type: 'dialog',
title: t('_sendTest.title'),
message: t('_sendTest.message'),
icon: 'question',
buttons: [
{
text: t('_sendTest.yes'),
style: 'primary',
},
{
text: t('_sendTest.no'),
},
],
onSelect(i) {
if (i === 0) {
$post('session/alert').then(() => {
dispatch(showModal({
type: 'dialog',
message: t('_sendTest.success'),
icon: 'info',
}));
}).catch((e) => {
console.error(e);
dispatch(showModal({
type: 'dialog',
message: t('_sendTest.failure'),
icon: 'error',
}));
});
}
},
}));
}, [dispatch, t]);
/**
* Session APIのエラーハンドリング
* APIがエラーを返した =
*/
useEffect(() => {
if (session.error) {
console.error(session.error);
localStorage.removeItem(LOCALSTORAGE_KEY_TOKEN);
location.reload();
}
}, [session.error]);
const defaultTemplate = t('_template.default');
return session.isLoading || score.isLoading ? (
<div className="vstack">
<Skeleton width="100%" height="1rem" />
<Skeleton width="100%" height="1rem" />
<Skeleton width="100%" height="2rem" />
<Skeleton width="100%" height="160px" />
</div>
) : (
<div className="fade vstack">
{session.data && (
<section>
<p>{t('welcomeBack', {acct: `@${session.data.username}@${session.data.host}`})}</p>
<p>
<strong>
{t('_missHai.rating')}{': '}
</strong>
{session.data.rating}
</p>
</section>
)}
<AnnouncementList />
{score.data && (
<>
<section>
<h2>{t('_missHai.data')}</h2>
<table className="table fluid">
<thead>
<tr>
<th></th>
<th>{t('_missHai.dataScore')}</th>
<th>{t('_missHai.dataDelta')}</th>
</tr>
</thead>
<tbody>
<tr>
<td>{t('notes')}</td>
<td>{score.data.notesCount}</td>
<td>{score.data.notesDelta}</td>
</tr>
<tr>
<td>{t('following')}</td>
<td>{score.data.followingCount}</td>
<td>{score.data.followingDelta}</td>
</tr>
<tr>
<td>{t('followers')}</td>
<td>{score.data.followersCount}</td>
<td>{score.data.followersDelta}</td>
</tr>
</tbody>
</table>
</section>
<section>
<h2>{t('_missHai.ranking')}</h2>
<Ranking limit={limit} />
{limit && <button className="btn link" onClick={() => setLimit(undefined)}>{t('_missHai.showAll')}</button>}
</section>
<section className="vstack mt-2">
<Card bodyClassName="vstack">
<h1>{t('alertMode')}</h1>
<div>
{
alertModes.map((mode) => (
<label key={mode} className="input-check">
<input type="radio" checked={mode === draft.alertMode} onChange={() => {
updateSetting({ alertMode: mode });
}} />
<span>{t(`_alertMode.${mode}`)}</span>
</label>
))
}
</div>
{ draft.alertMode === 'notification' && (
<div className="alert bg-danger mt-2">
<i className="icon bi bi-exclamation-circle"></i>
{t('_alertMode.notificationWarning')}
</div>
)}
{ draft.alertMode === 'note' && (
<>
<h2>{t('visibility')}</h2>
<div>
{
availableVisibilities.map((visibility) => (
<label key={visibility} className="input-check">
<input type="radio" checked={visibility === draft.visibility} onChange={() => {
updateSetting({ visibility });
}} />
<span>{t(`_visibility.${visibility}`)}</span>
</label>
))
}
</div>
<label className="input-check mt-2">
<input type="checkbox" checked={draft.localOnly} onChange={(e) => {
updateSetting({ localOnly: e.target.checked });
}} />
<span>{t('localOnly')}</span>
</label>
</>
)}
</Card>
<Card bodyClassName="vstack">
<h1>{t('template')}</h1>
<p>{t('_template.description')}</p>
<div className="hstack dense">
<button className="btn" onClick={onClickInsertVariables}>
<i className="bi bi-braces" />&nbsp;
{t('_template.insertVariables')}
</button>
<button className="btn link text-info" onClick={onClickInsertVariablesHelp}>
<i className="bi bi-question-circle" />
</button>
</div>
<textarea ref={templateTextarea} className="input-field" value={draft.template ?? defaultTemplate} placeholder={defaultTemplate} style={{height: 228}} onChange={(e) => {
dispatchDraft({ template: e.target.value });
}} />
<small className="text-dimmed">{t('_template.description2')}</small>
<div className="hstack" style={{justifyContent: 'flex-end'}}>
<button className="btn danger" onClick={() => dispatchDraft({ template: null })}>{t('resetToDefault')}</button>
<button className="btn primary" onClick={() => {
updateSettingWithDialog({ template: draft.template === '' ? null : draft.template });
}}>{t('save')}</button>
</div>
</Card>
<Card bodyClassName="vstack">
<button className="btn block" onClick={onClickSendAlert} disabled={draft.alertMode === 'nothing'}>{t('sendAlert')}</button>
<p className="text-dimmed">{t(draft.alertMode === 'nothing' ? 'sendAlertDisabled' : 'sendAlertDescription')}</p>
</Card>
</section>
</>
)}
</div>
);
};

View File

@ -0,0 +1,77 @@
import React, { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { $get } from '../misc/api';
interface RankingResponse {
isCalculating: boolean;
userCount: number;
ranking: Ranking[];
}
interface Ranking {
id: number;
username: string;
host: string;
rating: number;
}
export type RankingProps = {
limit?: number;
};
export const Ranking: React.VFC<RankingProps> = ({limit}) => {
const [response, setResponse] = useState<RankingResponse | null>(null);
const [isFetching, setIsFetching] = useState(true);
const [isError, setIsError] = useState(false);
const {t} = useTranslation();
// APIコール
useEffect(() => {
setIsFetching(true);
$get<RankingResponse>(`ranking?limit=${limit ?? ''}`)
.then((result) => {
setResponse(result);
setIsFetching(false);
})
.catch(c => {
console.error(c);
setIsError(true);
});
}, [limit, setIsFetching, setIsError]);
return (
isFetching ? (
<p className="text-dimmed">{t('fetching')}</p>
) : isError ? (
<div className="alert bg-danger">{t('failedToFetch')}</div>
) : response ? (
<>
<aside>{t('registeredUsersCount')}: {response?.userCount}</aside>
{response.isCalculating ? (
<p>{t('isCalculating')}</p>
) : (
<table className="table mt-1 fluid">
<thead>
<tr>
<th>{t('_missHai.order')}</th>
<th>{t('name')}</th>
<th>{t('_missHai.rating')}</th>
</tr>
</thead>
<tbody>
{response.ranking.map((r, i) => (
<tr key={i}>
<td>{i + 1}</td>
<td>
{r.username}@{r.host}
</td>
<td>{r.rating}</td>
</tr>
))}
</tbody>
</table>
)}
</>
) : null
);
};

View File

@ -0,0 +1,14 @@
import React, { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Ranking } from './Ranking';
export const RankingPage: React.VFC = () => {
const [limit, setLimit] = useState<number | undefined>(10);
const {t} = useTranslation();
return (
<div className="fade">
<Ranking limit={limit} />
{limit && <button className="btn link" onClick={() => setLimit(undefined)}>{t('_missHai.showAll')}</button>}
</div>
);
};

View File

@ -0,0 +1,133 @@
import React, { useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { useDispatch } from 'react-redux';
import { useGetSessionQuery } from '../services/session';
import { Card } from './Card';
import { Theme, themes } from '../misc/theme';
import { LOCALSTORAGE_KEY_TOKEN } from '../const';
import { changeLang, changeTheme, showModal } from '../store/slices/screen';
import { useSelector } from '../store';
import { languageName } from '../langs';
import { $delete } from '../misc/api';
export const SettingPage: React.VFC = () => {
const session = useGetSessionQuery(undefined);
const dispatch = useDispatch();
const data = session.data;
const {t} = useTranslation();
const currentTheme = useSelector(state => state.screen.theme);
const currentLang = useSelector(state => state.screen.language);
const onClickLogout = useCallback(() => {
dispatch(showModal({
type: 'dialog',
title: t('_logout.title'),
message: t('_logout.message'),
icon: 'question',
buttons: [
{
text: t('_logout.yes'),
style: 'primary',
},
{
text: t('_logout.no'),
},
],
onSelect(i) {
if (i === 0) {
localStorage.removeItem(LOCALSTORAGE_KEY_TOKEN);
location.reload();
}
},
}));
}, [dispatch, t]);
const onClickDeleteAccount = useCallback(() => {
dispatch(showModal({
type: 'dialog',
title: t('_deactivate.title'),
message: t('_deactivate.message'),
icon: 'question',
buttons: [
{
text: t('_deactivate.yes'),
style: 'danger',
},
{
text: t('_deactivate.no'),
},
],
primaryClassName: 'danger',
onSelect(i) {
if (i === 0) {
$delete('session').then(() => {
dispatch(showModal({
type: 'dialog',
message: t('_deactivate.success'),
icon: 'info',
onSelect() {
location.reload();
}
}));
}).catch((e) => {
console.error(e);
dispatch(showModal({
type: 'dialog',
message: t('_deactivate.failure'),
icon: 'error',
}));
});
}
},
}));
}, [dispatch, t]);
return session.isLoading || !data ? (
<div className="skeleton" style={{width: '100%', height: '128px'}}></div>
) : (
<div className="vstack fade">
<Card bodyClassName="vstack">
<h1>{t('appearance')}</h1>
<h2>{t('theme')}</h2>
<div>
{
themes.map(theme => (
<label key={theme} className="input-check">
<input type="radio" value={theme} checked={theme === currentTheme} onChange={(e) => dispatch(changeTheme(e.target.value as Theme))} />
<span>{t(`_themes.${theme}`)}</span>
</label>
))
}
</div>
<h2>{t('language')}</h2>
<select name="currentLang" className="input-field" value={currentLang} onChange={(e) => {
dispatch(changeLang(e.target.value));
}}>
{
(Object.keys(languageName) as Array<keyof typeof languageName>).map(n => (
<option value={n} key={n}>{languageName[n]}</option>
))
}
</select>
<div className="alert bg-info mt-2">
<i className="icon bi bi-translate" />
{t('translatedByTheCommunity')}&nbsp;
<a href="https://crowdin.com/project/misskey-tools" target="_blank" rel="noopener noreferrer">{t('helpTranslation')}</a>
</div>
</Card>
<Card bodyClassName="vstack">
<button className="btn block" onClick={onClickLogout}>{t('logout')}</button>
<p className="text-dimmed">{t('logoutDescription')}</p>
</Card>
<Card bodyClassName="vstack">
<button className="btn danger block" onClick={onClickDeleteAccount}>{t('deleteAccount')}</button>
<p className="text-dimmed">{t('deleteAccountDescription')}</p>
</Card>
</div>
);
};

View File

@ -0,0 +1,12 @@
import React from 'react';
export type SkeletonProps = {
width?: string | number;
height?: string | number;
};
export const Skeleton: React.VFC<SkeletonProps> = (p) => {
return (
<div className="skeleton" style={{width: p.width, height: p.height}}></div>
);
};

View File

@ -0,0 +1,31 @@
import React from 'react';
export type TabItem = {
label: string;
key: string;
};
export type TabProps = {
items: TabItem[];
selected: string;
onSelect: (key: string) => void;
};
// タブコンポーネント
export const Tab: React.VFC<TabProps> = (props) => {
return (
<div className="tab">
{props.items.map((item) => {
return (
<button
key={item.key}
className={'item ' + (item.key === props.selected ? 'active' : '')}
onClick={() => props.onSelect(item.key)}
>
{item.label}
</button>
);
})}
</div>
);
};

6
src/frontend/const.ts Normal file
View File

@ -0,0 +1,6 @@
export const LOCALSTORAGE_KEY_TOKEN = 'token';
export const LOCALSTORAGE_KEY_THEME = 'theme';
export const LOCALSTORAGE_KEY_LANG = 'lang';
export const LOCALSTORAGE_KEY_ACCOUNTS = 'accounts';
export const API_ENDPOINT = `//${location.host}/api/v1/`;

11
src/frontend/init.tsx Normal file
View File

@ -0,0 +1,11 @@
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import relativeTime from 'dayjs/plugin/relativeTime';
import dayjs from 'dayjs';
import 'dayjs/locale/ja';
import { App } from './App';
dayjs.extend(relativeTime);
ReactDOM.render(<App/>, document.getElementById('app'));

5
src/frontend/json5.d.ts vendored Normal file
View File

@ -0,0 +1,5 @@
declare module '*.json5' {
const data: any;
export default data;
}

View File

@ -0,0 +1,161 @@
{
"title": "Misskey Tools",
"description1": "Misskeyは楽しいものです。気がついたら1日中入り浸っていることも多いでしょう。",
"description2": "さあ、今すぐMisskey Toolsをインストールして、あなたの活動を把握しよう。",
"notes": "ノート",
"following": "フォロー",
"followers": "フォロワー",
"welcomeBack": "おかえりなさい、{{acct}}さん。",
"alertMode": "アラート送信方法",
"visibility": "公開範囲",
"appearance": "表示設定",
"template": "テンプレート",
"sendAlert": "アラートをテスト送信する",
"sendAlertDescription": "現在の設定を用いて、アラート送信をテストします。",
"sendAlertDisabled": "アラート送信方法が「通知しない」のため、送信をテストすることはできません。",
"logout": "ログアウトする",
"logoutDescription": "ログアウトしても、アラートは送信されます。",
"deleteAccount": "アカウント連携を解除する",
"deleteAccountDescription": "Misskey Toolsのアカウントを削除します。これにより、Misskeyとの連携設定も解除されます。",
"instanceUrl": "インスタンスURL",
"login": "ログイン",
"localOnly": "ローカルのみ",
"remoteFollowersOnly": "リモートフォロワーとローカル",
"help": "ヘルプ",
"save": "保存",
"theme": "テーマ",
"language": "言語",
"fetching": "取得中……",
"failedToFetch": "取得に失敗しました",
"registeredUsersCount": "登録者数",
"isCalculating": "現在算出中です。後ほどご確認ください!",
"ok": "OK",
"yes": "はい",
"no": "いいえ",
"termsOfService": "利用規約",
"name": "名前",
"resetToDefault": "初期値に戻す",
"error": "エラー",
"retry": "やり直す",
"saved": "保存しました。",
"disclaimerForMisskeyHq": "Misskey Toolsは、Misskey HQの公式ツールでは<b>ありません</b>。",
"translatedByTheCommunity": "Misskey Toolsはボランティアによって翻訳されています。",
"helpTranslation": "翻訳に協力する",
"announcements": "お知らせ",
"_welcomeMessage": {
"pattern1": "ついついノートしすぎていませんか?",
"pattern2": "Misskey, しすぎていませんか?",
"pattern3": "今日、何ノート書いた?",
"pattern4": "10000 ノートは初心者、そう思っていませんか?",
"pattern5": "息するように Misskey、そんなあなたへ。",
"pattern6": "あなたは真の Misskey 廃人ですか?"
},
"_welcome": {
"title": "プロ仕様のツールキット",
"description": "Misskey Toolsでは、Misskeyのために設計された、Misskeyをより楽しめるツールを取り揃えています。",
"misshaiAlertTitle": "ミス廃アラート",
"misshaiAlertDescription": "Misskeyにのめり込んでいませんかミス廃アラートを使えば、毎日のMisskeyでの活動量を以下のように定期投稿できます。",
"misshaiRankingDescription": "ミス廃ランキングでは、Misskeyでの活動を数値化し、ランキング表示します。",
"nextFeaturesTitle": "今後も追加予定。",
"nextFeaturesDescription": "これだけではありません。今後もアップデートで様々な機能を追加します!"
},
"_nav": {
"misshai": "ミス廃",
"accounts": "アカウント",
"settings": "設定"
},
"_missHai": {
"ranking": "ミス廃ランキング",
"rankingDescription": "ユーザーの「みす廃レート」を算出し、高い順にランキング表示しています。",
"showAll": "全員分見る",
"data": "みす廃データ",
"dataBody": "内容",
"dataScore": "スコア",
"dataDelta": "前日比",
"rating": "レート",
"order": "順位",
"showRanking": "ランキングを見る"
},
"_accounts": {
"currentAccount": "現在ログインしているアカウント",
"switchAccount": "アカウント切り替え",
"useAnother": "他のアカウントで登録する"
},
"_developerInfo": {
"title": "開発者",
"description": "何か困ったことがあったら、以下のアカウントにメッセージを送ってください。"
},
"_timeline": {
"title": "タイムライン",
"description": "{{hashtag}} タグを含む最新ノートを表示します。"
},
"_alertMode": {
"note": "自動的にノートを投稿",
"notification": "Misskeyに通知(標準)",
"nothing": "通知しない",
"notificationWarning": "「Misskey に通知」オプションは古いMisskeyでは動作しません。"
},
"_visibility": {
"public": "パブリック",
"home": "ホーム",
"followers": "フォロワー",
"users": "ログインユーザー"
},
"_themes": {
"light": "ライトテーマ",
"dark": "ダークテーマ",
"system": "システム設定に準じる"
},
"_template": {
"description": "アラートの自動投稿をカスタマイズできます。",
"description2": "ハッシュタグ #misshaialert は、テンプレートに関わらず自動付与されます。",
"default": "昨日のMisskeyの活動は\n\nート: {notesCount}({notesDelta})\nフォロー : {followingCount}({followingDelta})\nフォロワー :{followersCount}({followersDelta})\n\nでした。\n{url}",
"insertVariables": "変数を挿入する",
"insertVariablesHelp": "{ } で囲われた文字列は変数と呼ばれ、特別な意味を持ちます。これを含めると、投稿時に自動的に値が埋め込まれます。",
"_variables": {
"notesCount": "ノート数",
"followingCount": "フォロー数",
"followersCount": "フォロワー数",
"notesDelta": "ノート数の前日比",
"followingDelta": "フォロー数の前日比",
"followersDelta": "フォロワー数の前日比",
"url": "本サイトのURL",
"username": "アカウントのユーザー名",
"host": "アカウントの所属ホスト名",
"rating": "レート"
}
},
"_error": {
"sorry": "問題が発生しました。お手数ですが、やり直してください。",
"additionalInfo": "追加情報: ",
"hitorisskeyIsDenied": "ひとりすきーは連携できません。",
"teapot": "I'm a teapot.",
"sessionRequired": "セッションがありません。",
"tokenRequired": "トークンがありません。",
"invalidParameter": "パラメータが不正です。",
"notAuthorized": "権限がありません。",
"other": "なし"
},
"_sendTest": {
"title": "アラートをテスト送信しますか?",
"message": "現在の設定でアラートを送信します。設定が保存済みであるかどうか、実行前に必ずご確認ください。",
"yes": "送信する",
"no": "キャンセル",
"success": "送信しました。",
"failure": "送信に失敗しました。"
},
"_logout": {
"title": "ログアウトしてもよろしいですか?",
"message": "ログアウトしても、アラート送信や、お使いのMisskeyアカウントのデータ収集といった機能は動作し続けます。Misskey Toolsの利用を停止したい場合は、「アカウント連携を解除する」ボタンを押下して下さい。",
"yes": "ログアウトする",
"no": "キャンセル"
},
"_deactivate": {
"title": "アカウント連携を解除しますか?",
"message": "収集されたデータや個人設定など、全てのデータが削除されます。この操作は取り消すことができません。",
"yes": "解除する",
"no": "キャンセル",
"success": "アカウントを解除しました。トップ画面に戻ります。",
"failure": "アカウントを解除できませんでした。"
}
}

View File

@ -0,0 +1,161 @@
{
"title": "Misskey Tools",
"description1": "Misskey هو شيء ممتع. عندما أدركت ذلك ، فقد استخدمت Misskey طوال اليوم.",
"description2": "دعنا نحصل على حساب Misskey Tools ونعرف نشاطك.",
"notes": "ملاحظات",
"following": "متابعة",
"followers": "المتابعون",
"welcomeBack": "مرحبا بعودتك، {{acct}}.",
"alertMode": "كيفية إرسال التنبيهات",
"visibility": "الوضوح",
"appearance": "مظهر",
"template": "نموذج",
"sendAlert": "اختبر تنبيهك",
"sendAlertDescription": "أرسل تنبيهك بالإعدادات الحالية للاختبار.",
"sendAlertDisabled": "لا يمكنك اختبار إرسال التنبيه لأن إعداد \"كيفية إرسال التنبيهات\" هو \"لا تفعل شيئًا\".",
"logout": "تسجيل خروج",
"logoutDescription": "إذا قمت بتسجيل الخروج ، فسيتم إرسال تنبيهاتك تلقائيًا.",
"deleteAccount": "تعطيل تكامل الحساب",
"deleteAccountDescription": "حذف حساب Misskey Tools الخاص بك. سيؤدي هذا إلى تعطيل التكامل مع Misskey.",
"instanceUrl": "Url المثيل",
"login": "تسجيل الدخول",
"localOnly": "محلي فقط",
"remoteFollowersOnly": "المتابعون عن بعد والمحليون فقط",
"help": "مساعدة",
"save": "حفظ",
"theme": "مظهر",
"language": "لغة",
"fetching": "جار الجلب……",
"failedToFetch": "فشل الجلب",
"registeredUsersCount": "المستخدمون",
"isCalculating": "يتم حسابه الآن. يرجى إعادة التحقق لاحقًا!",
"ok": "موافق",
"yes": "موافق",
"no": "لا",
"termsOfService": "شروط الخدمة",
"name": "اسم",
"resetToDefault": "إعادة تعيين إلى الافتراضي",
"error": "خطأ",
"retry": "حاول مجددا",
"saved": "保存しました。",
"disclaimerForMisskeyHq": "Misskey Tools هي<b> ليست</b> أداة رسمية من Misskey HQ.",
"translatedByTheCommunity": "يقوم متطوعون بترجمة Misskey Tools.",
"helpTranslation": "إرسال الترجمات",
"announcements": "お知らせ",
"_welcomeMessage": {
"pattern1": "هل أنت متفرغ؟",
"pattern2": "هل تفرط في استخدام Misskey؟",
"pattern3": "كم عدد الملاحظات التي كتبتها اليوم؟",
"pattern4": "هل تعتقد حقًا أنك مخطئ؟",
"pattern5": "Misskey هو أنفاسي!",
"pattern6": "I'm Misskey freak!"
},
"_welcome": {
"title": "Toolkit for Professional.",
"description": "All tools are designed for Misskey, in order to make Misskey more enjoyable.",
"misshaiAlertTitle": "Miss-hai Alert",
"misshaiAlertDescription": "هل أنت قلق من الإفراط في استخدام Misskey؟ باستخدام إنذار Misshai ، يمكنك نشر أنشطتك تلقائيًا على Misskey على النحو التالي.",
"misshaiRankingDescription": "يظهر ترتيب Misshai أنشطتك الكمية على Misskey.",
"nextFeaturesTitle": "سيتم التحديث في المستقبل.",
"nextFeaturesDescription": "هذا ليس كل شيء. سنضيف المزيد من الأدوات عن طريق التحديثات في المستقبل."
},
"_nav": {
"misshai": "Misshai",
"accounts": "حسابات",
"settings": "إعدادات"
},
"_missHai": {
"ranking": "ترتيب Misshai",
"rankingDescription": "يعرض هذا الترتيب للمستخدمين \"تقييم Misshai\" بالترتيب من الأعلى إلى الأدنى.",
"showAll": "عرض الكل",
"data": "بيانات Misshai",
"dataBody": "المحتوى",
"dataScore": "نتيجة",
"dataDelta": "الفرق",
"rating": "تقييم",
"order": "الطلب",
"showRanking": "عرض الترتيب"
},
"_accounts": {
"currentAccount": "الحساب الحالي",
"switchAccount": "تبديل حسابك",
"useAnother": "سجل بحساب آخر"
},
"_developerInfo": {
"title": "المطور",
"description": "إذا كنت تريد دعمًا ، أرسل رسائل إلى الحسابات أدناه."
},
"_timeline": {
"title": "الخط الزمني",
"description": "يظهر أحدث الملاحظات بما في ذلك علامات {{hashtag}}."
},
"_alertMode": {
"note": "ملاحظة تلقائية",
"notification": "تنبيه حسابك (افتراضي)",
"nothing": "لا تفعل شيئا",
"notificationWarning": "لن يعمل خيار \"تنبيه حسابك\" على الإصدارات القديمة من Misskey."
},
"_visibility": {
"public": "عام",
"home": "الصفحة الرئيسية",
"followers": "المتابعون",
"users": "المستخدمون المسجلون"
},
"_themes": {
"light": "إضاءة",
"dark": "مظلم",
"system": "حسب إعدادات النظام"
},
"_template": {
"description": "تخصيص نموذج التنبيه الخاص بك.",
"description2": "سيتم إلحاق هاشتاج '#misshaialert' بغض النظر عن نموذج.",
"default": "كان نشاطي على Misskey بالأمس:\n\nملاحظات: {notesCount}({notesDelta})\nمتابعة {followingCount}({followingDelta})\nالمتابعون: {followersCount}({followersDelta})\n\n{url}",
"insertVariables": "أدخل متغيرات",
"insertVariablesHelp": "السلسلة المضمنة في{ } تسمى \"المتغيرات\" ولها معنى خاص. إذا قمت بتضمين هذا ، فسيتم استبداله تلقائيًا بالقيمة الفعلية عند إنشاء التنبيهات.",
"_variables": {
"notesCount": "عدد الملاحظات",
"followingCount": "عدد المتابعات",
"followersCount": "عدد المتابعين",
"notesDelta": "عدد الملاحظات (فرق يوم بعد يوم)",
"followingDelta": "عدد المتابعات (فرق يوم بعد يوم)",
"followersDelta": "عدد المتابعين (فرق يوم بعد يوم)",
"url": "عنوان Url لهذا الموقع",
"username": "اسم المستخدم الخاص بك",
"host": "مضيفك",
"rating": "تقييمك"
}
},
"_error": {
"sorry": "هناك خطأ ما. يرجى المحاولة مجددا.",
"additionalInfo": "معلومات اضافية: ",
"hitorisskeyIsDenied": "لا يمكنك التكامل مع hitorisskey.",
"teapot": "أنا إبريق شاي.",
"sessionRequired": "الجلسة مطلوبة.",
"tokenRequired": "الرمز مطلوب.",
"invalidParameter": "معلمة غير صالحة.",
"notAuthorized": "غير مخول.",
"other": "لا شيء"
},
"_sendTest": {
"title": "هل أنت متأكد أنك تريد اختبار التنبيه؟",
"message": "إرسال تنبيه بالإعدادات الحالية. تأكد من التحقق من حفظ الإعدادات قبل الإرسال.",
"yes": "إرسال",
"no": "إلغاء",
"success": "أرسل التنبيه.",
"failure": "فشل ارسال التنبيه."
},
"_logout": {
"title": "هل أنت متأكد أنك تريد تسجيل الخروج؟",
"message": "حتى إذا قمت بتسجيل الخروج ، ستستمر ميزات مثل إرسال التنبيهات وجمع البيانات من حساب Misskey الخاص بك في العمل. إذا كنت ترغب في التوقف عن استخدام Misskey Tools ، فانقر فوق الزر \"تعطيل تكامل الحساب\".",
"yes": "تسجيل خروج",
"no": "إلغاء"
},
"_deactivate": {
"title": "هل تريد تعطيل حساباتك؟",
"message": "سيتم حذف جميع البيانات ، بما في ذلك البيانات التي تم جمعها والإعدادات الشخصية. لا يمكنك التراجع عن هذه العملية.",
"yes": "تعطيل",
"no": "إلغاء",
"success": "حسابك تم تعطيله. العودة إلى أعلى الشاشة.",
"failure": "فشل حذف الحساب."
}
}

View File

@ -0,0 +1,161 @@
{
"title": "Misskey Tools",
"description1": "Misskeyは楽しいものです。気がついたら1日中入り浸っていることも多いでしょう。",
"description2": "さあ、今すぐMisskey Toolsをインストールして、あなたの活動を把握しよう。",
"notes": "ノート",
"following": "フォロー",
"followers": "フォロワー",
"welcomeBack": "おかえりなさい、{{acct}}さん。",
"alertMode": "アラート送信方法",
"visibility": "公開範囲",
"appearance": "表示設定",
"template": "テンプレート",
"sendAlert": "アラートをテスト送信する",
"sendAlertDescription": "現在の設定を用いて、アラート送信をテストします。",
"sendAlertDisabled": "アラート送信方法が「通知しない」のため、送信をテストすることはできません。",
"logout": "ログアウトする",
"logoutDescription": "ログアウトしても、アラートは送信されます。",
"deleteAccount": "アカウント連携を解除する",
"deleteAccountDescription": "Misskey Toolsのアカウントを削除します。これにより、Misskeyとの連携設定も解除されます。",
"instanceUrl": "インスタンスURL",
"login": "ログイン",
"localOnly": "ローカルのみ",
"remoteFollowersOnly": "リモートフォロワーとローカル",
"help": "ヘルプ",
"save": "保存",
"theme": "テーマ",
"language": "言語",
"fetching": "取得中……",
"failedToFetch": "取得に失敗しました",
"registeredUsersCount": "登録者数",
"isCalculating": "現在算出中です。後ほどご確認ください!",
"ok": "OK",
"yes": "はい",
"no": "いいえ",
"termsOfService": "利用規約",
"name": "名前",
"resetToDefault": "初期値に戻す",
"error": "エラー",
"retry": "やり直す",
"saved": "保存しました。",
"disclaimerForMisskeyHq": "Misskey Toolsは、Misskey HQの公式ツールでは<b>ありません</b>。",
"translatedByTheCommunity": "Misskey Toolsはボランティアによって翻訳されています。",
"helpTranslation": "翻訳に協力する",
"announcements": "お知らせ",
"_welcomeMessage": {
"pattern1": "ついついノートしすぎていませんか?",
"pattern2": "Misskey, しすぎていませんか?",
"pattern3": "今日、何ノート書いた?",
"pattern4": "10000 ノートは初心者、そう思っていませんか?",
"pattern5": "息するように Misskey、そんなあなたへ。",
"pattern6": "あなたは真の Misskey 廃人ですか?"
},
"_welcome": {
"title": "プロ仕様のツールキット",
"description": "Misskey Toolsでは、Misskeyのために設計された、Misskeyをより楽しめるツールを取り揃えています。",
"misshaiAlertTitle": "ミス廃アラート",
"misshaiAlertDescription": "Misskeyにのめり込んでいませんかミス廃アラートを使えば、毎日のMisskeyでの活動量を以下のように定期投稿できます。",
"misshaiRankingDescription": "ミス廃ランキングでは、Misskeyでの活動を数値化し、ランキング表示します。",
"nextFeaturesTitle": "今後も追加予定。",
"nextFeaturesDescription": "これだけではありません。今後もアップデートで様々な機能を追加します!"
},
"_nav": {
"misshai": "ミス廃",
"accounts": "アカウント",
"settings": "設定"
},
"_missHai": {
"ranking": "ミス廃ランキング",
"rankingDescription": "ユーザーの「みす廃レート」を算出し、高い順にランキング表示しています。",
"showAll": "全員分見る",
"data": "みす廃データ",
"dataBody": "内容",
"dataScore": "スコア",
"dataDelta": "前日比",
"rating": "レート",
"order": "順位",
"showRanking": "ランキングを見る"
},
"_accounts": {
"currentAccount": "現在ログインしているアカウント",
"switchAccount": "アカウント切り替え",
"useAnother": "他のアカウントで登録する"
},
"_developerInfo": {
"title": "開発者",
"description": "何か困ったことがあったら、以下のアカウントにメッセージを送ってください。"
},
"_timeline": {
"title": "タイムライン",
"description": "{{hashtag}} タグを含む最新ノートを表示します。"
},
"_alertMode": {
"note": "自動的にノートを投稿",
"notification": "Misskeyに通知(標準)",
"nothing": "通知しない",
"notificationWarning": "「Misskey に通知」オプションは古いMisskeyでは動作しません。"
},
"_visibility": {
"public": "パブリック",
"home": "ホーム",
"followers": "フォロワー",
"users": "ログインユーザー"
},
"_themes": {
"light": "ライトテーマ",
"dark": "ダークテーマ",
"system": "システム設定に準じる"
},
"_template": {
"description": "アラートの自動投稿をカスタマイズできます。",
"description2": "ハッシュタグ #misshaialert は、テンプレートに関わらず自動付与されます。",
"default": "昨日のMisskeyの活動は\n\nート: {notesCount}({notesDelta})\nフォロー : {followingCount}({followingDelta})\nフォロワー :{followersCount}({followersDelta})\n\nでした。\n{url}",
"insertVariables": "変数を挿入する",
"insertVariablesHelp": "{ } で囲われた文字列は変数と呼ばれ、特別な意味を持ちます。これを含めると、投稿時に自動的に値が埋め込まれます。",
"_variables": {
"notesCount": "ノート数",
"followingCount": "フォロー数",
"followersCount": "フォロワー数",
"notesDelta": "ノート数の前日比",
"followingDelta": "フォロー数の前日比",
"followersDelta": "フォロワー数の前日比",
"url": "本サイトのURL",
"username": "アカウントのユーザー名",
"host": "アカウントの所属ホスト名",
"rating": "レート"
}
},
"_error": {
"sorry": "問題が発生しました。お手数ですが、やり直してください。",
"additionalInfo": "追加情報: ",
"hitorisskeyIsDenied": "ひとりすきーは連携できません。",
"teapot": "I'm a teapot.",
"sessionRequired": "セッションがありません。",
"tokenRequired": "トークンがありません。",
"invalidParameter": "パラメータが不正です。",
"notAuthorized": "権限がありません。",
"other": "なし"
},
"_sendTest": {
"title": "アラートをテスト送信しますか?",
"message": "現在の設定でアラートを送信します。設定が保存済みであるかどうか、実行前に必ずご確認ください。",
"yes": "送信する",
"no": "キャンセル",
"success": "送信しました。",
"failure": "送信に失敗しました。"
},
"_logout": {
"title": "ログアウトしてもよろしいですか?",
"message": "ログアウトしても、アラート送信や、お使いのMisskeyアカウントのデータ収集といった機能は動作し続けます。Misskey Toolsの利用を停止したい場合は、「アカウント連携を解除する」ボタンを押下して下さい。",
"yes": "ログアウトする",
"no": "キャンセル"
},
"_deactivate": {
"title": "アカウント連携を解除しますか?",
"message": "収集されたデータや個人設定など、全てのデータが削除されます。この操作は取り消すことができません。",
"yes": "解除する",
"no": "キャンセル",
"success": "アカウントを解除しました。トップ画面に戻ります。",
"failure": "アカウントを解除できませんでした。"
}
}

View File

@ -0,0 +1,161 @@
{
"title": "Misskey Tools",
"description1": "Misskeyは楽しいものです。気がついたら1日中入り浸っていることも多いでしょう。",
"description2": "さあ、今すぐMisskey Toolsをインストールして、あなたの活動を把握しよう。",
"notes": "ノート",
"following": "フォロー",
"followers": "フォロワー",
"welcomeBack": "おかえりなさい、{{acct}}さん。",
"alertMode": "アラート送信方法",
"visibility": "公開範囲",
"appearance": "表示設定",
"template": "テンプレート",
"sendAlert": "アラートをテスト送信する",
"sendAlertDescription": "現在の設定を用いて、アラート送信をテストします。",
"sendAlertDisabled": "アラート送信方法が「通知しない」のため、送信をテストすることはできません。",
"logout": "ログアウトする",
"logoutDescription": "ログアウトしても、アラートは送信されます。",
"deleteAccount": "アカウント連携を解除する",
"deleteAccountDescription": "Misskey Toolsのアカウントを削除します。これにより、Misskeyとの連携設定も解除されます。",
"instanceUrl": "インスタンスURL",
"login": "ログイン",
"localOnly": "ローカルのみ",
"remoteFollowersOnly": "リモートフォロワーとローカル",
"help": "ヘルプ",
"save": "保存",
"theme": "テーマ",
"language": "言語",
"fetching": "取得中……",
"failedToFetch": "取得に失敗しました",
"registeredUsersCount": "登録者数",
"isCalculating": "現在算出中です。後ほどご確認ください!",
"ok": "OK",
"yes": "はい",
"no": "いいえ",
"termsOfService": "利用規約",
"name": "名前",
"resetToDefault": "初期値に戻す",
"error": "エラー",
"retry": "やり直す",
"saved": "保存しました。",
"disclaimerForMisskeyHq": "Misskey Toolsは、Misskey HQの公式ツールでは<b>ありません</b>。",
"translatedByTheCommunity": "Misskey Toolsはボランティアによって翻訳されています。",
"helpTranslation": "翻訳に協力する",
"announcements": "お知らせ",
"_welcomeMessage": {
"pattern1": "ついついノートしすぎていませんか?",
"pattern2": "Misskey, しすぎていませんか?",
"pattern3": "今日、何ノート書いた?",
"pattern4": "10000 ノートは初心者、そう思っていませんか?",
"pattern5": "息するように Misskey、そんなあなたへ。",
"pattern6": "あなたは真の Misskey 廃人ですか?"
},
"_welcome": {
"title": "プロ仕様のツールキット",
"description": "Misskey Toolsでは、Misskeyのために設計された、Misskeyをより楽しめるツールを取り揃えています。",
"misshaiAlertTitle": "ミス廃アラート",
"misshaiAlertDescription": "Misskeyにのめり込んでいませんかミス廃アラートを使えば、毎日のMisskeyでの活動量を以下のように定期投稿できます。",
"misshaiRankingDescription": "ミス廃ランキングでは、Misskeyでの活動を数値化し、ランキング表示します。",
"nextFeaturesTitle": "今後も追加予定。",
"nextFeaturesDescription": "これだけではありません。今後もアップデートで様々な機能を追加します!"
},
"_nav": {
"misshai": "ミス廃",
"accounts": "アカウント",
"settings": "設定"
},
"_missHai": {
"ranking": "ミス廃ランキング",
"rankingDescription": "ユーザーの「みす廃レート」を算出し、高い順にランキング表示しています。",
"showAll": "全員分見る",
"data": "みす廃データ",
"dataBody": "内容",
"dataScore": "スコア",
"dataDelta": "前日比",
"rating": "レート",
"order": "順位",
"showRanking": "ランキングを見る"
},
"_accounts": {
"currentAccount": "現在ログインしているアカウント",
"switchAccount": "アカウント切り替え",
"useAnother": "他のアカウントで登録する"
},
"_developerInfo": {
"title": "開発者",
"description": "何か困ったことがあったら、以下のアカウントにメッセージを送ってください。"
},
"_timeline": {
"title": "タイムライン",
"description": "{{hashtag}} タグを含む最新ノートを表示します。"
},
"_alertMode": {
"note": "自動的にノートを投稿",
"notification": "Misskeyに通知(標準)",
"nothing": "通知しない",
"notificationWarning": "「Misskey に通知」オプションは古いMisskeyでは動作しません。"
},
"_visibility": {
"public": "パブリック",
"home": "ホーム",
"followers": "フォロワー",
"users": "ログインユーザー"
},
"_themes": {
"light": "ライトテーマ",
"dark": "ダークテーマ",
"system": "システム設定に準じる"
},
"_template": {
"description": "アラートの自動投稿をカスタマイズできます。",
"description2": "ハッシュタグ #misshaialert は、テンプレートに関わらず自動付与されます。",
"default": "昨日のMisskeyの活動は\n\nート: {notesCount}({notesDelta})\nフォロー : {followingCount}({followingDelta})\nフォロワー :{followersCount}({followersDelta})\n\nでした。\n{url}",
"insertVariables": "変数を挿入する",
"insertVariablesHelp": "{ } で囲われた文字列は変数と呼ばれ、特別な意味を持ちます。これを含めると、投稿時に自動的に値が埋め込まれます。",
"_variables": {
"notesCount": "ノート数",
"followingCount": "フォロー数",
"followersCount": "フォロワー数",
"notesDelta": "ノート数の前日比",
"followingDelta": "フォロー数の前日比",
"followersDelta": "フォロワー数の前日比",
"url": "本サイトのURL",
"username": "アカウントのユーザー名",
"host": "アカウントの所属ホスト名",
"rating": "レート"
}
},
"_error": {
"sorry": "問題が発生しました。お手数ですが、やり直してください。",
"additionalInfo": "追加情報: ",
"hitorisskeyIsDenied": "ひとりすきーは連携できません。",
"teapot": "I'm a teapot.",
"sessionRequired": "セッションがありません。",
"tokenRequired": "トークンがありません。",
"invalidParameter": "パラメータが不正です。",
"notAuthorized": "権限がありません。",
"other": "なし"
},
"_sendTest": {
"title": "アラートをテスト送信しますか?",
"message": "現在の設定でアラートを送信します。設定が保存済みであるかどうか、実行前に必ずご確認ください。",
"yes": "送信する",
"no": "キャンセル",
"success": "送信しました。",
"failure": "送信に失敗しました。"
},
"_logout": {
"title": "ログアウトしてもよろしいですか?",
"message": "ログアウトしても、アラート送信や、お使いのMisskeyアカウントのデータ収集といった機能は動作し続けます。Misskey Toolsの利用を停止したい場合は、「アカウント連携を解除する」ボタンを押下して下さい。",
"yes": "ログアウトする",
"no": "キャンセル"
},
"_deactivate": {
"title": "アカウント連携を解除しますか?",
"message": "収集されたデータや個人設定など、全てのデータが削除されます。この操作は取り消すことができません。",
"yes": "解除する",
"no": "キャンセル",
"success": "アカウントを解除しました。トップ画面に戻ります。",
"failure": "アカウントを解除できませんでした。"
}
}

View File

@ -0,0 +1,161 @@
{
"title": "Misskey Tools",
"description1": "Misskeyは楽しいものです。気がついたら1日中入り浸っていることも多いでしょう。",
"description2": "さあ、今すぐMisskey Toolsをインストールして、あなたの活動を把握しよう。",
"notes": "ノート",
"following": "フォロー",
"followers": "フォロワー",
"welcomeBack": "おかえりなさい、{{acct}}さん。",
"alertMode": "アラート送信方法",
"visibility": "公開範囲",
"appearance": "表示設定",
"template": "テンプレート",
"sendAlert": "アラートをテスト送信する",
"sendAlertDescription": "現在の設定を用いて、アラート送信をテストします。",
"sendAlertDisabled": "アラート送信方法が「通知しない」のため、送信をテストすることはできません。",
"logout": "ログアウトする",
"logoutDescription": "ログアウトしても、アラートは送信されます。",
"deleteAccount": "アカウント連携を解除する",
"deleteAccountDescription": "Misskey Toolsのアカウントを削除します。これにより、Misskeyとの連携設定も解除されます。",
"instanceUrl": "インスタンスURL",
"login": "ログイン",
"localOnly": "ローカルのみ",
"remoteFollowersOnly": "リモートフォロワーとローカル",
"help": "ヘルプ",
"save": "保存",
"theme": "テーマ",
"language": "言語",
"fetching": "取得中……",
"failedToFetch": "取得に失敗しました",
"registeredUsersCount": "登録者数",
"isCalculating": "現在算出中です。後ほどご確認ください!",
"ok": "OK",
"yes": "はい",
"no": "いいえ",
"termsOfService": "利用規約",
"name": "名前",
"resetToDefault": "初期値に戻す",
"error": "エラー",
"retry": "やり直す",
"saved": "保存しました。",
"disclaimerForMisskeyHq": "Misskey Toolsは、Misskey HQの公式ツールでは<b>ありません</b>。",
"translatedByTheCommunity": "Misskey Toolsはボランティアによって翻訳されています。",
"helpTranslation": "翻訳に協力する",
"announcements": "お知らせ",
"_welcomeMessage": {
"pattern1": "ついついノートしすぎていませんか?",
"pattern2": "Misskey, しすぎていませんか?",
"pattern3": "今日、何ノート書いた?",
"pattern4": "10000 ノートは初心者、そう思っていませんか?",
"pattern5": "息するように Misskey、そんなあなたへ。",
"pattern6": "あなたは真の Misskey 廃人ですか?"
},
"_welcome": {
"title": "プロ仕様のツールキット",
"description": "Misskey Toolsでは、Misskeyのために設計された、Misskeyをより楽しめるツールを取り揃えています。",
"misshaiAlertTitle": "ミス廃アラート",
"misshaiAlertDescription": "Misskeyにのめり込んでいませんかミス廃アラートを使えば、毎日のMisskeyでの活動量を以下のように定期投稿できます。",
"misshaiRankingDescription": "ミス廃ランキングでは、Misskeyでの活動を数値化し、ランキング表示します。",
"nextFeaturesTitle": "今後も追加予定。",
"nextFeaturesDescription": "これだけではありません。今後もアップデートで様々な機能を追加します!"
},
"_nav": {
"misshai": "ミス廃",
"accounts": "アカウント",
"settings": "設定"
},
"_missHai": {
"ranking": "ミス廃ランキング",
"rankingDescription": "ユーザーの「みす廃レート」を算出し、高い順にランキング表示しています。",
"showAll": "全員分見る",
"data": "みす廃データ",
"dataBody": "内容",
"dataScore": "スコア",
"dataDelta": "前日比",
"rating": "レート",
"order": "順位",
"showRanking": "ランキングを見る"
},
"_accounts": {
"currentAccount": "現在ログインしているアカウント",
"switchAccount": "アカウント切り替え",
"useAnother": "他のアカウントで登録する"
},
"_developerInfo": {
"title": "開発者",
"description": "何か困ったことがあったら、以下のアカウントにメッセージを送ってください。"
},
"_timeline": {
"title": "タイムライン",
"description": "{{hashtag}} タグを含む最新ノートを表示します。"
},
"_alertMode": {
"note": "自動的にノートを投稿",
"notification": "Misskeyに通知(標準)",
"nothing": "通知しない",
"notificationWarning": "「Misskey に通知」オプションは古いMisskeyでは動作しません。"
},
"_visibility": {
"public": "パブリック",
"home": "ホーム",
"followers": "フォロワー",
"users": "ログインユーザー"
},
"_themes": {
"light": "ライトテーマ",
"dark": "ダークテーマ",
"system": "システム設定に準じる"
},
"_template": {
"description": "アラートの自動投稿をカスタマイズできます。",
"description2": "ハッシュタグ #misshaialert は、テンプレートに関わらず自動付与されます。",
"default": "昨日のMisskeyの活動は\n\nート: {notesCount}({notesDelta})\nフォロー : {followingCount}({followingDelta})\nフォロワー :{followersCount}({followersDelta})\n\nでした。\n{url}",
"insertVariables": "変数を挿入する",
"insertVariablesHelp": "{ } で囲われた文字列は変数と呼ばれ、特別な意味を持ちます。これを含めると、投稿時に自動的に値が埋め込まれます。",
"_variables": {
"notesCount": "ノート数",
"followingCount": "フォロー数",
"followersCount": "フォロワー数",
"notesDelta": "ノート数の前日比",
"followingDelta": "フォロー数の前日比",
"followersDelta": "フォロワー数の前日比",
"url": "本サイトのURL",
"username": "アカウントのユーザー名",
"host": "アカウントの所属ホスト名",
"rating": "レート"
}
},
"_error": {
"sorry": "問題が発生しました。お手数ですが、やり直してください。",
"additionalInfo": "追加情報: ",
"hitorisskeyIsDenied": "ひとりすきーは連携できません。",
"teapot": "I'm a teapot.",
"sessionRequired": "セッションがありません。",
"tokenRequired": "トークンがありません。",
"invalidParameter": "パラメータが不正です。",
"notAuthorized": "権限がありません。",
"other": "なし"
},
"_sendTest": {
"title": "アラートをテスト送信しますか?",
"message": "現在の設定でアラートを送信します。設定が保存済みであるかどうか、実行前に必ずご確認ください。",
"yes": "送信する",
"no": "キャンセル",
"success": "送信しました。",
"failure": "送信に失敗しました。"
},
"_logout": {
"title": "ログアウトしてもよろしいですか?",
"message": "ログアウトしても、アラート送信や、お使いのMisskeyアカウントのデータ収集といった機能は動作し続けます。Misskey Toolsの利用を停止したい場合は、「アカウント連携を解除する」ボタンを押下して下さい。",
"yes": "ログアウトする",
"no": "キャンセル"
},
"_deactivate": {
"title": "アカウント連携を解除しますか?",
"message": "収集されたデータや個人設定など、全てのデータが削除されます。この操作は取り消すことができません。",
"yes": "解除する",
"no": "キャンセル",
"success": "アカウントを解除しました。トップ画面に戻ります。",
"failure": "アカウントを解除できませんでした。"
}
}

View File

@ -0,0 +1,161 @@
{
"title": "Misskey Tools",
"description1": "Misskeyは楽しいものです。気がついたら1日中入り浸っていることも多いでしょう。",
"description2": "さあ、今すぐMisskey Toolsをインストールして、あなたの活動を把握しよう。",
"notes": "ノート",
"following": "フォロー",
"followers": "フォロワー",
"welcomeBack": "おかえりなさい、{{acct}}さん。",
"alertMode": "アラート送信方法",
"visibility": "公開範囲",
"appearance": "表示設定",
"template": "テンプレート",
"sendAlert": "アラートをテスト送信する",
"sendAlertDescription": "現在の設定を用いて、アラート送信をテストします。",
"sendAlertDisabled": "アラート送信方法が「通知しない」のため、送信をテストすることはできません。",
"logout": "ログアウトする",
"logoutDescription": "ログアウトしても、アラートは送信されます。",
"deleteAccount": "アカウント連携を解除する",
"deleteAccountDescription": "Misskey Toolsのアカウントを削除します。これにより、Misskeyとの連携設定も解除されます。",
"instanceUrl": "インスタンスURL",
"login": "ログイン",
"localOnly": "ローカルのみ",
"remoteFollowersOnly": "リモートフォロワーとローカル",
"help": "ヘルプ",
"save": "保存",
"theme": "テーマ",
"language": "言語",
"fetching": "取得中……",
"failedToFetch": "取得に失敗しました",
"registeredUsersCount": "登録者数",
"isCalculating": "現在算出中です。後ほどご確認ください!",
"ok": "OK",
"yes": "はい",
"no": "いいえ",
"termsOfService": "利用規約",
"name": "名前",
"resetToDefault": "初期値に戻す",
"error": "エラー",
"retry": "やり直す",
"saved": "保存しました。",
"disclaimerForMisskeyHq": "Misskey Toolsは、Misskey HQの公式ツールでは<b>ありません</b>。",
"translatedByTheCommunity": "Misskey Toolsはボランティアによって翻訳されています。",
"helpTranslation": "翻訳に協力する",
"announcements": "お知らせ",
"_welcomeMessage": {
"pattern1": "ついついノートしすぎていませんか?",
"pattern2": "Misskey, しすぎていませんか?",
"pattern3": "今日、何ノート書いた?",
"pattern4": "10000 ノートは初心者、そう思っていませんか?",
"pattern5": "息するように Misskey、そんなあなたへ。",
"pattern6": "あなたは真の Misskey 廃人ですか?"
},
"_welcome": {
"title": "プロ仕様のツールキット",
"description": "Misskey Toolsでは、Misskeyのために設計された、Misskeyをより楽しめるツールを取り揃えています。",
"misshaiAlertTitle": "ミス廃アラート",
"misshaiAlertDescription": "Misskeyにのめり込んでいませんかミス廃アラートを使えば、毎日のMisskeyでの活動量を以下のように定期投稿できます。",
"misshaiRankingDescription": "ミス廃ランキングでは、Misskeyでの活動を数値化し、ランキング表示します。",
"nextFeaturesTitle": "今後も追加予定。",
"nextFeaturesDescription": "これだけではありません。今後もアップデートで様々な機能を追加します!"
},
"_nav": {
"misshai": "ミス廃",
"accounts": "アカウント",
"settings": "設定"
},
"_missHai": {
"ranking": "ミス廃ランキング",
"rankingDescription": "ユーザーの「みす廃レート」を算出し、高い順にランキング表示しています。",
"showAll": "全員分見る",
"data": "みす廃データ",
"dataBody": "内容",
"dataScore": "スコア",
"dataDelta": "前日比",
"rating": "レート",
"order": "順位",
"showRanking": "ランキングを見る"
},
"_accounts": {
"currentAccount": "現在ログインしているアカウント",
"switchAccount": "アカウント切り替え",
"useAnother": "他のアカウントで登録する"
},
"_developerInfo": {
"title": "開発者",
"description": "何か困ったことがあったら、以下のアカウントにメッセージを送ってください。"
},
"_timeline": {
"title": "タイムライン",
"description": "{{hashtag}} タグを含む最新ノートを表示します。"
},
"_alertMode": {
"note": "自動的にノートを投稿",
"notification": "Misskeyに通知(標準)",
"nothing": "通知しない",
"notificationWarning": "「Misskey に通知」オプションは古いMisskeyでは動作しません。"
},
"_visibility": {
"public": "パブリック",
"home": "ホーム",
"followers": "フォロワー",
"users": "ログインユーザー"
},
"_themes": {
"light": "ライトテーマ",
"dark": "ダークテーマ",
"system": "システム設定に準じる"
},
"_template": {
"description": "アラートの自動投稿をカスタマイズできます。",
"description2": "ハッシュタグ #misshaialert は、テンプレートに関わらず自動付与されます。",
"default": "昨日のMisskeyの活動は\n\nート: {notesCount}({notesDelta})\nフォロー : {followingCount}({followingDelta})\nフォロワー :{followersCount}({followersDelta})\n\nでした。\n{url}",
"insertVariables": "変数を挿入する",
"insertVariablesHelp": "{ } で囲われた文字列は変数と呼ばれ、特別な意味を持ちます。これを含めると、投稿時に自動的に値が埋め込まれます。",
"_variables": {
"notesCount": "ノート数",
"followingCount": "フォロー数",
"followersCount": "フォロワー数",
"notesDelta": "ノート数の前日比",
"followingDelta": "フォロー数の前日比",
"followersDelta": "フォロワー数の前日比",
"url": "本サイトのURL",
"username": "アカウントのユーザー名",
"host": "アカウントの所属ホスト名",
"rating": "レート"
}
},
"_error": {
"sorry": "問題が発生しました。お手数ですが、やり直してください。",
"additionalInfo": "追加情報: ",
"hitorisskeyIsDenied": "ひとりすきーは連携できません。",
"teapot": "I'm a teapot.",
"sessionRequired": "セッションがありません。",
"tokenRequired": "トークンがありません。",
"invalidParameter": "パラメータが不正です。",
"notAuthorized": "権限がありません。",
"other": "なし"
},
"_sendTest": {
"title": "アラートをテスト送信しますか?",
"message": "現在の設定でアラートを送信します。設定が保存済みであるかどうか、実行前に必ずご確認ください。",
"yes": "送信する",
"no": "キャンセル",
"success": "送信しました。",
"failure": "送信に失敗しました。"
},
"_logout": {
"title": "ログアウトしてもよろしいですか?",
"message": "ログアウトしても、アラート送信や、お使いのMisskeyアカウントのデータ収集といった機能は動作し続けます。Misskey Toolsの利用を停止したい場合は、「アカウント連携を解除する」ボタンを押下して下さい。",
"yes": "ログアウトする",
"no": "キャンセル"
},
"_deactivate": {
"title": "アカウント連携を解除しますか?",
"message": "収集されたデータや個人設定など、全てのデータが削除されます。この操作は取り消すことができません。",
"yes": "解除する",
"no": "キャンセル",
"success": "アカウントを解除しました。トップ画面に戻ります。",
"failure": "アカウントを解除できませんでした。"
}
}

View File

@ -0,0 +1,161 @@
{
"title": "Misskey Tools",
"description1": "Misskeyは楽しいものです。気がついたら1日中入り浸っていることも多いでしょう。",
"description2": "さあ、今すぐMisskey Toolsをインストールして、あなたの活動を把握しよう。",
"notes": "ノート",
"following": "フォロー",
"followers": "フォロワー",
"welcomeBack": "おかえりなさい、{{acct}}さん。",
"alertMode": "アラート送信方法",
"visibility": "公開範囲",
"appearance": "表示設定",
"template": "テンプレート",
"sendAlert": "アラートをテスト送信する",
"sendAlertDescription": "現在の設定を用いて、アラート送信をテストします。",
"sendAlertDisabled": "アラート送信方法が「通知しない」のため、送信をテストすることはできません。",
"logout": "ログアウトする",
"logoutDescription": "ログアウトしても、アラートは送信されます。",
"deleteAccount": "アカウント連携を解除する",
"deleteAccountDescription": "Misskey Toolsのアカウントを削除します。これにより、Misskeyとの連携設定も解除されます。",
"instanceUrl": "インスタンスURL",
"login": "ログイン",
"localOnly": "ローカルのみ",
"remoteFollowersOnly": "リモートフォロワーとローカル",
"help": "ヘルプ",
"save": "保存",
"theme": "テーマ",
"language": "言語",
"fetching": "取得中……",
"failedToFetch": "取得に失敗しました",
"registeredUsersCount": "登録者数",
"isCalculating": "現在算出中です。後ほどご確認ください!",
"ok": "OK",
"yes": "はい",
"no": "いいえ",
"termsOfService": "利用規約",
"name": "名前",
"resetToDefault": "初期値に戻す",
"error": "エラー",
"retry": "やり直す",
"saved": "保存しました。",
"disclaimerForMisskeyHq": "Misskey Toolsは、Misskey HQの公式ツールでは<b>ありません</b>。",
"translatedByTheCommunity": "Misskey Toolsはボランティアによって翻訳されています。",
"helpTranslation": "翻訳に協力する",
"announcements": "お知らせ",
"_welcomeMessage": {
"pattern1": "ついついノートしすぎていませんか?",
"pattern2": "Misskey, しすぎていませんか?",
"pattern3": "今日、何ノート書いた?",
"pattern4": "10000 ノートは初心者、そう思っていませんか?",
"pattern5": "息するように Misskey、そんなあなたへ。",
"pattern6": "あなたは真の Misskey 廃人ですか?"
},
"_welcome": {
"title": "プロ仕様のツールキット",
"description": "Misskey Toolsでは、Misskeyのために設計された、Misskeyをより楽しめるツールを取り揃えています。",
"misshaiAlertTitle": "ミス廃アラート",
"misshaiAlertDescription": "Misskeyにのめり込んでいませんかミス廃アラートを使えば、毎日のMisskeyでの活動量を以下のように定期投稿できます。",
"misshaiRankingDescription": "ミス廃ランキングでは、Misskeyでの活動を数値化し、ランキング表示します。",
"nextFeaturesTitle": "今後も追加予定。",
"nextFeaturesDescription": "これだけではありません。今後もアップデートで様々な機能を追加します!"
},
"_nav": {
"misshai": "ミス廃",
"accounts": "アカウント",
"settings": "設定"
},
"_missHai": {
"ranking": "ミス廃ランキング",
"rankingDescription": "ユーザーの「みす廃レート」を算出し、高い順にランキング表示しています。",
"showAll": "全員分見る",
"data": "みす廃データ",
"dataBody": "内容",
"dataScore": "スコア",
"dataDelta": "前日比",
"rating": "レート",
"order": "順位",
"showRanking": "ランキングを見る"
},
"_accounts": {
"currentAccount": "現在ログインしているアカウント",
"switchAccount": "アカウント切り替え",
"useAnother": "他のアカウントで登録する"
},
"_developerInfo": {
"title": "開発者",
"description": "何か困ったことがあったら、以下のアカウントにメッセージを送ってください。"
},
"_timeline": {
"title": "タイムライン",
"description": "{{hashtag}} タグを含む最新ノートを表示します。"
},
"_alertMode": {
"note": "自動的にノートを投稿",
"notification": "Misskeyに通知(標準)",
"nothing": "通知しない",
"notificationWarning": "「Misskey に通知」オプションは古いMisskeyでは動作しません。"
},
"_visibility": {
"public": "パブリック",
"home": "ホーム",
"followers": "フォロワー",
"users": "ログインユーザー"
},
"_themes": {
"light": "ライトテーマ",
"dark": "ダークテーマ",
"system": "システム設定に準じる"
},
"_template": {
"description": "アラートの自動投稿をカスタマイズできます。",
"description2": "ハッシュタグ #misshaialert は、テンプレートに関わらず自動付与されます。",
"default": "昨日のMisskeyの活動は\n\nート: {notesCount}({notesDelta})\nフォロー : {followingCount}({followingDelta})\nフォロワー :{followersCount}({followersDelta})\n\nでした。\n{url}",
"insertVariables": "変数を挿入する",
"insertVariablesHelp": "{ } で囲われた文字列は変数と呼ばれ、特別な意味を持ちます。これを含めると、投稿時に自動的に値が埋め込まれます。",
"_variables": {
"notesCount": "ノート数",
"followingCount": "フォロー数",
"followersCount": "フォロワー数",
"notesDelta": "ノート数の前日比",
"followingDelta": "フォロー数の前日比",
"followersDelta": "フォロワー数の前日比",
"url": "本サイトのURL",
"username": "アカウントのユーザー名",
"host": "アカウントの所属ホスト名",
"rating": "レート"
}
},
"_error": {
"sorry": "問題が発生しました。お手数ですが、やり直してください。",
"additionalInfo": "追加情報: ",
"hitorisskeyIsDenied": "ひとりすきーは連携できません。",
"teapot": "I'm a teapot.",
"sessionRequired": "セッションがありません。",
"tokenRequired": "トークンがありません。",
"invalidParameter": "パラメータが不正です。",
"notAuthorized": "権限がありません。",
"other": "なし"
},
"_sendTest": {
"title": "アラートをテスト送信しますか?",
"message": "現在の設定でアラートを送信します。設定が保存済みであるかどうか、実行前に必ずご確認ください。",
"yes": "送信する",
"no": "キャンセル",
"success": "送信しました。",
"failure": "送信に失敗しました。"
},
"_logout": {
"title": "ログアウトしてもよろしいですか?",
"message": "ログアウトしても、アラート送信や、お使いのMisskeyアカウントのデータ収集といった機能は動作し続けます。Misskey Toolsの利用を停止したい場合は、「アカウント連携を解除する」ボタンを押下して下さい。",
"yes": "ログアウトする",
"no": "キャンセル"
},
"_deactivate": {
"title": "アカウント連携を解除しますか?",
"message": "収集されたデータや個人設定など、全てのデータが削除されます。この操作は取り消すことができません。",
"yes": "解除する",
"no": "キャンセル",
"success": "アカウントを解除しました。トップ画面に戻ります。",
"failure": "アカウントを解除できませんでした。"
}
}

View File

@ -0,0 +1,161 @@
{
"title": "Misskey Tools",
"description1": "Misskey is fun thing. When you realized it, you have been used Misskey all day long.",
"description2": "Let's get Misskey Tools account and know your activity.",
"notes": "Notes",
"following": "Following",
"followers": "Followers",
"welcomeBack": "Welcome back, {{acct}}.",
"alertMode": "How to Send Alerts",
"visibility": "Visibility",
"appearance": "Appearance",
"template": "Template",
"sendAlert": "Test your alert",
"sendAlertDescription": "Send your alert with current settings to test.",
"sendAlertDisabled": "You cannot test sending alert because the \"How to Send Alerts\" setting is \"Do Nothing\".",
"logout": "Log Out",
"logoutDescription": "If you log out, your alerts will be sent automatically.",
"deleteAccount": "Deactivate account integration",
"deleteAccountDescription": "Delete your Misskey Tools account. This will deactivate integration with Misskey.",
"instanceUrl": "Instance URL",
"login": "Login",
"localOnly": "Local Only",
"remoteFollowersOnly": "Remote Followers and Local Only",
"help": "Help",
"save": "Save",
"theme": "Theme",
"language": "Language",
"fetching": "Fetching...",
"failedToFetch": "Failed to fetch",
"registeredUsersCount": "Users",
"isCalculating": "It is being calculated now. Please check back later!",
"ok": "OK",
"yes": "Yes",
"no": "No",
"termsOfService": "Terms of Service",
"name": "Name",
"resetToDefault": "Reset to default",
"error": "Error",
"retry": "Try again",
"saved": "Saved.",
"disclaimerForMisskeyHq": "Misskey Tools is <b>not</b> a official tool by Misskey HQ.",
"translatedByTheCommunity": "Misskey Tools is translated by volunteers.",
"helpTranslation": "Submit translations",
"announcements": "Announcements",
"_welcomeMessage": {
"pattern1": "Are you overnoting?",
"pattern2": "Are you overusing Misskey?",
"pattern3": "How many notes did you write today?",
"pattern4": "Do you really think you're lite-misskist?",
"pattern5": "Misskey is my breathing!",
"pattern6": "I'm Misskey freak!"
},
"_welcome": {
"title": "Toolkit for Professional.",
"description": "All tools are designed for Misskey, in order to make Misskey more enjoyable.",
"misshaiAlertTitle": "Miss-hai Alert",
"misshaiAlertDescription": "Are you worried about overusing Misskey? With Miss-hai Alert, you can automatically post your activities on Misskey as below.",
"misshaiRankingDescription": "Miss-hai Ranking shows your quantified activities on Misskey.",
"nextFeaturesTitle": "Will update in the future.",
"nextFeaturesDescription": "This is not all. We will add more tools by updates in the future."
},
"_nav": {
"misshai": "Miss-hai",
"accounts": "Accounts",
"settings": "Settings"
},
"_missHai": {
"ranking": "Miss-hai Ranking",
"rankingDescription": "This ranking shows users \"Misshai Rating\" in order of the highest to lowest.",
"showAll": "Show All",
"data": "Miss-hai Data",
"dataBody": "Body",
"dataScore": "Score",
"dataDelta": "Difference",
"rating": "Rating",
"order": "Order",
"showRanking": "Show Ranking"
},
"_accounts": {
"currentAccount": "Current Account",
"switchAccount": "Switch your account",
"useAnother": "Register with another account"
},
"_developerInfo": {
"title": "Developer",
"description": "If you want supports, send messages to the below accounts."
},
"_timeline": {
"title": "Timeline",
"description": "Shows latest notes including {{hashtag}} tags."
},
"_alertMode": {
"note": "Automatic Note",
"notification": "Notify to your account (Default)",
"nothing": "Do Nothing",
"notificationWarning": "'Notify to your account' option will not be work on legacy versions of Misskey."
},
"_visibility": {
"public": "Public",
"home": "Home",
"followers": "Followers",
"users": "Logged-in Users"
},
"_themes": {
"light": "Light",
"dark": "Dark",
"system": "Follows System Preferences"
},
"_template": {
"description": "Customize template of your alert.",
"description2": "Hashtag '#misshaialert' will be appended regardless of the template.",
"default": "My Misskey activity yesterday was:\n\nNotes: {notesCount}({notesDelta})\nFollowing: {followingCount}({followingDelta})\nFollowers: {followersCount}({followersDelta})\n\n{url}",
"insertVariables": "Insert variables",
"insertVariablesHelp": "The string enclosed in { } is called \"variables\" and has a special meaning. If you include this, it will be automatically replaced to the actual value when alerts created.",
"_variables": {
"notesCount": "Notes Count",
"followingCount": "Following Count",
"followersCount": "Followers Count",
"notesDelta": "Notes Count (day-over-day difference)",
"followingDelta": "Following Count (day-over-day difference)",
"followersDelta": "Followers Count (day-over-day difference)",
"url": "URL of this site",
"username": "Your Username",
"host": "Your host",
"rating": "Your rating"
}
},
"_error": {
"sorry": "Something went wrong. Please retry again.",
"additionalInfo": "Additional Info: ",
"hitorisskeyIsDenied": "You cannot integrate with hitorisskey.",
"teapot": "I'm a teapot.",
"sessionRequired": "Session is required.",
"tokenRequired": "Token is required.",
"invalidParameter": "Invalid parameter.",
"notAuthorized": "Not authorized.",
"other": "None"
},
"_sendTest": {
"title": "Are you sure you want to test the alert?",
"message": "Send an alert with the current settings. Be sure to check that the settings have been saved before sending.",
"yes": "Send",
"no": "Cancel",
"success": "Alert sent.",
"failure": "Failed to sent the alert."
},
"_logout": {
"title": "Are you sure you want to logout?",
"message": "Even if you log out, features such as sending alerts and collecting data from your Misskey account will continue to work. If you wish to stop using Misskey Tools, click the \"Deactivate account integration\" button.",
"yes": "Logout",
"no": "Cancel"
},
"_deactivate": {
"title": "Do you want to deactivate your accounts?",
"message": "All data, including collected data and personal settings, will be deleted. You cannot undo this operation. You cannot undo this operation.",
"yes": "Deactivate",
"no": "Cancel",
"success": "Your account has been deactivated. Return to the top screen.",
"failure": "Failed to delete account."
}
}

View File

@ -0,0 +1,161 @@
{
"title": "Misskey Tools",
"description1": "Misskeyは楽しいものです。気がついたら1日中入り浸っていることも多いでしょう。",
"description2": "さあ、今すぐMisskey Toolsをインストールして、あなたの活動を把握しよう。",
"notes": "ノート",
"following": "フォロー",
"followers": "フォロワー",
"welcomeBack": "おかえりなさい、{{acct}}さん。",
"alertMode": "アラート送信方法",
"visibility": "公開範囲",
"appearance": "表示設定",
"template": "テンプレート",
"sendAlert": "アラートをテスト送信する",
"sendAlertDescription": "現在の設定を用いて、アラート送信をテストします。",
"sendAlertDisabled": "アラート送信方法が「通知しない」のため、送信をテストすることはできません。",
"logout": "ログアウトする",
"logoutDescription": "ログアウトしても、アラートは送信されます。",
"deleteAccount": "アカウント連携を解除する",
"deleteAccountDescription": "Misskey Toolsのアカウントを削除します。これにより、Misskeyとの連携設定も解除されます。",
"instanceUrl": "インスタンスURL",
"login": "ログイン",
"localOnly": "ローカルのみ",
"remoteFollowersOnly": "リモートフォロワーとローカル",
"help": "ヘルプ",
"save": "保存",
"theme": "テーマ",
"language": "言語",
"fetching": "取得中……",
"failedToFetch": "取得に失敗しました",
"registeredUsersCount": "登録者数",
"isCalculating": "現在算出中です。後ほどご確認ください!",
"ok": "OK",
"yes": "はい",
"no": "いいえ",
"termsOfService": "利用規約",
"name": "名前",
"resetToDefault": "初期値に戻す",
"error": "エラー",
"retry": "やり直す",
"saved": "保存しました。",
"disclaimerForMisskeyHq": "Misskey Toolsは、Misskey HQの公式ツールでは<b>ありません</b>。",
"translatedByTheCommunity": "Misskey Toolsはボランティアによって翻訳されています。",
"helpTranslation": "翻訳に協力する",
"announcements": "お知らせ",
"_welcomeMessage": {
"pattern1": "ついついノートしすぎていませんか?",
"pattern2": "Misskey, しすぎていませんか?",
"pattern3": "今日、何ノート書いた?",
"pattern4": "10000 ノートは初心者、そう思っていませんか?",
"pattern5": "息するように Misskey、そんなあなたへ。",
"pattern6": "あなたは真の Misskey 廃人ですか?"
},
"_welcome": {
"title": "プロ仕様のツールキット",
"description": "Misskey Toolsでは、Misskeyのために設計された、Misskeyをより楽しめるツールを取り揃えています。",
"misshaiAlertTitle": "ミス廃アラート",
"misshaiAlertDescription": "Misskeyにのめり込んでいませんかミス廃アラートを使えば、毎日のMisskeyでの活動量を以下のように定期投稿できます。",
"misshaiRankingDescription": "ミス廃ランキングでは、Misskeyでの活動を数値化し、ランキング表示します。",
"nextFeaturesTitle": "今後も追加予定。",
"nextFeaturesDescription": "これだけではありません。今後もアップデートで様々な機能を追加します!"
},
"_nav": {
"misshai": "ミス廃",
"accounts": "アカウント",
"settings": "設定"
},
"_missHai": {
"ranking": "ミス廃ランキング",
"rankingDescription": "ユーザーの「みす廃レート」を算出し、高い順にランキング表示しています。",
"showAll": "全員分見る",
"data": "みす廃データ",
"dataBody": "内容",
"dataScore": "スコア",
"dataDelta": "前日比",
"rating": "レート",
"order": "順位",
"showRanking": "ランキングを見る"
},
"_accounts": {
"currentAccount": "現在ログインしているアカウント",
"switchAccount": "アカウント切り替え",
"useAnother": "他のアカウントで登録する"
},
"_developerInfo": {
"title": "開発者",
"description": "何か困ったことがあったら、以下のアカウントにメッセージを送ってください。"
},
"_timeline": {
"title": "タイムライン",
"description": "{{hashtag}} タグを含む最新ノートを表示します。"
},
"_alertMode": {
"note": "自動的にノートを投稿",
"notification": "Misskeyに通知(標準)",
"nothing": "通知しない",
"notificationWarning": "「Misskey に通知」オプションは古いMisskeyでは動作しません。"
},
"_visibility": {
"public": "パブリック",
"home": "ホーム",
"followers": "フォロワー",
"users": "ログインユーザー"
},
"_themes": {
"light": "ライトテーマ",
"dark": "ダークテーマ",
"system": "システム設定に準じる"
},
"_template": {
"description": "アラートの自動投稿をカスタマイズできます。",
"description2": "ハッシュタグ #misshaialert は、テンプレートに関わらず自動付与されます。",
"default": "昨日のMisskeyの活動は\n\nート: {notesCount}({notesDelta})\nフォロー : {followingCount}({followingDelta})\nフォロワー :{followersCount}({followersDelta})\n\nでした。\n{url}",
"insertVariables": "変数を挿入する",
"insertVariablesHelp": "{ } で囲われた文字列は変数と呼ばれ、特別な意味を持ちます。これを含めると、投稿時に自動的に値が埋め込まれます。",
"_variables": {
"notesCount": "ノート数",
"followingCount": "フォロー数",
"followersCount": "フォロワー数",
"notesDelta": "ノート数の前日比",
"followingDelta": "フォロー数の前日比",
"followersDelta": "フォロワー数の前日比",
"url": "本サイトのURL",
"username": "アカウントのユーザー名",
"host": "アカウントの所属ホスト名",
"rating": "レート"
}
},
"_error": {
"sorry": "問題が発生しました。お手数ですが、やり直してください。",
"additionalInfo": "追加情報: ",
"hitorisskeyIsDenied": "ひとりすきーは連携できません。",
"teapot": "I'm a teapot.",
"sessionRequired": "セッションがありません。",
"tokenRequired": "トークンがありません。",
"invalidParameter": "パラメータが不正です。",
"notAuthorized": "権限がありません。",
"other": "なし"
},
"_sendTest": {
"title": "アラートをテスト送信しますか?",
"message": "現在の設定でアラートを送信します。設定が保存済みであるかどうか、実行前に必ずご確認ください。",
"yes": "送信する",
"no": "キャンセル",
"success": "送信しました。",
"failure": "送信に失敗しました。"
},
"_logout": {
"title": "ログアウトしてもよろしいですか?",
"message": "ログアウトしても、アラート送信や、お使いのMisskeyアカウントのデータ収集といった機能は動作し続けます。Misskey Toolsの利用を停止したい場合は、「アカウント連携を解除する」ボタンを押下して下さい。",
"yes": "ログアウトする",
"no": "キャンセル"
},
"_deactivate": {
"title": "アカウント連携を解除しますか?",
"message": "収集されたデータや個人設定など、全てのデータが削除されます。この操作は取り消すことができません。",
"yes": "解除する",
"no": "キャンセル",
"success": "アカウントを解除しました。トップ画面に戻ります。",
"failure": "アカウントを解除できませんでした。"
}
}

View File

@ -0,0 +1,161 @@
{
"title": "Misskey Tools",
"description1": "Misskeyは楽しいものです。気がついたら1日中入り浸っていることも多いでしょう。",
"description2": "さあ、今すぐMisskey Toolsをインストールして、あなたの活動を把握しよう。",
"notes": "ノート",
"following": "フォロー",
"followers": "フォロワー",
"welcomeBack": "おかえりなさい、{{acct}}さん。",
"alertMode": "アラート送信方法",
"visibility": "公開範囲",
"appearance": "表示設定",
"template": "テンプレート",
"sendAlert": "アラートをテスト送信する",
"sendAlertDescription": "現在の設定を用いて、アラート送信をテストします。",
"sendAlertDisabled": "アラート送信方法が「通知しない」のため、送信をテストすることはできません。",
"logout": "ログアウトする",
"logoutDescription": "ログアウトしても、アラートは送信されます。",
"deleteAccount": "アカウント連携を解除する",
"deleteAccountDescription": "Misskey Toolsのアカウントを削除します。これにより、Misskeyとの連携設定も解除されます。",
"instanceUrl": "インスタンスURL",
"login": "ログイン",
"localOnly": "ローカルのみ",
"remoteFollowersOnly": "リモートフォロワーとローカル",
"help": "ヘルプ",
"save": "保存",
"theme": "テーマ",
"language": "言語",
"fetching": "取得中……",
"failedToFetch": "取得に失敗しました",
"registeredUsersCount": "登録者数",
"isCalculating": "現在算出中です。後ほどご確認ください!",
"ok": "OK",
"yes": "はい",
"no": "いいえ",
"termsOfService": "利用規約",
"name": "名前",
"resetToDefault": "初期値に戻す",
"error": "エラー",
"retry": "やり直す",
"saved": "保存しました。",
"disclaimerForMisskeyHq": "Misskey Toolsは、Misskey HQの公式ツールでは<b>ありません</b>。",
"translatedByTheCommunity": "Misskey Toolsはボランティアによって翻訳されています。",
"helpTranslation": "翻訳に協力する",
"announcements": "お知らせ",
"_welcomeMessage": {
"pattern1": "ついついノートしすぎていませんか?",
"pattern2": "Misskey, しすぎていませんか?",
"pattern3": "今日、何ノート書いた?",
"pattern4": "10000 ノートは初心者、そう思っていませんか?",
"pattern5": "息するように Misskey、そんなあなたへ。",
"pattern6": "あなたは真の Misskey 廃人ですか?"
},
"_welcome": {
"title": "プロ仕様のツールキット",
"description": "Misskey Toolsでは、Misskeyのために設計された、Misskeyをより楽しめるツールを取り揃えています。",
"misshaiAlertTitle": "ミス廃アラート",
"misshaiAlertDescription": "Misskeyにのめり込んでいませんかミス廃アラートを使えば、毎日のMisskeyでの活動量を以下のように定期投稿できます。",
"misshaiRankingDescription": "ミス廃ランキングでは、Misskeyでの活動を数値化し、ランキング表示します。",
"nextFeaturesTitle": "今後も追加予定。",
"nextFeaturesDescription": "これだけではありません。今後もアップデートで様々な機能を追加します!"
},
"_nav": {
"misshai": "ミス廃",
"accounts": "アカウント",
"settings": "設定"
},
"_missHai": {
"ranking": "ミス廃ランキング",
"rankingDescription": "ユーザーの「みす廃レート」を算出し、高い順にランキング表示しています。",
"showAll": "全員分見る",
"data": "みす廃データ",
"dataBody": "内容",
"dataScore": "スコア",
"dataDelta": "前日比",
"rating": "レート",
"order": "順位",
"showRanking": "ランキングを見る"
},
"_accounts": {
"currentAccount": "現在ログインしているアカウント",
"switchAccount": "アカウント切り替え",
"useAnother": "他のアカウントで登録する"
},
"_developerInfo": {
"title": "開発者",
"description": "何か困ったことがあったら、以下のアカウントにメッセージを送ってください。"
},
"_timeline": {
"title": "タイムライン",
"description": "{{hashtag}} タグを含む最新ノートを表示します。"
},
"_alertMode": {
"note": "自動的にノートを投稿",
"notification": "Misskeyに通知(標準)",
"nothing": "通知しない",
"notificationWarning": "「Misskey に通知」オプションは古いMisskeyでは動作しません。"
},
"_visibility": {
"public": "パブリック",
"home": "ホーム",
"followers": "フォロワー",
"users": "ログインユーザー"
},
"_themes": {
"light": "ライトテーマ",
"dark": "ダークテーマ",
"system": "システム設定に準じる"
},
"_template": {
"description": "アラートの自動投稿をカスタマイズできます。",
"description2": "ハッシュタグ #misshaialert は、テンプレートに関わらず自動付与されます。",
"default": "昨日のMisskeyの活動は\n\nート: {notesCount}({notesDelta})\nフォロー : {followingCount}({followingDelta})\nフォロワー :{followersCount}({followersDelta})\n\nでした。\n{url}",
"insertVariables": "変数を挿入する",
"insertVariablesHelp": "{ } で囲われた文字列は変数と呼ばれ、特別な意味を持ちます。これを含めると、投稿時に自動的に値が埋め込まれます。",
"_variables": {
"notesCount": "ノート数",
"followingCount": "フォロー数",
"followersCount": "フォロワー数",
"notesDelta": "ノート数の前日比",
"followingDelta": "フォロー数の前日比",
"followersDelta": "フォロワー数の前日比",
"url": "本サイトのURL",
"username": "アカウントのユーザー名",
"host": "アカウントの所属ホスト名",
"rating": "レート"
}
},
"_error": {
"sorry": "問題が発生しました。お手数ですが、やり直してください。",
"additionalInfo": "追加情報: ",
"hitorisskeyIsDenied": "ひとりすきーは連携できません。",
"teapot": "I'm a teapot.",
"sessionRequired": "セッションがありません。",
"tokenRequired": "トークンがありません。",
"invalidParameter": "パラメータが不正です。",
"notAuthorized": "権限がありません。",
"other": "なし"
},
"_sendTest": {
"title": "アラートをテスト送信しますか?",
"message": "現在の設定でアラートを送信します。設定が保存済みであるかどうか、実行前に必ずご確認ください。",
"yes": "送信する",
"no": "キャンセル",
"success": "送信しました。",
"failure": "送信に失敗しました。"
},
"_logout": {
"title": "ログアウトしてもよろしいですか?",
"message": "ログアウトしても、アラート送信や、お使いのMisskeyアカウントのデータ収集といった機能は動作し続けます。Misskey Toolsの利用を停止したい場合は、「アカウント連携を解除する」ボタンを押下して下さい。",
"yes": "ログアウトする",
"no": "キャンセル"
},
"_deactivate": {
"title": "アカウント連携を解除しますか?",
"message": "収集されたデータや個人設定など、全てのデータが削除されます。この操作は取り消すことができません。",
"yes": "解除する",
"no": "キャンセル",
"success": "アカウントを解除しました。トップ画面に戻ります。",
"failure": "アカウントを解除できませんでした。"
}
}

View File

@ -0,0 +1,161 @@
{
"title": "Misskey Tools",
"description1": "Misskeyは楽しいものです。気がついたら1日中入り浸っていることも多いでしょう。",
"description2": "さあ、今すぐMisskey Toolsをインストールして、あなたの活動を把握しよう。",
"notes": "ノート",
"following": "フォロー",
"followers": "フォロワー",
"welcomeBack": "おかえりなさい、{{acct}}さん。",
"alertMode": "アラート送信方法",
"visibility": "公開範囲",
"appearance": "表示設定",
"template": "テンプレート",
"sendAlert": "アラートをテスト送信する",
"sendAlertDescription": "現在の設定を用いて、アラート送信をテストします。",
"sendAlertDisabled": "アラート送信方法が「通知しない」のため、送信をテストすることはできません。",
"logout": "ログアウトする",
"logoutDescription": "ログアウトしても、アラートは送信されます。",
"deleteAccount": "アカウント連携を解除する",
"deleteAccountDescription": "Misskey Toolsのアカウントを削除します。これにより、Misskeyとの連携設定も解除されます。",
"instanceUrl": "インスタンスURL",
"login": "ログイン",
"localOnly": "ローカルのみ",
"remoteFollowersOnly": "リモートフォロワーとローカル",
"help": "ヘルプ",
"save": "保存",
"theme": "テーマ",
"language": "言語",
"fetching": "取得中……",
"failedToFetch": "取得に失敗しました",
"registeredUsersCount": "登録者数",
"isCalculating": "現在算出中です。後ほどご確認ください!",
"ok": "OK",
"yes": "はい",
"no": "いいえ",
"termsOfService": "利用規約",
"name": "名前",
"resetToDefault": "初期値に戻す",
"error": "エラー",
"retry": "やり直す",
"saved": "保存しました。",
"disclaimerForMisskeyHq": "Misskey Toolsは、Misskey HQの公式ツールでは<b>ありません</b>。",
"translatedByTheCommunity": "Misskey Toolsはボランティアによって翻訳されています。",
"helpTranslation": "翻訳に協力する",
"announcements": "お知らせ",
"_welcomeMessage": {
"pattern1": "ついついノートしすぎていませんか?",
"pattern2": "Misskey, しすぎていませんか?",
"pattern3": "今日、何ノート書いた?",
"pattern4": "10000 ノートは初心者、そう思っていませんか?",
"pattern5": "息するように Misskey、そんなあなたへ。",
"pattern6": "あなたは真の Misskey 廃人ですか?"
},
"_welcome": {
"title": "プロ仕様のツールキット",
"description": "Misskey Toolsでは、Misskeyのために設計された、Misskeyをより楽しめるツールを取り揃えています。",
"misshaiAlertTitle": "ミス廃アラート",
"misshaiAlertDescription": "Misskeyにのめり込んでいませんかミス廃アラートを使えば、毎日のMisskeyでの活動量を以下のように定期投稿できます。",
"misshaiRankingDescription": "ミス廃ランキングでは、Misskeyでの活動を数値化し、ランキング表示します。",
"nextFeaturesTitle": "今後も追加予定。",
"nextFeaturesDescription": "これだけではありません。今後もアップデートで様々な機能を追加します!"
},
"_nav": {
"misshai": "ミス廃",
"accounts": "アカウント",
"settings": "設定"
},
"_missHai": {
"ranking": "ミス廃ランキング",
"rankingDescription": "ユーザーの「みす廃レート」を算出し、高い順にランキング表示しています。",
"showAll": "全員分見る",
"data": "みす廃データ",
"dataBody": "内容",
"dataScore": "スコア",
"dataDelta": "前日比",
"rating": "レート",
"order": "順位",
"showRanking": "ランキングを見る"
},
"_accounts": {
"currentAccount": "現在ログインしているアカウント",
"switchAccount": "アカウント切り替え",
"useAnother": "他のアカウントで登録する"
},
"_developerInfo": {
"title": "開発者",
"description": "何か困ったことがあったら、以下のアカウントにメッセージを送ってください。"
},
"_timeline": {
"title": "タイムライン",
"description": "{{hashtag}} タグを含む最新ノートを表示します。"
},
"_alertMode": {
"note": "自動的にノートを投稿",
"notification": "Misskeyに通知(標準)",
"nothing": "通知しない",
"notificationWarning": "「Misskey に通知」オプションは古いMisskeyでは動作しません。"
},
"_visibility": {
"public": "パブリック",
"home": "ホーム",
"followers": "フォロワー",
"users": "ログインユーザー"
},
"_themes": {
"light": "ライトテーマ",
"dark": "ダークテーマ",
"system": "システム設定に準じる"
},
"_template": {
"description": "アラートの自動投稿をカスタマイズできます。",
"description2": "ハッシュタグ #misshaialert は、テンプレートに関わらず自動付与されます。",
"default": "昨日のMisskeyの活動は\n\nート: {notesCount}({notesDelta})\nフォロー : {followingCount}({followingDelta})\nフォロワー :{followersCount}({followersDelta})\n\nでした。\n{url}",
"insertVariables": "変数を挿入する",
"insertVariablesHelp": "{ } で囲われた文字列は変数と呼ばれ、特別な意味を持ちます。これを含めると、投稿時に自動的に値が埋め込まれます。",
"_variables": {
"notesCount": "ノート数",
"followingCount": "フォロー数",
"followersCount": "フォロワー数",
"notesDelta": "ノート数の前日比",
"followingDelta": "フォロー数の前日比",
"followersDelta": "フォロワー数の前日比",
"url": "本サイトのURL",
"username": "アカウントのユーザー名",
"host": "アカウントの所属ホスト名",
"rating": "レート"
}
},
"_error": {
"sorry": "問題が発生しました。お手数ですが、やり直してください。",
"additionalInfo": "追加情報: ",
"hitorisskeyIsDenied": "ひとりすきーは連携できません。",
"teapot": "I'm a teapot.",
"sessionRequired": "セッションがありません。",
"tokenRequired": "トークンがありません。",
"invalidParameter": "パラメータが不正です。",
"notAuthorized": "権限がありません。",
"other": "なし"
},
"_sendTest": {
"title": "アラートをテスト送信しますか?",
"message": "現在の設定でアラートを送信します。設定が保存済みであるかどうか、実行前に必ずご確認ください。",
"yes": "送信する",
"no": "キャンセル",
"success": "送信しました。",
"failure": "送信に失敗しました。"
},
"_logout": {
"title": "ログアウトしてもよろしいですか?",
"message": "ログアウトしても、アラート送信や、お使いのMisskeyアカウントのデータ収集といった機能は動作し続けます。Misskey Toolsの利用を停止したい場合は、「アカウント連携を解除する」ボタンを押下して下さい。",
"yes": "ログアウトする",
"no": "キャンセル"
},
"_deactivate": {
"title": "アカウント連携を解除しますか?",
"message": "収集されたデータや個人設定など、全てのデータが削除されます。この操作は取り消すことができません。",
"yes": "解除する",
"no": "キャンセル",
"success": "アカウントを解除しました。トップ画面に戻ります。",
"failure": "アカウントを解除できませんでした。"
}
}

View File

@ -0,0 +1,161 @@
{
"title": "Misskey Tools",
"description1": "Misskeyは楽しいものです。気がついたら1日中入り浸っていることも多いでしょう。",
"description2": "さあ、今すぐMisskey Toolsをインストールして、あなたの活動を把握しよう。",
"notes": "ノート",
"following": "フォロー",
"followers": "フォロワー",
"welcomeBack": "おかえりなさい、{{acct}}さん。",
"alertMode": "アラート送信方法",
"visibility": "公開範囲",
"appearance": "表示設定",
"template": "テンプレート",
"sendAlert": "アラートをテスト送信する",
"sendAlertDescription": "現在の設定を用いて、アラート送信をテストします。",
"sendAlertDisabled": "アラート送信方法が「通知しない」のため、送信をテストすることはできません。",
"logout": "ログアウトする",
"logoutDescription": "ログアウトしても、アラートは送信されます。",
"deleteAccount": "アカウント連携を解除する",
"deleteAccountDescription": "Misskey Toolsのアカウントを削除します。これにより、Misskeyとの連携設定も解除されます。",
"instanceUrl": "インスタンスURL",
"login": "ログイン",
"localOnly": "ローカルのみ",
"remoteFollowersOnly": "リモートフォロワーとローカル",
"help": "ヘルプ",
"save": "保存",
"theme": "テーマ",
"language": "言語",
"fetching": "取得中……",
"failedToFetch": "取得に失敗しました",
"registeredUsersCount": "登録者数",
"isCalculating": "現在算出中です。後ほどご確認ください!",
"ok": "OK",
"yes": "はい",
"no": "いいえ",
"termsOfService": "利用規約",
"name": "名前",
"resetToDefault": "初期値に戻す",
"error": "エラー",
"retry": "やり直す",
"saved": "保存しました。",
"disclaimerForMisskeyHq": "Misskey Toolsは、Misskey HQの公式ツールでは<b>ありません</b>。",
"translatedByTheCommunity": "Misskey Toolsはボランティアによって翻訳されています。",
"helpTranslation": "翻訳に協力する",
"announcements": "お知らせ",
"_welcomeMessage": {
"pattern1": "ついついノートしすぎていませんか?",
"pattern2": "Misskey, しすぎていませんか?",
"pattern3": "今日、何ノート書いた?",
"pattern4": "10000 ノートは初心者、そう思っていませんか?",
"pattern5": "息するように Misskey、そんなあなたへ。",
"pattern6": "あなたは真の Misskey 廃人ですか?"
},
"_welcome": {
"title": "プロ仕様のツールキット",
"description": "Misskey Toolsでは、Misskeyのために設計された、Misskeyをより楽しめるツールを取り揃えています。",
"misshaiAlertTitle": "ミス廃アラート",
"misshaiAlertDescription": "Misskeyにのめり込んでいませんかミス廃アラートを使えば、毎日のMisskeyでの活動量を以下のように定期投稿できます。",
"misshaiRankingDescription": "ミス廃ランキングでは、Misskeyでの活動を数値化し、ランキング表示します。",
"nextFeaturesTitle": "今後も追加予定。",
"nextFeaturesDescription": "これだけではありません。今後もアップデートで様々な機能を追加します!"
},
"_nav": {
"misshai": "ミス廃",
"accounts": "アカウント",
"settings": "設定"
},
"_missHai": {
"ranking": "ミス廃ランキング",
"rankingDescription": "ユーザーの「みす廃レート」を算出し、高い順にランキング表示しています。",
"showAll": "全員分見る",
"data": "みす廃データ",
"dataBody": "内容",
"dataScore": "スコア",
"dataDelta": "前日比",
"rating": "レート",
"order": "順位",
"showRanking": "ランキングを見る"
},
"_accounts": {
"currentAccount": "現在ログインしているアカウント",
"switchAccount": "アカウント切り替え",
"useAnother": "他のアカウントで登録する"
},
"_developerInfo": {
"title": "開発者",
"description": "何か困ったことがあったら、以下のアカウントにメッセージを送ってください。"
},
"_timeline": {
"title": "タイムライン",
"description": "{{hashtag}} タグを含む最新ノートを表示します。"
},
"_alertMode": {
"note": "自動的にノートを投稿",
"notification": "Misskeyに通知(標準)",
"nothing": "通知しない",
"notificationWarning": "「Misskey に通知」オプションは古いMisskeyでは動作しません。"
},
"_visibility": {
"public": "パブリック",
"home": "ホーム",
"followers": "フォロワー",
"users": "ログインユーザー"
},
"_themes": {
"light": "ライトテーマ",
"dark": "ダークテーマ",
"system": "システム設定に準じる"
},
"_template": {
"description": "アラートの自動投稿をカスタマイズできます。",
"description2": "ハッシュタグ #misshaialert は、テンプレートに関わらず自動付与されます。",
"default": "昨日のMisskeyの活動は\n\nート: {notesCount}({notesDelta})\nフォロー : {followingCount}({followingDelta})\nフォロワー :{followersCount}({followersDelta})\n\nでした。\n{url}",
"insertVariables": "変数を挿入する",
"insertVariablesHelp": "{ } で囲われた文字列は変数と呼ばれ、特別な意味を持ちます。これを含めると、投稿時に自動的に値が埋め込まれます。",
"_variables": {
"notesCount": "ノート数",
"followingCount": "フォロー数",
"followersCount": "フォロワー数",
"notesDelta": "ノート数の前日比",
"followingDelta": "フォロー数の前日比",
"followersDelta": "フォロワー数の前日比",
"url": "本サイトのURL",
"username": "アカウントのユーザー名",
"host": "アカウントの所属ホスト名",
"rating": "レート"
}
},
"_error": {
"sorry": "問題が発生しました。お手数ですが、やり直してください。",
"additionalInfo": "追加情報: ",
"hitorisskeyIsDenied": "ひとりすきーは連携できません。",
"teapot": "I'm a teapot.",
"sessionRequired": "セッションがありません。",
"tokenRequired": "トークンがありません。",
"invalidParameter": "パラメータが不正です。",
"notAuthorized": "権限がありません。",
"other": "なし"
},
"_sendTest": {
"title": "アラートをテスト送信しますか?",
"message": "現在の設定でアラートを送信します。設定が保存済みであるかどうか、実行前に必ずご確認ください。",
"yes": "送信する",
"no": "キャンセル",
"success": "送信しました。",
"failure": "送信に失敗しました。"
},
"_logout": {
"title": "ログアウトしてもよろしいですか?",
"message": "ログアウトしても、アラート送信や、お使いのMisskeyアカウントのデータ収集といった機能は動作し続けます。Misskey Toolsの利用を停止したい場合は、「アカウント連携を解除する」ボタンを押下して下さい。",
"yes": "ログアウトする",
"no": "キャンセル"
},
"_deactivate": {
"title": "アカウント連携を解除しますか?",
"message": "収集されたデータや個人設定など、全てのデータが削除されます。この操作は取り消すことができません。",
"yes": "解除する",
"no": "キャンセル",
"success": "アカウントを解除しました。トップ画面に戻ります。",
"failure": "アカウントを解除できませんでした。"
}
}

View File

@ -0,0 +1,161 @@
{
"title": "Misskey Tools",
"description1": "Misskeyは楽しいものです。気がついたら1日中入り浸っていることも多いでしょう。",
"description2": "さあ、今すぐMisskey Toolsをインストールして、あなたの活動を把握しよう。",
"notes": "ノート",
"following": "フォロー",
"followers": "フォロワー",
"welcomeBack": "おかえりなさい、{{acct}}さん。",
"alertMode": "アラート送信方法",
"visibility": "公開範囲",
"appearance": "表示設定",
"template": "テンプレート",
"sendAlert": "アラートをテスト送信する",
"sendAlertDescription": "現在の設定を用いて、アラート送信をテストします。",
"sendAlertDisabled": "アラート送信方法が「通知しない」のため、送信をテストすることはできません。",
"logout": "ログアウトする",
"logoutDescription": "ログアウトしても、アラートは送信されます。",
"deleteAccount": "アカウント連携を解除する",
"deleteAccountDescription": "Misskey Toolsのアカウントを削除します。これにより、Misskeyとの連携設定も解除されます。",
"instanceUrl": "インスタンスURL",
"login": "ログイン",
"localOnly": "ローカルのみ",
"remoteFollowersOnly": "リモートフォロワーとローカル",
"help": "ヘルプ",
"save": "保存",
"theme": "テーマ",
"language": "言語",
"fetching": "取得中……",
"failedToFetch": "取得に失敗しました",
"registeredUsersCount": "登録者数",
"isCalculating": "現在算出中です。後ほどご確認ください!",
"ok": "OK",
"yes": "はい",
"no": "いいえ",
"termsOfService": "利用規約",
"name": "名前",
"resetToDefault": "初期値に戻す",
"error": "エラー",
"retry": "やり直す",
"saved": "保存しました。",
"disclaimerForMisskeyHq": "Misskey Toolsは、Misskey HQの公式ツールでは<b>ありません</b>。",
"translatedByTheCommunity": "Misskey Toolsはボランティアによって翻訳されています。",
"helpTranslation": "翻訳に協力する",
"announcements": "お知らせ",
"_welcomeMessage": {
"pattern1": "ついついノートしすぎていませんか?",
"pattern2": "Misskey, しすぎていませんか?",
"pattern3": "今日、何ノート書いた?",
"pattern4": "10000 ノートは初心者、そう思っていませんか?",
"pattern5": "息するように Misskey、そんなあなたへ。",
"pattern6": "あなたは真の Misskey 廃人ですか?"
},
"_welcome": {
"title": "プロ仕様のツールキット",
"description": "Misskey Toolsでは、Misskeyのために設計された、Misskeyをより楽しめるツールを取り揃えています。",
"misshaiAlertTitle": "ミス廃アラート",
"misshaiAlertDescription": "Misskeyにのめり込んでいませんかミス廃アラートを使えば、毎日のMisskeyでの活動量を以下のように定期投稿できます。",
"misshaiRankingDescription": "ミス廃ランキングでは、Misskeyでの活動を数値化し、ランキング表示します。",
"nextFeaturesTitle": "今後も追加予定。",
"nextFeaturesDescription": "これだけではありません。今後もアップデートで様々な機能を追加します!"
},
"_nav": {
"misshai": "ミス廃",
"accounts": "アカウント",
"settings": "設定"
},
"_missHai": {
"ranking": "ミス廃ランキング",
"rankingDescription": "ユーザーの「みす廃レート」を算出し、高い順にランキング表示しています。",
"showAll": "全員分見る",
"data": "みす廃データ",
"dataBody": "内容",
"dataScore": "スコア",
"dataDelta": "前日比",
"rating": "レート",
"order": "順位",
"showRanking": "ランキングを見る"
},
"_accounts": {
"currentAccount": "現在ログインしているアカウント",
"switchAccount": "アカウント切り替え",
"useAnother": "他のアカウントで登録する"
},
"_developerInfo": {
"title": "開発者",
"description": "何か困ったことがあったら、以下のアカウントにメッセージを送ってください。"
},
"_timeline": {
"title": "タイムライン",
"description": "{{hashtag}} タグを含む最新ノートを表示します。"
},
"_alertMode": {
"note": "自動的にノートを投稿",
"notification": "Misskeyに通知(標準)",
"nothing": "通知しない",
"notificationWarning": "「Misskey に通知」オプションは古いMisskeyでは動作しません。"
},
"_visibility": {
"public": "パブリック",
"home": "ホーム",
"followers": "フォロワー",
"users": "ログインユーザー"
},
"_themes": {
"light": "ライトテーマ",
"dark": "ダークテーマ",
"system": "システム設定に準じる"
},
"_template": {
"description": "アラートの自動投稿をカスタマイズできます。",
"description2": "ハッシュタグ #misshaialert は、テンプレートに関わらず自動付与されます。",
"default": "昨日のMisskeyの活動は\n\nート: {notesCount}({notesDelta})\nフォロー : {followingCount}({followingDelta})\nフォロワー :{followersCount}({followersDelta})\n\nでした。\n{url}",
"insertVariables": "変数を挿入する",
"insertVariablesHelp": "{ } で囲われた文字列は変数と呼ばれ、特別な意味を持ちます。これを含めると、投稿時に自動的に値が埋め込まれます。",
"_variables": {
"notesCount": "ノート数",
"followingCount": "フォロー数",
"followersCount": "フォロワー数",
"notesDelta": "ノート数の前日比",
"followingDelta": "フォロー数の前日比",
"followersDelta": "フォロワー数の前日比",
"url": "本サイトのURL",
"username": "アカウントのユーザー名",
"host": "アカウントの所属ホスト名",
"rating": "レート"
}
},
"_error": {
"sorry": "問題が発生しました。お手数ですが、やり直してください。",
"additionalInfo": "追加情報: ",
"hitorisskeyIsDenied": "ひとりすきーは連携できません。",
"teapot": "I'm a teapot.",
"sessionRequired": "セッションがありません。",
"tokenRequired": "トークンがありません。",
"invalidParameter": "パラメータが不正です。",
"notAuthorized": "権限がありません。",
"other": "なし"
},
"_sendTest": {
"title": "アラートをテスト送信しますか?",
"message": "現在の設定でアラートを送信します。設定が保存済みであるかどうか、実行前に必ずご確認ください。",
"yes": "送信する",
"no": "キャンセル",
"success": "送信しました。",
"failure": "送信に失敗しました。"
},
"_logout": {
"title": "ログアウトしてもよろしいですか?",
"message": "ログアウトしても、アラート送信や、お使いのMisskeyアカウントのデータ収集といった機能は動作し続けます。Misskey Toolsの利用を停止したい場合は、「アカウント連携を解除する」ボタンを押下して下さい。",
"yes": "ログアウトする",
"no": "キャンセル"
},
"_deactivate": {
"title": "アカウント連携を解除しますか?",
"message": "収集されたデータや個人設定など、全てのデータが削除されます。この操作は取り消すことができません。",
"yes": "解除する",
"no": "キャンセル",
"success": "アカウントを解除しました。トップ画面に戻ります。",
"failure": "アカウントを解除できませんでした。"
}
}

View File

@ -0,0 +1,19 @@
import enUS from './en-US.json';
import jaJP from './ja-JP.json';
export const resources = {
'en_US': { translation: enUS },
'ja_JP': { translation: jaJP },
};
export const languageName = {
'en_US': 'English',
'ja_JP': '日本語',
} as const;
export type LanguageCode = keyof typeof resources;
export const getBrowserLanguage = () => {
const lang = navigator.language;
return (Object.keys(resources) as LanguageCode[]).find(k => k.startsWith(lang)) ?? 'en_US';
};

View File

@ -0,0 +1,161 @@
{
"title": "Misskey Tools",
"description1": "Misskeyは楽しいものです。気がついたら1日中入り浸っていることも多いでしょう。",
"description2": "さあ、今すぐMisskey Toolsをインストールして、あなたの活動を把握しよう。",
"notes": "ノート",
"following": "フォロー",
"followers": "フォロワー",
"welcomeBack": "おかえりなさい、{{acct}}さん。",
"alertMode": "アラート送信方法",
"visibility": "公開範囲",
"appearance": "表示設定",
"template": "テンプレート",
"sendAlert": "アラートをテスト送信する",
"sendAlertDescription": "現在の設定を用いて、アラート送信をテストします。",
"sendAlertDisabled": "アラート送信方法が「通知しない」のため、送信をテストすることはできません。",
"logout": "ログアウトする",
"logoutDescription": "ログアウトしても、アラートは送信されます。",
"deleteAccount": "アカウント連携を解除する",
"deleteAccountDescription": "Misskey Toolsのアカウントを削除します。これにより、Misskeyとの連携設定も解除されます。",
"instanceUrl": "インスタンスURL",
"login": "ログイン",
"localOnly": "ローカルのみ",
"remoteFollowersOnly": "リモートフォロワーとローカル",
"help": "ヘルプ",
"save": "保存",
"theme": "テーマ",
"language": "言語",
"fetching": "取得中……",
"failedToFetch": "取得に失敗しました",
"registeredUsersCount": "登録者数",
"isCalculating": "現在算出中です。後ほどご確認ください!",
"ok": "OK",
"yes": "はい",
"no": "いいえ",
"termsOfService": "利用規約",
"name": "名前",
"resetToDefault": "初期値に戻す",
"error": "エラー",
"retry": "やり直す",
"saved": "保存しました。",
"disclaimerForMisskeyHq": "Misskey Toolsは、Misskey HQの公式ツールでは<b>ありません</b>。",
"translatedByTheCommunity": "Misskey Toolsはボランティアによって翻訳されています。",
"helpTranslation": "翻訳に協力する",
"announcements": "お知らせ",
"_welcomeMessage": {
"pattern1": "ついついノートしすぎていませんか?",
"pattern2": "Misskey, しすぎていませんか?",
"pattern3": "今日、何ノート書いた?",
"pattern4": "10000 ノートは初心者、そう思っていませんか?",
"pattern5": "息するように Misskey、そんなあなたへ。",
"pattern6": "あなたは真の Misskey 廃人ですか?"
},
"_welcome": {
"title": "プロ仕様のツールキット",
"description": "Misskey Toolsでは、Misskeyのために設計された、Misskeyをより楽しめるツールを取り揃えています。",
"misshaiAlertTitle": "ミス廃アラート",
"misshaiAlertDescription": "Misskeyにのめり込んでいませんかミス廃アラートを使えば、毎日のMisskeyでの活動量を以下のように定期投稿できます。",
"misshaiRankingDescription": "ミス廃ランキングでは、Misskeyでの活動を数値化し、ランキング表示します。",
"nextFeaturesTitle": "今後も追加予定。",
"nextFeaturesDescription": "これだけではありません。今後もアップデートで様々な機能を追加します!"
},
"_nav": {
"misshai": "ミス廃",
"accounts": "アカウント",
"settings": "設定"
},
"_missHai": {
"ranking": "ミス廃ランキング",
"rankingDescription": "ユーザーの「みす廃レート」を算出し、高い順にランキング表示しています。",
"showAll": "全員分見る",
"data": "みす廃データ",
"dataBody": "内容",
"dataScore": "スコア",
"dataDelta": "前日比",
"rating": "レート",
"order": "順位",
"showRanking": "ランキングを見る"
},
"_accounts": {
"currentAccount": "現在ログインしているアカウント",
"switchAccount": "アカウント切り替え",
"useAnother": "他のアカウントで登録する"
},
"_developerInfo": {
"title": "開発者",
"description": "何か困ったことがあったら、以下のアカウントにメッセージを送ってください。"
},
"_timeline": {
"title": "タイムライン",
"description": "{{hashtag}} タグを含む最新ノートを表示します。"
},
"_alertMode": {
"note": "自動的にノートを投稿",
"notification": "Misskeyに通知(標準)",
"nothing": "通知しない",
"notificationWarning": "「Misskey に通知」オプションは古いMisskeyでは動作しません。"
},
"_visibility": {
"public": "パブリック",
"home": "ホーム",
"followers": "フォロワー",
"users": "ログインユーザー"
},
"_themes": {
"light": "ライトテーマ",
"dark": "ダークテーマ",
"system": "システム設定に準じる"
},
"_template": {
"description": "アラートの自動投稿をカスタマイズできます。",
"description2": "ハッシュタグ #misshaialert は、テンプレートに関わらず自動付与されます。",
"default": "昨日のMisskeyの活動は\n\nート: {notesCount}({notesDelta})\nフォロー : {followingCount}({followingDelta})\nフォロワー :{followersCount}({followersDelta})\n\nでした。\n{url}",
"insertVariables": "変数を挿入する",
"insertVariablesHelp": "{ } で囲われた文字列は変数と呼ばれ、特別な意味を持ちます。これを含めると、投稿時に自動的に値が埋め込まれます。",
"_variables": {
"notesCount": "ノート数",
"followingCount": "フォロー数",
"followersCount": "フォロワー数",
"notesDelta": "ノート数の前日比",
"followingDelta": "フォロー数の前日比",
"followersDelta": "フォロワー数の前日比",
"url": "本サイトのURL",
"username": "アカウントのユーザー名",
"host": "アカウントの所属ホスト名",
"rating": "レート"
}
},
"_error": {
"sorry": "問題が発生しました。お手数ですが、やり直してください。",
"additionalInfo": "追加情報: ",
"hitorisskeyIsDenied": "ひとりすきーは連携できません。",
"teapot": "I'm a teapot.",
"sessionRequired": "セッションがありません。",
"tokenRequired": "トークンがありません。",
"invalidParameter": "パラメータが不正です。",
"notAuthorized": "権限がありません。",
"other": "なし"
},
"_sendTest": {
"title": "アラートをテスト送信しますか?",
"message": "現在の設定でアラートを送信します。設定が保存済みであるかどうか、実行前に必ずご確認ください。",
"yes": "送信する",
"no": "キャンセル",
"success": "送信しました。",
"failure": "送信に失敗しました。"
},
"_logout": {
"title": "ログアウトしてもよろしいですか?",
"message": "ログアウトしても、アラート送信や、お使いのMisskeyアカウントのデータ収集といった機能は動作し続けます。Misskey Toolsの利用を停止したい場合は、「アカウント連携を解除する」ボタンを押下して下さい。",
"yes": "ログアウトする",
"no": "キャンセル"
},
"_deactivate": {
"title": "アカウント連携を解除しますか?",
"message": "収集されたデータや個人設定など、全てのデータが削除されます。この操作は取り消すことができません。",
"yes": "解除する",
"no": "キャンセル",
"success": "アカウントを解除しました。トップ画面に戻ります。",
"failure": "アカウントを解除できませんでした。"
}
}

View File

@ -0,0 +1,161 @@
{
"title": "Misskey Tools",
"description1": "Misskeyをもっと効果的に。様々な機能を持ったオールインワンツール。",
"description2": "お使いのインスタンスURLを入力して、今すぐMisskey Toolsを使おう",
"notes": "ノート",
"following": "フォロー",
"followers": "フォロワー",
"welcomeBack": "おかえりなさい、{{acct}}さん。",
"alertMode": "アラート送信方法",
"visibility": "公開範囲",
"appearance": "表示設定",
"template": "テンプレート",
"sendAlert": "アラートをテスト送信する",
"sendAlertDescription": "現在の設定を用いて、アラート送信をテストします。",
"sendAlertDisabled": "アラート送信方法が「通知しない」のため、送信をテストすることはできません。",
"logout": "ログアウトする",
"logoutDescription": "ログアウトしても、アラートは送信されます。",
"deleteAccount": "アカウント連携を解除する",
"deleteAccountDescription": "Misskey Toolsのアカウントを削除します。これにより、Misskeyとの連携設定も解除されます。",
"instanceUrl": "インスタンスURL",
"login": "ログイン",
"localOnly": "ローカルのみ",
"remoteFollowersOnly": "リモートフォロワーとローカル",
"help": "ヘルプ",
"save": "保存",
"theme": "テーマ",
"language": "言語",
"fetching": "取得中……",
"failedToFetch": "取得に失敗しました",
"registeredUsersCount": "登録者数",
"isCalculating": "現在算出中です。後ほどご確認ください!",
"ok": "OK",
"yes": "はい",
"no": "いいえ",
"termsOfService": "利用規約",
"name": "名前",
"resetToDefault": "初期値に戻す",
"error": "エラー",
"retry": "やり直す",
"saved": "保存しました。",
"disclaimerForMisskeyHq": "Misskey Toolsは、Misskey HQの公式ツールでは<b>ありません</b>。",
"translatedByTheCommunity": "Misskey Toolsはボランティアによって翻訳されています。",
"helpTranslation": "翻訳に協力する",
"announcements": "お知らせ",
"_welcomeMessage": {
"pattern1": "ついついノートしすぎていませんか?",
"pattern2": "Misskey, しすぎていませんか?",
"pattern3": "今日、何ノート書いた?",
"pattern4": "10000 ノートは初心者、そう思っていませんか?",
"pattern5": "息するように Misskey、そんなあなたへ。",
"pattern6": "あなたは真の Misskey 廃人ですか?"
},
"_welcome": {
"title": "プロ仕様のツールキット",
"description": "Misskey Toolsでは、Misskeyのために設計された、Misskeyをより楽しめるツールを取り揃えています。",
"misshaiAlertTitle": "ミス廃アラート",
"misshaiAlertDescription": "Misskeyにのめり込んでいませんかミス廃アラートを使えば、毎日のMisskeyでの活動量を以下のように定期投稿できます。",
"misshaiRankingDescription": "ミス廃ランキングでは、Misskeyでの活動を数値化し、ランキング表示します。",
"nextFeaturesTitle": "今後も追加予定。",
"nextFeaturesDescription": "これだけではありません。今後もアップデートで様々な機能を追加します!"
},
"_nav": {
"misshai": "ミス廃",
"accounts": "アカウント",
"settings": "設定"
},
"_missHai": {
"ranking": "ミス廃ランキング",
"rankingDescription": "ユーザーの「ミス廃レート」を算出し、高い順にランキング表示しています。",
"showAll": "全員分見る",
"data": "ミス廃データ",
"dataBody": "内容",
"dataScore": "スコア",
"dataDelta": "前日比",
"rating": "レート",
"order": "順位",
"showRanking": "ランキングを見る"
},
"_accounts": {
"currentAccount": "現在ログインしているアカウント",
"switchAccount": "アカウント切り替え",
"useAnother": "他のアカウントで登録する"
},
"_developerInfo": {
"title": "開発者",
"description": "何か困ったことがあったら、以下のアカウントにメッセージを送ってください。"
},
"_timeline": {
"title": "タイムライン",
"description": "{{hashtag}} タグを含む最新ノートを表示します。"
},
"_alertMode": {
"note": "自動的にノートを投稿",
"notification": "Misskeyに通知(標準)",
"nothing": "通知しない",
"notificationWarning": "「Misskey に通知」オプションは古いMisskeyでは動作しません。"
},
"_visibility": {
"public": "パブリック",
"home": "ホーム",
"followers": "フォロワー",
"users": "ログインユーザー"
},
"_themes": {
"light": "ライトテーマ",
"dark": "ダークテーマ",
"system": "システム設定に準じる"
},
"_template": {
"description": "アラートの自動投稿をカスタマイズできます。",
"description2": "ハッシュタグ #misshaialert は、テンプレートに関わらず自動付与されます。",
"default": "昨日のMisskeyの活動は\n\nート: {notesCount}({notesDelta})\nフォロー : {followingCount}({followingDelta})\nフォロワー :{followersCount}({followersDelta})\n\nでした。\n{url}",
"insertVariables": "変数を挿入する",
"insertVariablesHelp": "{ } で囲われた文字列は変数と呼ばれ、特別な意味を持ちます。これを含めると、投稿時に自動的に値が埋め込まれます。",
"_variables": {
"notesCount": "ノート数",
"followingCount": "フォロー数",
"followersCount": "フォロワー数",
"notesDelta": "ノート数の前日比",
"followingDelta": "フォロー数の前日比",
"followersDelta": "フォロワー数の前日比",
"url": "本サイトのURL",
"username": "アカウントのユーザー名",
"host": "アカウントの所属ホスト名",
"rating": "レート"
}
},
"_error": {
"sorry": "問題が発生しました。お手数ですが、やり直してください。",
"additionalInfo": "追加情報: ",
"hitorisskeyIsDenied": "ひとりすきーは連携できません。",
"teapot": "I'm a teapot.",
"sessionRequired": "セッションがありません。",
"tokenRequired": "トークンがありません。",
"invalidParameter": "パラメータが不正です。",
"notAuthorized": "権限がありません。",
"other": "なし"
},
"_sendTest": {
"title": "アラートをテスト送信しますか?",
"message": "現在の設定でアラートを送信します。設定が保存済みであるかどうか、実行前に必ずご確認ください。",
"yes": "送信する",
"no": "キャンセル",
"success": "送信しました。",
"failure": "送信に失敗しました。"
},
"_logout": {
"title": "ログアウトしてもよろしいですか?",
"message": "ログアウトしても、アラート送信や、お使いのMisskeyアカウントのデータ収集といった機能は動作し続けます。Misskey Toolsの利用を停止したい場合は、「アカウント連携を解除する」ボタンを押下して下さい。",
"yes": "ログアウトする",
"no": "キャンセル"
},
"_deactivate": {
"title": "アカウント連携を解除しますか?",
"message": "収集されたデータや個人設定など、全てのデータが削除されます。この操作は取り消すことができません。",
"yes": "解除する",
"no": "キャンセル",
"success": "アカウントを解除しました。トップ画面に戻ります。",
"failure": "アカウントを解除できませんでした。"
}
}

View File

@ -0,0 +1,161 @@
{
"title": "Misskey Tools",
"description1": "Misskeyは楽しいものです。気がついたら1日中入り浸っていることも多いでしょう。",
"description2": "さあ、今すぐMisskey Toolsをインストールして、あなたの活動を把握しよう。",
"notes": "ノート",
"following": "フォロー",
"followers": "フォロワー",
"welcomeBack": "おかえりなさい、{{acct}}さん。",
"alertMode": "アラート送信方法",
"visibility": "公開範囲",
"appearance": "表示設定",
"template": "テンプレート",
"sendAlert": "アラートをテスト送信する",
"sendAlertDescription": "現在の設定を用いて、アラート送信をテストします。",
"sendAlertDisabled": "アラート送信方法が「通知しない」のため、送信をテストすることはできません。",
"logout": "ログアウトする",
"logoutDescription": "ログアウトしても、アラートは送信されます。",
"deleteAccount": "アカウント連携を解除する",
"deleteAccountDescription": "Misskey Toolsのアカウントを削除します。これにより、Misskeyとの連携設定も解除されます。",
"instanceUrl": "インスタンスURL",
"login": "ログイン",
"localOnly": "ローカルのみ",
"remoteFollowersOnly": "リモートフォロワーとローカル",
"help": "ヘルプ",
"save": "保存",
"theme": "テーマ",
"language": "言語",
"fetching": "取得中……",
"failedToFetch": "取得に失敗しました",
"registeredUsersCount": "登録者数",
"isCalculating": "現在算出中です。後ほどご確認ください!",
"ok": "OK",
"yes": "はい",
"no": "いいえ",
"termsOfService": "利用規約",
"name": "名前",
"resetToDefault": "初期値に戻す",
"error": "エラー",
"retry": "やり直す",
"saved": "保存しました。",
"disclaimerForMisskeyHq": "Misskey Toolsは、Misskey HQの公式ツールでは<b>ありません</b>。",
"translatedByTheCommunity": "Misskey Toolsはボランティアによって翻訳されています。",
"helpTranslation": "翻訳に協力する",
"announcements": "お知らせ",
"_welcomeMessage": {
"pattern1": "ついついノートしすぎていませんか?",
"pattern2": "Misskey, しすぎていませんか?",
"pattern3": "今日、何ノート書いた?",
"pattern4": "10000 ノートは初心者、そう思っていませんか?",
"pattern5": "息するように Misskey、そんなあなたへ。",
"pattern6": "あなたは真の Misskey 廃人ですか?"
},
"_welcome": {
"title": "プロ仕様のツールキット",
"description": "Misskey Toolsでは、Misskeyのために設計された、Misskeyをより楽しめるツールを取り揃えています。",
"misshaiAlertTitle": "ミス廃アラート",
"misshaiAlertDescription": "Misskeyにのめり込んでいませんかミス廃アラートを使えば、毎日のMisskeyでの活動量を以下のように定期投稿できます。",
"misshaiRankingDescription": "ミス廃ランキングでは、Misskeyでの活動を数値化し、ランキング表示します。",
"nextFeaturesTitle": "今後も追加予定。",
"nextFeaturesDescription": "これだけではありません。今後もアップデートで様々な機能を追加します!"
},
"_nav": {
"misshai": "ミス廃",
"accounts": "アカウント",
"settings": "設定"
},
"_missHai": {
"ranking": "ミス廃ランキング",
"rankingDescription": "ユーザーの「みす廃レート」を算出し、高い順にランキング表示しています。",
"showAll": "全員分見る",
"data": "みす廃データ",
"dataBody": "内容",
"dataScore": "スコア",
"dataDelta": "前日比",
"rating": "レート",
"order": "順位",
"showRanking": "ランキングを見る"
},
"_accounts": {
"currentAccount": "現在ログインしているアカウント",
"switchAccount": "アカウント切り替え",
"useAnother": "他のアカウントで登録する"
},
"_developerInfo": {
"title": "開発者",
"description": "何か困ったことがあったら、以下のアカウントにメッセージを送ってください。"
},
"_timeline": {
"title": "タイムライン",
"description": "{{hashtag}} タグを含む最新ノートを表示します。"
},
"_alertMode": {
"note": "自動的にノートを投稿",
"notification": "Misskeyに通知(標準)",
"nothing": "通知しない",
"notificationWarning": "「Misskey に通知」オプションは古いMisskeyでは動作しません。"
},
"_visibility": {
"public": "パブリック",
"home": "ホーム",
"followers": "フォロワー",
"users": "ログインユーザー"
},
"_themes": {
"light": "ライトテーマ",
"dark": "ダークテーマ",
"system": "システム設定に準じる"
},
"_template": {
"description": "アラートの自動投稿をカスタマイズできます。",
"description2": "ハッシュタグ #misshaialert は、テンプレートに関わらず自動付与されます。",
"default": "昨日のMisskeyの活動は\n\nート: {notesCount}({notesDelta})\nフォロー : {followingCount}({followingDelta})\nフォロワー :{followersCount}({followersDelta})\n\nでした。\n{url}",
"insertVariables": "変数を挿入する",
"insertVariablesHelp": "{ } で囲われた文字列は変数と呼ばれ、特別な意味を持ちます。これを含めると、投稿時に自動的に値が埋め込まれます。",
"_variables": {
"notesCount": "ノート数",
"followingCount": "フォロー数",
"followersCount": "フォロワー数",
"notesDelta": "ノート数の前日比",
"followingDelta": "フォロー数の前日比",
"followersDelta": "フォロワー数の前日比",
"url": "本サイトのURL",
"username": "アカウントのユーザー名",
"host": "アカウントの所属ホスト名",
"rating": "レート"
}
},
"_error": {
"sorry": "問題が発生しました。お手数ですが、やり直してください。",
"additionalInfo": "追加情報: ",
"hitorisskeyIsDenied": "ひとりすきーは連携できません。",
"teapot": "I'm a teapot.",
"sessionRequired": "セッションがありません。",
"tokenRequired": "トークンがありません。",
"invalidParameter": "パラメータが不正です。",
"notAuthorized": "権限がありません。",
"other": "なし"
},
"_sendTest": {
"title": "アラートをテスト送信しますか?",
"message": "現在の設定でアラートを送信します。設定が保存済みであるかどうか、実行前に必ずご確認ください。",
"yes": "送信する",
"no": "キャンセル",
"success": "送信しました。",
"failure": "送信に失敗しました。"
},
"_logout": {
"title": "ログアウトしてもよろしいですか?",
"message": "ログアウトしても、アラート送信や、お使いのMisskeyアカウントのデータ収集といった機能は動作し続けます。Misskey Toolsの利用を停止したい場合は、「アカウント連携を解除する」ボタンを押下して下さい。",
"yes": "ログアウトする",
"no": "キャンセル"
},
"_deactivate": {
"title": "アカウント連携を解除しますか?",
"message": "収集されたデータや個人設定など、全てのデータが削除されます。この操作は取り消すことができません。",
"yes": "解除する",
"no": "キャンセル",
"success": "アカウントを解除しました。トップ画面に戻ります。",
"failure": "アカウントを解除できませんでした。"
}
}

View File

@ -0,0 +1,161 @@
{
"title": "Misskey Tools",
"description1": "Misskeyは楽しいものです。気がついたら1日中入り浸っていることも多いでしょう。",
"description2": "さあ、今すぐMisskey Toolsをインストールして、あなたの活動を把握しよう。",
"notes": "ノート",
"following": "フォロー",
"followers": "フォロワー",
"welcomeBack": "おかえりなさい、{{acct}}さん。",
"alertMode": "アラート送信方法",
"visibility": "公開範囲",
"appearance": "表示設定",
"template": "テンプレート",
"sendAlert": "アラートをテスト送信する",
"sendAlertDescription": "現在の設定を用いて、アラート送信をテストします。",
"sendAlertDisabled": "アラート送信方法が「通知しない」のため、送信をテストすることはできません。",
"logout": "ログアウトする",
"logoutDescription": "ログアウトしても、アラートは送信されます。",
"deleteAccount": "アカウント連携を解除する",
"deleteAccountDescription": "Misskey Toolsのアカウントを削除します。これにより、Misskeyとの連携設定も解除されます。",
"instanceUrl": "インスタンスURL",
"login": "ログイン",
"localOnly": "ローカルのみ",
"remoteFollowersOnly": "リモートフォロワーとローカル",
"help": "ヘルプ",
"save": "保存",
"theme": "テーマ",
"language": "言語",
"fetching": "取得中……",
"failedToFetch": "取得に失敗しました",
"registeredUsersCount": "登録者数",
"isCalculating": "現在算出中です。後ほどご確認ください!",
"ok": "OK",
"yes": "はい",
"no": "いいえ",
"termsOfService": "利用規約",
"name": "名前",
"resetToDefault": "初期値に戻す",
"error": "エラー",
"retry": "やり直す",
"saved": "保存しました。",
"disclaimerForMisskeyHq": "Misskey Toolsは、Misskey HQの公式ツールでは<b>ありません</b>。",
"translatedByTheCommunity": "Misskey Toolsはボランティアによって翻訳されています。",
"helpTranslation": "翻訳に協力する",
"announcements": "お知らせ",
"_welcomeMessage": {
"pattern1": "ついついノートしすぎていませんか?",
"pattern2": "Misskey, しすぎていませんか?",
"pattern3": "今日、何ノート書いた?",
"pattern4": "10000 ノートは初心者、そう思っていませんか?",
"pattern5": "息するように Misskey、そんなあなたへ。",
"pattern6": "あなたは真の Misskey 廃人ですか?"
},
"_welcome": {
"title": "プロ仕様のツールキット",
"description": "Misskey Toolsでは、Misskeyのために設計された、Misskeyをより楽しめるツールを取り揃えています。",
"misshaiAlertTitle": "ミス廃アラート",
"misshaiAlertDescription": "Misskeyにのめり込んでいませんかミス廃アラートを使えば、毎日のMisskeyでの活動量を以下のように定期投稿できます。",
"misshaiRankingDescription": "ミス廃ランキングでは、Misskeyでの活動を数値化し、ランキング表示します。",
"nextFeaturesTitle": "今後も追加予定。",
"nextFeaturesDescription": "これだけではありません。今後もアップデートで様々な機能を追加します!"
},
"_nav": {
"misshai": "ミス廃",
"accounts": "アカウント",
"settings": "設定"
},
"_missHai": {
"ranking": "ミス廃ランキング",
"rankingDescription": "ユーザーの「みす廃レート」を算出し、高い順にランキング表示しています。",
"showAll": "全員分見る",
"data": "みす廃データ",
"dataBody": "内容",
"dataScore": "スコア",
"dataDelta": "前日比",
"rating": "レート",
"order": "順位",
"showRanking": "ランキングを見る"
},
"_accounts": {
"currentAccount": "現在ログインしているアカウント",
"switchAccount": "アカウント切り替え",
"useAnother": "他のアカウントで登録する"
},
"_developerInfo": {
"title": "開発者",
"description": "何か困ったことがあったら、以下のアカウントにメッセージを送ってください。"
},
"_timeline": {
"title": "タイムライン",
"description": "{{hashtag}} タグを含む最新ノートを表示します。"
},
"_alertMode": {
"note": "自動的にノートを投稿",
"notification": "Misskeyに通知(標準)",
"nothing": "通知しない",
"notificationWarning": "「Misskey に通知」オプションは古いMisskeyでは動作しません。"
},
"_visibility": {
"public": "パブリック",
"home": "ホーム",
"followers": "フォロワー",
"users": "ログインユーザー"
},
"_themes": {
"light": "ライトテーマ",
"dark": "ダークテーマ",
"system": "システム設定に準じる"
},
"_template": {
"description": "アラートの自動投稿をカスタマイズできます。",
"description2": "ハッシュタグ #misshaialert は、テンプレートに関わらず自動付与されます。",
"default": "昨日のMisskeyの活動は\n\nート: {notesCount}({notesDelta})\nフォロー : {followingCount}({followingDelta})\nフォロワー :{followersCount}({followersDelta})\n\nでした。\n{url}",
"insertVariables": "変数を挿入する",
"insertVariablesHelp": "{ } で囲われた文字列は変数と呼ばれ、特別な意味を持ちます。これを含めると、投稿時に自動的に値が埋め込まれます。",
"_variables": {
"notesCount": "ノート数",
"followingCount": "フォロー数",
"followersCount": "フォロワー数",
"notesDelta": "ノート数の前日比",
"followingDelta": "フォロー数の前日比",
"followersDelta": "フォロワー数の前日比",
"url": "本サイトのURL",
"username": "アカウントのユーザー名",
"host": "アカウントの所属ホスト名",
"rating": "レート"
}
},
"_error": {
"sorry": "問題が発生しました。お手数ですが、やり直してください。",
"additionalInfo": "追加情報: ",
"hitorisskeyIsDenied": "ひとりすきーは連携できません。",
"teapot": "I'm a teapot.",
"sessionRequired": "セッションがありません。",
"tokenRequired": "トークンがありません。",
"invalidParameter": "パラメータが不正です。",
"notAuthorized": "権限がありません。",
"other": "なし"
},
"_sendTest": {
"title": "アラートをテスト送信しますか?",
"message": "現在の設定でアラートを送信します。設定が保存済みであるかどうか、実行前に必ずご確認ください。",
"yes": "送信する",
"no": "キャンセル",
"success": "送信しました。",
"failure": "送信に失敗しました。"
},
"_logout": {
"title": "ログアウトしてもよろしいですか?",
"message": "ログアウトしても、アラート送信や、お使いのMisskeyアカウントのデータ収集といった機能は動作し続けます。Misskey Toolsの利用を停止したい場合は、「アカウント連携を解除する」ボタンを押下して下さい。",
"yes": "ログアウトする",
"no": "キャンセル"
},
"_deactivate": {
"title": "アカウント連携を解除しますか?",
"message": "収集されたデータや個人設定など、全てのデータが削除されます。この操作は取り消すことができません。",
"yes": "解除する",
"no": "キャンセル",
"success": "アカウントを解除しました。トップ画面に戻ります。",
"failure": "アカウントを解除できませんでした。"
}
}

View File

@ -0,0 +1,161 @@
{
"title": "Misskey Tools",
"description1": "Misskeyは楽しいものです。気がついたら1日中入り浸っていることも多いでしょう。",
"description2": "さあ、今すぐMisskey Toolsをインストールして、あなたの活動を把握しよう。",
"notes": "ノート",
"following": "フォロー",
"followers": "フォロワー",
"welcomeBack": "おかえりなさい、{{acct}}さん。",
"alertMode": "アラート送信方法",
"visibility": "公開範囲",
"appearance": "表示設定",
"template": "テンプレート",
"sendAlert": "アラートをテスト送信する",
"sendAlertDescription": "現在の設定を用いて、アラート送信をテストします。",
"sendAlertDisabled": "アラート送信方法が「通知しない」のため、送信をテストすることはできません。",
"logout": "ログアウトする",
"logoutDescription": "ログアウトしても、アラートは送信されます。",
"deleteAccount": "アカウント連携を解除する",
"deleteAccountDescription": "Misskey Toolsのアカウントを削除します。これにより、Misskeyとの連携設定も解除されます。",
"instanceUrl": "インスタンスURL",
"login": "ログイン",
"localOnly": "ローカルのみ",
"remoteFollowersOnly": "リモートフォロワーとローカル",
"help": "ヘルプ",
"save": "保存",
"theme": "テーマ",
"language": "言語",
"fetching": "取得中……",
"failedToFetch": "取得に失敗しました",
"registeredUsersCount": "登録者数",
"isCalculating": "現在算出中です。後ほどご確認ください!",
"ok": "OK",
"yes": "はい",
"no": "いいえ",
"termsOfService": "利用規約",
"name": "名前",
"resetToDefault": "初期値に戻す",
"error": "エラー",
"retry": "やり直す",
"saved": "保存しました。",
"disclaimerForMisskeyHq": "Misskey Toolsは、Misskey HQの公式ツールでは<b>ありません</b>。",
"translatedByTheCommunity": "Misskey Toolsはボランティアによって翻訳されています。",
"helpTranslation": "翻訳に協力する",
"announcements": "お知らせ",
"_welcomeMessage": {
"pattern1": "ついついノートしすぎていませんか?",
"pattern2": "Misskey, しすぎていませんか?",
"pattern3": "今日、何ノート書いた?",
"pattern4": "10000 ノートは初心者、そう思っていませんか?",
"pattern5": "息するように Misskey、そんなあなたへ。",
"pattern6": "あなたは真の Misskey 廃人ですか?"
},
"_welcome": {
"title": "プロ仕様のツールキット",
"description": "Misskey Toolsでは、Misskeyのために設計された、Misskeyをより楽しめるツールを取り揃えています。",
"misshaiAlertTitle": "ミス廃アラート",
"misshaiAlertDescription": "Misskeyにのめり込んでいませんかミス廃アラートを使えば、毎日のMisskeyでの活動量を以下のように定期投稿できます。",
"misshaiRankingDescription": "ミス廃ランキングでは、Misskeyでの活動を数値化し、ランキング表示します。",
"nextFeaturesTitle": "今後も追加予定。",
"nextFeaturesDescription": "これだけではありません。今後もアップデートで様々な機能を追加します!"
},
"_nav": {
"misshai": "ミス廃",
"accounts": "アカウント",
"settings": "設定"
},
"_missHai": {
"ranking": "ミス廃ランキング",
"rankingDescription": "ユーザーの「みす廃レート」を算出し、高い順にランキング表示しています。",
"showAll": "全員分見る",
"data": "みす廃データ",
"dataBody": "内容",
"dataScore": "スコア",
"dataDelta": "前日比",
"rating": "レート",
"order": "順位",
"showRanking": "ランキングを見る"
},
"_accounts": {
"currentAccount": "現在ログインしているアカウント",
"switchAccount": "アカウント切り替え",
"useAnother": "他のアカウントで登録する"
},
"_developerInfo": {
"title": "開発者",
"description": "何か困ったことがあったら、以下のアカウントにメッセージを送ってください。"
},
"_timeline": {
"title": "タイムライン",
"description": "{{hashtag}} タグを含む最新ノートを表示します。"
},
"_alertMode": {
"note": "自動的にノートを投稿",
"notification": "Misskeyに通知(標準)",
"nothing": "通知しない",
"notificationWarning": "「Misskey に通知」オプションは古いMisskeyでは動作しません。"
},
"_visibility": {
"public": "パブリック",
"home": "ホーム",
"followers": "フォロワー",
"users": "ログインユーザー"
},
"_themes": {
"light": "ライトテーマ",
"dark": "ダークテーマ",
"system": "システム設定に準じる"
},
"_template": {
"description": "アラートの自動投稿をカスタマイズできます。",
"description2": "ハッシュタグ #misshaialert は、テンプレートに関わらず自動付与されます。",
"default": "昨日のMisskeyの活動は\n\nート: {notesCount}({notesDelta})\nフォロー : {followingCount}({followingDelta})\nフォロワー :{followersCount}({followersDelta})\n\nでした。\n{url}",
"insertVariables": "変数を挿入する",
"insertVariablesHelp": "{ } で囲われた文字列は変数と呼ばれ、特別な意味を持ちます。これを含めると、投稿時に自動的に値が埋め込まれます。",
"_variables": {
"notesCount": "ノート数",
"followingCount": "フォロー数",
"followersCount": "フォロワー数",
"notesDelta": "ノート数の前日比",
"followingDelta": "フォロー数の前日比",
"followersDelta": "フォロワー数の前日比",
"url": "本サイトのURL",
"username": "アカウントのユーザー名",
"host": "アカウントの所属ホスト名",
"rating": "レート"
}
},
"_error": {
"sorry": "問題が発生しました。お手数ですが、やり直してください。",
"additionalInfo": "追加情報: ",
"hitorisskeyIsDenied": "ひとりすきーは連携できません。",
"teapot": "I'm a teapot.",
"sessionRequired": "セッションがありません。",
"tokenRequired": "トークンがありません。",
"invalidParameter": "パラメータが不正です。",
"notAuthorized": "権限がありません。",
"other": "なし"
},
"_sendTest": {
"title": "アラートをテスト送信しますか?",
"message": "現在の設定でアラートを送信します。設定が保存済みであるかどうか、実行前に必ずご確認ください。",
"yes": "送信する",
"no": "キャンセル",
"success": "送信しました。",
"failure": "送信に失敗しました。"
},
"_logout": {
"title": "ログアウトしてもよろしいですか?",
"message": "ログアウトしても、アラート送信や、お使いのMisskeyアカウントのデータ収集といった機能は動作し続けます。Misskey Toolsの利用を停止したい場合は、「アカウント連携を解除する」ボタンを押下して下さい。",
"yes": "ログアウトする",
"no": "キャンセル"
},
"_deactivate": {
"title": "アカウント連携を解除しますか?",
"message": "収集されたデータや個人設定など、全てのデータが削除されます。この操作は取り消すことができません。",
"yes": "解除する",
"no": "キャンセル",
"success": "アカウントを解除しました。トップ画面に戻ります。",
"failure": "アカウントを解除できませんでした。"
}
}

View File

@ -0,0 +1,161 @@
{
"title": "Misskey Tools",
"description1": "Misskeyは楽しいものです。気がついたら1日中入り浸っていることも多いでしょう。",
"description2": "さあ、今すぐMisskey Toolsをインストールして、あなたの活動を把握しよう。",
"notes": "ノート",
"following": "フォロー",
"followers": "フォロワー",
"welcomeBack": "おかえりなさい、{{acct}}さん。",
"alertMode": "アラート送信方法",
"visibility": "公開範囲",
"appearance": "表示設定",
"template": "テンプレート",
"sendAlert": "アラートをテスト送信する",
"sendAlertDescription": "現在の設定を用いて、アラート送信をテストします。",
"sendAlertDisabled": "アラート送信方法が「通知しない」のため、送信をテストすることはできません。",
"logout": "ログアウトする",
"logoutDescription": "ログアウトしても、アラートは送信されます。",
"deleteAccount": "アカウント連携を解除する",
"deleteAccountDescription": "Misskey Toolsのアカウントを削除します。これにより、Misskeyとの連携設定も解除されます。",
"instanceUrl": "インスタンスURL",
"login": "ログイン",
"localOnly": "ローカルのみ",
"remoteFollowersOnly": "リモートフォロワーとローカル",
"help": "ヘルプ",
"save": "保存",
"theme": "テーマ",
"language": "言語",
"fetching": "取得中……",
"failedToFetch": "取得に失敗しました",
"registeredUsersCount": "登録者数",
"isCalculating": "現在算出中です。後ほどご確認ください!",
"ok": "OK",
"yes": "はい",
"no": "いいえ",
"termsOfService": "利用規約",
"name": "名前",
"resetToDefault": "初期値に戻す",
"error": "エラー",
"retry": "やり直す",
"saved": "保存しました。",
"disclaimerForMisskeyHq": "Misskey Toolsは、Misskey HQの公式ツールでは<b>ありません</b>。",
"translatedByTheCommunity": "Misskey Toolsはボランティアによって翻訳されています。",
"helpTranslation": "翻訳に協力する",
"announcements": "お知らせ",
"_welcomeMessage": {
"pattern1": "ついついノートしすぎていませんか?",
"pattern2": "Misskey, しすぎていませんか?",
"pattern3": "今日、何ノート書いた?",
"pattern4": "10000 ノートは初心者、そう思っていませんか?",
"pattern5": "息するように Misskey、そんなあなたへ。",
"pattern6": "あなたは真の Misskey 廃人ですか?"
},
"_welcome": {
"title": "プロ仕様のツールキット",
"description": "Misskey Toolsでは、Misskeyのために設計された、Misskeyをより楽しめるツールを取り揃えています。",
"misshaiAlertTitle": "ミス廃アラート",
"misshaiAlertDescription": "Misskeyにのめり込んでいませんかミス廃アラートを使えば、毎日のMisskeyでの活動量を以下のように定期投稿できます。",
"misshaiRankingDescription": "ミス廃ランキングでは、Misskeyでの活動を数値化し、ランキング表示します。",
"nextFeaturesTitle": "今後も追加予定。",
"nextFeaturesDescription": "これだけではありません。今後もアップデートで様々な機能を追加します!"
},
"_nav": {
"misshai": "ミス廃",
"accounts": "アカウント",
"settings": "設定"
},
"_missHai": {
"ranking": "ミス廃ランキング",
"rankingDescription": "ユーザーの「みす廃レート」を算出し、高い順にランキング表示しています。",
"showAll": "全員分見る",
"data": "みす廃データ",
"dataBody": "内容",
"dataScore": "スコア",
"dataDelta": "前日比",
"rating": "レート",
"order": "順位",
"showRanking": "ランキングを見る"
},
"_accounts": {
"currentAccount": "現在ログインしているアカウント",
"switchAccount": "アカウント切り替え",
"useAnother": "他のアカウントで登録する"
},
"_developerInfo": {
"title": "開発者",
"description": "何か困ったことがあったら、以下のアカウントにメッセージを送ってください。"
},
"_timeline": {
"title": "タイムライン",
"description": "{{hashtag}} タグを含む最新ノートを表示します。"
},
"_alertMode": {
"note": "自動的にノートを投稿",
"notification": "Misskeyに通知(標準)",
"nothing": "通知しない",
"notificationWarning": "「Misskey に通知」オプションは古いMisskeyでは動作しません。"
},
"_visibility": {
"public": "パブリック",
"home": "ホーム",
"followers": "フォロワー",
"users": "ログインユーザー"
},
"_themes": {
"light": "ライトテーマ",
"dark": "ダークテーマ",
"system": "システム設定に準じる"
},
"_template": {
"description": "アラートの自動投稿をカスタマイズできます。",
"description2": "ハッシュタグ #misshaialert は、テンプレートに関わらず自動付与されます。",
"default": "昨日のMisskeyの活動は\n\nート: {notesCount}({notesDelta})\nフォロー : {followingCount}({followingDelta})\nフォロワー :{followersCount}({followersDelta})\n\nでした。\n{url}",
"insertVariables": "変数を挿入する",
"insertVariablesHelp": "{ } で囲われた文字列は変数と呼ばれ、特別な意味を持ちます。これを含めると、投稿時に自動的に値が埋め込まれます。",
"_variables": {
"notesCount": "ノート数",
"followingCount": "フォロー数",
"followersCount": "フォロワー数",
"notesDelta": "ノート数の前日比",
"followingDelta": "フォロー数の前日比",
"followersDelta": "フォロワー数の前日比",
"url": "本サイトのURL",
"username": "アカウントのユーザー名",
"host": "アカウントの所属ホスト名",
"rating": "レート"
}
},
"_error": {
"sorry": "問題が発生しました。お手数ですが、やり直してください。",
"additionalInfo": "追加情報: ",
"hitorisskeyIsDenied": "ひとりすきーは連携できません。",
"teapot": "I'm a teapot.",
"sessionRequired": "セッションがありません。",
"tokenRequired": "トークンがありません。",
"invalidParameter": "パラメータが不正です。",
"notAuthorized": "権限がありません。",
"other": "なし"
},
"_sendTest": {
"title": "アラートをテスト送信しますか?",
"message": "現在の設定でアラートを送信します。設定が保存済みであるかどうか、実行前に必ずご確認ください。",
"yes": "送信する",
"no": "キャンセル",
"success": "送信しました。",
"failure": "送信に失敗しました。"
},
"_logout": {
"title": "ログアウトしてもよろしいですか?",
"message": "ログアウトしても、アラート送信や、お使いのMisskeyアカウントのデータ収集といった機能は動作し続けます。Misskey Toolsの利用を停止したい場合は、「アカウント連携を解除する」ボタンを押下して下さい。",
"yes": "ログアウトする",
"no": "キャンセル"
},
"_deactivate": {
"title": "アカウント連携を解除しますか?",
"message": "収集されたデータや個人設定など、全てのデータが削除されます。この操作は取り消すことができません。",
"yes": "解除する",
"no": "キャンセル",
"success": "アカウントを解除しました。トップ画面に戻ります。",
"failure": "アカウントを解除できませんでした。"
}
}

View File

@ -0,0 +1,161 @@
{
"title": "Misskey Tools",
"description1": "Misskeyは楽しいものです。気がついたら1日中入り浸っていることも多いでしょう。",
"description2": "さあ、今すぐMisskey Toolsをインストールして、あなたの活動を把握しよう。",
"notes": "ノート",
"following": "フォロー",
"followers": "フォロワー",
"welcomeBack": "おかえりなさい、{{acct}}さん。",
"alertMode": "アラート送信方法",
"visibility": "公開範囲",
"appearance": "表示設定",
"template": "テンプレート",
"sendAlert": "アラートをテスト送信する",
"sendAlertDescription": "現在の設定を用いて、アラート送信をテストします。",
"sendAlertDisabled": "アラート送信方法が「通知しない」のため、送信をテストすることはできません。",
"logout": "ログアウトする",
"logoutDescription": "ログアウトしても、アラートは送信されます。",
"deleteAccount": "アカウント連携を解除する",
"deleteAccountDescription": "Misskey Toolsのアカウントを削除します。これにより、Misskeyとの連携設定も解除されます。",
"instanceUrl": "インスタンスURL",
"login": "ログイン",
"localOnly": "ローカルのみ",
"remoteFollowersOnly": "リモートフォロワーとローカル",
"help": "ヘルプ",
"save": "保存",
"theme": "テーマ",
"language": "言語",
"fetching": "取得中……",
"failedToFetch": "取得に失敗しました",
"registeredUsersCount": "登録者数",
"isCalculating": "現在算出中です。後ほどご確認ください!",
"ok": "OK",
"yes": "はい",
"no": "いいえ",
"termsOfService": "利用規約",
"name": "名前",
"resetToDefault": "初期値に戻す",
"error": "エラー",
"retry": "やり直す",
"saved": "保存しました。",
"disclaimerForMisskeyHq": "Misskey Toolsは、Misskey HQの公式ツールでは<b>ありません</b>。",
"translatedByTheCommunity": "Misskey Toolsはボランティアによって翻訳されています。",
"helpTranslation": "翻訳に協力する",
"announcements": "お知らせ",
"_welcomeMessage": {
"pattern1": "ついついノートしすぎていませんか?",
"pattern2": "Misskey, しすぎていませんか?",
"pattern3": "今日、何ノート書いた?",
"pattern4": "10000 ノートは初心者、そう思っていませんか?",
"pattern5": "息するように Misskey、そんなあなたへ。",
"pattern6": "あなたは真の Misskey 廃人ですか?"
},
"_welcome": {
"title": "プロ仕様のツールキット",
"description": "Misskey Toolsでは、Misskeyのために設計された、Misskeyをより楽しめるツールを取り揃えています。",
"misshaiAlertTitle": "ミス廃アラート",
"misshaiAlertDescription": "Misskeyにのめり込んでいませんかミス廃アラートを使えば、毎日のMisskeyでの活動量を以下のように定期投稿できます。",
"misshaiRankingDescription": "ミス廃ランキングでは、Misskeyでの活動を数値化し、ランキング表示します。",
"nextFeaturesTitle": "今後も追加予定。",
"nextFeaturesDescription": "これだけではありません。今後もアップデートで様々な機能を追加します!"
},
"_nav": {
"misshai": "ミス廃",
"accounts": "アカウント",
"settings": "設定"
},
"_missHai": {
"ranking": "ミス廃ランキング",
"rankingDescription": "ユーザーの「みす廃レート」を算出し、高い順にランキング表示しています。",
"showAll": "全員分見る",
"data": "みす廃データ",
"dataBody": "内容",
"dataScore": "スコア",
"dataDelta": "前日比",
"rating": "レート",
"order": "順位",
"showRanking": "ランキングを見る"
},
"_accounts": {
"currentAccount": "現在ログインしているアカウント",
"switchAccount": "アカウント切り替え",
"useAnother": "他のアカウントで登録する"
},
"_developerInfo": {
"title": "開発者",
"description": "何か困ったことがあったら、以下のアカウントにメッセージを送ってください。"
},
"_timeline": {
"title": "タイムライン",
"description": "{{hashtag}} タグを含む最新ノートを表示します。"
},
"_alertMode": {
"note": "自動的にノートを投稿",
"notification": "Misskeyに通知(標準)",
"nothing": "通知しない",
"notificationWarning": "「Misskey に通知」オプションは古いMisskeyでは動作しません。"
},
"_visibility": {
"public": "パブリック",
"home": "ホーム",
"followers": "フォロワー",
"users": "ログインユーザー"
},
"_themes": {
"light": "ライトテーマ",
"dark": "ダークテーマ",
"system": "システム設定に準じる"
},
"_template": {
"description": "アラートの自動投稿をカスタマイズできます。",
"description2": "ハッシュタグ #misshaialert は、テンプレートに関わらず自動付与されます。",
"default": "昨日のMisskeyの活動は\n\nート: {notesCount}({notesDelta})\nフォロー : {followingCount}({followingDelta})\nフォロワー :{followersCount}({followersDelta})\n\nでした。\n{url}",
"insertVariables": "変数を挿入する",
"insertVariablesHelp": "{ } で囲われた文字列は変数と呼ばれ、特別な意味を持ちます。これを含めると、投稿時に自動的に値が埋め込まれます。",
"_variables": {
"notesCount": "ノート数",
"followingCount": "フォロー数",
"followersCount": "フォロワー数",
"notesDelta": "ノート数の前日比",
"followingDelta": "フォロー数の前日比",
"followersDelta": "フォロワー数の前日比",
"url": "本サイトのURL",
"username": "アカウントのユーザー名",
"host": "アカウントの所属ホスト名",
"rating": "レート"
}
},
"_error": {
"sorry": "問題が発生しました。お手数ですが、やり直してください。",
"additionalInfo": "追加情報: ",
"hitorisskeyIsDenied": "ひとりすきーは連携できません。",
"teapot": "I'm a teapot.",
"sessionRequired": "セッションがありません。",
"tokenRequired": "トークンがありません。",
"invalidParameter": "パラメータが不正です。",
"notAuthorized": "権限がありません。",
"other": "なし"
},
"_sendTest": {
"title": "アラートをテスト送信しますか?",
"message": "現在の設定でアラートを送信します。設定が保存済みであるかどうか、実行前に必ずご確認ください。",
"yes": "送信する",
"no": "キャンセル",
"success": "送信しました。",
"failure": "送信に失敗しました。"
},
"_logout": {
"title": "ログアウトしてもよろしいですか?",
"message": "ログアウトしても、アラート送信や、お使いのMisskeyアカウントのデータ収集といった機能は動作し続けます。Misskey Toolsの利用を停止したい場合は、「アカウント連携を解除する」ボタンを押下して下さい。",
"yes": "ログアウトする",
"no": "キャンセル"
},
"_deactivate": {
"title": "アカウント連携を解除しますか?",
"message": "収集されたデータや個人設定など、全てのデータが削除されます。この操作は取り消すことができません。",
"yes": "解除する",
"no": "キャンセル",
"success": "アカウントを解除しました。トップ画面に戻ります。",
"failure": "アカウントを解除できませんでした。"
}
}

View File

@ -0,0 +1,161 @@
{
"title": "Misskey Tools",
"description1": "Misskeyは楽しいものです。気がついたら1日中入り浸っていることも多いでしょう。",
"description2": "さあ、今すぐMisskey Toolsをインストールして、あなたの活動を把握しよう。",
"notes": "ノート",
"following": "フォロー",
"followers": "フォロワー",
"welcomeBack": "おかえりなさい、{{acct}}さん。",
"alertMode": "アラート送信方法",
"visibility": "公開範囲",
"appearance": "表示設定",
"template": "テンプレート",
"sendAlert": "アラートをテスト送信する",
"sendAlertDescription": "現在の設定を用いて、アラート送信をテストします。",
"sendAlertDisabled": "アラート送信方法が「通知しない」のため、送信をテストすることはできません。",
"logout": "ログアウトする",
"logoutDescription": "ログアウトしても、アラートは送信されます。",
"deleteAccount": "アカウント連携を解除する",
"deleteAccountDescription": "Misskey Toolsのアカウントを削除します。これにより、Misskeyとの連携設定も解除されます。",
"instanceUrl": "インスタンスURL",
"login": "ログイン",
"localOnly": "ローカルのみ",
"remoteFollowersOnly": "リモートフォロワーとローカル",
"help": "ヘルプ",
"save": "保存",
"theme": "テーマ",
"language": "言語",
"fetching": "取得中……",
"failedToFetch": "取得に失敗しました",
"registeredUsersCount": "登録者数",
"isCalculating": "現在算出中です。後ほどご確認ください!",
"ok": "OK",
"yes": "はい",
"no": "いいえ",
"termsOfService": "利用規約",
"name": "名前",
"resetToDefault": "初期値に戻す",
"error": "エラー",
"retry": "やり直す",
"saved": "保存しました。",
"disclaimerForMisskeyHq": "Misskey Toolsは、Misskey HQの公式ツールでは<b>ありません</b>。",
"translatedByTheCommunity": "Misskey Toolsはボランティアによって翻訳されています。",
"helpTranslation": "翻訳に協力する",
"announcements": "お知らせ",
"_welcomeMessage": {
"pattern1": "ついついノートしすぎていませんか?",
"pattern2": "Misskey, しすぎていませんか?",
"pattern3": "今日、何ノート書いた?",
"pattern4": "10000 ノートは初心者、そう思っていませんか?",
"pattern5": "息するように Misskey、そんなあなたへ。",
"pattern6": "あなたは真の Misskey 廃人ですか?"
},
"_welcome": {
"title": "プロ仕様のツールキット",
"description": "Misskey Toolsでは、Misskeyのために設計された、Misskeyをより楽しめるツールを取り揃えています。",
"misshaiAlertTitle": "ミス廃アラート",
"misshaiAlertDescription": "Misskeyにのめり込んでいませんかミス廃アラートを使えば、毎日のMisskeyでの活動量を以下のように定期投稿できます。",
"misshaiRankingDescription": "ミス廃ランキングでは、Misskeyでの活動を数値化し、ランキング表示します。",
"nextFeaturesTitle": "今後も追加予定。",
"nextFeaturesDescription": "これだけではありません。今後もアップデートで様々な機能を追加します!"
},
"_nav": {
"misshai": "ミス廃",
"accounts": "アカウント",
"settings": "設定"
},
"_missHai": {
"ranking": "ミス廃ランキング",
"rankingDescription": "ユーザーの「みす廃レート」を算出し、高い順にランキング表示しています。",
"showAll": "全員分見る",
"data": "みす廃データ",
"dataBody": "内容",
"dataScore": "スコア",
"dataDelta": "前日比",
"rating": "レート",
"order": "順位",
"showRanking": "ランキングを見る"
},
"_accounts": {
"currentAccount": "現在ログインしているアカウント",
"switchAccount": "アカウント切り替え",
"useAnother": "他のアカウントで登録する"
},
"_developerInfo": {
"title": "開発者",
"description": "何か困ったことがあったら、以下のアカウントにメッセージを送ってください。"
},
"_timeline": {
"title": "タイムライン",
"description": "{{hashtag}} タグを含む最新ノートを表示します。"
},
"_alertMode": {
"note": "自動的にノートを投稿",
"notification": "Misskeyに通知(標準)",
"nothing": "通知しない",
"notificationWarning": "「Misskey に通知」オプションは古いMisskeyでは動作しません。"
},
"_visibility": {
"public": "パブリック",
"home": "ホーム",
"followers": "フォロワー",
"users": "ログインユーザー"
},
"_themes": {
"light": "ライトテーマ",
"dark": "ダークテーマ",
"system": "システム設定に準じる"
},
"_template": {
"description": "アラートの自動投稿をカスタマイズできます。",
"description2": "ハッシュタグ #misshaialert は、テンプレートに関わらず自動付与されます。",
"default": "昨日のMisskeyの活動は\n\nート: {notesCount}({notesDelta})\nフォロー : {followingCount}({followingDelta})\nフォロワー :{followersCount}({followersDelta})\n\nでした。\n{url}",
"insertVariables": "変数を挿入する",
"insertVariablesHelp": "{ } で囲われた文字列は変数と呼ばれ、特別な意味を持ちます。これを含めると、投稿時に自動的に値が埋め込まれます。",
"_variables": {
"notesCount": "ノート数",
"followingCount": "フォロー数",
"followersCount": "フォロワー数",
"notesDelta": "ノート数の前日比",
"followingDelta": "フォロー数の前日比",
"followersDelta": "フォロワー数の前日比",
"url": "本サイトのURL",
"username": "アカウントのユーザー名",
"host": "アカウントの所属ホスト名",
"rating": "レート"
}
},
"_error": {
"sorry": "問題が発生しました。お手数ですが、やり直してください。",
"additionalInfo": "追加情報: ",
"hitorisskeyIsDenied": "ひとりすきーは連携できません。",
"teapot": "I'm a teapot.",
"sessionRequired": "セッションがありません。",
"tokenRequired": "トークンがありません。",
"invalidParameter": "パラメータが不正です。",
"notAuthorized": "権限がありません。",
"other": "なし"
},
"_sendTest": {
"title": "アラートをテスト送信しますか?",
"message": "現在の設定でアラートを送信します。設定が保存済みであるかどうか、実行前に必ずご確認ください。",
"yes": "送信する",
"no": "キャンセル",
"success": "送信しました。",
"failure": "送信に失敗しました。"
},
"_logout": {
"title": "ログアウトしてもよろしいですか?",
"message": "ログアウトしても、アラート送信や、お使いのMisskeyアカウントのデータ収集といった機能は動作し続けます。Misskey Toolsの利用を停止したい場合は、「アカウント連携を解除する」ボタンを押下して下さい。",
"yes": "ログアウトする",
"no": "キャンセル"
},
"_deactivate": {
"title": "アカウント連携を解除しますか?",
"message": "収集されたデータや個人設定など、全てのデータが削除されます。この操作は取り消すことができません。",
"yes": "解除する",
"no": "キャンセル",
"success": "アカウントを解除しました。トップ画面に戻ります。",
"failure": "アカウントを解除できませんでした。"
}
}

View File

@ -0,0 +1,161 @@
{
"title": "Misskey Tools",
"description1": "Misskeyは楽しいものです。気がついたら1日中入り浸っていることも多いでしょう。",
"description2": "さあ、今すぐMisskey Toolsをインストールして、あなたの活動を把握しよう。",
"notes": "ノート",
"following": "フォロー",
"followers": "フォロワー",
"welcomeBack": "おかえりなさい、{{acct}}さん。",
"alertMode": "アラート送信方法",
"visibility": "公開範囲",
"appearance": "表示設定",
"template": "テンプレート",
"sendAlert": "アラートをテスト送信する",
"sendAlertDescription": "現在の設定を用いて、アラート送信をテストします。",
"sendAlertDisabled": "アラート送信方法が「通知しない」のため、送信をテストすることはできません。",
"logout": "ログアウトする",
"logoutDescription": "ログアウトしても、アラートは送信されます。",
"deleteAccount": "アカウント連携を解除する",
"deleteAccountDescription": "Misskey Toolsのアカウントを削除します。これにより、Misskeyとの連携設定も解除されます。",
"instanceUrl": "インスタンスURL",
"login": "ログイン",
"localOnly": "ローカルのみ",
"remoteFollowersOnly": "リモートフォロワーとローカル",
"help": "ヘルプ",
"save": "保存",
"theme": "テーマ",
"language": "言語",
"fetching": "取得中……",
"failedToFetch": "取得に失敗しました",
"registeredUsersCount": "登録者数",
"isCalculating": "現在算出中です。後ほどご確認ください!",
"ok": "OK",
"yes": "はい",
"no": "いいえ",
"termsOfService": "利用規約",
"name": "名前",
"resetToDefault": "初期値に戻す",
"error": "エラー",
"retry": "やり直す",
"saved": "保存しました。",
"disclaimerForMisskeyHq": "Misskey Toolsは、Misskey HQの公式ツールでは<b>ありません</b>。",
"translatedByTheCommunity": "Misskey Toolsはボランティアによって翻訳されています。",
"helpTranslation": "翻訳に協力する",
"announcements": "お知らせ",
"_welcomeMessage": {
"pattern1": "ついついノートしすぎていませんか?",
"pattern2": "Misskey, しすぎていませんか?",
"pattern3": "今日、何ノート書いた?",
"pattern4": "10000 ノートは初心者、そう思っていませんか?",
"pattern5": "息するように Misskey、そんなあなたへ。",
"pattern6": "あなたは真の Misskey 廃人ですか?"
},
"_welcome": {
"title": "プロ仕様のツールキット",
"description": "Misskey Toolsでは、Misskeyのために設計された、Misskeyをより楽しめるツールを取り揃えています。",
"misshaiAlertTitle": "ミス廃アラート",
"misshaiAlertDescription": "Misskeyにのめり込んでいませんかミス廃アラートを使えば、毎日のMisskeyでの活動量を以下のように定期投稿できます。",
"misshaiRankingDescription": "ミス廃ランキングでは、Misskeyでの活動を数値化し、ランキング表示します。",
"nextFeaturesTitle": "今後も追加予定。",
"nextFeaturesDescription": "これだけではありません。今後もアップデートで様々な機能を追加します!"
},
"_nav": {
"misshai": "ミス廃",
"accounts": "アカウント",
"settings": "設定"
},
"_missHai": {
"ranking": "ミス廃ランキング",
"rankingDescription": "ユーザーの「みす廃レート」を算出し、高い順にランキング表示しています。",
"showAll": "全員分見る",
"data": "みす廃データ",
"dataBody": "内容",
"dataScore": "スコア",
"dataDelta": "前日比",
"rating": "レート",
"order": "順位",
"showRanking": "ランキングを見る"
},
"_accounts": {
"currentAccount": "現在ログインしているアカウント",
"switchAccount": "アカウント切り替え",
"useAnother": "他のアカウントで登録する"
},
"_developerInfo": {
"title": "開発者",
"description": "何か困ったことがあったら、以下のアカウントにメッセージを送ってください。"
},
"_timeline": {
"title": "タイムライン",
"description": "{{hashtag}} タグを含む最新ノートを表示します。"
},
"_alertMode": {
"note": "自動的にノートを投稿",
"notification": "Misskeyに通知(標準)",
"nothing": "通知しない",
"notificationWarning": "「Misskey に通知」オプションは古いMisskeyでは動作しません。"
},
"_visibility": {
"public": "パブリック",
"home": "ホーム",
"followers": "フォロワー",
"users": "ログインユーザー"
},
"_themes": {
"light": "ライトテーマ",
"dark": "ダークテーマ",
"system": "システム設定に準じる"
},
"_template": {
"description": "アラートの自動投稿をカスタマイズできます。",
"description2": "ハッシュタグ #misshaialert は、テンプレートに関わらず自動付与されます。",
"default": "昨日のMisskeyの活動は\n\nート: {notesCount}({notesDelta})\nフォロー : {followingCount}({followingDelta})\nフォロワー :{followersCount}({followersDelta})\n\nでした。\n{url}",
"insertVariables": "変数を挿入する",
"insertVariablesHelp": "{ } で囲われた文字列は変数と呼ばれ、特別な意味を持ちます。これを含めると、投稿時に自動的に値が埋め込まれます。",
"_variables": {
"notesCount": "ノート数",
"followingCount": "フォロー数",
"followersCount": "フォロワー数",
"notesDelta": "ノート数の前日比",
"followingDelta": "フォロー数の前日比",
"followersDelta": "フォロワー数の前日比",
"url": "本サイトのURL",
"username": "アカウントのユーザー名",
"host": "アカウントの所属ホスト名",
"rating": "レート"
}
},
"_error": {
"sorry": "問題が発生しました。お手数ですが、やり直してください。",
"additionalInfo": "追加情報: ",
"hitorisskeyIsDenied": "ひとりすきーは連携できません。",
"teapot": "I'm a teapot.",
"sessionRequired": "セッションがありません。",
"tokenRequired": "トークンがありません。",
"invalidParameter": "パラメータが不正です。",
"notAuthorized": "権限がありません。",
"other": "なし"
},
"_sendTest": {
"title": "アラートをテスト送信しますか?",
"message": "現在の設定でアラートを送信します。設定が保存済みであるかどうか、実行前に必ずご確認ください。",
"yes": "送信する",
"no": "キャンセル",
"success": "送信しました。",
"failure": "送信に失敗しました。"
},
"_logout": {
"title": "ログアウトしてもよろしいですか?",
"message": "ログアウトしても、アラート送信や、お使いのMisskeyアカウントのデータ収集といった機能は動作し続けます。Misskey Toolsの利用を停止したい場合は、「アカウント連携を解除する」ボタンを押下して下さい。",
"yes": "ログアウトする",
"no": "キャンセル"
},
"_deactivate": {
"title": "アカウント連携を解除しますか?",
"message": "収集されたデータや個人設定など、全てのデータが削除されます。この操作は取り消すことができません。",
"yes": "解除する",
"no": "キャンセル",
"success": "アカウントを解除しました。トップ画面に戻ります。",
"failure": "アカウントを解除できませんでした。"
}
}

View File

@ -0,0 +1,161 @@
{
"title": "Misskey Tools",
"description1": "Misskeyは楽しいものです。気がついたら1日中入り浸っていることも多いでしょう。",
"description2": "さあ、今すぐMisskey Toolsをインストールして、あなたの活動を把握しよう。",
"notes": "ノート",
"following": "フォロー",
"followers": "フォロワー",
"welcomeBack": "おかえりなさい、{{acct}}さん。",
"alertMode": "アラート送信方法",
"visibility": "公開範囲",
"appearance": "表示設定",
"template": "テンプレート",
"sendAlert": "アラートをテスト送信する",
"sendAlertDescription": "現在の設定を用いて、アラート送信をテストします。",
"sendAlertDisabled": "アラート送信方法が「通知しない」のため、送信をテストすることはできません。",
"logout": "ログアウトする",
"logoutDescription": "ログアウトしても、アラートは送信されます。",
"deleteAccount": "アカウント連携を解除する",
"deleteAccountDescription": "Misskey Toolsのアカウントを削除します。これにより、Misskeyとの連携設定も解除されます。",
"instanceUrl": "インスタンスURL",
"login": "ログイン",
"localOnly": "ローカルのみ",
"remoteFollowersOnly": "リモートフォロワーとローカル",
"help": "ヘルプ",
"save": "保存",
"theme": "テーマ",
"language": "言語",
"fetching": "取得中……",
"failedToFetch": "取得に失敗しました",
"registeredUsersCount": "登録者数",
"isCalculating": "現在算出中です。後ほどご確認ください!",
"ok": "OK",
"yes": "はい",
"no": "いいえ",
"termsOfService": "利用規約",
"name": "名前",
"resetToDefault": "初期値に戻す",
"error": "エラー",
"retry": "やり直す",
"saved": "保存しました。",
"disclaimerForMisskeyHq": "Misskey Toolsは、Misskey HQの公式ツールでは<b>ありません</b>。",
"translatedByTheCommunity": "Misskey Toolsはボランティアによって翻訳されています。",
"helpTranslation": "翻訳に協力する",
"announcements": "お知らせ",
"_welcomeMessage": {
"pattern1": "ついついノートしすぎていませんか?",
"pattern2": "Misskey, しすぎていませんか?",
"pattern3": "今日、何ノート書いた?",
"pattern4": "10000 ノートは初心者、そう思っていませんか?",
"pattern5": "息するように Misskey、そんなあなたへ。",
"pattern6": "あなたは真の Misskey 廃人ですか?"
},
"_welcome": {
"title": "プロ仕様のツールキット",
"description": "Misskey Toolsでは、Misskeyのために設計された、Misskeyをより楽しめるツールを取り揃えています。",
"misshaiAlertTitle": "ミス廃アラート",
"misshaiAlertDescription": "Misskeyにのめり込んでいませんかミス廃アラートを使えば、毎日のMisskeyでの活動量を以下のように定期投稿できます。",
"misshaiRankingDescription": "ミス廃ランキングでは、Misskeyでの活動を数値化し、ランキング表示します。",
"nextFeaturesTitle": "今後も追加予定。",
"nextFeaturesDescription": "これだけではありません。今後もアップデートで様々な機能を追加します!"
},
"_nav": {
"misshai": "ミス廃",
"accounts": "アカウント",
"settings": "設定"
},
"_missHai": {
"ranking": "ミス廃ランキング",
"rankingDescription": "ユーザーの「みす廃レート」を算出し、高い順にランキング表示しています。",
"showAll": "全員分見る",
"data": "みす廃データ",
"dataBody": "内容",
"dataScore": "スコア",
"dataDelta": "前日比",
"rating": "レート",
"order": "順位",
"showRanking": "ランキングを見る"
},
"_accounts": {
"currentAccount": "現在ログインしているアカウント",
"switchAccount": "アカウント切り替え",
"useAnother": "他のアカウントで登録する"
},
"_developerInfo": {
"title": "開発者",
"description": "何か困ったことがあったら、以下のアカウントにメッセージを送ってください。"
},
"_timeline": {
"title": "タイムライン",
"description": "{{hashtag}} タグを含む最新ノートを表示します。"
},
"_alertMode": {
"note": "自動的にノートを投稿",
"notification": "Misskeyに通知(標準)",
"nothing": "通知しない",
"notificationWarning": "「Misskey に通知」オプションは古いMisskeyでは動作しません。"
},
"_visibility": {
"public": "パブリック",
"home": "ホーム",
"followers": "フォロワー",
"users": "ログインユーザー"
},
"_themes": {
"light": "ライトテーマ",
"dark": "ダークテーマ",
"system": "システム設定に準じる"
},
"_template": {
"description": "アラートの自動投稿をカスタマイズできます。",
"description2": "ハッシュタグ #misshaialert は、テンプレートに関わらず自動付与されます。",
"default": "昨日のMisskeyの活動は\n\nート: {notesCount}({notesDelta})\nフォロー : {followingCount}({followingDelta})\nフォロワー :{followersCount}({followersDelta})\n\nでした。\n{url}",
"insertVariables": "変数を挿入する",
"insertVariablesHelp": "{ } で囲われた文字列は変数と呼ばれ、特別な意味を持ちます。これを含めると、投稿時に自動的に値が埋め込まれます。",
"_variables": {
"notesCount": "ノート数",
"followingCount": "フォロー数",
"followersCount": "フォロワー数",
"notesDelta": "ノート数の前日比",
"followingDelta": "フォロー数の前日比",
"followersDelta": "フォロワー数の前日比",
"url": "本サイトのURL",
"username": "アカウントのユーザー名",
"host": "アカウントの所属ホスト名",
"rating": "レート"
}
},
"_error": {
"sorry": "問題が発生しました。お手数ですが、やり直してください。",
"additionalInfo": "追加情報: ",
"hitorisskeyIsDenied": "ひとりすきーは連携できません。",
"teapot": "I'm a teapot.",
"sessionRequired": "セッションがありません。",
"tokenRequired": "トークンがありません。",
"invalidParameter": "パラメータが不正です。",
"notAuthorized": "権限がありません。",
"other": "なし"
},
"_sendTest": {
"title": "アラートをテスト送信しますか?",
"message": "現在の設定でアラートを送信します。設定が保存済みであるかどうか、実行前に必ずご確認ください。",
"yes": "送信する",
"no": "キャンセル",
"success": "送信しました。",
"failure": "送信に失敗しました。"
},
"_logout": {
"title": "ログアウトしてもよろしいですか?",
"message": "ログアウトしても、アラート送信や、お使いのMisskeyアカウントのデータ収集といった機能は動作し続けます。Misskey Toolsの利用を停止したい場合は、「アカウント連携を解除する」ボタンを押下して下さい。",
"yes": "ログアウトする",
"no": "キャンセル"
},
"_deactivate": {
"title": "アカウント連携を解除しますか?",
"message": "収集されたデータや個人設定など、全てのデータが削除されます。この操作は取り消すことができません。",
"yes": "解除する",
"no": "キャンセル",
"success": "アカウントを解除しました。トップ画面に戻ります。",
"failure": "アカウントを解除できませんでした。"
}
}

View File

@ -0,0 +1,161 @@
{
"title": "Misskey Tools",
"description1": "Misskeyは楽しいものです。気がついたら1日中入り浸っていることも多いでしょう。",
"description2": "さあ、今すぐMisskey Toolsをインストールして、あなたの活動を把握しよう。",
"notes": "ノート",
"following": "フォロー",
"followers": "フォロワー",
"welcomeBack": "おかえりなさい、{{acct}}さん。",
"alertMode": "アラート送信方法",
"visibility": "公開範囲",
"appearance": "表示設定",
"template": "テンプレート",
"sendAlert": "アラートをテスト送信する",
"sendAlertDescription": "現在の設定を用いて、アラート送信をテストします。",
"sendAlertDisabled": "アラート送信方法が「通知しない」のため、送信をテストすることはできません。",
"logout": "ログアウトする",
"logoutDescription": "ログアウトしても、アラートは送信されます。",
"deleteAccount": "アカウント連携を解除する",
"deleteAccountDescription": "Misskey Toolsのアカウントを削除します。これにより、Misskeyとの連携設定も解除されます。",
"instanceUrl": "インスタンスURL",
"login": "ログイン",
"localOnly": "ローカルのみ",
"remoteFollowersOnly": "リモートフォロワーとローカル",
"help": "ヘルプ",
"save": "保存",
"theme": "テーマ",
"language": "言語",
"fetching": "取得中……",
"failedToFetch": "取得に失敗しました",
"registeredUsersCount": "登録者数",
"isCalculating": "現在算出中です。後ほどご確認ください!",
"ok": "OK",
"yes": "はい",
"no": "いいえ",
"termsOfService": "利用規約",
"name": "名前",
"resetToDefault": "初期値に戻す",
"error": "エラー",
"retry": "やり直す",
"saved": "保存しました。",
"disclaimerForMisskeyHq": "Misskey Toolsは、Misskey HQの公式ツールでは<b>ありません</b>。",
"translatedByTheCommunity": "Misskey Toolsはボランティアによって翻訳されています。",
"helpTranslation": "翻訳に協力する",
"announcements": "お知らせ",
"_welcomeMessage": {
"pattern1": "ついついノートしすぎていませんか?",
"pattern2": "Misskey, しすぎていませんか?",
"pattern3": "今日、何ノート書いた?",
"pattern4": "10000 ノートは初心者、そう思っていませんか?",
"pattern5": "息するように Misskey、そんなあなたへ。",
"pattern6": "あなたは真の Misskey 廃人ですか?"
},
"_welcome": {
"title": "プロ仕様のツールキット",
"description": "Misskey Toolsでは、Misskeyのために設計された、Misskeyをより楽しめるツールを取り揃えています。",
"misshaiAlertTitle": "ミス廃アラート",
"misshaiAlertDescription": "Misskeyにのめり込んでいませんかミス廃アラートを使えば、毎日のMisskeyでの活動量を以下のように定期投稿できます。",
"misshaiRankingDescription": "ミス廃ランキングでは、Misskeyでの活動を数値化し、ランキング表示します。",
"nextFeaturesTitle": "今後も追加予定。",
"nextFeaturesDescription": "これだけではありません。今後もアップデートで様々な機能を追加します!"
},
"_nav": {
"misshai": "ミス廃",
"accounts": "アカウント",
"settings": "設定"
},
"_missHai": {
"ranking": "ミス廃ランキング",
"rankingDescription": "ユーザーの「みす廃レート」を算出し、高い順にランキング表示しています。",
"showAll": "全員分見る",
"data": "みす廃データ",
"dataBody": "内容",
"dataScore": "スコア",
"dataDelta": "前日比",
"rating": "レート",
"order": "順位",
"showRanking": "ランキングを見る"
},
"_accounts": {
"currentAccount": "現在ログインしているアカウント",
"switchAccount": "アカウント切り替え",
"useAnother": "他のアカウントで登録する"
},
"_developerInfo": {
"title": "開発者",
"description": "何か困ったことがあったら、以下のアカウントにメッセージを送ってください。"
},
"_timeline": {
"title": "タイムライン",
"description": "{{hashtag}} タグを含む最新ノートを表示します。"
},
"_alertMode": {
"note": "自動的にノートを投稿",
"notification": "Misskeyに通知(標準)",
"nothing": "通知しない",
"notificationWarning": "「Misskey に通知」オプションは古いMisskeyでは動作しません。"
},
"_visibility": {
"public": "パブリック",
"home": "ホーム",
"followers": "フォロワー",
"users": "ログインユーザー"
},
"_themes": {
"light": "ライトテーマ",
"dark": "ダークテーマ",
"system": "システム設定に準じる"
},
"_template": {
"description": "アラートの自動投稿をカスタマイズできます。",
"description2": "ハッシュタグ #misshaialert は、テンプレートに関わらず自動付与されます。",
"default": "昨日のMisskeyの活動は\n\nート: {notesCount}({notesDelta})\nフォロー : {followingCount}({followingDelta})\nフォロワー :{followersCount}({followersDelta})\n\nでした。\n{url}",
"insertVariables": "変数を挿入する",
"insertVariablesHelp": "{ } で囲われた文字列は変数と呼ばれ、特別な意味を持ちます。これを含めると、投稿時に自動的に値が埋め込まれます。",
"_variables": {
"notesCount": "ノート数",
"followingCount": "フォロー数",
"followersCount": "フォロワー数",
"notesDelta": "ノート数の前日比",
"followingDelta": "フォロー数の前日比",
"followersDelta": "フォロワー数の前日比",
"url": "本サイトのURL",
"username": "アカウントのユーザー名",
"host": "アカウントの所属ホスト名",
"rating": "レート"
}
},
"_error": {
"sorry": "問題が発生しました。お手数ですが、やり直してください。",
"additionalInfo": "追加情報: ",
"hitorisskeyIsDenied": "ひとりすきーは連携できません。",
"teapot": "I'm a teapot.",
"sessionRequired": "セッションがありません。",
"tokenRequired": "トークンがありません。",
"invalidParameter": "パラメータが不正です。",
"notAuthorized": "権限がありません。",
"other": "なし"
},
"_sendTest": {
"title": "アラートをテスト送信しますか?",
"message": "現在の設定でアラートを送信します。設定が保存済みであるかどうか、実行前に必ずご確認ください。",
"yes": "送信する",
"no": "キャンセル",
"success": "送信しました。",
"failure": "送信に失敗しました。"
},
"_logout": {
"title": "ログアウトしてもよろしいですか?",
"message": "ログアウトしても、アラート送信や、お使いのMisskeyアカウントのデータ収集といった機能は動作し続けます。Misskey Toolsの利用を停止したい場合は、「アカウント連携を解除する」ボタンを押下して下さい。",
"yes": "ログアウトする",
"no": "キャンセル"
},
"_deactivate": {
"title": "アカウント連携を解除しますか?",
"message": "収集されたデータや個人設定など、全てのデータが削除されます。この操作は取り消すことができません。",
"yes": "解除する",
"no": "キャンセル",
"success": "アカウントを解除しました。トップ画面に戻ります。",
"failure": "アカウントを解除できませんでした。"
}
}

View File

@ -0,0 +1,161 @@
{
"title": "Misskey Tools",
"description1": "Misskeyは楽しいものです。気がついたら1日中入り浸っていることも多いでしょう。",
"description2": "さあ、今すぐMisskey Toolsをインストールして、あなたの活動を把握しよう。",
"notes": "ノート",
"following": "フォロー",
"followers": "フォロワー",
"welcomeBack": "おかえりなさい、{{acct}}さん。",
"alertMode": "アラート送信方法",
"visibility": "公開範囲",
"appearance": "表示設定",
"template": "テンプレート",
"sendAlert": "アラートをテスト送信する",
"sendAlertDescription": "現在の設定を用いて、アラート送信をテストします。",
"sendAlertDisabled": "アラート送信方法が「通知しない」のため、送信をテストすることはできません。",
"logout": "ログアウトする",
"logoutDescription": "ログアウトしても、アラートは送信されます。",
"deleteAccount": "アカウント連携を解除する",
"deleteAccountDescription": "Misskey Toolsのアカウントを削除します。これにより、Misskeyとの連携設定も解除されます。",
"instanceUrl": "インスタンスURL",
"login": "ログイン",
"localOnly": "ローカルのみ",
"remoteFollowersOnly": "リモートフォロワーとローカル",
"help": "ヘルプ",
"save": "保存",
"theme": "テーマ",
"language": "言語",
"fetching": "取得中……",
"failedToFetch": "取得に失敗しました",
"registeredUsersCount": "登録者数",
"isCalculating": "現在算出中です。後ほどご確認ください!",
"ok": "OK",
"yes": "はい",
"no": "いいえ",
"termsOfService": "利用規約",
"name": "名前",
"resetToDefault": "初期値に戻す",
"error": "エラー",
"retry": "やり直す",
"saved": "保存しました。",
"disclaimerForMisskeyHq": "Misskey Toolsは、Misskey HQの公式ツールでは<b>ありません</b>。",
"translatedByTheCommunity": "Misskey Toolsはボランティアによって翻訳されています。",
"helpTranslation": "翻訳に協力する",
"announcements": "お知らせ",
"_welcomeMessage": {
"pattern1": "ついついノートしすぎていませんか?",
"pattern2": "Misskey, しすぎていませんか?",
"pattern3": "今日、何ノート書いた?",
"pattern4": "10000 ノートは初心者、そう思っていませんか?",
"pattern5": "息するように Misskey、そんなあなたへ。",
"pattern6": "あなたは真の Misskey 廃人ですか?"
},
"_welcome": {
"title": "プロ仕様のツールキット",
"description": "Misskey Toolsでは、Misskeyのために設計された、Misskeyをより楽しめるツールを取り揃えています。",
"misshaiAlertTitle": "ミス廃アラート",
"misshaiAlertDescription": "Misskeyにのめり込んでいませんかミス廃アラートを使えば、毎日のMisskeyでの活動量を以下のように定期投稿できます。",
"misshaiRankingDescription": "ミス廃ランキングでは、Misskeyでの活動を数値化し、ランキング表示します。",
"nextFeaturesTitle": "今後も追加予定。",
"nextFeaturesDescription": "これだけではありません。今後もアップデートで様々な機能を追加します!"
},
"_nav": {
"misshai": "ミス廃",
"accounts": "アカウント",
"settings": "設定"
},
"_missHai": {
"ranking": "ミス廃ランキング",
"rankingDescription": "ユーザーの「みす廃レート」を算出し、高い順にランキング表示しています。",
"showAll": "全員分見る",
"data": "みす廃データ",
"dataBody": "内容",
"dataScore": "スコア",
"dataDelta": "前日比",
"rating": "レート",
"order": "順位",
"showRanking": "ランキングを見る"
},
"_accounts": {
"currentAccount": "現在ログインしているアカウント",
"switchAccount": "アカウント切り替え",
"useAnother": "他のアカウントで登録する"
},
"_developerInfo": {
"title": "開発者",
"description": "何か困ったことがあったら、以下のアカウントにメッセージを送ってください。"
},
"_timeline": {
"title": "タイムライン",
"description": "{{hashtag}} タグを含む最新ノートを表示します。"
},
"_alertMode": {
"note": "自動的にノートを投稿",
"notification": "Misskeyに通知(標準)",
"nothing": "通知しない",
"notificationWarning": "「Misskey に通知」オプションは古いMisskeyでは動作しません。"
},
"_visibility": {
"public": "パブリック",
"home": "ホーム",
"followers": "フォロワー",
"users": "ログインユーザー"
},
"_themes": {
"light": "ライトテーマ",
"dark": "ダークテーマ",
"system": "システム設定に準じる"
},
"_template": {
"description": "アラートの自動投稿をカスタマイズできます。",
"description2": "ハッシュタグ #misshaialert は、テンプレートに関わらず自動付与されます。",
"default": "昨日のMisskeyの活動は\n\nート: {notesCount}({notesDelta})\nフォロー : {followingCount}({followingDelta})\nフォロワー :{followersCount}({followersDelta})\n\nでした。\n{url}",
"insertVariables": "変数を挿入する",
"insertVariablesHelp": "{ } で囲われた文字列は変数と呼ばれ、特別な意味を持ちます。これを含めると、投稿時に自動的に値が埋め込まれます。",
"_variables": {
"notesCount": "ノート数",
"followingCount": "フォロー数",
"followersCount": "フォロワー数",
"notesDelta": "ノート数の前日比",
"followingDelta": "フォロー数の前日比",
"followersDelta": "フォロワー数の前日比",
"url": "本サイトのURL",
"username": "アカウントのユーザー名",
"host": "アカウントの所属ホスト名",
"rating": "レート"
}
},
"_error": {
"sorry": "問題が発生しました。お手数ですが、やり直してください。",
"additionalInfo": "追加情報: ",
"hitorisskeyIsDenied": "ひとりすきーは連携できません。",
"teapot": "I'm a teapot.",
"sessionRequired": "セッションがありません。",
"tokenRequired": "トークンがありません。",
"invalidParameter": "パラメータが不正です。",
"notAuthorized": "権限がありません。",
"other": "なし"
},
"_sendTest": {
"title": "アラートをテスト送信しますか?",
"message": "現在の設定でアラートを送信します。設定が保存済みであるかどうか、実行前に必ずご確認ください。",
"yes": "送信する",
"no": "キャンセル",
"success": "送信しました。",
"failure": "送信に失敗しました。"
},
"_logout": {
"title": "ログアウトしてもよろしいですか?",
"message": "ログアウトしても、アラート送信や、お使いのMisskeyアカウントのデータ収集といった機能は動作し続けます。Misskey Toolsの利用を停止したい場合は、「アカウント連携を解除する」ボタンを押下して下さい。",
"yes": "ログアウトする",
"no": "キャンセル"
},
"_deactivate": {
"title": "アカウント連携を解除しますか?",
"message": "収集されたデータや個人設定など、全てのデータが削除されます。この操作は取り消すことができません。",
"yes": "解除する",
"no": "キャンセル",
"success": "アカウントを解除しました。トップ画面に戻ります。",
"failure": "アカウントを解除できませんでした。"
}
}

View File

@ -0,0 +1,161 @@
{
"title": "Misskey Tools",
"description1": "Misskeyは楽しいものです。気がついたら1日中入り浸っていることも多いでしょう。",
"description2": "さあ、今すぐMisskey Toolsをインストールして、あなたの活動を把握しよう。",
"notes": "ノート",
"following": "フォロー",
"followers": "フォロワー",
"welcomeBack": "おかえりなさい、{{acct}}さん。",
"alertMode": "アラート送信方法",
"visibility": "公開範囲",
"appearance": "表示設定",
"template": "テンプレート",
"sendAlert": "アラートをテスト送信する",
"sendAlertDescription": "現在の設定を用いて、アラート送信をテストします。",
"sendAlertDisabled": "アラート送信方法が「通知しない」のため、送信をテストすることはできません。",
"logout": "ログアウトする",
"logoutDescription": "ログアウトしても、アラートは送信されます。",
"deleteAccount": "アカウント連携を解除する",
"deleteAccountDescription": "Misskey Toolsのアカウントを削除します。これにより、Misskeyとの連携設定も解除されます。",
"instanceUrl": "インスタンスURL",
"login": "ログイン",
"localOnly": "ローカルのみ",
"remoteFollowersOnly": "リモートフォロワーとローカル",
"help": "ヘルプ",
"save": "保存",
"theme": "テーマ",
"language": "言語",
"fetching": "取得中……",
"failedToFetch": "取得に失敗しました",
"registeredUsersCount": "登録者数",
"isCalculating": "現在算出中です。後ほどご確認ください!",
"ok": "OK",
"yes": "はい",
"no": "いいえ",
"termsOfService": "利用規約",
"name": "名前",
"resetToDefault": "初期値に戻す",
"error": "エラー",
"retry": "やり直す",
"saved": "保存しました。",
"disclaimerForMisskeyHq": "Misskey Toolsは、Misskey HQの公式ツールでは<b>ありません</b>。",
"translatedByTheCommunity": "Misskey Toolsはボランティアによって翻訳されています。",
"helpTranslation": "翻訳に協力する",
"announcements": "お知らせ",
"_welcomeMessage": {
"pattern1": "ついついノートしすぎていませんか?",
"pattern2": "Misskey, しすぎていませんか?",
"pattern3": "今日、何ノート書いた?",
"pattern4": "10000 ノートは初心者、そう思っていませんか?",
"pattern5": "息するように Misskey、そんなあなたへ。",
"pattern6": "あなたは真の Misskey 廃人ですか?"
},
"_welcome": {
"title": "プロ仕様のツールキット",
"description": "Misskey Toolsでは、Misskeyのために設計された、Misskeyをより楽しめるツールを取り揃えています。",
"misshaiAlertTitle": "ミス廃アラート",
"misshaiAlertDescription": "Misskeyにのめり込んでいませんかミス廃アラートを使えば、毎日のMisskeyでの活動量を以下のように定期投稿できます。",
"misshaiRankingDescription": "ミス廃ランキングでは、Misskeyでの活動を数値化し、ランキング表示します。",
"nextFeaturesTitle": "今後も追加予定。",
"nextFeaturesDescription": "これだけではありません。今後もアップデートで様々な機能を追加します!"
},
"_nav": {
"misshai": "ミス廃",
"accounts": "アカウント",
"settings": "設定"
},
"_missHai": {
"ranking": "ミス廃ランキング",
"rankingDescription": "ユーザーの「みす廃レート」を算出し、高い順にランキング表示しています。",
"showAll": "全員分見る",
"data": "みす廃データ",
"dataBody": "内容",
"dataScore": "スコア",
"dataDelta": "前日比",
"rating": "レート",
"order": "順位",
"showRanking": "ランキングを見る"
},
"_accounts": {
"currentAccount": "現在ログインしているアカウント",
"switchAccount": "アカウント切り替え",
"useAnother": "他のアカウントで登録する"
},
"_developerInfo": {
"title": "開発者",
"description": "何か困ったことがあったら、以下のアカウントにメッセージを送ってください。"
},
"_timeline": {
"title": "タイムライン",
"description": "{{hashtag}} タグを含む最新ノートを表示します。"
},
"_alertMode": {
"note": "自動的にノートを投稿",
"notification": "Misskeyに通知(標準)",
"nothing": "通知しない",
"notificationWarning": "「Misskey に通知」オプションは古いMisskeyでは動作しません。"
},
"_visibility": {
"public": "パブリック",
"home": "ホーム",
"followers": "フォロワー",
"users": "ログインユーザー"
},
"_themes": {
"light": "ライトテーマ",
"dark": "ダークテーマ",
"system": "システム設定に準じる"
},
"_template": {
"description": "アラートの自動投稿をカスタマイズできます。",
"description2": "ハッシュタグ #misshaialert は、テンプレートに関わらず自動付与されます。",
"default": "昨日のMisskeyの活動は\n\nート: {notesCount}({notesDelta})\nフォロー : {followingCount}({followingDelta})\nフォロワー :{followersCount}({followersDelta})\n\nでした。\n{url}",
"insertVariables": "変数を挿入する",
"insertVariablesHelp": "{ } で囲われた文字列は変数と呼ばれ、特別な意味を持ちます。これを含めると、投稿時に自動的に値が埋め込まれます。",
"_variables": {
"notesCount": "ノート数",
"followingCount": "フォロー数",
"followersCount": "フォロワー数",
"notesDelta": "ノート数の前日比",
"followingDelta": "フォロー数の前日比",
"followersDelta": "フォロワー数の前日比",
"url": "本サイトのURL",
"username": "アカウントのユーザー名",
"host": "アカウントの所属ホスト名",
"rating": "レート"
}
},
"_error": {
"sorry": "問題が発生しました。お手数ですが、やり直してください。",
"additionalInfo": "追加情報: ",
"hitorisskeyIsDenied": "ひとりすきーは連携できません。",
"teapot": "I'm a teapot.",
"sessionRequired": "セッションがありません。",
"tokenRequired": "トークンがありません。",
"invalidParameter": "パラメータが不正です。",
"notAuthorized": "権限がありません。",
"other": "なし"
},
"_sendTest": {
"title": "アラートをテスト送信しますか?",
"message": "現在の設定でアラートを送信します。設定が保存済みであるかどうか、実行前に必ずご確認ください。",
"yes": "送信する",
"no": "キャンセル",
"success": "送信しました。",
"failure": "送信に失敗しました。"
},
"_logout": {
"title": "ログアウトしてもよろしいですか?",
"message": "ログアウトしても、アラート送信や、お使いのMisskeyアカウントのデータ収集といった機能は動作し続けます。Misskey Toolsの利用を停止したい場合は、「アカウント連携を解除する」ボタンを押下して下さい。",
"yes": "ログアウトする",
"no": "キャンセル"
},
"_deactivate": {
"title": "アカウント連携を解除しますか?",
"message": "収集されたデータや個人設定など、全てのデータが削除されます。この操作は取り消すことができません。",
"yes": "解除する",
"no": "キャンセル",
"success": "アカウントを解除しました。トップ画面に戻ります。",
"failure": "アカウントを解除できませんでした。"
}
}

View File

@ -0,0 +1,161 @@
{
"title": "Misskey Tools",
"description1": "Misskeyは楽しいものです。気がついたら1日中入り浸っていることも多いでしょう。",
"description2": "さあ、今すぐMisskey Toolsをインストールして、あなたの活動を把握しよう。",
"notes": "ノート",
"following": "フォロー",
"followers": "フォロワー",
"welcomeBack": "おかえりなさい、{{acct}}さん。",
"alertMode": "アラート送信方法",
"visibility": "公開範囲",
"appearance": "表示設定",
"template": "テンプレート",
"sendAlert": "アラートをテスト送信する",
"sendAlertDescription": "現在の設定を用いて、アラート送信をテストします。",
"sendAlertDisabled": "アラート送信方法が「通知しない」のため、送信をテストすることはできません。",
"logout": "ログアウトする",
"logoutDescription": "ログアウトしても、アラートは送信されます。",
"deleteAccount": "アカウント連携を解除する",
"deleteAccountDescription": "Misskey Toolsのアカウントを削除します。これにより、Misskeyとの連携設定も解除されます。",
"instanceUrl": "インスタンスURL",
"login": "ログイン",
"localOnly": "ローカルのみ",
"remoteFollowersOnly": "リモートフォロワーとローカル",
"help": "ヘルプ",
"save": "保存",
"theme": "テーマ",
"language": "言語",
"fetching": "取得中……",
"failedToFetch": "取得に失敗しました",
"registeredUsersCount": "登録者数",
"isCalculating": "現在算出中です。後ほどご確認ください!",
"ok": "OK",
"yes": "はい",
"no": "いいえ",
"termsOfService": "利用規約",
"name": "名前",
"resetToDefault": "初期値に戻す",
"error": "エラー",
"retry": "やり直す",
"saved": "保存しました。",
"disclaimerForMisskeyHq": "Misskey Toolsは、Misskey HQの公式ツールでは<b>ありません</b>。",
"translatedByTheCommunity": "Misskey Toolsはボランティアによって翻訳されています。",
"helpTranslation": "翻訳に協力する",
"announcements": "お知らせ",
"_welcomeMessage": {
"pattern1": "ついついノートしすぎていませんか?",
"pattern2": "Misskey, しすぎていませんか?",
"pattern3": "今日、何ノート書いた?",
"pattern4": "10000 ノートは初心者、そう思っていませんか?",
"pattern5": "息するように Misskey、そんなあなたへ。",
"pattern6": "あなたは真の Misskey 廃人ですか?"
},
"_welcome": {
"title": "プロ仕様のツールキット",
"description": "Misskey Toolsでは、Misskeyのために設計された、Misskeyをより楽しめるツールを取り揃えています。",
"misshaiAlertTitle": "ミス廃アラート",
"misshaiAlertDescription": "Misskeyにのめり込んでいませんかミス廃アラートを使えば、毎日のMisskeyでの活動量を以下のように定期投稿できます。",
"misshaiRankingDescription": "ミス廃ランキングでは、Misskeyでの活動を数値化し、ランキング表示します。",
"nextFeaturesTitle": "今後も追加予定。",
"nextFeaturesDescription": "これだけではありません。今後もアップデートで様々な機能を追加します!"
},
"_nav": {
"misshai": "ミス廃",
"accounts": "アカウント",
"settings": "設定"
},
"_missHai": {
"ranking": "ミス廃ランキング",
"rankingDescription": "ユーザーの「みす廃レート」を算出し、高い順にランキング表示しています。",
"showAll": "全員分見る",
"data": "みす廃データ",
"dataBody": "内容",
"dataScore": "スコア",
"dataDelta": "前日比",
"rating": "レート",
"order": "順位",
"showRanking": "ランキングを見る"
},
"_accounts": {
"currentAccount": "現在ログインしているアカウント",
"switchAccount": "アカウント切り替え",
"useAnother": "他のアカウントで登録する"
},
"_developerInfo": {
"title": "開発者",
"description": "何か困ったことがあったら、以下のアカウントにメッセージを送ってください。"
},
"_timeline": {
"title": "タイムライン",
"description": "{{hashtag}} タグを含む最新ノートを表示します。"
},
"_alertMode": {
"note": "自動的にノートを投稿",
"notification": "Misskeyに通知(標準)",
"nothing": "通知しない",
"notificationWarning": "「Misskey に通知」オプションは古いMisskeyでは動作しません。"
},
"_visibility": {
"public": "パブリック",
"home": "ホーム",
"followers": "フォロワー",
"users": "ログインユーザー"
},
"_themes": {
"light": "ライトテーマ",
"dark": "ダークテーマ",
"system": "システム設定に準じる"
},
"_template": {
"description": "アラートの自動投稿をカスタマイズできます。",
"description2": "ハッシュタグ #misshaialert は、テンプレートに関わらず自動付与されます。",
"default": "昨日のMisskeyの活動は\n\nート: {notesCount}({notesDelta})\nフォロー : {followingCount}({followingDelta})\nフォロワー :{followersCount}({followersDelta})\n\nでした。\n{url}",
"insertVariables": "変数を挿入する",
"insertVariablesHelp": "{ } で囲われた文字列は変数と呼ばれ、特別な意味を持ちます。これを含めると、投稿時に自動的に値が埋め込まれます。",
"_variables": {
"notesCount": "ノート数",
"followingCount": "フォロー数",
"followersCount": "フォロワー数",
"notesDelta": "ノート数の前日比",
"followingDelta": "フォロー数の前日比",
"followersDelta": "フォロワー数の前日比",
"url": "本サイトのURL",
"username": "アカウントのユーザー名",
"host": "アカウントの所属ホスト名",
"rating": "レート"
}
},
"_error": {
"sorry": "問題が発生しました。お手数ですが、やり直してください。",
"additionalInfo": "追加情報: ",
"hitorisskeyIsDenied": "ひとりすきーは連携できません。",
"teapot": "I'm a teapot.",
"sessionRequired": "セッションがありません。",
"tokenRequired": "トークンがありません。",
"invalidParameter": "パラメータが不正です。",
"notAuthorized": "権限がありません。",
"other": "なし"
},
"_sendTest": {
"title": "アラートをテスト送信しますか?",
"message": "現在の設定でアラートを送信します。設定が保存済みであるかどうか、実行前に必ずご確認ください。",
"yes": "送信する",
"no": "キャンセル",
"success": "送信しました。",
"failure": "送信に失敗しました。"
},
"_logout": {
"title": "ログアウトしてもよろしいですか?",
"message": "ログアウトしても、アラート送信や、お使いのMisskeyアカウントのデータ収集といった機能は動作し続けます。Misskey Toolsの利用を停止したい場合は、「アカウント連携を解除する」ボタンを押下して下さい。",
"yes": "ログアウトする",
"no": "キャンセル"
},
"_deactivate": {
"title": "アカウント連携を解除しますか?",
"message": "収集されたデータや個人設定など、全てのデータが削除されます。この操作は取り消すことができません。",
"yes": "解除する",
"no": "キャンセル",
"success": "アカウントを解除しました。トップ画面に戻ります。",
"failure": "アカウントを解除できませんでした。"
}
}

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