From 4285303c8155dd91be7dcbb865d5e8f7cb0e1c71 Mon Sep 17 00:00:00 2001
From: かっこかり <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Tue, 30 Dec 2025 14:32:40 +0900
Subject: fix(frontend): follow-up of #17033 (#17047)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* wip

* fix

* ref -> reactive

* tweak throttle threshold

* tweak throttle threshold

* rss設定にはmanualSaveを使用するように

* Update MkWidgetSettingsDialog.vue

---------

Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
---
 packages/frontend/src/widgets/WidgetRssTicker.vue | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

(limited to 'packages/frontend/src/widgets/WidgetRssTicker.vue')

diff --git a/packages/frontend/src/widgets/WidgetRssTicker.vue b/packages/frontend/src/widgets/WidgetRssTicker.vue
index 95f82f7d7b..b0d9eec883 100644
--- a/packages/frontend/src/widgets/WidgetRssTicker.vue
+++ b/packages/frontend/src/widgets/WidgetRssTicker.vue
@@ -44,6 +44,7 @@ const widgetPropsDef = {
 	url: {
 		type: 'string',
 		default: 'http://feeds.afpbb.com/rss/afpbb/afpbbnews',
+		manualSave: true,
 	},
 	shuffle: {
 		type: 'boolean',
@@ -119,7 +120,7 @@ const tick = () => {
 		});
 };
 
-watch(() => fetchEndpoint, tick);
+watch(fetchEndpoint, tick);
 watch(() => widgetProps.refreshIntervalSec, () => {
 	if (intervalClear.value) {
 		intervalClear.value();
-- 
cgit v1.2.3-freya


From 97d485bdd279b1756b99937edcac6866673aa1c7 Mon Sep 17 00:00:00 2001
From: かっこかり <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Tue, 30 Dec 2025 15:59:18 +0900
Subject: enhance(frontend): ウィジェットの設定項目の多言語対応 (#17032)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* enhance(frontend): ウィジェットの設定項目の多言語対応

* Update Changelog

* refactor: move options locale key to root for optimizing artifacts for locale inlining

* fix

* fix

* ✌️

---------

Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
---
 CHANGELOG.md                                       |   1 +
 locales/ja-JP.yml                                  |  37 ++++++
 packages/frontend/src/widgets/WidgetActivity.vue   |   2 +
 packages/frontend/src/widgets/WidgetAichan.vue     |   2 +
 packages/frontend/src/widgets/WidgetAiscript.vue   |   2 +
 .../frontend/src/widgets/WidgetAiscriptApp.vue     |   3 +
 .../src/widgets/WidgetBirthdayFollowings.vue       |   3 +-
 packages/frontend/src/widgets/WidgetButton.vue     |   4 +
 packages/frontend/src/widgets/WidgetCalendar.vue   |   1 +
 packages/frontend/src/widgets/WidgetChat.vue       |   1 +
 packages/frontend/src/widgets/WidgetClicker.vue    |   2 +
 packages/frontend/src/widgets/WidgetClock.vue      |  42 ++++---
 .../frontend/src/widgets/WidgetDigitalClock.vue    |   8 +-
 packages/frontend/src/widgets/WidgetFederation.vue |   1 +
 .../frontend/src/widgets/WidgetInstanceCloud.vue   |   2 +
 packages/frontend/src/widgets/WidgetJobQueue.vue   |   3 +
 packages/frontend/src/widgets/WidgetMemo.vue       |   2 +
 .../frontend/src/widgets/WidgetNotifications.vue   |   2 +
 .../frontend/src/widgets/WidgetOnlineUsers.vue     |   1 +
 packages/frontend/src/widgets/WidgetPhotos.vue     |   2 +
 packages/frontend/src/widgets/WidgetRss.vue        |   5 +
 packages/frontend/src/widgets/WidgetRssTicker.vue  |   9 ++
 packages/frontend/src/widgets/WidgetSlideshow.vue  |   1 +
 packages/frontend/src/widgets/WidgetTrends.vue     |   1 +
 packages/frontend/src/widgets/WidgetUnixClock.vue  |   5 +
 packages/frontend/src/widgets/WidgetUserList.vue   |   1 +
 .../frontend/src/widgets/server-metric/index.vue   |   2 +
 packages/frontend/src/widgets/widget.ts            |   3 +-
 packages/i18n/src/autogen/locale.ts                | 132 +++++++++++++++++++++
 29 files changed, 262 insertions(+), 18 deletions(-)

(limited to 'packages/frontend/src/widgets/WidgetRssTicker.vue')

diff --git a/CHANGELOG.md b/CHANGELOG.md
index fc89b3d727..c6b374360c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,7 @@
 ### Client
 - Enhance: ドライブのファイル一覧で自動でもっと見るを利用可能に
 - Enhance: ウィジェットの表示設定をプレビューを見ながら行えるように
+- Enhance: ウィジェットの設定項目のラベルの多言語対応
 - Fix: ドライブクリーナーでファイルを削除しても画面に反映されない問題を修正 #16061
 
 ### Server
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 01e5101255..a6edca0b98 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -2603,6 +2603,43 @@ _widgets:
   birthdayFollowings: "今日誕生日のユーザー"
   chat: "ダイレクトメッセージ"
 
+_widgetOptions:
+  showHeader: "ヘッダーを表示"
+  transparent: "背景を透明にする"
+  height: "高さ"
+  _button:
+    colored: "色付き"
+  _clock:
+    size: "サイズ"
+    thickness: "針の太さ"
+    thicknessThin: "細い"
+    thicknessMedium: "普通"
+    thicknessThick: "太い"
+    graduations: "文字盤の目盛り"
+    graduationDots: "ドット"
+    graduationArabic: "アラビア数字"
+    fadeGraduations: "目盛りをフェード"
+    sAnimation: "秒針のアニメーション"
+    sAnimationElastic: "リアル"
+    sAnimationEaseOut: "滑らか"
+    twentyFour: "24時間表示"
+    labelTime: "時刻"
+    labelTz: "タイムゾーン"
+    labelTimeAndTz: "時刻とタイムゾーン"
+    timezone: "タイムゾーン"
+    showMs: "ミリ秒を表示"
+    showLabel: "ラベルを表示"
+  _jobQueue:
+    sound: "音を鳴らす"
+  _rss:
+    url: "RSSフィードのURL"
+    refreshIntervalSec: "更新間隔(秒)"
+    maxEntries: "最大表示件数"
+  _rssTicker:
+    shuffle: "表示順をシャッフル"
+    duration: "ティッカーのスクロール速度(秒)"
+    reverse: "逆方向にスクロール"
+
 _cw:
   hide: "隠す"
   show: "もっと見る"
diff --git a/packages/frontend/src/widgets/WidgetActivity.vue b/packages/frontend/src/widgets/WidgetActivity.vue
index 9625abb4d1..3d0f4657b1 100644
--- a/packages/frontend/src/widgets/WidgetActivity.vue
+++ b/packages/frontend/src/widgets/WidgetActivity.vue
@@ -38,10 +38,12 @@ const name = 'activity';
 const widgetPropsDef = {
 	showHeader: {
 		type: 'boolean',
+		label: i18n.ts._widgetOptions.showHeader,
 		default: true,
 	},
 	transparent: {
 		type: 'boolean',
+		label: i18n.ts._widgetOptions.transparent,
 		default: false,
 	},
 	view: {
diff --git a/packages/frontend/src/widgets/WidgetAichan.vue b/packages/frontend/src/widgets/WidgetAichan.vue
index 3951de1d84..5dde75e4f2 100644
--- a/packages/frontend/src/widgets/WidgetAichan.vue
+++ b/packages/frontend/src/widgets/WidgetAichan.vue
@@ -12,6 +12,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 <script lang="ts" setup>
 import { onMounted, onUnmounted, useTemplateRef } from 'vue';
 import { useWidgetPropsManager } from './widget.js';
+import { i18n } from '@/i18n.js';
 import type { WidgetComponentProps, WidgetComponentEmits, WidgetComponentExpose } from './widget.js';
 import type { FormWithDefault, GetFormResultType } from '@/utility/form.js';
 
@@ -20,6 +21,7 @@ const name = 'ai';
 const widgetPropsDef = {
 	transparent: {
 		type: 'boolean',
+		label: i18n.ts._widgetOptions.transparent,
 		default: false,
 	},
 } satisfies FormWithDefault;
diff --git a/packages/frontend/src/widgets/WidgetAiscript.vue b/packages/frontend/src/widgets/WidgetAiscript.vue
index 795c5a2cfa..c6cafb270f 100644
--- a/packages/frontend/src/widgets/WidgetAiscript.vue
+++ b/packages/frontend/src/widgets/WidgetAiscript.vue
@@ -37,10 +37,12 @@ const name = 'aiscript';
 const widgetPropsDef = {
 	showHeader: {
 		type: 'boolean',
+		label: i18n.ts._widgetOptions.showHeader,
 		default: true,
 	},
 	script: {
 		type: 'string',
+		label: i18n.ts.script,
 		multiline: true,
 		default: '(1 + 1)',
 		hidden: true,
diff --git a/packages/frontend/src/widgets/WidgetAiscriptApp.vue b/packages/frontend/src/widgets/WidgetAiscriptApp.vue
index 18acd966fd..9e6b812d35 100644
--- a/packages/frontend/src/widgets/WidgetAiscriptApp.vue
+++ b/packages/frontend/src/widgets/WidgetAiscriptApp.vue
@@ -24,6 +24,7 @@ import type { AsUiComponent, AsUiRoot } from '@/aiscript/ui.js';
 import * as os from '@/os.js';
 import { aiScriptReadline, createAiScriptEnv } from '@/aiscript/api.js';
 import { $i } from '@/i.js';
+import { i18n } from '@/i18n.js';
 import MkAsUi from '@/components/MkAsUi.vue';
 import MkContainer from '@/components/MkContainer.vue';
 import { registerAsUiLib } from '@/aiscript/ui.js';
@@ -33,11 +34,13 @@ const name = 'aiscriptApp';
 const widgetPropsDef = {
 	script: {
 		type: 'string',
+		label: i18n.ts.script,
 		multiline: true,
 		default: '',
 	},
 	showHeader: {
 		type: 'boolean',
+		label: i18n.ts._widgetOptions.showHeader,
 		default: true,
 	},
 } satisfies FormWithDefault;
diff --git a/packages/frontend/src/widgets/WidgetBirthdayFollowings.vue b/packages/frontend/src/widgets/WidgetBirthdayFollowings.vue
index d1991cd70a..d270f12eaf 100644
--- a/packages/frontend/src/widgets/WidgetBirthdayFollowings.vue
+++ b/packages/frontend/src/widgets/WidgetBirthdayFollowings.vue
@@ -33,11 +33,12 @@ import { misskeyApi } from '@/utility/misskey-api.js';
 import { i18n } from '@/i18n.js';
 import { $i } from '@/i.js';
 
-const name = i18n.ts._widgets.birthdayFollowings;
+const name = 'birthdayFollowings';
 
 const widgetPropsDef = {
 	showHeader: {
 		type: 'boolean',
+		label: i18n.ts._widgetOptions.showHeader,
 		default: true,
 	},
 } satisfies FormWithDefault;
diff --git a/packages/frontend/src/widgets/WidgetButton.vue b/packages/frontend/src/widgets/WidgetButton.vue
index f8ae03c5fd..fca1359470 100644
--- a/packages/frontend/src/widgets/WidgetButton.vue
+++ b/packages/frontend/src/widgets/WidgetButton.vue
@@ -20,20 +20,24 @@ import * as os from '@/os.js';
 import { aiScriptReadline, createAiScriptEnv } from '@/aiscript/api.js';
 import { $i } from '@/i.js';
 import MkButton from '@/components/MkButton.vue';
+import { i18n } from '@/i18n.js';
 
 const name = 'button';
 
 const widgetPropsDef = {
 	label: {
 		type: 'string',
+		label: i18n.ts.label,
 		default: 'BUTTON',
 	},
 	colored: {
 		type: 'boolean',
+		label: i18n.ts._widgetOptions._button.colored,
 		default: true,
 	},
 	script: {
 		type: 'string',
+		label: i18n.ts.script,
 		multiline: true,
 		default: 'Mk:dialog("hello" "world")',
 	},
diff --git a/packages/frontend/src/widgets/WidgetCalendar.vue b/packages/frontend/src/widgets/WidgetCalendar.vue
index f2321ca9fa..28336cbe09 100644
--- a/packages/frontend/src/widgets/WidgetCalendar.vue
+++ b/packages/frontend/src/widgets/WidgetCalendar.vue
@@ -50,6 +50,7 @@ const name = 'calendar';
 const widgetPropsDef = {
 	transparent: {
 		type: 'boolean',
+		label: i18n.ts._widgetOptions.transparent,
 		default: false,
 	},
 } satisfies FormWithDefault;
diff --git a/packages/frontend/src/widgets/WidgetChat.vue b/packages/frontend/src/widgets/WidgetChat.vue
index 8fee7f00f6..06d8f741f4 100644
--- a/packages/frontend/src/widgets/WidgetChat.vue
+++ b/packages/frontend/src/widgets/WidgetChat.vue
@@ -29,6 +29,7 @@ const name = 'chat';
 const widgetPropsDef = {
 	showHeader: {
 		type: 'boolean',
+		label: i18n.ts._widgetOptions.showHeader,
 		default: true,
 	},
 } satisfies FormWithDefault;
diff --git a/packages/frontend/src/widgets/WidgetClicker.vue b/packages/frontend/src/widgets/WidgetClicker.vue
index 282a1a6d93..614e7c7fe5 100644
--- a/packages/frontend/src/widgets/WidgetClicker.vue
+++ b/packages/frontend/src/widgets/WidgetClicker.vue
@@ -15,6 +15,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 import { useWidgetPropsManager } from './widget.js';
 import type { WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
 import type { FormWithDefault, GetFormResultType } from '@/utility/form.js';
+import { i18n } from '@/i18n.js';
 import MkContainer from '@/components/MkContainer.vue';
 import MkClickerGame from '@/components/MkClickerGame.vue';
 
@@ -23,6 +24,7 @@ const name = 'clicker';
 const widgetPropsDef = {
 	showHeader: {
 		type: 'boolean',
+		label: i18n.ts._widgetOptions.showHeader,
 		default: false,
 	},
 } satisfies FormWithDefault;
diff --git a/packages/frontend/src/widgets/WidgetClock.vue b/packages/frontend/src/widgets/WidgetClock.vue
index 7aa69a39b5..80f312e7c4 100644
--- a/packages/frontend/src/widgets/WidgetClock.vue
+++ b/packages/frontend/src/widgets/WidgetClock.vue
@@ -44,10 +44,12 @@ const name = 'clock';
 const widgetPropsDef = {
 	transparent: {
 		type: 'boolean',
+		label: i18n.ts._widgetOptions.transparent,
 		default: false,
 	},
 	size: {
 		type: 'radio',
+		label: i18n.ts._widgetOptions._clock.size,
 		default: 'medium',
 		options: [{
 			value: 'small' as const,
@@ -62,79 +64,89 @@ const widgetPropsDef = {
 	},
 	thickness: {
 		type: 'radio',
+		label: i18n.ts._widgetOptions._clock.thickness,
 		default: 0.2,
 		options: [{
 			value: 0.1 as const,
-			label: 'thin',
+			label: i18n.ts._widgetOptions._clock.thicknessThin,
 		}, {
 			value: 0.2 as const,
-			label: 'medium',
+			label: i18n.ts._widgetOptions._clock.thicknessMedium,
 		}, {
 			value: 0.3 as const,
-			label: 'thick',
+			label: i18n.ts._widgetOptions._clock.thicknessThick,
 		}],
 	},
 	graduations: {
 		type: 'radio',
+		label: i18n.ts._widgetOptions._clock.graduations,
 		default: 'numbers',
 		options: [{
 			value: 'none' as const,
-			label: 'None',
+			label: i18n.ts.none,
 		}, {
 			value: 'dots' as const,
-			label: 'Dots',
+			label: i18n.ts._widgetOptions._clock.graduationDots,
 		}, {
 			value: 'numbers' as const,
-			label: 'Numbers',
-		}],
+			label: i18n.ts._widgetOptions._clock.graduationArabic,
+		}, /*, {
+			value: 'roman' as const,
+			label: i18n.ts._widgetOptions._clock.graduationRoman,
+		}*/],
 	},
 	fadeGraduations: {
 		type: 'boolean',
+		label: i18n.ts._widgetOptions._clock.fadeGraduations,
 		default: true,
 	},
 	sAnimation: {
 		type: 'radio',
+		label: i18n.ts._widgetOptions._clock.sAnimation,
 		default: 'elastic',
 		options: [{
 			value: 'none' as const,
-			label: 'None',
+			label: i18n.ts.none,
 		}, {
 			value: 'elastic' as const,
-			label: 'Elastic',
+			label: i18n.ts._widgetOptions._clock.sAnimationElastic,
 		}, {
 			value: 'easeOut' as const,
-			label: 'Ease out',
+			label: i18n.ts._widgetOptions._clock.sAnimationEaseOut,
 		}],
 	},
 	twentyFour: {
 		type: 'boolean',
+		label: i18n.ts._widgetOptions._clock.twentyFour,
 		default: false,
 	},
 	label: {
 		type: 'radio',
+		label: i18n.ts.label,
 		default: 'none',
 		options: [{
 			value: 'none' as const,
-			label: 'None',
+			label: i18n.ts.none,
 		}, {
 			value: 'time' as const,
-			label: 'Time',
+			label: i18n.ts._widgetOptions._clock.labelTime,
 		}, {
 			value: 'tz' as const,
-			label: 'TZ',
+			label: i18n.ts._widgetOptions._clock.labelTz,
 		}, {
 			value: 'timeAndTz' as const,
-			label: 'Time + TZ',
+			label: i18n.ts._widgetOptions._clock.labelTimeAndTz,
 		}],
 	},
 	timezone: {
 		type: 'enum',
+		label: i18n.ts._widgetOptions._clock.timezone,
 		default: null,
 		enum: [...timezones.map((tz) => ({
 			label: tz.name,
 			value: tz.name.toLowerCase(),
 		})), {
-			label: '(auto)',
+			label: i18n.ts.auto,
 			value: null,
 		}],
 	},
diff --git a/packages/frontend/src/widgets/WidgetDigitalClock.vue b/packages/frontend/src/widgets/WidgetDigitalClock.vue
index b8cbc6429c..d50d4aef62 100644
--- a/packages/frontend/src/widgets/WidgetDigitalClock.vue
+++ b/packages/frontend/src/widgets/WidgetDigitalClock.vue
@@ -19,6 +19,7 @@ import { useWidgetPropsManager } from './widget.js';
 import type { WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
 import type { FormWithDefault, GetFormResultType } from '@/utility/form.js';
 import { timezones } from '@/utility/timezones.js';
+import { i18n } from '@/i18n.js';
 import MkDigitalClock from '@/components/MkDigitalClock.vue';
 
 const name = 'digitalClock';
@@ -26,29 +27,34 @@ const name = 'digitalClock';
 const widgetPropsDef = {
 	transparent: {
 		type: 'boolean',
+		label: i18n.ts._widgetOptions.transparent,
 		default: false,
 	},
 	fontSize: {
 		type: 'number',
+		label: i18n.ts.fontSize,
 		default: 1.5,
 		step: 0.1,
 	},
 	showMs: {
 		type: 'boolean',
+		label: i18n.ts._widgetOptions._clock.showMs,
 		default: true,
 	},
 	showLabel: {
 		type: 'boolean',
+		label: i18n.ts._widgetOptions._clock.showLabel,
 		default: true,
 	},
 	timezone: {
 		type: 'enum',
+		label: i18n.ts._widgetOptions._clock.timezone,
 		default: null,
 		enum: [...timezones.map((tz) => ({
 			label: tz.name,
 			value: tz.name.toLowerCase(),
 		})), {
-			label: '(auto)',
+			label: i18n.ts.auto,
 			value: null,
 		}],
 	},
diff --git a/packages/frontend/src/widgets/WidgetFederation.vue b/packages/frontend/src/widgets/WidgetFederation.vue
index 3e880af03b..91a3e61201 100644
--- a/packages/frontend/src/widgets/WidgetFederation.vue
+++ b/packages/frontend/src/widgets/WidgetFederation.vue
@@ -43,6 +43,7 @@ const name = 'federation';
 const widgetPropsDef = {
 	showHeader: {
 		type: 'boolean',
+		label: i18n.ts._widgetOptions.showHeader,
 		default: true,
 	},
 } satisfies FormWithDefault;
diff --git a/packages/frontend/src/widgets/WidgetInstanceCloud.vue b/packages/frontend/src/widgets/WidgetInstanceCloud.vue
index 8053dd43cf..6a8e30f54a 100644
--- a/packages/frontend/src/widgets/WidgetInstanceCloud.vue
+++ b/packages/frontend/src/widgets/WidgetInstanceCloud.vue
@@ -29,12 +29,14 @@ import MkTagCloud from '@/components/MkTagCloud.vue';
 import * as os from '@/os.js';
 import { misskeyApi } from '@/utility/misskey-api.js';
 import { getProxiedImageUrlNullable } from '@/utility/media-proxy.js';
+import { i18n } from '@/i18n.js';
 
 const name = 'instanceCloud';
 
 const widgetPropsDef = {
 	transparent: {
 		type: 'boolean',
+		label: i18n.ts._widgetOptions.transparent,
 		default: false,
 	},
 } satisfies FormWithDefault;
diff --git a/packages/frontend/src/widgets/WidgetJobQueue.vue b/packages/frontend/src/widgets/WidgetJobQueue.vue
index fba7d82062..877baaea02 100644
--- a/packages/frontend/src/widgets/WidgetJobQueue.vue
+++ b/packages/frontend/src/widgets/WidgetJobQueue.vue
@@ -61,16 +61,19 @@ import * as sound from '@/utility/sound.js';
 import { deepClone } from '@/utility/clone.js';
 import { prefer } from '@/preferences.js';
 import { genId } from '@/utility/id.js';
+import { i18n } from '@/i18n.js';
 
 const name = 'jobQueue';
 
 const widgetPropsDef = {
 	transparent: {
 		type: 'boolean',
+		label: i18n.ts._widgetOptions.transparent,
 		default: false,
 	},
 	sound: {
 		type: 'boolean',
+		label: i18n.ts._widgetOptions._jobQueue.sound,
 		default: false,
 	},
 } satisfies FormWithDefault;
diff --git a/packages/frontend/src/widgets/WidgetMemo.vue b/packages/frontend/src/widgets/WidgetMemo.vue
index 2beca8c43a..f96a11f059 100644
--- a/packages/frontend/src/widgets/WidgetMemo.vue
+++ b/packages/frontend/src/widgets/WidgetMemo.vue
@@ -29,10 +29,12 @@ const name = 'memo';
 const widgetPropsDef = {
 	showHeader: {
 		type: 'boolean',
+		label: i18n.ts._widgetOptions.showHeader,
 		default: true,
 	},
 	height: {
 		type: 'number',
+		label: i18n.ts.height,
 		default: 100,
 	},
 } satisfies FormWithDefault;
diff --git a/packages/frontend/src/widgets/WidgetNotifications.vue b/packages/frontend/src/widgets/WidgetNotifications.vue
index b588bcb029..48a29d6145 100644
--- a/packages/frontend/src/widgets/WidgetNotifications.vue
+++ b/packages/frontend/src/widgets/WidgetNotifications.vue
@@ -31,10 +31,12 @@ const name = 'notifications';
 const widgetPropsDef = {
 	showHeader: {
 		type: 'boolean',
+		label: i18n.ts._widgetOptions.showHeader,
 		default: true,
 	},
 	height: {
 		type: 'number',
+		label: i18n.ts.height,
 		default: 300,
 	},
 	excludeTypes: {
diff --git a/packages/frontend/src/widgets/WidgetOnlineUsers.vue b/packages/frontend/src/widgets/WidgetOnlineUsers.vue
index 9fd8c013d1..b0bb4b47b1 100644
--- a/packages/frontend/src/widgets/WidgetOnlineUsers.vue
+++ b/packages/frontend/src/widgets/WidgetOnlineUsers.vue
@@ -28,6 +28,7 @@ const name = 'onlineUsers';
 const widgetPropsDef = {
 	transparent: {
 		type: 'boolean',
+		label: i18n.ts._widgetOptions.transparent,
 		default: true,
 	},
 } satisfies FormWithDefault;
diff --git a/packages/frontend/src/widgets/WidgetPhotos.vue b/packages/frontend/src/widgets/WidgetPhotos.vue
index e89a642b99..4f592911d4 100644
--- a/packages/frontend/src/widgets/WidgetPhotos.vue
+++ b/packages/frontend/src/widgets/WidgetPhotos.vue
@@ -39,10 +39,12 @@ const name = 'photos';
 const widgetPropsDef = {
 	showHeader: {
 		type: 'boolean',
+		label: i18n.ts._widgetOptions.showHeader,
 		default: true,
 	},
 	transparent: {
 		type: 'boolean',
+		label: i18n.ts._widgetOptions.transparent,
 		default: false,
 	},
 } satisfies FormWithDefault;
diff --git a/packages/frontend/src/widgets/WidgetRss.vue b/packages/frontend/src/widgets/WidgetRss.vue
index 5fa9e833b8..2495c5a6e9 100644
--- a/packages/frontend/src/widgets/WidgetRss.vue
+++ b/packages/frontend/src/widgets/WidgetRss.vue
@@ -25,6 +25,7 @@ import * as Misskey from 'misskey-js';
 import { url as base } from '@@/js/config.js';
 import { useInterval } from '@@/js/use-interval.js';
 import { useWidgetPropsManager } from './widget.js';
+import { i18n } from '@/i18n.js';
 import type { WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
 import type { FormWithDefault, GetFormResultType } from '@/utility/form.js';
 import MkContainer from '@/components/MkContainer.vue';
@@ -34,19 +35,23 @@ const name = 'rss';
 const widgetPropsDef = {
 	url: {
 		type: 'string',
+		label: i18n.ts._widgetOptions._rss.url,
 		default: 'http://feeds.afpbb.com/rss/afpbb/afpbbnews',
 		manualSave: true,
 	},
 	refreshIntervalSec: {
 		type: 'number',
+		label: i18n.ts._widgetOptions._rss.refreshIntervalSec,
 		default: 60,
 	},
 	maxEntries: {
 		type: 'number',
+		label: i18n.ts._widgetOptions._rss.maxEntries,
 		default: 15,
 	},
 	showHeader: {
 		type: 'boolean',
+		label: i18n.ts._widgetOptions.showHeader,
 		default: true,
 	},
 } satisfies FormWithDefault;
diff --git a/packages/frontend/src/widgets/WidgetRssTicker.vue b/packages/frontend/src/widgets/WidgetRssTicker.vue
index b0d9eec883..9ed21e6d00 100644
--- a/packages/frontend/src/widgets/WidgetRssTicker.vue
+++ b/packages/frontend/src/widgets/WidgetRssTicker.vue
@@ -35,6 +35,7 @@ import MkMarqueeText from '@/components/MkMarqueeText.vue';
 import type { FormWithDefault, GetFormResultType } from '@/utility/form.js';
 import MkContainer from '@/components/MkContainer.vue';
 import { shuffle } from '@/utility/shuffle.js';
+import { i18n } from '@/i18n.js';
 import { url as base } from '@@/js/config.js';
 import { useInterval } from '@@/js/use-interval.js';
 
@@ -43,23 +44,28 @@ const name = 'rssTicker';
 const widgetPropsDef = {
 	url: {
 		type: 'string',
+		label: i18n.ts._widgetOptions._rss.url,
 		default: 'http://feeds.afpbb.com/rss/afpbb/afpbbnews',
 		manualSave: true,
 	},
 	shuffle: {
 		type: 'boolean',
+		label: i18n.ts._widgetOptions._rssTicker.shuffle,
 		default: true,
 	},
 	refreshIntervalSec: {
 		type: 'number',
+		label: i18n.ts._widgetOptions._rss.refreshIntervalSec,
 		default: 60,
 	},
 	maxEntries: {
 		type: 'number',
+		label: i18n.ts._widgetOptions._rss.maxEntries,
 		default: 15,
 	},
 	duration: {
 		type: 'range',
+		label: i18n.ts._widgetOptions._rssTicker.duration,
 		default: 70,
 		step: 1,
 		min: 5,
@@ -67,14 +73,17 @@ const widgetPropsDef = {
 	},
 	reverse: {
 		type: 'boolean',
+		label: i18n.ts._widgetOptions._rssTicker.reverse,
 		default: false,
 	},
 	showHeader: {
 		type: 'boolean',
+		label: i18n.ts._widgetOptions.showHeader,
 		default: false,
 	},
 	transparent: {
 		type: 'boolean',
+		label: i18n.ts._widgetOptions.transparent,
 		default: false,
 	},
 } satisfies FormWithDefault;
diff --git a/packages/frontend/src/widgets/WidgetSlideshow.vue b/packages/frontend/src/widgets/WidgetSlideshow.vue
index 240210c1fb..13ca278c23 100644
--- a/packages/frontend/src/widgets/WidgetSlideshow.vue
+++ b/packages/frontend/src/widgets/WidgetSlideshow.vue
@@ -33,6 +33,7 @@ const name = 'slideshow';
 const widgetPropsDef = {
 	height: {
 		type: 'number',
+		label: i18n.ts._widgetOptions.height,
 		default: 300,
 	},
 	folderId: {
diff --git a/packages/frontend/src/widgets/WidgetTrends.vue b/packages/frontend/src/widgets/WidgetTrends.vue
index dcb900b0c9..1984750cd7 100644
--- a/packages/frontend/src/widgets/WidgetTrends.vue
+++ b/packages/frontend/src/widgets/WidgetTrends.vue
@@ -41,6 +41,7 @@ const name = 'hashtags';
 const widgetPropsDef = {
 	showHeader: {
 		type: 'boolean',
+		label: i18n.ts._widgetOptions.showHeader,
 		default: true,
 	},
 } satisfies FormWithDefault;
diff --git a/packages/frontend/src/widgets/WidgetUnixClock.vue b/packages/frontend/src/widgets/WidgetUnixClock.vue
index 226a4c73aa..1bb361664f 100644
--- a/packages/frontend/src/widgets/WidgetUnixClock.vue
+++ b/packages/frontend/src/widgets/WidgetUnixClock.vue
@@ -18,6 +18,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 <script lang="ts" setup>
 import { onUnmounted, ref, watch } from 'vue';
 import { useWidgetPropsManager } from './widget.js';
+import { i18n } from '@/i18n.js';
 import type { WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
 import type { FormWithDefault, GetFormResultType } from '@/utility/form.js';
 
@@ -26,19 +27,23 @@ const name = 'unixClock';
 const widgetPropsDef = {
 	transparent: {
 		type: 'boolean',
+		label: i18n.ts._widgetOptions.transparent,
 		default: false,
 	},
 	fontSize: {
 		type: 'number',
+		label: i18n.ts.fontSize,
 		default: 1.5,
 		step: 0.1,
 	},
 	showMs: {
 		type: 'boolean',
+		label: i18n.ts._widgetOptions._clock.showMs,
 		default: true,
 	},
 	showLabel: {
 		type: 'boolean',
+		label: i18n.ts._widgetOptions._clock.showLabel,
 		default: true,
 	},
 } satisfies FormWithDefault;
diff --git a/packages/frontend/src/widgets/WidgetUserList.vue b/packages/frontend/src/widgets/WidgetUserList.vue
index 9e914fa648..3fc46f303f 100644
--- a/packages/frontend/src/widgets/WidgetUserList.vue
+++ b/packages/frontend/src/widgets/WidgetUserList.vue
@@ -41,6 +41,7 @@ const name = 'userList';
 const widgetPropsDef = {
 	showHeader: {
 		type: 'boolean',
+		label: i18n.ts._widgetOptions.showHeader,
 		default: true,
 	},
 	listId: {
diff --git a/packages/frontend/src/widgets/server-metric/index.vue b/packages/frontend/src/widgets/server-metric/index.vue
index f52b6fd12e..5d93c6a982 100644
--- a/packages/frontend/src/widgets/server-metric/index.vue
+++ b/packages/frontend/src/widgets/server-metric/index.vue
@@ -40,10 +40,12 @@ const name = 'serverMetric';
 const widgetPropsDef = {
 	showHeader: {
 		type: 'boolean',
+		label: i18n.ts._widgetOptions.showHeader,
 		default: true,
 	},
 	transparent: {
 		type: 'boolean',
+		label: i18n.ts._widgetOptions.transparent,
 		default: false,
 	},
 	view: {
diff --git a/packages/frontend/src/widgets/widget.ts b/packages/frontend/src/widgets/widget.ts
index d4209f6251..2a954b6540 100644
--- a/packages/frontend/src/widgets/widget.ts
+++ b/packages/frontend/src/widgets/widget.ts
@@ -10,6 +10,7 @@ import type { Reactive } from 'vue';
 import type { FormWithDefault, GetFormResultType } from '@/utility/form.js';
 import * as os from '@/os.js';
 import { deepClone } from '@/utility/clone.js';
+import { i18n } from '@/i18n';
 
 export type Widget<P extends Record<string, unknown>> = {
 	id: string;
@@ -75,7 +76,7 @@ export const useWidgetPropsManager = <F extends FormWithDefault>(
 			canceled: true;
 		}>((resolve) => {
 			const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkWidgetSettingsDialog.vue')), {
-				widgetName: name,
+				widgetName: i18n.ts._widgets[name] ?? name,
 				form: form,
 				currentSettings: widgetProps,
 			}, {
diff --git a/packages/i18n/src/autogen/locale.ts b/packages/i18n/src/autogen/locale.ts
index d8571483aa..5a7c0c541f 100644
--- a/packages/i18n/src/autogen/locale.ts
+++ b/packages/i18n/src/autogen/locale.ts
@@ -9893,6 +9893,138 @@ export interface Locale extends ILocale {
          */
         "chat": string;
     };
+    "_widgetOptions": {
+        /**
+         * ヘッダーを表示
+         */
+        "showHeader": string;
+        /**
+         * 背景を透明にする
+         */
+        "transparent": string;
+        /**
+         * 高さ
+         */
+        "height": string;
+        "_button": {
+            /**
+             * 色付き
+             */
+            "colored": string;
+        };
+        "_clock": {
+            /**
+             * サイズ
+             */
+            "size": string;
+            /**
+             * 針の太さ
+             */
+            "thickness": string;
+            /**
+             * 細い
+             */
+            "thicknessThin": string;
+            /**
+             * 普通
+             */
+            "thicknessMedium": string;
+            /**
+             * 太い
+             */
+            "thicknessThick": string;
+            /**
+             * 文字盤の目盛り
+             */
+            "graduations": string;
+            /**
+             * ドット
+             */
+            "graduationDots": string;
+            /**
+             * アラビア数字
+             */
+            "graduationArabic": string;
+            /**
+             * 目盛りをフェード
+             */
+            "fadeGraduations": string;
+            /**
+             * 秒針のアニメーション
+             */
+            "sAnimation": string;
+            /**
+             * リアル
+             */
+            "sAnimationElastic": string;
+            /**
+             * 滑らか
+             */
+            "sAnimationEaseOut": string;
+            /**
+             * 24時間表示
+             */
+            "twentyFour": string;
+            /**
+             * 時刻
+             */
+            "labelTime": string;
+            /**
+             * タイムゾーン
+             */
+            "labelTz": string;
+            /**
+             * 時刻とタイムゾーン
+             */
+            "labelTimeAndTz": string;
+            /**
+             * タイムゾーン
+             */
+            "timezone": string;
+            /**
+             * ミリ秒を表示
+             */
+            "showMs": string;
+            /**
+             * ラベルを表示
+             */
+            "showLabel": string;
+        };
+        "_jobQueue": {
+            /**
+             * 音を鳴らす
+             */
+            "sound": string;
+        };
+        "_rss": {
+            /**
+             * RSSフィードのURL
+             */
+            "url": string;
+            /**
+             * 更新間隔(秒)
+             */
+            "refreshIntervalSec": string;
+            /**
+             * 最大表示件数
+             */
+            "maxEntries": string;
+        };
+        "_rssTicker": {
+            /**
+             * 表示順をシャッフル
+             */
+            "shuffle": string;
+            /**
+             * ティッカーのスクロール速度(秒)
+             */
+            "duration": string;
+            /**
+             * 逆方向にスクロール
+             */
+            "reverse": string;
+        };
+    };
     "_cw": {
         /**
          * 隠す
-- 
cgit v1.2.3-freya

