fix(i18n): prevent base name overwrites when editing in localized UI
Include base names in API responses to correctly populate edit forms. Show base values as placeholders in translation fields for better UX. Use default locale when fetching previous state for history diffs.
This commit is contained in:
@@ -30,6 +30,10 @@ function fieldValue(language: Language): string {
|
||||
return props.translations[language.code]?.[props.field] ?? '';
|
||||
}
|
||||
|
||||
function fieldPlaceholder(language: Language): string {
|
||||
return language.code === defaultLanguage.value?.code ? '' : props.baseValue;
|
||||
}
|
||||
|
||||
function updateField(language: Language, value: string) {
|
||||
if (language.code === defaultLanguage.value?.code) {
|
||||
emit('update:baseValue', value);
|
||||
@@ -68,6 +72,7 @@ function inputValue(event: Event): string {
|
||||
<input
|
||||
:id="`${idPrefix}-${language.code}`"
|
||||
:value="fieldValue(language)"
|
||||
:placeholder="fieldPlaceholder(language)"
|
||||
:required="required && language.code === defaultLanguage?.code"
|
||||
@input="updateField(language, inputValue($event))"
|
||||
/>
|
||||
|
||||
@@ -56,6 +56,7 @@ export interface EditHistoryEntry {
|
||||
export interface Pokemon extends EditInfo {
|
||||
id: number;
|
||||
name: string;
|
||||
baseName?: string;
|
||||
translations?: TranslationMap;
|
||||
environment: NamedEntity;
|
||||
skills: Skill[];
|
||||
@@ -79,6 +80,7 @@ export interface PokemonDetail extends Pokemon {
|
||||
export interface Habitat extends EditInfo {
|
||||
id: number;
|
||||
name: string;
|
||||
baseName?: string;
|
||||
translations?: TranslationMap;
|
||||
recipe: Array<NamedEntity & { quantity: number }>;
|
||||
pokemon?: NamedEntity[];
|
||||
@@ -113,6 +115,7 @@ export interface HabitatUsage {
|
||||
export interface Item extends EditInfo {
|
||||
id: number;
|
||||
name: string;
|
||||
baseName?: string;
|
||||
translations?: TranslationMap;
|
||||
category: NamedEntity;
|
||||
usage: NamedEntity | null;
|
||||
@@ -147,6 +150,7 @@ export interface Recipe extends EditInfo {
|
||||
export interface DailyChecklistItem {
|
||||
id: number;
|
||||
title: string;
|
||||
baseTitle?: string;
|
||||
translations?: TranslationMap;
|
||||
}
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ const configNameInput = computed({
|
||||
return configForm.value.name;
|
||||
}
|
||||
|
||||
return configForm.value.translations[currentConfigLocale.value]?.name ?? configForm.value.name;
|
||||
return configForm.value.translations[currentConfigLocale.value]?.name ?? '';
|
||||
},
|
||||
set: (value: string) => {
|
||||
if (isConfigDefaultLocale.value) {
|
||||
@@ -92,6 +92,7 @@ const configNameInput = computed({
|
||||
updateConfigTranslation(currentConfigLocale.value, value);
|
||||
}
|
||||
});
|
||||
const configNamePlaceholder = computed(() => (isConfigDefaultLocale.value ? '' : configForm.value.name));
|
||||
const activeConfigTab = computed({
|
||||
get: () => activeConfigType.value,
|
||||
set: (value: string) => {
|
||||
@@ -194,7 +195,7 @@ function closeChecklistModal() {
|
||||
}
|
||||
|
||||
function editChecklistItem(item: DailyChecklistItem) {
|
||||
checklistForm.value = { id: item.id, title: item.title, translations: item.translations ?? {} };
|
||||
checklistForm.value = { id: item.id, title: item.baseTitle ?? item.title, translations: item.translations ?? {} };
|
||||
checklistModalOpen.value = true;
|
||||
}
|
||||
|
||||
@@ -240,7 +241,7 @@ function updateConfigTranslation(localeCode: string, value: string) {
|
||||
}
|
||||
|
||||
function configBaseNameForSave() {
|
||||
if (configForm.value.name.trim() !== '' || isConfigDefaultLocale.value) {
|
||||
if (configForm.value.name.trim() !== '') {
|
||||
return configForm.value.name;
|
||||
}
|
||||
|
||||
@@ -805,7 +806,7 @@ onMounted(() => {
|
||||
<form id="admin-config-form" class="modal-edit-form" @submit.prevent="saveConfig">
|
||||
<div class="field">
|
||||
<label for="config-name">{{ t('common.name') }}</label>
|
||||
<input id="config-name" v-model="configNameInput" :required="configNameRequired" />
|
||||
<input id="config-name" v-model="configNameInput" :placeholder="configNamePlaceholder" :required="configNameRequired" />
|
||||
</div>
|
||||
<div v-if="selectedConfig.supportsItemDrop" class="check-row">
|
||||
<label>
|
||||
|
||||
@@ -146,7 +146,7 @@ async function loadEditor() {
|
||||
if (isEditing.value) {
|
||||
const habitat = await api.habitatDetail(routeId.value);
|
||||
habitatForm.value = {
|
||||
name: habitat.name,
|
||||
name: habitat.baseName ?? habitat.name,
|
||||
translations: habitat.translations ?? {},
|
||||
recipeItems: habitat.recipe.map((recipeItem) => ({ itemId: String(recipeItem.id), quantity: recipeItem.quantity })),
|
||||
pokemonAppearances: groupPokemonAppearances(habitat)
|
||||
|
||||
@@ -68,7 +68,7 @@ async function loadEditor() {
|
||||
if (isEditing.value) {
|
||||
const item = await api.itemDetail(routeId.value);
|
||||
itemForm.value = {
|
||||
name: item.name,
|
||||
name: item.baseName ?? item.name,
|
||||
translations: item.translations ?? {},
|
||||
categoryId: String(item.category.id),
|
||||
usageId: item.usage ? String(item.usage.id) : '',
|
||||
|
||||
@@ -101,7 +101,7 @@ async function loadEditor() {
|
||||
const pokemon = await api.pokemonDetail(routeId.value);
|
||||
pokemonForm.value = {
|
||||
id: String(pokemon.id),
|
||||
name: pokemon.name,
|
||||
name: pokemon.baseName ?? pokemon.name,
|
||||
translations: pokemon.translations ?? {},
|
||||
environmentId: String(pokemon.environment.id),
|
||||
skillIds: pokemon.skills.map((skill) => String(skill.id)),
|
||||
|
||||
Reference in New Issue
Block a user