vTrans bundles several text-processing APIs behind a single interface, stores the results in the database, and provides backend pages for testing, analysis, and maintenance.
The primary use case is translation. With LLM-based providers (for example the OpenAI provider), it can also be used for other scenarios where the source and target language are the same, for example summarizing, rephrasing, or editing content.
Note: vTrans is currently in an early beta phase. Production use is only recommended after appropriate testing and close monitoring.
Install it via the REDAXO installer (not yet available) or copy it manually to redaxo/src/addons/vtrans and activate it in the backend.
Requirements:
- REDAXO >= 5.17.0
- PHP >= 8.2
- In the backend, open
vTrans -> Connectionsand create a connection. - Select a provider (for example
deepl-api-free-v2,openai, orgoogle-translate-basic-v2). - Enter the API key, API URL, and any additional parameters.
- Optionally mark it as the default and/or enable it for the Playground.
- Open
vTrans -> Playgroundand test it.
Example for a DeepL Free connection:
- Key:
deepl_free - Label:
DeepL Free - Provider:
deepl-api-free-v2 - API URL:
https://api-free.deepl.com/v2/translate - API Key:
YOUR_DEEPL_KEY
Notes:
- Free keys belong to the free API URL
https://api-free.deepl.com/v2/translate. - The default connection is used automatically when no
connectionvalue is passed in the request.
- Access several providers through one unified API
- Manage connections centrally in the backend
- Test requests manually in the Playground
- DB cache is monitored via string hash, connection, language, and format
- Stable keys (optional) for reusable content
- Search, filter, review, and edit stored records under
Data - Keep provider metadata such as usage or rate limits as raw data
- Market leader with very good quality for common languages
deepl-api-free-v2deepl-api-pro-v2- Supports
contextandcustomInstructions
- Good to very good translation quality
amazon-translate-v1- API-key-/credential-based depending on the provider implementation
- Good to very good translation quality
google-translate-basic-v2- API-key-based
- No prompt options
- Very good translation quality
- Service-account / OAuth-based
- No prompt options
- Good quality - sufficient for most use cases
- Open source - can also be self-hosted
libretranslate-v1- Optional
apiKey - No prompt options
- Simple, rather technical translation
mymemory-v2- Endpoint-based (default:
https://api.mymemory.translated.net/get) - Optional
apiKeyandemail - No prompt options
- Flexible depending on the model
openai- Freely configurable endpoints and parameters
- Supports
contextandcustomInstructions
- Useful during development
- Generates simple test output to verify the functionality
- Local only - no API - no costs
The costs of the different providers vary widely and usually consist of a monthly base fee (subscription) and costs per 1 million characters. There are also often free or included quotas. This is something everyone needs to compare for themselves. LibreTranslate can also be self-hosted on suitable hardware. For a large website, you should expect around 20–50 EUR per language (of course only a rough estimate).
Configuration is done via the backend page Connections. There, connections are defined. Depending on the interface, the corresponding details are stored:
- Key (identification)
- Label (name)
- Provider / API (provider / interface)
- Debug flag
- Timeout
- Max. characters
- Playground flag (available in the Playground)
- Various provider-specific parameters
Notes:
- The default connection is used automatically when no individual
Connectionis defined in the request. - The default connection and availability in the Playground can be switched quickly in the Connections overview.
Requests can be tested manually here.
- Connection
- Source and target language
- Format (
textorhtml) - Text
- Optional key
- Additional
contextandcustomInstructionswhere supported
If a key is set, vTrans works with a stable dataset per model and target language.
- If an entry with the same hash already exists, it is reused.
- If the content has changed, the existing key-based record is updated.
- Without a key, only the normal cache based on hash, connection, language, and format is used.
vTrans uses the namespace FriendsOfRedaxo\VTrans.
use FriendsOfRedaxo\VTrans\VTrans; // Namespace for the VTrans class
$translated = VTrans::translate(
'<p>Hello world</p>', // content to translate
'en', // source language (also 'auto' possible)
'de', // target language
'html', // format (text or html)
'homepage_hero', // optional key
[ // additional optional parameters
'connection' => 'deepl_free', // connection (otherwise the default connection is used)
'context' => 'Marketing headline', // additional context (if supported)
'customInstructions' => [ // additional instructions (if supported)
'Use formal tone.',
'Keep HTML tags unchanged.',
],
]
);
echo $translated;
// Optional debug output
$meta = VTrans::getLastResultMeta();
$data = VTrans::getLastResultData();
dump($meta);
dump($data);Supported request options include:
connection: key of a saved connection (recommended)context: additional context for supported providerscustomInstructions: array or multiline string with additional instructionsdebug: enables provider debug datacache: boolean (trueby default). Withfalse, DB cache lookup and persistence are skipped.
This example simply translates the German original content and outputs it in another language when no content is available for that language — meaning the article is empty.
<?php
use FriendsOfRedaxo\VTrans\VTrans;
// Current language of the REDAXO article context
$curLang = rex_clang::getCurrent()->getCode();
// Content of the current article
$articleContent = $this->getArticle();
// If we are in a non-default language and there is no content yet,
// retrieve the German original content and let vTrans translate it.
if (rex_clang::getCurrentId() !== 1 && $articleContent === '') {
// German original content from the base language (ID 1)
$articleContentOrg = (new rex_article_content(rex_article::getCurrentId(), 1))->getArticle();
$articleContent = VTrans::translate(
$articleContentOrg, // Content to translate
'de', // Source language
$curLang, // Target language
'html', // Format
'artCont-' . rex_article::getCurrentId() // Key for better caching
);
}
?>
<!DOCTYPE html>
<html lang="<?php echo htmlspecialchars($curLang, ENT_QUOTES, 'UTF-8'); ?>">
<head>
<meta charset="utf-8">
<title>vTrans Demo</title>
</head>
<body>
<h1>vTrans Demo</h1>
<!-- Simple language switcher for the demo -->
<nav>
<?php foreach (rex_clang::getAll(true) as $lang): ?>
<?php if ($lang->getValue('id') === rex_clang::getCurrentId()): ?>
| <strong><?php echo htmlspecialchars($lang->getValue('name')); ?></strong>
<?php else: ?>
| <a href="<?php echo rex_getUrl($this->getValue('article_id'), $lang->getValue('id')); ?>">
<?php echo htmlspecialchars($lang->getValue('name')); ?>
</a>
<?php endif; ?>
<?php endforeach; ?>
</nav>
<?php echo $articleContent; ?>
</body>
</html>In this example, only the actual content is translated. Other parts such as navigation, footer, meta data, etc. can be translated in the same way. For navigation, manual translation is often recommended, because this often also affects the URL.
With cache => false, a request can be executed directly via the API without first checking the database and without saving the result afterwards.
$translated = VTrans::translate(
$text,
'de',
'en',
'text',
null,
[
'connection' => 'openai_default',
'cache' => false,
]
);
$meta = VTrans::getLastResultMeta();
$data = VTrans::getLastResultData();In no-cache mode:
- no database lookup is performed before the provider call
- no result is stored in
rex_vtrans - raw provider data is still available directly via
VTrans::getLastResultData()
VTrans::getLastResultData() returns the raw data from the last request, such as usage data, rate limits, debug information, or provider-specific metadata.
When using the html format, a provider-independent HTML filter automatically protects certain content before the API call and restores it after translation.
<span translate="no">Thomas König</span>
<span class="notranslate">REDAXO CMS</span><div data-vtrans-exclude>
<script>var config = { lang: 'de' };</script>
<p>This block is not sent to the API.</p>
</div><script>…</script><style>…</style><code>…</code><svg>…</svg>
- Project: https://github.com/FriendsOfREDAXO/vtrans
- Community: https://www.redaxo.org
- Friends Of REDAXO
- Matthias Weiss / VIEWSION.net (Lead)
MIT, see LICENSE.