This commit is contained in:
syuilo 2018-05-20 20:26:38 +09:00
parent 8694c0ee42
commit dfa15e64ac
48 changed files with 146 additions and 158 deletions

View File

@ -7,7 +7,7 @@ import locale from '../../locales';
export default class Replacer { export default class Replacer {
private lang: string; private lang: string;
public pattern = /%i18n:([a-z0-9_\-\.\/\|\!]+?)%/g; public pattern = /%i18n:([a-z0-9_\-\.\/\|]+?)%/g;
constructor(lang: string) { constructor(lang: string) {
this.lang = lang; this.lang = lang;
@ -56,11 +56,6 @@ export default class Replacer {
public replacement(match, key) { public replacement(match, key) {
let path = null; let path = null;
const shouldEscape = key[0] == '!';
if (shouldEscape) {
key = key.substr(1);
}
if (key.indexOf('|') != -1) { if (key.indexOf('|') != -1) {
path = key.split('|')[0]; path = key.split('|')[0];
key = key.split('|')[1]; key = key.split('|')[1];
@ -68,8 +63,6 @@ export default class Replacer {
const txt = this.get(path, key); const txt = this.get(path, key);
return shouldEscape return txt.replace(/'/g, '\\x27').replace(/"/g, '\\x22');
? txt.replace(/'/g, '\\x27').replace(/"/g, '\\x22')
: txt.replace(/"/g, '"');
} }
} }

View File

@ -23,7 +23,7 @@ export default async function(mios: MiOS, force = false, silent = false) {
} }
if (!silent) { if (!silent) {
alert('%i18n:!common.update-available%'.replace('{newer}', newer).replace('{current}', current)); alert('%i18n:common.update-available%'.replace('{newer}', newer).replace('{current}', current));
} }
return newer; return newer;

View File

@ -62,7 +62,7 @@ export class HomeStream extends Stream {
// トークンが再生成されたとき // トークンが再生成されたとき
// このままではMisskeyが利用できないので強制的にサインアウトさせる // このままではMisskeyが利用できないので強制的にサインアウトさせる
this.on('my_token_regenerated', () => { this.on('my_token_regenerated', () => {
alert('%i18n:!common.my-token-regenerated%'); alert('%i18n:common.my-token-regenerated%');
os.signout(); os.signout();
}); });
} }

View File

@ -8,21 +8,21 @@
<template v-if="network">%fa:check%</template> <template v-if="network">%fa:check%</template>
<template v-if="!network">%fa:times%</template> <template v-if="!network">%fa:times%</template>
</template> </template>
{{ network == null ? '%i18n:!@checking-network%' : '%i18n:!@network%' }}<mk-ellipsis v-if="network == null"/> {{ network == null ? '%i18n:@checking-network%' : '%i18n:@network%' }}<mk-ellipsis v-if="network == null"/>
</p> </p>
<p v-if="network == true" :data-wip="internet == null"> <p v-if="network == true" :data-wip="internet == null">
<template v-if="internet != null"> <template v-if="internet != null">
<template v-if="internet">%fa:check%</template> <template v-if="internet">%fa:check%</template>
<template v-if="!internet">%fa:times%</template> <template v-if="!internet">%fa:times%</template>
</template> </template>
{{ internet == null ? '%i18n:!@checking-internet%' : '%i18n:!@internet%' }}<mk-ellipsis v-if="internet == null"/> {{ internet == null ? '%i18n:@checking-internet%' : '%i18n:@internet%' }}<mk-ellipsis v-if="internet == null"/>
</p> </p>
<p v-if="internet == true" :data-wip="server == null"> <p v-if="internet == true" :data-wip="server == null">
<template v-if="server != null"> <template v-if="server != null">
<template v-if="server">%fa:check%</template> <template v-if="server">%fa:check%</template>
<template v-if="!server">%fa:times%</template> <template v-if="!server">%fa:times%</template>
</template> </template>
{{ server == null ? '%i18n:!@checking-server%' : '%i18n:!@server%' }}<mk-ellipsis v-if="server == null"/> {{ server == null ? '%i18n:@checking-server%' : '%i18n:@server%' }}<mk-ellipsis v-if="server == null"/>
</p> </p>
</div> </div>
<p v-if="!end">%i18n:@finding%<mk-ellipsis/></p> <p v-if="!end">%i18n:@finding%<mk-ellipsis/></p>

View File

@ -3,9 +3,9 @@
<img src="data:image/jpeg;base64,%base64:/assets/error.jpg%" alt=""/> <img src="data:image/jpeg;base64,%base64:/assets/error.jpg%" alt=""/>
<h1>%i18n:@title%</h1> <h1>%i18n:@title%</h1>
<p class="text"> <p class="text">
<span>{{ '%i18n:!@description%'.substr(0, '%i18n:!@description%'.indexOf('{')) }}</span> <span>{{ '%i18n:@description%'.substr(0, '%i18n:@description%'.indexOf('{')) }}</span>
<a @click="reload">{{ '%i18n:!@description%'.match(/\{(.+?)\}/)[1] }}</a> <a @click="reload">{{ '%i18n:@description%'.match(/\{(.+?)\}/)[1] }}</a>
<span>{{ '%i18n:!@description%'.substr('%i18n:!@description%'.indexOf('}') + 1) }}</span> <span>{{ '%i18n:@description%'.substr('%i18n:@description%'.indexOf('}') + 1) }}</span>
</p> </p>
<button v-if="!troubleshooting" @click="troubleshooting = true">%i18n:@troubleshoot%</button> <button v-if="!troubleshooting" @click="troubleshooting = true">%i18n:@troubleshoot%</button>
<x-troubleshooter v-if="troubleshooting"/> <x-troubleshooter v-if="troubleshooting"/>

View File

@ -8,7 +8,7 @@
<p class="empty" v-if="!init && messages.length == 0">%fa:info-circle%%i18n:@empty%</p> <p class="empty" v-if="!init && messages.length == 0">%fa:info-circle%%i18n:@empty%</p>
<p class="no-history" v-if="!init && messages.length > 0 && !existMoreMessages">%fa:flag%%i18n:@no-history%</p> <p class="no-history" v-if="!init && messages.length > 0 && !existMoreMessages">%fa:flag%%i18n:@no-history%</p>
<button class="more" :class="{ fetching: fetchingMoreMessages }" v-if="existMoreMessages" @click="fetchMoreMessages" :disabled="fetchingMoreMessages"> <button class="more" :class="{ fetching: fetchingMoreMessages }" v-if="existMoreMessages" @click="fetchMoreMessages" :disabled="fetchingMoreMessages">
<template v-if="fetchingMoreMessages">%fa:spinner .pulse .fw%</template>{{ fetchingMoreMessages ? '%i18n:!common.loading%' : '%i18n:!@more%' }} <template v-if="fetchingMoreMessages">%fa:spinner .pulse .fw%</template>{{ fetchingMoreMessages ? '%i18n:common.loading%' : '%i18n:@more%' }}
</button> </button>
<template v-for="(message, i) in _messages"> <template v-for="(message, i) in _messages">
<x-message :message="message" :key="message.id"/> <x-message :message="message" :key="message.id"/>
@ -172,7 +172,7 @@ export default Vue.extend({
}); });
} else if (message.userId != (this as any).os.i.id) { } else if (message.userId != (this as any).os.i.id) {
// Notify // Notify
this.notify('%i18n:!@new-message%'); this.notify('%i18n:@new-message%');
} }
}, },

View File

@ -5,7 +5,7 @@
</p> </p>
<ul ref="choices"> <ul ref="choices">
<li v-for="(choice, i) in choices"> <li v-for="(choice, i) in choices">
<input :value="choice" @input="onInput(i, $event)" :placeholder="'%i18n:!@choice-n%'.replace('{}', i + 1)"> <input :value="choice" @input="onInput(i, $event)" :placeholder="'%i18n:@choice-n%'.replace('{}', i + 1)">
<button @click="remove(i)" title="%i18n:@remove%"> <button @click="remove(i)" title="%i18n:@remove%">
%fa:times% %fa:times%
</button> </button>

View File

@ -1,19 +1,19 @@
<template> <template>
<div class="mk-poll" :data-is-voted="isVoted"> <div class="mk-poll" :data-is-voted="isVoted">
<ul> <ul>
<li v-for="choice in poll.choices" :key="choice.id" @click="vote(choice.id)" :class="{ voted: choice.voted }" :title="!isVoted ? '%i18n:!@vote-to%'.replace('{}', choice.text) : ''"> <li v-for="choice in poll.choices" :key="choice.id" @click="vote(choice.id)" :class="{ voted: choice.voted }" :title="!isVoted ? '%i18n:@vote-to%'.replace('{}', choice.text) : ''">
<div class="backdrop" :style="{ 'width': (showResult ? (choice.votes / total * 100) : 0) + '%' }"></div> <div class="backdrop" :style="{ 'width': (showResult ? (choice.votes / total * 100) : 0) + '%' }"></div>
<span> <span>
<template v-if="choice.isVoted">%fa:check%</template> <template v-if="choice.isVoted">%fa:check%</template>
<span>{{ choice.text }}</span> <span>{{ choice.text }}</span>
<span class="votes" v-if="showResult">({{ '%i18n:!@vote-count%'.replace('{}', choice.votes) }})</span> <span class="votes" v-if="showResult">({{ '%i18n:@vote-count%'.replace('{}', choice.votes) }})</span>
</span> </span>
</li> </li>
</ul> </ul>
<p v-if="total > 0"> <p v-if="total > 0">
<span>{{ '%i18n:!@total-users%'.replace('{}', total) }}</span> <span>{{ '%i18n:@total-users%'.replace('{}', total) }}</span>
<span></span> <span></span>
<a v-if="!isVoted" @click="toggleShowResult">{{ showResult ? '%i18n:!@vote%' : '%i18n:!@show-result%' }}</a> <a v-if="!isVoted" @click="toggleShowResult">{{ showResult ? '%i18n:@vote%' : '%i18n:@show-result%' }}</a>
<span v-if="isVoted">%i18n:@voted%</span> <span v-if="isVoted">%i18n:@voted%</span>
</p> </p>
</div> </div>

View File

@ -22,7 +22,7 @@
import Vue from 'vue'; import Vue from 'vue';
import * as anime from 'animejs'; import * as anime from 'animejs';
const placeholder = '%i18n:!@choose-reaction%'; const placeholder = '%i18n:@choose-reaction%';
export default Vue.extend({ export default Vue.extend({
props: ['note', 'source', 'compact', 'cb'], props: ['note', 'source', 'compact', 'cb'],

View File

@ -9,7 +9,7 @@
<label class="token" v-if="user && user.twoFactorEnabled"> <label class="token" v-if="user && user.twoFactorEnabled">
<input v-model="token" type="number" placeholder="%i18n:@token%" required/>%fa:lock% <input v-model="token" type="number" placeholder="%i18n:@token%" required/>%fa:lock%
</label> </label>
<button type="submit" :disabled="signing">{{ signing ? '%i18n:!@signing-in%' : '%i18n:!@signin%' }}</button> <button type="submit" :disabled="signing">{{ signing ? '%i18n:@signing-in%' : '%i18n:@signin%' }}</button>
もしくは <a :href="`${apiUrl}/signin/twitter`">Twitterでログイン</a> もしくは <a :href="`${apiUrl}/signin/twitter`">Twitterでログイン</a>
</form> </form>
</template> </template>

View File

@ -127,7 +127,7 @@ export default Vue.extend({
location.href = '/'; location.href = '/';
}); });
}).catch(() => { }).catch(() => {
alert('%i18n:!@some-error%'); alert('%i18n:@some-error%');
(window as any).grecaptcha.reset(); (window as any).grecaptcha.reset();
this.recaptchaed = false; this.recaptchaed = false;

View File

@ -44,16 +44,16 @@ export default Vue.extend({
const time = this._time; const time = this._time;
const ago = (this.now.getTime() - time.getTime()) / 1000/*ms*/; const ago = (this.now.getTime() - time.getTime()) / 1000/*ms*/;
return ( return (
ago >= 31536000 ? '%i18n:!common.time.years_ago%' .replace('{}', (~~(ago / 31536000)).toString()) : ago >= 31536000 ? '%i18n:common.time.years_ago%' .replace('{}', (~~(ago / 31536000)).toString()) :
ago >= 2592000 ? '%i18n:!common.time.months_ago%' .replace('{}', (~~(ago / 2592000)).toString()) : ago >= 2592000 ? '%i18n:common.time.months_ago%' .replace('{}', (~~(ago / 2592000)).toString()) :
ago >= 604800 ? '%i18n:!common.time.weeks_ago%' .replace('{}', (~~(ago / 604800)).toString()) : ago >= 604800 ? '%i18n:common.time.weeks_ago%' .replace('{}', (~~(ago / 604800)).toString()) :
ago >= 86400 ? '%i18n:!common.time.days_ago%' .replace('{}', (~~(ago / 86400)).toString()) : ago >= 86400 ? '%i18n:common.time.days_ago%' .replace('{}', (~~(ago / 86400)).toString()) :
ago >= 3600 ? '%i18n:!common.time.hours_ago%' .replace('{}', (~~(ago / 3600)).toString()) : ago >= 3600 ? '%i18n:common.time.hours_ago%' .replace('{}', (~~(ago / 3600)).toString()) :
ago >= 60 ? '%i18n:!common.time.minutes_ago%'.replace('{}', (~~(ago / 60)).toString()) : ago >= 60 ? '%i18n:common.time.minutes_ago%'.replace('{}', (~~(ago / 60)).toString()) :
ago >= 10 ? '%i18n:!common.time.seconds_ago%'.replace('{}', (~~(ago % 60)).toString()) : ago >= 10 ? '%i18n:common.time.seconds_ago%'.replace('{}', (~~(ago % 60)).toString()) :
ago >= 0 ? '%i18n:!common.time.just_now%' : ago >= 0 ? '%i18n:common.time.just_now%' :
ago < 0 ? '%i18n:!common.time.future%' : ago < 0 ? '%i18n:common.time.future%' :
'%i18n:!common.time.unknown%'); '%i18n:common.time.unknown%');
} }
}, },
created() { created() {

View File

@ -3,7 +3,7 @@
<p>%i18n:@description%<a :href="`${docsUrl}/link-to-twitter`" target="_blank">%i18n:@detail%</a></p> <p>%i18n:@description%<a :href="`${docsUrl}/link-to-twitter`" target="_blank">%i18n:@detail%</a></p>
<p class="account" v-if="os.i.twitter" :title="`Twitter ID: ${os.i.twitter.userId}`">%i18n:@connected-to%: <a :href="`https://twitter.com/${os.i.twitter.screenName}`" target="_blank">@{{ os.i.twitter.screenName }}</a></p> <p class="account" v-if="os.i.twitter" :title="`Twitter ID: ${os.i.twitter.userId}`">%i18n:@connected-to%: <a :href="`https://twitter.com/${os.i.twitter.screenName}`" target="_blank">@{{ os.i.twitter.screenName }}</a></p>
<p> <p>
<a :href="`${apiUrl}/connect/twitter`" target="_blank" @click.prevent="connect">{{ os.i.twitter ? '%i18n:!@reconnect%' : '%i18n:!@connect%' }}</a> <a :href="`${apiUrl}/connect/twitter`" target="_blank" @click.prevent="connect">{{ os.i.twitter ? '%i18n:@reconnect%' : '%i18n:@connect%' }}</a>
<span v-if="os.i.twitter"> or </span> <span v-if="os.i.twitter"> or </span>
<a :href="`${apiUrl}/disconnect/twitter`" target="_blank" v-if="os.i.twitter" @click.prevent="disconnect">%i18n:@disconnect%</a> <a :href="`${apiUrl}/disconnect/twitter`" target="_blank" v-if="os.i.twitter" @click.prevent="disconnect">%i18n:@disconnect%</a>
</p> </p>

View File

@ -14,7 +14,7 @@
</svg> </svg>
</div> </div>
<p class="fetching" v-if="fetching">%i18n:@fetching%<mk-ellipsis/></p> <p class="fetching" v-if="fetching">%i18n:@fetching%<mk-ellipsis/></p>
<h1 v-if="!fetching">{{ broadcasts.length == 0 ? '%i18n:!@no-broadcasts%' : broadcasts[i].title }}</h1> <h1 v-if="!fetching">{{ broadcasts.length == 0 ? '%i18n:@no-broadcasts%' : broadcasts[i].title }}</h1>
<p v-if="!fetching"> <p v-if="!fetching">
<span v-if="broadcasts.length != 0" v-html="broadcasts[i].text"></span> <span v-if="broadcasts.length != 0" v-html="broadcasts[i].text"></span>
<template v-if="broadcasts.length == 0">%i18n:@have-a-nice-day%</template> <template v-if="broadcasts.length == 0">%i18n:@have-a-nice-day%</template>

View File

@ -3,9 +3,9 @@
<article> <article>
<h1>%fa:heart%%i18n:@title%</h1> <h1>%fa:heart%%i18n:@title%</h1>
<p> <p>
{{ '%i18n:!@text%'.substr(0, '%i18n:!@text%'.indexOf('{')) }} {{ '%i18n:@text%'.substr(0, '%i18n:@text%'.indexOf('{')) }}
<a href="https://syuilo.com">@syuilo</a> <a href="https://syuilo.com">@syuilo</a>
{{ '%i18n:!@text%'.substr('%i18n:!@text%'.indexOf('}') + 1) }} {{ '%i18n:@text%'.substr('%i18n:@text%'.indexOf('}') + 1) }}
</p> </p>
</article> </article>
</div> </div>

View File

@ -2,7 +2,7 @@
<div class="mk-calendar" :data-melt="design == 4 || design == 5"> <div class="mk-calendar" :data-melt="design == 4 || design == 5">
<template v-if="design == 0 || design == 1"> <template v-if="design == 0 || design == 1">
<button @click="prev" title="%i18n:@prev%">%fa:chevron-circle-left%</button> <button @click="prev" title="%i18n:@prev%">%fa:chevron-circle-left%</button>
<p class="title">{{ '%i18n:!@title%'.replace('{1}', year).replace('{2}', month) }}</p> <p class="title">{{ '%i18n:@title%'.replace('{1}', year).replace('{2}', month) }}</p>
<button @click="next" title="%i18n:@next%">%fa:chevron-circle-right%</button> <button @click="next" title="%i18n:@next%">%fa:chevron-circle-right%</button>
</template> </template>
@ -21,7 +21,7 @@
:data-is-out-of-range="isOutOfRange(i + 1)" :data-is-out-of-range="isOutOfRange(i + 1)"
:data-is-donichi="isDonichi(i + 1)" :data-is-donichi="isDonichi(i + 1)"
@click="go(i + 1)" @click="go(i + 1)"
:title="isOutOfRange(i + 1) ? null : '%i18n:!@go%'" :title="isOutOfRange(i + 1) ? null : '%i18n:@go%'"
> >
<div>{{ i + 1 }}</div> <div>{{ i + 1 }}</div>
</div> </div>
@ -58,13 +58,13 @@ export default Vue.extend({
month: new Date().getMonth() + 1, month: new Date().getMonth() + 1,
selected: new Date(), selected: new Date(),
weekdayText: [ weekdayText: [
'%i18n:!common.weekday-short.sunday%', '%i18n:common.weekday-short.sunday%',
'%i18n:!common.weekday-short.monday%', '%i18n:common.weekday-short.monday%',
'%i18n:!common.weekday-short.tuesday%', '%i18n:common.weekday-short.tuesday%',
'%i18n:!common.weekday-short.wednesday%', '%i18n:common.weekday-short.wednesday%',
'%i18n:!common.weekday-short.thursday%', '%i18n:common.weekday-short.thursday%',
'%i18n:!common.weekday-short.friday%', '%i18n:common.weekday-short.friday%',
'%i18n:!common.weekday-short.saturday%' '%i18n:common.weekday-short.saturday%'
] ]
}; };
}, },

View File

@ -64,46 +64,46 @@ export default Vue.extend({
this.isContextmenuShowing = true; this.isContextmenuShowing = true;
contextmenu(e, [{ contextmenu(e, [{
type: 'item', type: 'item',
text: '%i18n:!@contextmenu.rename%', text: '%i18n:@contextmenu.rename%',
icon: '%fa:i-cursor%', icon: '%fa:i-cursor%',
onClick: this.rename onClick: this.rename
}, { }, {
type: 'item', type: 'item',
text: '%i18n:!@contextmenu.copy-url%', text: '%i18n:@contextmenu.copy-url%',
icon: '%fa:link%', icon: '%fa:link%',
onClick: this.copyUrl onClick: this.copyUrl
}, { }, {
type: 'link', type: 'link',
href: `${this.file.url}?download`, href: `${this.file.url}?download`,
text: '%i18n:!@contextmenu.download%', text: '%i18n:@contextmenu.download%',
icon: '%fa:download%', icon: '%fa:download%',
}, { }, {
type: 'divider', type: 'divider',
}, { }, {
type: 'item', type: 'item',
text: '%i18n:!common.delete%', text: '%i18n:common.delete%',
icon: '%fa:R trash-alt%', icon: '%fa:R trash-alt%',
onClick: this.deleteFile onClick: this.deleteFile
}, { }, {
type: 'divider', type: 'divider',
}, { }, {
type: 'nest', type: 'nest',
text: '%i18n:!@contextmenu.else-files%', text: '%i18n:@contextmenu.else-files%',
menu: [{ menu: [{
type: 'item', type: 'item',
text: '%i18n:!@contextmenu.set-as-avatar%', text: '%i18n:@contextmenu.set-as-avatar%',
onClick: this.setAsAvatar onClick: this.setAsAvatar
}, { }, {
type: 'item', type: 'item',
text: '%i18n:!@contextmenu.set-as-banner%', text: '%i18n:@contextmenu.set-as-banner%',
onClick: this.setAsBanner onClick: this.setAsBanner
}] }]
}, { }, {
type: 'nest', type: 'nest',
text: '%i18n:!@contextmenu.open-in-app%', text: '%i18n:@contextmenu.open-in-app%',
menu: [{ menu: [{
type: 'item', type: 'item',
text: '%i18n:!@contextmenu.add-app%...', text: '%i18n:@contextmenu.add-app%...',
onClick: this.addApp onClick: this.addApp
}] }]
}], { }], {
@ -141,8 +141,8 @@ export default Vue.extend({
rename() { rename() {
(this as any).apis.input({ (this as any).apis.input({
title: '%i18n:!@contextmenu.rename-file%', title: '%i18n:@contextmenu.rename-file%',
placeholder: '%i18n:!@contextmenu.input-new-file-name%', placeholder: '%i18n:@contextmenu.input-new-file-name%',
default: this.file.name, default: this.file.name,
allowEmpty: false allowEmpty: false
}).then(name => { }).then(name => {
@ -157,9 +157,9 @@ export default Vue.extend({
copyToClipboard(this.file.url); copyToClipboard(this.file.url);
(this as any).apis.dialog({ (this as any).apis.dialog({
title: '%fa:check%%i18n:@contextmenu.copied%', title: '%fa:check%%i18n:@contextmenu.copied%',
text: '%i18n:!@contextmenu.copied-url-to-clipboard%', text: '%i18n:@contextmenu.copied-url-to-clipboard%',
actions: [{ actions: [{
text: '%i18n:!common.ok%' text: '%i18n:common.ok%'
}] }]
}); });
}, },

View File

@ -54,26 +54,26 @@ export default Vue.extend({
this.isContextmenuShowing = true; this.isContextmenuShowing = true;
contextmenu(e, [{ contextmenu(e, [{
type: 'item', type: 'item',
text: '%i18n:!@contextmenu.move-to-this-folder%', text: '%i18n:@contextmenu.move-to-this-folder%',
icon: '%fa:arrow-right%', icon: '%fa:arrow-right%',
onClick: this.go onClick: this.go
}, { }, {
type: 'item', type: 'item',
text: '%i18n:!@contextmenu.show-in-new-window%', text: '%i18n:@contextmenu.show-in-new-window%',
icon: '%fa:R window-restore%', icon: '%fa:R window-restore%',
onClick: this.newWindow onClick: this.newWindow
}, { }, {
type: 'divider', type: 'divider',
}, { }, {
type: 'item', type: 'item',
text: '%i18n:!@contextmenu.rename%', text: '%i18n:@contextmenu.rename%',
icon: '%fa:i-cursor%', icon: '%fa:i-cursor%',
onClick: this.rename onClick: this.rename
}, { }, {
type: 'divider', type: 'divider',
}, { }, {
type: 'item', type: 'item',
text: '%i18n:!common.delete%', text: '%i18n:common.delete%',
icon: '%fa:R trash-alt%', icon: '%fa:R trash-alt%',
onClick: this.deleteFolder onClick: this.deleteFolder
}], { }], {
@ -159,15 +159,15 @@ export default Vue.extend({
switch (err) { switch (err) {
case 'detected-circular-definition': case 'detected-circular-definition':
(this as any).apis.dialog({ (this as any).apis.dialog({
title: '%fa:exclamation-triangle%%i18n:!@unable-to-process%', title: '%fa:exclamation-triangle%%i18n:@unable-to-process%',
text: '%i18n:!@circular-reference-detected%', text: '%i18n:@circular-reference-detected%',
actions: [{ actions: [{
text: '%i18n:!common.ok%' text: '%i18n:common.ok%'
}] }]
}); });
break; break;
default: default:
alert('%i18n:!@unhandled-error% ' + err); alert('%i18n:@unhandled-error% ' + err);
} }
}); });
} }
@ -199,8 +199,8 @@ export default Vue.extend({
rename() { rename() {
(this as any).apis.input({ (this as any).apis.input({
title: '%i18n:!@contextmenu.rename-folder%', title: '%i18n:@contextmenu.rename-folder%',
placeholder: '%i18n:!@contextmenu.input-new-folder-name%', placeholder: '%i18n:@contextmenu.input-new-folder-name%',
default: this.folder.name default: this.folder.name
}).then(name => { }).then(name => {
(this as any).api('drive/folders/update', { (this as any).api('drive/folders/update', {

View File

@ -8,7 +8,7 @@
@drop.stop="onDrop" @drop.stop="onDrop"
> >
<template v-if="folder == null">%fa:cloud%</template> <template v-if="folder == null">%fa:cloud%</template>
<span>{{ folder == null ? '%i18n:!@drive%' : folder.name }}</span> <span>{{ folder == null ? '%i18n:@drive%' : folder.name }}</span>
</div> </div>
</template> </template>

View File

@ -138,17 +138,17 @@ export default Vue.extend({
onContextmenu(e) { onContextmenu(e) {
contextmenu(e, [{ contextmenu(e, [{
type: 'item', type: 'item',
text: '%i18n:!@contextmenu.create-folder%', text: '%i18n:@contextmenu.create-folder%',
icon: '%fa:R folder%', icon: '%fa:R folder%',
onClick: this.createFolder onClick: this.createFolder
}, { }, {
type: 'item', type: 'item',
text: '%i18n:!@contextmenu.upload%', text: '%i18n:@contextmenu.upload%',
icon: '%fa:upload%', icon: '%fa:upload%',
onClick: this.selectLocalFile onClick: this.selectLocalFile
}, { }, {
type: 'item', type: 'item',
text: '%i18n:!@contextmenu.url-upload%', text: '%i18n:@contextmenu.url-upload%',
icon: '%fa:cloud-upload-alt%', icon: '%fa:cloud-upload-alt%',
onClick: this.urlUpload onClick: this.urlUpload
}]); }]);
@ -306,15 +306,15 @@ export default Vue.extend({
switch (err) { switch (err) {
case 'detected-circular-definition': case 'detected-circular-definition':
(this as any).apis.dialog({ (this as any).apis.dialog({
title: '%fa:exclamation-triangle%%i18n:!@unable-to-process%', title: '%fa:exclamation-triangle%%i18n:@unable-to-process%',
text: '%i18n:!@circular-reference-detected%', text: '%i18n:@circular-reference-detected%',
actions: [{ actions: [{
text: '%i18n:!common.ok%' text: '%i18n:common.ok%'
}] }]
}); });
break; break;
default: default:
alert('%i18n:!@unhandled-error% ' + err); alert('%i18n:@unhandled-error% ' + err);
} }
}); });
} }
@ -327,8 +327,8 @@ export default Vue.extend({
urlUpload() { urlUpload() {
(this as any).apis.input({ (this as any).apis.input({
title: '%i18n:!@url-upload%', title: '%i18n:@url-upload%',
placeholder: '%i18n:!@url-of-file%' placeholder: '%i18n:@url-of-file%'
}).then(url => { }).then(url => {
(this as any).api('drive/files/upload_from_url', { (this as any).api('drive/files/upload_from_url', {
url: url, url: url,
@ -337,9 +337,9 @@ export default Vue.extend({
(this as any).apis.dialog({ (this as any).apis.dialog({
title: '%fa:check%%i18n:@url-upload-requested%', title: '%fa:check%%i18n:@url-upload-requested%',
text: '%i18n:!@may-take-time%', text: '%i18n:@may-take-time%',
actions: [{ actions: [{
text: '%i18n:!common.ok%' text: '%i18n:common.ok%'
}] }]
}); });
}); });
@ -347,8 +347,8 @@ export default Vue.extend({
createFolder() { createFolder() {
(this as any).apis.input({ (this as any).apis.input({
title: '%i18n:!@create-folder%', title: '%i18n:@create-folder%',
placeholder: '%i18n:!@folder-name%' placeholder: '%i18n:@folder-name%'
}).then(name => { }).then(name => {
(this as any).api('drive/folders/create', { (this as any).api('drive/folders/create', {
name: name, name: name,

View File

@ -1,7 +1,7 @@
<template> <template>
<mk-window width="400px" height="550px" @closed="$destroy"> <mk-window width="400px" height="550px" @closed="$destroy">
<span slot="header" :class="$style.header"> <span slot="header" :class="$style.header">
<img :src="`${user.avatarUrl}?thumbnail&size=64`" alt=""/>%i18n:!@followers%.replace('{}', {{ user | userName }}) <img :src="`${user.avatarUrl}?thumbnail&size=64`" alt=""/>%i18n:@followers%.replace('{}', {{ user | userName }})
</span> </span>
<mk-followers :user="user"/> <mk-followers :user="user"/>
</mk-window> </mk-window>

View File

@ -1,7 +1,7 @@
<template> <template>
<mk-window width="400px" height="550px" @closed="$destroy"> <mk-window width="400px" height="550px" @closed="$destroy">
<span slot="header" :class="$style.header"> <span slot="header" :class="$style.header">
<img :src="`${user.avatarUrl}?thumbnail&size=64`" alt=""/>%i18n:!@following%.replace('{}', {{ user | userName }}) <img :src="`${user.avatarUrl}?thumbnail&size=64`" alt=""/>%i18n:@following%.replace('{}', {{ user | userName }})
</span> </span>
<mk-following :user="user"/> <mk-following :user="user"/>
</mk-window> </mk-window>

View File

@ -6,9 +6,9 @@
<div class="renote" v-if="isRenote"> <div class="renote" v-if="isRenote">
<mk-avatar class="avatar" :user="note.user"/> <mk-avatar class="avatar" :user="note.user"/>
%fa:retweet% %fa:retweet%
<span>{{ '%i18n:!@reposted-by%'.substr(0, '%i18n:!@reposted-by%'.indexOf('{')) }}</span> <span>{{ '%i18n:@reposted-by%'.substr(0, '%i18n:@reposted-by%'.indexOf('{')) }}</span>
<a class="name" :href="note.user | userPage" v-user-preview="note.userId">{{ note.user | userName }}</a> <a class="name" :href="note.user | userPage" v-user-preview="note.userId">{{ note.user | userName }}</a>
<span>{{ '%i18n:!@reposted-by%'.substr('%i18n:!@reposted-by%'.indexOf('}') + 1) }}</span> <span>{{ '%i18n:@reposted-by%'.substr('%i18n:@reposted-by%'.indexOf('}') + 1) }}</span>
<mk-time :time="note.createdAt"/> <mk-time :time="note.createdAt"/>
</div> </div>
<article> <article>

View File

@ -81,7 +81,7 @@
</transition-group> </transition-group>
</div> </div>
<button class="more" :class="{ fetching: fetchingMoreNotifications }" v-if="moreNotifications" @click="fetchMoreNotifications" :disabled="fetchingMoreNotifications"> <button class="more" :class="{ fetching: fetchingMoreNotifications }" v-if="moreNotifications" @click="fetchMoreNotifications" :disabled="fetchingMoreNotifications">
<template v-if="fetchingMoreNotifications">%fa:spinner .pulse .fw%</template>{{ fetchingMoreNotifications ? '%i18n:!common.loading%' : '%i18n:!@more%' }} <template v-if="fetchingMoreNotifications">%fa:spinner .pulse .fw%</template>{{ fetchingMoreNotifications ? '%i18n:common.loading%' : '%i18n:@more%' }}
</button> </button>
<p class="empty" v-if="notifications.length == 0 && !fetching">%i18n:@empty%</p> <p class="empty" v-if="notifications.length == 0 && !fetching">%i18n:@empty%</p>
<p class="loading" v-if="fetching">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p> <p class="loading" v-if="fetching">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p>

View File

@ -4,8 +4,8 @@
<span :class="$style.icon" v-if="geo">%fa:map-marker-alt%</span> <span :class="$style.icon" v-if="geo">%fa:map-marker-alt%</span>
<span v-if="!reply">%i18n:@note%</span> <span v-if="!reply">%i18n:@note%</span>
<span v-if="reply">%i18n:@reply%</span> <span v-if="reply">%i18n:@reply%</span>
<span :class="$style.count" v-if="media.length != 0">{{ '%i18n:!@attaches%'.replace('{}', media.length) }}</span> <span :class="$style.count" v-if="media.length != 0">{{ '%i18n:@attaches%'.replace('{}', media.length) }}</span>
<span :class="$style.count" v-if="uploadings.length != 0">{{ '%i18n:!@uploading-media%'.replace('{}', uploadings.length) }}<mk-ellipsis/></span> <span :class="$style.count" v-if="uploadings.length != 0">{{ '%i18n:@uploading-media%'.replace('{}', uploadings.length) }}<mk-ellipsis/></span>
</span> </span>
<mk-note-preview v-if="reply" :class="$style.notePreview" :note="reply"/> <mk-note-preview v-if="reply" :class="$style.notePreview" :note="reply"/>

View File

@ -37,7 +37,7 @@
<button class="visibility" title="公開範囲" @click="setVisibility" ref="visibilityButton">%fa:lock%</button> <button class="visibility" title="公開範囲" @click="setVisibility" ref="visibilityButton">%fa:lock%</button>
<p class="text-count" :class="{ over: text.length > 1000 }">{{ 1000 - text.length }}</p> <p class="text-count" :class="{ over: text.length > 1000 }">{{ 1000 - text.length }}</p>
<button :class="{ posting }" class="submit" :disabled="!canPost" @click="post"> <button :class="{ posting }" class="submit" :disabled="!canPost" @click="post">
{{ posting ? '%i18n:!@posting%' : submitText }}<mk-ellipsis v-if="posting"/> {{ posting ? '%i18n:@posting%' : submitText }}<mk-ellipsis v-if="posting"/>
</button> </button>
<input ref="file" type="file" accept="image/*" multiple="multiple" tabindex="-1" @change="onChangeFile"/> <input ref="file" type="file" accept="image/*" multiple="multiple" tabindex="-1" @change="onChangeFile"/>
<div class="dropzone" v-if="draghover"></div> <div class="dropzone" v-if="draghover"></div>
@ -86,18 +86,18 @@ export default Vue.extend({
placeholder(): string { placeholder(): string {
return this.renote return this.renote
? '%i18n:!@quote-placeholder%' ? '%i18n:@quote-placeholder%'
: this.reply : this.reply
? '%i18n:!@reply-placeholder%' ? '%i18n:@reply-placeholder%'
: '%i18n:!@note-placeholder%'; : '%i18n:@note-placeholder%';
}, },
submitText(): string { submitText(): string {
return this.renote return this.renote
? '%i18n:!@renote%' ? '%i18n:@renote%'
: this.reply : this.reply
? '%i18n:!@reply%' ? '%i18n:@reply%'
: '%i18n:!@note%'; : '%i18n:@note%';
}, },
canPost(): boolean { canPost(): boolean {
@ -304,16 +304,16 @@ export default Vue.extend({
this.deleteDraft(); this.deleteDraft();
this.$emit('posted'); this.$emit('posted');
(this as any).apis.notify(this.renote (this as any).apis.notify(this.renote
? '%i18n:!@reposted%' ? '%i18n:@reposted%'
: this.reply : this.reply
? '%i18n:!@replied%' ? '%i18n:@replied%'
: '%i18n:!@posted%'); : '%i18n:@posted%');
}).catch(err => { }).catch(err => {
(this as any).apis.notify(this.renote (this as any).apis.notify(this.renote
? '%i18n:!@renote-failed%' ? '%i18n:@renote-failed%'
: this.reply : this.reply
? '%i18n:!@reply-failed%' ? '%i18n:@reply-failed%'
: '%i18n:!@note-failed%'); : '%i18n:@note-failed%');
}).then(() => { }).then(() => {
this.posting = false; this.posting = false;
}); });

View File

@ -5,7 +5,7 @@
<footer> <footer>
<a class="quote" v-if="!quote" @click="onQuote">%i18n:@quote%</a> <a class="quote" v-if="!quote" @click="onQuote">%i18n:@quote%</a>
<button class="ui cancel" @click="cancel">%i18n:@cancel%</button> <button class="ui cancel" @click="cancel">%i18n:@cancel%</button>
<button class="ui primary ok" @click="ok" :disabled="wait">{{ wait ? '%i18n:!@reposting%' : '%i18n:!@renote%' }}</button> <button class="ui primary ok" @click="ok" :disabled="wait">{{ wait ? '%i18n:@reposting%' : '%i18n:@renote%' }}</button>
</footer> </footer>
</template> </template>
<template v-if="quote"> <template v-if="quote">
@ -32,9 +32,9 @@ export default Vue.extend({
renoteId: this.note.id renoteId: this.note.id
}).then(data => { }).then(data => {
this.$emit('posted'); this.$emit('posted');
(this as any).apis.notify('%i18n:!@success%'); (this as any).apis.notify('%i18n:@success%');
}).catch(err => { }).catch(err => {
(this as any).apis.notify('%i18n:!@failure%'); (this as any).apis.notify('%i18n:@failure%');
}).then(() => { }).then(() => {
this.wait = false; this.wait = false;
}); });

View File

@ -34,7 +34,7 @@ export default Vue.extend({
methods: { methods: {
register() { register() {
(this as any).apis.input({ (this as any).apis.input({
title: '%i18n:!@enter-password%', title: '%i18n:@enter-password%',
type: 'password' type: 'password'
}).then(password => { }).then(password => {
(this as any).api('i/2fa/register', { (this as any).api('i/2fa/register', {
@ -47,13 +47,13 @@ export default Vue.extend({
unregister() { unregister() {
(this as any).apis.input({ (this as any).apis.input({
title: '%i18n:!@enter-password%', title: '%i18n:@enter-password%',
type: 'password' type: 'password'
}).then(password => { }).then(password => {
(this as any).api('i/2fa/unregister', { (this as any).api('i/2fa/unregister', {
password: password password: password
}).then(() => { }).then(() => {
(this as any).apis.notify('%i18n:!@unregistered%'); (this as any).apis.notify('%i18n:@unregistered%');
(this as any).os.i.twoFactorEnabled = false; (this as any).os.i.twoFactorEnabled = false;
}); });
}); });
@ -63,10 +63,10 @@ export default Vue.extend({
(this as any).api('i/2fa/done', { (this as any).api('i/2fa/done', {
token: this.token token: this.token
}).then(() => { }).then(() => {
(this as any).apis.notify('%i18n:!@success%'); (this as any).apis.notify('%i18n:@success%');
(this as any).os.i.twoFactorEnabled = true; (this as any).os.i.twoFactorEnabled = true;
}).catch(() => { }).catch(() => {
(this as any).apis.notify('%i18n:!@failed%'); (this as any).apis.notify('%i18n:@failed%');
}); });
} }
} }

View File

@ -15,7 +15,7 @@ export default Vue.extend({
methods: { methods: {
regenerateToken() { regenerateToken() {
(this as any).apis.input({ (this as any).apis.input({
title: '%i18n:!@enter-password%', title: '%i18n:@enter-password%',
type: 'password' type: 'password'
}).then(password => { }).then(password => {
(this as any).api('i/regenerate_token', { (this as any).api('i/regenerate_token', {

View File

@ -11,21 +11,21 @@ export default Vue.extend({
methods: { methods: {
reset() { reset() {
(this as any).apis.input({ (this as any).apis.input({
title: '%i18n:!@enter-current-password%', title: '%i18n:@enter-current-password%',
type: 'password' type: 'password'
}).then(currentPassword => { }).then(currentPassword => {
(this as any).apis.input({ (this as any).apis.input({
title: '%i18n:!@enter-new-password%', title: '%i18n:@enter-new-password%',
type: 'password' type: 'password'
}).then(newPassword => { }).then(newPassword => {
(this as any).apis.input({ (this as any).apis.input({
title: '%i18n:!@enter-new-password-again%', title: '%i18n:@enter-new-password-again%',
type: 'password' type: 'password'
}).then(newPassword2 => { }).then(newPassword2 => {
if (newPassword !== newPassword2) { if (newPassword !== newPassword2) {
(this as any).apis.dialog({ (this as any).apis.dialog({
title: null, title: null,
text: '%i18n:!@not-match%', text: '%i18n:@not-match%',
actions: [{ actions: [{
text: 'OK' text: 'OK'
}] }]
@ -36,7 +36,7 @@ export default Vue.extend({
currentPasword: currentPassword, currentPasword: currentPassword,
newPassword: newPassword newPassword: newPassword
}).then(() => { }).then(() => {
(this as any).apis.notify('%i18n:!@changed%'); (this as any).apis.notify('%i18n:@changed%');
}); });
}); });
}); });

View File

@ -371,13 +371,13 @@ export default Vue.extend({
this.latestVersion = newer; this.latestVersion = newer;
if (newer == null) { if (newer == null) {
(this as any).apis.dialog({ (this as any).apis.dialog({
title: '%i18n:!@no-updates%', title: '%i18n:@no-updates%',
text: '%i18n:!@no-updates-desc%' text: '%i18n:@no-updates-desc%'
}); });
} else { } else {
(this as any).apis.dialog({ (this as any).apis.dialog({
title: '%i18n:!@update-available%', title: '%i18n:@update-available%',
text: '%i18n:!@update-available-desc%' text: '%i18n:@update-available-desc%'
}); });
} }
}); });
@ -385,8 +385,8 @@ export default Vue.extend({
clean() { clean() {
localStorage.clear(); localStorage.clear();
(this as any).apis.dialog({ (this as any).apis.dialog({
title: '%i18n:!@cache-cleared%', title: '%i18n:@cache-cleared%',
text: '%i18n:!@caache-cleared-desc%' text: '%i18n:@caache-cleared-desc%'
}); });
}, },
soundTest() { soundTest() {

View File

@ -29,7 +29,7 @@ export default Vue.extend({
} }
}, },
mounted() { mounted() {
document.title = '%i18n:!@title%'; document.title = '%i18n:@title%';
}, },
methods: { methods: {
onSelected(file) { onSelected(file) {

View File

@ -113,7 +113,7 @@ html.setAttribute('lang', lang);
const head = document.getElementsByTagName('head')[0]; const head = document.getElementsByTagName('head')[0];
const meta = document.createElement('meta'); const meta = document.createElement('meta');
meta.setAttribute('name', 'description'); meta.setAttribute('name', 'description');
meta.setAttribute('content', '%i18n:!common.misskey%'); meta.setAttribute('content', '%i18n:common.misskey%');
head.appendChild(meta); head.appendChild(meta);
//#endregion //#endregion

View File

@ -32,7 +32,7 @@
<div class="files" v-if="files.length > 0"> <div class="files" v-if="files.length > 0">
<x-file v-for="file in files" :key="file.id" :file="file"/> <x-file v-for="file in files" :key="file.id" :file="file"/>
<button class="more" v-if="moreFiles" @click="fetchMoreFiles"> <button class="more" v-if="moreFiles" @click="fetchMoreFiles">
{{ fetchingMoreFiles ? '%i18n:!common.loading%' : '%i18n:!@load-more%' }} {{ fetchingMoreFiles ? '%i18n:common.loading%' : '%i18n:@load-more%' }}
</button> </button>
</div> </div>
<div class="empty" v-if="files.length == 0 && folders.length == 0 && !fetching"> <div class="empty" v-if="files.length == 0 && folders.length == 0 && !fetching">

View File

@ -7,7 +7,7 @@
<template v-if="!wait && user.isFollowing">%fa:minus%</template> <template v-if="!wait && user.isFollowing">%fa:minus%</template>
<template v-if="!wait && !user.isFollowing">%fa:plus%</template> <template v-if="!wait && !user.isFollowing">%fa:plus%</template>
<template v-if="wait">%fa:spinner .pulse .fw%</template> <template v-if="wait">%fa:spinner .pulse .fw%</template>
{{ user.isFollowing ? '%i18n:!@unfollow%' : '%i18n:!@follow%' }} {{ user.isFollowing ? '%i18n:@unfollow%' : '%i18n:@follow%' }}
</button> </button>
</template> </template>

View File

@ -6,9 +6,9 @@
<div class="renote" v-if="isRenote"> <div class="renote" v-if="isRenote">
<mk-avatar class="avatar" :user="note.user"/> <mk-avatar class="avatar" :user="note.user"/>
%fa:retweet% %fa:retweet%
<span>{{ '%i18n:!@reposted-by%'.substr(0, '%i18n:!@reposted-by%'.indexOf('{')) }}</span> <span>{{ '%i18n:@reposted-by%'.substr(0, '%i18n:@reposted-by%'.indexOf('{')) }}</span>
<router-link class="name" :to="note.user | userPage">{{ note.user | userName }}</router-link> <router-link class="name" :to="note.user | userPage">{{ note.user | userName }}</router-link>
<span>{{ '%i18n:!@reposted-by%'.substr('%i18n:!@reposted-by%'.indexOf('}') + 1) }}</span> <span>{{ '%i18n:@reposted-by%'.substr('%i18n:@reposted-by%'.indexOf('}') + 1) }}</span>
<mk-time :time="note.createdAt"/> <mk-time :time="note.createdAt"/>
</div> </div>
<article> <article>

View File

@ -12,7 +12,7 @@
<button class="more" v-if="moreNotifications" @click="fetchMoreNotifications" :disabled="fetchingMoreNotifications"> <button class="more" v-if="moreNotifications" @click="fetchMoreNotifications" :disabled="fetchingMoreNotifications">
<template v-if="fetchingMoreNotifications">%fa:spinner .pulse .fw%</template> <template v-if="fetchingMoreNotifications">%fa:spinner .pulse .fw%</template>
{{ fetchingMoreNotifications ? '%i18n:!common.loading%' : '%i18n:!@more%' }} {{ fetchingMoreNotifications ? '%i18n:common.loading%' : '%i18n:@more%' }}
</button> </button>
<p class="empty" v-if="notifications.length == 0 && !fetching">%i18n:@empty%</p> <p class="empty" v-if="notifications.length == 0 && !fetching">%i18n:@empty%</p>

View File

@ -20,7 +20,7 @@
<a @click="addVisibleUser">+ユーザーを追加</a> <a @click="addVisibleUser">+ユーザーを追加</a>
</div> </div>
<input v-show="useCw" v-model="cw" placeholder="内容への注釈 (オプション)"> <input v-show="useCw" v-model="cw" placeholder="内容への注釈 (オプション)">
<textarea v-model="text" ref="text" :disabled="posting" :placeholder="reply ? '%i18n:!@reply-placeholder%' : renote ? '%i18n:!@renote-placeholder%' : '%i18n:!@note-placeholder%'"></textarea> <textarea v-model="text" ref="text" :disabled="posting" :placeholder="reply ? '%i18n:@reply-placeholder%' : renote ? '%i18n:@renote-placeholder%' : '%i18n:@note-placeholder%'"></textarea>
<div class="attaches" v-show="files.length != 0"> <div class="attaches" v-show="files.length != 0">
<x-draggable class="files" :list="files" :options="{ animation: 150 }"> <x-draggable class="files" :list="files" :options="{ animation: 150 }">
<div class="file" v-for="file in files" :key="file.id"> <div class="file" v-for="file in files" :key="file.id">

View File

@ -94,7 +94,7 @@ export default Vue.extend({
}, },
methods: { methods: {
search() { search() {
const query = window.prompt('%i18n:!@search%'); const query = window.prompt('%i18n:@search%');
if (query == null || query == '') return; if (query == null || query == '') return;
this.$router.push('/search?q=' + encodeURIComponent(query)); this.$router.push('/search?q=' + encodeURIComponent(query));
}, },

View File

@ -3,7 +3,7 @@
<mk-notes ref="timeline" :more="existMore ? more : null"> <mk-notes ref="timeline" :more="existMore ? more : null">
<div slot="empty"> <div slot="empty">
%fa:R comments% %fa:R comments%
{{ withMedia ? '%i18n:!@no-notes-with-media%' : '%i18n:!@no-notes%' }} {{ withMedia ? '%i18n:@no-notes-with-media%' : '%i18n:@no-notes%' }}
</div> </div>
</mk-notes> </mk-notes>
</div> </div>

View File

@ -2,7 +2,7 @@
<mk-ui> <mk-ui>
<template slot="header" v-if="!fetching"> <template slot="header" v-if="!fetching">
<img :src="`${user.avatarUrl}?thumbnail&size=64`" alt=""> <img :src="`${user.avatarUrl}?thumbnail&size=64`" alt="">
{{ '%i18n:!@followers-of%'.replace('{}', name) }} {{ '%i18n:@followers-of%'.replace('{}', name) }}
</template> </template>
<mk-users-list <mk-users-list
v-if="!fetching" v-if="!fetching"
@ -49,7 +49,7 @@ export default Vue.extend({
this.user = user; this.user = user;
this.fetching = false; this.fetching = false;
document.title = '%i18n:!@followers-of%'.replace('{}', this.name) + ' | Misskey'; document.title = '%i18n:@followers-of%'.replace('{}', this.name) + ' | Misskey';
}); });
}, },
onLoaded() { onLoaded() {

View File

@ -2,7 +2,7 @@
<mk-ui> <mk-ui>
<template slot="header" v-if="!fetching"> <template slot="header" v-if="!fetching">
<img :src="`${user.avatarUrl}?thumbnail&size=64`" alt=""> <img :src="`${user.avatarUrl}?thumbnail&size=64`" alt="">
{{ '%i18n:!@following-of%'.replace('{}', name) }} {{ '%i18n:@following-of%'.replace('{}', name) }}
</template> </template>
<mk-users-list <mk-users-list
v-if="!fetching" v-if="!fetching"
@ -48,7 +48,7 @@ export default Vue.extend({
this.user = user; this.user = user;
this.fetching = false; this.fetching = false;
document.title = '%i18n:!@followers-of%'.replace('{}', this.name) + ' | Misskey'; document.title = '%i18n:@followers-of%'.replace('{}', this.name) + ' | Misskey';
}); });
}, },
onLoaded() { onLoaded() {

View File

@ -21,7 +21,7 @@ export default Vue.extend({
}, },
methods: { methods: {
fn() { fn() {
const ok = window.confirm('%i18n:!@read-all%'); const ok = window.confirm('%i18n:@read-all%');
if (!ok) return; if (!ok) return;
(this as any).api('notifications/markAsRead_all'); (this as any).api('notifications/markAsRead_all');

View File

@ -3,7 +3,7 @@
<span slot="header">%fa:search% {{ q }}</span> <span slot="header">%fa:search% {{ q }}</span>
<main v-if="!fetching"> <main v-if="!fetching">
<mk-notes :class="$style.notes" :notes="notes"> <mk-notes :class="$style.notes" :notes="notes">
<span v-if="notes.length == 0">{{ '%i18n:!@empty%'.replace('{}', q) }}</span> <span v-if="notes.length == 0">{{ '%i18n:@empty%'.replace('{}', q) }}</span>
<button v-if="existMore" @click="more" :disabled="fetching" slot="tail"> <button v-if="existMore" @click="more" :disabled="fetching" slot="tail">
<span v-if="!fetching">%i18n:@load-more%</span> <span v-if="!fetching">%i18n:@load-more%</span>
<span v-if="fetching">%i18n:common.loading%<mk-ellipsis/></span> <span v-if="fetching">%i18n:common.loading%<mk-ellipsis/></span>

View File

@ -25,7 +25,7 @@ export default Vue.extend({
} }
}, },
mounted() { mounted() {
document.title = '%i18n:!@title%'; document.title = '%i18n:@title%';
}, },
methods: { methods: {
onSelected(file) { onSelected(file) {

View File

@ -2,7 +2,7 @@
<mk-ui> <mk-ui>
<span slot="header">%fa:cog%%i18n:@settings%</span> <span slot="header">%fa:cog%%i18n:@settings%</span>
<main> <main>
<p v-html="'%i18n:!@signed-in-as%'.replace('{}', '<b>' + name + '</b>')"></p> <p v-html="'%i18n:@signed-in-as%'.replace('{}', '<b>' + name + '</b>')"></p>
<div> <div>
<x-profile/> <x-profile/>
@ -91,7 +91,7 @@
<md-card-content> <md-card-content>
<p class="account" v-if="os.i.twitter"><a :href="`https://twitter.com/${os.i.twitter.screenName}`" target="_blank">@{{ os.i.twitter.screenName }}</a></p> <p class="account" v-if="os.i.twitter"><a :href="`https://twitter.com/${os.i.twitter.screenName}`" target="_blank">@{{ os.i.twitter.screenName }}</a></p>
<p> <p>
<a :href="`${apiUrl}/connect/twitter`" target="_blank">{{ os.i.twitter ? '%i18n:!@twitter-reconnect%' : '%i18n:!@twitter-connect%' }}</a> <a :href="`${apiUrl}/connect/twitter`" target="_blank">{{ os.i.twitter ? '%i18n:@twitter-reconnect%' : '%i18n:@twitter-connect%' }}</a>
<span v-if="os.i.twitter"> or </span> <span v-if="os.i.twitter"> or </span>
<a :href="`${apiUrl}/disconnect/twitter`" target="_blank" v-if="os.i.twitter">%i18n:@twitter-disconnect%</a> <a :href="`${apiUrl}/disconnect/twitter`" target="_blank" v-if="os.i.twitter">%i18n:@twitter-disconnect%</a>
</p> </p>
@ -223,13 +223,13 @@ export default Vue.extend({
this.latestVersion = newer; this.latestVersion = newer;
if (newer == null) { if (newer == null) {
(this as any).apis.dialog({ (this as any).apis.dialog({
title: '%i18n:!@no-updates%', title: '%i18n:@no-updates%',
text: '%i18n:!@no-updates-desc%' text: '%i18n:@no-updates-desc%'
}); });
} else { } else {
(this as any).apis.dialog({ (this as any).apis.dialog({
title: '%i18n:!@update-available%', title: '%i18n:@update-available%',
text: '%i18n:!@update-available-desc%' text: '%i18n:@update-available-desc%'
}); });
} }
}); });

View File

@ -158,7 +158,7 @@ export default Vue.extend({
(this as any).os.i.bannerId = i.bannerId; (this as any).os.i.bannerId = i.bannerId;
(this as any).os.i.bannerUrl = i.bannerUrl; (this as any).os.i.bannerUrl = i.bannerUrl;
alert('%i18n:!@saved%'); alert('%i18n:@saved%');
}); });
} }
} }

View File

@ -2,17 +2,12 @@
* Replace i18n texts * Replace i18n texts
*/ */
export const pattern = /%i18n:([a-z0-9_\-@\.\!]+?)%/g; export const pattern = /%i18n:([a-z0-9_\-@\.]+?)%/g;
export const replacement = (ctx, match, key) => { export const replacement = (ctx, match, key) => {
const client = '/src/client/app/'; const client = '/src/client/app/';
let name = null; let name = null;
const shouldEscape = key[0] == '!';
if (shouldEscape) {
key = key.substr(1);
}
if (key[0] == '@') { if (key[0] == '@') {
name = ctx.src.substr(ctx.src.indexOf(client) + client.length); name = ctx.src.substr(ctx.src.indexOf(client) + client.length);
key = key.substr(1); key = key.substr(1);
@ -20,5 +15,5 @@ export const replacement = (ctx, match, key) => {
const path = name ? `${name}|${key}` : key; const path = name ? `${name}|${key}` : key;
return shouldEscape ? `%i18n:!${path}%` : `%i18n:${path}%`; return `%i18n:${path}%`;
}; };