mirror of
https://github.com/SamyRai/turash.git
synced 2025-12-26 23:01:33 +00:00
203 lines
6.2 KiB
Go
203 lines
6.2 KiB
Go
package service
|
|
|
|
import (
|
|
"bugulma/backend/internal/domain"
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
"sync"
|
|
)
|
|
|
|
// TranslationCache provides caching for translations to avoid redundant API calls
|
|
// DEPRECATED: This cache is kept for backward compatibility but should not be used in new code.
|
|
// Use TranslationCacheService instead, which provides better features (LRU eviction, stats, context support).
|
|
// TranslationCache will be removed in a future version.
|
|
type TranslationCache struct {
|
|
repo domain.LocalizationRepository
|
|
cache map[string]map[string]string // [russianText][targetLocale] -> translation
|
|
mu sync.RWMutex
|
|
commonTerms map[string]map[string]string // Pre-populated common terms
|
|
}
|
|
|
|
// NewTranslationCache creates a new translation cache
|
|
func NewTranslationCache(repo domain.LocalizationRepository) *TranslationCache {
|
|
cache := &TranslationCache{
|
|
repo: repo,
|
|
cache: make(map[string]map[string]string),
|
|
commonTerms: make(map[string]map[string]string),
|
|
}
|
|
cache.initCommonTerms()
|
|
return cache
|
|
}
|
|
|
|
// initCommonTerms initializes common translation terms that appear frequently
|
|
func (tc *TranslationCache) initCommonTerms() {
|
|
// Common materials
|
|
tc.commonTerms["кирпич"] = map[string]string{
|
|
"en": "brick",
|
|
"tt": "кирпич", // Keep same for Tatar or translate if needed
|
|
}
|
|
|
|
// Common architectural styles
|
|
tc.commonTerms["модерн"] = map[string]string{
|
|
"en": "modern",
|
|
"tt": "модерн",
|
|
}
|
|
|
|
tc.commonTerms["эклектика"] = map[string]string{
|
|
"en": "eclecticism",
|
|
"tt": "эклектика",
|
|
}
|
|
|
|
// Common building types
|
|
tc.commonTerms["доходный дом"] = map[string]string{
|
|
"en": "income-producing house",
|
|
"tt": "доходный дом",
|
|
}
|
|
|
|
tc.commonTerms["мельница"] = map[string]string{
|
|
"en": "mill",
|
|
"tt": "тегермән",
|
|
}
|
|
|
|
// Common roles
|
|
tc.commonTerms["купец"] = map[string]string{
|
|
"en": "merchant",
|
|
"tt": "сәүдәгәр",
|
|
}
|
|
|
|
tc.commonTerms["архитектор"] = map[string]string{
|
|
"en": "architect",
|
|
"tt": "архитектор",
|
|
}
|
|
}
|
|
|
|
// GetCachedTranslation checks cache and database for existing translation
|
|
// Returns (translation, found, error)
|
|
func (tc *TranslationCache) GetCachedTranslation(ctx context.Context, russianText, targetLocale, entityType, field string) (string, bool, error) {
|
|
if russianText == "" {
|
|
return "", false, nil
|
|
}
|
|
|
|
// Normalize text for cache lookup (trim whitespace, lowercase for common terms)
|
|
normalized := strings.TrimSpace(russianText)
|
|
|
|
// Check in-memory cache first
|
|
tc.mu.RLock()
|
|
if localeMap, ok := tc.cache[normalized]; ok {
|
|
if translation, found := localeMap[targetLocale]; found && translation != "" {
|
|
tc.mu.RUnlock()
|
|
return translation, true, nil
|
|
}
|
|
}
|
|
tc.mu.RUnlock()
|
|
|
|
// Check common terms (exact match)
|
|
if localeMap, ok := tc.commonTerms[normalized]; ok {
|
|
if translation, found := localeMap[targetLocale]; found && translation != "" {
|
|
// Cache it
|
|
tc.mu.Lock()
|
|
if tc.cache[normalized] == nil {
|
|
tc.cache[normalized] = make(map[string]string)
|
|
}
|
|
tc.cache[normalized][targetLocale] = translation
|
|
tc.mu.Unlock()
|
|
return translation, true, nil
|
|
}
|
|
}
|
|
|
|
// Check database for existing translation of the same Russian text
|
|
// Search for any entity with the same Russian source text translated to target locale
|
|
existing, err := tc.findExistingTranslation(ctx, normalized, targetLocale, entityType, field)
|
|
if err == nil && existing != "" {
|
|
// Cache it
|
|
tc.mu.Lock()
|
|
if tc.cache[normalized] == nil {
|
|
tc.cache[normalized] = make(map[string]string)
|
|
}
|
|
tc.cache[normalized][targetLocale] = existing
|
|
tc.mu.Unlock()
|
|
return existing, true, nil
|
|
}
|
|
|
|
return "", false, nil
|
|
}
|
|
|
|
// findExistingTranslation searches the database for an existing translation
|
|
// by looking for the same Russian text pattern in source entities
|
|
func (tc *TranslationCache) findExistingTranslation(ctx context.Context, russianText, targetLocale, entityType, field string) (string, error) {
|
|
if russianText == "" {
|
|
return "", nil
|
|
}
|
|
|
|
normalized := strings.TrimSpace(russianText)
|
|
if normalized == "" {
|
|
return "", nil
|
|
}
|
|
|
|
// Search for Russian localizations with matching text
|
|
ruLocalizations, err := tc.repo.SearchLocalizations(ctx, normalized, "ru", 10)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
// Find a matching Russian localization and check for target locale translation
|
|
for _, ruLoc := range ruLocalizations {
|
|
if ruLoc.EntityType == entityType && ruLoc.Field == field && ruLoc.Value == normalized {
|
|
// Found matching Russian text, check for target locale translation
|
|
targetLoc, err := tc.repo.GetByEntityAndField(ctx, ruLoc.EntityType, ruLoc.EntityID, ruLoc.Field, targetLocale)
|
|
if err == nil && targetLoc != nil && targetLoc.Value != "" {
|
|
return targetLoc.Value, nil
|
|
}
|
|
}
|
|
}
|
|
|
|
return "", nil
|
|
}
|
|
|
|
// SetCachedTranslation stores a translation in the cache
|
|
func (tc *TranslationCache) SetCachedTranslation(russianText, targetLocale, translation string) {
|
|
if russianText == "" || translation == "" {
|
|
return
|
|
}
|
|
|
|
normalized := strings.TrimSpace(russianText)
|
|
tc.mu.Lock()
|
|
defer tc.mu.Unlock()
|
|
|
|
if tc.cache[normalized] == nil {
|
|
tc.cache[normalized] = make(map[string]string)
|
|
}
|
|
tc.cache[normalized][targetLocale] = translation
|
|
}
|
|
|
|
// ClearCache clears the in-memory cache
|
|
func (tc *TranslationCache) ClearCache() {
|
|
tc.mu.Lock()
|
|
defer tc.mu.Unlock()
|
|
tc.cache = make(map[string]map[string]string)
|
|
}
|
|
|
|
// PreloadCache preloads common translations from the database
|
|
func (tc *TranslationCache) PreloadCache(ctx context.Context, entityType, field, targetLocale string) error {
|
|
// Get all localizations for this entity type and locale
|
|
localizations, err := tc.repo.GetByEntityTypeAndLocale(ctx, entityType, targetLocale)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get localizations: %w", err)
|
|
}
|
|
|
|
// Filter by field and cache translations with their Russian source
|
|
for _, loc := range localizations {
|
|
if loc.Field == field {
|
|
// Get the Russian source text for this entity/field
|
|
ruLoc, err := tc.repo.GetByEntityAndField(ctx, loc.EntityType, loc.EntityID, loc.Field, "ru")
|
|
if err == nil && ruLoc != nil && ruLoc.Value != "" {
|
|
// Cache the translation with its Russian source
|
|
tc.SetCachedTranslation(ruLoc.Value, targetLocale, loc.Value)
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|