Internationalization
Build bilingual and multilingual FormPlatform interfaces with stable message keys, localized metadata and substitution-aware runtime text.
Internationalization
FORMPLATFORM separates platform UI text from form-authored business content.
The platform locale is stored in `localStorage` as `formplatform.locale`.
English (`en`) is the default and Simplified Chinese (`zh-CN`) is currently
supported.
Platform Vue code
Platform views and components use stable keys from `ClientApp/src/i18n.js`.
Never translate rendered DOM text and never use a source sentence as the key.
<script setup>
import { useI18n } from '../i18n.js'
const { t } = useI18n()
</script>
<template>
<button>{{ t('customer.save') }}</button>
<p>{{ t('customer.updated', { name: customer.name }) }}</p>
</template>
Add both catalog entries:
// zh-CN
'customer.save': '保存客户',
'customer.updated': '已更新客户 {name}',
// en
'customer.save': 'Save customer',
'customer.updated': 'Customer {name} was updated',
The legacy DOM localizer is not installed. This is intentional: substring
replacement cannot understand context and caused corrupt text such as `adm在`.
System and layout forms
Platform-owned forms can store an `xxxKey` next to any display property. The
renderer recursively converts the key into the real property.
{
"type": "button",
"props": {
"textKey": "common.save"
}
}
This works in nested objects too, including Menu items and Breadcrumb items.
System and Functional forms that implement platform UI should use catalog keys.
Survey and other business-form content
Business content is authored content, not platform UI. Its default language
stays in the normal component properties. Explicit locale overrides are stored
on the component:
{
"id": "customerName",
"type": "input",
"props": {
"label": "Customer name",
"placeholder": "Enter your name"
},
"other": {
"required": true,
"requiredMessage": "Customer name is required"
},
"tooltip": {
"helpEnabled": true,
"helpType": "always",
"helpContent": "Use the name on your account."
},
"translations": {
"zh-CN": {
"props": {
"label": "客户姓名",
"placeholder": "请输入姓名"
},
"other": {
"requiredMessage": "客户姓名为必填项"
},
"tooltip": {
"helpContent": "请使用账户上的姓名。"
}
}
}
}
The renderer deep-merges the selected locale over the default component.
Missing translations fall back to the default content. Control values, IDs,
property names, validation code, URLs, and database mappings must not be
translated.
Action Code and form JavaScript
Action modules receive `args.api.t()` and `args.api.getLocale()`. A module may
export its own message catalogs. Catalogs are registered only while that form's
Action Code is active and are removed when the form is unloaded.
export const messages = {
en: {
'list.saved': 'Record {id} was saved'
},
'zh-CN': {
'list.saved': '记录 {id} 已保存'
}
}
export default {
messages,
async init(args) {
console.info('locale:', args.api.getLocale())
},
async onSaved(args) {
args.api.notify({
type: 'success',
messageKey: 'list.saved',
messageParams: { id: args.data.id },
message: `Record ${args.data.id} was saved`
})
}
}
Use message keys in action-chain parameters as data. Resolve them only at the
point where text is displayed:
args.api.notify({
type: args.parameters.type,
messageKey: args.parameters.messageKey,
messageParams: args.parameters.messageParams
})
Server responses
API responses should make a stable machine-readable `code` or `messageKey`
authoritative. The optional English `message` is a fallback for old clients,
logs, and untranslated keys.
{
"code": "customer.notFound",
"messageKey": "errors.customerNotFound",
"messageParams": { "id": "42" },
"message": "Customer 42 was not found"
}
Server notifications use the same shape:
{
"type": "warning",
"titleKey": "warning.title",
"messageKey": "customer.profileIncomplete",
"messageParams": { "name": "Mike" },
"durationMs": 7000
}
The client resolves `messageKey`, `titleKey`, and validation-error descriptor
objects. Requests send the current locale in `Accept-Language`. Domain and
validation APIs should normally return keys instead of localized prose so that
one response is deterministic and the browser can change language immediately.
Use ASP.NET `IStringLocalizer` only for server-owned rendered output such as
emails, exported reports, or text that cannot be translated by the client.
Adding another language
1. Add the locale to `supportedLocales` in `ClientApp/src/i18n.js`.
2. Add a complete platform catalog.
3. Add the language to `LanguageSwitcher.vue`.
4. Add explicit `translations[locale]` values to business forms that require it.
5. Test key fallback, interpolation, validation messages, Action Code
notifications, and server error responses.