diff --git a/CHANGELOG.md b/CHANGELOG.md
index 21bf164e58..81981e8ae5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,13 @@
 You should also include the user name that made the change.
 -->
 
+## 12.106.2 (2022/02/11)
+
+### Bugfixes
+- クライアント: 削除したノートがタイムラインから自動で消えない問題を修正 @syuilo
+- クライアント: リアクション数が正しくないことがある問題を修正 @syuilo
+- 一部環境でマイグレーションが動作しない問題を修正 @syuilo
+
 ## 12.106.1 (2022/02/11)
 
 ### Bugfixes
diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml
index 568470c7b2..86d3fb5cdd 100644
--- a/locales/zh-CN.yml
+++ b/locales/zh-CN.yml
@@ -831,6 +831,8 @@ smartphone: "智能手机"
 tablet: "平板"
 auto: "自动"
 themeColor: "主题颜色"
+size: "大小"
+numberOfColumn: "列数"
 _emailUnavailable:
   used: "已经被使用过"
   format: "无效的格式"
@@ -958,7 +960,7 @@ _mfm:
   rotateDescription: "旋转指定的角度。"
 _instanceTicker:
   none: "不显示"
-  remote: "显示给远程用户"
+  remote: "仅显示远程用户的"
   always: "始终显示"
 _serverDisconnectedBehavior:
   reload: "自动重载"
diff --git a/package.json b/package.json
index 964aff2cfe..dbf3f2e008 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
 	"name": "misskey",
-	"version": "12.106.1",
+	"version": "12.106.2",
 	"codename": "indigo",
 	"repository": {
 		"type": "git",
diff --git a/packages/backend/migration/1644010796173-convert-hard-mutes.js b/packages/backend/migration/1644010796173-convert-hard-mutes.js
index f06da65670..6169cb0144 100644
--- a/packages/backend/migration/1644010796173-convert-hard-mutes.js
+++ b/packages/backend/migration/1644010796173-convert-hard-mutes.js
@@ -5,10 +5,11 @@ module.exports = class convertHardMutes1644010796173 {
     name = 'convertHardMutes1644010796173'
 
     async up(queryRunner) {
-        let entries = await queryRunner.query(`SELECT "userId", "mutedWords" FROM "user_profile"`);
+        let entries = await queryRunner.query(`SELECT "userId", "mutedWords" FROM "user_profile" WHERE "userHost" IS NULL`);
         for(let i = 0; i < entries.length; i++) {
             let words = entries[i].mutedWords
                 .map(line => {
+										if (typeof line === 'string') return [];
                     const regexp = line.join(" ").match(/^\/(.+)\/(.*)$/);
                     if (regexp) {
                         // convert regexp's
diff --git a/packages/client/src/components/note.vue b/packages/client/src/components/note.vue
index 6c596fb60d..7cf5fb0474 100644
--- a/packages/client/src/components/note.vue
+++ b/packages/client/src/components/note.vue
@@ -138,11 +138,13 @@ const props = defineProps<{
 
 const inChannel = inject('inChannel', null);
 
+const note = $ref(JSON.parse(JSON.stringify(props.note)));
+
 const isRenote = (
-	props.note.renote != null &&
-	props.note.text == null &&
-	props.note.fileIds.length === 0 &&
-	props.note.poll == null
+	note.renote != null &&
+	note.text == null &&
+	note.fileIds.length === 0 &&
+	note.poll == null
 );
 
 const el = ref<HTMLElement>();
@@ -150,8 +152,8 @@ const menuButton = ref<HTMLElement>();
 const renoteButton = ref<InstanceType<typeof XRenoteButton>>();
 const renoteTime = ref<HTMLElement>();
 const reactButton = ref<HTMLElement>();
-let appearNote = $ref(isRenote ? props.note.renote as misskey.entities.Note : props.note);
-const isMyRenote = $i && ($i.id === props.note.userId);
+let appearNote = $ref(isRenote ? note.renote as misskey.entities.Note : note);
+const isMyRenote = $i && ($i.id === note.userId);
 const showContent = ref(false);
 const collapsed = ref(appearNote.cw == null && appearNote.text != null && (
 	(appearNote.text.split('\n').length > 9) ||
@@ -176,8 +178,9 @@ const keymap = {
 };
 
 useNoteCapture({
-	appearNote: $$(appearNote),
 	rootEl: el,
+	note: $$(appearNote),
+	isDeletedRef: $$(isDeleted),
 });
 
 function reply(viaKeyboard = false): void {
@@ -225,12 +228,12 @@ function onContextmenu(ev: MouseEvent): void {
 		ev.preventDefault();
 		react();
 	} else {
-		os.contextMenu(getNoteMenu({ note: props.note, translating, translation, menuButton }), ev).then(focus);
+		os.contextMenu(getNoteMenu({ note: note, translating, translation, menuButton }), ev).then(focus);
 	}
 }
 
 function menu(viaKeyboard = false): void {
-	os.popupMenu(getNoteMenu({ note: props.note, translating, translation, menuButton }), menuButton.value, {
+	os.popupMenu(getNoteMenu({ note: note, translating, translation, menuButton }), menuButton.value, {
 		viaKeyboard
 	}).then(focus);
 }
@@ -243,7 +246,7 @@ function showRenoteMenu(viaKeyboard = false): void {
 		danger: true,
 		action: () => {
 			os.api('notes/delete', {
-				noteId: props.note.id
+				noteId: note.id
 			});
 			isDeleted.value = true;
 		}
diff --git a/packages/client/src/scripts/use-note-capture.ts b/packages/client/src/scripts/use-note-capture.ts
index b7cf99d5e1..b2a96062c7 100644
--- a/packages/client/src/scripts/use-note-capture.ts
+++ b/packages/client/src/scripts/use-note-capture.ts
@@ -5,34 +5,35 @@ import { $i } from '@/account';
 
 export function useNoteCapture(props: {
 	rootEl: Ref<HTMLElement>;
-	appearNote: Ref<misskey.entities.Note>;
+	note: Ref<misskey.entities.Note>;
+	isDeletedRef: Ref<boolean>;
 }) {
-	const appearNote = props.appearNote;
+	const note = props.note;
 	const connection = $i ? stream : null;
 
 	function onStreamNoteUpdated(data): void {
 		const { type, id, body } = data;
 
-		if (id !== appearNote.value.id) return;
+		if (id !== note.value.id) return;
 
 		switch (type) {
 			case 'reacted': {
 				const reaction = body.reaction;
 
 				if (body.emoji) {
-					const emojis = appearNote.value.emojis || [];
+					const emojis = note.value.emojis || [];
 					if (!emojis.includes(body.emoji)) {
-						appearNote.value.emojis = [...emojis, body.emoji];
+						note.value.emojis = [...emojis, body.emoji];
 					}
 				}
 
 				// TODO: reactionsプロパティがない場合ってあったっけ? なければ || {} は消せる
-				const currentCount = (appearNote.value.reactions || {})[reaction] || 0;
+				const currentCount = (note.value.reactions || {})[reaction] || 0;
 
-				appearNote.value.reactions[reaction] = currentCount + 1;
+				note.value.reactions[reaction] = currentCount + 1;
 
 				if ($i && (body.userId === $i.id)) {
-					appearNote.value.myReaction = reaction;
+					note.value.myReaction = reaction;
 				}
 				break;
 			}
@@ -41,12 +42,12 @@ export function useNoteCapture(props: {
 				const reaction = body.reaction;
 
 				// TODO: reactionsプロパティがない場合ってあったっけ? なければ || {} は消せる
-				const currentCount = (appearNote.value.reactions || {})[reaction] || 0;
+				const currentCount = (note.value.reactions || {})[reaction] || 0;
 
-				appearNote.value.reactions[reaction] = Math.max(0, currentCount - 1);
+				note.value.reactions[reaction] = Math.max(0, currentCount - 1);
 
 				if ($i && (body.userId === $i.id)) {
-					appearNote.value.myReaction = null;
+					note.value.myReaction = null;
 				}
 				break;
 			}
@@ -54,7 +55,7 @@ export function useNoteCapture(props: {
 			case 'pollVoted': {
 				const choice = body.choice;
 
-				const choices = [...appearNote.value.poll.choices];
+				const choices = [...note.value.poll.choices];
 				choices[choice] = {
 					...choices[choice],
 					votes: choices[choice].votes + 1,
@@ -63,12 +64,12 @@ export function useNoteCapture(props: {
 					} : {})
 				};
 
-				appearNote.value.poll.choices = choices;
+				note.value.poll.choices = choices;
 				break;
 			}
 
 			case 'deleted': {
-				appearNote.value.deletedAt = new Date();
+				props.isDeletedRef.value = true;
 				break;
 			}
 		}
@@ -77,7 +78,7 @@ export function useNoteCapture(props: {
 	function capture(withHandler = false): void {
 		if (connection) {
 			// TODO: このノートがストリーミング経由で流れてきた場合のみ sr する
-			connection.send(document.body.contains(props.rootEl.value) ? 'sr' : 's', { id: appearNote.value.id });
+			connection.send(document.body.contains(props.rootEl.value) ? 'sr' : 's', { id: note.value.id });
 			if (withHandler) connection.on('noteUpdated', onStreamNoteUpdated);
 		}
 	}
@@ -85,7 +86,7 @@ export function useNoteCapture(props: {
 	function decapture(withHandler = false): void {
 		if (connection) {
 			connection.send('un', {
-				id: appearNote.value.id,
+				id: note.value.id,
 			});
 			if (withHandler) connection.off('noteUpdated', onStreamNoteUpdated);
 		}