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

В позиционной записи строки элемент — это значение содержимого ячейки, а значение
текста по общей конвенции бывает строкой либо объектом «язык → текст». Значит
объект {ru, en} там законен так же, как строка, и новой формы это не заводит.

Раньше ячейка с многоязычным текстом не считалась «простой», поэтому строка
двуязычного макета оставалась объектной:

  { "cells": [{ "text": { "ru": "Пусто", "en": "Empty" } }, { … }] }
  [{ "ru": "Пусто", "en": "Empty" }, { … }]

Объект-элемент читается как ячейка, если несёт хоть один её ключ, и как текст
в противном случае: идентификаторы языков с ключами ячейки не пересекаются
(в корпусе это ru, en, ru1, Русский).

Попутно исправлен признак «список позиционный»: он искал элемент-строку, поэтому
строка из одних многоязычных текстов позиционной не признавалась и ключ cells
у неё оставался.

Правка не должна менять скомпилированный XML — и не меняет: пилот из 40 макетов
собрался побайтово так же, JSON при этом изменился у 13. Стенд 7 из 10.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-08-11 21:13:32 +03:00
co-authored by Claude Opus 5
parent f926acd4f4
commit b5fef09844
6 changed files with 62 additions and 17 deletions
@@ -1,4 +1,4 @@
# mxl-compile v1.36 — Compile 1C spreadsheet from JSON
# mxl-compile v1.37 — Compile 1C spreadsheet from JSON
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param(
[Parameter(Mandatory)]
@@ -845,6 +845,17 @@ function Set-CellProp {
$cell | Add-Member -NotePropertyName $name -NotePropertyValue $value -Force
}
# Ячейка это или многоязычный текст: у ячейки есть хоть один ключ её схемы, у ML-значения
# ключи — идентификаторы языков. Пересечений нет: в корпусе это ru, en, ru1, Русский.
function Test-CellObject {
param($el)
$cellKeys = @('col', 'span', 'rowspan', 'style', 'param', 'detail', 'text', 'template')
foreach ($p in $el.PSObject.Properties) {
if ($cellKeys -contains $p.Name) { return $true }
}
return $false
}
function Expand-ShorthandRow {
param($row, [string]$areaName, [int]$rowIdx, $openByCol, [int]$maxCols)
@@ -897,6 +908,12 @@ function Expand-ShorthandRow {
$m = [regex]::Match($el, '^\{(.+)\}$')
if ($m.Success) { Set-CellProp $cell 'param' $m.Groups[1].Value }
else { Set-CellProp $cell 'text' $el }
} elseif (-not (Test-CellObject $el)) {
# Объект без единого ключа ячейки — это многоязычный ТЕКСТ: в позиционной записи
# элемент и есть значение текста, а значение текста по общей конвенции бывает
# строкой либо объектом «язык → текст».
$cell = [PSCustomObject]@{ col = $idx; span = 1 }
Set-CellProp $cell 'text' $el
} else {
# Объектный элемент — обычная ячейка mxl, позиция берётся из индекса.
if ($el.PSObject.Properties['col']) {
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# mxl-compile v1.36 — Compile 1C spreadsheet from JSON
# mxl-compile v1.37 — Compile 1C spreadsheet from JSON
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
import hashlib
@@ -884,6 +884,13 @@ def main():
# "{Имя}" — параметр. Разворачиваем в обычную строку с явными col/span/rowspan,
# поэтому весь код ниже про шорткат не знает.
def is_cell_object(el):
"""Ячейка это или многоязычный текст: у ячейки есть хоть один ключ её схемы,
у ML-значения ключи — идентификаторы языков. Пересечений нет: в корпусе это
ru, en, ru1, Русский."""
cell_keys = ('col', 'span', 'rowspan', 'style', 'param', 'detail', 'text', 'template')
return any(k in el for k in cell_keys)
def expand_shorthand_row(row, area_name, row_idx, open_by_col, max_cols):
cells = []
placed = {} # 1-based col -> ячейка, занимающая колонку в ЭТОЙ строке
@@ -933,6 +940,11 @@ def main():
cell['param'] = m.group(1)
else:
cell['text'] = el
elif not is_cell_object(el):
# Объект без единого ключа ячейки — это многоязычный ТЕКСТ: в позиционной
# записи элемент и есть значение текста, а значение текста по общей конвенции
# бывает строкой либо объектом «язык → текст».
cell = CIDict({'col': idx, 'span': 1, 'text': el})
else:
# Объектный элемент — обычная ячейка mxl, позиция берётся из индекса.
if 'col' in el: