Machine Translation
The Localization Admin page can machine-translate a localization JSON file into one or more languages in a single pass. It's built on a provider-agnostic abstraction — Azure AI Translator, DeepL, and Google Cloud Translation each ship built in — and reuses a Dataverse-backed translation memory, so you only pay to translate each string once. Results download per language or as a single zip, each annotated with how many strings were newly translated versus reused from memory.
Translating a file
Once the feature is configured (see Setup, below), a translate panel appears on the framework's Localization Admin page:
- Upload a file — drag & drop or browse to a localization JSON file such as
app.en.json. - Confirm the source language — it's auto-detected from the filename's culture segment (
app.en.json) and stays editable. - Pick target languages — every culture your portal supports that the provider can translate is offered; cultures the provider can't translate are shown disabled.
- Translate — strings are sent in batches that respect the provider's per-request limits, and the chosen languages are translated concurrently.
- Download — grab each language on its own or all of them as a zip. Every row reports how many strings were translated versus reused from memory.
Translation memory
Each string the provider translates is stored in Dataverse, keyed by source text, source language, and target language. The next time that same string comes through — in another file, another run, or an edit that leaves it untouched — it's served from memory instead of being re-sent. Because providers bill per character, this keeps repeat runs and incremental re-translations essentially free, and the per-language result shows the split so you can see exactly what was new.
Setup
The translate panel appears only when both pieces below are in place; otherwise the admin page omits it (or shows a one-line prompt explaining what's missing).
1. Install the translation-memory solution
The translation memory lives in two Dataverse tables provisioned by the PowerPortalsProLocalization managed solution. Download the latest managed solution from the GitHub releases and import it into your environment. The admin page detects the solution by its unique name and only offers translation once it's present.
2. Register a translation provider
Three providers ship ready to use — Azure AI Translator, DeepL, and Google Cloud Translation — each in its own NuGet package so the core framework carries no translation-vendor dependency. Add the package for the service you have a key for and register it next to AddPowerPortalsProWebServer(). For Azure, create a free (F0) or paid Azure AI Translator resource, then register it with your key and region:
// Register the Azure AI Translator provider — leave the key unset to keep the panel hidden
builder.Services
.AddPowerPortalsProWebServer()
.AddPowerPortalsProAzureTranslationService(options =>
{
options.TranslationKey = builder.Configuration["Azure:Translation:Key"];
options.Region = "westus";
});
For DeepL, add the PowerPortalsPro.Web.Server.Translation.DeepL package and register it with your auth key (free-tier keys ending in :fx route to the free endpoint automatically):
// Register the DeepL provider — leave the key unset to keep the panel hidden
builder.Services
.AddPowerPortalsProWebServer()
.AddPowerPortalsProDeepLTranslationService(options =>
{
options.AuthKey = builder.Configuration["DeepL:Translation:Key"];
});
For Google Cloud Translation, add the PowerPortalsPro.Web.Server.Translation.Google package and register it with an API key that has the Cloud Translation API enabled:
// Register the Google Cloud Translation provider — leave the key unset to keep the panel hidden
builder.Services
.AddPowerPortalsProWebServer()
.AddPowerPortalsProGoogleTranslationService(options =>
{
options.ApiKey = builder.Configuration["Google:Translation:Key"];
});
Note
Leaving the key blank is safe: the provider simply isn't registered and the translate panel stays hidden, so the same build runs with or without translation configured.
Bring your own provider
Translation is provider-agnostic. The built-in Azure, DeepL, and Google providers are each an implementation of ITranslationProvider, shipped in their own PowerPortalsPro.Web.Server.Translation.* packages so the core framework carries no translation-vendor dependency. To use a different service — Amazon Translate, an on-prem model, an LLM — implement ITranslationProvider and register it in place of the built-in ones. Everything above it (the admin UI, translation memory, batching, and the translated-vs-reused counts) stays the same.
Blazor and React
The translate panel is a self-contained component on both stacks, so you can host it on your own admin page instead of the framework's. Each loads its own availability data and renders nothing until translation is configured:
// Renders nothing unless a provider is configured and the solution is installed
import { LocalizationTranslator } from '@powerportalspro/react-fluent';
<LocalizationTranslator /><!-- Renders nothing unless a provider is configured and the solution is installed -->
<LocalizationTranslator />Note
Translation runs are bounded automatically: requests are split to stay under the provider's per-request size limits, target languages run with capped concurrency, and throttled (HTTP 429) responses are retried with exponential backoff — so a large multi-language job stays within rate limits on any provider tier without extra configuration.
