Apps SDK — WPF
Make your WPF app multilingual with one line of code. The SDK translates your UI live, caches translations on disk for instant offline startup, and never breaks your app — every failure falls back to the original text.
Not using WPF? Cross-platform desktop apps use the Avalonia SDK, and any other language or framework can integrate through the REST API directly.
Quick start
- Create an app project in the dashboard and copy your API key.
- Install the SDK package (the SDK is in preview, so
--prereleaseis required):
dotnet add package Transable.Sdk.Wpf --prerelease
The package lives on NuGet: Transable.Sdk.Wpf (the WPF adapter) pulls in Transable.Sdk, the UI-framework-agnostic core.
- Add one line to your
App.xaml.cs:
using Transable.Sdk.Wpf;
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
TransableWpf.Init("tk_live_yourKeyHere");
base.OnStartup(e);
}
}
That's the whole integration. On startup the SDK detects the user's OS language, discovers your
windows (a sweep of Application.Current.Windows plus a class handler
on Window.Loaded, so new windows are picked up automatically) and
translates static UI text: TextBlock.Text, string
Content / Header values (buttons,
menu items, group boxes, tab headers), Window.Title, and
ToolTip strings. _File-style
access keys are preserved.
Modes
The default is Magic mode: everything that is safe to translate gets translated, and you only mark what should stay untouched. Other modes are available through TransableOptions:
- Magic (default) — automatic translation of static UI text.
- Manual — you call
Transable.T("key", "Fallback text")for each string. - SemiAuto — only windows and containers you explicitly mark with
tr:Transable.Scope="True"are translated. - ApiOnly — use the translation client and cache without any UI scanning.
- WebView — reserved for hybrid apps; not available yet.
TransableWpf.Init("tk_live_yourKeyHere", new TransableOptions
{
Mode = TransableMode.Manual, // Magic is the default
DefaultLanguage = "de", // null = detect from the OS
});
Marking text: Ignore, Key, Force
Attached properties control translation per element (and per logical subtree). Add the namespace once:
<Window xmlns:tr="https://transable.to/sdk/wpf">
<!-- Never translate this element or its children -->
<TextBlock Text="Build v2.4.1-beta" tr:Transable.Ignore="True" />
<!-- Stable key: the fallback text can change without re-keying -->
<TextBlock Text="Welcome back!" tr:Transable.Key="home.greeting" />
<!-- Translate even if Safe mode would normally skip it -->
<TextBlock Text="RC1" tr:Transable.Force="True" />
</Window>
The value set closest to the element wins: a local Force="True" on a
descendant overrides an inherited Ignore="True" and vice versa; when
both are set on the same element, Force wins. The scanner honors
values set locally (a XAML attribute or SetValue from code) — values
coming from styles are not picked up as subtree markers.
Language selector
The SDK ships a ready-made selector control fed by your project's enabled languages (native names and flags included). Place it anywhere in your layout:
<tr:TransableLanguageSelector />
Or switch languages programmatically:
Transable.Sdk.Transable.SetLanguage("de");
var current = Transable.Sdk.Transable.CurrentLanguage;
Transable.Sdk.Transable.LanguageChanged += (_, e) => Console.WriteLine($"Now in {e.NewLanguage}");
(In code the core entry point is qualified as Transable.Sdk.Transable
because the WPF namespace also contains a Transable class — the
attached properties above.) The user's choice is persisted and restored on the next launch.
Safe mode
Safe mode is on by default. It filters out strings that should never be sent for translation, before anything leaves the user's machine:
- user input —
TextBox.Textis never read or sent anywhere, not even withTransable.Force(WPF has no built-in watermark, so input controls have nothing to translate); - emails, URLs, file paths, GUIDs, and version numbers;
- pure numbers, punctuation, and strings without letters;
- log-like lines (leading timestamps) and code-like identifiers such as
PascalCaseNames— while single words like "Save" or "Cancel" still translate normally.
An honest limitation: in MVVM apps, Magic mode translates the static "chrome" of your
interface — text set in XAML or from code. Properties with an active binding are skipped on
purpose: it keeps translations from fighting your ViewModel and guarantees bound user data (names,
emails, documents) never reaches the translation server. The same applies to values coming from
styles, templates, or triggers (only plain local values are ever rewritten) and to
ItemsSource-generated items — rows of lists, grids, and combo boxes
are data, not chrome. For bound content, use Transable.T("key", "Fallback") in your ViewModel.
Offline cache
Every translation is cached on disk (per language, under %LocalAppData%/Transable/cache).
The second launch of your app is translated instantly from the local cache — even fully offline.
The cache is content-addressed: when you change a string, only that string is retranslated.
Limits and error behavior
The SDK is built around one rule: it never crashes, never throws into your code, and never blocks your UI thread. Whatever happens, users see the original text. It is also unconditionally inert in the XAML designer.
- Network errors, timeouts, or server failures — the original text stays, translation retries quietly in the background.
- Rate limits (HTTP 429) — the SDK honors
Retry-Afterand pauses; queued texts are not lost. - Monthly quota exhausted — network translation pauses until the next day; cached translations keep working.
- Invalid or revoked key — translation is disabled for the session with a single warning through the optional logger.
Rate limits are per API key across your whole install base. If your app has many simultaneous first-time users, consider the Advanced plan.
Troubleshooting
- Nothing is translated: check that the API key is correct and active on the project page, and that the target language is enabled for your project.
- The setup page never shows "Connected": run the app once with the
TransableWpf.Initline in place; corporate proxies or firewalls may blockhttps://transable.to. - A string that should stay untouched gets translated: mark it with
tr:Transable.Ignore="True". - Bound text is not translated: that's Safe mode by design — see Safe mode and use
Transable.T()for ViewModel strings.
Still stuck? Contact support — include your project name and the SDK version.