diff --git a/packages/client/src/pages/settings/sounds.vue b/packages/client/src/pages/settings/sounds.vue
index 490a1b551459f439a71ddaced33beaa4788ac32b..d01e87c1f82fa6588c8ae86e1186d53204ace54f 100644
--- a/packages/client/src/pages/settings/sounds.vue
+++ b/packages/client/src/pages/settings/sounds.vue
@@ -1,24 +1,24 @@
 <template>
 <div class="_formRoot">
 	<FormRange v-model="masterVolume" :min="0" :max="1" :step="0.05" :text-converter="(v) => `${Math.floor(v * 100)}%`" class="_formBlock">
-		<template #label>{{ $ts.masterVolume }}</template>
+		<template #label>{{ i18n.ts.masterVolume }}</template>
 	</FormRange>
 
 	<FormSection>
-		<template #label>{{ $ts.sounds }}</template>
+		<template #label>{{ i18n.ts.sounds }}</template>
 		<FormLink v-for="type in Object.keys(sounds)" :key="type" style="margin-bottom: 8px;" @click="edit(type)">
 			{{ $t('_sfx.' + type) }}
-			<template #suffix>{{ sounds[type].type || $ts.none }}</template>
+			<template #suffix>{{ sounds[type].type || i18n.ts.none }}</template>
 			<template #suffixIcon><i class="fas fa-chevron-down"></i></template>
 		</FormLink>
 	</FormSection>
 
-	<FormButton danger class="_formBlock" @click="reset()"><i class="fas fa-redo"></i> {{ $ts.default }}</FormButton>
+	<FormButton danger class="_formBlock" @click="reset()"><i class="fas fa-redo"></i> {{ i18n.ts.default }}</FormButton>
 </div>
 </template>
 
-<script lang="ts">
-import { defineComponent } from 'vue';
+<script lang="ts" setup>
+import { computed, defineExpose, ref } from 'vue';
 import FormRange from '@/components/form/range.vue';
 import FormButton from '@/components/ui/button.vue';
 import FormLink from '@/components/form/link.vue';
@@ -27,6 +27,28 @@ import * as os from '@/os';
 import { ColdDeviceStorage } from '@/store';
 import { playFile } from '@/scripts/sound';
 import * as symbols from '@/symbols';
+import { i18n } from '@/i18n';
+
+const masterVolume = computed({
+	get: () => {
+		return ColdDeviceStorage.get('sound_masterVolume');
+	},
+	set: (value) => {
+		ColdDeviceStorage.set('sound_masterVolume', value);
+	}
+});
+
+const volumeIcon = computed(() => masterVolume.value === 0 ? 'fas fa-volume-mute' : 'fas fa-volume-up');
+
+const sounds = ref({
+    note: ColdDeviceStorage.get('sound_note'),
+    noteMy: ColdDeviceStorage.get('sound_noteMy'),
+    notification: ColdDeviceStorage.get('sound_notification'),
+    chat: ColdDeviceStorage.get('sound_chat'),
+    chatBg: ColdDeviceStorage.get('sound_chatBg'),
+    antenna: ColdDeviceStorage.get('sound_antenna'),
+    channel: ColdDeviceStorage.get('sound_channel'),
+});
 
 const soundsTypes = [
 	null,
@@ -55,94 +77,58 @@ const soundsTypes = [
 	'noizenecio/kick_gaba2',
 ];
 
-export default defineComponent({
-	components: {
-		FormLink,
-		FormButton,
-		FormRange,
-		FormSection,
-	},
-
-	emits: ['info'],
-
-	data() {
-		return {
-			[symbols.PAGE_INFO]: {
-				title: this.$ts.sounds,
-				icon: 'fas fa-music',
-				bg: 'var(--bg)',
-			},
-			sounds: {},
-		}
-	},
-
-	computed: {
-		masterVolume: { // TODO: (外部)関数にcomputedを使うのはアレなので直す
-			get() { return ColdDeviceStorage.get('sound_masterVolume'); },
-			set(value) { ColdDeviceStorage.set('sound_masterVolume', value); }
+async function edit(type) {
+	const { canceled, result } = await os.form(i18n.t('_sfx.' + type), {
+		type: {
+			type: 'enum',
+			enum: soundsTypes.map(x => ({
+				value: x,
+				label: x == null ? i18n.ts.none : x,
+			})),
+			label: i18n.ts.sound,
+			default: sounds.value[type].type,
+		},
+		volume: {
+			type: 'range',
+			mim: 0,
+			max: 1,
+			step: 0.05,
+			textConverter: (v) => `${Math.floor(v * 100)}%`,
+			label: i18n.ts.volume,
+			default: sounds.value[type].volume
 		},
-		volumeIcon() {
-			return this.masterVolume === 0 ? 'fas fa-volume-mute' : 'fas fa-volume-up';
+		listen: {
+			type: 'button',
+			content: i18n.ts.listen,
+			action: (_, values) => {
+				playFile(values.type, values.volume);
+			}
 		}
-	},
+	});
+	if (canceled) return;
 
-	created() {
-		this.sounds.note = ColdDeviceStorage.get('sound_note');
-		this.sounds.noteMy = ColdDeviceStorage.get('sound_noteMy');
-		this.sounds.notification = ColdDeviceStorage.get('sound_notification');
-		this.sounds.chat = ColdDeviceStorage.get('sound_chat');
-		this.sounds.chatBg = ColdDeviceStorage.get('sound_chatBg');
-		this.sounds.antenna = ColdDeviceStorage.get('sound_antenna');
-		this.sounds.channel = ColdDeviceStorage.get('sound_channel');
-	},
+	const v = {
+		type: result.type,
+		volume: result.volume,
+	};
 
-	methods: {
-		async edit(type) {
-			const { canceled, result } = await os.form(this.$t('_sfx.' + type), {
-				type: {
-					type: 'enum',
-					enum: soundsTypes.map(x => ({
-						value: x,
-						label: x == null ? this.$ts.none : x,
-					})),
-					label: this.$ts.sound,
-					default: this.sounds[type].type,
-				},
-				volume: {
-					type: 'range',
-					mim: 0,
-					max: 1,
-					step: 0.05,
-					textConverter: (v) => `${Math.floor(v * 100)}%`,
-					label: this.$ts.volume,
-					default: this.sounds[type].volume
-				},
-				listen: {
-					type: 'button',
-					content: this.$ts.listen,
-					action: (_, values) => {
-						playFile(values.type, values.volume);
-					}
-				}
-			});
-			if (canceled) return;
+	ColdDeviceStorage.set('sound_' + type, v);
+	sounds.value[type] = v;
+}
 
-			const v = {
-				type: result.type,
-				volume: result.volume,
-			};
-
-			ColdDeviceStorage.set('sound_' + type, v);
-			this.sounds[type] = v;
-		},
+function reset() {
+	for (const sound of Object.keys(sounds.value)) {
+		const v = ColdDeviceStorage.default['sound_' + sound];
+		ColdDeviceStorage.set('sound_' + sound, v);
+		sounds.value[sound] = v;
+	}
+}
 
-		reset() {
-			for (const sound of Object.keys(this.sounds)) {
-				const v = ColdDeviceStorage.default['sound_' + sound];
-				ColdDeviceStorage.set('sound_' + sound, v);
-				this.sounds[sound] = v;
-			}
-		}
+defineExpose({
+	[symbols.PAGE_INFO]: {
+		title: i18n.ts.sounds,
+		icon: 'fas fa-music',
+		bg: 'var(--bg)',
 	}
 });
 </script>