i18n Internationalization
NocoBase plugins manage multilingual files through the src/locale/ directory. After writing the translation files, use this.t() in the Plugin, useT() hook in components, and tExpr() in FlowModel definitions to get translated text.
Translation Files
Create JSON files by language under the plugin's src/locale/. The key is the English original text, and the value is the translation for the corresponding language:
A few things to note:
- Use English text as the key, so even if a translation is missing it falls back to English
- Use double curly braces for variables
{{name}}, consistent with i18next syntax - Adding language files for the first time requires an application restart to take effect; subsequent content changes will hot reload
- NocoBase automatically uses the plugin's package name as the translation namespace, so translations from different plugins won't conflict
Using in Plugin: this.t()
In the Plugin class, this.t() automatically injects the current plugin's package name as the namespace — no need to manually pass ns:
Using in Components: useT()
You cannot use this.t() directly in React components. The plugin scaffolding automatically generates a locale.ts file that provides the useT() hook:
Use it in components like this:
The t function returned by useT() is already bound to the plugin's namespace — just pass the key directly.
Using in FlowModel: tExpr()
FlowModel.define() and registerFlow() are executed at module load time, when i18n has not yet been initialized, so you cannot call t() directly. In this scenario, use tExpr() — it generates a deferred translation expression string that is resolved at runtime:
In short: this.t() and useT() are for runtime translation, while tExpr() is for deferred translation in static definitions.
tExpr has two sources: the auto-generated locale.ts from the plugin and @nocobase/flow-engine. The difference is that the tExpr from locale.ts is already bound to the plugin's package name as namespace, while the one imported directly from @nocobase/flow-engine has no namespace binding. In plugin code, always use the tExpr exported from locale.ts so that translations correctly match the plugin's own language files.
Quick Reference for the Three Methods
Related Links
- Context - Common Capabilities - Internationalization — Full API reference for ctx.t and ctx.i18n
- Language List — Complete list of language codes supported by NocoBase
- Component Development — Using useFlowContext in components
- FlowEngine Overview — Usage of tExpr in FlowModel

