Add 'Seed Defaults' button to load all predefined translations
- Add /translations/seed-all-defaults API endpoint - Loads all DEFAULT_TRANSLATIONS (makers, models, colors, fuels, transmissions) - Includes 100+ predefined translations (Mohave, Sonata, colors, etc.) - Add 'Seed Defaults' button to admin translations page 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -637,6 +637,47 @@ def fill_default_translations(db: Session = Depends(get_db)):
|
|||||||
return {"message": f"Updated {updated_count} translations with default values"}
|
return {"message": f"Updated {updated_count} translations with default values"}
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/seed-all-defaults")
|
||||||
|
def seed_all_default_translations(db: Session = Depends(get_db)):
|
||||||
|
"""
|
||||||
|
Seed ALL translations from the DEFAULT_TRANSLATIONS dictionary into the database.
|
||||||
|
This pre-populates translations for all known terms, not just those in the cars table.
|
||||||
|
"""
|
||||||
|
added_count = 0
|
||||||
|
skipped_count = 0
|
||||||
|
|
||||||
|
for category, terms in DEFAULT_TRANSLATIONS.items():
|
||||||
|
for korean_text, translations in terms.items():
|
||||||
|
# Check if already exists
|
||||||
|
existing = db.query(Translation).filter(
|
||||||
|
Translation.source_text == korean_text,
|
||||||
|
Translation.category == category
|
||||||
|
).first()
|
||||||
|
|
||||||
|
if existing:
|
||||||
|
skipped_count += 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
trans = Translation(
|
||||||
|
source_text=korean_text,
|
||||||
|
category=category,
|
||||||
|
text_en=translations.get("en", korean_text),
|
||||||
|
text_mn=translations.get("mn", korean_text),
|
||||||
|
text_ru=translations.get("ru", korean_text)
|
||||||
|
)
|
||||||
|
db.add(trans)
|
||||||
|
added_count += 1
|
||||||
|
|
||||||
|
db.commit()
|
||||||
|
|
||||||
|
return {
|
||||||
|
"message": f"Seeded {added_count} translations from default dictionary (skipped {skipped_count} existing)",
|
||||||
|
"added": added_count,
|
||||||
|
"skipped": skipped_count,
|
||||||
|
"categories": list(DEFAULT_TRANSLATIONS.keys())
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
# AI Auto-Translation Service
|
# AI Auto-Translation Service
|
||||||
import httpx
|
import httpx
|
||||||
import json
|
import json
|
||||||
|
|||||||
@@ -115,6 +115,18 @@ export default function TranslationsPage() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleSeedAllDefaults = async () => {
|
||||||
|
try {
|
||||||
|
const result = await translationsApi.seedAllDefaults();
|
||||||
|
alert(`${result.message}\n\nCategories: ${result.categories.join(', ')}`);
|
||||||
|
loadTranslations();
|
||||||
|
loadStats();
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Failed to seed defaults:', err);
|
||||||
|
alert('Failed to seed default translations');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleAutoTranslate = async (translation: Translation) => {
|
const handleAutoTranslate = async (translation: Translation) => {
|
||||||
setTranslatingId(translation.id);
|
setTranslatingId(translation.id);
|
||||||
try {
|
try {
|
||||||
@@ -217,9 +229,20 @@ export default function TranslationsPage() {
|
|||||||
<div className="flex justify-between items-center mb-6">
|
<div className="flex justify-between items-center mb-6">
|
||||||
<h1 className="text-2xl font-bold text-gray-800">Translations Management</h1>
|
<h1 className="text-2xl font-bold text-gray-800">Translations Management</h1>
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
|
<button
|
||||||
|
onClick={handleSeedAllDefaults}
|
||||||
|
className="bg-indigo-600 text-white px-4 py-2 rounded-lg hover:bg-indigo-700 flex items-center gap-2"
|
||||||
|
title="Load all predefined translations (makers, models, colors, fuels, etc.)"
|
||||||
|
>
|
||||||
|
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12" />
|
||||||
|
</svg>
|
||||||
|
Seed Defaults
|
||||||
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={handleAutoExtract}
|
onClick={handleAutoExtract}
|
||||||
className="bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 flex items-center gap-2"
|
className="bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 flex items-center gap-2"
|
||||||
|
title="Extract terms from cars in database"
|
||||||
>
|
>
|
||||||
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
|
||||||
|
|||||||
@@ -294,6 +294,11 @@ export const translationsApi = {
|
|||||||
return data;
|
return data;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
seedAllDefaults: async (): Promise<{ message: string; added: number; skipped: number; categories: string[] }> => {
|
||||||
|
const { data } = await api.post('/translations/seed-all-defaults');
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
|
||||||
bulkLookup: async (texts: string[], lang: string, category?: string): Promise<{ translations: Record<string, string> }> => {
|
bulkLookup: async (texts: string[], lang: string, category?: string): Promise<{ translations: Record<string, string> }> => {
|
||||||
const { data } = await api.post('/translations/bulk-lookup', {
|
const { data } = await api.post('/translations/bulk-lookup', {
|
||||||
texts,
|
texts,
|
||||||
|
|||||||
Reference in New Issue
Block a user