「Mery 翻訳」の版間の差分
ページの作成:「== 概要 == 「Mery 翻訳」は、Mery エディタ上で選択したテキストやカーソル位置の行を翻訳するためのマクロです。 Google 翻訳のエンドポイントを ''curl.exe'' から呼び出し、翻訳結果を元の文章の直下へ挿入します。英語のコメントやドキュメントを読みながら、その場ですぐ日本語訳を確認したい場合などに便利です。 例えば、次のような英文を選…」 |
編集の要約なし |
||
| 62行目: | 62行目: | ||
Google 翻訳への通信に Windows の ''curl.exe'' を利用するため、あらかじめ ''curl.exe'' が利用可能であることを確認してください。 | Google 翻訳への通信に Windows の ''curl.exe'' を利用するため、あらかじめ ''curl.exe'' が利用可能であることを確認してください。 | ||
また、マクロ冒頭にある ''CONFIG'' | また、マクロ冒頭にある ''CONFIG'' を変更することで、翻訳する言語や表示方式などを設定できます。 | ||
標準設定は次のとおりです。 | 標準設定は次のとおりです。 | ||
| 70行目: | 70行目: | ||
/** 翻訳元言語。空文字または "auto" で自動判定 */ | /** 翻訳元言語。空文字または "auto" で自動判定 */ | ||
sourceLanguage: "auto", | sourceLanguage: "auto", | ||
/** 翻訳先言語 */ | /** 翻訳先言語 */ | ||
targetLanguage: "ja", | targetLanguage: "ja", | ||
/** 検出言語が targetLanguage と同じときの翻訳先 */ | /** 検出言語が targetLanguage と同じときの翻訳先 */ | ||
reverseLanguage: "en", | reverseLanguage: "en", | ||
/** curl のタイムアウト(秒) */ | /** curl のタイムアウト(秒) */ | ||
timeoutSec: 10, | timeoutSec: 10, | ||
/** | |||
* 翻訳結果の表示方法(複数同時に有効化可) | |||
* - editor: エディターへ挿入(選択範囲の直下) | |||
* - outputBar: アウトプットバーへ出力 | |||
* - tip: ツールチップで表示 | |||
*/ | |||
display: { | |||
editor: true, | |||
outputBar: false, | |||
tip: false, | |||
}, | |||
/** | |||
* アウトプットバー出力時に自動で表示するか | |||
* true で表示、false で表示しない | |||
*/ | |||
outputBarVisible: true, | |||
/** | |||
* tip 表示時の位置フラグ | |||
* meShowTipPosCaret (キャレット位置) | meShowTipPosMouse (マウス位置) | |||
*/ | |||
tipFlags: meShowTipPosCaret, | |||
}; | }; | ||
</pre> | </pre> | ||
| 303行目: | 324行目: | ||
* | * | ||
* VSCode 拡張「Comment Translate」と同じ Google 翻訳の非公式エンドポイントを、 | * VSCode 拡張「Comment Translate」と同じ Google 翻訳の非公式エンドポイントを、 | ||
* shell.Exec + curl | * shell.Exec + curl で呼び出して翻訳します。 | ||
* (q は encodeURIComponent して渡します。stdin の q@- は Mery 経由だと欠落します) | * (q は encodeURIComponent して渡します。stdin の q@- は Mery 経由だと欠落します) | ||
* | * | ||
| 315行目: | 336行目: | ||
* | * | ||
* 設定は下の CONFIG を編集してください。 | * 設定は下の CONFIG を編集してください。 | ||
* display は複数同時に true にできます(組み合わせ可)。 | |||
*/ | */ | ||
| 326行目: | 348行目: | ||
/** curl のタイムアウト(秒) */ | /** curl のタイムアウト(秒) */ | ||
timeoutSec: 10, | timeoutSec: 10, | ||
/** | |||
* 翻訳結果の表示方法(複数同時に有効化可) | |||
* - editor: エディターへ挿入(選択範囲の直下) | |||
* - outputBar: アウトプットバーへ出力 | |||
* - tip: ツールチップで表示 | |||
*/ | |||
display: { | |||
editor: true, | |||
outputBar: false, | |||
tip: false, | |||
}, | |||
/** | |||
* アウトプットバー出力時に自動で表示するか | |||
* true で表示、false で表示しない | |||
*/ | |||
outputBarVisible: true, | |||
/** | |||
* tip 表示時の位置フラグ | |||
* meShowTipPosCaret (キャレット位置) | meShowTipPosMouse (マウス位置) | |||
*/ | |||
tipFlags: meShowTipPosCaret, | |||
}; | }; | ||
| 335行目: | 381行目: | ||
function main() { | function main() { | ||
let keepResultTip = false; | |||
try { | try { | ||
const target = resolveTranslateTarget(); | const target = resolveTranslateTarget(); | ||
| 340行目: | 387行目: | ||
Status = "翻訳するテキストがありません"; | Status = "翻訳するテキストがありません"; | ||
return; | return; | ||
} | |||
if (!hasAnyDisplayTarget()) { | |||
throw new Error( | |||
"CONFIG.display のいずれか(editor / outputBar / tip)を true にしてください。" | |||
); | |||
} | } | ||
| 353行目: | 406行目: | ||
const outcome = runTranslation(target.text); | const outcome = runTranslation(target.text); | ||
keepResultTip = presentTranslation( | |||
outcome.translatedText, | outcome.translatedText, | ||
outcome.sourceLanguage, | outcome.sourceLanguage, | ||
| 366行目: | 419行目: | ||
alert("Translator: " + message); | alert("Translator: " + message); | ||
} finally { | } finally { | ||
ShowTip("", meShowTipHide); | // tip 結果表示を残す場合は非表示にしない | ||
if (!keepResultTip) { | |||
ShowTip("", meShowTipHide); | |||
} | |||
} | } | ||
} | |||
function hasAnyDisplayTarget() { | |||
const display = CONFIG.display || {}; | |||
return !!(display.editor || display.outputBar || display.tip); | |||
} | |||
/** | |||
* CONFIG.display に従って翻訳結果を出力する。 | |||
* tip を使った場合は true を返し、進捗チップの非表示を抑止する。 | |||
*/ | |||
function presentTranslation(translatedText, sourceLanguage, targetLanguage) { | |||
const display = CONFIG.display || {}; | |||
const block = formatTranslationBlock( | |||
translatedText, | |||
sourceLanguage, | |||
targetLanguage | |||
); | |||
if (display.editor) { | |||
insertTranslationBelow(translatedText, sourceLanguage, targetLanguage); | |||
} | |||
if (display.outputBar) { | |||
writeTranslationToOutputBar(block); | |||
} | |||
if (display.tip) { | |||
const flags = | |||
CONFIG.tipFlags == null ? meShowTipPosCaret : CONFIG.tipFlags; | |||
ShowTip( | |||
formatTranslationTip(translatedText, sourceLanguage, targetLanguage), | |||
flags | |||
); | |||
return true; | |||
} | |||
return false; | |||
} | |||
function formatTranslationBlock(translatedText, sourceLanguage, targetLanguage) { | |||
const header = | |||
"----- 翻訳: " + | |||
sourceLanguage + | |||
" -> " + | |||
targetLanguage + | |||
" -----"; | |||
const footer = repeatChar("-", header.length); | |||
return { | |||
header: header, | |||
footer: footer, | |||
translatedText: translatedText, | |||
full: header + "\n" + translatedText + "\n" + footer, | |||
}; | |||
} | |||
/** ツールチップ用の短い表示形式 */ | |||
function formatTranslationTip(translatedText, sourceLanguage, targetLanguage) { | |||
return ( | |||
"[翻訳: " + | |||
sourceLanguage + | |||
" -> " + | |||
targetLanguage + | |||
"]\n" + | |||
translatedText | |||
); | |||
} | |||
function writeTranslationToOutputBar(block) { | |||
// Visible は CONFIG.outputBarVisible が true のときだけ立てる | |||
if (CONFIG.outputBarVisible) { | |||
OutputBar.Visible = true; | |||
} | |||
OutputBar.Writeln(block.full); | |||
} | } | ||
| 643行目: | 773行目: | ||
sel.EndOfLine(false, mePosLogical); | sel.EndOfLine(false, mePosLogical); | ||
const | const block = formatTranslationBlock( | ||
translatedText, | |||
sourceLanguage | sourceLanguage, | ||
targetLanguage | |||
targetLanguage | ); | ||
const body = "\n" + block.full; | |||
const body = "\n" + | |||
// 文書末尾なら、フッター直後に空行を残せるよう末尾改行を付ける | // 文書末尾なら、フッター直後に空行を残せるよう末尾改行を付ける | ||
| 679行目: | 807行目: | ||
== 更新履歴 == | == 更新履歴 == | ||
* 2026-08-12 出力方法を設定できるようにしました | |||
* 2026-08-11 公開 | * 2026-08-11 公開 | ||
スポンサーリンク