mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-08-13 06:53:21 +03:00
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:
co-authored by
Claude Opus 5
parent
572b75984a
commit
1e06e43e92
@@ -214,8 +214,8 @@
|
||||
| `style` | нет | rowStyle | Стиль ячейки (переопределяет rowStyle) |
|
||||
| `param` | нет | — | Параметр заполнения |
|
||||
| `detail` | нет | — | Параметр расшифровки (только с `param`) |
|
||||
| `text` | нет | — | Статический текст |
|
||||
| `template` | нет | — | Шаблонный текст с `[Параметр]` |
|
||||
| `text` | нет | — | Статический текст. Строка или объект `{ ru, en }` — см. ниже |
|
||||
| `template` | нет | — | Шаблонный текст с `[Параметр]`. Строка или объект, как `text` |
|
||||
|
||||
### Содержимое ячейки
|
||||
|
||||
@@ -225,6 +225,17 @@
|
||||
- `text` — статический текст;
|
||||
- ничего — пустая ячейка (нужна, например, ради рамки).
|
||||
|
||||
### Текст на нескольких языках
|
||||
|
||||
`text` и `template` принимают строку или объект «язык → текст». Строка означает русский; объект даёт по надписи на каждый язык, в порядке ключей.
|
||||
|
||||
```json
|
||||
{ "col": 1, "text": "Наименование" }
|
||||
{ "col": 2, "text": { "ru": "Поставщик", "en": "Supplier" } }
|
||||
```
|
||||
|
||||
Языки макета объявляются отдельно (`languageSettings` в XML) и по умолчанию ограничены русским; писать текст на языке, которого нет в объявленных, допустимо — так устроено большинство типовых макетов.
|
||||
|
||||
## `rowStyle` — автозаполнение
|
||||
|
||||
Стиль применяется ко ВСЕЙ ширине строки: позиции без явных ячеек получают тот же стиль. Так в табличных строках получаются сплошные рамки.
|
||||
@@ -244,8 +255,8 @@ XML не возвращается.
|
||||
- рамка с разным стилем у разных сторон; стили линий кроме сплошной;
|
||||
- группировки строк и колонок;
|
||||
- колонтитулы, параметры печати, область печати;
|
||||
- многоязычные надписи: при разборе берётся первый вариант текста, при генерации язык
|
||||
всегда `ru`, остальные теряются.
|
||||
- объявление языков макета: список языков и текущий язык всегда описываются как русский —
|
||||
сами надписи при этом сохраняются на всех языках.
|
||||
|
||||
Пересборка макета из DSL — это полная перегенерация, а не точечная правка XML, поэтому
|
||||
diff после round-trip обычно шире фактической доработки.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# mxl-compile v1.23 — Compile 1C spreadsheet from JSON (+write_xml_file/write_utf8_bom: общий эталон записи)
|
||||
# mxl-compile v1.24 — Compile 1C spreadsheet from JSON (+write_xml_file/write_utf8_bom: общий эталон записи)
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
@@ -558,6 +558,29 @@ function Esc-XmlText {
|
||||
return $s.Replace('&','&').Replace('<','<').Replace('>','>')
|
||||
}
|
||||
|
||||
# Текст ячейки платформа хранит по элементу на язык. Конвенция ML-значений (та же, что у
|
||||
# synonym/tooltip/title в метаданных и формах): строка — русский текст, объект — по элементу
|
||||
# на язык В ПОРЯДКЕ КЛЮЧЕЙ.
|
||||
function Emit-CellText {
|
||||
param($value)
|
||||
$pairs = @()
|
||||
if ($value -is [System.Collections.IDictionary]) {
|
||||
foreach ($k in $value.Keys) { $pairs += @{ Lang = "$k"; Text = "$($value[$k])" } }
|
||||
} elseif ($value -is [System.Management.Automation.PSCustomObject]) {
|
||||
foreach ($p in $value.PSObject.Properties) { $pairs += @{ Lang = $p.Name; Text = "$($p.Value)" } }
|
||||
} else {
|
||||
$pairs += @{ Lang = 'ru'; Text = "$value" }
|
||||
}
|
||||
X "`t`t`t`t`t<tl>"
|
||||
foreach ($p in $pairs) {
|
||||
X "`t`t`t`t`t`t<v8:item>"
|
||||
X "`t`t`t`t`t`t`t<v8:lang>$($p.Lang)</v8:lang>"
|
||||
X "`t`t`t`t`t`t`t<v8:content>$(Esc-XmlText $p.Text)</v8:content>"
|
||||
X "`t`t`t`t`t`t</v8:item>"
|
||||
}
|
||||
X "`t`t`t`t`t</tl>"
|
||||
}
|
||||
|
||||
# Helper: determine fillType from cell content
|
||||
# Text НЕ эмитим: платформа его практически не пишет — на выборке корпуса 344 981 текстовая
|
||||
# ячейка из 348 023 (99,1%) ссылается на формат БЕЗ fillType. Наличие <tl> и так означает
|
||||
@@ -1045,23 +1068,9 @@ foreach ($area in $def.areas) {
|
||||
}
|
||||
}
|
||||
|
||||
if ($cellInfo.Text) {
|
||||
X "`t`t`t`t`t<tl>"
|
||||
X "`t`t`t`t`t`t<v8:item>"
|
||||
X "`t`t`t`t`t`t`t<v8:lang>ru</v8:lang>"
|
||||
X "`t`t`t`t`t`t`t<v8:content>$(Esc-XmlText $cellInfo.Text)</v8:content>"
|
||||
X "`t`t`t`t`t`t</v8:item>"
|
||||
X "`t`t`t`t`t</tl>"
|
||||
}
|
||||
if ($cellInfo.Text) { Emit-CellText $cellInfo.Text }
|
||||
|
||||
if ($cellInfo.Template) {
|
||||
X "`t`t`t`t`t<tl>"
|
||||
X "`t`t`t`t`t`t<v8:item>"
|
||||
X "`t`t`t`t`t`t`t<v8:lang>ru</v8:lang>"
|
||||
X "`t`t`t`t`t`t`t<v8:content>$(Esc-XmlText $cellInfo.Template)</v8:content>"
|
||||
X "`t`t`t`t`t`t</v8:item>"
|
||||
X "`t`t`t`t`t</tl>"
|
||||
}
|
||||
if ($cellInfo.Template) { Emit-CellText $cellInfo.Template }
|
||||
|
||||
X "`t`t`t`t</c>"
|
||||
X "`t`t`t</c>"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
# mxl-compile v1.23 — Compile 1C spreadsheet from JSON (+write_xml_file/write_utf8_bom: общий эталон записи)
|
||||
# mxl-compile v1.24 — Compile 1C spreadsheet from JSON (+write_xml_file/write_utf8_bom: общий эталон записи)
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
import argparse
|
||||
import hashlib
|
||||
@@ -606,6 +606,22 @@ def main():
|
||||
col_format_map = column_layouts[0]['FormatMap']
|
||||
|
||||
# 6c. Helper: determine fillType from cell content
|
||||
# Текст ячейки платформа хранит по элементу на язык. Конвенция ML-значений (та же, что у
|
||||
# synonym/tooltip/title в метаданных и формах): строка — русский текст, объект — по элементу
|
||||
# на язык В ПОРЯДКЕ КЛЮЧЕЙ.
|
||||
def emit_cell_text(lines, value):
|
||||
if isinstance(value, dict):
|
||||
pairs = [(str(k), str(v)) for k, v in value.items()]
|
||||
else:
|
||||
pairs = [('ru', str(value))]
|
||||
lines.append('\t\t\t\t\t<tl>')
|
||||
for lang, content in pairs:
|
||||
lines.append('\t\t\t\t\t\t<v8:item>')
|
||||
lines.append(f'\t\t\t\t\t\t\t<v8:lang>{lang}</v8:lang>')
|
||||
lines.append(f'\t\t\t\t\t\t\t<v8:content>{esc_xml_text(content)}</v8:content>')
|
||||
lines.append('\t\t\t\t\t\t</v8:item>')
|
||||
lines.append('\t\t\t\t\t</tl>')
|
||||
|
||||
def get_fill_type(cell):
|
||||
"""Text НЕ эмитим: платформа его практически не пишет — на выборке корпуса 344 981
|
||||
текстовая ячейка из 348 023 (99,1%) ссылается на формат БЕЗ fillType. Наличие <tl>
|
||||
@@ -1033,20 +1049,10 @@ def main():
|
||||
lines.append(f'\t\t\t\t\t<detailParameter>{cell_info["Detail"]}</detailParameter>')
|
||||
|
||||
if cell_info['Text']:
|
||||
lines.append('\t\t\t\t\t<tl>')
|
||||
lines.append('\t\t\t\t\t\t<v8:item>')
|
||||
lines.append('\t\t\t\t\t\t\t<v8:lang>ru</v8:lang>')
|
||||
lines.append(f'\t\t\t\t\t\t\t<v8:content>{esc_xml_text(cell_info["Text"])}</v8:content>')
|
||||
lines.append('\t\t\t\t\t\t</v8:item>')
|
||||
lines.append('\t\t\t\t\t</tl>')
|
||||
emit_cell_text(lines, cell_info['Text'])
|
||||
|
||||
if cell_info['Template']:
|
||||
lines.append('\t\t\t\t\t<tl>')
|
||||
lines.append('\t\t\t\t\t\t<v8:item>')
|
||||
lines.append('\t\t\t\t\t\t\t<v8:lang>ru</v8:lang>')
|
||||
lines.append(f'\t\t\t\t\t\t\t<v8:content>{esc_xml_text(cell_info["Template"])}</v8:content>')
|
||||
lines.append('\t\t\t\t\t\t</v8:item>')
|
||||
lines.append('\t\t\t\t\t</tl>')
|
||||
emit_cell_text(lines, cell_info['Template'])
|
||||
|
||||
lines.append('\t\t\t\t</c>')
|
||||
lines.append('\t\t\t</c>')
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# 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
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
@@ -248,9 +248,22 @@ foreach ($riNode in $root.SelectNodes("d:rowsItem", $ns)) {
|
||||
$dNode = $cContent.SelectSingleNode("d:detailParameter", $ns)
|
||||
if ($dNode) { $detail = $dNode.InnerText }
|
||||
|
||||
# Текст ячейки платформа хранит по элементу на язык. Раньше брался ПЕРВЫЙ, и всё
|
||||
# остальное терялось — в корпусе ERP 98% макетов держат текст и под ru, и под en.
|
||||
# Конвенция ML-значений: только ru → строка, иначе объект «язык → текст».
|
||||
$text = $null
|
||||
$tNode = $cContent.SelectSingleNode("d:tl/v8:item/v8:content", $ns)
|
||||
if ($tNode) { $text = $tNode.InnerText }
|
||||
$items = $cContent.SelectNodes("d:tl/v8:item", $ns)
|
||||
if ($items -and $items.Count -gt 0) {
|
||||
$byLang = [ordered]@{}
|
||||
foreach ($it in $items) {
|
||||
$langNode = $it.SelectSingleNode("v8:lang", $ns)
|
||||
$contentNode = $it.SelectSingleNode("v8:content", $ns)
|
||||
$lang = if ($langNode) { $langNode.InnerText } else { '' }
|
||||
$byLang[$lang] = if ($contentNode) { $contentNode.InnerText } else { '' }
|
||||
}
|
||||
if ($byLang.Count -eq 1 -and $byLang.Contains('ru')) { $text = $byLang['ru'] }
|
||||
else { $text = $byLang }
|
||||
}
|
||||
|
||||
$cells += @{
|
||||
Col = $col
|
||||
|
||||
@@ -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,
|
||||
|
||||
+15
-4
@@ -214,8 +214,8 @@
|
||||
| `style` | нет | rowStyle | Стиль ячейки (переопределяет rowStyle) |
|
||||
| `param` | нет | — | Параметр заполнения |
|
||||
| `detail` | нет | — | Параметр расшифровки (только с `param`) |
|
||||
| `text` | нет | — | Статический текст |
|
||||
| `template` | нет | — | Шаблонный текст с `[Параметр]` |
|
||||
| `text` | нет | — | Статический текст. Строка или объект `{ ru, en }` — см. ниже |
|
||||
| `template` | нет | — | Шаблонный текст с `[Параметр]`. Строка или объект, как `text` |
|
||||
|
||||
### Содержимое ячейки
|
||||
|
||||
@@ -225,6 +225,17 @@
|
||||
- `text` — статический текст;
|
||||
- ничего — пустая ячейка (нужна, например, ради рамки).
|
||||
|
||||
### Текст на нескольких языках
|
||||
|
||||
`text` и `template` принимают строку или объект «язык → текст». Строка означает русский; объект даёт по надписи на каждый язык, в порядке ключей.
|
||||
|
||||
```json
|
||||
{ "col": 1, "text": "Наименование" }
|
||||
{ "col": 2, "text": { "ru": "Поставщик", "en": "Supplier" } }
|
||||
```
|
||||
|
||||
Языки макета объявляются отдельно (`languageSettings` в XML) и по умолчанию ограничены русским; писать текст на языке, которого нет в объявленных, допустимо — так устроено большинство типовых макетов.
|
||||
|
||||
## `rowStyle` — автозаполнение
|
||||
|
||||
Стиль применяется ко ВСЕЙ ширине строки: позиции без явных ячеек получают тот же стиль. Так в табличных строках получаются сплошные рамки.
|
||||
@@ -244,8 +255,8 @@ XML не возвращается.
|
||||
- рамка с разным стилем у разных сторон; стили линий кроме сплошной;
|
||||
- группировки строк и колонок;
|
||||
- колонтитулы, параметры печати, область печати;
|
||||
- многоязычные надписи: при разборе берётся первый вариант текста, при генерации язык
|
||||
всегда `ru`, остальные теряются.
|
||||
- объявление языков макета: список языков и текущий язык всегда описываются как русский —
|
||||
сами надписи при этом сохраняются на всех языках.
|
||||
|
||||
Пересборка макета из DSL — это полная перегенерация, а не точечная правка XML, поэтому
|
||||
diff после round-trip обычно шире фактической доработки.
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document xmlns="http://v8.1c.ru/8.2/data/spreadsheet" xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:v8="http://v8.1c.ru/8.1/data/core" xmlns:v8ui="http://v8.1c.ru/8.1/data/ui" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<languageSettings>
|
||||
<currentLanguage>ru</currentLanguage>
|
||||
<defaultLanguage>ru</defaultLanguage>
|
||||
<languageInfo>
|
||||
<id>ru</id>
|
||||
<code>Русский</code>
|
||||
<description>Русский</description>
|
||||
</languageInfo>
|
||||
</languageSettings>
|
||||
<columns>
|
||||
<size>3</size>
|
||||
</columns>
|
||||
<rowsItem>
|
||||
<index>0</index>
|
||||
<row>
|
||||
<c>
|
||||
<i>0</i>
|
||||
<c>
|
||||
<f>1</f>
|
||||
<tl>
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Только по-русски</v8:content>
|
||||
</v8:item>
|
||||
</tl>
|
||||
</c>
|
||||
</c>
|
||||
<c>
|
||||
<i>1</i>
|
||||
<c>
|
||||
<f>1</f>
|
||||
<tl>
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Поставщик</v8:content>
|
||||
</v8:item>
|
||||
<v8:item>
|
||||
<v8:lang>en</v8:lang>
|
||||
<v8:content>Supplier</v8:content>
|
||||
</v8:item>
|
||||
</tl>
|
||||
</c>
|
||||
</c>
|
||||
<c>
|
||||
<i>2</i>
|
||||
<c>
|
||||
<f>2</f>
|
||||
<tl>
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Итого: [Сумма]</v8:content>
|
||||
</v8:item>
|
||||
<v8:item>
|
||||
<v8:lang>en</v8:lang>
|
||||
<v8:content>Total: [Сумма]</v8:content>
|
||||
</v8:item>
|
||||
</tl>
|
||||
</c>
|
||||
</c>
|
||||
</row>
|
||||
</rowsItem>
|
||||
<templateMode>true</templateMode>
|
||||
<defaultFormatIndex>1</defaultFormatIndex>
|
||||
<height>1</height>
|
||||
<vgRows>1</vgRows>
|
||||
<namedItem xsi:type="NamedItemCells">
|
||||
<name>Шапка</name>
|
||||
<area>
|
||||
<type>Rows</type>
|
||||
<beginRow>0</beginRow>
|
||||
<endRow>0</endRow>
|
||||
<beginColumn>-1</beginColumn>
|
||||
<endColumn>-1</endColumn>
|
||||
</area>
|
||||
</namedItem>
|
||||
<font faceName="Arial" height="10" bold="false" italic="false" underline="false" strikeout="false" kind="Absolute" scale="100"/>
|
||||
<format>
|
||||
<width>10</width>
|
||||
</format>
|
||||
<format>
|
||||
<font>0</font>
|
||||
<fillType>Template</fillType>
|
||||
</format>
|
||||
</document>
|
||||
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"name": "Многоязычный текст ячейки: строка = ru, объект = по элементу на язык",
|
||||
"input": {
|
||||
"columns": 3,
|
||||
"areas": [
|
||||
{
|
||||
"name": "Шапка",
|
||||
"rows": [
|
||||
{
|
||||
"cells": [
|
||||
{ "col": 1, "text": "Только по-русски" },
|
||||
{ "col": 2, "text": { "ru": "Поставщик", "en": "Supplier" } },
|
||||
{ "col": 3, "template": { "ru": "Итого: [Сумма]", "en": "Total: [Сумма]" } }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"params": {
|
||||
"outputPath": "Template.xml"
|
||||
},
|
||||
"validatePath": "Template.xml",
|
||||
"expect": {
|
||||
"files": ["Template.xml"],
|
||||
"fileContains": {
|
||||
"file": "Template.xml",
|
||||
"text": [
|
||||
"<v8:lang>en</v8:lang>",
|
||||
"<v8:content>Supplier</v8:content>",
|
||||
"<v8:content>Поставщик</v8:content>"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user