Update model translations

This commit is contained in:
qananasikq
2026-07-01 14:42:35 +03:00
parent 1c5c30e31e
commit efbbf4a067
7 changed files with 805 additions and 2 deletions

View File

@@ -26,6 +26,9 @@ from .translations import (
FUEL_TYPE_MAP,
GEARBOX_MAP_KO,
MODEL_BODY_TYPE_MAP,
MODEL_EXACT_TRANSLATIONS,
MODEL_PHRASE_TRANSLATIONS,
MODEL_TOKEN_TRANSLATIONS,
MODEL_TRANSLATIONS,
SELL_TYPE_MAP,
expand_allowed_brands,
@@ -173,7 +176,7 @@ class EncarMapper:
model_raw = self._as_str(payload.get("Model") or "UNKNOWN")
badge = self._as_str(payload.get("Badge") or "")
badge_detail = self._as_str(payload.get("BadgeDetail") or "")
model = self._translate_text(model_raw)
model = self._translate_model(model_raw)
year = self._to_year(payload.get("FormYear") or payload.get("Year"))
# Price в 만원 (10 000 KRW) → переводим в KRW
@@ -352,6 +355,68 @@ class EncarMapper:
translated = re.sub(r"\s+", " ", translated).strip()
return translated
def _has_korean(self, text: str) -> bool:
return bool(re.search(r"[가-힣]", text))
def _normalize_model_text(self, text: str) -> str:
normalized = self._as_str(text)
if not normalized:
return normalized
# На оригинальном сайте Encar скобок нет — убираем скобки вместе с содержимым.
normalized = re.sub(r"[\(\[(【][^)\])】]*[\)\])】]?", " ", normalized)
normalized = normalized.replace("·", " ").replace("/", " ")
normalized = re.sub(r"(?<=[A-Za-z])-클래스", " 클래스", normalized)
normalized = re.sub(r"(?<=[0-9])시리즈", "시리즈", normalized)
normalized = re.sub(r"\s+", " ", normalized).strip()
return normalized
def _translate_model(self, text: str) -> str:
"""Безопасно переводит модель Encar: точные совпадения + корейские фрагменты.
Старый общий replace ломал смешанные названия. Здесь английские строки
возвращаются как есть, а короткие корейские токены заменяются только
когда они реально присутствуют как отдельный смысловой фрагмент.
"""
original = self._normalize_model_text(text)
if not original or not self._has_korean(original):
return original
exact = MODEL_EXACT_TRANSLATIONS.get(original)
if exact:
return exact
translated = original
# Сначала длинные точные модели и фразы — чтобы "렉с턴 스포츠 칸"
# не превратился в "Rexton Sport 칸".
combined = {**MODEL_EXACT_TRANSLATIONS, **MODEL_PHRASE_TRANSLATIONS, **MODEL_TRANSLATIONS}
for source, target in sorted(combined.items(), key=lambda item: len(item[0]), reverse=True):
if source in translated:
# Заменяем только когда корейский ключ стоит как отдельный
# смысловой фрагмент (границы — не корейские символы). Иначе
# короткий ключ "레이" (Ray) резал бы "슈팅브레이크" → "슈팅브Ray크".
pattern = rf"(?<![가-힣]){re.escape(source)}(?![가-힣])"
translated = re.sub(pattern, target, translated)
# Потом безопасные короткие токены.
for source, target in sorted(MODEL_TOKEN_TRANSLATIONS.items(), key=lambda item: len(item[0]), reverse=True):
translated = re.sub(rf"(?<![A-Za-z0-9가-힣]){re.escape(source)}(?![A-Za-z0-9가-힣])", target, translated)
# Типовые слитные варианты Encar: 5시리즈, S-클래스.
translated = re.sub(r"(?<=\d)시리즈", " Series", translated)
translated = re.sub(r"(?<=[A-Za-z])-?클래스", "-Class", translated)
translated = re.sub(r"\b([A-Z]{1,4}) Class\b", r"\1-Class", translated)
# Оставшиеся непереведённые корейские фрагменты отбрасываем — как на
# оригинальном сайте (напр. "슈팅브레이크" исчезает, не портя слово).
translated = re.sub(r"[가-힣]+", " ", translated)
# Чистим осиротевшую пунктуацию/скобки после удаления корейского.
translated = re.sub(r"\(\s*\)", " ", translated)
translated = re.sub(r"\s*-\s*(?=$|\))", "", translated)
translated = re.sub(r"\s+([),])", r"\1", translated)
translated = re.sub(r"\s+", " ", translated).strip(" -")
return translated
def _translate_color(self, color_raw: str) -> str:
value = self._as_str(color_raw)
if not value: