summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSatsuki Yanagi <17376330+u1-liquid@users.noreply.github.com>2020-03-22 10:51:40 +0900
committerGitHub <noreply@github.com>2020-03-22 10:51:40 +0900
commit903e93ae01f3cf0dfbcb7bfb4b01167f5c03db25 (patch)
tree8abf048d54b14d66443ccd46e743e8e9b4828e36 /src
parentUpdate ja-JP.yml (diff)
downloadsharkey-903e93ae01f3cf0dfbcb7bfb4b01167f5c03db25.tar.gz
sharkey-903e93ae01f3cf0dfbcb7bfb4b01167f5c03db25.tar.bz2
sharkey-903e93ae01f3cf0dfbcb7bfb4b01167f5c03db25.zip
i18n (#6171)
* i18n Resolve #6155 * i18n for drive * :v: * Extract doc Co-authored-by: syuilo <syuilotan@yahoo.co.jp>
Diffstat (limited to 'src')
-rw-r--r--src/client/components/drive.file.vue4
-rw-r--r--src/client/components/drive.folder.vue16
-rw-r--r--src/client/components/drive.vue28
-rw-r--r--src/client/components/emoji-picker.vue19
-rwxr-xr-xsrc/client/components/signin.vue4
-rw-r--r--src/client/pages/index.welcome.setup.vue2
-rw-r--r--src/client/pages/messaging-room.form.vue4
-rw-r--r--src/client/pages/messaging.vue2
-rw-r--r--src/client/pages/page-editor/els/page-editor.el.if.vue2
-rw-r--r--src/client/pages/page-editor/els/page-editor.el.section.vue2
-rw-r--r--src/client/pages/page-editor/page-editor.script-block.vue2
-rw-r--r--src/client/pages/page-editor/page-editor.vue67
-rw-r--r--src/client/pages/pages.vue4
-rw-r--r--src/docs/pages.ja-JP.md10
14 files changed, 79 insertions, 87 deletions
diff --git a/src/client/components/drive.file.vue b/src/client/components/drive.file.vue
index 2ef3fd38e4..014e1a6ca5 100644
--- a/src/client/components/drive.file.vue
+++ b/src/client/components/drive.file.vue
@@ -139,9 +139,9 @@ export default Vue.extend({
rename() {
this.$root.dialog({
- title: this.$t('contextmenu.rename-file'),
+ title: this.$t('renameFile'),
input: {
- placeholder: this.$t('contextmenu.input-new-file-name'),
+ placeholder: this.$t('inputNewFileName'),
default: this.file.name,
allowEmpty: false
}
diff --git a/src/client/components/drive.folder.vue b/src/client/components/drive.folder.vue
index 658aced3e8..2e861e2480 100644
--- a/src/client/components/drive.folder.vue
+++ b/src/client/components/drive.folder.vue
@@ -137,14 +137,14 @@ export default Vue.extend({
switch (err) {
case 'detected-circular-definition':
this.$root.dialog({
- title: this.$t('unable-to-process'),
- text: this.$t('circular-reference-detected')
+ title: this.$t('unableToProcess'),
+ text: this.$t('circularReferenceFolder')
});
break;
default:
this.$root.dialog({
type: 'error',
- text: this.$t('unhandled-error')
+ text: this.$t('error')
});
}
});
@@ -177,9 +177,9 @@ export default Vue.extend({
rename() {
this.$root.dialog({
- title: this.$t('contextmenu.rename-folder'),
+ title: this.$t('renameFolder'),
input: {
- placeholder: this.$t('contextmenu.input-new-folder-name'),
+ placeholder: this.$t('inputNewFolderName'),
default: this.folder.name
}
}).then(({ canceled, result: name }) => {
@@ -206,14 +206,14 @@ export default Vue.extend({
case 'b0fc8a17-963c-405d-bfbc-859a487295e1':
this.$root.dialog({
type: 'error',
- title: this.$t('unable-to-delete'),
- text: this.$t('has-child-files-or-folders')
+ title: this.$t('unableToDelete'),
+ text: this.$t('hasChildFilesOrFolders')
});
break;
default:
this.$root.dialog({
type: 'error',
- text: this.$t('unable-to-delete')
+ text: this.$t('unableToDelete')
});
}
});
diff --git a/src/client/components/drive.vue b/src/client/components/drive.vue
index bb35b156aa..fddac5b9aa 100644
--- a/src/client/components/drive.vue
+++ b/src/client/components/drive.vue
@@ -263,14 +263,14 @@ export default Vue.extend({
switch (err) {
case 'detected-circular-definition':
this.$root.dialog({
- title: this.$t('unable-to-process'),
- text: this.$t('circular-reference-detected')
+ title: this.$t('unableToProcess'),
+ text: this.$t('circularReferenceFolder')
});
break;
default:
this.$root.dialog({
type: 'error',
- text: this.$t('unhandled-error')
+ text: this.$t('error')
});
}
});
@@ -284,9 +284,9 @@ export default Vue.extend({
urlUpload() {
this.$root.dialog({
- title: this.$t('url-upload'),
+ title: this.$t('uploadFromUrl'),
input: {
- placeholder: this.$t('url-of-file')
+ placeholder: this.$t('uploadFromUrlDescription')
}
}).then(({ canceled, result: url }) => {
if (canceled) return;
@@ -296,17 +296,17 @@ export default Vue.extend({
});
this.$root.dialog({
- title: this.$t('url-upload-requested'),
- text: this.$t('may-take-time')
+ title: this.$t('uploadFromUrlRequested'),
+ text: this.$t('uploadFromUrlMayTakeTime')
});
});
},
createFolder() {
this.$root.dialog({
- title: this.$t('create-folder'),
+ title: this.$t('createFolder'),
input: {
- placeholder: this.$t('folder-name')
+ placeholder: this.$t('folderName')
}
}).then(({ canceled, result: name }) => {
if (canceled) return;
@@ -321,9 +321,9 @@ export default Vue.extend({
renameFolder(folder) {
this.$root.dialog({
- title: this.$t('contextmenu.rename-folder'),
+ title: this.$t('renameFolder'),
input: {
- placeholder: this.$t('contextmenu.input-new-folder-name'),
+ placeholder: this.$t('inputNewFolderName'),
default: folder.name
}
}).then(({ canceled, result: name }) => {
@@ -349,14 +349,14 @@ export default Vue.extend({
case 'b0fc8a17-963c-405d-bfbc-859a487295e1':
this.$root.dialog({
type: 'error',
- title: this.$t('unable-to-delete'),
- text: this.$t('has-child-files-or-folders')
+ title: this.$t('unableToDelete'),
+ text: this.$t('hasChildFilesOrFolders')
});
break;
default:
this.$root.dialog({
type: 'error',
- text: this.$t('unable-to-delete')
+ text: this.$t('unableToDelete')
});
}
});
diff --git a/src/client/components/emoji-picker.vue b/src/client/components/emoji-picker.vue
index a647b0ea04..e346023f29 100644
--- a/src/client/components/emoji-picker.vue
+++ b/src/client/components/emoji-picker.vue
@@ -2,12 +2,11 @@
<x-popup :source="source" ref="popup" @closed="() => { $emit('closed'); destroyDom(); }">
<div class="omfetrab">
<header>
- <button v-for="category in categories"
+ <button v-for="(category, i) in categories"
class="_button"
- :title="category.text"
@click="go(category)"
:class="{ active: category.isActive }"
- :key="category.text"
+ :key="i"
>
<fa :icon="category.icon" fixed-width/>
</button>
@@ -15,7 +14,7 @@
<div class="emojis">
<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">
<button v-for="(emoji, i) in ($store.state.device.recentEmojis || [])"
class="_button"
@@ -27,9 +26,10 @@
<img v-else :src="$store.state.device.disableShowingAnimatedImages ? getStaticImageUrl(emoji.url) : emoji.url"/>
</button>
</div>
+
+ <header class="category"><fa :icon="faAsterisk" fixed-width/> {{ $t('customEmojis') }}</header>
</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">
<div class="list">
<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: {},
faGlobe, faHistory,
categories: [{
- text: this.$t('customEmoji'),
icon: faAsterisk,
isActive: true
}, {
name: 'people',
- text: this.$t('people'),
icon: faLaugh,
isActive: false
}, {
name: 'animals_and_nature',
- text: this.$t('animals-and-nature'),
icon: faLeaf,
isActive: false
}, {
name: 'food_and_drink',
- text: this.$t('food-and-drink'),
icon: faUtensils,
isActive: false
}, {
name: 'activity',
- text: this.$t('activity'),
icon: faFutbol,
isActive: false
}, {
name: 'travel_and_places',
- text: this.$t('travel-and-places'),
icon: faCity,
isActive: false
}, {
name: 'objects',
- text: this.$t('objects'),
icon: faDice,
isActive: false
}, {
name: 'symbols',
- text: this.$t('symbols'),
icon: faHeart,
isActive: false
}, {
name: 'flags',
- text: this.$t('flags'),
icon: faFlag,
isActive: false
}]
diff --git a/src/client/components/signin.vue b/src/client/components/signin.vue
index 758bc59107..3d68289390 100755
--- a/src/client/components/signin.vue
+++ b/src/client/components/signin.vue
@@ -155,7 +155,7 @@ export default Vue.extend({
if (err === null) return;
this.$root.dialog({
type: 'error',
- text: this.$t('login-failed')
+ text: this.$t('signinFailed')
});
this.signing = false;
});
@@ -176,7 +176,7 @@ export default Vue.extend({
}).catch(() => {
this.$root.dialog({
type: 'error',
- text: this.$t('login-failed')
+ text: this.$t('signinFailed')
});
this.challengeData = null;
this.totpLogin = false;
diff --git a/src/client/pages/index.welcome.setup.vue b/src/client/pages/index.welcome.setup.vue
index a339ac0a28..6d08f5b5d4 100644
--- a/src/client/pages/index.welcome.setup.vue
+++ b/src/client/pages/index.welcome.setup.vue
@@ -61,7 +61,7 @@ export default Vue.extend({
this.$root.dialog({
type: 'error',
- text: this.$t('some-error')
+ text: this.$t('error')
});
});
}
diff --git a/src/client/pages/messaging-room.form.vue b/src/client/pages/messaging-room.form.vue
index 14659fb1c4..72e2632772 100644
--- a/src/client/pages/messaging-room.form.vue
+++ b/src/client/pages/messaging-room.form.vue
@@ -113,7 +113,7 @@ export default Vue.extend({
if (items[0].kind == 'file') {
this.$root.dialog({
type: 'error',
- text: this.$t('only-one-file-attached')
+ text: this.$t('onlyOneFileCanBeAttached')
});
}
}
@@ -138,7 +138,7 @@ export default Vue.extend({
e.preventDefault();
this.$root.dialog({
type: 'error',
- text: this.$t('only-one-file-attached')
+ text: this.$t('onlyOneFileCanBeAttached')
});
return;
}
diff --git a/src/client/pages/messaging.vue b/src/client/pages/messaging.vue
index 2179115dea..47d761d895 100644
--- a/src/client/pages/messaging.vue
+++ b/src/client/pages/messaging.vue
@@ -145,7 +145,7 @@ export default Vue.extend({
if (groups1.length === 0 && groups2.length === 0) {
this.$root.dialog({
type: 'warning',
- title: this.$t('noGroups'),
+ title: this.$t('youHaveNoGroups'),
text: this.$t('joinOrCreateGroup'),
});
return;
diff --git a/src/client/pages/page-editor/els/page-editor.el.if.vue b/src/client/pages/page-editor/els/page-editor.el.if.vue
index 3c545a7ddc..5e531a7ab5 100644
--- a/src/client/pages/page-editor/els/page-editor.el.if.vue
+++ b/src/client/pages/page-editor/els/page-editor.el.if.vue
@@ -69,7 +69,7 @@ export default Vue.extend({
async add() {
const { canceled, result: type } = await this.$root.dialog({
type: null,
- title: this.$t('choose-block'),
+ title: this.$t('_pages.chooseBlock'),
select: {
groupedItems: this.getPageBlockList()
},
diff --git a/src/client/pages/page-editor/els/page-editor.el.section.vue b/src/client/pages/page-editor/els/page-editor.el.section.vue
index d405ee1965..8de796e6d6 100644
--- a/src/client/pages/page-editor/els/page-editor.el.section.vue
+++ b/src/client/pages/page-editor/els/page-editor.el.section.vue
@@ -80,7 +80,7 @@ export default Vue.extend({
async add() {
const { canceled, result: type } = await this.$root.dialog({
type: null,
- title: this.$t('choose-block'),
+ title: this.$t('_pages.chooseBlock'),
select: {
groupedItems: this.getPageBlockList()
},
diff --git a/src/client/pages/page-editor/page-editor.script-block.vue b/src/client/pages/page-editor/page-editor.script-block.vue
index ae56803a39..f56e848c39 100644
--- a/src/client/pages/page-editor/page-editor.script-block.vue
+++ b/src/client/pages/page-editor/page-editor.script-block.vue
@@ -212,7 +212,7 @@ export default Vue.extend({
async changeType() {
const { canceled, result: type } = await this.$root.dialog({
type: null,
- title: this.$t('select-type'),
+ title: this.$t('_pages.selectType'),
select: {
groupedItems: this.getScriptBlockList(this.getExpectedType ? this.getExpectedType() : null)
},
diff --git a/src/client/pages/page-editor/page-editor.vue b/src/client/pages/page-editor/page-editor.vue
index 8b357584a5..6144b0bd9c 100644
--- a/src/client/pages/page-editor/page-editor.vue
+++ b/src/client/pages/page-editor/page-editor.vue
@@ -2,7 +2,7 @@
<div>
<div class="gwbmwxkm _panel">
<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">
<button class="_button" @click="del()" v-if="!readonly"><fa :icon="faTrashAlt"/></button>
<button class="_button" @click="() => showOptions = !showOptions"><fa :icon="faCog"/></button>
@@ -11,37 +11,37 @@
</header>
<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">
- <span>{{ $t('title') }}</span>
+ <span>{{ $t('_pages.title') }}</span>
</mk-input>
<template v-if="showOptions">
<mk-input v-model="summary">
- <span>{{ $t('summary') }}</span>
+ <span>{{ $t('_pages.summary') }}</span>
</mk-input>
<mk-input v-model="name">
<template #prefix>{{ url }}/@{{ author.username }}/pages/</template>
- <span>{{ $t('url') }}</span>
+ <span>{{ $t('_pages.url') }}</span>
</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">
- <template #label>{{ $t('font') }}</template>
- <option value="serif">{{ $t('fontSerif') }}</option>
- <option value="sans-serif">{{ $t('fontSansSerif') }}</option>
+ <template #label>{{ $t('_pages.font') }}</template>
+ <option value="serif">{{ $t('_pages.fontSerif') }}</option>
+ <option value="sans-serif">{{ $t('_pages.fontSansSerif') }}</option>
</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">
- <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">
<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>
</template>
@@ -53,7 +53,7 @@
</div>
<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">
<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"
@@ -70,22 +70,14 @@
</x-draggable>
<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>
</mk-container>
<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;">
- <mk-textarea :value="JSON.stringify(content, null, 2)" readonly tall>{{ $t('content') }}</mk-textarea>
- <mk-textarea :value="JSON.stringify(variables, null, 2)" readonly tall>{{ $t('variables') }}</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('_pages.variables') }}</mk-textarea>
</div>
</mk-container>
</div>
@@ -152,7 +144,6 @@ export default Vue.extend({
variables: [],
aiScript: null,
showOptions: false,
- moreDetails: false,
url,
faPlus, faICursor, faSave, faStickyNote, faMagic, faCog, faTrashAlt, faExternalLinkSquareAlt, faCode
};
@@ -243,14 +234,14 @@ export default Vue.extend({
if (err.info.param == 'name') {
this.$root.dialog({
type: 'error',
- title: this.$t('title-invalid-name'),
- text: this.$t('text-invalid-name')
+ title: this.$t('_pages.invalidNameTitle'),
+ text: this.$t('_pages.invalidNameText')
});
}
} else if (err.code == 'NAME_ALREADY_EXISTS') {
this.$root.dialog({
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.$root.dialog({
type: 'success',
- text: this.$t('page-updated')
+ text: this.$t('_pages.updated')
});
}).catch(onError);
} else {
@@ -272,7 +263,7 @@ export default Vue.extend({
this.currentName = this.name.trim();
this.$root.dialog({
type: 'success',
- text: this.$t('page-created')
+ text: this.$t('_pages.created')
});
this.$router.push(`/my/pages/edit/${this.pageId}`);
}).catch(onError);
@@ -282,7 +273,7 @@ export default Vue.extend({
del() {
this.$root.dialog({
type: 'warning',
- text: this.$t('are-you-sure-delete'),
+ text: this.$t('removeAreYouSure', { x: this.title.trim() }),
showCancelButton: true
}).then(({ canceled }) => {
if (canceled) return;
@@ -291,7 +282,7 @@ export default Vue.extend({
}).then(() => {
this.$root.dialog({
type: 'success',
- text: this.$t('page-deleted')
+ text: this.$t('_pages.deleted')
});
this.$router.push(`/my/pages`);
});
@@ -301,7 +292,7 @@ export default Vue.extend({
async add() {
const { canceled, result: type } = await this.$root.dialog({
type: null,
- title: this.$t('chooseBlock'),
+ title: this.$t('_pages.chooseBlock'),
select: {
groupedItems: this.getPageBlockList()
},
@@ -315,7 +306,7 @@ export default Vue.extend({
async addVariable() {
let { canceled, result: name } = await this.$root.dialog({
- title: this.$t('enterVariableName'),
+ title: this.$t('_pages.enterVariableName'),
input: {
type: 'text',
},
@@ -328,7 +319,7 @@ export default Vue.extend({
if (this.aiScript.isUsedName(name)) {
this.$root.dialog({
type: 'error',
- text: this.$t('the-variable-name-is-already-used')
+ text: this.$t('_pages.variableNameIsAlreadyUsed')
});
return;
}
@@ -348,7 +339,7 @@ export default Vue.extend({
getPageBlockList() {
return [{
- label: this.$t('content-blocks'),
+ label: this.$t('_pages.contentBlocks'),
items: [
{ value: 'section', text: this.$t('_pages.blocks.section') },
{ value: 'text', text: this.$t('_pages.blocks.text') },
@@ -356,7 +347,7 @@ export default Vue.extend({
{ value: 'textarea', text: this.$t('_pages.blocks.textarea') },
]
}, {
- label: this.$t('input-blocks'),
+ label: this.$t('_pages.inputBlocks'),
items: [
{ value: 'button', text: this.$t('_pages.blocks.button') },
{ value: 'radioButton', text: this.$t('_pages.blocks.radioButton') },
@@ -367,7 +358,7 @@ export default Vue.extend({
{ value: 'counter', text: this.$t('_pages.blocks.counter') }
]
}, {
- label: this.$t('special-blocks'),
+ label: this.$t('_pages.specialBlocks'),
items: [
{ value: 'if', text: this.$t('_pages.blocks.if') },
{ value: 'post', text: this.$t('_pages.blocks.post') }
diff --git a/src/client/pages/pages.vue b/src/client/pages/pages.vue
index bee7d30a61..d993d0196e 100644
--- a/src/client/pages/pages.vue
+++ b/src/client/pages/pages.vue
@@ -1,7 +1,7 @@
<template>
<div>
<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">
<mk-button class="new" @click="create()"><fa :icon="faPlus"/></mk-button>
<mk-pagination :pagination="myPagesPagination" #default="{items}">
@@ -11,7 +11,7 @@
</mk-container>
<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">
<mk-pagination :pagination="likedPagesPagination" #default="{items}">
<mk-page-preview v-for="like in items" class="ckltabjg" :page="like.page" :key="like.page.id"/>
diff --git a/src/docs/pages.ja-JP.md b/src/docs/pages.ja-JP.md
new file mode 100644
index 0000000000..3804c5a5c2
--- /dev/null
+++ b/src/docs/pages.ja-JP.md
@@ -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標準で関数を引数に取る関数(高階関数と呼ばれます)も存在します。関数は予め定義しておくほかに、このような高階関数のスロットに即席でセットすることもできます。