diff --git a/locales/index.d.ts b/locales/index.d.ts
index 7eebd65a0d..b516e742b9 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -383,6 +383,10 @@ export interface Locale extends ILocale {
* ノートを翻訳する
*/
"translateNote": string;
+ /**
+ * 投票を翻訳する
+ */
+ "translatePoll": string;
/**
* ノート本文に翻訳ボタンを表示
*/
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index cb27e3dfd4..2eaf8afa0e 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -90,6 +90,7 @@ inviteRevokeConfirm: "本当に全ての招待コードを失効させますか
enableAbsoluteTime: "絶対時刻表記を使用する"
posted: "ノートを公開しました。"
translateNote: "ノートを翻訳する"
+translatePoll: "投票を翻訳する"
showTranslateButtonInNote: "ノート本文に翻訳ボタンを表示"
editNickName: "ニックネームを編集"
hideAvatarsInNote: "ノートでアイコンを隠す"
diff --git a/packages/frontend/src/components/MkNote.vue b/packages/frontend/src/components/MkNote.vue
index a94bfb1c29..15146dc5d6 100644
--- a/packages/frontend/src/components/MkNote.vue
+++ b/packages/frontend/src/components/MkNote.vue
@@ -110,7 +110,6 @@ SPDX-License-Identifier: AGPL-3.0-only
:enableEmojiMenuReaction="!!$i"
@click.stop
/>
-
@@ -128,6 +127,21 @@ SPDX-License-Identifier: AGPL-3.0-only
+
+
+
+
+
+
+
+
{{ i18n.tsx.translatedFrom({ x: pollTranslation.sourceLang }) }}:
+
+
+
+
+
+
+
@@ -355,7 +369,9 @@ const isDeleted = ref(false);
const muted = ref(checkMute(appearNote.value, $i?.mutedWords));
const hardMuted = ref(props.withHardMute && checkMute(appearNote.value, $i?.hardMutedWords, true));
const translation = ref(null);
+const pollTranslation = ref(null);
const translating = ref(false);
+const pollTranslating = ref(false);
const viewTextSource = ref(false);
const noNyaize = ref(false);
const canRenote = computed(() => ['public', 'home'].includes(appearNote.value.visibility) || (appearNote.value.visibility === 'followers' && appearNote.value.userId === $i?.id));
@@ -757,9 +773,15 @@ async function clip(): Promise {
const isForeignLanguage: boolean = appearNote.value.text != null && (() => {
const targetLang = (miLocalStorage.getItem('lang') ?? navigator.language).slice(0, 2);
const postLang = detectLanguage(appearNote.value.text);
- const choicesLang = appearNote.value.poll?.choices.map((choice) => choice.text).join(' ') ?? '';
- const pollLang = detectLanguage(choicesLang);
- return postLang !== '' && (postLang !== targetLang || pollLang !== targetLang);
+ return postLang !== '' && postLang !== targetLang;
+})();
+
+const pollIsForeignLanguage: boolean = appearNote.value.poll != null && (() => {
+ const targetLang = (miLocalStorage.getItem('lang') ?? navigator.language).slice(0, 2);
+ const langs = appearNote.value.poll.choices
+ .map((choice) => detectLanguage(choice.text))
+ .filter((lang) => lang != targetLang).length;
+ return langs != 0;
})();
if (defaultStore.state.useAutoTranslate && instance.translatorAvailable && $i.policies.canUseTranslator && $i.policies.canUseAutoTranslate && !isLong && (appearNote.value.cw == null || showContent.value) && appearNote.value.text && isForeignLanguage) translate();
@@ -793,6 +815,34 @@ async function translate(): Promise {
vibrate(defaultStore.state.vibrateSystem ? [5, 5, 10] : []);
}
+async function pollTranslate(): Promise {
+ if (pollTranslation.value != null) return;
+ collapsed.value = false;
+ pollTranslating.value = true;
+
+ vibrate(defaultStore.state.vibrateSystem ? 5 : []);
+
+ if (props.mock) {
+ return;
+ }
+ const res = await misskeyApi('notes/polls/translate', {
+ noteId: appearNote.value.id,
+ targetLang: miLocalStorage.getItem('lang') ?? navigator.language,
+ }).catch((err) => {
+ translating.value = false;
+ os.alert(
+ {
+ type: 'error',
+ title: err.message,
+ text: err.id,
+ });
+ });
+ pollTranslating.value = false;
+ pollTranslation.value = res;
+
+ vibrate(defaultStore.state.vibrateSystem ? [5, 5, 10] : []);
+}
+
function showRenoteMenu(): void {
if (props.mock) {
return;