Neovim 翻译弹窗
Source: Dev.to

创建者: opencode 和 Sérgio Araújo
前置条件
-
安装 translate‑shell
translate‑shell 是一个基于 Google Translate、Bing、Yandex 等的命令行翻译工具。直接下载
wget git.io/trans chmod +x ./trans sudo mv trans /usr/local/bin/或通过 git
git clone https://github.com/soimort/translate-shell cd translate-shell && make && sudo make install依赖项:
gawk(4.0+) 和bash或zsh(通常在 Linux 上预装)。
Neovim 实现
1. 添加翻译函数
Create (or edit) ~/.config/nvim/lua/core/utils/nvim_utils.lua and add the translate_popup function:
function M.translate_popup()
local text = ''
local is_multiline = false
local mode = vim.api.nvim_get_mode().mode
if mode == 'v' or mode == 'V' or mode == '\x16' then
local start_pos = vim.api.nvim_buf_get_mark(0, '')
local lines = vim.api.nvim_buf_get_lines(0, start_pos[1] - 1, end_pos[1], false)
if #lines > 1 then
is_multiline = true
text = table.concat(lines, '\n')
else
text = table.concat(lines, ' ')
end
else
text = vim.fn.expand('') or ''
end
if text == '' then return end
local ok, trans = pcall(function()
local handle = io.popen('trans -b -no-ansi en:pt-BR ' .. vim.fn.shellescape(text))
if not handle then return nil end
local result = handle:read('*a')
handle:close()
return result
end)
if not ok or not trans or trans == '' then
vim.notify('Failed to translate', vim.log.levels.ERROR, { title = 'Translate' })
return
end
local lines = vim.split(trans:gsub('^%s+', ''):gsub('%s+$', ''), '\n')
local filtered = {}
for _, line in ipairs(lines) do
table.insert(filtered, line)
end
if #filtered == 0 then
vim.notify('Empty translation result', vim.log.levels.WARN, { title = 'Translate' })
return
end
local width = 20
for _, line in ipairs(filtered) do
local line_width = vim.fn.strdisplaywidth(line)
if line_width > width then
width = math.min(80, line_width)
end
end
local height = #filtered
local buf = vim.api.nvim_create_buf(false, true)
vim.api.nvim_buf_set_lines(buf, 0, -1, false, filtered)
vim.api.nvim_buf_set_option(buf, 'filetype', 'markdown')
vim.api.nvim_buf_set_option(buf, 'modifiable', false)
vim.api.nvim_set_hl(0, 'TranslateBg', { bg = '#ffcc66', fg = '#000000' })
vim.api.nvim_buf_set_extmark(buf, vim.api.nvim_create_namespace('translate'), 0, 0, {
hl_group = 'TranslateBg',
hl_eol = true,
end_line = height - 1,
})
local row, col = unpack(vim.api.nvim_win_get_cursor(0))
local win = vim.api.nvim_open_win(buf, true, {
style = 'minimal',
relative = 'cursor',
width = width + 2,
height = height,
row = 1,
col = 0,
border = 'rounded',
noautocmd = true,
})
vim.api.nvim_set_option_value('winblend', 0, { win = win })
vim.api.nvim_set_option_value('winhighlight', 'Normal:TranslateBg', { win = win })
vim.keymap.set('n', 'q', 'close', { buffer = buf, nowait = true })
vim.keymap.set('n', '', 'close', { buffer = buf, nowait = true })
end
2. 添加键映射
A small helper for creating mappings (optional, but handy):
-- https://blog.devgenius.io/create-custom-keymaps-in-neovim-with-lua-d1167de0f2c2
-- https://oroques.dev/notes/neovim-init/
function M.map(mode, lhs, rhs, opts)
local options = { noremap = true, silent = true }
if opts then options = vim.tbl_extend('force', options, opts) end
vim.keymap.set(mode, lhs, rhs, options)
end
Add the mappings in ~/.config/nvim/lua/core/keymaps.lua:
map('n', 'st', nvim_utils.translate_popup,
{ desc = 'Show Translate (word under cursor)' })
map('x', 'st', nvim_utils.translate_popup,
{ desc = 'Show Translate (selection)' })
3. 记忆法
The st shortcut was chosen with the mnemonic:
- s → show
- t → translate
Just like other translators “show translate”, or simply “translate”。
功能
- 光标下的单词 – 在光标位于单词上时按下
st。 - 可视选择 – 选中文本后按
st进行翻译。 - 多行 – 选中的段落保留换行。
- 默认语言 – 英语 → 巴西葡萄牙语 (
en:pt-BR)。 - 样式化弹窗 – 橙黄背景 (
#ffcc66),黑色文字。 - 关闭方式 –
q或 “。
演示

致谢
- opencode – 实现与开发
- Sérgio Araújo – 思路、测试与反馈

