mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-08-13 15:03:20 +03:00
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:
co-authored by
Claude Opus 5
parent
f926acd4f4
commit
b5fef09844
@@ -144,12 +144,16 @@
|
|||||||
| Элемент | Значение |
|
| Элемент | Значение |
|
||||||
|---------|----------|
|
|---------|----------|
|
||||||
| `"текст"` | Статический текст (`text`) |
|
| `"текст"` | Статический текст (`text`) |
|
||||||
|
| `{ "ru": "…", "en": "…" }` | Тот же текст на нескольких языках |
|
||||||
| `"{Имя}"` | Параметр (`param`) |
|
| `"{Имя}"` | Параметр (`param`) |
|
||||||
| `">"` | Продолжение ячейки слева — увеличивает её `span` |
|
| `">"` | Продолжение ячейки слева — увеличивает её `span` |
|
||||||
| `"|"` | Продолжение ячейки сверху — увеличивает её `rowspan` |
|
| `"|"` | Продолжение ячейки сверху — увеличивает её `rowspan` |
|
||||||
| `null` | Пустая колонка: позиция занята, ячейка не создаётся |
|
| `null` | Пустая колонка: позиция занята, ячейка не создаётся |
|
||||||
| `{ ... }` | Обычная ячейка **без** `col`; нужна для `style`, `detail`, `template` |
|
| `{ ... }` | Обычная ячейка **без** `col`; нужна для `style`, `detail`, `template` |
|
||||||
|
|
||||||
|
Объект-элемент читается как ячейка, если несёт хоть один её ключ (`span`, `rowspan`, `style`,
|
||||||
|
`param`, `detail`, `text`, `template`), и как многоязычный текст в противном случае.
|
||||||
|
|
||||||
```json
|
```json
|
||||||
"rows": [
|
"rows": [
|
||||||
["Вид", "Остаток", ">", "Итог"],
|
["Вид", "Остаток", ">", "Итог"],
|
||||||
|
|||||||
@@ -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
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
param(
|
param(
|
||||||
[Parameter(Mandatory)]
|
[Parameter(Mandatory)]
|
||||||
@@ -845,6 +845,17 @@ function Set-CellProp {
|
|||||||
$cell | Add-Member -NotePropertyName $name -NotePropertyValue $value -Force
|
$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 {
|
function Expand-ShorthandRow {
|
||||||
param($row, [string]$areaName, [int]$rowIdx, $openByCol, [int]$maxCols)
|
param($row, [string]$areaName, [int]$rowIdx, $openByCol, [int]$maxCols)
|
||||||
|
|
||||||
@@ -897,6 +908,12 @@ function Expand-ShorthandRow {
|
|||||||
$m = [regex]::Match($el, '^\{(.+)\}$')
|
$m = [regex]::Match($el, '^\{(.+)\}$')
|
||||||
if ($m.Success) { Set-CellProp $cell 'param' $m.Groups[1].Value }
|
if ($m.Success) { Set-CellProp $cell 'param' $m.Groups[1].Value }
|
||||||
else { Set-CellProp $cell 'text' $el }
|
else { Set-CellProp $cell 'text' $el }
|
||||||
|
} elseif (-not (Test-CellObject $el)) {
|
||||||
|
# Объект без единого ключа ячейки — это многоязычный ТЕКСТ: в позиционной записи
|
||||||
|
# элемент и есть значение текста, а значение текста по общей конвенции бывает
|
||||||
|
# строкой либо объектом «язык → текст».
|
||||||
|
$cell = [PSCustomObject]@{ col = $idx; span = 1 }
|
||||||
|
Set-CellProp $cell 'text' $el
|
||||||
} else {
|
} else {
|
||||||
# Объектный элемент — обычная ячейка mxl, позиция берётся из индекса.
|
# Объектный элемент — обычная ячейка mxl, позиция берётся из индекса.
|
||||||
if ($el.PSObject.Properties['col']) {
|
if ($el.PSObject.Properties['col']) {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/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
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
import argparse
|
import argparse
|
||||||
import hashlib
|
import hashlib
|
||||||
@@ -884,6 +884,13 @@ def main():
|
|||||||
# "{Имя}" — параметр. Разворачиваем в обычную строку с явными col/span/rowspan,
|
# "{Имя}" — параметр. Разворачиваем в обычную строку с явными 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):
|
def expand_shorthand_row(row, area_name, row_idx, open_by_col, max_cols):
|
||||||
cells = []
|
cells = []
|
||||||
placed = {} # 1-based col -> ячейка, занимающая колонку в ЭТОЙ строке
|
placed = {} # 1-based col -> ячейка, занимающая колонку в ЭТОЙ строке
|
||||||
@@ -933,6 +940,11 @@ def main():
|
|||||||
cell['param'] = m.group(1)
|
cell['param'] = m.group(1)
|
||||||
else:
|
else:
|
||||||
cell['text'] = el
|
cell['text'] = el
|
||||||
|
elif not is_cell_object(el):
|
||||||
|
# Объект без единого ключа ячейки — это многоязычный ТЕКСТ: в позиционной
|
||||||
|
# записи элемент и есть значение текста, а значение текста по общей конвенции
|
||||||
|
# бывает строкой либо объектом «язык → текст».
|
||||||
|
cell = CIDict({'col': idx, 'span': 1, 'text': el})
|
||||||
else:
|
else:
|
||||||
# Объектный элемент — обычная ячейка mxl, позиция берётся из индекса.
|
# Объектный элемент — обычная ячейка mxl, позиция берётся из индекса.
|
||||||
if 'col' in el:
|
if 'col' in el:
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# mxl-decompile v1.15 — Decompile 1C spreadsheet to JSON
|
# mxl-decompile v1.16 — Decompile 1C spreadsheet to JSON
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
param(
|
param(
|
||||||
[Parameter(Mandatory)]
|
[Parameter(Mandatory)]
|
||||||
@@ -631,20 +631,17 @@ function Get-ColumnStyles {
|
|||||||
return $out
|
return $out
|
||||||
}
|
}
|
||||||
|
|
||||||
# Список признаётся позиционным по тому же правилу, что и в компиляторе: есть элемент-строка
|
# Список позиционный, если позиция в нём НЕ записана: ни у одного элемента нет col.
|
||||||
# или пропуск. Список из одних объектов таковым не считаем — он читается как обычный.
|
# Прежняя проверка искала элемент-строку, поэтому строка из одних многоязычных текстов
|
||||||
|
# позиционной не признавалась и оставалась объектной.
|
||||||
function Test-PositionalList {
|
function Test-PositionalList {
|
||||||
param($cells)
|
param($cells)
|
||||||
foreach ($el in $cells) {
|
foreach ($el in $cells) {
|
||||||
if ($null -eq $el -or $el -is [string]) { return $true }
|
if ($el -is [System.Collections.IDictionary] -and $el.Contains('col')) { return $false }
|
||||||
}
|
}
|
||||||
return $false
|
return $true
|
||||||
}
|
}
|
||||||
|
|
||||||
# Позиционная запись списка ячеек: позиция берётся из порядка, `col` не пишется.
|
|
||||||
# Применяем, когда первая ячейка стоит в колонке 1 — иначе список начнётся с череды null
|
|
||||||
# и станет длиннее объектного. Ячейка, у которой кроме текста или параметра ничего нет,
|
|
||||||
# пишется строкой; span раскрывается маркерами ">"; всё прочее — объектным элементом без col.
|
|
||||||
# Custom JSON serializer — компактный, 2-пробельный indent, массивы примитивов inline.
|
# Custom JSON serializer — компактный, 2-пробельный indent, массивы примитивов inline.
|
||||||
# В отличие от ConvertTo-Json (PS5.1):
|
# В отличие от ConvertTo-Json (PS5.1):
|
||||||
# - не выравнивает ключи объекта по самому длинному
|
# - не выравнивает ключи объекта по самому длинному
|
||||||
@@ -771,6 +768,10 @@ function ConvertTo-CompactJson {
|
|||||||
return (Convert-StringToJsonLiteral "$obj")
|
return (Convert-StringToJsonLiteral "$obj")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Позиционная запись списка ячеек: позиция берётся из порядка, `col` не пишется.
|
||||||
|
# Ячейка, у которой кроме текста или параметра ничего нет, пишется значением; span
|
||||||
|
# раскрывается маркерами ">"; пропуск колонки — null; всё прочее — объектным элементом
|
||||||
|
# без col. Выбираем ту запись, которая КОРОЧЕ.
|
||||||
function ConvertTo-PositionalCells {
|
function ConvertTo-PositionalCells {
|
||||||
param($cells)
|
param($cells)
|
||||||
# Пропуск колонки — null. Выбираем ту запись, которая КОРОЧЕ: раньше позиционная форма
|
# Пропуск колонки — null. Выбираем ту запись, которая КОРОЧЕ: раньше позиционная форма
|
||||||
@@ -787,10 +788,12 @@ function ConvertTo-PositionalCells {
|
|||||||
|
|
||||||
$span = if ($c.Contains("span")) { [int]$c["span"] } else { 1 }
|
$span = if ($c.Contains("span")) { [int]$c["span"] } else { 1 }
|
||||||
$keys = @($c.Keys | Where-Object { $_ -notin @("col", "span") })
|
$keys = @($c.Keys | Where-Object { $_ -notin @("col", "span") })
|
||||||
$plainText = ($keys.Count -eq 1 -and $keys[0] -eq "text" -and $c["text"] -is [string])
|
# Текст — единственное содержимое: пишем значением. Оно бывает строкой либо
|
||||||
|
# объектом «язык → текст», и в позиционной записи элемент И ЕСТЬ это значение.
|
||||||
|
$plainText = ($keys.Count -eq 1 -and $keys[0] -eq "text")
|
||||||
$plainParam = ($keys.Count -eq 1 -and $keys[0] -eq "param")
|
$plainParam = ($keys.Count -eq 1 -and $keys[0] -eq "param")
|
||||||
|
|
||||||
if ($plainText) { $out += $c["text"] }
|
if ($plainText) { $out += , $c["text"] }
|
||||||
elseif ($plainParam) { $out += "{$($c["param"])}" }
|
elseif ($plainParam) { $out += "{$($c["param"])}" }
|
||||||
else {
|
else {
|
||||||
$obj = [ordered]@{}
|
$obj = [ordered]@{}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# mxl-decompile v1.15 — Decompile 1C spreadsheet to JSON
|
# mxl-decompile v1.16 — Decompile 1C spreadsheet to JSON
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
@@ -791,7 +791,7 @@ def main():
|
|||||||
|
|
||||||
def to_positional_cells(cells):
|
def to_positional_cells(cells):
|
||||||
"""Позиционная запись списка ячеек: позиция берётся из порядка, `col` не пишется.
|
"""Позиционная запись списка ячеек: позиция берётся из порядка, `col` не пишется.
|
||||||
Ячейка, у которой кроме текста или параметра ничего нет, пишется строкой; span
|
Ячейка, у которой кроме текста или параметра ничего нет, пишется значением; span
|
||||||
раскрывается маркерами ">"; прочее — объектным элементом без col. Пропуск колонки —
|
раскрывается маркерами ">"; прочее — объектным элементом без col. Пропуск колонки —
|
||||||
null. Выбираем ту запись, которая КОРОЧЕ: раньше позиционная форма отбрасывалась,
|
null. Выбираем ту запись, которая КОРОЧЕ: раньше позиционная форма отбрасывалась,
|
||||||
как только первая ячейка стояла не в первой колонке, хотя один-два null впереди
|
как только первая ячейка стояла не в первой колонке, хотя один-два null впереди
|
||||||
@@ -809,7 +809,9 @@ def main():
|
|||||||
expected += 1
|
expected += 1
|
||||||
span = int(c.get("span", 1) or 1)
|
span = int(c.get("span", 1) or 1)
|
||||||
keys = [k for k in c if k not in ("col", "span")]
|
keys = [k for k in c if k not in ("col", "span")]
|
||||||
plain_text = len(keys) == 1 and keys[0] == "text" and isinstance(c["text"], str)
|
# Текст — единственное содержимое: пишем значением. Оно бывает строкой либо
|
||||||
|
# объектом «язык → текст», и в позиционной записи элемент И ЕСТЬ это значение.
|
||||||
|
plain_text = len(keys) == 1 and keys[0] == "text"
|
||||||
plain_param = len(keys) == 1 and keys[0] == "param"
|
plain_param = len(keys) == 1 and keys[0] == "param"
|
||||||
if plain_text:
|
if plain_text:
|
||||||
out.append(c["text"])
|
out.append(c["text"])
|
||||||
@@ -1019,8 +1021,11 @@ def main():
|
|||||||
dsl_row["cells"] = to_positional_cells(dsl_cells)
|
dsl_row["cells"] = to_positional_cells(dsl_cells)
|
||||||
# Самая короткая из применимых форм: если у строки нет своих свойств, а список ячеек
|
# Самая короткая из применимых форм: если у строки нет своих свойств, а список ячеек
|
||||||
# позиционный — строка пишется просто массивом, без ключа cells.
|
# позиционный — строка пишется просто массивом, без ключа cells.
|
||||||
|
# Список позиционный, если позиция в нём НЕ записана: ни у одного элемента нет col.
|
||||||
|
# Прежняя проверка искала элемент-строку, поэтому строка из одних многоязычных
|
||||||
|
# текстов позиционной не признавалась и оставалась объектной.
|
||||||
if (len(dsl_row) == 1 and "cells" in dsl_row
|
if (len(dsl_row) == 1 and "cells" in dsl_row
|
||||||
and any(el is None or isinstance(el, str) for el in dsl_row["cells"])):
|
and not any(isinstance(el, dict) and "col" in el for el in dsl_row["cells"])):
|
||||||
area_rows.append(dsl_row["cells"])
|
area_rows.append(dsl_row["cells"])
|
||||||
else:
|
else:
|
||||||
area_rows.append(dsl_row)
|
area_rows.append(dsl_row)
|
||||||
|
|||||||
@@ -144,12 +144,16 @@
|
|||||||
| Элемент | Значение |
|
| Элемент | Значение |
|
||||||
|---------|----------|
|
|---------|----------|
|
||||||
| `"текст"` | Статический текст (`text`) |
|
| `"текст"` | Статический текст (`text`) |
|
||||||
|
| `{ "ru": "…", "en": "…" }` | Тот же текст на нескольких языках |
|
||||||
| `"{Имя}"` | Параметр (`param`) |
|
| `"{Имя}"` | Параметр (`param`) |
|
||||||
| `">"` | Продолжение ячейки слева — увеличивает её `span` |
|
| `">"` | Продолжение ячейки слева — увеличивает её `span` |
|
||||||
| `"|"` | Продолжение ячейки сверху — увеличивает её `rowspan` |
|
| `"|"` | Продолжение ячейки сверху — увеличивает её `rowspan` |
|
||||||
| `null` | Пустая колонка: позиция занята, ячейка не создаётся |
|
| `null` | Пустая колонка: позиция занята, ячейка не создаётся |
|
||||||
| `{ ... }` | Обычная ячейка **без** `col`; нужна для `style`, `detail`, `template` |
|
| `{ ... }` | Обычная ячейка **без** `col`; нужна для `style`, `detail`, `template` |
|
||||||
|
|
||||||
|
Объект-элемент читается как ячейка, если несёт хоть один её ключ (`span`, `rowspan`, `style`,
|
||||||
|
`param`, `detail`, `text`, `template`), и как многоязычный текст в противном случае.
|
||||||
|
|
||||||
```json
|
```json
|
||||||
"rows": [
|
"rows": [
|
||||||
["Вид", "Остаток", ">", "Итог"],
|
["Вид", "Остаток", ">", "Итог"],
|
||||||
|
|||||||
Reference in New Issue
Block a user