Neovim plugin + pandoc tool for writing bilingual legal documents in markdown with parallel two-column export to PDF and Word.
Built for legal contracts where text in two languages must appear side by side with synchronized sections.
Write in markdown with fenced divs — export to PDF and Word with a single command:
Markdown source (Neovim)
PDF output (LuaLaTeX + paracol)
Word output (DOCX tables)
- Parallel columns — two languages side by side, sections aligned
- Page-break support — columns flow naturally across pages (no gaps)
- RTL support — Arabic, Hebrew with automatic font switching
- Contract templates — ready-made skeletons for EN-RU, EN-AR, EN-HE
- Syntax highlighting — colored markers for bilingual blocks, concealing support
- Block folding — fold bilingual sections with preview from both columns
- Quick section insert — keymap to add bilingual blocks without typing tags
- Export from nvim —
:Bilingual pdf/:Bilingual docx - Professional PDF — LuaLaTeX with PT Serif, paracol, proper typography
- Word export — clean DOCX with two-column tables
- Neovim >= 0.10
- pandoc >= 3.0 —
brew install pandoc - LuaLaTeX (for PDF) —
brew install --cask mactexorbrew install basictex
Fonts (bundled on macOS):
- PT Serif, Helvetica Neue, Menlo
- Geeza Pro (Arabic), Arial Hebrew (Hebrew)
Plug '/path/to/nvim.bilingual'{ dir = "/path/to/nvim.bilingual" }No setup() call needed — the plugin loads automatically.
:Bilingual newA menu appears with language pairs:
Language pair:
> English / Russian
English / Arabic
English / Hebrew
Select one — a new buffer opens with a full contract template (~10 articles).
Or specify the pair directly:
:Bilingual new en-ru
:Bilingual new en-ar
:Bilingual new en-hePress <leader>bs in a markdown file to insert an empty bilingual section at the cursor:
::: {.bilingual}
::: {.col}
:::
::: {.col}
:::
:::If the file already contains RTL content (Arabic/Hebrew), the second column automatically gets dir=rtl lang=ar/he.
:Bilingual pdf " export to PDF
:Bilingual docx " export to Word
:Bilingual " export bothOutput goes to ~/Documents/bilingual-exports/.
Or from the command line:
./export.sh document.md # PDF + DOCX
./export.sh document.md --pdf # PDF only
./export.sh document.md --docx # DOCX onlyWrap bilingual sections in ::: {.bilingual} with two ::: {.col} children:
---
title:
- "Sale and Purchase Agreement"
- "Договор купли-продажи"
date: "February 26, 2026"
---
::: {.bilingual}
::: {.col}
### Article 1. Definitions
"Agreement" means this Sale and Purchase Agreement.
:::
::: {.col}
### Статья 1. Определения
«Договор» означает настоящий Договор купли-продажи.
:::
:::Text outside .bilingual blocks spans the full page width — useful for signatures, document headers, and notes.
Add dir=rtl and lang= to the .col div:
::: {.bilingual}
::: {.col}
### Article 1. Definitions
:::
::: {.col dir=rtl lang=ar}
### المادة 1. التعريفات
:::
:::| Attribute | Effect |
|---|---|
dir=rtl |
Right-to-left text direction |
lang=ar |
Arabic font (Geeza Pro) |
lang=he |
Hebrew font (Arial Hebrew) |
Font switching is automatic — PT Serif is the main font with Geeza Pro (Arabic) and Arial Hebrew (Hebrew) as fallbacks via luaotfload. When LuaLaTeX encounters Arabic or Hebrew characters, it switches to the appropriate font automatically. This means Arabic text in document titles also renders correctly.
For better display of Arabic/Hebrew in the editor, enable terminal bidi:
" init.vim
set termbidi-- init.lua
vim.opt.termbidi = trueThis delegates bidirectional text rendering to the terminal. With termbidi, Arabic and Hebrew characters display in correct reading order. However, terminals always start lines from the left margin — full RTL paragraph alignment is not available. For correct RTL layout, use the PDF/DOCX export.
Note on RTL in editors: No terminal or markdown editor fully supports RTL paragraph alignment for pandoc fenced divs. Arabic/Hebrew character order displays correctly in Typora and Terminal.app, but text remains left-aligned. Ghostty, iTerm2, and Neovide show reversed characters. For correct RTL layout with right-to-left alignment, use the PDF/DOCX export — the editor is for writing, the export is for reading.
The plugin also provides syntax highlighting for bilingual blocks and folding (zc to fold, zo to open, zM/zR for all). Set conceallevel=1 for a compact view that replaces ::: {.bilingual} markers with minimal glyphs.
Mark changes directly in markdown using CriticMarkup syntax:
The price shall be {--USD 50,000--}{++USD 75,000++}.
This Agreement {~~shall~>may~~} be terminated.
{>>Consider adding force majeure clause here<<}| Syntax | Meaning | Redline rendering |
|---|---|---|
{++text++} |
Addition | Green underline |
{--text--} |
Deletion | Red strikethrough |
{~~old~>new~~} |
Substitution | Red strikethrough + green underline |
{>>comment<<} |
Comment | Yellow italic in brackets |
{==text==} |
Highlight | Yellow background |
:Bilingual pdf " redline — show changes (default)
:Bilingual accept pdf " clean — accept all changes
:Bilingual accept " clean PDF + DOCXFrom the command line:
./export.sh document.md --pdf # redline
./export.sh document.md --pdf --accept # clean version| Command | Description |
|---|---|
:Bilingual new |
Create contract from template (interactive menu) |
:Bilingual new en-ru |
Create EN-RU contract directly |
:Bilingual new en-ar |
Create EN-AR contract (Arabic RTL) |
:Bilingual new en-he |
Create EN-HE contract (Hebrew RTL) |
:Bilingual section |
Insert empty bilingual section at cursor |
:Bilingual pdf |
Export current file to PDF |
:Bilingual docx |
Export current file to DOCX |
:Bilingual |
Export to both PDF and DOCX |
:Bilingual accept |
Export clean version (accept all changes) |
:Bilingual accept pdf |
Clean PDF only |
:Bilingual redline |
Export with visible changes (default) |
All commands have tab-completion.
| Key | Mode | Action |
|---|---|---|
<leader>bs |
Normal | Insert bilingual section at cursor |
<leader>ba |
Visual | Mark selection as addition {++...++} |
<leader>bd |
Visual | Mark selection as deletion {--...--} |
<leader>bc |
Visual | Add comment {>>...<<} |
Active only in markdown/mdx files.
Three templates are included, each with ~10 articles:
| Template | Languages | Jurisdiction |
|---|---|---|
en-ru |
English + Russian | configurable |
en-ar |
English + Arabic (RTL) | UAE |
en-he |
English + Hebrew (RTL) | Israel |
Each template includes: definitions, subject, price and payment, term and termination, representations and warranties, liability, confidentiality, force majeure, governing law, general provisions, and signature blocks.
All placeholder values are marked with [___] for easy find-and-replace.
- Pandoc reads markdown and applies the Lua filter (
filter/bilingual.lua) - The filter collects consecutive
.bilingualblocks intoparacolenvironments - Each section pair uses
\switchcolumn*for vertical synchronization luaotfloadfallback auto-switches fonts for Arabic/Hebrew charactersparacolhandles page breaks within parallel columns — no empty gaps- LuaLaTeX with
babel(bidi=basic) renders the final PDF with correct paragraph-level bidirectional text
- Same Lua filter, but generates two-column tables instead of paracol
- RTL content is wrapped in
Divelements withdir="rtl"attribute - Pandoc converts to DOCX with proper table formatting
| File | Languages |
|---|---|
example/contract.md |
English + Russian |
example/contract-ar.md |
English + Arabic (RTL) |
example/contract-he.md |
English + Hebrew (RTL) |
./export.sh example/contract.md
./export.sh example/contract-ar.md
./export.sh example/contract-he.mdnvim.bilingual/
├── plugin/bilingual.lua -- bootstrap, commands
├── lua/bilingual/
│ └── init.lua -- new, section, export, keymaps
├── after/syntax/
│ └── markdown.vim -- bilingual block highlighting + conceal
├── filter/
│ └── bilingual.lua -- pandoc Lua filter (paracol + tables)
├── templates/
│ ├── bilingual.latex -- LaTeX template (fonts, paracol, babel bidi)
│ └── contracts/
│ ├── en-ru.md -- English / Russian template
│ ├── en-ar.md -- English / Arabic template
│ └── en-he.md -- English / Hebrew template
├── example/
│ ├── contract.md -- EN-RU example
│ ├── contract-ar.md -- EN-AR example (RTL)
│ └── contract-he.md -- EN-HE example (RTL)
├── assets/ -- screenshots for README
├── export.sh -- CLI export script
└── README.md


