* i18n

Resolve #6155

* i18n for drive

* ✌️

* Extract doc

Co-authored-by: syuilo <syuilotan@yahoo.co.jp>
This commit is contained in:
Satsuki Yanagi 2020-03-22 10:51:40 +09:00 committed by GitHub
parent 06c7fe669c
commit 903e93ae01
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 111 additions and 112 deletions

View file

@ -88,7 +88,6 @@ add: "追加"
reaction: "リアクション" reaction: "リアクション"
reactionSettingDescription: "リアクションピッカーに表示するリアクションを設定します。" reactionSettingDescription: "リアクションピッカーに表示するリアクションを設定します。"
rememberNoteVisibility: "公開範囲を記憶する" rememberNoteVisibility: "公開範囲を記憶する"
renameFile: "ファイル名を変更"
attachCancel: "添付取り消し" attachCancel: "添付取り消し"
markAsSensitive: "閲覧注意にする" markAsSensitive: "閲覧注意にする"
unmarkAsSensitive: "閲覧注意を解除する" unmarkAsSensitive: "閲覧注意を解除する"
@ -207,10 +206,13 @@ messaging: "チャット"
upload: "アップロード" upload: "アップロード"
fromDrive: "ドライブから" fromDrive: "ドライブから"
fromUrl: "URLから" fromUrl: "URLから"
uploadFromUrl: "URLアップロード"
uploadFromUrlDescription: "アップロードしたいファイルのURL"
uploadFromUrlRequested: "アップロードをリクエストしました"
uploadFromUrlMayTakeTime: "アップロードが完了するまで時間がかかる場合があります。"
explore: "みつける" explore: "みつける"
games: "Misskey Games" games: "Misskey Games"
messageRead: "既読" messageRead: "既読"
recentUsedEmojis: "最近使用した絵文字"
noMoreHistory: "これより過去の履歴はありません" noMoreHistory: "これより過去の履歴はありません"
startMessaging: "チャットを開始" startMessaging: "チャットを開始"
nUsersRead: "{n}人が読みました" nUsersRead: "{n}人が読みました"
@ -234,14 +236,22 @@ lightThemes: "明るいテーマ"
darkThemes: "暗いテーマ" darkThemes: "暗いテーマ"
syncDeviceDarkMode: "デバイスのダークモードと同期する" syncDeviceDarkMode: "デバイスのダークモードと同期する"
drive: "ドライブ" drive: "ドライブ"
fileName: "ファイル名"
selectFile: "ファイルを選択" selectFile: "ファイルを選択"
selectFiles: "ファイルを選択" selectFiles: "ファイルを選択"
renameFolder: "フォルダー名を変更" renameFile: "ファイル名を変更"
folderName: "フォルダー名"
createFolder: "フォルダーを作成" createFolder: "フォルダーを作成"
renameFolder: "フォルダー名を変更"
deleteFolder: "フォルダーを削除" deleteFolder: "フォルダーを削除"
addFile: "ファイルを追加" addFile: "ファイルを追加"
emptyDrive: "ドライブは空です" emptyDrive: "ドライブは空です"
emptyFolder: "フォルダーは空です" emptyFolder: "フォルダーは空です"
unableToDelete: "削除できません"
inputNewFileName: "新しいファイル名を入力してください"
inputNewFolderName: "新しいフォルダ名を入力してください"
circularReferenceFolder: "移動先のフォルダーは、移動するフォルダーのサブフォルダーです。"
hasChildFilesOrFolders: "このフォルダは空でないため、削除できません。"
copyUrl: "URLをコピー" copyUrl: "URLをコピー"
rename: "名前を変更" rename: "名前を変更"
avatar: "アイコン" avatar: "アイコン"
@ -395,13 +405,14 @@ strongPassword: "強いパスワード"
passwordMatched: "一致しました" passwordMatched: "一致しました"
passwordNotMatched: "一致していません" passwordNotMatched: "一致していません"
signinWith: "{x}でログイン" signinWith: "{x}でログイン"
signinFailed: "ログインできませんでした。ユーザー名とパスワードを確認してください。"
tapSecurityKey: "セキュリティーキーにタッチ" tapSecurityKey: "セキュリティーキーにタッチ"
or: "もしくは" or: "もしくは"
uiLanguage: "UIの表示言語" uiLanguage: "UIの表示言語"
groupInvited: "グループに招待されました" groupInvited: "グループに招待されました"
aboutX: "{x}について" aboutX: "{x}について"
useOsNativeEmojis: "OSネイティブの絵文字を使用" useOsNativeEmojis: "OSネイティブの絵文字を使用"
noGroups: "グループがありません" youHaveNoGroups: "グループがありません"
joinOrCreateGroup: "既存のグループに招待してもらうか、新しくグループを作成してください。" joinOrCreateGroup: "既存のグループに招待してもらうか、新しくグループを作成してください。"
noHistory: "履歴はありません" noHistory: "履歴はありません"
disableAnimatedMfm: "動きのあるMFMを無効にする" disableAnimatedMfm: "動きのあるMFMを無効にする"
@ -453,6 +464,8 @@ none: "なし"
volume: "音量" volume: "音量"
details: "詳細" details: "詳細"
chooseEmoji: "絵文字を選択" chooseEmoji: "絵文字を選択"
unableToProcess: "操作を完了できません"
recentUsed: "最近使用"
_sfx: _sfx:
note: "ノート" note: "ノート"
@ -679,45 +692,39 @@ _pages:
newPage: "ページの作成" newPage: "ページの作成"
editPage: "ページの編集" editPage: "ページの編集"
readPage: "ソースを表示中" readPage: "ソースを表示中"
page-created: "ページを作成しました" created: "ページを作成しました"
page-updated: "ページを更新しました" updated: "ページを更新しました"
name-already-exists: "指定されたページURLは既に存在しています" deleted: "ページを削除しました"
title-invalid-name: "不正なページURLです" nameAlreadyExists: "指定されたページURLは既に存在しています"
text-invalid-name: "空白でないか確認してください" invalidNameTitle: "不正なページURLです"
invalidNameText: "空白でないか確認してください"
editThisPage: "このページを編集" editThisPage: "このページを編集"
viewSource: "ソースを表示" viewSource: "ソースを表示"
viewPage: "ページを見る" viewPage: "ページを見る"
like: "いいね" like: "いいね"
unlike: "いいね解除" unlike: "いいね解除"
liked-pages: "いいねしたページ" my: "自分のページ"
my-pages: "自分のページ" liked: "いいねしたページ"
inspector: "インスペクター" inspector: "インスペクター"
content: "ページブロック" content: "ページブロック"
variables: "変数" variables: "変数"
variables-info: "変数を使うことで動的なページを作成できます。テキスト内で <b>{ 変数名 }</b> と書くとそこに変数の値を埋め込めます。例えば <b>Hello { thing } world!</b> というテキストで、変数(thing)の値が <b>ai</b> だった場合、テキストは <b>Hello ai world!</b> になります。"
variables-info2: "変数の評価(値を算出すること)は上から下に行われるので、ある変数の中で自分より下の変数を参照することはできません。例えば上から <b>A、B、C</b> と3つの変数を定義したとき、<b>C</b>の中で<b>A</b>や<b>B</b>を参照することはできますが、<b>A</b>の中で<b>B</b>や<b>C</b>を参照することはできません。"
variables-info3: "ユーザーからの入力を受け取るには、ページに「ユーザー入力」ブロックを設置し、「変数名」に入力を格納したい変数名を設定します(変数は自動で作成されます)。その変数を使ってユーザー入力に応じた動作を行えます。"
variables-info4: "関数を使うと、値の算出処理を再利用可能な形にまとめることができます。関数を作るには、「関数」タイプの変数を作成します。関数にはスロット(引数)を設定することができ、スロットの値は関数内で変数として利用可能です。また、AiScript標準で関数を引数に取る関数(高階関数と呼ばれます)も存在します。関数は予め定義しておくほかに、このような高階関数のスロットに即席でセットすることもできます。"
more-details: "詳しい説明"
title: "タイトル" title: "タイトル"
url: "ページURL" url: "ページURL"
summary: "ページの要約" summary: "ページの要約"
alignCenter: "中央寄せ" alignCenter: "中央寄せ"
hide-title-when-pinned: "ピン留めされているときにタイトルを非表示" hideTitleWhenPinned: "ピン留めされているときにタイトルを非表示"
font: "フォント" font: "フォント"
fontSerif: "セリフ" fontSerif: "セリフ"
fontSansSerif: "サンセリフ" fontSansSerif: "サンセリフ"
set-eye-catching-image: "アイキャッチ画像を設定" eyeCatchingImageSet: "アイキャッチ画像を設定"
remove-eye-catching-image: "アイキャッチ画像を削除" eyeCatchingImageRemove: "アイキャッチ画像を削除"
chooseBlock: "ブロックを追加" chooseBlock: "ブロックを追加"
selectType: "種類を選択" selectType: "種類を選択"
enterVariableName: "変数名を決めてください" enterVariableName: "変数名を決めてください"
the-variable-name-is-already-used: "その変数名は既に使われています" variableNameIsAlreadyUsed: "その変数名は既に使われています"
content-blocks: "コンテンツ" contentBlocks: "コンテンツ"
input-blocks: "入力" inputBlocks: "入力"
special-blocks: "特殊" specialBlocks: "特殊"
post-from-post-form: "この内容を投稿"
posted-from-post-form: "投稿しました"
blocks: blocks:
text: "テキスト" text: "テキスト"
textarea: "テキストエリア" textarea: "テキストエリア"

View file

@ -139,9 +139,9 @@ export default Vue.extend({
rename() { rename() {
this.$root.dialog({ this.$root.dialog({
title: this.$t('contextmenu.rename-file'), title: this.$t('renameFile'),
input: { input: {
placeholder: this.$t('contextmenu.input-new-file-name'), placeholder: this.$t('inputNewFileName'),
default: this.file.name, default: this.file.name,
allowEmpty: false allowEmpty: false
} }

View file

@ -137,14 +137,14 @@ export default Vue.extend({
switch (err) { switch (err) {
case 'detected-circular-definition': case 'detected-circular-definition':
this.$root.dialog({ this.$root.dialog({
title: this.$t('unable-to-process'), title: this.$t('unableToProcess'),
text: this.$t('circular-reference-detected') text: this.$t('circularReferenceFolder')
}); });
break; break;
default: default:
this.$root.dialog({ this.$root.dialog({
type: 'error', type: 'error',
text: this.$t('unhandled-error') text: this.$t('error')
}); });
} }
}); });
@ -177,9 +177,9 @@ export default Vue.extend({
rename() { rename() {
this.$root.dialog({ this.$root.dialog({
title: this.$t('contextmenu.rename-folder'), title: this.$t('renameFolder'),
input: { input: {
placeholder: this.$t('contextmenu.input-new-folder-name'), placeholder: this.$t('inputNewFolderName'),
default: this.folder.name default: this.folder.name
} }
}).then(({ canceled, result: name }) => { }).then(({ canceled, result: name }) => {
@ -206,14 +206,14 @@ export default Vue.extend({
case 'b0fc8a17-963c-405d-bfbc-859a487295e1': case 'b0fc8a17-963c-405d-bfbc-859a487295e1':
this.$root.dialog({ this.$root.dialog({
type: 'error', type: 'error',
title: this.$t('unable-to-delete'), title: this.$t('unableToDelete'),
text: this.$t('has-child-files-or-folders') text: this.$t('hasChildFilesOrFolders')
}); });
break; break;
default: default:
this.$root.dialog({ this.$root.dialog({
type: 'error', type: 'error',
text: this.$t('unable-to-delete') text: this.$t('unableToDelete')
}); });
} }
}); });

View file

@ -263,14 +263,14 @@ export default Vue.extend({
switch (err) { switch (err) {
case 'detected-circular-definition': case 'detected-circular-definition':
this.$root.dialog({ this.$root.dialog({
title: this.$t('unable-to-process'), title: this.$t('unableToProcess'),
text: this.$t('circular-reference-detected') text: this.$t('circularReferenceFolder')
}); });
break; break;
default: default:
this.$root.dialog({ this.$root.dialog({
type: 'error', type: 'error',
text: this.$t('unhandled-error') text: this.$t('error')
}); });
} }
}); });
@ -284,9 +284,9 @@ export default Vue.extend({
urlUpload() { urlUpload() {
this.$root.dialog({ this.$root.dialog({
title: this.$t('url-upload'), title: this.$t('uploadFromUrl'),
input: { input: {
placeholder: this.$t('url-of-file') placeholder: this.$t('uploadFromUrlDescription')
} }
}).then(({ canceled, result: url }) => { }).then(({ canceled, result: url }) => {
if (canceled) return; if (canceled) return;
@ -296,17 +296,17 @@ export default Vue.extend({
}); });
this.$root.dialog({ this.$root.dialog({
title: this.$t('url-upload-requested'), title: this.$t('uploadFromUrlRequested'),
text: this.$t('may-take-time') text: this.$t('uploadFromUrlMayTakeTime')
}); });
}); });
}, },
createFolder() { createFolder() {
this.$root.dialog({ this.$root.dialog({
title: this.$t('create-folder'), title: this.$t('createFolder'),
input: { input: {
placeholder: this.$t('folder-name') placeholder: this.$t('folderName')
} }
}).then(({ canceled, result: name }) => { }).then(({ canceled, result: name }) => {
if (canceled) return; if (canceled) return;
@ -321,9 +321,9 @@ export default Vue.extend({
renameFolder(folder) { renameFolder(folder) {
this.$root.dialog({ this.$root.dialog({
title: this.$t('contextmenu.rename-folder'), title: this.$t('renameFolder'),
input: { input: {
placeholder: this.$t('contextmenu.input-new-folder-name'), placeholder: this.$t('inputNewFolderName'),
default: folder.name default: folder.name
} }
}).then(({ canceled, result: name }) => { }).then(({ canceled, result: name }) => {
@ -349,14 +349,14 @@ export default Vue.extend({
case 'b0fc8a17-963c-405d-bfbc-859a487295e1': case 'b0fc8a17-963c-405d-bfbc-859a487295e1':
this.$root.dialog({ this.$root.dialog({
type: 'error', type: 'error',
title: this.$t('unable-to-delete'), title: this.$t('unableToDelete'),
text: this.$t('has-child-files-or-folders') text: this.$t('hasChildFilesOrFolders')
}); });
break; break;
default: default:
this.$root.dialog({ this.$root.dialog({
type: 'error', type: 'error',
text: this.$t('unable-to-delete') text: this.$t('unableToDelete')
}); });
} }
}); });

View file

@ -2,12 +2,11 @@
<x-popup :source="source" ref="popup" @closed="() => { $emit('closed'); destroyDom(); }"> <x-popup :source="source" ref="popup" @closed="() => { $emit('closed'); destroyDom(); }">
<div class="omfetrab"> <div class="omfetrab">
<header> <header>
<button v-for="category in categories" <button v-for="(category, i) in categories"
class="_button" class="_button"
:title="category.text"
@click="go(category)" @click="go(category)"
:class="{ active: category.isActive }" :class="{ active: category.isActive }"
:key="category.text" :key="i"
> >
<fa :icon="category.icon" fixed-width/> <fa :icon="category.icon" fixed-width/>
</button> </button>
@ -15,7 +14,7 @@
<div class="emojis"> <div class="emojis">
<template v-if="categories[0].isActive"> <template v-if="categories[0].isActive">
<header class="category"><fa :icon="faHistory" fixed-width/> {{ $t('recentUsedEmojis') }}</header> <header class="category"><fa :icon="faHistory" fixed-width/> {{ $t('recentUsed') }}</header>
<div class="list"> <div class="list">
<button v-for="(emoji, i) in ($store.state.device.recentEmojis || [])" <button v-for="(emoji, i) in ($store.state.device.recentEmojis || [])"
class="_button" class="_button"
@ -27,9 +26,10 @@
<img v-else :src="$store.state.device.disableShowingAnimatedImages ? getStaticImageUrl(emoji.url) : emoji.url"/> <img v-else :src="$store.state.device.disableShowingAnimatedImages ? getStaticImageUrl(emoji.url) : emoji.url"/>
</button> </button>
</div> </div>
<header class="category"><fa :icon="faAsterisk" fixed-width/> {{ $t('customEmojis') }}</header>
</template> </template>
<header class="category"><fa :icon="categories.find(x => x.isActive).icon" fixed-width/> {{ categories.find(x => x.isActive).text }}</header>
<template v-if="categories.find(x => x.isActive).name"> <template v-if="categories.find(x => x.isActive).name">
<div class="list"> <div class="list">
<button v-for="emoji in emojilist.filter(e => e.category === categories.find(x => x.isActive).name)" <button v-for="emoji in emojilist.filter(e => e.category === categories.find(x => x.isActive).name)"
@ -92,47 +92,38 @@ export default Vue.extend({
customEmojis: {}, customEmojis: {},
faGlobe, faHistory, faGlobe, faHistory,
categories: [{ categories: [{
text: this.$t('customEmoji'),
icon: faAsterisk, icon: faAsterisk,
isActive: true isActive: true
}, { }, {
name: 'people', name: 'people',
text: this.$t('people'),
icon: faLaugh, icon: faLaugh,
isActive: false isActive: false
}, { }, {
name: 'animals_and_nature', name: 'animals_and_nature',
text: this.$t('animals-and-nature'),
icon: faLeaf, icon: faLeaf,
isActive: false isActive: false
}, { }, {
name: 'food_and_drink', name: 'food_and_drink',
text: this.$t('food-and-drink'),
icon: faUtensils, icon: faUtensils,
isActive: false isActive: false
}, { }, {
name: 'activity', name: 'activity',
text: this.$t('activity'),
icon: faFutbol, icon: faFutbol,
isActive: false isActive: false
}, { }, {
name: 'travel_and_places', name: 'travel_and_places',
text: this.$t('travel-and-places'),
icon: faCity, icon: faCity,
isActive: false isActive: false
}, { }, {
name: 'objects', name: 'objects',
text: this.$t('objects'),
icon: faDice, icon: faDice,
isActive: false isActive: false
}, { }, {
name: 'symbols', name: 'symbols',
text: this.$t('symbols'),
icon: faHeart, icon: faHeart,
isActive: false isActive: false
}, { }, {
name: 'flags', name: 'flags',
text: this.$t('flags'),
icon: faFlag, icon: faFlag,
isActive: false isActive: false
}] }]

View file

@ -155,7 +155,7 @@ export default Vue.extend({
if (err === null) return; if (err === null) return;
this.$root.dialog({ this.$root.dialog({
type: 'error', type: 'error',
text: this.$t('login-failed') text: this.$t('signinFailed')
}); });
this.signing = false; this.signing = false;
}); });
@ -176,7 +176,7 @@ export default Vue.extend({
}).catch(() => { }).catch(() => {
this.$root.dialog({ this.$root.dialog({
type: 'error', type: 'error',
text: this.$t('login-failed') text: this.$t('signinFailed')
}); });
this.challengeData = null; this.challengeData = null;
this.totpLogin = false; this.totpLogin = false;

View file

@ -61,7 +61,7 @@ export default Vue.extend({
this.$root.dialog({ this.$root.dialog({
type: 'error', type: 'error',
text: this.$t('some-error') text: this.$t('error')
}); });
}); });
} }

View file

@ -113,7 +113,7 @@ export default Vue.extend({
if (items[0].kind == 'file') { if (items[0].kind == 'file') {
this.$root.dialog({ this.$root.dialog({
type: 'error', type: 'error',
text: this.$t('only-one-file-attached') text: this.$t('onlyOneFileCanBeAttached')
}); });
} }
} }
@ -138,7 +138,7 @@ export default Vue.extend({
e.preventDefault(); e.preventDefault();
this.$root.dialog({ this.$root.dialog({
type: 'error', type: 'error',
text: this.$t('only-one-file-attached') text: this.$t('onlyOneFileCanBeAttached')
}); });
return; return;
} }

View file

@ -145,7 +145,7 @@ export default Vue.extend({
if (groups1.length === 0 && groups2.length === 0) { if (groups1.length === 0 && groups2.length === 0) {
this.$root.dialog({ this.$root.dialog({
type: 'warning', type: 'warning',
title: this.$t('noGroups'), title: this.$t('youHaveNoGroups'),
text: this.$t('joinOrCreateGroup'), text: this.$t('joinOrCreateGroup'),
}); });
return; return;

View file

@ -69,7 +69,7 @@ export default Vue.extend({
async add() { async add() {
const { canceled, result: type } = await this.$root.dialog({ const { canceled, result: type } = await this.$root.dialog({
type: null, type: null,
title: this.$t('choose-block'), title: this.$t('_pages.chooseBlock'),
select: { select: {
groupedItems: this.getPageBlockList() groupedItems: this.getPageBlockList()
}, },

View file

@ -80,7 +80,7 @@ export default Vue.extend({
async add() { async add() {
const { canceled, result: type } = await this.$root.dialog({ const { canceled, result: type } = await this.$root.dialog({
type: null, type: null,
title: this.$t('choose-block'), title: this.$t('_pages.chooseBlock'),
select: { select: {
groupedItems: this.getPageBlockList() groupedItems: this.getPageBlockList()
}, },

View file

@ -212,7 +212,7 @@ export default Vue.extend({
async changeType() { async changeType() {
const { canceled, result: type } = await this.$root.dialog({ const { canceled, result: type } = await this.$root.dialog({
type: null, type: null,
title: this.$t('select-type'), title: this.$t('_pages.selectType'),
select: { select: {
groupedItems: this.getScriptBlockList(this.getExpectedType ? this.getExpectedType() : null) groupedItems: this.getScriptBlockList(this.getExpectedType ? this.getExpectedType() : null)
}, },

View file

@ -2,7 +2,7 @@
<div> <div>
<div class="gwbmwxkm _panel"> <div class="gwbmwxkm _panel">
<header> <header>
<div class="title"><fa :icon="faStickyNote"/> {{ readonly ? $t('readPage') : pageId ? $t('editPage') : $t('newPage') }}</div> <div class="title"><fa :icon="faStickyNote"/> {{ readonly ? $t('_pages.readPage') : pageId ? $t('_pages.editPage') : $t('_pages.newPage') }}</div>
<div class="buttons"> <div class="buttons">
<button class="_button" @click="del()" v-if="!readonly"><fa :icon="faTrashAlt"/></button> <button class="_button" @click="del()" v-if="!readonly"><fa :icon="faTrashAlt"/></button>
<button class="_button" @click="() => showOptions = !showOptions"><fa :icon="faCog"/></button> <button class="_button" @click="() => showOptions = !showOptions"><fa :icon="faCog"/></button>
@ -11,37 +11,37 @@
</header> </header>
<section> <section>
<router-link class="view" v-if="pageId" :to="`/@${ author.username }/pages/${ currentName }`"><fa :icon="faExternalLinkSquareAlt"/> {{ $t('view-page') }}</router-link> <router-link class="view" v-if="pageId" :to="`/@${ author.username }/pages/${ currentName }`"><fa :icon="faExternalLinkSquareAlt"/> {{ $t('_pages.viewPage') }}</router-link>
<mk-input v-model="title"> <mk-input v-model="title">
<span>{{ $t('title') }}</span> <span>{{ $t('_pages.title') }}</span>
</mk-input> </mk-input>
<template v-if="showOptions"> <template v-if="showOptions">
<mk-input v-model="summary"> <mk-input v-model="summary">
<span>{{ $t('summary') }}</span> <span>{{ $t('_pages.summary') }}</span>
</mk-input> </mk-input>
<mk-input v-model="name"> <mk-input v-model="name">
<template #prefix>{{ url }}/@{{ author.username }}/pages/</template> <template #prefix>{{ url }}/@{{ author.username }}/pages/</template>
<span>{{ $t('url') }}</span> <span>{{ $t('_pages.url') }}</span>
</mk-input> </mk-input>
<mk-switch v-model="alignCenter">{{ $t('alignCenter') }}</mk-switch> <mk-switch v-model="alignCenter">{{ $t('_pages.alignCenter') }}</mk-switch>
<mk-select v-model="font"> <mk-select v-model="font">
<template #label>{{ $t('font') }}</template> <template #label>{{ $t('_pages.font') }}</template>
<option value="serif">{{ $t('fontSerif') }}</option> <option value="serif">{{ $t('_pages.fontSerif') }}</option>
<option value="sans-serif">{{ $t('fontSansSerif') }}</option> <option value="sans-serif">{{ $t('_pages.fontSansSerif') }}</option>
</mk-select> </mk-select>
<mk-switch v-model="hideTitleWhenPinned">{{ $t('hide-title-when-pinned') }}</mk-switch> <mk-switch v-model="hideTitleWhenPinned">{{ $t('_pages.hideTitleWhenPinned') }}</mk-switch>
<div class="eyeCatch"> <div class="eyeCatch">
<mk-button v-if="eyeCatchingImageId == null && !readonly" @click="setEyeCatchingImage()"><fa :icon="faPlus"/> {{ $t('set-eye-catching-image') }}</mk-button> <mk-button v-if="eyeCatchingImageId == null && !readonly" @click="setEyeCatchingImage()"><fa :icon="faPlus"/> {{ $t('_pages.eyeCatchingImageSet') }}</mk-button>
<div v-else-if="eyeCatchingImage"> <div v-else-if="eyeCatchingImage">
<img :src="eyeCatchingImage.url" :alt="eyeCatchingImage.name"/> <img :src="eyeCatchingImage.url" :alt="eyeCatchingImage.name"/>
<mk-button @click="removeEyeCatchingImage()" v-if="!readonly"><fa :icon="faTrashAlt"/> {{ $t('remove-eye-catching-image') }}</mk-button> <mk-button @click="removeEyeCatchingImage()" v-if="!readonly"><fa :icon="faTrashAlt"/> {{ $t('_pages.eyeCatchingImageRemove') }}</mk-button>
</div> </div>
</div> </div>
</template> </template>
@ -53,7 +53,7 @@
</div> </div>
<mk-container :body-togglable="true"> <mk-container :body-togglable="true">
<template #header><fa :icon="faMagic"/> {{ $t('variables') }}</template> <template #header><fa :icon="faMagic"/> {{ $t('_pages.variables') }}</template>
<div class="qmuvgica"> <div class="qmuvgica">
<x-draggable tag="div" class="variables" v-show="variables.length > 0" :list="variables" handle=".drag-handle" :group="{ name: 'variables' }" animation="150" swap-threshold="0.5"> <x-draggable tag="div" class="variables" v-show="variables.length > 0" :list="variables" handle=".drag-handle" :group="{ name: 'variables' }" animation="150" swap-threshold="0.5">
<x-variable v-for="variable in variables" <x-variable v-for="variable in variables"
@ -70,22 +70,14 @@
</x-draggable> </x-draggable>
<mk-button @click="addVariable()" class="add" v-if="!readonly"><fa :icon="faPlus"/></mk-button> <mk-button @click="addVariable()" class="add" v-if="!readonly"><fa :icon="faPlus"/></mk-button>
<x-info><span v-html="$t('variables-info')"></span><a @click="() => moreDetails = true" style="display:block;">{{ $t('more-details') }}</a></x-info>
<template v-if="moreDetails">
<x-info><span v-html="$t('variables-info2')"></span></x-info>
<x-info><span v-html="$t('variables-info3')"></span></x-info>
<x-info><span v-html="$t('variables-info4')"></span></x-info>
</template>
</div> </div>
</mk-container> </mk-container>
<mk-container :body-togglable="true" :expanded="false"> <mk-container :body-togglable="true" :expanded="false">
<template #header><fa :icon="faCode"/> {{ $t('inspector') }}</template> <template #header><fa :icon="faCode"/> {{ $t('_pages.inspector') }}</template>
<div style="padding:0 32px 32px 32px;"> <div style="padding:0 32px 32px 32px;">
<mk-textarea :value="JSON.stringify(content, null, 2)" readonly tall>{{ $t('content') }}</mk-textarea> <mk-textarea :value="JSON.stringify(content, null, 2)" readonly tall>{{ $t('_pages.content') }}</mk-textarea>
<mk-textarea :value="JSON.stringify(variables, null, 2)" readonly tall>{{ $t('variables') }}</mk-textarea> <mk-textarea :value="JSON.stringify(variables, null, 2)" readonly tall>{{ $t('_pages.variables') }}</mk-textarea>
</div> </div>
</mk-container> </mk-container>
</div> </div>
@ -152,7 +144,6 @@ export default Vue.extend({
variables: [], variables: [],
aiScript: null, aiScript: null,
showOptions: false, showOptions: false,
moreDetails: false,
url, url,
faPlus, faICursor, faSave, faStickyNote, faMagic, faCog, faTrashAlt, faExternalLinkSquareAlt, faCode faPlus, faICursor, faSave, faStickyNote, faMagic, faCog, faTrashAlt, faExternalLinkSquareAlt, faCode
}; };
@ -243,14 +234,14 @@ export default Vue.extend({
if (err.info.param == 'name') { if (err.info.param == 'name') {
this.$root.dialog({ this.$root.dialog({
type: 'error', type: 'error',
title: this.$t('title-invalid-name'), title: this.$t('_pages.invalidNameTitle'),
text: this.$t('text-invalid-name') text: this.$t('_pages.invalidNameText')
}); });
} }
} else if (err.code == 'NAME_ALREADY_EXISTS') { } else if (err.code == 'NAME_ALREADY_EXISTS') {
this.$root.dialog({ this.$root.dialog({
type: 'error', type: 'error',
text: this.$t('name-already-exists') text: this.$t('_pages.nameAlreadyExists')
}); });
} }
}; };
@ -262,7 +253,7 @@ export default Vue.extend({
this.currentName = this.name.trim(); this.currentName = this.name.trim();
this.$root.dialog({ this.$root.dialog({
type: 'success', type: 'success',
text: this.$t('page-updated') text: this.$t('_pages.updated')
}); });
}).catch(onError); }).catch(onError);
} else { } else {
@ -272,7 +263,7 @@ export default Vue.extend({
this.currentName = this.name.trim(); this.currentName = this.name.trim();
this.$root.dialog({ this.$root.dialog({
type: 'success', type: 'success',
text: this.$t('page-created') text: this.$t('_pages.created')
}); });
this.$router.push(`/my/pages/edit/${this.pageId}`); this.$router.push(`/my/pages/edit/${this.pageId}`);
}).catch(onError); }).catch(onError);
@ -282,7 +273,7 @@ export default Vue.extend({
del() { del() {
this.$root.dialog({ this.$root.dialog({
type: 'warning', type: 'warning',
text: this.$t('are-you-sure-delete'), text: this.$t('removeAreYouSure', { x: this.title.trim() }),
showCancelButton: true showCancelButton: true
}).then(({ canceled }) => { }).then(({ canceled }) => {
if (canceled) return; if (canceled) return;
@ -291,7 +282,7 @@ export default Vue.extend({
}).then(() => { }).then(() => {
this.$root.dialog({ this.$root.dialog({
type: 'success', type: 'success',
text: this.$t('page-deleted') text: this.$t('_pages.deleted')
}); });
this.$router.push(`/my/pages`); this.$router.push(`/my/pages`);
}); });
@ -301,7 +292,7 @@ export default Vue.extend({
async add() { async add() {
const { canceled, result: type } = await this.$root.dialog({ const { canceled, result: type } = await this.$root.dialog({
type: null, type: null,
title: this.$t('chooseBlock'), title: this.$t('_pages.chooseBlock'),
select: { select: {
groupedItems: this.getPageBlockList() groupedItems: this.getPageBlockList()
}, },
@ -315,7 +306,7 @@ export default Vue.extend({
async addVariable() { async addVariable() {
let { canceled, result: name } = await this.$root.dialog({ let { canceled, result: name } = await this.$root.dialog({
title: this.$t('enterVariableName'), title: this.$t('_pages.enterVariableName'),
input: { input: {
type: 'text', type: 'text',
}, },
@ -328,7 +319,7 @@ export default Vue.extend({
if (this.aiScript.isUsedName(name)) { if (this.aiScript.isUsedName(name)) {
this.$root.dialog({ this.$root.dialog({
type: 'error', type: 'error',
text: this.$t('the-variable-name-is-already-used') text: this.$t('_pages.variableNameIsAlreadyUsed')
}); });
return; return;
} }
@ -348,7 +339,7 @@ export default Vue.extend({
getPageBlockList() { getPageBlockList() {
return [{ return [{
label: this.$t('content-blocks'), label: this.$t('_pages.contentBlocks'),
items: [ items: [
{ value: 'section', text: this.$t('_pages.blocks.section') }, { value: 'section', text: this.$t('_pages.blocks.section') },
{ value: 'text', text: this.$t('_pages.blocks.text') }, { value: 'text', text: this.$t('_pages.blocks.text') },
@ -356,7 +347,7 @@ export default Vue.extend({
{ value: 'textarea', text: this.$t('_pages.blocks.textarea') }, { value: 'textarea', text: this.$t('_pages.blocks.textarea') },
] ]
}, { }, {
label: this.$t('input-blocks'), label: this.$t('_pages.inputBlocks'),
items: [ items: [
{ value: 'button', text: this.$t('_pages.blocks.button') }, { value: 'button', text: this.$t('_pages.blocks.button') },
{ value: 'radioButton', text: this.$t('_pages.blocks.radioButton') }, { value: 'radioButton', text: this.$t('_pages.blocks.radioButton') },
@ -367,7 +358,7 @@ export default Vue.extend({
{ value: 'counter', text: this.$t('_pages.blocks.counter') } { value: 'counter', text: this.$t('_pages.blocks.counter') }
] ]
}, { }, {
label: this.$t('special-blocks'), label: this.$t('_pages.specialBlocks'),
items: [ items: [
{ value: 'if', text: this.$t('_pages.blocks.if') }, { value: 'if', text: this.$t('_pages.blocks.if') },
{ value: 'post', text: this.$t('_pages.blocks.post') } { value: 'post', text: this.$t('_pages.blocks.post') }

View file

@ -1,7 +1,7 @@
<template> <template>
<div> <div>
<mk-container :body-togglable="true"> <mk-container :body-togglable="true">
<template #header><fa :icon="faEdit" fixed-width/>{{ $t('my-pages') }}</template> <template #header><fa :icon="faEdit" fixed-width/>{{ $t('_pages.my') }}</template>
<div class="rknalgpo my"> <div class="rknalgpo my">
<mk-button class="new" @click="create()"><fa :icon="faPlus"/></mk-button> <mk-button class="new" @click="create()"><fa :icon="faPlus"/></mk-button>
<mk-pagination :pagination="myPagesPagination" #default="{items}"> <mk-pagination :pagination="myPagesPagination" #default="{items}">
@ -11,7 +11,7 @@
</mk-container> </mk-container>
<mk-container :body-togglable="true"> <mk-container :body-togglable="true">
<template #header><fa :icon="faHeart" fixed-width/>{{ $t('liked-pages') }}</template> <template #header><fa :icon="faHeart" fixed-width/>{{ $t('_pages.liked') }}</template>
<div class="rknalgpo"> <div class="rknalgpo">
<mk-pagination :pagination="likedPagesPagination" #default="{items}"> <mk-pagination :pagination="likedPagesPagination" #default="{items}">
<mk-page-preview v-for="like in items" class="ckltabjg" :page="like.page" :key="like.page.id"/> <mk-page-preview v-for="like in items" class="ckltabjg" :page="like.page" :key="like.page.id"/>

10
src/docs/pages.ja-JP.md Normal file
View file

@ -0,0 +1,10 @@
# Pages
## 変数
変数を使うことで動的なページを作成できます。テキスト内で <b>{ 変数名 }</b> と書くとそこに変数の値を埋め込めます。例えば <b>Hello { thing } world!</b> というテキストで、変数(thing)の値が <b>ai</b> だった場合、テキストは <b>Hello ai world!</b> になります。
変数の評価(値を算出すること)は上から下に行われるので、ある変数の中で自分より下の変数を参照することはできません。例えば上から <b>A、B、C</b> と3つの変数を定義したとき、<b>C</b>の中で<b>A</b><b>B</b>を参照することはできますが、<b>A</b>の中で<b>B</b><b>C</b>を参照することはできません。
ユーザーからの入力を受け取るには、ページに「ユーザー入力」ブロックを設置し、「変数名」に入力を格納したい変数名を設定します(変数は自動で作成されます)。その変数を使ってユーザー入力に応じた動作を行えます。
関数を使うと、値の算出処理を再利用可能な形にまとめることができます。関数を作るには、「関数」タイプの変数を作成します。関数にはスロット(引数)を設定することができ、スロットの値は関数内で変数として利用可能です。また、AiScript標準で関数を引数に取る関数(高階関数と呼ばれます)も存在します。関数は予め定義しておくほかに、このような高階関数のスロットに即席でセットすることもできます。