Skip to content

Commit 59bea47

Browse files
authored
fix(i18n): 优化英文界面并补齐应用管理多语言文案 (#1112)
* fix(i18n): localize app management and polish English copy * fix(i18n): complete app translations and preserve localized actions * fix(i18n): preserve UI jokes and localize scan skill labels
1 parent b56c069 commit 59bea47

33 files changed

Lines changed: 2003 additions & 335 deletions

‎scripts/validate-i18n.js‎

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -131,12 +131,6 @@ function getEnglishOnlyKeys() {
131131
"gamepad_x360", // X360 (Xbox 360) - product name
132132
"gamepad_xone", // XOne (Xbox One) - product name
133133
"port_web_ui", // Web UI
134-
"boom_sunshine", // Boom!
135-
"boom_sunshine_title", // Boom!
136-
"boom_sunshine_button", // Boom!
137-
"boom_sunshine_button_desc", // Boom!
138-
"boom_sunshine_button_title", // Boom!
139-
"boom_sunshine_button_desc", // Boom!
140134
"upnp", // UPnP
141135
"scan_result_type_url", // URL
142136
"scan_result_filter_url_title", // URL

‎src_assets/common/assets/web/components/AppCard.vue‎

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,8 @@ export default {
113113
key: 'exclude-global-prep-cmd',
114114
className: 'tag-exclude-global-prep-cmd',
115115
icon: 'fa-ellipsis-h',
116-
label: '跳过预处理',
117-
title: '全局预处理命令',
116+
label: this.$t('apps.tag_skip_prep'),
117+
title: this.$t('apps.tag_skip_prep_desc'),
118118
});
119119
}
120120
@@ -123,8 +123,8 @@ export default {
123123
key: 'menu-cmd',
124124
className: 'tag-menu',
125125
count: this.app['menu-cmd'].length,
126-
label: '菜单',
127-
title: '菜单命令',
126+
label: this.$t('apps.tag_menu'),
127+
title: this.$t('apps.menu_cmd_name'),
128128
});
129129
}
130130
@@ -133,8 +133,8 @@ export default {
133133
key: 'elevated',
134134
className: 'tag-elevated',
135135
icon: 'fa-shield-alt',
136-
label: '管理员',
137-
title: '管理员',
136+
label: this.$t('apps.tag_admin'),
137+
title: this.$t('_common.run_as'),
138138
});
139139
}
140140
@@ -143,8 +143,8 @@ export default {
143143
key: 'auto-detach',
144144
className: 'tag-detach',
145145
icon: 'fa-unlink',
146-
label: '分离运行',
147-
title: '关闭时不退出串流',
146+
label: this.$t('apps.tag_auto_detach'),
147+
title: this.$t('apps.auto_detach'),
148148
});
149149
}
150150
@@ -196,7 +196,7 @@ export default {
196196
*/
197197
async copyToClipboard(text, appName, event) {
198198
if (!text) {
199-
this.$emit('copy-error', '没有可复制的命令');
199+
this.$emit('copy-error', this.$t('apps.copy_no_command'));
200200
return;
201201
}
202202
@@ -223,14 +223,14 @@ export default {
223223
this.showCopySuccess(targetElement, appName);
224224
} catch (err) {
225225
console.error('复制失败:', err);
226-
this.$emit('copy-error', '复制失败,请手动复制');
226+
this.$emit('copy-error', this.$t('apps.copy_failed_manual'));
227227
} finally {
228228
document.body.removeChild(textArea);
229229
}
230230
}
231231
} catch (err) {
232232
console.error('复制到剪贴板失败:', err);
233-
this.$emit('copy-error', '复制失败,请检查浏览器权限');
233+
this.$emit('copy-error', this.$t('apps.copy_failed_permissions'));
234234
}
235235
},
236236
@@ -242,7 +242,7 @@ export default {
242242
element.classList.add('copy-success');
243243
244244
// 发出成功事件
245-
this.$emit('copy-success', `📋 已复制 "${appName}" 的命令`);
245+
this.$emit('copy-success', this.$t('apps.copy_command_success', { name: appName }));
246246
247247
// 400ms后移除动画类
248248
setTimeout(() => {

‎src_assets/common/assets/web/components/AppEditor.vue‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<i class="fas fa-edit me-2"></i>
88
{{ isNewApp ? t('apps.add_new') : t('apps.edit') }}
99
</h5>
10-
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
10+
<button type="button" class="btn-close" data-bs-dismiss="modal" :aria-label="t('_common.close')"></button>
1111
</div>
1212
<div class="modal-body">
1313
<input type="file" ref="fileInput" style="display: none" />
@@ -109,7 +109,7 @@
109109
</span>
110110
<span class="cmd-tag">
111111
<code>"C:\Program Files\...\game.exe"</code>
112-
<span class="cmd-tag-desc">Start program directly</span>
112+
<span class="cmd-tag-desc">{{ t('apps.launch_program_directly') }}</span>
113113
</span>
114114
</div>
115115
</div>
@@ -501,6 +501,7 @@ const initializeFileSelector = () => {
501501
const notify = (type) => (message) => showMessage(message, type)
502502
fileSelector.value = createFileSelector({
503503
platform: props.platform,
504+
translate: t,
504505
onSuccess: notify('info'),
505506
onError: notify('error'),
506507
onInfo: notify('info'),
@@ -590,7 +591,7 @@ const cleanup = () => {
590591
591592
const validateField = (fieldName) => {
592593
const validationKey = FIELD_VALIDATION_MAP[fieldName] || fieldName
593-
const result = validateFieldHelper(validationKey, formData.value[fieldName])
594+
const result = validateFieldHelper(validationKey, formData.value[fieldName], {}, t)
594595
validation.value[fieldName] = result
595596
return result
596597
}
@@ -716,7 +717,7 @@ const getButtonTitle = (type) => fileSelector.value?.getButtonTitle(type) || t('
716717
717718
const saveApp = async () => {
718719
formData.value.dlssnr = normalizeDlssnrConfig(formData.value.dlssnr)
719-
const formValidation = validateAppForm(formData.value)
720+
const formValidation = validateAppForm(formData.value, t)
720721
if (!formValidation.isValid) {
721722
if (formValidation.errors.length) alert(formValidation.errors[0])
722723
return

‎src_assets/common/assets/web/components/AppListItem.vue‎

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,16 @@
2828
<h3 class="app-name-list">{{ app.name }}</h3>
2929
<div class="app-tags-list">
3030
<span v-if="app['exclude-global-prep-cmd'] && app['exclude-global-prep-cmd'] !== 'false'" class="app-tag-list tag-exclude-global-prep-cmd">
31-
<i class="fas fa-ellipsis-h me-1"></i>全局预处理
31+
<i class="fas fa-ellipsis-h me-1"></i>{{ $t('apps.tag_skip_prep') }}
3232
</span>
3333
<span v-if="app['menu-cmd'] && app['menu-cmd'].length > 0" class="app-tag-list tag-menu">
34-
<span class="badge rounded-pill bg-secondary me-1">{{ app['menu-cmd'].length }}</span>菜单
34+
<span class="badge rounded-pill bg-secondary me-1">{{ app['menu-cmd'].length }}</span>{{ $t('apps.tag_menu') }}
3535
</span>
3636
<span v-if="app.elevated && app.elevated !== 'false'" class="app-tag-list tag-elevated">
37-
<i class="fas fa-shield-alt me-1"></i>管理员
37+
<i class="fas fa-shield-alt me-1"></i>{{ $t('apps.tag_admin') }}
3838
</span>
3939
<span v-if="app['auto-detach'] && app['auto-detach'] !== 'false'" class="app-tag-list tag-detach">
40-
<i class="fas fa-unlink me-1"></i>自动分离
40+
<i class="fas fa-unlink me-1"></i>{{ $t('apps.tag_auto_detach') }}
4141
</span>
4242
</div>
4343
</div>
@@ -133,7 +133,7 @@ export default {
133133
*/
134134
async copyToClipboard(text, appName, event) {
135135
if (!text) {
136-
this.$emit('copy-error', '没有可复制的命令');
136+
this.$emit('copy-error', this.$t('apps.copy_no_command'));
137137
return;
138138
}
139139
@@ -160,14 +160,14 @@ export default {
160160
this.showCopySuccess(targetElement, appName);
161161
} catch (err) {
162162
console.error('复制失败:', err);
163-
this.$emit('copy-error', '复制失败,请手动复制');
163+
this.$emit('copy-error', this.$t('apps.copy_failed_manual'));
164164
} finally {
165165
document.body.removeChild(textArea);
166166
}
167167
}
168168
} catch (err) {
169169
console.error('复制到剪贴板失败:', err);
170-
this.$emit('copy-error', '复制失败,请检查浏览器权限');
170+
this.$emit('copy-error', this.$t('apps.copy_failed_permissions'));
171171
}
172172
},
173173
@@ -179,7 +179,7 @@ export default {
179179
element.classList.add('copy-success');
180180
181181
// 发出成功事件
182-
this.$emit('copy-success', `📋 已复制 "${appName}" 的命令`);
182+
this.$emit('copy-success', this.$t('apps.copy_command_success', { name: appName }));
183183
184184
// 400ms后移除动画类
185185
setTimeout(() => {

‎src_assets/common/assets/web/components/ImageSelector.vue‎

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
@dragleave="handleDragLeave"
3737
@dragover.prevent
3838
@drop.prevent.stop="handleDrop"
39-
placeholder="选择图片文件或拖拽到此处"
39+
:placeholder="$t('apps.image_path_placeholder')"
4040
/>
4141
<button
4242
class="btn btn-outline-secondary"
@@ -51,10 +51,10 @@
5151
<!-- 图片预览 -->
5252
<div v-if="!isDesktopImage && imagePath" class="image-preview-container mt-3">
5353
<div class="image-preview">
54-
<img :src="previewUrl" alt="图片预览" @error="handleImageError" />
54+
<img :src="previewUrl" :alt="$t('apps.image_preview')" @error="handleImageError" />
5555
</div>
5656
<div class="image-preview-circle">
57-
<img :src="previewUrl" alt="图片预览" @error="handleImageError" />
57+
<img :src="previewUrl" :alt="$t('apps.image_preview')" @error="handleImageError" />
5858
</div>
5959
</div>
6060

@@ -139,7 +139,7 @@ export default {
139139
handleDragEnter(event) {
140140
event.preventDefault()
141141
this.dragCounter++
142-
this.$emit('image-error', '杂鱼~快放进来呀~')
142+
this.$emit('image-error', this.$t('apps.image_drop_hint'))
143143
},
144144
145145
/**
@@ -162,7 +162,7 @@ export default {
162162
163163
const file = event.dataTransfer.files[0]
164164
if (!file) {
165-
this.$emit('image-error', '其他地方不可以!')
165+
this.$emit('image-error', this.$t('apps.image_drop_empty'))
166166
return
167167
}
168168
@@ -173,20 +173,20 @@ export default {
173173
* 处理文件上传
174174
*/
175175
async processFile(file) {
176-
const validation = validateFile(file)
176+
const validation = validateFile(file, { translate: this.$t })
177177
if (!validation.isValid) {
178178
this.$emit('image-error', validation.message)
179179
return
180180
}
181181
182182
try {
183-
this.$emit('image-error', '正在上传图片...')
183+
this.$emit('image-error', this.$t('apps.image_uploading'))
184184
const path = await this.uploadImageToSunshine(file)
185185
this.$emit('update-image', path)
186186
this.$emit('image-error', '')
187187
} catch (error) {
188188
console.error('上传图片失败:', error)
189-
this.$emit('image-error', `上传图片失败: ${error.message}`)
189+
this.$emit('image-error', this.$t('apps.image_upload_failed', { error: error.message }))
190190
}
191191
},
192192
@@ -235,15 +235,15 @@ export default {
235235
* 处理图片加载错误
236236
*/
237237
handleImageError() {
238-
this.$emit('image-error', '图片加载失败,请检查文件路径')
238+
this.$emit('image-error', this.$t('apps.image_load_failed'))
239239
},
240240
241241
/**
242242
* 打开封面查找器
243243
*/
244244
openCoverFinder() {
245245
if (!this.appName) {
246-
this.$emit('image-error', '请先输入应用名称')
246+
this.$emit('image-error', this.$t('apps.image_app_name_required'))
247247
return
248248
}
249249
this.showCoverFinder = true

‎src_assets/common/assets/web/composables/useApps.js‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,12 @@ export function useApps() {
280280
const getGameLibrarySkillIcon = (skillId) => getGameLibraryCapabilityIcon(skillId)
281281

282282
const getGameLibrarySkillLabel = (skillId) => {
283+
if (skillId === GAME_LIBRARY_SKILL_IDS.titleNormalize) {
284+
return translate('apps.scan_options.ai_name_cleanup')
285+
}
286+
if (skillId === GAME_LIBRARY_SKILL_IDS.coverSelection) {
287+
return translate('apps.scan_options.ai_cover_matching')
288+
}
283289
const locale = typeof document === 'undefined'
284290
? ''
285291
: String(document.documentElement?.getAttribute?.('lang') || '').toLowerCase()

0 commit comments

Comments
 (0)