1
0
mirror of https://github.com/byulmaru/quesdon synced 2024-11-30 15:58:01 +09:00

한글화

This commit is contained in:
robin* 2018-08-07 23:00:22 +09:00
parent 75a25b145f
commit f491b45c27
14 changed files with 101 additions and 126 deletions

View File

@ -5,20 +5,20 @@ import { gitVersion, upstreamUrl, usingDarkTheme } from "../initial-state"
export class Footer extends React.Component {
render() {
return <footer className="container">
<p>Quesdon AGPL-3.0 <a href={upstreamUrl}></a>&nbsp;
(<a href={`${upstreamUrl}/commits/${gitVersion}`}>{gitVersion.slice(0, 7)}</a>)</p>
<p>
: <a href="https://mstdn.jp/@quesdon">@quesdon@mstdn.jp</a>
&nbsp;
<a href="https://twitter.com/quesdon">@Quesdon on Twitter</a>
&nbsp;
<Link to="/@quesdon@mstdn.jp">Quesdon ()</Link>
Quesdon@Planet은 <a href="https://quesdon.rinsuki.net/">Quesdon</a> ,
AGPL-3.0 .
<a href={upstreamUrl}> </a>&nbsp;
<a href="https://github.com/rinsuki/quesdon"> (rinsuki/quesdon)</a>&nbsp;
(<a href={`${upstreamUrl}/commits/${gitVersion}`}>{gitVersion.slice(0, 7)}</a>)</p>
<p>
: <a href="https://planet.moe/@planet">@planet@planet.moe</a>
</p>
<p>: <a href="https://mstdn.maud.io/@rinsuki">@rinsuki@mstdn.maud.io</a></p>
<p>: <a href="https://mstdn.maud.io/@rinsuki">@rinsuki@mstdn.maud.io</a></p>
<p>
{usingDarkTheme
? <a href="#" onClick={this.leaveDarkTheme.bind(this)}></a>
: <a href="#" onClick={this.enterDarkTheme.bind(this)}>(β)</a>
? <a href="#" onClick={this.leaveDarkTheme.bind(this)}> </a>
: <a href="#" onClick={this.enterDarkTheme.bind(this)}> (β)</a>
}
</p>
</footer>

View File

@ -20,14 +20,14 @@ export class Header extends React.Component<{}, State> {
}
render() {
return <Navbar light expand="md" color="light"><Container>
<NavbarBrand to="/">Quesdon</NavbarBrand>
<NavbarBrand to="/">Quesdon@Planet</NavbarBrand>
<NavbarToggler onClick={this.toggle.bind(this)} />
<Collapse navbar isOpen={this.state.isOpen}>
<Nav className="mr-auto" navbar>
<NavItem>
{me
? <NavLink to="/my">@{me.acctDisplay}<QuestionRemaining/></NavLink>
: <NavLink to="/login"></NavLink>}
: <NavLink to="/login"></NavLink>}
</NavItem>
</Nav>
</Collapse>

View File

@ -6,13 +6,10 @@ import { PageLatest } from "./latest"
export class PageIndex extends React.Component {
render() {
return <div>
<title>Quesdon</title>
<h1>Quesdon</h1>
<p>askfmとかそんなかんじのやつのMastodonアカウントで使えるやつです</p>
<p><strong>
2018121Twitterアカウントでも使えるようになりましたTwitterでログインTwitterアカウントで利用できます
</strong></p>
<p>{me ? <Link to="/my"></Link> : <Link to="/login"></Link>}</p>
<title>Quesdon@Planet</title>
<h1>Quesdon@Planet</h1>
<p>Mastodon에서 askfm스러운 </p>
<p>{me ? <Link to="/my"></Link> : <Link to="/login"></Link>}</p>
<PageLatest />
</div>
}

View File

@ -28,13 +28,13 @@ export class PageLatest extends React.Component<{}, State> {
questions,
} = this.state
return <div>
<Title> - Quesdon</Title>
<h2> <Button color="white" onClick={this.load.bind(this)} disabled={loading}></Button></h2>
<Title> - Quesdon</Title>
<h2> <Button color="white" onClick={this.load.bind(this)} disabled={loading}></Button></h2>
{ loading
? <Loading/>
: loadFailed
? <span>
. .
({loadFailed < 0 ? loadFailed : "HTTP-" + loadFailed})
</span>
: questions.map((question) => <Question {...question} key={question._id}/>)

View File

@ -19,33 +19,18 @@ export class PageLogin extends React.Component<{}, State> {
render() {
const { loading } = this.state
return <div>
<Title></Title>
<h1></h1>
<p>Mastodonアカウントがあるインスタンスを入力してください</p>
<Title></Title>
<h1></h1>
<p> Mastodon .</p>
<form action="javascript://" onSubmit={this.send.bind(this)}>
<FormGroup>
<Input name="instance" placeholder="mastodon.social" list="major-instances"/>
<Input name="instance" placeholder="planet.moe" list="major-instances"/>
<datalist id="major-instances">
{majorInstances.map((instance) => <option value={instance} />)}
</datalist>
</FormGroup>
<Button type="submit" color="primary" disabled={loading}>{ loading ? "読み込み中" : "ログイン" }</Button>
<span>&nbsp;&nbsp;</span>
<Button type="button" color="secondary" disabled={loading} onClick={this.twitterLogin.bind(this)}>
{ loading ? "読み込み中" : "Twitterでログイン" }
</Button>
<Button type="submit" color="primary" disabled={loading}>{ loading ? "불러오는 중" : "로그인" }</Button>
</form>
<Alert color="danger" className="mt-3">
<h5>Twitterアカウントでのサービス提供終了について</h5>
<p>Twitterの開発者向けポリシー改定の影響でQuesdonでのTwitterアカウントを利用したサービス提供を<strong>2018930</strong></p>
<p>TwitterアカウントでQuesdonにログインできなくなりTwitterアカウントで開設した質問箱で回答した質問等も閲覧できなくなります</p>
<p>Mastodonアカウントへの質問データの移行はTwitterアカウントからTwitter
<a href="https://twitter.com/quesdon">@quesdon</a>
</p>
<p></p>
<strong>Mastodonアカウントでログインされているユーザーの皆様には影響はありません</strong>
</Alert>
</div>
}
@ -58,7 +43,7 @@ export class PageLogin extends React.Component<{}, State> {
loading: true,
})
function errorMsg(code: number | string) {
return "ログインに失敗しました。入力内容をご確認の上、再度お試しください (" + code + ")"
return "로그인에 실패했어요. 입력한 내용을 확인하신 후 다시 시도해 주세요. (" + code + ")"
}
const req = await apiFetch("/api/web/oauth/get_url", {
method: "POST",
@ -86,10 +71,4 @@ export class PageLogin extends React.Component<{}, State> {
if (!urlRes) return
location.href = urlRes.url
}
twitterLogin() {
const form = new FormData()
form.append("instance", "twitter.com")
this.callApi(form)
}
}

View File

@ -23,14 +23,14 @@ export class PageMyFollowers extends React.Component<{}, State> {
render() {
return <div>
<Title>Quesdonを利用しているフォロワー一覧 - </Title>
<h1>Quesdonを利用しているフォロワー一覧</h1>
<Title>Quesdon@Planet을 - </Title>
<h1>Quesdon@Planet을 </h1>
<ul>
{this.state.accounts.map((user) => <li><UserLink {...user} /></li>)}
</ul>
<Button disabled={this.state.loading || !this.state.maxId}
onClick={this.readMore.bind(this)}>
{this.state.loading ? "読み込み中" : this.state.maxId ? "もっと" : "これで全部です"}
{this.state.loading ? "불러오는 중" : this.state.maxId ? "더 보기" : "이게 끝이에요 0_0"}
</Button>
</div>
}
@ -41,7 +41,7 @@ export class PageMyFollowers extends React.Component<{}, State> {
async readMore() {
function errorMsg(code: number | string) {
return "読み込みに失敗しました。再度お試しください (" + code + ")"
return "불러오기에 실패했어요. 다시 시도해 주세요. (" + code + ")"
}
this.setState({loading: true})
const param = this.state.maxId ? "?max_id=" + this.state.maxId : ""

View File

@ -10,20 +10,20 @@ export class PageMyIndex extends React.Component {
render() {
if (!me) return null
return <div>
<Title></Title>
<h1></h1>
<p>{me.name}!</p>
<Title></Title>
<h1></h1>
<p>, {me.name}!</p>
<ul>
<li><Link to={`/@${me.acct}`}></Link></li>
<li><Link to="/my/questions"><QuestionRemaining/></Link></li>
{!me.isTwitter && <li><Link to="/my/followers">Quesdonを利用しているフォロワー一覧</Link></li>}
<li><Link to="/my/settings"></Link></li>
<li><a href="javascript://" onClick={this.logoutConfirm.bind(this)}></a></li>
<li><Link to={`/@${me.acct}`}> </Link></li>
<li><Link to="/my/questions"> <QuestionRemaining/></Link></li>
{!me.isTwitter && <li><Link to="/my/followers">Quesdon@Planet을 </Link></li>}
<li><Link to="/my/settings"></Link></li>
<li><a href="javascript://" onClick={this.logoutConfirm.bind(this)}></a></li>
</ul>
</div>
}
logoutConfirm() {
if (!confirm("ログアウトしていい?")) return
if (!confirm("정말 로그아웃 하실 건가요?")) return
apiFetch("/api/web/logout")
.then((r) => r.json())
.then((r) => {

View File

@ -27,24 +27,24 @@ export class PageMyQuestions extends React.Component<{}, State> {
questions,
} = this.state
return <div>
<Title> - </Title>
<h1></h1>
<Link to="/my"></Link>
<Title> - </Title>
<h1> </h1>
<Link to="/my"> </Link>
<div className="mt-3">
{loading
? <Loading/>
: loadFailed
? <span>
({ loadFailed < 0 ? loadFailed : "HTTP-" + loadFailed })
<a href="javascript://" onClick={this.load.bind(this)}></a>
.({ loadFailed < 0 ? loadFailed : "HTTP-" + loadFailed })
<a href="javascript://" onClick={this.load.bind(this)}></a>
</span>
: questions.map((q) => <Question {...q} hideAnswerUser key={q._id}/>)
}
</div>
<Button href={this.getShareUrl()} color="secondary" target="_blank">
Mastodon에
<wbr />
()
( )
</Button>
</div>
}
@ -86,7 +86,7 @@ export class PageMyQuestions extends React.Component<{}, State> {
}
getShareUrl() {
const user = (window as any).USER as APIUser
const text = `私の${user.questionBoxName || "質問箱"}です #quesdon ${location.origin}/@${user.acct}`
const text = `저의 ${user.questionBoxName || "질문 상자"}에요! #quesdon ${location.origin}/@${user.acct}`
return `https://${user.hostName}/${user.isTwitter ? "intent/tweet" : "share"}?text=${encodeURIComponent(text)}`
}
}

View File

@ -22,54 +22,54 @@ export class PageMySettings extends React.Component<{}, State> {
descriptionMax: 200,
questionBoxNameMax: 10,
descriptionCount: (me.description || "").length,
questionBoxNameCount: (me.questionBoxName || "質問箱").length,
questionBoxNameCount: (me.questionBoxName || "질문 상자").length,
saving: false,
}
}
render() {
if (!me) return null
return <div>
<Title></Title>
<h1></h1>
<Link to="/my"></Link>
<Title></Title>
<h1></h1>
<Link to="/my"> </Link>
<form action="javascript://" onSubmit={this.onSubmit.bind(this)}>
<FormGroup>
<label></label>
<label> </label>
<Input type="textarea" name="description"
placeholder="しぶやのりんさんがすき"
placeholder="이루어져라, 우리들의 꿈!"
onInput={this.inputDescription.bind(this)}
defaultValue={me.description}/>
<FormText>{this.descriptionRemaining()} </FormText>
<FormText> {this.descriptionRemaining()}, </FormText>
</FormGroup>
<FormGroup>
<label></label>
<label>'질문 상자' </label>
<InputGroup>
<InputGroupAddon addonType="prepend"></InputGroupAddon>
<Input type="text" name="questionBoxName" placeholder="質問箱"
<InputGroupAddon addonType="prepend"> </InputGroupAddon>
<Input type="text" name="questionBoxName" placeholder="질문 상자"
onInput={this.inputQuestionBoxName.bind(this)}
defaultValue={me.questionBoxName || "質問箱"}/>
defaultValue={me.questionBoxName || "질문 상자"}/>
</InputGroup>
<FormText>{this.questionBoxNameRemaining()} </FormText>
<FormText> {this.questionBoxNameRemaining()}, </FormText>
</FormGroup>
<FormGroup>
<Checkbox name="allAnon" value="1" checked={me.allAnon}></Checkbox>
<Checkbox name="allAnon" value="1" checked={me.allAnon}> </Checkbox>
</FormGroup>
<FormGroup>
<Checkbox name="stopNewQuestion" value="1" checked={me.stopNewQuestion}></Checkbox>
<Checkbox name="stopNewQuestion" value="1" checked={me.stopNewQuestion}> </Checkbox>
</FormGroup>
<Button type="submit" color="primary" disabled={this.sendableForm()}>
{this.state.saving && "しています..."}
{this.state.saving && "중이에요..."}
</Button>
</form>
<h2 className="mt-3 mb-2"></h2>
<h2 className="mt-3 mb-2"> </h2>
{me.pushbulletEnabled
? <Button color="warning" onClick={this.pushbulletDisconnect.bind(this)}>Pushbulletとの接続を解除する</Button>
? <Button color="warning" onClick={this.pushbulletDisconnect.bind(this)}>Pushbullet </Button>
: <Button href="/api/web/accounts/pushbullet/redirect" color="success">
Pushbulletと接続して新しい質問が来た際に通知を受け取る
Pushbullet
</Button>
}
<h2 className="mt-3 mb-2"></h2>
<Button color="danger" onClick={this.allDeleteQuestions.bind(this)}>()</Button>
<h2 className="mt-3 mb-2"> </h2>
<Button color="danger" onClick={this.allDeleteQuestions.bind(this)}> ( !) !!!</Button>
</div>
}

View File

@ -7,8 +7,8 @@ export class PageNotFound extends React.Component {
return <div>
<Title>Not Found</Title>
<h1>Not Found</h1>
<p></p>
<p><Link to="/"></Link></p>
<p> .</p>
<p><Link to="/"> </Link></p>
</div>
}
}

View File

@ -35,27 +35,27 @@ export class PageUserIndex extends React.Component<Props, State> {
const { user } = this.state
if (!user) return <Loading/>
return <div>
<Title>{user.name} @{user.acctDisplay} {user.questionBoxName}</Title>
<Title>{user.name} {user.questionBoxName || "질문함"}</Title>
<Jumbotron><div style={{textAlign: "center"}}>
<img src={user.avatarUrl} style={{maxWidth: "8em", height: "8em"}}/>
<h1>{user.name}</h1>
<p>
{user.questionBoxName || "質問箱"}&nbsp;
{user.questionBoxName || "질문함"}&nbsp;
<a href={user.url || `https://${user.hostName}/@${user.acct.split("@")[0]}`}
rel="nofollow">
{user.isTwitter ? "Twitter" : "Mastodon"}
Mastodon
</a>
</p>
<p>{user.description}</p>
{ user.stopNewQuestion ? <p></p> :
{ user.stopNewQuestion ? <p> .</p> :
<form action="javascript://" onSubmit={this.questionSubmit.bind(this)}>
<Input type="textarea" name="question"
placeholder="質問する内容を入力"
placeholder="질문 내용을 입력해 주세요:"
onInput={this.questionInput.bind(this)}
/>
<div className="d-flex mt-1">
{me && !user.allAnon && <div className="p-1">
<Checkbox name="noAnon" value="true"></Checkbox>
<Checkbox name="noAnon" value="true"> </Checkbox>
</div>}
<div className="ml-auto">
<span className={"mr-3 " +
@ -69,14 +69,14 @@ export class PageUserIndex extends React.Component<Props, State> {
|| this.state.questionLength > QUESTION_TEXT_MAX_LENGTH
|| this.state.questionNow
}>
{this.state.questionNow ? "中..." : "する"}
{this.state.questionNow ? "중..." : "하기"}
</Button>
</div>
</div>
</form>
}
</div></Jumbotron>
<h2>&nbsp;{this.state.questions && <Badge pill>{this.state.questions.length}</Badge>}</h2>
<h2>&nbsp;{this.state.questions && <Badge pill>{this.state.questions.length}</Badge>}</h2>
{this.state.questions
? <div>
{this.state.questions.map((question) =>
@ -106,7 +106,7 @@ export class PageUserIndex extends React.Component<Props, State> {
body: form,
}).then((r) => r.json()).then((r) => {
this.setState({questionNow: false})
alert("質問しました!")
alert("질문을 보냈어요!")
location.reload()
})
}

View File

@ -32,7 +32,7 @@ export class PageUserQuestion extends React.Component<Props, State> {
render() {
if (!this.state.question) return <Loading/>
return <div>
<Title>{this.state.question.user.name} : {this.state.question.question}</Title>
<Title>{this.state.question.user.name} : "{this.state.question.question}"</Title>
<Question {...this.state.question} noNsfwGuard/>
</div>
}

View File

@ -42,9 +42,9 @@ export class Question extends React.Component<Props, State> {
</CardBody>
{ this.state.nsfwGuard && <div className="nsfw-guard" onClick={this.nsfwGuardClick.bind(this)}>
<div>
<div></div>
{ !this.props.hideAnswerUser && <div>: @{this.props.user.acctDisplay}</div>}
<div>/</div>
<div> </div>
{ !this.props.hideAnswerUser && <div>: @{this.props.user.acctDisplay}</div>}
<div> </div>
</div>
</div> }
</Card>
@ -53,7 +53,7 @@ export class Question extends React.Component<Props, State> {
renderAnswerUser() {
if (this.props.hideAnswerUser) return null
return <span className="mr-2">
:&nbsp;
:&nbsp;
<UserLink {...this.props.user}/>
</span>
}
@ -61,7 +61,7 @@ export class Question extends React.Component<Props, State> {
renderQuestionUser() {
if (!this.props.questionUser) return null
return <span className="mr-2">
:&nbsp;
:&nbsp;
<UserLink {...this.props.questionUser}/>
</span>
}
@ -73,18 +73,18 @@ export class Question extends React.Component<Props, State> {
renderAnswerForm() {
return <form action="javascript://" onSubmit={this.onSubmit.bind(this)}>
<FormGroup>
<Input type="textarea" name="answer" placeholder="回答内容を入力" onInput={this.onInput.bind(this)}/>
<Input type="textarea" name="answer" placeholder="답변 내용을 입력해 주세요:" onInput={this.onInput.bind(this)}/>
</FormGroup>
<Button type="submit" color="primary" disabled={!this.state.isNotEmpty}></Button>
<span className="ml-3">: </span>
<Button type="submit" color="primary" disabled={!this.state.isNotEmpty}></Button>
<span className="ml-3"> : </span>
<Input type="select" name="visibility" style={{width: "inherit", display: "inline-block"}}>
<option value="public"></option>
<option value="unlisted"></option>
<option value="private"></option>
<option value="no">稿</option>
<option value="public"></option>
<option value="unlisted"> </option>
<option value="private"></option>
<option value="no"> !</option>
</Input>
<Checkbox name="isNSFW" value="true" className="ml-2">NSFW</Checkbox>
<Button type="button" color="danger" style={{float: "right"}} onClick={this.onDelete.bind(this)}></Button>
<Button type="button" color="danger" style={{float: "right"}} onClick={this.onDelete.bind(this)}></Button>
</form>
}
@ -98,17 +98,17 @@ export class Question extends React.Component<Props, State> {
method: "POST",
body: form,
}).then((r) => r.json()).then((r) => {
alert("答えました")
alert("답변했어요!")
location.reload()
})
}
onDelete(e: any) {
if (!confirm("質問を削除します。\n削除した質問は二度と元に戻せません。\n本当に質問を削除しますか?")) return
if (!confirm("질문을 삭제하려고요?\n삭제한 질문은 다시 되돌릴 수 없어요.\n정말로 삭제하실 건가요?")) return
apiFetch("/api/web/questions/" + this.props._id + "/delete", {
method: "POST",
}).then((r) => r.json()).then((r) => {
alert("削除しました")
alert("삭제했어요.")
location.reload()
})
}

View File

@ -12,14 +12,13 @@ html
script(src="/assets/bundle.js?version="+GIT_COMMIT)
body
#root
p ...あれ、もしかしてページが表示されてませんか?
p ご迷惑をおかけしています。何回かリロードしていただいた後、それでもこの画面が表示されるようでしたら、以下の動作環境を満たしていることを確認した後、Mastodon @quesdon@mstdn.jp もしくは Twitter @quesdon までお問い合わせください。
p: strong 2018年1月20日深夜に大幅アップデートを行いました。以前は閲覧できていたのに1月20日以降に閲覧できなくなった場合は、こちらのミスである可能性が非常に高いです。お手数ですが、 Mastodonの @quesdon@mstdn.jp もしくは Twitter @quesdon までお問い合わせください。
h2 動作環境
p ...어? 혹시 페이지가 나오지 않나요??
p 불편을 끼쳐 드려 죄송해요. 새로고침을 해 보시고, 만약 그래도 이 화면만 계속 뜬다면 아래 동작 환경을 충족하는지 확인 후 Mastodon @planet@planet.moe 에 문의해 주세요.
h2 동작 환경
ul
li iOS
del 9.3.5
| &nbsp;10以上 (推奨: iOS 11.2.2以上)
li Chrome 63以上
li Firefox 57以上
p Edge, Internet Explorerは動作対象外です。Google Chrome、もしくはFirefoxをお使いください。
| &nbsp;10 이상 (추천: iOS 11.2.2 이상)
li Chrome 63 이상
li Firefox 57 이상
p Edge, Internet Explorer는 지원 대상이 아니라서 오류가 발생할 수 있어요. Firefox나 Google Chrome을 추천드려요.