Introduction
LinaPro internationalization is loaded and merged by the core framework. The core framework provides base language packs, source plugins provide their own language packs, and dynamic plugin release artifacts can carry language resources. After a plugin is enabled, the core framework merges all available resources into the runtime locale directory for the admin workspace, menus, error messages, plugin pages, and API documentation.
The main repository currently provides two locale resource sets by default: zh-CN and en-US. Other languages must be created and maintained by the project team.
Configuration
Internationalization is configured in config.yaml:
i18n:
default: zh-CN
enabled: true
locales:
- locale: en-US
nativeName: English
- locale: zh-CN
nativeName: 简体中文
| Option | Description |
|---|---|
default | Default locale used when a request does not include a locale identifier or requests an unsupported locale |
enabled | Whether multilingual support is enabled; when disabled, the frontend hides the language switcher |
locales | Runtime list of selectable locales and display names |
locales affects both the frontend language switcher and the set of language resources that should be fully maintained at runtime.
Resource Layout
Core framework language resources live under:
apps/lina-core/manifest/i18n/<locale>/
A typical structure looks like this:
manifest/i18n/
├── zh-CN/
│ ├── framework.json
│ ├── menu.json
│ ├── dict.json
│ ├── config.json
│ ├── error.json
│ ├── job.json
│ ├── notify.json
│ ├── role.json
│ ├── plugin.json
│ ├── public-frontend.json
│ └── apidoc/
│ ├── common.json
│ └── core-api-*.json
└── en-US/
└── ...
JSON files directly under <locale>/ provide runtime UI copy, while JSON files under apidoc/ provide API documentation translations. The two resource types are loaded separately so API documentation resources do not pollute runtime UI copy.
Language Pack Format
Language packs use JSON. They may use nested structures or flat dot-separated keys:
{
"menu": {
"dashboard": {
"title": "Dashboard"
}
},
"framework": {
"description": "An AI-native full-stack framework for sustainable delivery"
}
}
Equivalent flat-key form:
{
"menu.dashboard.title": "Dashboard",
"framework.description": "An AI-native full-stack framework for sustainable delivery"
}
After loading, the runtime normalizes resources into flat keys. To reduce collisions, plugin language packs should stay under the plugin's own namespace.
Plugin Internationalization
Source plugins maintain language packs in their own manifest/i18n/ directories:
apps/lina-plugins/content-notice/manifest/i18n/
├── zh-CN/
│ ├── content-notice.json
│ └── apidoc/
│ └── plugin-api-notice.json
└── en-US/
└── content-notice.json
Plugin language packs should use a plugins.<plugin-id>. namespace:
{
"plugins": {
"content-notice": {
"notice": {
"title": "Notices",
"status": {
"draft": "Draft",
"published": "Published"
}
}
}
}
}
Dynamic plugin language resources are shipped with the release artifact. When the core framework loads a valid release version, those resources are merged as plugin resources; when the plugin is disabled or upgraded, they change along with the runtime snapshot.
API Documentation Translation
API documentation translations live under manifest/i18n/<locale>/apidoc/. Both the core framework and plugins can maintain their own apidoc resources:
manifest/i18n/zh-CN/apidoc/core-api-auth.json
manifest/i18n/zh-CN/apidoc/common.json
manifest/i18n/zh-CN/apidoc/plugin-api-notice.json
API documentation translations use structured keys. Display text should not be used as keys. Plugin translations should only maintain their own plugin namespace, while core framework translations should only maintain core API namespaces.
en-US API documentation resources can usually remain as empty placeholders, allowing English summary, dc, and field descriptions in source code to serve as the default copy. Chinese and other non-English languages should provide complete translations so the admin workspace Developer Center stays readable.
Locale Selection
Runtime locale selection usually comes from request headers, query parameters, or user preferences stored by the frontend. The exact call path is coordinated by the admin workspace and core framework middleware. If the requested locale does not exist or is not configured, the core framework falls back to i18n.default.
When i18n.enabled: false, the frontend hides the language switcher, while the core framework still loads the required copy using the default locale.
Adding a New Language
Adding a new language usually requires four steps:
- Add the language code and native display name to
i18n.localesinconfig.yaml. - Create core framework language packs under
apps/lina-core/manifest/i18n/<locale>/. - Add language packs under
manifest/i18n/<locale>/for every enabled plugin. - If API documentation localization is required, add resources under
manifest/i18n/<locale>/apidoc/.
Example:
i18n:
locales:
- locale: ja-JP
nativeName: 日本語
Create the directory:
mkdir -p apps/lina-core/manifest/i18n/ja-JP/apidoc
LinaPro does not automatically generate translation content for newly added languages. Missing translations fall back to default copy or display untranslated keys, depending on the call site.
Cache and Refresh
Runtime language resources are cached. In development, restarting the service is the most direct way to pick up language pack changes:
make dev
In production, use runtime cache invalidation and refresh the smallest necessary scope:
| Scope | Description |
|---|---|
| Specific locale | Refresh only one locale |
| Specific plugin | Refresh only one plugin's language resources |
| Core framework resources | Refresh only core framework language packs |
| API documentation resources | Refresh only the apidoc translation directory |
Avoid clearing all language and plugin caches without a reason. A full refresh can cause brief translation jitter and increases load cost on the next request.
Language Codes
LinaPro uses standard IETF BCP 47 language codes. Common examples:
| Language | Code |
|---|---|
| Simplified Chinese | zh-CN |
| Traditional Chinese | zh-TW |
| English | en-US |
| Japanese | ja-JP |
| Korean | ko-KR |
Directory names, locale fields in config.yaml, and frontend request locale parameters should stay consistent.