多语言调整

This commit is contained in:
tianmo committed 2026-10-22 18:51:26 +08:00
1 parent 04de5e5a8e
commit 8bd9154414
23 files changed
+395 -155

No files matched your search

-8
View File
@@ -100,14 +100,6 @@
"presetListError": "Voreinstellungsliste kann nicht gelesen werden",
"presetReadError": "Voreinstellung konnte nicht gelesen werden: {file}"
},
"presets": {
"particleSweep": "1.Partikel-Sweep",
"barBlocks": "2.Balkenblöcke",
"forceTrail": "3.Kraftfeldschweif",
"lightningSequence": "4.Blitzsequenz",
"texturePivot": "5.Textur-Pivot",
"subEmitter": "6.Sub-Emitter"
},
"curve": {
"bezierHint": "Ziehen Sie den quadratischen Griff, um den Bogen anzupassen. · Doppelklicken Sie auf eine leere Stelle, um einen neuen zu erstellen. · Doppelklicken Sie auf einen Knoten, um ihn zu löschen",
"linearHint": "Doppelklicken Sie auf eine leere Stelle, um eine neue zu erstellen. Doppelklicken Sie auf einen Knoten, um ihn zu löschen. Ziehen Sie einen Knoten, um ihn anzupassen.",
-8
View File
@@ -112,14 +112,6 @@
"presetListError": "Unable to read preset list",
"presetReadError": "Unable to read preset: {file}"
},
"presets": {
"particleSweep": "1. Particle Sweep",
"barBlocks": "2. Bar Blocks",
"forceTrail": "3. Force Field Trail",
"lightningSequence": "4. Lightning Sequence",
"texturePivot": "5. Texture Pivot",
"subEmitter": "6. Sub-emitter"
},
"curve": {
"bezierHint": "Drag square handles · Double-click empty space to add · Double-click a node to delete",
"linearHint": "Double-click empty space to add · Double-click a node to delete · Drag nodes to adjust",
-8
View File
@@ -100,14 +100,6 @@
"presetListError": "No se puede leer la lista preestablecida",
"presetReadError": "No se puede leer el ajuste preestablecido: {file}"
},
"presets": {
"particleSweep": "1.Barrido de partículas",
"barBlocks": "2.Bloques rectangulares",
"forceTrail": "3.Estela de campo de fuerza",
"lightningSequence": "4.Secuencia de rayos",
"texturePivot": "5.Pivote de textura",
"subEmitter": "6.Subemisor"
},
"curve": {
"bezierHint": "Arrastre el controlador cuadrado para ajustar el arco · Haga doble clic en un espacio en blanco para crear uno nuevo · Haga doble clic en un nodo para eliminarlo",
"linearHint": "Haga doble clic en un espacio en blanco para crear uno nuevo. Haga doble clic en un nodo para eliminarlo. Arrastra un nodo para ajustarlo.",
-8
View File
@@ -100,14 +100,6 @@
"presetListError": "Impossible de lire la liste des préréglages",
"presetReadError": "Impossible de lire le préréglage : {file}"
},
"presets": {
"particleSweep": "1.Balayage de particules",
"barBlocks": "2.Blocs rectangulaires",
"forceTrail": "3.Traînée de champ de force",
"lightningSequence": "4.Séquence d’éclairs",
"texturePivot": "5.Pivot de texture",
"subEmitter": "6.Sous-émetteur"
},
"curve": {
"bezierHint": "Faites glisser la poignée carrée pour ajuster l'arc · Double-cliquez sur un espace vide pour en créer un nouveau · Double-cliquez sur un nœud pour le supprimer",
"linearHint": "Double-cliquez sur un espace vide pour en créer un nouveau. Double-cliquez sur un nœud pour le supprimer. Faites glisser un nœud pour l'ajuster.",
-8
View File
@@ -100,14 +100,6 @@
"presetListError": "プリセットリストを読み取れません",
"presetReadError": "プリセットを読み取れません: {file}"
},
"presets": {
"particleSweep": "1.パーティクルスイープ",
"barBlocks": "2.バーブロック",
"forceTrail": "3.フォースフィールドトレイル",
"lightningSequence": "4.雷シーケンス",
"texturePivot": "5.テクスチャピボット",
"subEmitter": "6.サブエミッター"
},
"curve": {
"bezierHint": "四角いハンドルをドラッグして円弧を調整します。 · 空白スペースをダブルクリックして新しいスペースを作成します。 · ノードをダブルクリックして削除します。",
"linearHint": "空白スペースをダブルクリックして、新しいスペースを作成します。ノードをダブルクリックして削除します。ノードをドラッグして調整します。",
-8
View File
@@ -100,14 +100,6 @@
"presetListError": "사전 설정 목록을 읽을 수 없습니다.",
"presetReadError": "사전 설정을 읽을 수 없습니다: {file}"
},
"presets": {
"particleSweep": "1.파티클 스윕",
"barBlocks": "2.바 블록",
"forceTrail": "3.힘장 트레일",
"lightningSequence": "4.번개 시퀀스",
"texturePivot": "5.텍스처 피벗",
"subEmitter": "6.하위 이미터"
},
"curve": {
"bezierHint": "원호를 조정하려면 사각형 핸들을 드래그하세요. · 새 공간을 만들려면 빈 공간을 두 번 클릭하세요. · 삭제하려면 노드를 두 번 클릭하세요.",
"linearHint": "빈 공간을 더블클릭하면 새로운 공간이 생성됩니다. 삭제하려면 노드를 두 번 클릭하세요. 노드를 드래그하여 조정하세요.",
-8
View File
@@ -100,14 +100,6 @@
"presetListError": "Não é possível ler a lista predefinida",
"presetReadError": "Não é possível ler a predefinição: {file}"
},
"presets": {
"particleSweep": "1.Varredura de partículas",
"barBlocks": "2.Blocos retangulares",
"forceTrail": "3.Rastro de campo de força",
"lightningSequence": "4.Sequência de raios",
"texturePivot": "5.Pivô da textura",
"subEmitter": "6.Subemissor"
},
"curve": {
"bezierHint": "Arraste a alça quadrada para ajustar o arco · Clique duas vezes em um espaço em branco para criar um novo · Clique duas vezes em um nó para excluí-lo",
"linearHint": "Clique duas vezes em um espaço em branco para criar um novo. Clique duas vezes em um nó para excluí-lo. Arraste um nó para ajustá-lo.",
-8
View File
@@ -112,14 +112,6 @@
"presetListError": "无法读取预设列表",
"presetReadError": "无法读取预设:{file}"
},
"presets": {
"particleSweep": "1.粒子扫过",
"barBlocks": "2.长条方块",
"forceTrail": "3.力场拖尾",
"lightningSequence": "4.雷电序列帧",
"texturePivot": "5.贴图轴点",
"subEmitter": "6.子发射器"
},
"curve": {
"bezierHint": "拖动方形手柄调整弧度 · 双击空白新建 · 双击节点删除",
"linearHint": "双击空白新建 · 双击节点删除 · 拖动节点调整",
-8
View File
@@ -100,14 +100,6 @@
"presetListError": "無法讀取預設列表",
"presetReadError": "無法讀取預設:{file}"
},
"presets": {
"particleSweep": "1.粒子掃過",
"barBlocks": "2.長條方塊",
"forceTrail": "3.力場拖尾",
"lightningSequence": "4.雷電序列幀",
"texturePivot": "5.貼圖軸點",
"subEmitter": "6.子發射器"
},
"curve": {
"bezierHint": "拖曳方形手把調整弧度 · 雙擊空白新建 · 雙擊節點刪除",
"linearHint": "雙擊空白新建 · 雙擊節點刪除 · 拖曳節點調整",
@@ -27,19 +27,11 @@ import ColorGradientEditor from '../ColorGradientEditor.vue'
import ImageResourceCard from '../ImageResourceCard.vue'
import SpineObjectPanel from '../../spine/SpineObjectPanel.vue'
import { useParticlePanelContext } from './particlePanelContext'
import { resolvePresetDisplayName, type PresetOption } from './presetNames'
const { configFileInput, selectedPreset, presetOptions, presetLoading, configMessage, configError, saveConfig, onConfigFileChange, refreshPresets, loadSelectedPreset, collapsed, toggle, select } = useParticlePanelContext()
const { t } = useI18n()
const presetNameKeys: Record<string, string> = {
'1.粒子扫过.json': 'presets.particleSweep',
'2.长条方块.json': 'presets.barBlocks',
'3.力场拖尾.json': 'presets.forceTrail',
'4.雷电序列帧.json': 'presets.lightningSequence',
'5.贴图轴点.json': 'presets.texturePivot',
'6.子发射器.json': 'presets.subEmitter',
}
function presetDisplayName(preset: { name: string; file: string }) {
const key = presetNameKeys[preset.file]
return key ? t(key) : preset.name
const { locale } = useI18n()
function presetDisplayName(preset: PresetOption) {
return resolvePresetDisplayName(preset, locale.value)
}
</script>
+40
View File
@@ -0,0 +1,40 @@
export type PresetDisplayName = string | Record<string, string>
export interface PresetOption {
name?: PresetDisplayName
file: string
}
function normalizeName(value: unknown): PresetDisplayName | undefined {
if (typeof value === 'string') return value.trim() || undefined
if (!value || typeof value !== 'object' || Array.isArray(value)) return undefined
const entries = Object.entries(value)
.filter((entry): entry is [string, string] => typeof entry[1] === 'string' && !!entry[1].trim())
return entries.length ? Object.fromEntries(entries) : undefined
}
/** 兼容自动生成的仅含 file 条目、旧字符串 name 和多语言 name。 */
export function parsePresetIndex(value: unknown): PresetOption[] {
if (!Array.isArray(value)) return []
const result: PresetOption[] = []
for (const item of value) {
if (typeof item === 'string' && item.trim()) {
result.push({ file: item })
continue
}
if (!item || typeof item !== 'object' || Array.isArray(item)) continue
const file = typeof item.file === 'string' ? item.file.trim() : ''
if (!file) continue
result.push({ file, name: normalizeName(item.name) })
}
return result
}
export function resolvePresetDisplayName(preset: PresetOption, locale: string) {
if (typeof preset.name === 'string') return preset.name
if (preset.name && typeof preset.name === 'object') {
return preset.name[locale] || preset.name.en || preset.name['zh-CN']
|| preset.file.replace(/^.*[\\/]/, '').replace(/\.json$/i, '')
}
return preset.file.replace(/^.*[\\/]/, '').replace(/\.json$/i, '')
}
@@ -25,12 +25,12 @@ import {
} from '../../export/spineConnectorClient'
import { automaticLoopTransitionFrames } from '../../core/loopSegmentTiming'
import { translate } from '../../i18n'
import { parsePresetIndex, type PresetOption } from './presetNames'
export function useProjectPresets(store: ReturnType<typeof useParticleStore>) {
const configFileInput = ref<HTMLInputElement | null>(null)
const selectedPreset = ref('')
const presetOptions = ref<Array<{ name: string; file: string }>>([])
const presetOptions = ref<PresetOption[]>([])
const presetLoading = ref(false)
const configMessage = ref('')
const configError = ref(false)
@@ -62,9 +62,7 @@ async function refreshPresets() {
const response = await fetch(`/Preset/index.json?t=${Date.now()}`, { cache: 'no-store' })
if (!response.ok) throw new Error(translate('config.presetListError'))
const presets = await response.json()
presetOptions.value = Array.isArray(presets)
? presets.filter((item): item is { name: string; file: string } => !!item && typeof item.name === 'string' && typeof item.file === 'string')
: []
presetOptions.value = parsePresetIndex(presets)
} catch {
presetOptions.value = []
}