Neovim 翻译弹窗

发布: (2026年2月28日 GMT+8 22:08)
4 分钟阅读
原文: Dev.to

Source: Dev.to

Neovim 翻译弹出窗口的封面图

Sérgio Araújo

创建者: opencodeSérgio Araújo

前置条件

  1. 安装 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+) 和 bashzsh(通常在 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:

  • sshow
  • ttranslate

Just like other translators “show translate”, or simply “translate”。

功能

  • 光标下的单词 – 在光标位于单词上时按下 st
  • 可视选择 – 选中文本后按 st 进行翻译。
  • 多行 – 选中的段落保留换行。
  • 默认语言 – 英语 → 巴西葡萄牙语 (en:pt-BR)。
  • 样式化弹窗 – 橙黄背景 (#ffcc66),黑色文字。
  • 关闭方式q 或 “。

演示

演示 GIF

![Demo GIF](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f86ah372f8y0kxhqzv8m.gif)

致谢

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

参考文献

0 浏览
Back to Blog

相关文章

阅读更多 »