diff --git a/gulpfile.ts b/gulpfile.ts index 262c0a5030af41f9df9596b79151c05dd7060310..880adb51de02928bdf5c9e99ee464307f349c3d9 100644 --- a/gulpfile.ts +++ b/gulpfile.ts @@ -11,7 +11,7 @@ const cleanCSS = require('gulp-clean-css'); const sass = require('gulp-dart-sass'); const fiber = require('fibers'); -const locales = require('./locales'); +const locales: { [x: string]: any } = require('./locales'); const meta = require('./package.json'); gulp.task('build:ts', () => { @@ -31,8 +31,10 @@ gulp.task('build:copy:views', () => gulp.task('build:copy:locales', cb => { fs.mkdirSync('./built/client/assets/locales', { recursive: true }); + const v = { '_version_': meta.version }; + for (const [lang, locale] of Object.entries(locales)) { - fs.writeFileSync(`./built/client/assets/locales/${lang}.${meta.version}.json`, JSON.stringify(locale), 'utf-8'); + fs.writeFileSync(`./built/client/assets/locales/${lang}.${meta.version}.json`, JSON.stringify({ ...locale, ...v }), 'utf-8'); } cb(); diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index ab293eb89de1c0b8e22f78217fba6cb8c842c97c..3c7dc6640bc2cce7b69aa42c2d0c9e0a9d732247 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -507,6 +507,8 @@ addRelay: "リレーã®è¿½åŠ " inboxUrl: "inboxã®URL" addedRelays: "è¿½åŠ æ¸ˆã¿ã®ãƒªãƒ¬ãƒ¼" serviceworkerInfo: "プッシュ通知を行ã†ã«ã¯æœ‰åŠ¹ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚" +deletedNote: "削除ã•ã‚ŒãŸæŠ•ç¨¿" +invisibleNote: "éžå…¬é–‹ã®æŠ•ç¨¿" _theme: explore: "テーマを探ã™" @@ -1102,3 +1104,17 @@ _relayStatus: requesting: "承èªå¾…ã¡" accepted: "承èªæ¸ˆã¿" rejected: "æ‹’å¦æ¸ˆã¿" + +_notification: + fileUploaded: "ファイルãŒã‚¢ãƒƒãƒ—ãƒãƒ¼ãƒ‰ã•ã‚Œã¾ã—ãŸ" + youGotMention: "{name}ã‹ã‚‰ã®ãƒ¡ãƒ³ã‚·ãƒ§ãƒ³" + youGotReply: "{name}ã‹ã‚‰ã®ãƒªãƒ—ライ" + youGotQuote: "{name}ã«ã‚ˆã‚‹å¼•ç”¨" + youRenoted: "{name}ãŒRenoteã—ã¾ã—ãŸ" + youGotPoll: "{name}ãŒæŠ•ç¥¨ã—ã¾ã—ãŸ" + youGotMessagingMessageFromUser: "{name}ã‹ã‚‰ã®ãƒãƒ£ãƒƒãƒˆãŒã‚ã‚Šã¾ã™" + youGotMessagingMessageFromGroup: "{name}ã®ãƒãƒ£ãƒƒãƒˆãŒã‚ã‚Šã¾ã™" + youWereFollowed: "フォãƒãƒ¼ã•ã‚Œã¾ã—ãŸ" + youReceivedFollowRequest: "フォãƒãƒ¼ãƒªã‚¯ã‚¨ã‚¹ãƒˆãŒæ¥ã¾ã—ãŸ" + yourFollowRequestAccepted: "フォãƒãƒ¼ãƒªã‚¯ã‚¨ã‚¹ãƒˆãŒæ‰¿èªã•ã‚Œã¾ã—ãŸ" + youWereInvitedToGroup: "グループã«æ‹›å¾…ã•ã‚Œã¾ã—ãŸ" diff --git a/package.json b/package.json index 15c1478dbdbbb4712d93e1a756f030dd1ab64aed..d34394d138c701a0fa50a468f071d10ddd2d7fca 100644 --- a/package.json +++ b/package.json @@ -125,6 +125,7 @@ "css-loader": "3.5.3", "cssnano": "4.1.10", "dateformat": "3.0.3", + "deep-entries": "3.1.0", "diskusage": "1.1.3", "double-ended-queue": "2.1.0-0", "escape-regexp": "0.0.1", @@ -151,6 +152,7 @@ "http-proxy-agent": "4.0.1", "http-signature": "1.3.4", "https-proxy-agent": "5.0.0", + "idb-keyval": "3.2.0", "insert-text-at-cursor": "0.3.0", "is-root": "2.1.0", "is-svg": "4.2.1", diff --git a/src/client/app.vue b/src/client/app.vue index 5e7396205bf7e60a4822fee8b86a6fb9c4a8be34..8e192d46338981a24491d71d2887bf86425bd9c2 100644 --- a/src/client/app.vue +++ b/src/client/app.vue @@ -136,15 +136,12 @@ import { faGripVertical, faChevronLeft, faHashtag, faBroadcastTower, faFireAlt, import { faBell, faEnvelope, faLaugh, faComments } from '@fortawesome/free-regular-svg-icons'; import { ResizeObserver } from '@juggle/resize-observer'; import { v4 as uuid } from 'uuid'; -import i18n from './i18n'; import { host, instanceName } from './config'; import { search } from './scripts/search'; const DESKTOP_THRESHOLD = 1100; export default Vue.extend({ - i18n, - components: { XClock: () => import('./components/header-clock.vue').then(m => m.default), MkButton: () => import('./components/ui/button.vue').then(m => m.default), diff --git a/src/client/components/captcha.vue b/src/client/components/captcha.vue index 6b1ee6f0b265544816dec10b36bf9ab8e7bf7828..1a894d9350b286f10ec966583a65a013b13b7940 100644 --- a/src/client/components/captcha.vue +++ b/src/client/components/captcha.vue @@ -7,7 +7,6 @@ <script lang="ts"> import Vue from 'vue'; -import i18n from '../i18n'; type Captcha = { render(container: string | Node, options: { @@ -31,7 +30,6 @@ declare global { } export default Vue.extend({ - i18n, props: { provider: { type: String, diff --git a/src/client/components/cw-button.vue b/src/client/components/cw-button.vue index 4516e5210c964c149fdd33af8709559beb9b0d0f..07a44d970f8d2a0493d4b2f795d807560caab25e 100644 --- a/src/client/components/cw-button.vue +++ b/src/client/components/cw-button.vue @@ -7,13 +7,10 @@ <script lang="ts"> import Vue from 'vue'; -import i18n from '../i18n'; import { length } from 'stringz'; import { concat } from '../../prelude/array'; export default Vue.extend({ - i18n, - props: { value: { type: Boolean, diff --git a/src/client/components/date-separated-list.vue b/src/client/components/date-separated-list.vue index b80c6494eda4cd9d0fa57c5b9ae8eecec19cb232..a27e9a05a201b069a5e606ca7489669189b8a449 100644 --- a/src/client/components/date-separated-list.vue +++ b/src/client/components/date-separated-list.vue @@ -15,11 +15,8 @@ <script lang="ts"> import Vue from 'vue'; import { faAngleUp, faAngleDown } from '@fortawesome/free-solid-svg-icons'; -import i18n from '../i18n'; export default Vue.extend({ - i18n, - props: { items: { type: Array, diff --git a/src/client/components/dialog.vue b/src/client/components/dialog.vue index da8e54684b40e6a6205345b027f3b0cb3a8ddd50..58115b47a29e814505f3f9e0722c8d00648e8c9d 100644 --- a/src/client/components/dialog.vue +++ b/src/client/components/dialog.vue @@ -57,11 +57,8 @@ import MkInput from './ui/input.vue'; import MkSelect from './ui/select.vue'; import MkSignin from './signin.vue'; import parseAcct from '../../misc/acct/parse'; -import i18n from '../i18n'; export default Vue.extend({ - i18n, - components: { MkButton, MkInput, diff --git a/src/client/components/drive-window.vue b/src/client/components/drive-window.vue index d63881c0edfbc75ca96d6838cac9c847e2c06a38..c42cb666171d769492f5b9256e43308969f544c8 100644 --- a/src/client/components/drive-window.vue +++ b/src/client/components/drive-window.vue @@ -12,13 +12,10 @@ <script lang="ts"> import Vue from 'vue'; -import i18n from '../i18n'; import XDrive from './drive.vue'; import XWindow from './window.vue'; export default Vue.extend({ - i18n, - components: { XDrive, XWindow, diff --git a/src/client/components/drive.file.vue b/src/client/components/drive.file.vue index a547abf9a07930d710b6f100d4f66d8a83c3189a..1b24c61df53d611ee38580c20dad1c6863145d56 100644 --- a/src/client/components/drive.file.vue +++ b/src/client/components/drive.file.vue @@ -32,7 +32,6 @@ <script lang="ts"> import Vue from 'vue'; import { faEye, faEyeSlash } from '@fortawesome/free-regular-svg-icons'; -import i18n from '../i18n'; import copyToClipboard from '../scripts/copy-to-clipboard'; //import updateAvatar from '../api/update-avatar'; //import updateBanner from '../api/update-banner'; @@ -40,8 +39,6 @@ import XFileThumbnail from './drive-file-thumbnail.vue'; import { faDownload, faLink, faICursor, faTrashAlt } from '@fortawesome/free-solid-svg-icons'; export default Vue.extend({ - i18n, - components: { XFileThumbnail }, diff --git a/src/client/components/drive.folder.vue b/src/client/components/drive.folder.vue index b778acc77f551a961cba82f3046e7b5873e36dab..9e80653194fd0bd99090fd0723b101220ec7bbc8 100644 --- a/src/client/components/drive.folder.vue +++ b/src/client/components/drive.folder.vue @@ -28,11 +28,8 @@ <script lang="ts"> import Vue from 'vue'; import { faFolder, faFolderOpen } from '@fortawesome/free-regular-svg-icons'; -import i18n from '../i18n'; export default Vue.extend({ - i18n, - props: { folder: { type: Object, diff --git a/src/client/components/drive.nav-folder.vue b/src/client/components/drive.nav-folder.vue index 0689faecd24897a6314daf4fc9cb2a860e2fee9c..9e805a5e93fd2a711f14773114c5366fd6b15a94 100644 --- a/src/client/components/drive.nav-folder.vue +++ b/src/client/components/drive.nav-folder.vue @@ -15,11 +15,8 @@ <script lang="ts"> import Vue from 'vue'; import { faCloud } from '@fortawesome/free-solid-svg-icons'; -import i18n from '../i18n'; export default Vue.extend({ - i18n, - props: { folder: { type: Object, diff --git a/src/client/components/drive.vue b/src/client/components/drive.vue index 08c7097a8fb3b6e4b1293e43063ffc966446f259..65eb1cb8163075279704c61d0a79fdb2a34db8cb 100644 --- a/src/client/components/drive.vue +++ b/src/client/components/drive.vue @@ -48,7 +48,6 @@ <script lang="ts"> import Vue from 'vue'; import { faAngleRight } from '@fortawesome/free-solid-svg-icons'; -import i18n from '../i18n'; import XNavFolder from './drive.nav-folder.vue'; import XFolder from './drive.folder.vue'; import XFile from './drive.file.vue'; @@ -56,8 +55,6 @@ import XUploader from './uploader.vue'; import MkButton from './ui/button.vue'; export default Vue.extend({ - i18n, - components: { XNavFolder, XFolder, diff --git a/src/client/components/emoji-picker.vue b/src/client/components/emoji-picker.vue index 868a6125c43578096a44eaf79e7c3e2273259284..7871b438c9693370b0546f7c0822eea3b7b795ea 100644 --- a/src/client/components/emoji-picker.vue +++ b/src/client/components/emoji-picker.vue @@ -64,7 +64,6 @@ <script lang="ts"> import Vue from 'vue'; -import i18n from '../i18n'; import { emojilist } from '../../misc/emojilist'; import { getStaticImageUrl } from '../scripts/get-static-image-url'; import { faAsterisk, faLeaf, faUtensils, faFutbol, faCity, faDice, faGlobe, faHistory, faUser } from '@fortawesome/free-solid-svg-icons'; @@ -73,8 +72,6 @@ import { groupByX } from '../../prelude/array'; import XPopup from './popup.vue'; export default Vue.extend({ - i18n, - components: { XPopup, }, diff --git a/src/client/components/error.vue b/src/client/components/error.vue index dd9de43c1664b12a4e1e4d572c094637552efbac..fea81305ed996853db692516f10e59ac6d7a393b 100644 --- a/src/client/components/error.vue +++ b/src/client/components/error.vue @@ -9,11 +9,9 @@ <script lang="ts"> import Vue from 'vue'; import { faExclamationTriangle } from '@fortawesome/free-solid-svg-icons'; -import i18n from '../i18n'; import MkButton from './ui/button.vue'; export default Vue.extend({ - i18n, components: { MkButton, }, diff --git a/src/client/components/follow-button.vue b/src/client/components/follow-button.vue index 23cb0cd94527c6b37cacdb531456247f8e25ce40..7967c0e1595f342ef656f648fcb575630a1f5594 100644 --- a/src/client/components/follow-button.vue +++ b/src/client/components/follow-button.vue @@ -30,12 +30,9 @@ <script lang="ts"> import Vue from 'vue'; -import i18n from '../i18n'; import { faSpinner, faPlus, faMinus, faHourglassHalf } from '@fortawesome/free-solid-svg-icons'; export default Vue.extend({ - i18n, - props: { user: { type: Object, diff --git a/src/client/components/google.vue b/src/client/components/google.vue index 01dcf24bf8756f1216cdb37f7d7b240ecbc55252..de96cbd16a55041333379712a683c50c25b557cd 100644 --- a/src/client/components/google.vue +++ b/src/client/components/google.vue @@ -8,10 +8,8 @@ <script lang="ts"> import Vue from 'vue'; import { faSearch } from '@fortawesome/free-solid-svg-icons'; -import i18n from '../i18n'; export default Vue.extend({ - i18n, props: ['q'], data() { return { diff --git a/src/client/components/image-viewer.vue b/src/client/components/image-viewer.vue index 3359b600da45814ee0bd3aa9d8375eeae7809694..c78112b98896f750f0612ef11660093f1ef8a6f9 100644 --- a/src/client/components/image-viewer.vue +++ b/src/client/components/image-viewer.vue @@ -6,12 +6,9 @@ <script lang="ts"> import Vue from 'vue'; -import i18n from '../i18n'; import XModal from './modal.vue'; export default Vue.extend({ - i18n, - components: { XModal, }, diff --git a/src/client/components/instance-stats.vue b/src/client/components/instance-stats.vue index 378e9ce3919c96c434d68e01ed7c03e1e0524c2b..552e3523f738995b1dd6767f82026de2a7291471 100644 --- a/src/client/components/instance-stats.vue +++ b/src/client/components/instance-stats.vue @@ -125,7 +125,6 @@ import Vue from 'vue'; import { faChartBar, faUser, faPencilAlt } from '@fortawesome/free-solid-svg-icons'; import Chart from 'chart.js'; -import i18n from '../i18n'; import MkSelect from './ui/select.vue'; const chartLimit = 90; @@ -140,8 +139,6 @@ const alpha = (hex, a) => { }; export default Vue.extend({ - i18n, - components: { MkSelect }, diff --git a/src/client/components/media-banner.vue b/src/client/components/media-banner.vue index 088c11fab7a9f113f278afb16df3dcb8d9da9845..0f746d4340ebfb137434e705c97ed947130602f7 100644 --- a/src/client/components/media-banner.vue +++ b/src/client/components/media-banner.vue @@ -28,10 +28,8 @@ <script lang="ts"> import Vue from 'vue'; import { faExclamationTriangle } from '@fortawesome/free-solid-svg-icons'; -import i18n from '../i18n'; export default Vue.extend({ - i18n, props: { media: { type: Object, diff --git a/src/client/components/media-image.vue b/src/client/components/media-image.vue index 6c33b657ffce9b729e04ce0d5296ec4c3f92b838..6d1b5345de56be4f991aee96feede7f9d87d35b2 100644 --- a/src/client/components/media-image.vue +++ b/src/client/components/media-image.vue @@ -21,12 +21,10 @@ <script lang="ts"> import Vue from 'vue'; import { faExclamationTriangle, faEyeSlash } from '@fortawesome/free-solid-svg-icons'; -import i18n from '../i18n'; import { getStaticImageUrl } from '../scripts/get-static-image-url'; import ImageViewer from './image-viewer.vue'; export default Vue.extend({ - i18n, props: { image: { type: Object, diff --git a/src/client/components/media-video.vue b/src/client/components/media-video.vue index d9b4415cbf1df8c18ed8f202cd986978ddec6e4c..a5e06bfaa9bd177f8f0dbbb74e8c1c3fb475b2d1 100644 --- a/src/client/components/media-video.vue +++ b/src/client/components/media-video.vue @@ -23,10 +23,8 @@ import Vue from 'vue'; import { faPlayCircle } from '@fortawesome/free-regular-svg-icons'; import { faExclamationTriangle, faEyeSlash } from '@fortawesome/free-solid-svg-icons'; -import i18n from '../i18n'; export default Vue.extend({ - i18n, props: { video: { type: Object, diff --git a/src/client/components/mention.vue b/src/client/components/mention.vue index 06dcf1288787ee9a896ae888c049de457660cea9..8c939f839a2a81a6ea43ec13c532f6470ce41dd1 100644 --- a/src/client/components/mention.vue +++ b/src/client/components/mention.vue @@ -16,12 +16,10 @@ <script lang="ts"> import Vue from 'vue'; -import i18n from '../i18n'; import { toUnicode } from 'punycode'; import { host as localHost } from '../config'; export default Vue.extend({ - i18n, props: { username: { type: String, diff --git a/src/client/components/note.vue b/src/client/components/note.vue index fd895ad5aed4878591250a7bbf624e2033687c5f..6e513a4b2a4712c1e2f9ece2dbc6ac2cda291cfb 100644 --- a/src/client/components/note.vue +++ b/src/client/components/note.vue @@ -93,7 +93,6 @@ import { faBolt, faTimes, faBullhorn, faStar, faLink, faExternalLinkSquareAlt, f import { faCopy, faTrashAlt, faEdit, faEye, faEyeSlash } from '@fortawesome/free-regular-svg-icons'; import { parse } from '../../mfm/parse'; import { sum, unique } from '../../prelude/array'; -import i18n from '../i18n'; import XSub from './note.sub.vue'; import XNoteHeader from './note-header.vue'; import XNotePreview from './note-preview.vue'; @@ -109,7 +108,6 @@ import { url } from '../config'; import copyToClipboard from '../scripts/copy-to-clipboard'; export default Vue.extend({ - i18n, components: { XSub, diff --git a/src/client/components/notes.vue b/src/client/components/notes.vue index 0cf4dee2ddda365470a30dd193af2f90423d9c6b..515bc58e2e8eec716b5f1092293e2fd120533726 100644 --- a/src/client/components/notes.vue +++ b/src/client/components/notes.vue @@ -29,15 +29,12 @@ <script lang="ts"> import Vue from 'vue'; -import i18n from '../i18n'; import paging from '../scripts/paging'; import XNote from './note.vue'; import XList from './date-separated-list.vue'; import MkButton from './ui/button.vue'; export default Vue.extend({ - i18n, - components: { XNote, XList, MkButton }, diff --git a/src/client/components/notification.vue b/src/client/components/notification.vue index d3ebc8f1790b6c361fae0b59d31979c8dfc0690d..de233d14ac9b4fd2cfda96f43d70abcfb8df6fb2 100644 --- a/src/client/components/notification.vue +++ b/src/client/components/notification.vue @@ -61,13 +61,11 @@ import Vue from 'vue'; import { faIdCardAlt, faPlus, faQuoteLeft, faQuoteRight, faRetweet, faReply, faAt, faCheck, faPollH } from '@fortawesome/free-solid-svg-icons'; import { faClock } from '@fortawesome/free-regular-svg-icons'; -import getNoteSummary from '../../misc/get-note-summary'; +import noteSummary from '../../misc/get-note-summary'; import XReactionIcon from './reaction-icon.vue'; import MkFollowButton from './follow-button.vue'; -import i18n from '../i18n'; export default Vue.extend({ - i18n, components: { XReactionIcon, MkFollowButton }, @@ -89,7 +87,7 @@ export default Vue.extend({ }, data() { return { - getNoteSummary, + getNoteSummary: (text: string) => noteSummary(text, this.$root.i18n.messages[this.$root.i18n.locale]), followRequestDone: false, groupInviteDone: false, faIdCardAlt, faPlus, faQuoteLeft, faQuoteRight, faRetweet, faReply, faAt, faClock, faCheck, faPollH diff --git a/src/client/components/notifications.vue b/src/client/components/notifications.vue index ecf5268983c6ed16d6239a2e32b38ce4bbd1417e..3ed198a04cd1d7f760c0a3507f5af46974ffd587 100644 --- a/src/client/components/notifications.vue +++ b/src/client/components/notifications.vue @@ -18,15 +18,12 @@ <script lang="ts"> import Vue from 'vue'; -import i18n from '../i18n'; import paging from '../scripts/paging'; import XNotification from './notification.vue'; import XList from './date-separated-list.vue'; import XNote from './note.vue'; export default Vue.extend({ - i18n, - components: { XNotification, XList, diff --git a/src/client/components/page/page.post.vue b/src/client/components/page/page.post.vue index 6f79374f3478c98dfc1c153d8d8917ce1ddbbdfc..da5bc8bfab7951da2a0d62e36d8d0d77b80c9a8f 100644 --- a/src/client/components/page/page.post.vue +++ b/src/client/components/page/page.post.vue @@ -8,13 +8,11 @@ <script lang="ts"> import Vue from 'vue'; import { faCheck, faPaperPlane } from '@fortawesome/free-solid-svg-icons'; -import i18n from '../../i18n'; import MkTextarea from '../ui/textarea.vue'; import MkButton from '../ui/button.vue'; import { apiUrl } from '../../config'; export default Vue.extend({ - i18n, components: { MkTextarea, MkButton, diff --git a/src/client/components/page/page.vue b/src/client/components/page/page.vue index e3b04d7fd66e977e544f53217772d763972b4969..b3cc01ec22820b428b7d4fe63fd5555f2c708cac 100644 --- a/src/client/components/page/page.vue +++ b/src/client/components/page/page.vue @@ -9,14 +9,11 @@ import Vue from 'vue'; import { parse } from '@syuilo/aiscript'; import { faHeart as faHeartS } from '@fortawesome/free-solid-svg-icons'; import { faHeart } from '@fortawesome/free-regular-svg-icons'; -import i18n from '../../i18n'; import XBlock from './page.block.vue'; import { Hpml } from '../../scripts/hpml/evaluator'; import { url } from '../../config'; export default Vue.extend({ - i18n, - components: { XBlock }, diff --git a/src/client/components/poll-editor.vue b/src/client/components/poll-editor.vue index 91c7dab59806b46daa466c1a1fcbe64f9df4b68a..0687e999b5fcbf4b1aebd295959158bf0ae43438 100644 --- a/src/client/components/poll-editor.vue +++ b/src/client/components/poll-editor.vue @@ -51,7 +51,6 @@ <script lang="ts"> import Vue from 'vue'; import { faExclamationTriangle, faTimes } from '@fortawesome/free-solid-svg-icons'; -import i18n from '../i18n'; import { erase } from '../../prelude/array'; import { addTime } from '../../prelude/time'; import { formatDateTimeString } from '../../misc/format-time-string'; @@ -61,7 +60,6 @@ import MkSwitch from './ui/switch.vue'; import MkButton from './ui/button.vue'; export default Vue.extend({ - i18n, components: { MkInput, MkSelect, diff --git a/src/client/components/poll.vue b/src/client/components/poll.vue index c748b6b099c38f6db95322b2ef4a1b9061cb184c..e0c42cd008aaf4c5f37c50b87ed3b17f4fba8e9f 100644 --- a/src/client/components/poll.vue +++ b/src/client/components/poll.vue @@ -24,11 +24,9 @@ <script lang="ts"> import Vue from 'vue'; import { faCheck } from '@fortawesome/free-solid-svg-icons'; -import i18n from '../i18n'; import { sum } from '../../prelude/array'; export default Vue.extend({ - i18n, props: { note: { type: Object, diff --git a/src/client/components/post-form-attaches.vue b/src/client/components/post-form-attaches.vue index d9c0653617f59f572d820fbc3b7b186589aaae7d..2415bf28ec24f7eea924423b7859e7e52553c9da 100644 --- a/src/client/components/post-form-attaches.vue +++ b/src/client/components/post-form-attaches.vue @@ -14,15 +14,12 @@ <script lang="ts"> import Vue from 'vue'; -import i18n from '../i18n'; import * as XDraggable from 'vuedraggable'; import { faTimesCircle, faEye, faEyeSlash } from '@fortawesome/free-regular-svg-icons'; import { faExclamationTriangle, faICursor } from '@fortawesome/free-solid-svg-icons'; import XFileThumbnail from './drive-file-thumbnail.vue' export default Vue.extend({ - i18n, - components: { XDraggable, XFileThumbnail diff --git a/src/client/components/post-form.vue b/src/client/components/post-form.vue index 05faea51466eb65361bf794ace019044b9adac72..cdb61f51d500615e89826f208c645c1cd742b570 100644 --- a/src/client/components/post-form.vue +++ b/src/client/components/post-form.vue @@ -57,7 +57,6 @@ import { faEyeSlash, faLaughSquint } from '@fortawesome/free-regular-svg-icons'; import insertTextAtCursor from 'insert-text-at-cursor'; import { length } from 'stringz'; import { toASCII } from 'punycode'; -import i18n from '../i18n'; import MkVisibilityChooser from './visibility-chooser.vue'; import MkUserSelect from './user-select.vue'; import XNotePreview from './note-preview.vue'; @@ -70,8 +69,6 @@ import { formatTimeString } from '../../misc/format-time-string'; import { selectDriveFile } from '../scripts/select-drive-file'; export default Vue.extend({ - i18n, - components: { XNotePreview, XUploader: () => import('./uploader.vue').then(m => m.default), diff --git a/src/client/components/reaction-icon.vue b/src/client/components/reaction-icon.vue index 3c6d56b80a1b62c4dd6adaf15d8a0f04b8defe89..fe2b5283689b41a4f1e2dd1778c0a40d2f443429 100644 --- a/src/client/components/reaction-icon.vue +++ b/src/client/components/reaction-icon.vue @@ -4,9 +4,7 @@ <script lang="ts"> import Vue from 'vue'; -import i18n from '../i18n'; export default Vue.extend({ - i18n, props: { reaction: { type: String, diff --git a/src/client/components/reaction-picker.vue b/src/client/components/reaction-picker.vue index 99b27ad9c937e784a03ae4d1c31aa950cb72be9a..e331410c394567b4ca1de7f147fb20e85dd767eb 100644 --- a/src/client/components/reaction-picker.vue +++ b/src/client/components/reaction-picker.vue @@ -11,14 +11,11 @@ <script lang="ts"> import Vue from 'vue'; -import i18n from '../i18n'; import { emojiRegex } from '../../misc/emoji-regex'; import XReactionIcon from './reaction-icon.vue'; import XPopup from './popup.vue'; export default Vue.extend({ - i18n, - components: { XPopup, XReactionIcon, diff --git a/src/client/components/reactions-viewer.details.vue b/src/client/components/reactions-viewer.details.vue index ea2523a11f495b4a7970915ddc5127a51db37a03..67c8b261be2f9d6976e35c82c6344388707460d4 100644 --- a/src/client/components/reactions-viewer.details.vue +++ b/src/client/components/reactions-viewer.details.vue @@ -20,10 +20,8 @@ <script lang="ts"> import Vue from 'vue'; -import i18n from '../i18n'; export default Vue.extend({ - i18n, props: { reaction: { type: String, diff --git a/src/client/components/remote-caution.vue b/src/client/components/remote-caution.vue index 95b37d3053546cefedca2366b19cab2f12e990cc..21af9f766a096ffc5146d034bfc76223c8d24c53 100644 --- a/src/client/components/remote-caution.vue +++ b/src/client/components/remote-caution.vue @@ -5,10 +5,8 @@ <script lang="ts"> import Vue from 'vue'; import { faExclamationTriangle } from '@fortawesome/free-solid-svg-icons'; -import i18n from '../i18n'; export default Vue.extend({ - i18n, props: { href: { type: String, diff --git a/src/client/components/signin-dialog.vue b/src/client/components/signin-dialog.vue index a356c3ccdbedcd915fe22a92dce3d6cdc431b3ca..98b75e627cc6250c236548f3f5f07b2a3f42fb6f 100644 --- a/src/client/components/signin-dialog.vue +++ b/src/client/components/signin-dialog.vue @@ -7,13 +7,10 @@ <script lang="ts"> import Vue from 'vue'; -import i18n from '../i18n'; import XWindow from './window.vue'; import MkSignin from './signin.vue'; export default Vue.extend({ - i18n, - components: { MkSignin, XWindow, diff --git a/src/client/components/signin.vue b/src/client/components/signin.vue index dc73ad8a0fc0a7e8f87ad6078c40c8af801b3255..a7653b17b0c3e4893c9993c2c411b0df6d13f820 100755 --- a/src/client/components/signin.vue +++ b/src/client/components/signin.vue @@ -49,13 +49,10 @@ import { faLock, faGavel } from '@fortawesome/free-solid-svg-icons'; import { faTwitter, faDiscord, faGithub } from '@fortawesome/free-brands-svg-icons'; import MkButton from './ui/button.vue'; import MkInput from './ui/input.vue'; -import i18n from '../i18n'; import { apiUrl, host } from '../config'; import { byteify, hexify } from '../scripts/2fa'; export default Vue.extend({ - i18n, - components: { MkButton, MkInput, diff --git a/src/client/components/signup-dialog.vue b/src/client/components/signup-dialog.vue index 4db79af5121f135a3887b127b0dd0ed0e51d8aa3..eff1f79c48774f095740bc2641d61cdcd1f244fe 100644 --- a/src/client/components/signup-dialog.vue +++ b/src/client/components/signup-dialog.vue @@ -7,13 +7,10 @@ <script lang="ts"> import Vue from 'vue'; -import i18n from '../i18n'; import XWindow from './window.vue'; import XSignup from './signup.vue'; export default Vue.extend({ - i18n, - components: { XSignup, XWindow, diff --git a/src/client/components/signup.vue b/src/client/components/signup.vue index acb6a745ab5a123c3f14590efe12acaf4cdacec2..ff1932b42d14526e51a8722fa458d59dcd539431 100644 --- a/src/client/components/signup.vue +++ b/src/client/components/signup.vue @@ -53,15 +53,12 @@ import Vue from 'vue'; import { faLock, faExclamationTriangle, faSpinner, faCheck, faKey } from '@fortawesome/free-solid-svg-icons'; const getPasswordStrength = require('syuilo-password-strength'); import { toUnicode } from 'punycode'; -import i18n from '../i18n'; import { host, url } from '../config'; import MkButton from './ui/button.vue'; import MkInput from './ui/input.vue'; import MkSwitch from './ui/switch.vue'; export default Vue.extend({ - i18n, - components: { MkButton, MkInput, diff --git a/src/client/components/stream-indicator.vue b/src/client/components/stream-indicator.vue index dd7a5d07c14640571c4c2b5e5116eb5f5cc76d03..ec00f4cbfe7983aec45fa4ff7a0bb8383cf33213 100644 --- a/src/client/components/stream-indicator.vue +++ b/src/client/components/stream-indicator.vue @@ -10,10 +10,8 @@ <script lang="ts"> import Vue from 'vue'; -import i18n from '../i18n'; export default Vue.extend({ - i18n, data() { return { hasDisconnected: false, diff --git a/src/client/components/sub-note-content.vue b/src/client/components/sub-note-content.vue index e60c19744231a071328a9babc5da59ae3517743e..a14c832ea85dd3ab3c8cfefb75cf039693ba8c41 100644 --- a/src/client/components/sub-note-content.vue +++ b/src/client/components/sub-note-content.vue @@ -21,12 +21,10 @@ <script lang="ts"> import Vue from 'vue'; import { faReply } from '@fortawesome/free-solid-svg-icons'; -import i18n from '../i18n'; import XPoll from './poll.vue'; import XMediaList from './media-list.vue'; export default Vue.extend({ - i18n, components: { XPoll, XMediaList, diff --git a/src/client/components/time.vue b/src/client/components/time.vue index 6d092cf4f8fd9056ed375d7ca95019933b5bb930..2a871d6d8187fdb589cbf4f0eca87a1fff6040bf 100644 --- a/src/client/components/time.vue +++ b/src/client/components/time.vue @@ -8,10 +8,8 @@ <script lang="ts"> import Vue from 'vue'; -import i18n from '../i18n'; export default Vue.extend({ - i18n, props: { time: { type: [Date, String], diff --git a/src/client/components/uploader.vue b/src/client/components/uploader.vue index 4ceb5e2877f8727f3e1d70dbbd11d346bbfc713a..6ebdf123b1f9ea3e2a7ddf5c50031d662f031b7c 100644 --- a/src/client/components/uploader.vue +++ b/src/client/components/uploader.vue @@ -21,13 +21,11 @@ <script lang="ts"> import Vue from 'vue'; -import i18n from '../i18n'; import { apiUrl } from '../config'; //import getMD5 from '../../scripts/get-md5'; import { faSpinner } from '@fortawesome/free-solid-svg-icons'; export default Vue.extend({ - i18n, data() { return { uploads: [], diff --git a/src/client/components/url-preview-popup.vue b/src/client/components/url-preview-popup.vue index acd9b1aa9ae1c7f76baa36f1463f74cc6d6dc241..52731296cb392c2a2014e0c62b5ee4d27dd2e470 100644 --- a/src/client/components/url-preview-popup.vue +++ b/src/client/components/url-preview-popup.vue @@ -6,12 +6,9 @@ <script lang="ts"> import Vue from 'vue'; -import i18n from '../i18n'; import MkUrlPreview from './url-preview.vue'; export default Vue.extend({ - i18n, - components: { MkUrlPreview }, diff --git a/src/client/components/url-preview.vue b/src/client/components/url-preview.vue index c2dd0038bec32c26aba478926a098d68a8befd7e..d77cfafd1e52eb5f84f10b66953a13bd54846db7 100644 --- a/src/client/components/url-preview.vue +++ b/src/client/components/url-preview.vue @@ -32,12 +32,9 @@ <script lang="ts"> import Vue from 'vue'; import { faPlayCircle } from '@fortawesome/free-regular-svg-icons'; -import i18n from '../i18n'; import { url as local, lang } from '../config'; export default Vue.extend({ - i18n, - props: { url: { type: String, diff --git a/src/client/components/user-list.vue b/src/client/components/user-list.vue index bde3af69066058d302b238154dbb40ff6f0b23e1..7a9cd58a481e0f1919501af44212c4eb0c7e8474 100644 --- a/src/client/components/user-list.vue +++ b/src/client/components/user-list.vue @@ -31,14 +31,11 @@ <script lang="ts"> import Vue from 'vue'; -import i18n from '../i18n'; import paging from '../scripts/paging'; import MkContainer from './ui/container.vue'; import MkFollowButton from './follow-button.vue'; export default Vue.extend({ - i18n, - components: { MkContainer, MkFollowButton, diff --git a/src/client/components/user-menu.vue b/src/client/components/user-menu.vue index a2275197d89bde3464bb998d9db84adc71642698..25937fb3c04427eedb806239f30cf5e89adc7fc6 100644 --- a/src/client/components/user-menu.vue +++ b/src/client/components/user-menu.vue @@ -6,15 +6,12 @@ import Vue from 'vue'; import { faAt, faListUl, faEye, faEyeSlash, faBan, faPencilAlt, faComments, faUsers, faMicrophoneSlash } from '@fortawesome/free-solid-svg-icons'; import { faSnowflake, faEnvelope } from '@fortawesome/free-regular-svg-icons'; -import i18n from '../i18n'; import XMenu from './menu.vue'; import copyToClipboard from '../scripts/copy-to-clipboard'; import { host } from '../config'; import getAcct from '../../misc/acct/render'; export default Vue.extend({ - i18n, - components: { XMenu }, diff --git a/src/client/components/user-preview.vue b/src/client/components/user-preview.vue index 89150eaaccd3eb139bd36d56674751b5ab7eedaf..8c8eee2a3458b93be05bd95a39df1694cc57751b 100644 --- a/src/client/components/user-preview.vue +++ b/src/client/components/user-preview.vue @@ -28,13 +28,10 @@ <script lang="ts"> import Vue from 'vue'; -import i18n from '../i18n'; import parseAcct from '../../misc/acct/parse'; import MkFollowButton from './follow-button.vue'; export default Vue.extend({ - i18n, - components: { MkFollowButton }, diff --git a/src/client/components/user-select.vue b/src/client/components/user-select.vue index a82626652d6207ba100782a27bbc4d1f9230eb28..9b4a68ddb35af45caeaa3c3d031d8e266b27459b 100644 --- a/src/client/components/user-select.vue +++ b/src/client/components/user-select.vue @@ -21,14 +21,11 @@ <script lang="ts"> import Vue from 'vue'; -import i18n from '../i18n'; import { faTimes, faCheck } from '@fortawesome/free-solid-svg-icons'; import MkInput from './ui/input.vue'; import XWindow from './window.vue'; export default Vue.extend({ - i18n, - components: { MkInput, XWindow, diff --git a/src/client/components/users-dialog.vue b/src/client/components/users-dialog.vue index 9d0c5e4251cdc1acb8730bc6950a09ea59fd09ea..0e0cc36c2a31b30efe4a6b3e2d0d1175e6d348ff 100644 --- a/src/client/components/users-dialog.vue +++ b/src/client/components/users-dialog.vue @@ -31,13 +31,10 @@ <script lang="ts"> import Vue from 'vue'; import { faTimes } from '@fortawesome/free-solid-svg-icons'; -import i18n from '../i18n'; import paging from '../scripts/paging'; import XModal from './modal.vue'; export default Vue.extend({ - i18n, - components: { XModal, }, diff --git a/src/client/components/visibility-chooser.vue b/src/client/components/visibility-chooser.vue index dc7b41e2863216674cefeada2767fbb3c6286bdd..0f7e37a0884f44db383b0ac0d958663729bed951 100644 --- a/src/client/components/visibility-chooser.vue +++ b/src/client/components/visibility-chooser.vue @@ -37,11 +37,9 @@ import Vue from 'vue'; import { faGlobe, faUnlock, faHome } from '@fortawesome/free-solid-svg-icons'; import { faEnvelope } from '@fortawesome/free-regular-svg-icons'; -import i18n from '../i18n'; import XPopup from './popup.vue'; export default Vue.extend({ - i18n, components: { XPopup }, diff --git a/src/client/components/window.vue b/src/client/components/window.vue index 0b2ba248bfe6b526af068a23c111c7814a5211b5..db13985181039031743304add2af5bf1febe12e2 100644 --- a/src/client/components/window.vue +++ b/src/client/components/window.vue @@ -20,12 +20,9 @@ <script lang="ts"> import Vue from 'vue'; import { faTimes, faCheck } from '@fortawesome/free-solid-svg-icons'; -import i18n from '../i18n'; import XModal from './modal.vue'; export default Vue.extend({ - i18n, - components: { XModal, }, diff --git a/src/client/config.ts b/src/client/config.ts index 0d4a96964ec3a4113399aa62f184f80bc2f437ff..f71647a05c1ff42aa6a6ca91fe075f825755f820 100644 --- a/src/client/config.ts +++ b/src/client/config.ts @@ -1,3 +1,6 @@ +import { clientDb, entries } from './db'; +import { fromEntries } from '../prelude/array'; + declare const _LANGS_: string[]; declare const _VERSION_: string; declare const _ENV_: string; @@ -12,7 +15,7 @@ export const apiUrl = url + '/api'; export const wsUrl = url.replace('http://', 'ws://').replace('https://', 'wss://') + '/streaming'; export const lang = localStorage.getItem('lang'); export const langs = _LANGS_; -export const locale = JSON.parse(localStorage.getItem('locale')); +export const getLocale = async () => fromEntries((await entries(clientDb.i18n)) as [string, string][]); export const version = _VERSION_; export const env = _ENV_; export const instanceName = siteName === 'Misskey' ? null : siteName; diff --git a/src/client/db.ts b/src/client/db.ts new file mode 100644 index 0000000000000000000000000000000000000000..3000a0c96836a4c6a25f82a5fde836c0cbd55620 --- /dev/null +++ b/src/client/db.ts @@ -0,0 +1,68 @@ +import { Store } from 'idb-keyval'; +// Provide functions from idb-keyval +export { get, set, del, clear, keys } from 'idb-keyval'; + +//#region Construct DB +export const clientDb = { + i18n: new Store('MisskeyClient', 'i18n') +}; +//#endregion + +//#region Provide some tool functions +function openTransaction(store: Store, mode: IDBTransactionMode): Promise<IDBTransaction>{ + return store._dbp.then(db => db.transaction(store.storeName, mode)); +} + +export function entries(store: Store): Promise<[IDBValidKey, unknown][]> { + const entries: [IDBValidKey, unknown][] = []; + + return store._withIDBStore('readonly', store => { + store.openCursor().onsuccess = function () { + if (!this.result) return; + entries.push([this.result.key, this.result.value]); + this.result.continue(); + }; + }).then(() => entries); +} + +export async function bulkGet(keys: IDBValidKey[], store: Store): Promise<[IDBValidKey, unknown][]> { + const valPromises: Promise<[IDBValidKey, unknown]>[] = []; + + const tx = await openTransaction(store, 'readwrite'); + const st = tx.objectStore(store.storeName); + for (const key of keys) { + valPromises.push(new Promise((resolve, reject) => { + const getting = st.get(key); + getting.onsuccess = function (e) { + return resolve([key, this.result]); + }; + getting.onerror = function (e) { + return reject(this.error); + }; + })); + } + return new Promise((resolve, reject) => { + tx.oncomplete = () => resolve(Promise.all(valPromises)); + tx.abort = tx.onerror = () => reject(tx.error); + }); +} + +export async function bulkSet(map: [IDBValidKey, any][], store: Store): Promise<void> { + const tx = await openTransaction(store, 'readwrite'); + const st = tx.objectStore(store.storeName); + for (const [key, value] of map) { + st.put(value, key); + } + return new Promise((resolve, reject) => { + tx.oncomplete = () => resolve(); + tx.abort = tx.onerror = () => reject(tx.error); + }); +} + +export function count(store: Store): Promise<number> { + let req: IDBRequest<number>; + return store._withIDBStore('readonly', store => { + req = store.count(); + }).then(() => req.result); +} +//#endregion diff --git a/src/client/i18n.ts b/src/client/i18n.ts deleted file mode 100644 index 05d319fbafd8a6045504080bf76a555ed3f74b6e..0000000000000000000000000000000000000000 --- a/src/client/i18n.ts +++ /dev/null @@ -1,12 +0,0 @@ -import Vue from 'vue'; -import VueI18n from 'vue-i18n'; -import { lang, locale } from './config'; - -Vue.use(VueI18n); - -export default new VueI18n({ - locale: lang, - messages: { - [lang]: locale - } -}); diff --git a/src/client/init.ts b/src/client/init.ts index 500092061a8d830c10aae629d5ee6534098784ea..e2772502f662b485851bf1c3b24997f4ee786693 100644 --- a/src/client/init.ts +++ b/src/client/init.ts @@ -7,13 +7,13 @@ import Vuex from 'vuex'; import VueMeta from 'vue-meta'; import PortalVue from 'portal-vue'; import VAnimateCss from 'v-animate-css'; +import VueI18n from 'vue-i18n'; import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'; -import i18n from './i18n'; import VueHotkey from './scripts/hotkey'; import App from './app.vue'; import MiOS from './mios'; -import { version, langs, instanceName } from './config'; +import { version, langs, instanceName, getLocale } from './config'; import PostFormDialog from './components/post-form-dialog.vue'; import Dialog from './components/dialog.vue'; import Menu from './components/menu.vue'; @@ -21,12 +21,15 @@ import { router } from './router'; import { applyTheme, lightTheme } from './theme'; import { isDeviceDarkmode } from './scripts/is-device-darkmode'; import createStore from './store'; +import { clientDb, get, count } from './db'; +import { setI18nContexts } from './scripts/set-i18n-contexts'; Vue.use(Vuex); Vue.use(VueHotkey); Vue.use(VueMeta); Vue.use(PortalVue); Vue.use(VAnimateCss); +Vue.use(VueI18n); Vue.component('fa', FontAwesomeIcon); require('./directives'); @@ -96,27 +99,6 @@ if (isMobile || window.innerWidth <= 1024) { head.appendChild(viewport); } -//#region Fetch locale data -const cachedLocale = localStorage.getItem('locale'); - -if (cachedLocale == null) { - fetch(`/assets/locales/${lang}.${version}.json`) - .then(response => response.json()).then(locale => { - localStorage.setItem('locale', JSON.stringify(locale)); - i18n.locale = lang; - i18n.setLocaleMessage(lang, locale); - }); -} else { - // TODO: å¤ã„時ã ã‘æ›´æ–° - setTimeout(() => { - fetch(`/assets/locales/${lang}.${version}.json`) - .then(response => response.json()).then(locale => { - localStorage.setItem('locale', JSON.stringify(locale)); - }); - }, 1000 * 5); -} -//#endregion - //#region Set lang attr const html = document.documentElement; html.setAttribute('lang', lang); @@ -167,6 +149,18 @@ os.init(async () => { }); //#endregion + //#region Fetch locale data + const i18n = new VueI18n(); + + await count(clientDb.i18n).then(async n => { + if (n === 0) return setI18nContexts(lang, version, i18n); + if ((await get('_version_', clientDb.i18n) !== version)) return setI18nContexts(lang, version, i18n, true); + + i18n.locale = lang; + i18n.setLocaleMessage(lang, await getLocale()); + }); + //#endregion + if ('Notification' in window && store.getters.isSignedIn) { // 許å¯ã‚’å¾—ã¦ã„ãªã‹ã£ãŸã‚‰ãƒªã‚¯ã‚¨ã‚¹ãƒˆ if (Notification.permission === 'default') { @@ -176,6 +170,7 @@ os.init(async () => { const app = new Vue({ store: store, + i18n, metaInfo: { title: null, titleTemplate: title => title ? `${title} | ${(instanceName || 'Misskey')}` : (instanceName || 'Misskey') @@ -183,7 +178,8 @@ os.init(async () => { data() { return { stream: os.stream, - isMobile: isMobile + isMobile: isMobile, + i18n // TODO: 消ã›ãªã„ã‹è€ƒãˆã‚‹ SEE: https://github.com/syuilo/misskey/pull/6396#discussion_r429511030 }; }, methods: { diff --git a/src/client/pages/about-misskey.vue b/src/client/pages/about-misskey.vue index 84cd5d5e9c62d6a2fe76f0cf314f3f464a6da358..2c4a257b156b3e274b95ec91440d51fc4f9565ba 100644 --- a/src/client/pages/about-misskey.vue +++ b/src/client/pages/about-misskey.vue @@ -63,12 +63,9 @@ import Vue from 'vue'; import { faInfoCircle } from '@fortawesome/free-solid-svg-icons'; import { version } from '../config'; -import i18n from '../i18n'; import MkLink from '../components/link.vue'; export default Vue.extend({ - i18n, - components: { MkLink }, diff --git a/src/client/pages/about.vue b/src/client/pages/about.vue index a3a4b6ac736b172d2de43436df0185210aa6df5d..25fb0ca13e79b93ca51b8bff178f845712d46eb2 100644 --- a/src/client/pages/about.vue +++ b/src/client/pages/about.vue @@ -25,12 +25,9 @@ import Vue from 'vue'; import { faInfoCircle } from '@fortawesome/free-solid-svg-icons'; import { version } from '../config'; -import i18n from '../i18n'; import MkInstanceStats from '../components/instance-stats.vue'; export default Vue.extend({ - i18n, - metaInfo() { return { title: this.$t('instance') as string diff --git a/src/client/pages/announcements.vue b/src/client/pages/announcements.vue index 5c6d4f58af9c7d87b9a3348671148cfc5249c8b7..089475ed60728a40c11afea5126a2070e8dd89c9 100644 --- a/src/client/pages/announcements.vue +++ b/src/client/pages/announcements.vue @@ -21,13 +21,10 @@ <script lang="ts"> import Vue from 'vue'; import { faCheck, faBroadcastTower } from '@fortawesome/free-solid-svg-icons'; -import i18n from '../i18n'; import MkPagination from '../components/ui/pagination.vue'; import MkButton from '../components/ui/button.vue'; export default Vue.extend({ - i18n, - metaInfo() { return { title: this.$t('announcements') as string diff --git a/src/client/pages/auth.form.vue b/src/client/pages/auth.form.vue index e6f61f52f144accef2994a3cb8e43b769deb02ea..c5a9b769aca56917bac935f6ddbb040c491b8fdb 100644 --- a/src/client/pages/auth.form.vue +++ b/src/client/pages/auth.form.vue @@ -23,11 +23,9 @@ <script lang="ts"> import Vue from 'vue'; -import i18n from '../i18n'; import MkButton from '../components/ui/button.vue'; export default Vue.extend({ - i18n, components: { MkButton }, diff --git a/src/client/pages/auth.vue b/src/client/pages/auth.vue index e025924fe025be10868aa6bfaf162d3feda42e0e..5c40842da1008190a2574ac7602efc2d8547dff7 100755 --- a/src/client/pages/auth.vue +++ b/src/client/pages/auth.vue @@ -30,12 +30,10 @@ <script lang="ts"> import Vue from 'vue'; -import i18n from '../i18n'; import XForm from './auth.form.vue'; import MkSignin from '../components/signin.vue'; export default Vue.extend({ - i18n, components: { XForm, MkSignin, diff --git a/src/client/pages/doc.vue b/src/client/pages/doc.vue index 7c4f7ebccfac41ca863d87a17420fbc4ea3d1ac7..e4c4ef5c6c6d370d4ac26117cf6e812ffde87cc6 100644 --- a/src/client/pages/doc.vue +++ b/src/client/pages/doc.vue @@ -19,7 +19,6 @@ import Vue from 'vue'; import { faFileAlt } from '@fortawesome/free-solid-svg-icons' import MarkdownIt from 'markdown-it'; import MarkdownItAnchor from 'markdown-it-anchor'; -import i18n from '../i18n'; import { url, lang } from '../config'; import MkLink from '../components/link.vue'; @@ -32,8 +31,6 @@ markdown.use(MarkdownItAnchor, { }); export default Vue.extend({ - i18n, - metaInfo() { return { title: this.title, diff --git a/src/client/pages/explore.vue b/src/client/pages/explore.vue index 7ff4b5ed606f3325d7658fc0ffced83d4da8d330..39904846cf195e389d2b0cceb675aef3ff709b1e 100644 --- a/src/client/pages/explore.vue +++ b/src/client/pages/explore.vue @@ -57,13 +57,10 @@ import Vue from 'vue'; import { faChartLine, faPlus, faHashtag, faRocket } from '@fortawesome/free-solid-svg-icons'; import { faBookmark, faCommentAlt } from '@fortawesome/free-regular-svg-icons'; -import i18n from '../i18n'; import XUserList from '../components/user-list.vue'; import MkContainer from '../components/ui/container.vue'; export default Vue.extend({ - i18n, - metaInfo() { return { title: this.$t('explore') as string diff --git a/src/client/pages/follow.vue b/src/client/pages/follow.vue index d765259737bb1b11868ef079e0fd0d3733af1751..8659763bb7880c18b16395f2f79f757316998e68 100644 --- a/src/client/pages/follow.vue +++ b/src/client/pages/follow.vue @@ -5,11 +5,8 @@ <script lang="ts"> import Vue from 'vue'; -import i18n from '../i18n'; export default Vue.extend({ - i18n, - created() { const acct = new URL(location.href).searchParams.get('acct'); if (acct == null) return; diff --git a/src/client/pages/index.welcome.entrance.vue b/src/client/pages/index.welcome.entrance.vue index a9343e87ccc1f569056f9aa64adbe0f5cd678114..9bb2e85fc32dc3c3cd13102beb698f63b4f89715 100644 --- a/src/client/pages/index.welcome.entrance.vue +++ b/src/client/pages/index.welcome.entrance.vue @@ -20,12 +20,9 @@ import XSigninDialog from '../components/signin-dialog.vue'; import XSignupDialog from '../components/signup-dialog.vue'; import MkButton from '../components/ui/button.vue'; import XNotes from '../components/notes.vue'; -import i18n from '../i18n'; import { host } from '../config'; export default Vue.extend({ - i18n, - components: { MkButton, XNotes, diff --git a/src/client/pages/index.welcome.setup.vue b/src/client/pages/index.welcome.setup.vue index 6d08f5b5d4a12a149bbc95455d5734574185300a..9a66a4dffbc4f631059e72aaf6a61a62535e9cd7 100644 --- a/src/client/pages/index.welcome.setup.vue +++ b/src/client/pages/index.welcome.setup.vue @@ -25,10 +25,8 @@ import { faLock } from '@fortawesome/free-solid-svg-icons'; import MkButton from '../components/ui/button.vue'; import MkInput from '../components/ui/input.vue'; import { host } from '../config'; -import i18n from '../i18n'; export default Vue.extend({ - i18n, components: { MkButton, diff --git a/src/client/pages/instance/announcements.vue b/src/client/pages/instance/announcements.vue index 2889cf8cce43597d0adab4b821a9a5d94c896389..0e11e2932e2c9df7a9f8dcb6deaa15f4a661364f 100644 --- a/src/client/pages/instance/announcements.vue +++ b/src/client/pages/instance/announcements.vue @@ -28,14 +28,11 @@ import Vue from 'vue'; import { faBroadcastTower, faPlus } from '@fortawesome/free-solid-svg-icons'; import { faSave, faTrashAlt } from '@fortawesome/free-regular-svg-icons'; -import i18n from '../../i18n'; import MkButton from '../../components/ui/button.vue'; import MkInput from '../../components/ui/input.vue'; import MkTextarea from '../../components/ui/textarea.vue'; export default Vue.extend({ - i18n, - metaInfo() { return { title: this.$t('announcements') as string diff --git a/src/client/pages/instance/federation.instance.vue b/src/client/pages/instance/federation.instance.vue index 08f4d1b4fb263ef89c5d345e70a2895cba80f800..6b6352a151b78e61721ee75a208a3e240ae9f889 100644 --- a/src/client/pages/instance/federation.instance.vue +++ b/src/client/pages/instance/federation.instance.vue @@ -120,7 +120,6 @@ <script lang="ts"> import Vue from 'vue'; import Chart from 'chart.js'; -import i18n from '../../i18n'; import { faTimes, faCrosshairs, faCloudDownloadAlt, faCloudUploadAlt, faUsers, faPencilAlt, faFileImage, faDatabase, faTrafficLight, faLongArrowAltUp, faLongArrowAltDown, faMinusCircle, faTrashAlt } from '@fortawesome/free-solid-svg-icons'; import XWindow from '../../components/window.vue'; import MkUsersDialog from '../../components/users-dialog.vue'; @@ -141,8 +140,6 @@ const alpha = hex => { }; export default Vue.extend({ - i18n, - components: { XWindow, MkSelect, diff --git a/src/client/pages/instance/federation.vue b/src/client/pages/instance/federation.vue index 5babc604539e51c74f601c957a82dd741beab57f..77819235d7d5b1ede0c4bdee5d5b54ee195fd146 100644 --- a/src/client/pages/instance/federation.vue +++ b/src/client/pages/instance/federation.vue @@ -62,7 +62,6 @@ <script lang="ts"> import Vue from 'vue'; import { faGlobe, faCircle, faExchangeAlt, faCaretDown, faCaretUp, faTrafficLight } from '@fortawesome/free-solid-svg-icons'; -import i18n from '../../i18n'; import MkButton from '../../components/ui/button.vue'; import MkInput from '../../components/ui/input.vue'; import MkSelect from '../../components/ui/select.vue'; @@ -70,8 +69,6 @@ import MkPagination from '../../components/ui/pagination.vue'; import MkInstanceInfo from './federation.instance.vue'; export default Vue.extend({ - i18n, - metaInfo() { return { title: this.$t('federation') as string diff --git a/src/client/pages/instance/index.vue b/src/client/pages/instance/index.vue index 1d90aa5537f46cd19ac9753eaf2bf734ac9a7e09..d21f8d455e854d165c8fa08f906424e502dba0dc 100644 --- a/src/client/pages/instance/index.vue +++ b/src/client/pages/instance/index.vue @@ -107,7 +107,6 @@ import MkButton from '../../components/ui/button.vue'; import MkSelect from '../../components/ui/select.vue'; import MkInput from '../../components/ui/input.vue'; import { version, url } from '../../config'; -import i18n from '../../i18n'; const alpha = (hex, a) => { const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex)!; @@ -118,8 +117,6 @@ const alpha = (hex, a) => { }; export default Vue.extend({ - i18n, - metaInfo() { return { title: this.$t('instance') as string diff --git a/src/client/pages/instance/queue.queue.vue b/src/client/pages/instance/queue.queue.vue index 7f0fc7d2bcbc1249ad0043b69c9c310232f160e2..1649d1e1725f93aa32427720c84adfdd8bcd49f2 100644 --- a/src/client/pages/instance/queue.queue.vue +++ b/src/client/pages/instance/queue.queue.vue @@ -25,7 +25,6 @@ <script lang="ts"> import Vue from 'vue'; import Chart from 'chart.js'; -import i18n from '../../i18n'; const alpha = (hex, a) => { const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex)!; @@ -36,8 +35,6 @@ const alpha = (hex, a) => { }; export default Vue.extend({ - i18n, - props: { domain: { required: true diff --git a/src/client/pages/instance/queue.vue b/src/client/pages/instance/queue.vue index c4892e88db629d9bd17ec26fd9f9b4abad426729..7a2204e5198ec8c75b482b6d1404cb4100ee5370 100644 --- a/src/client/pages/instance/queue.vue +++ b/src/client/pages/instance/queue.vue @@ -21,13 +21,10 @@ import Vue from 'vue'; import { faExchangeAlt } from '@fortawesome/free-solid-svg-icons'; import { faTrashAlt } from '@fortawesome/free-regular-svg-icons'; -import i18n from '../../i18n'; import MkButton from '../../components/ui/button.vue'; import XQueue from './queue.queue.vue'; export default Vue.extend({ - i18n, - metaInfo() { return { title: `${this.$t('jobQueue')} | ${this.$t('instance')}` diff --git a/src/client/pages/instance/relays.vue b/src/client/pages/instance/relays.vue index 9b523bd0ecb4d366cee4b412df73d84adba65cae..dd18867b6a9e68563c9ed1ab557835108b42db22 100644 --- a/src/client/pages/instance/relays.vue +++ b/src/client/pages/instance/relays.vue @@ -28,13 +28,10 @@ import Vue from 'vue'; import { faPlus, faProjectDiagram } from '@fortawesome/free-solid-svg-icons'; import { faSave, faTrashAlt } from '@fortawesome/free-regular-svg-icons'; -import i18n from '../../i18n'; import MkButton from '../../components/ui/button.vue'; import MkInput from '../../components/ui/input.vue'; export default Vue.extend({ - i18n, - metaInfo() { return { title: this.$t('relays') as string diff --git a/src/client/pages/instance/settings.vue b/src/client/pages/instance/settings.vue index afd6d4cc6d4b4b809b47d9bf8b23207b576f6104..0436e87804b6c982f1340933859d431e3e9a3343 100644 --- a/src/client/pages/instance/settings.vue +++ b/src/client/pages/instance/settings.vue @@ -210,12 +210,9 @@ import MkSwitch from '../../components/ui/switch.vue'; import MkInfo from '../../components/ui/info.vue'; import MkUserSelect from '../../components/user-select.vue'; import { url } from '../../config'; -import i18n from '../../i18n'; import getAcct from '../../../misc/acct/render'; export default Vue.extend({ - i18n, - metaInfo() { return { title: this.$t('instance') as string diff --git a/src/client/pages/instance/users.user.vue b/src/client/pages/instance/users.user.vue index 1fb064f7f08f970034592f2d3c76adcce8be08e7..25f0260637e460fdbde53d14ca174949c709116b 100644 --- a/src/client/pages/instance/users.user.vue +++ b/src/client/pages/instance/users.user.vue @@ -39,12 +39,9 @@ import { faTimes, faBookmark, faKey, faSync, faMicrophoneSlash, faExternalLinkSq import { faSnowflake, faTrashAlt, faBookmark as farBookmark } from '@fortawesome/free-regular-svg-icons'; import MkButton from '../../components/ui/button.vue'; import MkSwitch from '../../components/ui/switch.vue'; -import i18n from '../../i18n'; import Progress from '../../scripts/loading'; export default Vue.extend({ - i18n, - components: { MkButton, MkSwitch, diff --git a/src/client/pages/messaging/index.vue b/src/client/pages/messaging/index.vue index 7a55004cbf9ce0a718e5aaf862c26e22dd679847..7ee782c4a9081b23d117f8d6b4460be58450a110 100644 --- a/src/client/pages/messaging/index.vue +++ b/src/client/pages/messaging/index.vue @@ -42,14 +42,11 @@ <script lang="ts"> import Vue from 'vue'; import { faUser, faUsers, faComments, faPlus } from '@fortawesome/free-solid-svg-icons'; -import i18n from '../../i18n'; import getAcct from '../../../misc/acct/render'; import MkButton from '../../components/ui/button.vue'; import MkUserSelect from '../../components/user-select.vue'; export default Vue.extend({ - i18n, - components: { MkButton }, diff --git a/src/client/pages/messaging/messaging-room.form.vue b/src/client/pages/messaging/messaging-room.form.vue index 0cd3dfcc8580a395d331a7a51f980ffeaebf4acf..be47efd2ce5af234b257e9a080fe7e6f860f0fc2 100644 --- a/src/client/pages/messaging/messaging-room.form.vue +++ b/src/client/pages/messaging/messaging-room.form.vue @@ -27,12 +27,10 @@ import Vue from 'vue'; import { faPaperPlane, faPhotoVideo, faLaughSquint } from '@fortawesome/free-solid-svg-icons'; import insertTextAtCursor from 'insert-text-at-cursor'; import * as autosize from 'autosize'; -import i18n from '../../i18n'; import { formatTimeString } from '../../../misc/format-time-string'; import { selectFile } from '../../scripts/select-file'; export default Vue.extend({ - i18n, components: { XUploader: () => import('../../components/uploader.vue').then(m => m.default), }, diff --git a/src/client/pages/messaging/messaging-room.message.vue b/src/client/pages/messaging/messaging-room.message.vue index 67756572ff4faa98b2beddb26fd645e92eaeca17..58e1e54ad85b7fa52126af07bef4f1772ee8b89f 100644 --- a/src/client/pages/messaging/messaging-room.message.vue +++ b/src/client/pages/messaging/messaging-room.message.vue @@ -38,13 +38,11 @@ <script lang="ts"> import Vue from 'vue'; -import i18n from '../../i18n'; import { parse } from '../../../mfm/parse'; import { unique } from '../../../prelude/array'; import MkUrlPreview from '../../components/url-preview.vue'; export default Vue.extend({ - i18n, components: { MkUrlPreview }, diff --git a/src/client/pages/messaging/messaging-room.vue b/src/client/pages/messaging/messaging-room.vue index 317ad087fe04e4992473c3066d94d10328b959e9..e97d5532acd9114893d4626661ee30142bb17763 100644 --- a/src/client/pages/messaging/messaging-room.vue +++ b/src/client/pages/messaging/messaging-room.vue @@ -37,7 +37,6 @@ <script lang="ts"> import Vue from 'vue'; import { faArrowCircleDown, faFlag, faUsers, faInfoCircle } from '@fortawesome/free-solid-svg-icons'; -import i18n from '../../i18n'; import XList from '../../components/date-separated-list.vue'; import XMessage from './messaging-room.message.vue'; import XForm from './messaging-room.form.vue'; @@ -45,8 +44,6 @@ import { url } from '../../config'; import parseAcct from '../../../misc/acct/parse'; export default Vue.extend({ - i18n, - components: { XMessage, XForm, diff --git a/src/client/pages/miauth.vue b/src/client/pages/miauth.vue index 0e170af11a224ae70742e419b0d2f58e0bf3d737..15cde8bc2512792c03fa7cc48b7be82320ef588c 100644 --- a/src/client/pages/miauth.vue +++ b/src/client/pages/miauth.vue @@ -40,12 +40,10 @@ <script lang="ts"> import Vue from 'vue'; -import i18n from '../i18n'; import MkSignin from '../components/signin.vue'; import MkButton from '../components/ui/button.vue'; export default Vue.extend({ - i18n, components: { MkSignin, MkButton, diff --git a/src/client/pages/my-antennas/index.antenna.vue b/src/client/pages/my-antennas/index.antenna.vue index 2a9aebbcbf90be57f900850f4dc09a31ce429feb..6435e4fc9a139b296149b5b9834357f50ba107b1 100644 --- a/src/client/pages/my-antennas/index.antenna.vue +++ b/src/client/pages/my-antennas/index.antenna.vue @@ -48,7 +48,6 @@ <script lang="ts"> import Vue from 'vue'; import { faSave, faTrash } from '@fortawesome/free-solid-svg-icons'; -import i18n from '../../i18n'; import MkButton from '../../components/ui/button.vue'; import MkInput from '../../components/ui/input.vue'; import MkTextarea from '../../components/ui/textarea.vue'; @@ -58,8 +57,6 @@ import MkUserSelect from '../../components/user-select.vue'; import getAcct from '../../../misc/acct/render'; export default Vue.extend({ - i18n, - components: { MkButton, MkInput, MkTextarea, MkSelect, MkSwitch }, diff --git a/src/client/pages/my-groups/group.vue b/src/client/pages/my-groups/group.vue index c8170a2a575aaff477b5c1eb10ff7232ee9c1d1e..0132bc2c33ed635de190d94747dadbcaa85bf3e7 100644 --- a/src/client/pages/my-groups/group.vue +++ b/src/client/pages/my-groups/group.vue @@ -41,14 +41,11 @@ <script lang="ts"> import Vue from 'vue'; import { faTimes, faUsers } from '@fortawesome/free-solid-svg-icons'; -import i18n from '../../i18n'; import Progress from '../../scripts/loading'; import MkButton from '../../components/ui/button.vue'; import MkUserSelect from '../../components/user-select.vue'; export default Vue.extend({ - i18n, - metaInfo() { return { title: this.group ? `${this.group.name} | ${this.$t('manageGroups')}` : this.$t('manageGroups') diff --git a/src/client/pages/my-lists/list.vue b/src/client/pages/my-lists/list.vue index cf85a80ccb6de8cff8a7c20c50999dea77917bbc..7052c55160c8007bf73eb3d76a96d27152b79b7d 100644 --- a/src/client/pages/my-lists/list.vue +++ b/src/client/pages/my-lists/list.vue @@ -40,14 +40,11 @@ <script lang="ts"> import Vue from 'vue'; import { faTimes, faListUl } from '@fortawesome/free-solid-svg-icons'; -import i18n from '../../i18n'; import Progress from '../../scripts/loading'; import MkButton from '../../components/ui/button.vue'; import MkUserSelect from '../../components/user-select.vue'; export default Vue.extend({ - i18n, - metaInfo() { return { title: this.list ? `${this.list.name} | ${this.$t('manageLists')}` : this.$t('manageLists') diff --git a/src/client/pages/my-settings/2fa.vue b/src/client/pages/my-settings/2fa.vue index 6ceca21fe60edb122472363f76da01204a78cc1f..58ba03c41c1813e5638934891c68dc260e8b99df 100644 --- a/src/client/pages/my-settings/2fa.vue +++ b/src/client/pages/my-settings/2fa.vue @@ -65,7 +65,6 @@ <script lang="ts"> import Vue from 'vue'; import { faLock } from '@fortawesome/free-solid-svg-icons'; -import i18n from '../../i18n'; import { hostname } from '../../config'; import { byteify, hexify, stringify } from '../../scripts/2fa'; import MkButton from '../../components/ui/button.vue'; @@ -74,7 +73,6 @@ import MkInput from '../../components/ui/input.vue'; import MkSwitch from '../../components/ui/switch.vue'; export default Vue.extend({ - i18n, components: { MkButton, MkInfo, MkInput, MkSwitch }, diff --git a/src/client/pages/my-settings/api.vue b/src/client/pages/my-settings/api.vue index f394c826de5d1ab4702c09c247c7c1b1005297c4..79b459fb5eeb5fd2d4b2cc7e39a43d9134eccefd 100644 --- a/src/client/pages/my-settings/api.vue +++ b/src/client/pages/my-settings/api.vue @@ -13,12 +13,10 @@ <script lang="ts"> import Vue from 'vue'; import { faKey, faSyncAlt } from '@fortawesome/free-solid-svg-icons'; -import i18n from '../../i18n'; import MkButton from '../../components/ui/button.vue'; import MkInput from '../../components/ui/input.vue'; export default Vue.extend({ - i18n, components: { MkButton, MkInput }, diff --git a/src/client/pages/my-settings/drive.vue b/src/client/pages/my-settings/drive.vue index c3d2d1dc2db6c193e127b3235833aa249890fb00..7612c5011f78d47dc9b68ea5b1fbb9bba663108e 100644 --- a/src/client/pages/my-settings/drive.vue +++ b/src/client/pages/my-settings/drive.vue @@ -13,12 +13,9 @@ import Vue from 'vue'; import { faCloud, faFolderOpen } from '@fortawesome/free-solid-svg-icons'; import { faClock, faEyeSlash, faTrashAlt } from '@fortawesome/free-regular-svg-icons'; import MkButton from '../../components/ui/button.vue'; -import i18n from '../../i18n'; import { selectDriveFolder } from '../../scripts/select-drive-folder'; export default Vue.extend({ - i18n, - components: { MkButton, }, diff --git a/src/client/pages/my-settings/import-export.vue b/src/client/pages/my-settings/import-export.vue index 47957411895b7c79900d1df366282eef6252b03d..cc148d48d49cde3cb028b662bd1e10aa2b1bfe9d 100644 --- a/src/client/pages/my-settings/import-export.vue +++ b/src/client/pages/my-settings/import-export.vue @@ -21,12 +21,9 @@ import Vue from 'vue'; import { faDownload, faUpload, faBoxes } from '@fortawesome/free-solid-svg-icons'; import MkButton from '../../components/ui/button.vue'; import MkSelect from '../../components/ui/select.vue'; -import i18n from '../../i18n'; import { apiUrl } from '../../config'; export default Vue.extend({ - i18n, - components: { MkButton, MkSelect, diff --git a/src/client/pages/my-settings/integration.vue b/src/client/pages/my-settings/integration.vue index 3dd7783f12f1e9e7c52e1206c800fd8f689084c4..2d6e57e22c8a00fe993fe125447e63647baf69bb 100644 --- a/src/client/pages/my-settings/integration.vue +++ b/src/client/pages/my-settings/integration.vue @@ -29,13 +29,10 @@ import Vue from 'vue'; import { faShareAlt } from '@fortawesome/free-solid-svg-icons'; import { faTwitter, faDiscord, faGithub } from '@fortawesome/free-brands-svg-icons'; -import i18n from '../../i18n'; import { apiUrl } from '../../config'; import MkButton from '../../components/ui/button.vue'; export default Vue.extend({ - i18n, - components: { MkButton }, diff --git a/src/client/pages/my-settings/mute-block.vue b/src/client/pages/my-settings/mute-block.vue index 03cf4aacc82766cca0420a9cb195743790299a59..8eb43a6e29653d689777380e86caa5369d915bfb 100644 --- a/src/client/pages/my-settings/mute-block.vue +++ b/src/client/pages/my-settings/mute-block.vue @@ -34,11 +34,8 @@ import Vue from 'vue'; import { faBan } from '@fortawesome/free-solid-svg-icons'; import MkPagination from '../../components/ui/pagination.vue'; -import i18n from '../../i18n'; export default Vue.extend({ - i18n, - components: { MkPagination, }, diff --git a/src/client/pages/my-settings/privacy.vue b/src/client/pages/my-settings/privacy.vue index 7ac9062d8818bba32a53b8cee7267119b53d6ad8..527ac9ea37a78ab908fe218cc61d8e01405e29ff 100644 --- a/src/client/pages/my-settings/privacy.vue +++ b/src/client/pages/my-settings/privacy.vue @@ -24,11 +24,8 @@ import Vue from 'vue'; import { faLock } from '@fortawesome/free-solid-svg-icons'; import MkSelect from '../../components/ui/select.vue'; import MkSwitch from '../../components/ui/switch.vue'; -import i18n from '../../i18n'; export default Vue.extend({ - i18n, - components: { MkSelect, MkSwitch, diff --git a/src/client/pages/my-settings/profile.vue b/src/client/pages/my-settings/profile.vue index b168c89ec02f827890a3d060f20b80ea51db6aa4..16bba7a2709c1c08c683b1fae983848dd890e2f7 100644 --- a/src/client/pages/my-settings/profile.vue +++ b/src/client/pages/my-settings/profile.vue @@ -62,13 +62,10 @@ import MkButton from '../../components/ui/button.vue'; import MkInput from '../../components/ui/input.vue'; import MkTextarea from '../../components/ui/textarea.vue'; import MkSwitch from '../../components/ui/switch.vue'; -import i18n from '../../i18n'; import { host } from '../../config'; import { selectFile } from '../../scripts/select-file'; export default Vue.extend({ - i18n, - components: { MkButton, MkInput, diff --git a/src/client/pages/my-settings/reaction.vue b/src/client/pages/my-settings/reaction.vue index 68c481707cee996c37a177f3ebcaace5ee6ba8d5..ef4f6f6723fc7e48b14c637ffd207d2a562de83a 100644 --- a/src/client/pages/my-settings/reaction.vue +++ b/src/client/pages/my-settings/reaction.vue @@ -21,13 +21,10 @@ import { faUndo } from '@fortawesome/free-solid-svg-icons'; import MkInput from '../../components/ui/input.vue'; import MkButton from '../../components/ui/button.vue'; import MkReactionPicker from '../../components/reaction-picker.vue'; -import i18n from '../../i18n'; import { emojiRegexWithCustom } from '../../../misc/emoji-regex'; import { defaultSettings } from '../../store'; export default Vue.extend({ - i18n, - components: { MkInput, MkButton, diff --git a/src/client/pages/my-settings/security.vue b/src/client/pages/my-settings/security.vue index ba670b2f6887b8f8cccb5684b3aabfeaae1e502a..dc77ca12c514a3a3effc3a9ada2ce485edcd46b2 100644 --- a/src/client/pages/my-settings/security.vue +++ b/src/client/pages/my-settings/security.vue @@ -11,11 +11,8 @@ import Vue from 'vue'; import { faLock } from '@fortawesome/free-solid-svg-icons'; import MkButton from '../../components/ui/button.vue'; -import i18n from '../../i18n'; export default Vue.extend({ - i18n, - components: { MkButton, }, diff --git a/src/client/pages/not-found.vue b/src/client/pages/not-found.vue index 9608e07786b6c4f543848ea8f722543d91192d0c..7f4c46c23d3c31eec16d637d316613e15df0793e 100644 --- a/src/client/pages/not-found.vue +++ b/src/client/pages/not-found.vue @@ -15,11 +15,8 @@ <script lang="ts"> import Vue from 'vue'; import { faExclamationTriangle } from '@fortawesome/free-solid-svg-icons'; -import i18n from '../i18n'; export default Vue.extend({ - i18n, - metaInfo() { return { title: this.$t('notFound') as string diff --git a/src/client/pages/note.vue b/src/client/pages/note.vue index 37c66833e970a0e34304543801563479481f4551..48629a4ebeec0074899aa538c05f597c88282d8a 100644 --- a/src/client/pages/note.vue +++ b/src/client/pages/note.vue @@ -29,14 +29,12 @@ <script lang="ts"> import Vue from 'vue'; import { faChevronUp, faChevronDown } from '@fortawesome/free-solid-svg-icons'; -import i18n from '../i18n'; import Progress from '../scripts/loading'; import XNote from '../components/note.vue'; import XNotes from '../components/notes.vue'; import MkRemoteCaution from '../components/remote-caution.vue'; export default Vue.extend({ - i18n, metaInfo() { return { title: this.$t('note') as string diff --git a/src/client/pages/page-editor/els/page-editor.el.button.vue b/src/client/pages/page-editor/els/page-editor.el.button.vue index 9ca9fe06f3b7240d3d01a1d06b40161e0041933c..9821201666a0baedc75ac58d32cf412e4a7331e4 100644 --- a/src/client/pages/page-editor/els/page-editor.el.button.vue +++ b/src/client/pages/page-editor/els/page-editor.el.button.vue @@ -40,15 +40,12 @@ <script lang="ts"> import Vue from 'vue'; import { faBolt } from '@fortawesome/free-solid-svg-icons'; -import i18n from '../../../i18n'; import XContainer from '../page-editor.container.vue'; import MkSelect from '../../../components/ui/select.vue'; import MkInput from '../../../components/ui/input.vue'; import MkSwitch from '../../../components/ui/switch.vue'; export default Vue.extend({ - i18n, - components: { XContainer, MkSelect, MkInput, MkSwitch }, diff --git a/src/client/pages/page-editor/els/page-editor.el.canvas.vue b/src/client/pages/page-editor/els/page-editor.el.canvas.vue index 49773189192085d844b828e095f1cfed6637d9e8..a499207806a89a5920dfe38d9c822dac5d431d03 100644 --- a/src/client/pages/page-editor/els/page-editor.el.canvas.vue +++ b/src/client/pages/page-editor/els/page-editor.el.canvas.vue @@ -13,13 +13,10 @@ <script lang="ts"> import Vue from 'vue'; import { faPaintBrush, faMagic } from '@fortawesome/free-solid-svg-icons'; -import i18n from '../../../i18n'; import XContainer from '../page-editor.container.vue'; import MkInput from '../../../components/ui/input.vue'; export default Vue.extend({ - i18n, - components: { XContainer, MkInput }, diff --git a/src/client/pages/page-editor/els/page-editor.el.counter.vue b/src/client/pages/page-editor/els/page-editor.el.counter.vue index d9a4ddddee3e18d8beac15ffb84168d11c616071..f439f3e6ff4f8cd21b3af5c1369e42d31cbb4bcf 100644 --- a/src/client/pages/page-editor/els/page-editor.el.counter.vue +++ b/src/client/pages/page-editor/els/page-editor.el.counter.vue @@ -13,13 +13,10 @@ <script lang="ts"> import Vue from 'vue'; import { faBolt, faMagic } from '@fortawesome/free-solid-svg-icons'; -import i18n from '../../../i18n'; import XContainer from '../page-editor.container.vue'; import MkInput from '../../../components/ui/input.vue'; export default Vue.extend({ - i18n, - components: { XContainer, MkInput }, 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 0449b9cf2b949a891bfc18196f7ac61fce8f4c3a..53cb9e2aee8f3af4f1b01d62b41513e16f5b30bf 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 @@ -28,13 +28,10 @@ import Vue from 'vue'; import { v4 as uuid } from 'uuid'; import { faPlus, faQuestion } from '@fortawesome/free-solid-svg-icons'; -import i18n from '../../../i18n'; import XContainer from '../page-editor.container.vue'; import MkSelect from '../../../components/ui/select.vue'; export default Vue.extend({ - i18n, - components: { XContainer, MkSelect }, diff --git a/src/client/pages/page-editor/els/page-editor.el.image.vue b/src/client/pages/page-editor/els/page-editor.el.image.vue index e22701e5c0a1485c97295b2e7efc876ecbda1b39..dd690da6f15c3abd61bfcdcd521995e944b308fc 100644 --- a/src/client/pages/page-editor/els/page-editor.el.image.vue +++ b/src/client/pages/page-editor/els/page-editor.el.image.vue @@ -17,14 +17,11 @@ import Vue from 'vue'; import { faPencilAlt } from '@fortawesome/free-solid-svg-icons'; import { faImage, faFolderOpen } from '@fortawesome/free-regular-svg-icons'; -import i18n from '../../../i18n'; import XContainer from '../page-editor.container.vue'; import MkFileThumbnail from '../../../components/drive-file-thumbnail.vue'; import { selectDriveFile } from '../../../scripts/select-drive-file'; export default Vue.extend({ - i18n, - components: { XContainer, MkFileThumbnail }, diff --git a/src/client/pages/page-editor/els/page-editor.el.number-input.vue b/src/client/pages/page-editor/els/page-editor.el.number-input.vue index 76dd254464aaf553dd11595c5194151ee533deed..62d2e1bf8a6d0def51ef42be59fd3365640a7df8 100644 --- a/src/client/pages/page-editor/els/page-editor.el.number-input.vue +++ b/src/client/pages/page-editor/els/page-editor.el.number-input.vue @@ -13,13 +13,10 @@ <script lang="ts"> import Vue from 'vue'; import { faBolt, faMagic } from '@fortawesome/free-solid-svg-icons'; -import i18n from '../../../i18n'; import XContainer from '../page-editor.container.vue'; import MkInput from '../../../components/ui/input.vue'; export default Vue.extend({ - i18n, - components: { XContainer, MkInput }, diff --git a/src/client/pages/page-editor/els/page-editor.el.post.vue b/src/client/pages/page-editor/els/page-editor.el.post.vue index 2c6ce24e95de0d50e82fd01748ac59cbc00ad68d..06dea51c1f5057612fa0aac537a5a0ccde3ebb07 100644 --- a/src/client/pages/page-editor/els/page-editor.el.post.vue +++ b/src/client/pages/page-editor/els/page-editor.el.post.vue @@ -13,15 +13,12 @@ <script lang="ts"> import Vue from 'vue'; import { faPaperPlane } from '@fortawesome/free-regular-svg-icons'; -import i18n from '../../../i18n'; import XContainer from '../page-editor.container.vue'; import MkTextarea from '../../../components/ui/textarea.vue'; import MkInput from '../../../components/ui/input.vue'; import MkSwitch from '../../../components/ui/switch.vue'; export default Vue.extend({ - i18n, - components: { XContainer, MkTextarea, MkInput, MkSwitch }, diff --git a/src/client/pages/page-editor/els/page-editor.el.radio-button.vue b/src/client/pages/page-editor/els/page-editor.el.radio-button.vue index 8d404ec0df79c3a9e66f74220259eab225617ad6..34a9366d628bf5cd7e0c2fe4cc315361a28adf26 100644 --- a/src/client/pages/page-editor/els/page-editor.el.radio-button.vue +++ b/src/client/pages/page-editor/els/page-editor.el.radio-button.vue @@ -14,13 +14,11 @@ <script lang="ts"> import Vue from 'vue'; import { faBolt, faMagic } from '@fortawesome/free-solid-svg-icons'; -import i18n from '../../../i18n'; import XContainer from '../page-editor.container.vue'; import MkTextarea from '../../../components/ui/textarea.vue'; import MkInput from '../../../components/ui/input.vue'; export default Vue.extend({ - i18n, components: { XContainer, MkTextarea, MkInput }, 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 a32cf9c753455b8571d8536f7d5d1aa205db9ec3..e89a8b840c4282d955caf50820ecd94ef16da40e 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 @@ -21,12 +21,9 @@ import Vue from 'vue'; import { v4 as uuid } from 'uuid'; import { faPlus, faPencilAlt } from '@fortawesome/free-solid-svg-icons'; import { faStickyNote } from '@fortawesome/free-regular-svg-icons'; -import i18n from '../../../i18n'; import XContainer from '../page-editor.container.vue'; export default Vue.extend({ - i18n, - components: { XContainer }, diff --git a/src/client/pages/page-editor/els/page-editor.el.switch.vue b/src/client/pages/page-editor/els/page-editor.el.switch.vue index 8f169c3d23cee06e59dd5a7d9322a7cf1261f665..5055da4f6f17db35e87a0d3469a247060697d21f 100644 --- a/src/client/pages/page-editor/els/page-editor.el.switch.vue +++ b/src/client/pages/page-editor/els/page-editor.el.switch.vue @@ -13,14 +13,11 @@ <script lang="ts"> import Vue from 'vue'; import { faBolt, faMagic } from '@fortawesome/free-solid-svg-icons'; -import i18n from '../../../i18n'; import XContainer from '../page-editor.container.vue'; import MkSwitch from '../../../components/ui/switch.vue'; import MkInput from '../../../components/ui/input.vue'; export default Vue.extend({ - i18n, - components: { XContainer, MkSwitch, MkInput }, diff --git a/src/client/pages/page-editor/els/page-editor.el.text-input.vue b/src/client/pages/page-editor/els/page-editor.el.text-input.vue index 7c9e3d6a0e34ad5fa9c30644a9ca826686f57c70..bd5fb3761727b573b8bfda16ff3243a4ba38c4f2 100644 --- a/src/client/pages/page-editor/els/page-editor.el.text-input.vue +++ b/src/client/pages/page-editor/els/page-editor.el.text-input.vue @@ -13,13 +13,10 @@ <script lang="ts"> import Vue from 'vue'; import { faBolt, faMagic } from '@fortawesome/free-solid-svg-icons'; -import i18n from '../../../i18n'; import XContainer from '../page-editor.container.vue'; import MkInput from '../../../components/ui/input.vue'; export default Vue.extend({ - i18n, - components: { XContainer, MkInput }, diff --git a/src/client/pages/page-editor/els/page-editor.el.text.vue b/src/client/pages/page-editor/els/page-editor.el.text.vue index c6722236eb51b17b106e7f0176c70c8bd2933f4c..a50b1113bd7714a4a609f324b688d009f573cb6b 100644 --- a/src/client/pages/page-editor/els/page-editor.el.text.vue +++ b/src/client/pages/page-editor/els/page-editor.el.text.vue @@ -11,12 +11,9 @@ <script lang="ts"> import Vue from 'vue'; import { faAlignLeft } from '@fortawesome/free-solid-svg-icons'; -import i18n from '../../../i18n'; import XContainer from '../page-editor.container.vue'; export default Vue.extend({ - i18n, - components: { XContainer }, diff --git a/src/client/pages/page-editor/els/page-editor.el.textarea-input.vue b/src/client/pages/page-editor/els/page-editor.el.textarea-input.vue index 8081e706bcccbc375892a683b0b2367d0de2c74d..33c49c705b5952826746932bd9f76ef127621590 100644 --- a/src/client/pages/page-editor/els/page-editor.el.textarea-input.vue +++ b/src/client/pages/page-editor/els/page-editor.el.textarea-input.vue @@ -13,14 +13,11 @@ <script lang="ts"> import Vue from 'vue'; import { faBolt, faMagic } from '@fortawesome/free-solid-svg-icons'; -import i18n from '../../../i18n'; import XContainer from '../page-editor.container.vue'; import MkTextarea from '../../../components/ui/textarea.vue'; import MkInput from '../../../components/ui/input.vue'; export default Vue.extend({ - i18n, - components: { XContainer, MkTextarea, MkInput }, diff --git a/src/client/pages/page-editor/els/page-editor.el.textarea.vue b/src/client/pages/page-editor/els/page-editor.el.textarea.vue index d31da5dfa3923dec8afb1639e2b2afab53b4474c..e2e8848ccfd25eb395d2e54036bfb594a030dfdd 100644 --- a/src/client/pages/page-editor/els/page-editor.el.textarea.vue +++ b/src/client/pages/page-editor/els/page-editor.el.textarea.vue @@ -11,12 +11,9 @@ <script lang="ts"> import Vue from 'vue'; import { faAlignLeft } from '@fortawesome/free-solid-svg-icons'; -import i18n from '../../../i18n'; import XContainer from '../page-editor.container.vue'; export default Vue.extend({ - i18n, - components: { XContainer }, diff --git a/src/client/pages/page-editor/page-editor.container.vue b/src/client/pages/page-editor/page-editor.container.vue index 5bc97446710d4796042485763fbf2b2346597ce4..3fa09f5600bed7d391b4e3f0ec1f48216008c967 100644 --- a/src/client/pages/page-editor/page-editor.container.vue +++ b/src/client/pages/page-editor/page-editor.container.vue @@ -28,11 +28,8 @@ import Vue from 'vue'; import { faBars, faAngleUp, faAngleDown } from '@fortawesome/free-solid-svg-icons'; import { faTrashAlt } from '@fortawesome/free-regular-svg-icons'; -import i18n from '../../i18n'; export default Vue.extend({ - i18n, - props: { expanded: { type: Boolean, 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 9eafd5daa08d37e2ac1856a9a81f66720e1b0fbc..f3270f02e3a8440a663349fb3e730d0cffced49f 100644 --- a/src/client/pages/page-editor/page-editor.script-block.vue +++ b/src/client/pages/page-editor/page-editor.script-block.vue @@ -59,14 +59,11 @@ import Vue from 'vue'; import { faPencilAlt, faPlug } from '@fortawesome/free-solid-svg-icons'; import { v4 as uuid } from 'uuid'; -import i18n from '../../i18n'; import XContainer from './page-editor.container.vue'; import MkTextarea from '../../components/ui/textarea.vue'; import { isLiteralBlock, funcDefs, blockDefs } from '../../scripts/hpml/index'; export default Vue.extend({ - i18n, - components: { XContainer, MkTextarea }, diff --git a/src/client/pages/page-editor/page-editor.vue b/src/client/pages/page-editor/page-editor.vue index 4437c7716d4e1f8714547e507c66716835e5a2a8..2beb2df389ae5a3b4c4c38bd1a17cf64bac748b5 100644 --- a/src/client/pages/page-editor/page-editor.vue +++ b/src/client/pages/page-editor/page-editor.vue @@ -91,7 +91,6 @@ import PrismEditor from 'vue-prism-editor'; import { faICursor, faPlus, faMagic, faCog, faCode, faExternalLinkSquareAlt } from '@fortawesome/free-solid-svg-icons'; import { faSave, faStickyNote, faTrashAlt } from '@fortawesome/free-regular-svg-icons'; import { v4 as uuid } from 'uuid'; -import i18n from '../../i18n'; import XVariable from './page-editor.script-block.vue'; import XBlocks from './page-editor.blocks.vue'; import MkTextarea from '../../components/ui/textarea.vue'; @@ -107,8 +106,6 @@ import { collectPageVars } from '../../scripts/collect-page-vars'; import { selectDriveFile } from '../../scripts/select-drive-file'; export default Vue.extend({ - i18n, - components: { XDraggable, XVariable, XBlocks, MkTextarea, MkContainer, MkButton, MkSelect, MkSwitch, MkInput, PrismEditor }, diff --git a/src/client/pages/pages.vue b/src/client/pages/pages.vue index dd3d09db0872ea67ab709b9c2fa73a9b98f38187..a2617857157eeeeb6ee1838536ff3c2fb9082a3e 100644 --- a/src/client/pages/pages.vue +++ b/src/client/pages/pages.vue @@ -28,14 +28,12 @@ import Vue from 'vue'; import { faPlus, faEdit } from '@fortawesome/free-solid-svg-icons'; import { faStickyNote, faHeart } from '@fortawesome/free-regular-svg-icons'; -import i18n from '../i18n'; import MkPagePreview from '../components/page-preview.vue'; import MkPagination from '../components/ui/pagination.vue'; import MkButton from '../components/ui/button.vue'; import MkContainer from '../components/ui/container.vue'; export default Vue.extend({ - i18n, components: { MkPagePreview, MkPagination, MkButton, MkContainer }, diff --git a/src/client/pages/preferences/index.vue b/src/client/pages/preferences/index.vue index 9f4bb679562dfe7a41fb10e4659f79105ad9549c..14d22bf02da6b8eda81b98694a0947dfa60659c6 100644 --- a/src/client/pages/preferences/index.vue +++ b/src/client/pages/preferences/index.vue @@ -99,8 +99,8 @@ import MkRadio from '../../components/ui/radio.vue'; import MkRange from '../../components/ui/range.vue'; import XTheme from './theme.vue'; import XSidebar from './sidebar.vue'; -import i18n from '../../i18n'; import { langs } from '../../config'; +import { clientDb, set } from '../../db'; const sounds = [ null, @@ -120,8 +120,6 @@ const sounds = [ ]; export default Vue.extend({ - i18n, - metaInfo() { return { title: this.$t('settings') as string @@ -228,9 +226,23 @@ export default Vue.extend({ watch: { lang() { + const dialog = this.$root.dialog({ + type: 'waiting', + iconOnly: true + }); + localStorage.setItem('lang', this.lang); - localStorage.removeItem('locale'); - location.reload(); + + return set('_version_', `changeLang-${(new Date()).toJSON()}`, clientDb.i18n) + .then(() => location.reload()) + .catch(() => { + dialog.close(); + this.$root.dialog({ + type: 'error', + iconOnly: true, + autoClose: true + }); + }); }, fontSize() { diff --git a/src/client/pages/preferences/sidebar.vue b/src/client/pages/preferences/sidebar.vue index 2dced10e7bb7968f8ecd0cc1a8acd95ea544dea3..34c9916cf51de2bf8c03d1ced64d5c76b7a73d61 100644 --- a/src/client/pages/preferences/sidebar.vue +++ b/src/client/pages/preferences/sidebar.vue @@ -19,12 +19,9 @@ import Vue from 'vue'; import { faListUl, faSave, faRedo } from '@fortawesome/free-solid-svg-icons'; import MkButton from '../../components/ui/button.vue'; import MkTextarea from '../../components/ui/textarea.vue'; -import i18n from '../../i18n'; import { defaultDeviceUserSettings } from '../../store'; export default Vue.extend({ - i18n, - components: { MkButton, MkTextarea, diff --git a/src/client/pages/preferences/theme.vue b/src/client/pages/preferences/theme.vue index f35b5d6ed8ac1092f116504760ff8993f0b87c1e..2111fa22483a65a023b94250fea08d799bc6dd33 100644 --- a/src/client/pages/preferences/theme.vue +++ b/src/client/pages/preferences/theme.vue @@ -87,14 +87,11 @@ import MkButton from '../../components/ui/button.vue'; import MkSelect from '../../components/ui/select.vue'; import MkSwitch from '../../components/ui/switch.vue'; import MkTextarea from '../../components/ui/textarea.vue'; -import i18n from '../../i18n'; import { Theme, builtinThemes, applyTheme, validateTheme } from '../../theme'; import { selectFile } from '../../scripts/select-file'; import { isDeviceDarkmode } from '../../scripts/is-device-darkmode'; export default Vue.extend({ - i18n, - components: { MkInput, MkButton, diff --git a/src/client/pages/room/room.vue b/src/client/pages/room/room.vue index 6ede771c568d410fdee43c2f27f99ab3b6722531..cf6850526f56acaa3335b66fda7bdf4dd9491d74 100644 --- a/src/client/pages/room/room.vue +++ b/src/client/pages/room/room.vue @@ -59,7 +59,6 @@ <script lang="ts"> import Vue from 'vue'; -import i18n from '../../i18n'; import { Room } from '../../scripts/room/room'; import parseAcct from '../../../misc/acct/parse'; import XPreview from './preview.vue'; @@ -74,8 +73,6 @@ import { selectFile } from '../../scripts/select-file'; let room: Room; export default Vue.extend({ - i18n, - components: { XPreview, MkButton, diff --git a/src/client/pages/scratchpad.vue b/src/client/pages/scratchpad.vue index 622c40398f7a208a1809746cee0323eda6137727..81d4e6045993a1e33c44220988141246185b4d82 100644 --- a/src/client/pages/scratchpad.vue +++ b/src/client/pages/scratchpad.vue @@ -28,14 +28,11 @@ import "prismjs"; import 'prismjs/themes/prism-okaidia.css'; import PrismEditor from 'vue-prism-editor'; import { AiScript, parse, utils, values } from '@syuilo/aiscript'; -import i18n from '../i18n'; import MkContainer from '../components/ui/container.vue'; import MkButton from '../components/ui/button.vue'; import { createAiScriptEnv } from '../scripts/create-aiscript-env'; export default Vue.extend({ - i18n, - metaInfo() { return { title: this.$t('scratchpad') as string diff --git a/src/client/pages/share.vue b/src/client/pages/share.vue index 566650e309cc563c825acba802f585b756b7097a..153de76801d2a7040f5bdb2bd16ab7b127a45652 100644 --- a/src/client/pages/share.vue +++ b/src/client/pages/share.vue @@ -18,13 +18,10 @@ <script lang="ts"> import Vue from 'vue'; import { faShareAlt } from '@fortawesome/free-solid-svg-icons'; -import i18n from '../i18n'; import PostFormDialog from '../components/post-form-dialog.vue'; import MkButton from '../components/ui/button.vue'; export default Vue.extend({ - i18n, - metaInfo() { return { title: this.$t('share') as string diff --git a/src/client/pages/user/follow-list.vue b/src/client/pages/user/follow-list.vue index 3da0b8359de9388a620d0eefeb733f30d8ad75eb..666e2d04fefcc8b374f6bd815a3c60463fce2b8e 100644 --- a/src/client/pages/user/follow-list.vue +++ b/src/client/pages/user/follow-list.vue @@ -19,13 +19,10 @@ <script lang="ts"> import Vue from 'vue'; import parseAcct from '../../../misc/acct/parse'; -import i18n from '../../i18n'; import MkFollowButton from '../../components/follow-button.vue'; import MkPagination from '../../components/ui/pagination.vue'; export default Vue.extend({ - i18n, - components: { MkPagination, MkFollowButton, diff --git a/src/client/pages/user/index.photos.vue b/src/client/pages/user/index.photos.vue index 07b4db0a93cd8ecbf8818d93f96c9d5a816b7ab2..83a2618403a9b4a0cb2e90ab2bc77e4949580f51 100644 --- a/src/client/pages/user/index.photos.vue +++ b/src/client/pages/user/index.photos.vue @@ -14,11 +14,9 @@ <script lang="ts"> import Vue from 'vue'; -import i18n from '../../i18n'; import { getStaticImageUrl } from '../../scripts/get-static-image-url'; export default Vue.extend({ - i18n, props: ['user'], data() { return { diff --git a/src/client/scripts/compose-notification.ts b/src/client/scripts/compose-notification.ts index bf3255250676b94415f14ccf4b14dd45dbc63a29..29eb515bfe0700a2ce8aa50db288589173a7dbbb 100644 --- a/src/client/scripts/compose-notification.ts +++ b/src/client/scripts/compose-notification.ts @@ -1,58 +1,95 @@ import getNoteSummary from '../../misc/get-note-summary'; import getUserName from '../../misc/get-user-name'; +import { clientDb, get, bulkGet } from '../db'; +import { fromEntries } from '../../prelude/array'; -type Notification = { - title: string; - body: string; - icon: string; - onclick?: any; -}; +const getTranslation = (text: string): Promise<string> => get(text, clientDb.i18n); -// TODO: i18n +export default async function(type, data): Promise<[string, NotificationOptions]> { + const contexts = ['deletedNote', 'invisibleNote', 'withNFiles', '_cw.poll']; + const locale = fromEntries(await bulkGet(contexts, clientDb.i18n) as [string, string][]); -export default function(type, data): Notification { switch (type) { - case 'driveFileCreated': - return { - title: 'File uploaded', + case 'driveFileCreated': // TODO (Server Side) + return [await getTranslation('_notification.fileUploaded'), { body: data.name, icon: data.url - }; - + }]; case 'notification': switch (data.type) { case 'mention': - return { - title: `${getUserName(data.user)}:`, - body: getNoteSummary(data), + return [(await getTranslation('_notification.youGotMention')).replace('{name}', getUserName(data.user)), { + body: getNoteSummary(data.note, locale), icon: data.user.avatarUrl - }; + }]; case 'reply': - return { - title: `You got reply from ${getUserName(data.user)}:`, - body: getNoteSummary(data), + return [(await getTranslation('_notification.youGotReply')).replace('{name}', getUserName(data.user)), { + body: getNoteSummary(data.note, locale), + icon: data.user.avatarUrl + }]; + + case 'renote': + return [(await getTranslation('_notification.youRenoted')).replace('{name}', getUserName(data.user)), { + body: getNoteSummary(data.note, locale), icon: data.user.avatarUrl - }; + }]; case 'quote': - return { - title: `${getUserName(data.user)}:`, - body: getNoteSummary(data), + return [(await getTranslation('_notification.youGotQuote')).replace('{name}', getUserName(data.user)), { + body: getNoteSummary(data.note, locale), icon: data.user.avatarUrl - }; + }]; case 'reaction': - return { - title: `${getUserName(data.user)}: ${data.reaction}:`, - body: getNoteSummary(data.note), + return [`${data.reaction} ${getUserName(data.user)}`, { + body: getNoteSummary(data.note, locale), + icon: data.user.avatarUrl + }]; + + case 'pollVote': + return [(await getTranslation('_notification.youGotPoll')).replace('{name}', getUserName(data.user)), { + body: getNoteSummary(data.note, locale), + icon: data.user.avatarUrl + }]; + + case 'follow': + return [await getTranslation('_notification.youWereFollowed'), { + body: getUserName(data.user), icon: data.user.avatarUrl - }; + }]; + + case 'receiveFollowRequest': + return [await getTranslation('_notification.youReceivedFollowRequest'), { + body: getUserName(data.user), + icon: data.user.avatarUrl + }]; + + case 'followRequestAccepted': + return [await getTranslation('_notification.yourFollowRequestAccepted'), { + body: getUserName(data.user), + icon: data.user.avatarUrl + }]; + + case 'groupInvited': + return [await getTranslation('_notification.youWereInvitedToGroup'), { + body: data.group.name + }]; default: return null; } - + case 'unreadMessagingMessage': + if (data.groupId === null) { + return [(await getTranslation('_notification.youGotMessagingMessageFromUser')).replace('{name}', getUserName(data.user)), { + icon: data.user.avatarUrl, + tag: `messaging:user:${data.user.id}` + }]; + } + return [(await getTranslation('_notification.youGotMessagingMessageFromGroup')).replace('{name}', data.group.name), { + icon: data.user.avatarUrl, + tag: `messaging:group:${data.group.id}` + }]; default: return null; } diff --git a/src/client/scripts/set-i18n-contexts.ts b/src/client/scripts/set-i18n-contexts.ts new file mode 100644 index 0000000000000000000000000000000000000000..2eb76047f1e17e487862ddea2aa7278c07a87fa5 --- /dev/null +++ b/src/client/scripts/set-i18n-contexts.ts @@ -0,0 +1,18 @@ +import VueI18n from 'vue-i18n'; +import { clientDb, clear, bulkSet } from '../db'; +import { deepEntries, delimitEntry } from 'deep-entries'; +import { fromEntries } from '../../prelude/array'; + +export function setI18nContexts(lang: string, version: string, i18n: VueI18n, cleardb = false) { + return Promise.all([ + cleardb ? clear(clientDb.i18n) : Promise.resolve(), + fetch(`/assets/locales/${lang}.${version}.json`) + ]) + .then(([, response]) => response.json()) + .then(locale => { + const flatLocaleEntries = deepEntries(locale, delimitEntry) as [string, string][]; + bulkSet(flatLocaleEntries, clientDb.i18n); + i18n.locale = lang; + i18n.setLocaleMessage(lang, fromEntries(flatLocaleEntries)); + }); +} diff --git a/src/client/sw.js b/src/client/sw.ts similarity index 88% rename from src/client/sw.js rename to src/client/sw.ts index 68e43429ac04be6b4ec319aeb8430f4a69c96db6..341198852e4015838ddb61d60923b4a8604325ab 100644 --- a/src/client/sw.js +++ b/src/client/sw.ts @@ -1,6 +1,7 @@ /** * Service Worker */ +declare var self: ServiceWorkerGlobalScope; import composeNotification from './scripts/compose-notification'; @@ -14,7 +15,7 @@ const apiUrl = `${location.origin}/api/`; self.addEventListener('install', ev => { console.info('installed'); - ev.waitUntil( + ev.waitUntil( caches.open(cacheName) .then(cache => { return cache.addAll([ @@ -22,7 +23,7 @@ self.addEventListener('install', ev => { ]); }) .then(() => self.skipWaiting()) - ); + ); }); self.addEventListener('activate', ev => { @@ -55,16 +56,12 @@ self.addEventListener('push', ev => { // クライアントå–å¾— ev.waitUntil(self.clients.matchAll({ includeUncontrolled: true - }).then(clients => { + }).then(async clients => { // クライアントãŒã‚ã£ãŸã‚‰ã‚¹ãƒˆãƒªãƒ¼ãƒ ã«æŽ¥ç¶šã—ã¦ã„ã‚‹ã¨ã„ã†ã“ã¨ãªã®ã§é€šçŸ¥ã—ãªã„ if (clients.length != 0) return; const { type, body } = ev.data.json(); - const n = composeNotification(type, body); - return self.registration.showNotification(n.title, { - body: n.body, - icon: n.icon, - }); + return self.registration.showNotification(...(await composeNotification(type, body))); })); }); diff --git a/src/client/tsconfig.json b/src/client/tsconfig.json index 3ec0271f63af9da39401a1910484dff4bbfeba7e..aac0d1bfe7a30a01776c8c0bbdd3f81fb0c35261 100644 --- a/src/client/tsconfig.json +++ b/src/client/tsconfig.json @@ -21,6 +21,11 @@ "typeRoots": [ "node_modules/@types", "src/@types" + ], + "lib": [ + "esnext", + "dom", + "webworker" ] }, "compileOnSave": false, diff --git a/src/client/widgets/activity.chart.vue b/src/client/widgets/activity.chart.vue index 0278e02ae751f7dfcab1c543e4fc56e36c164f17..2b70493552ea78810db5059f7fd59090ff0462b8 100644 --- a/src/client/widgets/activity.chart.vue +++ b/src/client/widgets/activity.chart.vue @@ -26,7 +26,6 @@ <script lang="ts"> import Vue from 'vue'; -import i18n from '../i18n'; function dragListen(fn) { window.addEventListener('mousemove', fn); @@ -41,7 +40,6 @@ function dragClear(fn) { } export default Vue.extend({ - i18n, props: ['data'], data() { return { diff --git a/src/client/widgets/activity.vue b/src/client/widgets/activity.vue index 6c32642bb675837ea24651ac1a4a7bb61064e651..4fdd81ae52e06da8cc7a4b383f692011406af8e5 100644 --- a/src/client/widgets/activity.vue +++ b/src/client/widgets/activity.vue @@ -19,7 +19,6 @@ import { faChartBar, faSort } from '@fortawesome/free-solid-svg-icons'; import MkContainer from '../components/ui/container.vue'; import define from './define'; -import i18n from '../i18n'; import XCalendar from './activity.calendar.vue'; import XChart from './activity.chart.vue'; @@ -30,7 +29,6 @@ export default define({ view: 0 }) }).extend({ - i18n, components: { MkContainer, XCalendar, diff --git a/src/client/widgets/calendar.vue b/src/client/widgets/calendar.vue index c041734a4dabfb20ccca565b207352bdb8ca796a..328e6bc62f0307e110c9f8d9ddf215a508d482c9 100644 --- a/src/client/widgets/calendar.vue +++ b/src/client/widgets/calendar.vue @@ -33,7 +33,6 @@ <script lang="ts"> import define from './define'; -import i18n from '../i18n'; export default define({ name: 'calendar', @@ -41,7 +40,6 @@ export default define({ design: 0 }) }).extend({ - i18n, data() { return { now: new Date(), diff --git a/src/client/widgets/memo.vue b/src/client/widgets/memo.vue index 3c170adc4ee774f6315766dca37aeab25565fc8a..cdc716b9fadd082d50b837c347f9a73092b27bf6 100644 --- a/src/client/widgets/memo.vue +++ b/src/client/widgets/memo.vue @@ -15,7 +15,6 @@ import { faStickyNote } from '@fortawesome/free-solid-svg-icons'; import MkContainer from '../components/ui/container.vue'; import define from './define'; -import i18n from '../i18n'; export default define({ name: 'memo', @@ -23,7 +22,6 @@ export default define({ compact: false }) }).extend({ - i18n, components: { MkContainer diff --git a/src/client/widgets/notifications.vue b/src/client/widgets/notifications.vue index 9c1bddb2ee29bf2cbf37c6fc7e4990411c38c21b..39fc8a9361cc3c1dcbcb0eaabe5dafa57d9e38e1 100644 --- a/src/client/widgets/notifications.vue +++ b/src/client/widgets/notifications.vue @@ -15,7 +15,6 @@ import { faBell } from '@fortawesome/free-solid-svg-icons'; import MkContainer from '../components/ui/container.vue'; import XNotifications from '../components/notifications.vue'; import define from './define'; -import i18n from '../i18n'; const basisSteps = [25, 50, 75, 100] const previewHeights = [200, 300, 400, 500] @@ -27,7 +26,6 @@ export default define({ basisStep: 0 }) }).extend({ - i18n, components: { MkContainer, diff --git a/src/client/widgets/photos.vue b/src/client/widgets/photos.vue index 1deb6de62dbf60df030a69867f549331f8985d7a..6e4e43a56507c13e02c175c566f87f9fc1eb191c 100644 --- a/src/client/widgets/photos.vue +++ b/src/client/widgets/photos.vue @@ -20,7 +20,6 @@ import { faCamera } from '@fortawesome/free-solid-svg-icons'; import MkContainer from '../components/ui/container.vue'; import define from './define'; -import i18n from '../i18n'; import { getStaticImageUrl } from '../scripts/get-static-image-url'; export default define({ @@ -29,7 +28,6 @@ export default define({ design: 0, }) }).extend({ - i18n, components: { MkContainer, }, diff --git a/src/client/widgets/rss.vue b/src/client/widgets/rss.vue index 61c1e23b6e1b32b9506685144470e3b47220c7c6..4e57281e9ff212ae4a275c38a55a54576e658020 100644 --- a/src/client/widgets/rss.vue +++ b/src/client/widgets/rss.vue @@ -18,7 +18,6 @@ import { faRssSquare, faCog } from '@fortawesome/free-solid-svg-icons'; import MkContainer from '../components/ui/container.vue'; import define from './define'; -import i18n from '../i18n'; export default define({ name: 'rss', @@ -27,7 +26,6 @@ export default define({ url: 'http://feeds.afpbb.com/rss/afpbb/afpbbnews' }) }).extend({ - i18n, components: { MkContainer }, diff --git a/src/client/widgets/timeline.vue b/src/client/widgets/timeline.vue index 55f78f985f24752d1a832cb70b7b4802a101d650..633131182802d4c6f9d30adbe74e9dfe2d2f0209 100644 --- a/src/client/widgets/timeline.vue +++ b/src/client/widgets/timeline.vue @@ -27,7 +27,6 @@ import { faComments } from '@fortawesome/free-regular-svg-icons'; import MkContainer from '../components/ui/container.vue'; import XTimeline from '../components/timeline.vue'; import define from './define'; -import i18n from '../i18n'; const basisSteps = [25, 50, 75, 100] const previewHeights = [200, 300, 400, 500] @@ -41,7 +40,6 @@ export default define({ basisStep: 0 }) }).extend({ - i18n, components: { MkContainer, diff --git a/src/client/widgets/trends.vue b/src/client/widgets/trends.vue index 690383d1f9607a39137ca292cb46d3581a84448e..61f5bfbd32528d8fb3b7ba87507d86cc3205c569 100644 --- a/src/client/widgets/trends.vue +++ b/src/client/widgets/trends.vue @@ -23,7 +23,6 @@ import { faHashtag } from '@fortawesome/free-solid-svg-icons'; import MkContainer from '../components/ui/container.vue'; import define from './define'; -import i18n from '../i18n'; import XChart from './trends.chart.vue'; export default define({ @@ -32,7 +31,6 @@ export default define({ compact: false }) }).extend({ - i18n, components: { MkContainer, XChart }, diff --git a/src/misc/get-note-summary.ts b/src/misc/get-note-summary.ts index e3458cb189e3fc191d7cc6bac996e923ce475e18..c23306ab1125a608b0532405c66f2d33ccfaddc9 100644 --- a/src/misc/get-note-summary.ts +++ b/src/misc/get-note-summary.ts @@ -2,13 +2,13 @@ * 投稿を表ã™æ–‡å—列をå–å¾—ã—ã¾ã™ã€‚ * @param {*} note (packã•ã‚ŒãŸ)投稿 */ -const summarize = (note: any): string => { +const summarize = (note: any, locale: any): string => { if (note.deletedAt) { - return '(削除ã•ã‚ŒãŸæŠ•ç¨¿)'; + return `(${locale['deletedNote']})`; } if (note.isHidden) { - return '(éžå…¬é–‹ã®æŠ•ç¨¿)'; + return `(${locale['invisibleNote']})`; } let summary = ''; @@ -22,18 +22,18 @@ const summarize = (note: any): string => { // ファイルãŒæ·»ä»˜ã•ã‚Œã¦ã„ã‚‹ã¨ã if ((note.files || []).length != 0) { - summary += ` (${note.files.length}ã¤ã®ãƒ•ã‚¡ã‚¤ãƒ«)`; + summary += ` (${locale['withNFiles'].replace('{n}', note.files.length)})`; } // 投票ãŒæ·»ä»˜ã•ã‚Œã¦ã„ã‚‹ã¨ã if (note.poll) { - summary += ' (投票)'; + summary += ` (${locale._cw?.poll || locale['_cw.poll']})`; } // 返信ã®ã¨ã if (note.replyId) { if (note.reply) { - summary += `\n\nRE: ${summarize(note.reply)}`; + summary += `\n\nRE: ${summarize(note.reply, locale)}`; } else { summary += '\n\nRE: ...'; } @@ -42,7 +42,7 @@ const summarize = (note: any): string => { // Renoteã®ã¨ã if (note.renoteId) { if (note.renote) { - summary += `\n\nRN: ${summarize(note.renote)}`; + summary += `\n\nRN: ${summarize(note.renote, locale)}`; } else { summary += '\n\nRN: ...'; } diff --git a/src/prelude/array.ts b/src/prelude/array.ts index f4d684d57430eb15c7f7dea87c7e7a72fbcad576..9e1dfead53564906472c377d47a286aedfff726d 100644 --- a/src/prelude/array.ts +++ b/src/prelude/array.ts @@ -130,7 +130,17 @@ export function cumulativeSum(xs: number[]): number[] { } // Object.fromEntries() -export function fromEntries(xs: [string, any][]): { [x: string]: any; } { +export function fromEntries<T extends readonly (readonly [PropertyKey, any])[]>(xs: T): + T[number] extends infer U + ? + ( + U extends readonly any[] + ? (x: { [_ in U[0]]: U[1] }) => any + : never + ) extends (x: infer V) => any + ? V + : never + : never { return xs.reduce((obj, [k, v]) => Object.assign(obj, { [k]: v }), {} as { [x: string]: any; }); } diff --git a/src/server/web/index.ts b/src/server/web/index.ts index 3da86944d798a0b486f18e3b44f39ad4f10e6156..5bb052a693fe3cec568f26dadc15b4874595ca5e 100644 --- a/src/server/web/index.ts +++ b/src/server/web/index.ts @@ -245,7 +245,8 @@ router.get('/notes/:note', async ctx => { const meta = await fetchMeta(); await ctx.render('note', { note: _note, - summary: getNoteSummary(_note), + // TODO: Let locale changeable by instance setting + summary: getNoteSummary(_note, locales['ja-JP']), instanceName: meta.name || 'Misskey', icon: meta.iconUrl }); diff --git a/src/server/web/views/flush.pug b/src/server/web/views/flush.pug index f279c236051a16ddfc15e7935783f4f7b962d08a..59fed1f15de77944725eb5cacff55cfd2b681beb 100644 --- a/src/server/web/views/flush.pug +++ b/src/server/web/views/flush.pug @@ -1,20 +1,38 @@ doctype html html + #msg script. - localStorage.removeItem('locale'); + const msg = document.getElementById('msg'); try { - navigator.serviceWorker.controller.postMessage('clear'); + localStorage.clear(); + message('localStorage cleared'); - navigator.serviceWorker.getRegistrations().then(registrations => { - return Promise.all(registrations.map(registration => registration.unregister())); - }).then(() => { - location = '/'; - }); + const delidb = indexedDB.deleteDatabase('MisskeyClient'); + delidb.onsuccess = () => message('indexedDB cleared'); + + if (navigator.serviceWorker.controller) { + navigator.serviceWorker.controller.postMessage('clear'); + navigator.serviceWorker.getRegistrations() + .then(registrations => { + return Promise.all(registrations.map(registration => registration.unregister())); + }) + .then(() => { + message('Success Flush! Please reopen Misskey.\næˆåŠŸã—ã¾ã—ãŸã€‚Misskeyã‚’é–‹ãç›´ã—ã¦ãã ã•ã„。'); + }) + .catch(e => { throw Error(e) }); + } else { + message('Success Flush! Please reopen Misskey.\næˆåŠŸã—ã¾ã—ãŸã€‚Misskeyã‚’é–‹ãç›´ã—ã¦ãã ã•ã„。'); + } } catch (e) { console.error(e); + message(`${e}Â¥nÂ¥nFlush Failed. Please reopen Misskey.\n失敗ã—ã¾ã—ãŸã€‚Misskeyã‚’é–‹ãç›´ã—ã¦ãã ã•ã„。`); setTimeout(() => { location = '/'; }, 10000) } + + function message(text) { + msg.insertAdjacentHTML('beforeend', `<p>[${(new Date()).toString()}] ${text.replace(/Â¥n/g,'<br>')}</p>`) + } diff --git a/src/services/push-notification.ts b/src/services/push-notification.ts index f0d9c4e22ccb7edd6f3e1dfec7d9966cc172be66..d0a0c04d62f0eeff73d0577a3ae9e3f74750906c 100644 --- a/src/services/push-notification.ts +++ b/src/services/push-notification.ts @@ -2,8 +2,13 @@ import * as push from 'web-push'; import config from '../config'; import { SwSubscriptions } from '../models'; import { fetchMeta } from '../misc/fetch-meta'; +import { PackedNotification } from '../models/repositories/notification'; +import { PackedMessagingMessage } from '../models/repositories/messaging-message'; -export default async function(userId: string, type: string, body?: any) { +type notificationType = 'notification' | 'unreadMessagingMessage'; +type notificationBody = PackedNotification | PackedMessagingMessage; + +export default async function(userId: string, type: notificationType, body: notificationBody) { const meta = await fetchMeta(); if (!meta.enableServiceWorker || meta.swPublicKey == null || meta.swPrivateKey == null) return; diff --git a/webpack.config.ts b/webpack.config.ts index 64cf4c858151db69360d90bfcbe9843b14b5d66a..fa364e603af94a9f4fbe404d7c09bd190a70cc08 100644 --- a/webpack.config.ts +++ b/webpack.config.ts @@ -34,7 +34,7 @@ const postcss = { module.exports = { entry: { app: './src/client/init.ts', - sw: './src/client/sw.js' + sw: './src/client/sw.ts' }, module: { rules: [{ diff --git a/yarn.lock b/yarn.lock index c10ddb19c2176c85150101fa5fb1808e7140d525..4ea29f672567ee6f431d0bd17f89712ade32c29d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2819,6 +2819,11 @@ decompress-response@^4.2.0: dependencies: mimic-response "^2.0.0" +deep-entries@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/deep-entries/-/deep-entries-3.1.0.tgz#e456aa791d01b045641c75e41e170c0c95a9d472" + integrity sha512-pCpcCqx/hclnT2e4mMlM9geG8XIaxWN+yNKJHHwu1FZyYKErKU/fPztYYSk2HwnqRPf55cDEXraV6MLv8I5FrA== + deep-eql@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df" @@ -4488,6 +4493,11 @@ icss-utils@^4.0.0, icss-utils@^4.1.1: dependencies: postcss "^7.0.14" +idb-keyval@3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/idb-keyval/-/idb-keyval-3.2.0.tgz#cbbf354deb5684b6cdc84376294fc05932845bd6" + integrity sha512-slx8Q6oywCCSfKgPgL0sEsXtPVnSbTLWpyiDcu6msHOyKOLari1TD1qocXVCft80umnkk3/Qqh3lwoFt8T/BPQ== + ieee754@1.1.13, ieee754@^1.1.13, ieee754@^1.1.4: version "1.1.13" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84"