feat(mxl-compile,mxl-decompile): многоязычный текст ячейки

Платформа хранит текст ячейки по элементу на язык. Декомпилятор брал ПЕРВЫЙ и терял
остальное, компилятор писал всегда ru захардкоженно. В корпусе ERP текст лежит и под
ru, и под en у 10 730 макетов из 10 924 — то есть терялось у 98%.

Форма взята готовая — конвенция ML-значений из docs/meta-dsl-spec.md §4.4, по которой
уже живут synonym, tooltip и title в метаданных и формах: строка означает русский
текст, объект даёт по надписи на язык в порядке ключей. Новых понятий не вводили,
ключи те же (text и template).

Документный ключ для языков НЕ заводили, и это измерение, а не экономия: блок
languageSettings мы и так эмитим байт в байт как платформа (currentLanguage ru,
defaultLanguage ru, один languageInfo). Отклонения редки — 8 макетов ERP с
currentLanguage en, 3 без него, 157 с объявленной парой ru+en, всего около 1,6%.
Заодно это снимает развилку из разбора PR #62: список языков компилятор дописывать
не должен, платформа его не дописывает.

Эффект на пилоте: категория row[].cell[].tl упала с 47 252 до 12 488 — минус 74%,
самое крупное улучшение кампании. Остаток частично классифицирован: 348 строк — ячейки
с ПУСТЫМ <tl> у оригинала, которых мы не эмитим вовсе; полностью разобрать мешает
обрезка диффа по 400 строк на объект.

Снэпшоты не дрейфанули: кейсы пишут текст строкой, и вывод для неё прежний.

Проверено: тесты 54/54 на обоих рантаймах, verify-snapshots 24/24, вывод портов
совпадает байт в байт и в компиляции, и в декомпиляции.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-08-10 20:52:03 +03:00
co-authored by Claude Opus 5
parent 572b75984a
commit 1e06e43e92
8 changed files with 228 additions and 45 deletions
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# mxl-decompile v1.5 — Decompile 1C spreadsheet to JSON
# mxl-decompile v1.6 — Decompile 1C spreadsheet to JSON
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
@@ -428,10 +428,22 @@ def main():
if d_node is not None and d_node.text:
detail = d_node.text
# Текст ячейки платформа хранит по элементу на язык. Раньше брался ПЕРВЫЙ, и всё
# остальное терялось — в корпусе ERP 98% макетов держат текст и под ru, и под en.
# Конвенция ML-значений: только ru → строка, иначе объект «язык → текст».
text = None
t_node = find(c_content, "d:tl/v8:item/v8:content")
if t_node is not None and t_node.text:
text = t_node.text
items = findall(c_content, "d:tl/v8:item")
if items:
by_lang = OrderedDict()
for it in items:
lang_node = find(it, "v8:lang")
content_node = find(it, "v8:content")
lang = (text_of(lang_node) or '') if lang_node is not None else ''
by_lang[lang] = (text_of(content_node) or '') if content_node is not None else ''
if len(by_lang) == 1 and 'ru' in by_lang:
text = by_lang['ru']
else:
text = by_lang
cells.append({
"Col": col,