Skip to content

Commit 4525f31

Browse files
Copilotwan92hen
andauthored
docs: add translation contribution guide with reference PR and checklist
Agent-Logs-Url: https://github.com/1Panel-dev/1Panel/sessions/e6a41d10-557e-4ca1-a78b-18888a9f17be Co-authored-by: wan92hen <27671436+wan92hen@users.noreply.github.com>
1 parent 0b146f7 commit 4525f31

2 files changed

Lines changed: 235 additions & 0 deletions

File tree

CONTRIBUTING.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ Please submit a PR broken down into small changes bit by bit. A PR consisting of
1212

1313
Note: If you split your pull request to small changes, please make sure any of the changes goes to master will not break anything. Otherwise, it can not be merged until this feature complete.
1414

15+
## Add a new translation
16+
17+
If you'd like to help translate 1Panel into a new language, please read the [Translation Contribution Guide](docs/TRANSLATION.md). It lists every file you need to create or modify, along with a reference PR you can use as a concrete example.
18+
1519
## Report issues
1620
It is a great way to contribute by reporting an issue. Well-written and complete bug reports are always welcome! Please open an issue and follow the template to fill in required information.
1721

docs/TRANSLATION.md

Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
# Translation Contribution Guide
2+
3+
Thank you for your interest in helping translate 1Panel into a new language! This guide walks through every file you need to create or modify to add full language support across the frontend and backend.
4+
5+
> **Reference PR:** [feat(i18n): add de-DE locale support (#12051)](https://github.com/1Panel-dev/1Panel/pull/12051) — a complete, real-world example of adding a brand-new locale (German).
6+
7+
---
8+
9+
## Overview
10+
11+
1Panel's i18n system spans two layers:
12+
13+
| Layer | Technology | Translation format |
14+
|---|---|---|
15+
| **Frontend** (Vue 3) | `vue-i18n` + Element Plus | TypeScript (`.ts`) |
16+
| **Backend** (Go) | `go-i18n` / `nicksnyder/go-i18n` | YAML (`.yaml`) |
17+
18+
Adding a new language requires changes in **both** layers, as well as registering the locale in a few selector components.
19+
20+
---
21+
22+
## Step 1 – Frontend translation file
23+
24+
Copy the reference English file and translate all values.
25+
26+
```
27+
frontend/src/lang/modules/en.ts → frontend/src/lang/modules/<locale>.ts
28+
```
29+
30+
Replace every English string with its translation. Keep all keys, nested objects, and the `getFuLocaleMessage` call at the bottom unchanged:
31+
32+
```ts
33+
// frontend/src/lang/modules/<locale>.ts
34+
import { getFuLocaleMessage } from '@/lang/fu';
35+
36+
const message = {
37+
commons: {
38+
// ... translated strings
39+
},
40+
// ...
41+
};
42+
43+
export default {
44+
...getFuLocaleMessage('<locale>'),
45+
...message,
46+
};
47+
```
48+
49+
> **Tip:** The file is ~4 400 lines. Using a translation tool for a first pass is fine, but please review the output for accuracy and context.
50+
51+
---
52+
53+
## Step 2 – Register the locale loader
54+
55+
Open `frontend/src/lang/index.ts` and add your locale to `LOCALE_LOADERS`:
56+
57+
```ts
58+
// frontend/src/lang/index.ts
59+
const LOCALE_LOADERS: Record<string, LocaleLoader> = {
60+
// existing entries …
61+
'<locale>': () => import('./modules/<locale>'),
62+
};
63+
```
64+
65+
---
66+
67+
## Step 3 – FU component translations
68+
69+
`frontend/src/lang/fu.ts` contains translations for custom FU table/steps components. Add a new entry for your locale:
70+
71+
```ts
72+
// frontend/src/lang/fu.ts
73+
const fuLocales: Record<string, FuLocaleMessage> = {
74+
// existing entries …
75+
'<locale>': {
76+
fu: {
77+
table: {
78+
more: '...',
79+
custom_table_rows: '...',
80+
},
81+
steps: {
82+
cancel: '...',
83+
prev: '...',
84+
next: '...',
85+
finish: '...',
86+
},
87+
},
88+
},
89+
};
90+
```
91+
92+
---
93+
94+
## Step 4 – Element Plus component locale
95+
96+
Element Plus ships its own locale strings (used in date pickers, pagination, etc.). Import the matching locale pack and wire it into `frontend/src/App.vue`:
97+
98+
```ts
99+
// frontend/src/App.vue — import section
100+
import <varName> from 'element-plus/es/locale/lang/<ep-locale-code>';
101+
```
102+
103+
Then add a branch in the `i18nLocale` computed property:
104+
105+
```ts
106+
const i18nLocale = computed(() => {
107+
// existing branches …
108+
if (globalStore.language === '<locale>') return <varName>;
109+
return zhCn; // fallback unchanged
110+
});
111+
```
112+
113+
You can find all available Element Plus locale codes in `node_modules/element-plus/es/locale/lang/`.
114+
115+
---
116+
117+
## Step 5 – Login page language selector
118+
119+
Open `frontend/src/views/login/components/login-form.vue` and add your locale label to `languageLabelMap`:
120+
121+
```ts
122+
const languageLabelMap: Record<string, string> = {
123+
// existing entries …
124+
'<locale>': '<Native language name>',
125+
};
126+
```
127+
128+
---
129+
130+
## Step 6 – Panel settings language selector
131+
132+
Open `frontend/src/views/setting/panel/index.vue` and add an option to `languageOptions`:
133+
134+
```ts
135+
const languageOptions = ref([
136+
// existing entries …
137+
{ value: '<locale>', label: '<Native language name>' },
138+
]);
139+
```
140+
141+
---
142+
143+
## Step 7 – Backend translation files (core & agent)
144+
145+
The backend has **two** independent Go modules, each with its own YAML translation file. Copy the English reference and translate:
146+
147+
```
148+
core/i18n/lang/en.yaml → core/i18n/lang/<locale>.yaml (~264 lines)
149+
agent/i18n/lang/en.yaml → agent/i18n/lang/<locale>.yaml (~592 lines)
150+
```
151+
152+
YAML format example:
153+
154+
```yaml
155+
ErrInvalidParams: "Invalid request parameters: {{ .detail }}"
156+
ErrRecordExist: "Record already exists"
157+
#
158+
```
159+
160+
---
161+
162+
## Step 8 – Register backend locale in Go
163+
164+
Add your locale key and file path in both i18n registries:
165+
166+
**`core/i18n/i18n.go`**
167+
```go
168+
var langFiles = map[string]string{
169+
// existing entries …
170+
"<locale>": "lang/<locale>.yaml",
171+
}
172+
```
173+
174+
**`agent/i18n/i18n.go`**
175+
```go
176+
var langFiles = map[string]string{
177+
// existing entries …
178+
"<locale>": "lang/<locale>.yaml",
179+
}
180+
```
181+
182+
---
183+
184+
## Checklist
185+
186+
Before opening a PR, verify the following:
187+
188+
- [ ] `frontend/src/lang/modules/<locale>.ts` created and all strings translated
189+
- [ ] Locale registered in `frontend/src/lang/index.ts` (`LOCALE_LOADERS`)
190+
- [ ] Locale entry added to `frontend/src/lang/fu.ts`
191+
- [ ] Element Plus locale imported and mapped in `frontend/src/App.vue`
192+
- [ ] Locale label added to `languageLabelMap` in `frontend/src/views/login/components/login-form.vue`
193+
- [ ] Locale option added to `languageOptions` in `frontend/src/views/setting/panel/index.vue`
194+
- [ ] `core/i18n/lang/<locale>.yaml` created
195+
- [ ] `agent/i18n/lang/<locale>.yaml` created
196+
- [ ] Locale registered in `core/i18n/i18n.go` (`langFiles`)
197+
- [ ] Locale registered in `agent/i18n/i18n.go` (`langFiles`)
198+
- [ ] Manually verified: new locale appears in the login language dropdown
199+
- [ ] Manually verified: new locale appears in **Settings → Panel → Language**
200+
- [ ] Manually verified: UI renders correctly after switching to the new locale
201+
202+
---
203+
204+
## Locale code conventions
205+
206+
Use [BCP 47](https://www.ietf.org/rfc/bcp/bcp47.txt) locale codes. Examples used in this project:
207+
208+
| Language | Locale code |
209+
|---|---|
210+
| Simplified Chinese | `zh` |
211+
| Traditional Chinese | `zh-Hant` |
212+
| English | `en` |
213+
| Japanese | `ja` |
214+
| Korean | `ko` |
215+
| Russian | `ru` |
216+
| Malay | `ms` |
217+
| Turkish | `tr` |
218+
| Brazilian Portuguese | `pt-BR` |
219+
| Spanish (Spain) | `es-ES` |
220+
221+
Use lowercase for simple codes (`ja`, `ko`) and the standard casing for regional variants (`pt-BR`, `es-ES`, `zh-Hant`). The frontend file name should be the lowercase version of the locale code (e.g. `pt-br.ts`, `es-es.ts`, `zh-hant.ts`), while the YAML file name mirrors the locale code exactly (`pt-BR.yaml`, `es-ES.yaml`, `zh-Hant.yaml`).
222+
223+
---
224+
225+
## PR title convention
226+
227+
```
228+
feat(i18n): add <language name> (<locale>) locale support
229+
```
230+
231+
Example: `feat(i18n): add German (de-DE) locale support`

0 commit comments

Comments
 (0)