Skip to content

piotr-bienkowski/XLIFF2Editor

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

42 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Xliff 2 Editor

Overview

A PyQt6-based graphical XLIFF editor for professional translation workflows. Supports XLIFF 2.0, 2.1, and 2.2 files. Provides tag-aware editing, AI/MT translation via multiple providers (Claude, Gemini, OpenAI, DeepL), translation memory (TMX) support, spell checking, SDL Trados SDLXLIFF conversion, memoQ MQXLIFF conversion, bilingual Excel import/export, and automatic light/dark theme switching.

**A note for Windows users: ** To clone this repository, first you need to install the git binary for Windows (Git Guides - install git Β· GitHub) and then open a command line window (cmd) and enter the following:

git clone https://github.com/piotr-bienkowski/XLIFF2Editor.git

Running the Editor

From any directory:

python -m XLIFF2Editor

Or from inside the XLIFF2Editor directory:

python Xedaibt.py

The application detects the system theme at startup and applies light or dark mode automatically. The theme can be toggled manually at any time via Options β†’ Switch to Light/Dark Theme.


Dependencies

Python Packages (Required)

Package Purpose
PyQt6 GUI framework
beautifulsoup4 XML/XLIFF parsing
lxml XML processing (used by BeautifulSoup and converters)
fuzzywuzzy Fuzzy string matching for TM lookups

Python Packages (Optional)

AI/MT translation, spell checking, and Excel import/export are optional features. Install only the packages for the functionality you intend to use.

Package Provider/Feature Purpose
anthropic Claude Claude API client
google-generativeai Gemini Google Gemini API client
openai OpenAI OpenAI API client
deepl DeepL DeepL MT API client
pyenchant β€” Spell checking (gracefully disabled if missing)
openpyxl Excel Read/write Excel workbooks (.xlsx)
regex Excel Unicode-aware SRX segmentation (falls back to stdlib re if missing)

System Dependencies

Dependency Purpose
Enchant dictionaries (e.g., hunspell-pl, hunspell-en-us) Language dictionaries for spell checking

Companion Modules

Module Purpose
sdlxliff_xliff22_converter.py Converts SDL Trados SDLXLIFF files to XLIFF 2.2
xliff22_to_sdlxliff_batch_merger.py Merges XLIFF 2.2 translations back into SDLXLIFF files
mqxliff_xliff22_converter.py Converts memoQ MQXLIFF files to XLIFF 2.2
xliff22_to_mqxliff_merger.py Merges XLIFF 2.2 translations back into MQXLIFF files
excel_xliff22_converter.py Converts bilingual Excel workbooks to XLIFF 2.2
xliff22_to_excel_merger.py Merges XLIFF 2.2 translations back into Excel
srx_segmenter.py SRX 2.0 sentence segmenter (used by Excel converter)
segment.srx SRX 2.0 segmentation rules

Installation

pip install PyQt6 beautifulsoup4 lxml fuzzywuzzy

For AI/MT translation, install the client(s) for the provider(s) you want to use:

pip install anthropic                # Claude
pip install google-generativeai      # Gemini
pip install openai                   # OpenAI
pip install deepl                    # DeepL

For Excel import/export:

pip install openpyxl regex

For spell checking dictionaries (Debian/Ubuntu):

sudo apt install libenchant-2-2 hunspell-en-us hunspell-pl

Configuration Files

File Purpose
~/XLIFF2Editor/xconfig.json All settings: API keys, preferences, recent files, context history
~/xliff_editor_glossary.tsv Default glossary (tab-delimited, UTF-8)

All persistent settings are stored in a single file inside the module directory. It is created automatically on first launch. Edit it directly to add API keys.

xconfig.json

{
  "api_keys": {
    "ANTHROPIC_API_KEY": "",
    "GOOGLE_API_KEY": "",
    "OPENAI_API_KEY": "",
    "DEEPL_API_KEY": ""
  },
  "settings": {
    "font_size": 10,
    "underline_color": {"r": 57, "g": 255, "b": 20},
    "ai_provider": "Claude",
    "glossary_file": ""
  },
  "recent_files": [],
  "contexts": []
}

Fill in only the key(s) for the provider(s) you intend to use. glossary_file is optional β€” if empty, ~/xliff_editor_glossary.tsv is used.

Migration from previous versions

On first launch after upgrading, the editor automatically migrates settings from the old ~/.xliff_editor_*.json files and API keys from ~/config.json, then deletes the old files. ~/config.json itself is not deleted (it may be shared with other scripts). GEMINI_API_KEY in the old config is imported as GOOGLE_API_KEY.


Functionalities

File Operations

Feature Shortcut Description
Open XLIFF Ctrl+O Open XLIFF files (.xliff, .xlf)
Open Recent Menu Quick access to recently opened files
Save XLIFF Ctrl+S Save changes to current file
Save As Ctrl+Shift+S Save to a new file location
Close XLIFF Ctrl+W Close current file with save prompt
Exit Ctrl+Q Exit application

SDLXLIFF Conversion (File β†’ SDLXLIFF)

Feature Description
Import from SDLXLIFF Convert one or more SDLXLIFF files to XLIFF 2.2 format
Export to SDLXLIFF Merge XLIFF 2.2 translations back into original SDLXLIFF files

memoQ Conversion (File β†’ memoQ)

Feature Description
Import from memoQ (MQXLIFF) Convert one or more MQXLIFF files to XLIFF 2.2 format
Export to memoQ (MQXLIFF) Merge XLIFF 2.2 translations back into original MQXLIFF files

Bilingual Excel Conversion (File β†’ Excel)

Feature Description
Import from Excel Convert a bilingual Excel workbook (.xlsx) to XLIFF 2.2 for editing
Export to Excel Merge XLIFF 2.2 translations back into the original Excel file in-place

An Import dialog lets you specify:

Setting Default Description
Source language en-US BCP-47 language tag for the source column
Target language pl-PL BCP-47 language tag for the target column
Source column A Excel column letter(s) containing source text
Target column B Excel column letter(s) where translations will be merged
First data row 2 First row number containing translatable content (skips header rows)
Segment source off When checked, splits source cells into sentence-level units using SRX 2.0 rules

After import, the XLIFF is offered for saving under the original filename with a .xlf extension.

Round-trip metadata is stored in the XLIFF so the merger knows where to write each translation back:

  • x-excel-row on each <unit> β€” the 1-based Excel row number the segment came from
  • x-excel-src-col / x-excel-tgt-col on <file> β€” the source and target column letters

Segmentation (Segment source checkbox):

When segmentation is enabled, long source cells are split into sentence-level <unit> elements using SRX 2.0 rules (segment.srx). Multiple units from the same cell share the same x-excel-row and are joined back on export. Alt+Enter line breaks (\n) within a cell are handled separately from SRX rules:

  • \n followed by an uppercase letter is treated as a segment boundary regardless of punctuation.
  • \n followed by a lowercase letter (a typographic line wrap within a sentence) is preserved as an inline <ph equiv="\n"/> tag.

On export, the merger reconstructs the original cell structure: segments are joined with a space for SRX-based boundaries and with \n for Alt+Enter boundaries. Inline <ph equiv="\n"/> tags in translated segments are converted back to \n characters in the Excel cell.

The memoQ converter handles XLIFF 1.2 files with the MQXliff namespace extension as exported by memoQ. Inline tags (bpt/ept flat pairs, g, ph, x) are converted to XLIFF 2.2 pc/ph elements for editing and converted back on export. The mq:status attribute is mapped to/from XLIFF 2.2 state using the values defined in MQXliffSchema-4-0-21.xsd.

Translation Memory (TMX)

Feature Shortcut Description
Load TMX Ctrl+T Load a TMX file for fuzzy matching
TM Matching Automatic Displays matches β‰₯ 70% similarity in the right panel
Insert TM Match Double-click Overwrites target with the selected TM match
Insert Glossary Term Single-click Inserts the translation at cursor (does not overwrite)

The right panel shows two sections when a segment is selected:

  1. TM matches β€” sorted by score descending, format 85% β€” translation. Double-clicking a match overwrites the entire target.
  2. Glossary matches β€” terms from the loaded glossary file that appear in the source segment, format source term β€” translation. Single-clicking inserts the translation at the current cursor position in the target editor. If the editor is not focused, the translation is appended to the existing target text.

A greyed-out ── glossary ── separator divides the two sections when both are present.

TMX loading uses lxml.etree.iterparse β€” the file is streamed element by element and each parsed node is discarded immediately after use, keeping memory consumption flat at approximately 1Γ— the file size regardless of how large the TMX is.

Segment Filter Bar

A filter bar sits between the AI toolbar and the segment table. It hides non-matching rows in real time without modifying the file.

Control Description
Filter source… Show only segments whose source text contains the entered string
Filter target… Show only segments whose target text contains the entered string
AND / OR When both fields are filled: AND requires both to match; OR requires either to match
Regex Treat filter strings as regular expressions (Python re syntax, case-sensitive)
πŸ” Apply the filter (Enter in either field also applies)
βœ• Clear both fields and show all rows
  • Filtering is case-insensitive in plain-text mode and case-sensitive in Regex mode.
  • Batch operations (AI Translate All, Copy All Sources to Targets, Clear All Targets) operate only on the visible (non-hidden) rows while a filter is active.
  • The filter is cleared automatically when a file is opened or closed.

Editing

Feature Shortcut Description
Insert Next Tag Ctrl+N Insert the next missing tag from source
Clear Current Target Ctrl+D Clear target text of selected segment
Clear All Targets Ctrl+Shift+D Clear all target segments (with confirmation)
Set Status to Translated Ctrl+E Mark current segment as translated
Copy Source to Target Alt+S Copy source text to target for current row
Copy All Sources to Targets Ctrl+Shift+C Copy all source texts to targets

Language Management

Feature Shortcut Description
Set Target Language Ctrl+L Set or change target language code
Edit Languages Ctrl+Shift+L Edit both source and target language codes

AI / MT Translation

Feature Shortcut Description
AI Translate Current Ctrl+Shift+A Translate current segment with the selected provider
AI Translate All Initial Ctrl+Shift+T Batch translate all untranslated segments

The AI toolbar at the top of the window contains two controls:

  • AI selector β€” choose the active provider (saved between sessions)
  • Context field β€” optional free-text context injected into every prompt (editable combo box with history; expands to fill remaining toolbar width)
Provider Key in xconfig.json Model used
Claude ANTHROPIC_API_KEY claude-sonnet-4-20250514
Gemini GOOGLE_API_KEY gemini-2.0-flash
OpenAI OPENAI_API_KEY gpt-4o-mini
DeepL DEEPL_API_KEY DeepL MT

Rate limiting: all providers are throttled to a maximum of one API call per second.

Completion dialog: shown after batch translation only; single-segment translation gives no dialog.

Glossary: loaded from a tab-delimited file (source term TAB target term, one pair per line, UTF-8). Only terms that actually appear in the source segment are included in the prompt β€” this prevents the model from reproducing the entire glossary instead of translating. Switch the glossary file at runtime via Options β†’ Load Glossary…

Context history: each context string used for translation is saved to xconfig.json. Reselect previous contexts from the toolbar dropdown without retyping.

DeepL note: tags (<1>, </1>, <2/>) are temporarily renamed to valid XML names before sending to the DeepL API and restored afterwards. DeepL does not use the glossary file.

DeepL language codes: most target languages use the 2-letter code (PL, DE…). English and Portuguese require a regional variant (EN-US, EN-GB, PT-BR, PT-PT) and are converted automatically from the XLIFF trgLang attribute.

UI Customization

Feature Description
Change Font Size Adjust font size (6–24pt)
Change Spell Check Underline Color Customize the color of spell check underlines (dark mode only)
Load Glossary… Switch the active glossary TSV file at runtime
Switch to Light/Dark Theme Toggle between light and dark theme; system theme is applied on launch

Spell Checking

  • Automatic spell checking for target segments
  • Wavy underline for misspelled words (configurable color)
  • Right-click context menu with spelling suggestions
  • Add words to personal dictionary
  • Supports multiple languages via enchant dictionaries

Tag Protection

The custom editor (TagProtectedTextEdit) provides:

  • Visual highlighting of tags in red bold text
  • Protection against accidental tag modification
  • Tags displayed as simplified tokens: <1>, </1>, <1/>
  • Cursor navigation around protected tag regions

Segment Locking

  • Locked segments (translate="no") are displayed with a πŸ”’ padlock icon
  • Locked segments cannot be edited
  • Grey text and darker background indicate locked status

UI Layout

+-------------------------------------------------------------------+
| Menu Bar: File | Tasks | Options                                   |
+-------------------------------------------------------------------+
| AI: [Claude β–Ό]  Context: [context text...               β–Ό]        |
+-------------------------------------------------------------------+
| ID  | πŸ“„ | Source              | Target         | Status | Matches|
|-----+----+---------------------+----------------+--------|--------|
| 1   | πŸ“„ | Source text here    | Translation    | initial| 85% —… |
| 2   | πŸ“„ | Another segment...  | ...            | transl.| stud —…|
+-------------------------------------------------------------------+
  • AI selector β€” choose provider; persisted between sessions
  • Context field β€” free-text context appended to every translation prompt; previous values available in the dropdown
  • ID β€” segment identifier from the XLIFF file; πŸ”’ prefix for locked segments
  • πŸ“„ β€” file column; hover to see the full file ID in a tooltip
  • Source β€” read-only source text with inline tag highlighting
  • Target β€” editable target text with tag protection and spell checking
  • Status β€” XLIFF state attribute value
  • Right panel β€” TM matches (double-click to overwrite) followed by glossary matches (single-click to insert at cursor)

Supported File Formats

Input/Output

  • XLIFF 2.0, 2.1, 2.2 (.xliff, .xlf) β€” native format
  • TMX (.tmx) β€” translation memory (read-only)

Via Converter Modules

  • SDLXLIFF (.sdlxliff) β€” SDL Trados format (import/export)
  • MQXLIFF (.mqxliff) β€” memoQ format (import/export)
  • Excel (.xlsx) β€” bilingual workbook format (import/export)

Classes Overview

Class Purpose
TagProtectedTextEdit Custom QPlainTextEdit with tag protection and spell checking
RichTextDelegate Qt delegate for rendering tags in red within table cells
TMXLoadThread Background thread for loading TMX files
XLIFFLoadThread Background thread for loading XLIFF files
AITranslationThread Background thread for AI translation operations
XLIFFEditor Main application window and controller (XLIFF2Editor package)

Status Value Mappings

SDLXLIFF β†’ XLIFF 2.2

SDL Status XLIFF 2.2 State
Draft initial
Translated translated
ApprovedTranslation translated
ApprovedSignOff final
RejectedTranslation needs-review-translation
RejectedSignOff needs-review-translation

XLIFF 2.2 β†’ SDLXLIFF

XLIFF 2.2 State SDL Status
initial Draft
translated Translated
reviewed ApprovedTranslation
final ApprovedSignOff
needs-review-* RejectedTranslation

memoQ β†’ XLIFF 2.2

memoQ status XLIFF 2.2 state
NotStarted initial
PreTranslated translated
PartiallyEdited translated
ManuallyConfirmed final
AssembledFromFragments translated
AutoJoined translated
AutoSplit initial
AutoSplitAndEmpty initial
Ackknowledged (schema) reviewed

XLIFF 2.2 β†’ memoQ

XLIFF 2.2 state memoQ status
initial NotStarted
translated PartiallyEdited
reviewed Ackknowledged
final ManuallyConfirmed
needs-review-* PartiallyEdited

Converter Module: sdlxliff_xliff22_converter.py

Converts SDLXLIFF (SDL Trados) files to XLIFF 2.2 format.

python sdlxliff_xliff22_converter.py input.sdlxliff -o output.xlf
python sdlxliff_xliff22_converter.py *.sdlxliff -o merged.xlf

Using the converter from your own script

Import directly from the XLIFF2Editor package:

from XLIFF2Editor.sdlxliff_xliff22_converter import convert_sdlxliff_to_xliff22
from pathlib import Path

# Convert a single file
stats = convert_sdlxliff_to_xliff22(
    input_paths=["project.sdlxliff"],
    output_path="project.xlf",
)
print(f"Converted {stats['total_segments']} segments from {stats['total_files']} file(s).")

# Merge an entire job package into one XLIFF for batch translation
sdlxliff_files = sorted(Path("job/").glob("*.sdlxliff"))
stats = convert_sdlxliff_to_xliff22(
    input_paths=sdlxliff_files,
    output_path="job/merged.xlf",
    verbose=False,  # suppress progress output
)

The function returns a dict with at least total_segments and total_files. Set verbose=False to suppress console output when calling from a pipeline.

Converter Module: xliff22_to_sdlxliff_batch_merger.py

Merges XLIFF 2.2 translations back into original SDLXLIFF files.

python xliff22_to_sdlxliff_batch_merger.py merged.xlf \
    --sdlxliff-dir ./originals \
    --output-dir ./updated

Converter Module: mqxliff_xliff22_converter.py

Converts memoQ MQXLIFF (XLIFF 1.2 + MQXliff namespace) files to XLIFF 2.2 format.

python mqxliff_xliff22_converter.py input.mqxliff -o output.xlf
python mqxliff_xliff22_converter.py *.mqxliff -o merged.xlf

Using the converter from your own script

from XLIFF2Editor.mqxliff_xliff22_converter import convert_mqxliff_to_xliff22
from pathlib import Path

stats = convert_mqxliff_to_xliff22(
    input_paths=["project.mqxliff"],
    output_path="project.xlf",
)
print(f"Converted {stats['total_segments']} segments from {stats['total_files']} file(s).")

Inline tag handling

memoQ uses bpt/ept as flat siblings (not nested) to mark paired codes such as bold or italic. The converter collects the tail text of bpt and all content until the matching ept and wraps it in an XLIFF 2.2 pc element. g elements are converted to pc directly; ph, x, and it become ph. On export back to MQXLIFF, pc is written as g and ph as x.


Converter Module: xliff22_to_mqxliff_merger.py

Merges XLIFF 2.2 translations back into original MQXLIFF files.

python xliff22_to_mqxliff_merger.py merged.xlf \
    --mqxliff-dir ./originals \
    --output-dir ./updated

File matching uses exact filename lookup (the file ID in XLIFF 2.2 is set to the original MQXLIFF filename), with case-insensitive fallback. Updated files are written to --output-dir; originals are not modified.


Converter Module: excel_xliff22_converter.py

Converts a bilingual Excel workbook (.xlsx) to XLIFF 2.2. Can be used standalone or via the File β†’ Excel β†’ Import from Excel menu.

Using the converter from your own script

from XLIFF2Editor.excel_xliff22_converter import convert_excel_to_xliff22

stats = convert_excel_to_xliff22(
    input_path="brochure.xlsx",
    output_path="brochure.xlf",
    src_lang="en-US",
    tgt_lang="pl-PL",
    src_col="A",        # column letter(s) for source text
    tgt_col="B",        # column letter(s) for target text
    first_row=2,        # first data row (skip header)
    segment=True,       # split cells into sentence-level units
    srx_path=None,      # defaults to segment.srx next to this file
)
print(f"Converted {stats['total_rows']} rows into {stats['total_units']} units.")

Newline handling

Excel cells often contain Alt+Enter (\n) line breaks. The converter handles them in two ways:

  • \n before an uppercase letter β€” treated as a segment boundary. The text is pre-split at this point before SRX rules are applied. The boundary is marked with a trailing <ph equiv="\n"/> on the last sentence of the preceding block.
  • \n before a lowercase letter β€” a typographic line wrap within a sentence. Preserved as an inline <ph equiv="\n"/> in the <source> element.

This ensures that cells like "Sentence one.\nBecause of this." and "Title line\ncontinued in lower case" are handled correctly on both import and export.


Converter Module: xliff22_to_excel_merger.py

Merges XLIFF 2.2 translations back into the original Excel workbook in-place (target column only).

Using the merger from your own script

from XLIFF2Editor.xliff22_to_excel_merger import merge_xliff22_to_excel

result = merge_xliff22_to_excel(
    xliff_path="brochure.xlf",
    excel_path="brochure.xlsx",   # modified in-place
)
print(f"Written {result['rows_written']} row(s), skipped {result['units_skipped']}.")

The merger reads x-excel-tgt-col from the XLIFF <file> element to determine which Excel column to write to, so the correct column is always used regardless of what was entered in the import dialog. It raises ValueError if the XLIFF was not produced by convert_excel_to_xliff22.

Newline reconstruction

Segment boundaries that originated from Alt+Enter line breaks are identified by a trailing <ph> on the source element (empty tail, any equiv value β€” translation tools may change equiv="\n" to a space). Such boundaries are joined with \n in the merged cell; SRX-based sentence boundaries are joined with a space. Trailing <ph> tags are stripped from the target text before writing. Inline <ph equiv="\n"/> tags within a target are converted back to \n.

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Packages

 
 
 

Contributors

Languages