feat(mxl-compile,mxl-decompile): textLanguages — текст строкой на всех языках макета

Строка в text/template разворачивается по одному элементу на каждый язык из
документного ключа textLanguages (по умолчанию только ru). Декомпилятор собирает
набор языков по всем текстам макета и пишет строкой текст, одинаковый на всём
наборе; различающийся остаётся объектом.

Языки текстов и языки, объявленные в конфигурации, — разные вещи: типовые ERP
объявляют один ru, а тексты хранят под ru и en. Набор постоянен внутри
конфигурации, поэтому он документный, а не вычисляемый: к моменту компиляции
тексты уже свёрнуты в строки.

Заодно: эмиссия tl проверяет НАЛИЧИЕ ключа text/template, а не истинность —
пустая строка это текст, платформа такие ячейки пишет с пустым tl, а по
истинности он терялся.

Проверено на пилоте (40 макетов ERP): скомпилированный XML совпадает с прошлым
прогоном байт в байт обоими рантаймами, объём JSON −47%.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-08-11 12:00:20 +03:00
co-authored by Claude Opus 5
parent 4cceb03269
commit 683ed8e08d
10 changed files with 340 additions and 36 deletions
@@ -77,6 +77,7 @@
| `page` | нет | — | Формат страницы: `"A4-landscape"` (780), `"A4-portrait"` (540) или число. Автоматически вычисляет `defaultWidth` из суммы пропорций `"Nx"` |
| `defaultWidth` | нет | 10 | Ширина колонок по умолчанию. Игнорируется если задан `page` и все колонки используют `"Nx"` |
| `columnWidths` | нет | `{}` | Ширины колонок. Ключи 1-based: `"1"`, `"3-14"`, `"5,7,9"`. Значения: число (абсолют) или `"Nx"` (множитель от defaultWidth, напр. `"2x"`, `"0.5x"`) |
| `textLanguages` | нет | `["ru"]` | Языки, на которых пишется текст, заданный строкой (см. ниже) |
| `fonts` | нет | — | Именованные шрифты (если не задано, создаётся Arial 10) |
| `styles` | нет | `{}` | Именованные стили |
| `areas` | да | — | Массив областей — диапазонов подряд идущих строк (порядок = порядок в документе); имя необязательно |
@@ -227,14 +228,26 @@
### Текст на нескольких языках
`text` и `template` принимают строку или объект «язык → текст». Строка означает русский; объект даёт по надписи на каждый язык, в порядке ключей.
`text` и `template` принимают строку или объект «язык → текст». Объект даёт по надписи на каждый язык, в порядке ключей. Строка означает один и тот же текст на всех языках макета — по умолчанию только русский.
```json
{ "col": 1, "text": "Наименование" }
{ "col": 2, "text": { "ru": "Поставщик", "en": "Supplier" } }
```
Языки макета объявляются отдельно (`languageSettings` в XML) и по умолчанию ограничены русским; писать текст на языке, которого нет в объявленных, допустимо — так устроено большинство типовых макетов.
Набор языков задаётся документным ключом `textLanguages`:
```json
{ "columns": 3, "textLanguages": ["ru", "en"], "areas": [] }
```
С таким объявлением `"Наименование"` из примера выше даст надпись и под `ru`, и под `en`.
**Языки текстов и языки, объявленные в конфигурации, — разные вещи**, и у типовых они не совпадают: почти все макеты ERP объявляют один русский, а тексты хранят под `ru` и `en`. Писать текст на языке, которого нет среди объявленных в конфигурации, платформа позволяет.
Набор постоянен внутри конфигурации, а не подбирается под макет: в ERP это `ru` и `en` у всех макетов с текстом, в БП, УТ и УНФ — только `ru`. Поэтому `textLanguages` объявляется один раз на макет и обычно повторяет соседние. Вывести его из самих текстов компилятор не может: к моменту компиляции они уже свёрнуты в строки.
Пустая строка — это текст: ячейка с `"text": ""` даёт пустую надпись, а не ячейку без текста.
## `rowStyle` — автозаполнение
@@ -1,4 +1,4 @@
# mxl-compile v1.25 — Compile 1C spreadsheet from JSON (+write_xml_file/write_utf8_bom: общий эталон записи)
# mxl-compile v1.26 — Compile 1C spreadsheet from JSON
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param(
[Parameter(Mandatory)]
@@ -559,8 +559,14 @@ function Esc-XmlText {
}
# Текст ячейки платформа хранит по элементу на язык. Конвенция ML-значений (та же, что у
# synonym/tooltip/title в метаданных и формах): строка — русский текст, объект — по элементу
# на язык В ПОРЯДКЕ КЛЮЧЕЙ.
# synonym/tooltip/title в метаданных и формах): объект — по элементу на язык В ПОРЯДКЕ КЛЮЧЕЙ,
# строка — один и тот же текст на всех языках макета (textLanguages, по умолчанию только ru).
$textLanguages = @('ru')
if ($def.textLanguages) {
$declared = @($def.textLanguages | ForEach-Object { "$_" } | Where-Object { $_ })
if ($declared.Count -gt 0) { $textLanguages = $declared }
}
function Emit-CellText {
param($value)
$pairs = @()
@@ -569,7 +575,7 @@ function Emit-CellText {
} 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" }
foreach ($l in $textLanguages) { $pairs += @{ Lang = $l; Text = "$value" } }
}
X "`t`t`t`t`t<tl>"
foreach ($p in $pairs) {
@@ -1094,9 +1100,11 @@ foreach ($area in $def.areas) {
}
}
if ($cellInfo.Text) { Emit-CellText $cellInfo.Text }
# Проверяем НАЛИЧИЕ ключа, а не истинность: пустая строка — это текст, платформа
# такие ячейки пишет с пустым <tl>, и по истинности он терялся.
if ($null -ne $cellInfo.Text) { Emit-CellText $cellInfo.Text }
if ($cellInfo.Template) { Emit-CellText $cellInfo.Template }
if ($null -ne $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.25 — Compile 1C spreadsheet from JSON (+write_xml_file/write_utf8_bom: общий эталон записи)
# mxl-compile v1.26 — Compile 1C spreadsheet from JSON
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
import hashlib
@@ -607,13 +607,18 @@ def main():
# 6c. Helper: determine fillType from cell content
# Текст ячейки платформа хранит по элементу на язык. Конвенция ML-значений (та же, что у
# synonym/tooltip/title в метаданных и формах): строка — русский текст, объект — по элементу
# на язык В ПОРЯДКЕ КЛЮЧЕЙ.
# synonym/tooltip/title в метаданных и формах): объект — по элементу на язык В ПОРЯДКЕ
# КЛЮЧЕЙ, строка — один и тот же текст на всех языках макета (textLanguages, по умолчанию
# только ru).
text_languages = [str(x) for x in (defn.get('textLanguages') or []) if str(x)]
if not text_languages:
text_languages = ['ru']
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))]
pairs = [(lang, str(value)) for lang in text_languages]
lines.append('\t\t\t\t\t<tl>')
for lang, content in pairs:
lines.append('\t\t\t\t\t\t<v8:item>')
@@ -1072,10 +1077,12 @@ def main():
if cell_info['Detail']:
lines.append(f'\t\t\t\t\t<detailParameter>{cell_info["Detail"]}</detailParameter>')
if cell_info['Text']:
# Проверяем НАЛИЧИЕ ключа, а не истинность: пустая строка — это текст,
# платформа такие ячейки пишет с пустым <tl>, и по истинности он терялся.
if cell_info['Text'] is not None:
emit_cell_text(lines, cell_info['Text'])
if cell_info['Template']:
if cell_info['Template'] is not None:
emit_cell_text(lines, cell_info['Template'])
lines.append('\t\t\t\t</c>')
@@ -1,4 +1,4 @@
# mxl-decompile v1.8 — Decompile 1C spreadsheet to JSON
# mxl-decompile v1.9 — Decompile 1C spreadsheet to JSON
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param(
[Parameter(Mandatory)]
@@ -209,6 +209,8 @@ foreach ($niNode in $root.SelectNodes("d:namedItem", $ns)) {
# --- 8. Extract rows ---
$rowData = @{}
# Языки, на которых в макете вообще есть текст. Порядок — первого появления.
$docLangs = [ordered]@{}
foreach ($riNode in $root.SelectNodes("d:rowsItem", $ns)) {
$rowIdx = [int]$riNode.SelectSingleNode("d:index", $ns).InnerText
$rowNode = $riNode.SelectSingleNode("d:row", $ns)
@@ -250,8 +252,10 @@ foreach ($riNode in $root.SelectNodes("d:rowsItem", $ns)) {
# Текст ячейки платформа хранит по элементу на язык. Раньше брался ПЕРВЫЙ, и всё
# остальное терялось — в корпусе ERP 98% макетов держат текст и под ru, и под en.
# Конвенция ML-значений: только ru → строка, иначе объект «язык → текст».
# Здесь собираем «язык → текст» как есть; свернётся в строку позже, когда станет
# известен набор языков всего макета (Get-DslText).
$text = $null
$hasText = $false
$items = $cContent.SelectNodes("d:tl/v8:item", $ns)
if ($items -and $items.Count -gt 0) {
$byLang = [ordered]@{}
@@ -260,9 +264,12 @@ foreach ($riNode in $root.SelectNodes("d:rowsItem", $ns)) {
$contentNode = $it.SelectSingleNode("v8:content", $ns)
$lang = if ($langNode) { $langNode.InnerText } else { '' }
$byLang[$lang] = if ($contentNode) { $contentNode.InnerText } else { '' }
$docLangs[$lang] = $true
}
if ($byLang.Count -eq 1 -and $byLang.Contains('ru')) { $text = $byLang['ru'] }
else { $text = $byLang }
$text = $byLang
# Единственный пустой русский текст содержимым не считается — такая ячейка
# уходит в заполнители строки.
$hasText = -not ($byLang.Count -eq 1 -and $byLang.Contains('ru') -and "$($byLang['ru'])" -eq '')
}
$cells += @{
@@ -271,6 +278,7 @@ foreach ($riNode in $root.SelectNodes("d:rowsItem", $ns)) {
Param = $param
Detail = $detail
Text = $text
HasText = $hasText
}
}
}
@@ -290,6 +298,23 @@ foreach ($riNode in $root.SelectNodes("d:rowsItem", $ns)) {
}
}
# Языки текстов макета и языки, объявленные в конфигурации, — разные вещи: у типовых они не
# совпадают. Строкой пишем текст, одинаковый на ВСЁМ наборе языков макета; остальное — объектом.
$textLanguages = @($docLangs.Keys)
function Get-DslText {
param($byLang)
if ($byLang -isnot [System.Collections.IDictionary]) { return $byLang }
if ($byLang.Count -ne $textLanguages.Count) { return $byLang }
$common = $null
foreach ($l in $textLanguages) {
if (-not $byLang.Contains($l)) { return $byLang }
if ($null -eq $common) { $common = "$($byLang[$l])" }
elseif ("$($byLang[$l])" -cne $common) { return $byLang }
}
return $common
}
# --- 9. Build style key (ignoring fillType) ---
function Get-BorderDesc {
@@ -634,7 +659,7 @@ foreach ($area in $blocks) {
$gapCells = @()
foreach ($cell in $rd.Cells) {
$hasContent = $cell.Param -or $cell.Text
$hasContent = $cell.Param -or $cell.HasText
$hasMerge = $mergeMap.ContainsKey("$globalRow,$($cell.Col)")
if ($hasContent -or $hasMerge) {
@@ -703,10 +728,10 @@ foreach ($area in $blocks) {
if ($cell.Param) {
$dslCell["param"] = $cell.Param
if ($cell.Detail) { $dslCell["detail"] = $cell.Detail }
} elseif ($fillType -eq "Template" -and $cell.Text) {
$dslCell["template"] = $cell.Text
} elseif ($cell.Text) {
$dslCell["text"] = $cell.Text
} elseif ($fillType -eq "Template" -and $cell.HasText) {
$dslCell["template"] = Get-DslText $cell.Text
} elseif ($cell.HasText) {
$dslCell["text"] = Get-DslText $cell.Text
}
$dslCells += $dslCell
@@ -801,6 +826,10 @@ $result = [ordered]@{
defaultWidth = $defaultWidth
}
if ($compressedWidths.Count -gt 0) { $result["columnWidths"] = $compressedWidths }
# Набор языков объявляем, только если он отличается от умолчания компилятора (один ru).
if ($textLanguages.Count -gt 0 -and -not ($textLanguages.Count -eq 1 -and $textLanguages[0] -ceq 'ru')) {
$result["textLanguages"] = [array]$textLanguages
}
# Remove empty "default" style
if ($styleDefs.Contains("default") -and $styleDefs["default"].Count -eq 0) {
$styleDefs.Remove("default")
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# mxl-decompile v1.8 — Decompile 1C spreadsheet to JSON
# mxl-decompile v1.9 — Decompile 1C spreadsheet to JSON
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
@@ -380,6 +380,8 @@ def main():
# --- 8. Extract rows ---
row_data = {}
# Языки, на которых в макете вообще есть текст. Порядок — первого появления.
doc_langs = OrderedDict()
for ri_node in findall(root, "d:rowsItem"):
row_idx = int_of(find(ri_node, "d:index"))
row_node = find(ri_node, "d:row")
@@ -430,8 +432,10 @@ def main():
# Текст ячейки платформа хранит по элементу на язык. Раньше брался ПЕРВЫЙ, и всё
# остальное терялось — в корпусе ERP 98% макетов держат текст и под ru, и под en.
# Конвенция ML-значений: только ru → строка, иначе объект «язык → текст».
# Здесь собираем «язык → текст» как есть; свернётся в строку позже, когда станет
# известен набор языков всего макета (get_dsl_text).
text = None
has_text = False
items = findall(c_content, "d:tl/v8:item")
if items:
by_lang = OrderedDict()
@@ -440,10 +444,11 @@ def main():
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
doc_langs[lang] = True
text = by_lang
# Единственный пустой русский текст содержимым не считается — такая ячейка
# уходит в заполнители строки.
has_text = not (len(by_lang) == 1 and by_lang.get('ru') == '')
cells.append({
"Col": col,
@@ -451,6 +456,7 @@ def main():
"Param": param,
"Detail": detail,
"Text": text,
"HasText": has_text,
})
# Ссылка строки на колоночную раскладку; пусто = раскладка по умолчанию.
@@ -465,6 +471,26 @@ def main():
"ColumnsId": row_columns_id,
}
# Языки текстов макета и языки, объявленные в конфигурации, — разные вещи: у типовых они
# не совпадают. Строкой пишем текст, одинаковый на ВСЁМ наборе языков макета; остальное —
# объектом.
text_languages = list(doc_langs.keys())
def get_dsl_text(by_lang):
if not isinstance(by_lang, dict):
return by_lang
if len(by_lang) != len(text_languages):
return by_lang
common = None
for lang in text_languages:
if lang not in by_lang:
return by_lang
if common is None:
common = by_lang[lang]
elif by_lang[lang] != common:
return by_lang
return common
# --- 9. Build style key (ignoring fillType) ---
def get_border_desc(fmt):
@@ -791,7 +817,7 @@ def main():
gap_cells = []
for cell in rd["Cells"]:
has_content = cell["Param"] or cell["Text"]
has_content = cell["Param"] or cell["HasText"]
has_merge = f"{global_row},{cell['Col']}" in merge_map
if has_content or has_merge:
@@ -856,10 +882,10 @@ def main():
dsl_cell["param"] = cell["Param"]
if cell["Detail"]:
dsl_cell["detail"] = cell["Detail"]
elif fill_type == "Template" and cell["Text"]:
dsl_cell["template"] = cell["Text"]
elif cell["Text"]:
dsl_cell["text"] = cell["Text"]
elif fill_type == "Template" and cell["HasText"]:
dsl_cell["template"] = get_dsl_text(cell["Text"])
elif cell["HasText"]:
dsl_cell["text"] = get_dsl_text(cell["Text"])
dsl_cells.append(dsl_cell)
@@ -963,6 +989,9 @@ def main():
result["defaultWidth"] = default_width
if len(compressed_widths) > 0:
result["columnWidths"] = compressed_widths
# Набор языков объявляем, только если он отличается от умолчания компилятора (один ru).
if text_languages and text_languages != ['ru']:
result["textLanguages"] = text_languages
# Remove empty "default" style
if "default" in style_defs and len(style_defs["default"]) == 0:
+15 -2
View File
@@ -77,6 +77,7 @@
| `page` | нет | — | Формат страницы: `"A4-landscape"` (780), `"A4-portrait"` (540) или число. Автоматически вычисляет `defaultWidth` из суммы пропорций `"Nx"` |
| `defaultWidth` | нет | 10 | Ширина колонок по умолчанию. Игнорируется если задан `page` и все колонки используют `"Nx"` |
| `columnWidths` | нет | `{}` | Ширины колонок. Ключи 1-based: `"1"`, `"3-14"`, `"5,7,9"`. Значения: число (абсолют) или `"Nx"` (множитель от defaultWidth, напр. `"2x"`, `"0.5x"`) |
| `textLanguages` | нет | `["ru"]` | Языки, на которых пишется текст, заданный строкой (см. ниже) |
| `fonts` | нет | — | Именованные шрифты (если не задано, создаётся Arial 10) |
| `styles` | нет | `{}` | Именованные стили |
| `areas` | да | — | Массив областей — диапазонов подряд идущих строк (порядок = порядок в документе); имя необязательно |
@@ -227,14 +228,26 @@
### Текст на нескольких языках
`text` и `template` принимают строку или объект «язык → текст». Строка означает русский; объект даёт по надписи на каждый язык, в порядке ключей.
`text` и `template` принимают строку или объект «язык → текст». Объект даёт по надписи на каждый язык, в порядке ключей. Строка означает один и тот же текст на всех языках макета — по умолчанию только русский.
```json
{ "col": 1, "text": "Наименование" }
{ "col": 2, "text": { "ru": "Поставщик", "en": "Supplier" } }
```
Языки макета объявляются отдельно (`languageSettings` в XML) и по умолчанию ограничены русским; писать текст на языке, которого нет в объявленных, допустимо — так устроено большинство типовых макетов.
Набор языков задаётся документным ключом `textLanguages`:
```json
{ "columns": 3, "textLanguages": ["ru", "en"], "areas": [] }
```
С таким объявлением `"Наименование"` из примера выше даст надпись и под `ru`, и под `en`.
**Языки текстов и языки, объявленные в конфигурации, — разные вещи**, и у типовых они не совпадают: почти все макеты ERP объявляют один русский, а тексты хранят под `ru` и `en`. Писать текст на языке, которого нет среди объявленных в конфигурации, платформа позволяет.
Набор постоянен внутри конфигурации, а не подбирается под макет: в ERP это `ru` и `en` у всех макетов с текстом, в БП, УТ и УНФ — только `ru`. Поэтому `textLanguages` объявляется один раз на макет и обычно повторяет соседние. Вывести его из самих текстов компилятор не может: к моменту компиляции они уже свёрнуты в строки.
Пустая строка — это текст: ячейка с `"text": ""` даёт пустую надпись, а не ячейку без текста.
## `rowStyle` — автозаполнение
@@ -0,0 +1,70 @@
<?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>2</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>
<v8:item>
<v8:lang>en</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>
</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>
</document>
@@ -0,0 +1,36 @@
{
"name": "textLanguages: строка = текст на всех объявленных языках",
"input": {
"columns": 2,
"textLanguages": ["ru", "en"],
"areas": [
{
"name": "Шапка",
"rows": [
{
"cells": [
{ "col": 1, "text": "Итого" },
{ "col": 2, "text": { "ru": "Поставщик", "en": "Supplier" } }
]
}
]
}
]
},
"params": {
"outputPath": "Template.xml"
},
"validatePath": "Template.xml",
"expect": {
"files": ["Template.xml"],
"fileContains": {
"file": "Template.xml",
"text": [
"<v8:lang>ru</v8:lang>",
"<v8:lang>en</v8:lang>",
"<v8:content>Итого</v8:content>",
"<v8:content>Supplier</v8:content>"
]
}
}
}
@@ -0,0 +1,29 @@
{
"name": "Декомпиляция макета с текстом на нескольких языках",
"preRun": [
{
"script": "mxl-compile/scripts/mxl-compile",
"input": {
"columns": 2,
"textLanguages": ["ru", "en"],
"areas": [
{
"name": "Test",
"rows": [
{
"cells": [
{ "col": 1, "text": "Итого" },
{ "col": 2, "text": { "ru": "Поставщик", "en": "Supplier" } }
]
}
]
}
]
},
"args": { "-JsonPath": "{inputFile}", "-OutputPath": "Template.xml" },
"cwd": "{workDir}"
}
],
"params": { "templatePath": "Template.xml" },
"expect": { "stdoutContains": "textLanguages" }
}
@@ -0,0 +1,70 @@
<?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>2</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>
<v8:item>
<v8:lang>en</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>
</row>
</rowsItem>
<templateMode>true</templateMode>
<defaultFormatIndex>1</defaultFormatIndex>
<height>1</height>
<vgRows>1</vgRows>
<namedItem xsi:type="NamedItemCells">
<name>Test</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>
</document>