Методология6 мин чтения

Как назвать еду на шести языках: что мы поняли

Перевод названий продуктов — это не словарь, а культурология. Что мы научились локализуя 845+ продуктов на 6 языков для каталога Vnutri.

Слово 'apple' в шести языках на одной странице — apple, manzana, poma, pomme, Apfel, яблоко

В Vnutri каждое имя продукта переведено на 6 языков: en, es, ca, fr, de, ru. Это ~5 000 уникальных строк (845 продуктов × 6 локалей). Когда мы начали локализацию, казалось, что задача — найти словарь и прогнать каталог через переводчик. Через 3 месяца стало ясно: перевод названий еды — это не словарь.

Почему обычный перевод не работает

Три проблемы.

1. Имя — не описание. «Pollock» по-английски — это рыба. По-русски — «минтай». Google Translate выдаёт «полок» (буквально транслитерируя), потому что не знает, что речь о рыбе. Минтай — это knowledge о категории и регионе, не о буквальном переводе.

2. Сорта — региональны. Apple Honeycrisp в США — обычный сорт. В Европе он редкий. Apple Granny Smith — наоборот. Когда я говорю «apple» по-английски, я подразумеваю средний американский сорт; «manzana» по-испански — средний испанский. Это разные физические продукты с близкими, но не идентичными нутрициональными профилями.

3. Регионализмы. «Eggplant» (US) = «aubergine» (UK) = «berenjena» (ES) = «albergínia» (CA) = «aubergine» (FR) = «Aubergine» (DE) = «баклажан» (RU). На английском это уже две разных конвенции в одном языке. То же с «zucchini» / «courgette».

И худшее — научные названия. «Salmo salar» — это атлантический лосось. Большинство переводчиков просто оставляют латынь («Anguilliformes»), потому что не знают, что это «угорь».

Три слоя локализации

Мы построили пайплайн из трёх слоёв, каждый дешевле предыдущего, но менее точный для редких случаев.

Слой 1: OFF ingredients taxonomy

Open Food Facts ingredients taxonomy — кураторный мультиязычный словарь продуктов. 4 212 записей × 100+ языков каждая. Лицензия ODbL, можно использовать.

Match rate: ~70 % продуктов в каталоге находятся в OFF. Это первый и самый дешёвый pass.

Match tiered:

  1. Direct (apple → apple) → берём перевод.
  2. Singularized (apples → apple) → берём перевод.
  3. 2-token sorted subkey (black beans → beans + black) → берём перевод.
  4. Reversed subkey (beans black → black beans) → берём перевод.
  5. Head noun (chocolate dark → chocolate) → берём перевод (с осторожностью).

При совпадении — берём готовые имена из OFF на все 6 локалей. Качество отличное: OFF — curated, false matches практически невозможны.

Слой 2: Wikidata

Для оставшихся ~30 % продуктов — Wikidata через wbsearchentities API. Tiered picker с фильтрами по P31 (instance of food).

  1. Exact label/alias match + food signal в description/P31.
  2. Substring overlap + strong food keyword (vegetable, fish, meat).
  3. P31 в food whitelist (Q2095 food, Q3314483 cultivar, Q502163 fruit).
  4. Description matches broad food regex.

Внутри tier сортируем по realTranslationCount — это отсеивает scientific binomials, которые скопированы в каждый язык неизменными.

Match rate: ~25 % дополнительных продуктов. Кэшируется. Большая часть остановилась на ~476 продуктах — Wikidata aggressive rate limits unauthenticated.

Слой 3: Google Cloud Translation v3 (Translation LLM)

Финальный pass. general/translation-llm model в us-central1. Это не обычный NMT (neural machine translation) — Translation LLM лучше для food names со state.

Почему LLM лучше NMT:

  • Гендерное согласование. «cooked adzuki beans» → испанский: «judías adzuki cocidas» ✓ feminine plural. NMT даёт masculine default «cocido», что грамматически неправильно. LLM видит существительное в той же строке и применяет правильное согласование.
  • Идиоматическая лексика. «pollock» → русский: NMT даёт «поллок», LLM даёт «минтай». «cloudberry» → french: NMT эхом возвращает «cloudberry», LLM даёт «mûre des marais».

Стоимость — $80/M chars (vs $20 для NMT). Для 5 000 × 30 символов × 5 не-EN локалей = ~$60 на полный прогон. Кэшируется per (phrase, lang).

После LLM-pass'а — hardcoded fix-table для 13 LLM-галлюцинаций, которые мы поймали ручной валидацией.

Конкретные ловушки

Что мы научились в процессе.

Бренды. «Blackberry» по-английски — ягода. LLM иногда переводит как «BlackBerry» (телефон) в Spanish. Fix: hardcoded блок-лист брендов.

Аббревиатуры. «fig» (англ. инжир) — LLM в German перевёл как «Abb.», русский как «рис.» (думая, что это «figure» в таблице). Слово вышло из контекста, и LLM выбрал статистически частое значение «fig.» (figure abbreviation).

Пассив-агрессивные binomials. Wikidata часто хранит латинские названия как primary label («Anguilliformes» для «eel»). Если эти binomials копируются как «переводы», то 100+ языков получают одинаковую латинскую строку, которая выглядит как «много переводов» — но это все одна и та же строка. Фильтр на realTranslationCount (count distinct languages that have different strings) убирает эти случаи.

Переключение глагол/существительное. «skate» по-английски — рыба (морской скат). LLM в русский перевёл как «кататься на коньках» (skating). Контекст «100 г skate» не помог — LLM выбрал более частое значение.

Sushi-эффект. Японские слова, заимствованные в большинство европейских языков. «Tofu», «miso», «sushi», «edamame» — остаются как есть на всех 6 локалях. Не переводим.

State suffix

Раз отдельная проблема — состояния. «apple cooked» → русский должен быть «яблоко, варёное» (с гендерным согласованием для среднего рода). LLM с этим справляется, но только если comma-suffix преобразован в adjective-prefix перед посылкой: «apple, cooked» → «cooked apple» → «варёное яблоко».

Иначе LLM переводит comma-form буквально как «яблоко, готовое», что калька с английского и грамматически странно по-русски.

Это hardcoded transform до LLM-вызова. Comma-form → natural noun phrase → LLM → natural target noun phrase.

Word order по локалям

Английский кладёт прилагательное перед существительным: «red apple». Французский — после: «pomme rouge». Испанский — после: «manzana roja» (но некоторые перед: «buena manzana»). Каталонский — почти всегда после.

При прямом переводе LLM держит порядок исходного языка. Это даёт некрасивые «manzana roja» вместо «manzana roja» (good) или «pomme rouge» вместо «pomme rouge» (good). Чаще проблема всплывает с длинными compound names: «raw black beans» → «judías negras crudas» (правильно) vs «crudas judías negras» (неправильно).

Финальный reorder-pass (Claude Sonnet, cached) проходит по каждой локали и переставляет слова в noun-first форму. Это отдельный stage в пайплайне.

Halal/Kosher не пишем

Это про process certification, а не про сам продукт. «Kosher cheese» — это не тот же сыр, что обычный сыр (требования к производству). Vnutri не помечает продукты как halal/kosher — это не свойство продукта, а свойство процесса производства. См. 9 diet explained, где это объяснено.

Покрытие

После трёх слоёв пайплайна:

  • en — 100 % (canonical)
  • es — 95 %
  • ca — 90 %
  • fr — 94 %
  • de — 92 %
  • ru — 89 %

Остатки — где имя точно не есть в OFF/Wikidata, и LLM выдал что-то некорректное. Они обрабатываются ручной правкой в name-overrides.json.

Что мы НЕ делаем

  • Не переводим бренды. Если в имени brand-name, оно остаётся как есть.
  • Не выдаём LLM свободу. Каждый перевод проверяется против OFF/Wikidata, где есть data point.
  • Не доверяем NMT. Только Translation LLM или curated taxonomy.

Открытые проблемы

Региональные сорта. «Apple» — в каталоге одно усреднённое яблоко. У русского пользователя «яблоко» — это, вероятно, антоновка или гала; у американского — Honeycrisp или Red Delicious. Разные физические продукты с близкими, но не идентичными нутриционными профилями.

Локальные блюда. Pelmeni, borscht, kasha — слова, которые в каждом языке существуют, но обозначают слегка разные физические блюда. Vnutri usually uses Russian/source-language name with English transliteration as anchor.

Транслитерация vs перевод. «Sushi» в немецком — «Sushi». «Sushi» в русском — «суши». «Pizza» в немецком — «Pizza». «Pizza» в русском — «пицца». Когда транслитерировать, когда переводить — нет жёстких правил, мы идём по convention.

Подробнее

Архитектура каталога — где наши данные. Технические детали реализации — в коде apps/scripts/ репозитория.

Источники