Export & Import
Translations need to travel: between staging and production, to an external translation agency, to a colleague’s computer for review, to backup storage. PerfLocale supports three formats covering every common use case - pick the one that fits the receiver.
Formats
- XLIFF 2.0 - the industry-standard translation exchange format. Open in any CAT tool (SDL Trados, memoQ, Phrase, Crowdin, etc.) to hand off work to professional translators. Post content, titles, excerpts, + meta fields marked translatable are exported as
<unit>/<segment>elements per the XLIFF 2.0 schema (urn:oasis:names:tc:xliff:document:2.0). - .po / .mo - classic gettext format. Best for exporting string translations (from PerfLocale → Strings) to edit in Poedit or Loco, or to ship as a language pack alongside a theme/plugin.
- JSON - PerfLocale’s own format. Round-trips every plugin-specific field (translation link groups, workflow state, glossary, etc.) with no loss. Use for site-to-site migration or full backups.
Exporting via the admin UI
At Settings → Export & Import:
- Choose what to export (translations / strings / glossary / language definitions / all).
- Optionally filter by post type + language pair.
- Pick a format (XLIFF / PO-MO / JSON).
- Click Download. Small exports stream directly to your browser; large ones queue as a
data_exportbackground job and the admin redirects to PerfLocale → Jobs. When the job completes, a single-use Download button appears on the job row — click it and the export file is streamed to your browser and deleted from the server in the same request. The async/sync split is governed by the data_export threshold under Settings → Performance → Background Thresholds (default: 5,000 translation rows).
Importing via the admin UI
Same page, Import section. Upload a file in any of the supported formats. PerfLocale auto-detects the format from the content, validates it, shows a preview (X rows, Y new, Z updates), and asks for confirmation before writing. Imports are idempotent - re-importing the same file is a no-op on data that hasn’t changed.
Large imports queue automatically via PerfLocale's background-jobs system (Action Scheduler when loaded; WP-Cron otherwise) and the admin redirects to PerfLocale → Jobs for live progress. Small operations still finish inline. The uploaded file is persisted under wp-content/uploads/perflocale-temp/ for the worker to read and is cleaned up on completion.
WP-CLI (faster for large exports)
For sites with tens of thousands of translations, the CLI is still a strong choice (streams directly to disk, runs under your shell's time budget, easy to schedule). Each subcommand writes a single file; format is dictated by the subcommand, not a flag:
# Full-site JSON envelope (everything PerfLocale owns - languages, links,
# strings, glossary, slugs, settings, role caps, workflow state).
# The envelope embeds a `format_version` field so older importers refuse
# mismatched payloads.
wp perflocale export /tmp/full-backup.json
wp perflocale import /tmp/full-backup.json # additive merge
wp perflocale import /tmp/full-backup.json --mode=replace # truncate-then-load
# Gettext PO files for string translations, one language at a time
wp perflocale po-export /tmp/de.po --lang=de
wp perflocale po-export /tmp/de-mytheme.po --lang=de --domain=mytheme
wp perflocale po-import /tmp/de.po --lang=de
wp perflocale po-import /tmp/de.po --lang=de --replace
# Glossary as RFC 4180 CSV (round-trips notes, case-sensitive flag, language pairs)
wp perflocale glossary-export-csv /tmp/glossary.csv
wp perflocale glossary-import-csv /tmp/glossary.csv
wp perflocale glossary-import-csv /tmp/glossary.csv --replace
# Multisite: one envelope keyed by blog ID, all sites at once
wp perflocale network-export /tmp/network.json
wp perflocale network-export /tmp/network.json --include-inactive
wp perflocale network-import /tmp/network.json --mode=replace
wp perflocale network-import /tmp/network.json --site=42 # restore one slice on a single-site target
# XLIFF for translation-agency handoff is exported via the admin UI;
# import the returned XLIFF file with the same `wp perflocale import` command
# (format is auto-detected from file contents).
wp perflocale import /tmp/de-posts.xliff
See WP-CLI Commands → Export & Import for the complete flag reference.
Merge vs. replace semantics
- Merge (default) - additive. Existing rows kept; foreign keys re-mapped via id-maps so cross-site references survive intact. Idempotent on re-run.
- Replace - truncates the target tables (scoped to the current site on multisite) before loading. Use only when you genuinely want to wipe the destination's PerfLocale state first.
Translation-agency handoff pattern
Typical flow when hiring an external agency:
- Export the source post(s) as XLIFF with target language = German (source = your default).
- Agency opens the XLIFF in their CAT tool, fills in translations, returns the file.
- Import the returned XLIFF via UI or CLI. Status of each translation becomes Pending for your review.
- Approve / tweak in the editor, change status to Published.
What isn’t included in exports
The exporter ships everything you need to reconstitute a site’s multilingual configuration and translation data. A small set of things is deliberately left out, because including them would either leak secrets, queue meaningless work on the destination, or duplicate state that’s regenerated automatically:
- API keys / tokens / secrets / passwords — every settings key matching
*_api_key,*_token,*_secret, or*_passwordis stripped from the settings blob before write. The destination operator re-enters them (or supplies them viawp-config.phpconstants / env vars). This is the right behavior for security: a JSON file shouldn’t round-trip your DeepL key through email. - Webhook subscriber URLs — site-specific infrastructure with HMAC secrets; the destination should re-register its own integrations.
- Translation Memory rows — available as an optional section (tick the box in the export UI / pass the section name to CLI). Skipped by default because it’s a runtime cache that rebuilds as you translate.
- Background-jobs queue state — the
jobstable holds operational state with source-site-specific user / post / blog IDs. Importing it would queue meaningless work on the destination. The destination starts with an empty queue and dispatches its own. - Per-user admin UI preferences — user-meta keys like
perflocale_strings_hidden_langsare user-id-specific and not portable across sites with different user tables. - Generated translation files — the
.l10n.phpoutput files inuploads/perflocale/translations/are regenerated fromstrings+string_translationson the destination. Shipping the build artifacts would multiply export size for no benefit. - Internal caches — the addon-failure tracker, the active-engine memo, the eager-link-map, and similar diagnostic / runtime options are auto-rebuilt from the data that is exported.
Cross-site ID remapping
The importer doesn’t blindly insert primary-key values from the export. It resolves language_id references via the language slug, so a German row exported from a site where German has id = 3 lands correctly under whatever id German happens to have on the destination. Same for string_id via original_hash, group IDs via group type + member identity, etc. This is what makes export → import work cleanly between sites that were configured independently.
Format version + compatibility
Every export carries a format_version integer (currently 1). The importer accepts the current version and any older version it knows how to migrate. It refuses newer versions with a clear error rather than risk silent data loss on a partial-format-understanding import. Upgrade the destination plugin first if you see that error.
Related
- WP-CLI Commands
- Migration - from WPML / Polylang / TranslatePress.
- Content Translation