Skip to main content

Translation

Buildocs UI Engine supports multi-language interfaces. In most cases you do not need to write any translation code — the frontend sends the active locale with every request, and the loadform endpoint passes the resolved translations straight back.


How it works

The frontend manages the active locale via i18next. When a form opens, the SDK calls fetchFormDefinitionWithMeta against the Buildocs API, passing the current locale. Buildocs resolves the translations for that locale and returns them in the response payload. The FormHostProvider then spreads that payload into the /loadform request body, so uiTranslations arrives at your controller already populated:

// FormHostProvider — no changes needed
runLoadFormEvent: async (args: TLoadForm) => {
const buildocsApiResponse = await buildocsApi.fetchFormDefinitionWithMeta(args.formCode);
const result = await myApi.runLoadForm({...args, ...buildocsApiResponse?.payload}, '/loadform');
return result;
},

The controller receives request.UiTranslations and returns it as-is:

// LoadForm controller — no changes needed
response.Set(HandlerResponse.UiTranslations, request.UiTranslations);

The SDK receives the translations and applies them when rendering the form. Widget labels, button text, and other form content are all translated automatically.


Setting the default locale

Configure the default locale in i18n.ts:

i18n
.use(initReactI18next)
.init({
lng: 'en-US', // active locale — sent with every request
fallbackLng: 'en-US',
resources: { ... }
});

The value of lng is what Buildocs uses to look up translations.


Language switcher

Use the built-in LanguageSwitcher component to let users switch languages at runtime. When the language changes, the SDK reloads the form, which triggers a new fetchFormDefinitionWithMeta call with the updated locale — the correct translations are returned automatically.

import { LanguageSwitcher } from '@buildocsdev/sdk';

<LanguageSwitcher />

If you render a form with key={language}, changing the language forces a full re-mount and re-load:

const { i18n } = useTranslation();

<Form key={i18n.language} params={{ pluginCode, formCode, guid }} />

Translating dynamic dropdown options

The only case where you may need to add translation logic in your handler is for dynamic dropdown options — Buildocs cannot pre-translate values you generate at runtime.

The locale is sent by the SDK as the standard Accept-Language HTTP header. Handlers do not have a Locale property; instead, use the Translate(key) method inherited from AbstractHandler. It reads the header, applies locale fallbacks (fr-FRfren), and looks up the key in your localization JSON files.

Using translation files

Define option labels in your localization files:

// Localization/en.json
{
"status.draft": "Draft",
"status.active": "Active",
"status.closed": "Closed"
}
// Localization/de.json
{
"status.draft": "Entwurf",
"status.active": "Aktiv",
"status.closed": "Geschlossen"
}

Then use Translate() to build the options:

public override async Task Form_onInit(bool isInitialLoad)
{
await base.Form_onInit(isInitialLoad);

cmd.PopulateSelectBoxList("status", new Dictionary<string, string>
{
{ "draft", Translate("status.draft") },
{ "active", Translate("status.active") },
{ "closed", Translate("status.closed") }
});
}

Reading locale for database queries

If you need the raw locale string to query a translations table in your database, inject IHttpContextAccessor into your handler and read the header directly:

public class EventHandler : GenericFormHandler
{
private readonly IHttpContextAccessor _httpContext;

public EventHandler(HandlerContext context, IHttpContextAccessor httpContext) : base(context)
{
_httpContext = httpContext;
}

private string GetLocale()
{
var header = _httpContext.HttpContext?.Request.Headers["Accept-Language"].ToString();
return header?.Split(',')[0].Split(';')[0].Trim() ?? "en";
}

public override async Task Form_onInit(bool isInitialLoad)
{
await base.Form_onInit(isInitialLoad);

string locale = GetLocale();

var statuses = await _db.StatusTranslations
.Where(st => st.Locale == locale)
.ToDictionaryAsync(st => st.StatusId.ToString(), st => st.Label);

cmd.PopulateSelectBoxList("status", statuses);
}
}

For IHttpContextAccessor to be injected, register it in your Program.cs:

builder.Services.AddHttpContextAccessor();