diff --git a/.claude/skills/form-compile/scripts/form-compile.ps1 b/.claude/skills/form-compile/scripts/form-compile.ps1
index d2981494..44f1c497 100644
--- a/.claude/skills/form-compile/scripts/form-compile.ps1
+++ b/.claude/skills/form-compile/scripts/form-compile.ps1
@@ -1,4 +1,4 @@
-# form-compile v1.23 — Compile 1C managed form from JSON or object metadata
+# form-compile v1.24 — Compile 1C managed form from JSON or object metadata
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param(
[string]$JsonPath,
@@ -1878,7 +1878,7 @@ function Emit-Element {
$typeKey = $null
$xmlTag = $null
- foreach ($key in @("columnGroup","group","input","check","radio","label","labelField","table","pages","page","button","picture","picField","calendar","cmdBar","popup")) {
+ foreach ($key in @("columnGroup","buttonGroup","group","input","check","radio","label","labelField","table","pages","page","button","picture","picField","calendar","cmdBar","popup")) {
if ($el.$key -ne $null) {
$typeKey = $key
break
@@ -1893,7 +1893,7 @@ function Emit-Element {
# Validate known keys — warn about typos and unknown properties
$knownKeys = @{
# type keys
- "group"=1;"columnGroup"=1;"input"=1;"check"=1;"radio"=1;"label"=1;"labelField"=1;"table"=1;"pages"=1;"page"=1
+ "group"=1;"columnGroup"=1;"buttonGroup"=1;"input"=1;"check"=1;"radio"=1;"label"=1;"labelField"=1;"table"=1;"pages"=1;"page"=1
"button"=1;"picture"=1;"picField"=1;"calendar"=1;"cmdBar"=1;"popup"=1
# columnGroup-specific
"showInHeader"=1
@@ -1945,6 +1945,7 @@ function Emit-Element {
switch ($typeKey) {
"group" { Emit-Group -el $el -name $name -id $id -indent $indent }
"columnGroup" { Emit-ColumnGroup -el $el -name $name -id $id -indent $indent }
+ "buttonGroup" { Emit-ButtonGroup -el $el -name $name -id $id -indent $indent }
"input" { Emit-Input -el $el -name $name -id $id -indent $indent }
"check" { Emit-Check -el $el -name $name -id $id -indent $indent }
"radio" { Emit-Radio -el $el -name $name -id $id -indent $indent }
@@ -2787,6 +2788,35 @@ function Emit-CommandBar {
X "$indent"
}
+function Emit-ButtonGroup {
+ param($el, [string]$name, [int]$id, [string]$indent)
+
+ X "$indent"
+ $inner = "$indent`t"
+
+ Emit-Title -el $el -name $name -indent $inner
+
+ if ($el.representation) {
+ X "$inner$($el.representation)"
+ }
+
+ Emit-CommonFlags -el $el -indent $inner
+
+ # Companion: ExtendedTooltip
+ Emit-Companion -tag "ExtendedTooltip" -name "${name}РасширеннаяПодсказка" -indent $inner
+
+ # Children (кнопки в контексте командной панели)
+ if ($el.children -and $el.children.Count -gt 0) {
+ X "$inner"
+ foreach ($child in $el.children) {
+ Emit-Element -el $child -indent "$inner`t" -inCmdBar $true
+ }
+ X "$inner"
+ }
+
+ X "$indent"
+}
+
function Emit-Popup {
param($el, [string]$name, [int]$id, [string]$indent)
@@ -2933,10 +2963,18 @@ function Emit-Commands {
Emit-MLText -tag "Title" -text "$cmdTitle" -indent $inner
}
+ if ($cmd.tooltip) {
+ Emit-MLText -tag "ToolTip" -text "$($cmd.tooltip)" -indent $inner
+ }
+
if ($cmd.action) {
X "$inner$($cmd.action)"
}
+ if ($cmd.currentRowUse) {
+ X "$inner$($cmd.currentRowUse)"
+ }
+
if ($cmd.shortcut) {
X "$inner$($cmd.shortcut)"
}
diff --git a/.claude/skills/form-compile/scripts/form-compile.py b/.claude/skills/form-compile/scripts/form-compile.py
index 9910f9b7..b4fc7ea1 100644
--- a/.claude/skills/form-compile/scripts/form-compile.py
+++ b/.claude/skills/form-compile/scripts/form-compile.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# form-compile v1.23 — Compile 1C managed form from JSON or object metadata
+# form-compile v1.24 — Compile 1C managed form from JSON or object metadata
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
import copy
@@ -1338,7 +1338,7 @@ KNOWN_FORM_EVENTS = [
]
KNOWN_KEYS = {
- "group", "columnGroup", "input", "check", "radio", "label", "labelField", "table", "pages", "page",
+ "group", "columnGroup", "buttonGroup", "input", "check", "radio", "label", "labelField", "table", "pages", "page",
"button", "picture", "picField", "calendar", "cmdBar", "popup",
"showInHeader",
"radioButtonType", "choiceList", "columnsCount",
@@ -1364,7 +1364,7 @@ KNOWN_KEYS = {
"rowPictureDataPath", "tableAutofill",
}
-TYPE_KEYS = ["columnGroup", "group", "input", "check", "radio", "label", "labelField", "table", "pages", "page",
+TYPE_KEYS = ["columnGroup", "buttonGroup", "group", "input", "check", "radio", "label", "labelField", "table", "pages", "page",
"button", "picture", "picField", "calendar", "cmdBar", "popup"]
# Synonyms: model often writes XML name or Russian (ПолеПереключателя/RadioButtonField → radio)
@@ -1792,6 +1792,7 @@ def emit_element(lines, el, indent, in_cmd_bar=False):
emitters = {
'group': emit_group,
'columnGroup': emit_column_group,
+ 'buttonGroup': emit_button_group,
'input': emit_input,
'check': emit_check,
'radio': emit_radio_button_field,
@@ -2452,6 +2453,30 @@ def emit_popup(lines, el, name, eid, indent):
lines.append(f'{indent}')
+def emit_button_group(lines, el, name, eid, indent):
+ lines.append(f'{indent}')
+ inner = f'{indent}\t'
+
+ emit_title(lines, el, name, inner)
+
+ if el.get('representation'):
+ lines.append(f'{inner}{el["representation"]}')
+
+ emit_common_flags(lines, el, inner)
+
+ # Companion: ExtendedTooltip
+ emit_companion(lines, 'ExtendedTooltip', f'{name}РасширеннаяПодсказка', inner)
+
+ # Children (кнопки в контексте командной панели)
+ if el.get('children') and len(el['children']) > 0:
+ lines.append(f'{inner}')
+ for child in el['children']:
+ emit_element(lines, child, f'{inner}\t', in_cmd_bar=True)
+ lines.append(f'{inner}')
+
+ lines.append(f'{indent}')
+
+
# --- Attribute emitter ---
def emit_attributes(lines, attrs, indent):
@@ -2554,9 +2579,15 @@ def emit_commands(lines, cmds, indent):
if cmd_title:
emit_mltext(lines, inner, 'Title', str(cmd_title))
+ if cmd.get('tooltip'):
+ emit_mltext(lines, inner, 'ToolTip', str(cmd['tooltip']))
+
if cmd.get('action'):
lines.append(f'{inner}{cmd["action"]}')
+ if cmd.get('currentRowUse'):
+ lines.append(f'{inner}{cmd["currentRowUse"]}')
+
if cmd.get('shortcut'):
lines.append(f'{inner}{cmd["shortcut"]}')
diff --git a/.claude/skills/form-decompile/scripts/form-decompile.ps1 b/.claude/skills/form-decompile/scripts/form-decompile.ps1
index e36bf66d..205dacb2 100644
--- a/.claude/skills/form-decompile/scripts/form-decompile.ps1
+++ b/.claude/skills/form-decompile/scripts/form-decompile.ps1
@@ -1,4 +1,4 @@
-# form-decompile v0.2 — Decompile 1C managed Form.xml to JSON DSL (draft)
+# form-decompile v0.3 — Decompile 1C managed Form.xml to JSON DSL (draft)
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
# ВНИМАНИЕ: раундтрип не гарантируется. Навык исключён из авто-использования моделью.
param(
@@ -280,7 +280,7 @@ function Decompile-Type {
# --- 4. Element dispatch ---
$ELEMENT_KEY = @{
- 'UsualGroup'='group'; 'ColumnGroup'='columnGroup'; 'InputField'='input'; 'CheckBoxField'='check';
+ 'UsualGroup'='group'; 'ColumnGroup'='columnGroup'; 'ButtonGroup'='buttonGroup'; 'InputField'='input'; 'CheckBoxField'='check';
'RadioButtonField'='radio'; 'LabelDecoration'='label'; 'LabelField'='labelField';
'PictureDecoration'='picture'; 'PictureField'='picField'; 'CalendarField'='calendar';
'Table'='table'; 'Pages'='pages'; 'Page'='page'; 'Button'='button'; 'CommandBar'='cmdBar'; 'Popup'='popup'
@@ -455,6 +455,13 @@ function Decompile-Element {
$rep = Get-Child $node 'Representation'; if ($rep) { $obj['representation'] = $rep }
$lic = Get-Child $node 'LocationInCommandBar'; if ($lic) { $obj['locationInCommandBar'] = $lic }
}
+ 'ButtonGroup' {
+ $obj[$key] = $name
+ Add-CommonProps $obj $node $name
+ $rep = Get-Child $node 'Representation'; if ($rep) { $obj['representation'] = $rep }
+ $kids = Decompile-Children $node
+ if ($kids) { $obj['children'] = $kids }
+ }
'CommandBar' {
$obj[$key] = $name
Add-CommonProps $obj $node $name
@@ -507,9 +514,25 @@ if ($evForm) {
if ($evMap.Count -gt 0) { $dsl['events'] = $evMap }
}
-# elements
+# elements (+ форменный AutoCommandBar как autoCmdBar-элемент, если у него есть содержимое)
+$elemList = New-Object System.Collections.ArrayList
+$acb = $root.SelectSingleNode("lf:AutoCommandBar", $ns)
+if ($acb) {
+ $haln = Get-Child $acb 'HorizontalAlign'
+ $acbAutofill = Get-Child $acb 'Autofill'
+ $acbKids = Decompile-Children $acb
+ if ($haln -or ($acbAutofill -eq 'false') -or $acbKids) {
+ $acbObj = [ordered]@{}
+ $acbObj['autoCmdBar'] = $acb.GetAttribute("name")
+ if ($haln) { $acbObj['horizontalAlign'] = $haln }
+ if ($acbAutofill -eq 'false') { $acbObj['autofill'] = $false }
+ if ($acbKids) { $acbObj['children'] = $acbKids }
+ [void]$elemList.Add($acbObj)
+ }
+}
$elements = Decompile-Children $root
-if ($elements) { $dsl['elements'] = $elements }
+if ($elements) { foreach ($e in $elements) { [void]$elemList.Add($e) } }
+if ($elemList.Count -gt 0) { $dsl['elements'] = @($elemList) }
# attributes
$attrsNode = $root.SelectSingleNode("lf:Attributes", $ns)
@@ -560,6 +583,8 @@ if ($cmdsNode) {
$co = [ordered]@{}; $co['name'] = $c.GetAttribute("name")
$act = Get-Child $c 'Action'; if ($act) { $co['action'] = $act }
$tNode = $c.SelectSingleNode("lf:Title", $ns); if ($tNode) { $t = Get-LangText $tNode; if ($null -ne $t) { $co['title'] = $t } }
+ $ttNode = $c.SelectSingleNode("lf:ToolTip", $ns); if ($ttNode) { $t = Get-LangText $ttNode; if ($null -ne $t) { $co['tooltip'] = $t } }
+ $cru = Get-Child $c 'CurrentRowUse'; if ($cru) { $co['currentRowUse'] = $cru }
$sc = Get-Child $c 'Shortcut'; if ($sc) { $co['shortcut'] = $sc }
$ref = $c.SelectSingleNode("lf:Picture/xr:Ref", $ns); if ($ref) { $co['picture'] = $ref.InnerText }
$rep = Get-Child $c 'Representation'; if ($rep) { $co['representation'] = $rep }
diff --git a/docs/form-dsl-spec.md b/docs/form-dsl-spec.md
index f2dc2378..6aa63707 100644
--- a/docs/form-dsl-spec.md
+++ b/docs/form-dsl-spec.md
@@ -385,6 +385,42 @@ Pages поддерживает `pagesRepresentation`: `None`, `TabsOnTop`, `Tabs
{ "popup": "Печать", "picture": "StdPicture.Print", "children": [ ... ] }
```
+#### buttonGroup — ButtonGroup
+
+Группа кнопок внутри командной панели (`autoCmdBar`/`cmdBar`/`popup`). Значение ключа — имя элемента.
+
+```json
+{ "buttonGroup": "ГруппаПереместить", "title": "Переместить", "children": [
+ { "button": "ПереместитьВверх", "command": "ПереместитьВверх" },
+ { "button": "ПереместитьВниз", "command": "ПереместитьВниз" }
+] }
+```
+
+| Свойство | Тип | Описание |
+|----------|-----|----------|
+| `buttonGroup` | string | Имя элемента |
+| `title` | string/object | Заголовок группы |
+| `representation` | string | `Auto`, `Picture`, `Text`, `PictureAndText` |
+| `children` | array | Кнопки (`button`) внутри группы |
+
+#### autoCmdBar — командная панель формы
+
+Командная панель самой формы (``). Задаётся как элемент в `elements`; компилятор автоматически вынимает его из дерева. Нужен только если в панель помещаются **явные** кнопки/группы или меняется выравнивание/автозаполнение — иначе панель формируется автоматически.
+
+```json
+{ "autoCmdBar": "ФормаКоманднаяПанель", "horizontalAlign": "Right", "autofill": false, "children": [
+ { "button": "ОК", "command": "ОК", "defaultButton": true },
+ { "button": "Отмена", "command": "Отмена" }
+] }
+```
+
+| Свойство | Тип | Описание |
+|----------|-----|----------|
+| `autoCmdBar` | string | Имя панели (обычно `ФормаКоманднаяПанель`) |
+| `horizontalAlign` | string | `Right`, `Left`, `Center` |
+| `autofill` | bool | `false` — отключить автозаполнение стандартными командами |
+| `children` | array | Кнопки/группы кнопок панели |
+
---
## 5. Attributes — реквизиты формы
@@ -443,6 +479,8 @@ Pages поддерживает `pagesRepresentation`: `None`, `TabsOnTop`, `Tabs
| `name` | string | Имя команды (обязательно) |
| `action` | string | Имя процедуры-обработчика |
| `title` | string | Заголовок |
+| `tooltip` | string/object | Всплывающая подсказка команды (``) |
+| `currentRowUse` | string | Использование текущей строки: `Auto`, `DontUse`, `Use` |
| `shortcut` | string | Клавиатурное сочетание |
| `picture` | string | Ссылка на картинку |
| `representation` | string | `Auto`, `Picture`, `Text`, `PictureAndText` |
diff --git a/tests/skills/cases/form-compile/button-group.json b/tests/skills/cases/form-compile/button-group.json
new file mode 100644
index 00000000..f15c09fb
--- /dev/null
+++ b/tests/skills/cases/form-compile/button-group.json
@@ -0,0 +1,36 @@
+{
+ "name": "ButtonGroup в командной панели + команды с tooltip/currentRowUse",
+ "preRun": [
+ {
+ "script": "meta-compile/scripts/meta-compile",
+ "input": { "type": "DataProcessor", "name": "ГруппыКнопок" },
+ "args": { "-JsonPath": "{inputFile}", "-OutputDir": "{workDir}" }
+ },
+ {
+ "script": "form-add/scripts/form-add",
+ "args": { "-ObjectPath": "{workDir}/DataProcessors/ГруппыКнопок.xml", "-FormName": "Форма" }
+ }
+ ],
+ "params": { "outputPath": "DataProcessors/ГруппыКнопок/Forms/Форма/Ext/Form.xml" },
+ "validatePath": "DataProcessors/ГруппыКнопок/Forms/Форма/Ext/Form.xml",
+ "input": {
+ "title": "Группы кнопок",
+ "elements": [
+ { "cmdBar": "Панель", "children": [
+ { "button": "Выполнить", "command": "Выполнить", "defaultButton": true },
+ { "buttonGroup": "ГруппаПереместить", "title": "Переместить", "children": [
+ { "button": "Вверх", "command": "Вверх" },
+ { "button": "Вниз", "command": "Вниз" }
+ ]}
+ ]}
+ ],
+ "attributes": [
+ { "name": "Объект", "type": "DataProcessorObject.ГруппыКнопок", "main": true }
+ ],
+ "commands": [
+ { "name": "Выполнить", "action": "ВыполнитьОбработка", "tooltip": "Запустить обработку", "shortcut": "Ctrl+Enter" },
+ { "name": "Вверх", "action": "ВверхОбработка", "currentRowUse": "DontUse" },
+ { "name": "Вниз", "action": "ВнизОбработка", "currentRowUse": "DontUse" }
+ ]
+ }
+}
diff --git a/tests/skills/cases/form-compile/snapshots/button-group/Configuration.xml b/tests/skills/cases/form-compile/snapshots/button-group/Configuration.xml
new file mode 100644
index 00000000..dec13ea8
--- /dev/null
+++ b/tests/skills/cases/form-compile/snapshots/button-group/Configuration.xml
@@ -0,0 +1,252 @@
+
+
+
+
+
+ UUID-002
+ UUID-003
+
+
+ UUID-004
+ UUID-005
+
+
+ UUID-006
+ UUID-007
+
+
+ UUID-008
+ UUID-009
+
+
+ UUID-010
+ UUID-011
+
+
+ UUID-012
+ UUID-013
+
+
+ UUID-014
+ UUID-015
+
+
+
+ TestConfig
+
+
+ ru
+ TestConfig
+
+
+
+
+ Version8_3_24
+ ManagedApplication
+
+ PlatformApplication
+
+ Russian
+
+
+
+
+ false
+ false
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Biometrics
+ true
+
+
+ Location
+ false
+
+
+ BackgroundLocation
+ false
+
+
+ BluetoothPrinters
+ false
+
+
+ WiFiPrinters
+ false
+
+
+ Contacts
+ false
+
+
+ Calendars
+ false
+
+
+ PushNotifications
+ false
+
+
+ LocalNotifications
+ false
+
+
+ InAppPurchases
+ false
+
+
+ PersonalComputerFileExchange
+ false
+
+
+ Ads
+ false
+
+
+ NumberDialing
+ false
+
+
+ CallProcessing
+ false
+
+
+ CallLog
+ false
+
+
+ AutoSendSMS
+ false
+
+
+ ReceiveSMS
+ false
+
+
+ SMSLog
+ false
+
+
+ Camera
+ false
+
+
+ Microphone
+ false
+
+
+ MusicLibrary
+ false
+
+
+ PictureAndVideoLibraries
+ false
+
+
+ AudioPlaybackAndVibration
+ false
+
+
+ BackgroundAudioPlaybackAndVibration
+ false
+
+
+ InstallPackages
+ false
+
+
+ OSBackup
+ true
+
+
+ ApplicationUsageStatistics
+ false
+
+
+ BarcodeScanning
+ false
+
+
+ BackgroundAudioRecording
+ false
+
+
+ AllFilesAccess
+ false
+
+
+ Videoconferences
+ false
+
+
+ NFC
+ false
+
+
+ DocumentScanning
+ false
+
+
+ SpeechToText
+ false
+
+
+ Geofences
+ false
+
+
+ IncomingShareRequests
+ false
+
+
+ AllIncomingShareRequestsTypesProcessing
+ false
+
+
+
+
+
+ Normal
+
+
+ Language.Русский
+
+
+
+
+
+ Managed
+ NotAutoFree
+ DontUse
+ DontUse
+ TaxiEnableVersion8_2
+ DontUse
+ Version8_3_24
+
+
+
+ Русский
+ ГруппыКнопок
+
+
+
\ No newline at end of file
diff --git a/tests/skills/cases/form-compile/snapshots/button-group/DataProcessors/ГруппыКнопок.xml b/tests/skills/cases/form-compile/snapshots/button-group/DataProcessors/ГруппыКнопок.xml
new file mode 100644
index 00000000..f4859f98
--- /dev/null
+++ b/tests/skills/cases/form-compile/snapshots/button-group/DataProcessors/ГруппыКнопок.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+ UUID-002
+ UUID-003
+
+
+ UUID-004
+ UUID-005
+
+
+
+ ГруппыКнопок
+
+
+ ru
+ Группы кнопок
+
+
+
+ false
+ DataProcessor.ГруппыКнопок.Form.Форма
+
+ false
+
+
+
+
+
+
+
+
diff --git a/tests/skills/cases/form-compile/snapshots/button-group/DataProcessors/ГруппыКнопок/Ext/ManagerModule.bsl b/tests/skills/cases/form-compile/snapshots/button-group/DataProcessors/ГруппыКнопок/Ext/ManagerModule.bsl
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/skills/cases/form-compile/snapshots/button-group/DataProcessors/ГруппыКнопок/Ext/ObjectModule.bsl b/tests/skills/cases/form-compile/snapshots/button-group/DataProcessors/ГруппыКнопок/Ext/ObjectModule.bsl
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/skills/cases/form-compile/snapshots/button-group/DataProcessors/ГруппыКнопок/Forms/Форма.xml b/tests/skills/cases/form-compile/snapshots/button-group/DataProcessors/ГруппыКнопок/Forms/Форма.xml
new file mode 100644
index 00000000..dffeea01
--- /dev/null
+++ b/tests/skills/cases/form-compile/snapshots/button-group/DataProcessors/ГруппыКнопок/Forms/Форма.xml
@@ -0,0 +1,22 @@
+
+
+
+
\ No newline at end of file
diff --git a/tests/skills/cases/form-compile/snapshots/button-group/DataProcessors/ГруппыКнопок/Forms/Форма/Ext/Form.xml b/tests/skills/cases/form-compile/snapshots/button-group/DataProcessors/ГруппыКнопок/Forms/Форма/Ext/Form.xml
new file mode 100644
index 00000000..3e4f7617
--- /dev/null
+++ b/tests/skills/cases/form-compile/snapshots/button-group/DataProcessors/ГруппыКнопок/Forms/Форма/Ext/Form.xml
@@ -0,0 +1,92 @@
+
+
diff --git a/tests/skills/cases/form-compile/snapshots/button-group/DataProcessors/ГруппыКнопок/Forms/Форма/Ext/Form/Module.bsl b/tests/skills/cases/form-compile/snapshots/button-group/DataProcessors/ГруппыКнопок/Forms/Форма/Ext/Form/Module.bsl
new file mode 100644
index 00000000..8ead4cec
--- /dev/null
+++ b/tests/skills/cases/form-compile/snapshots/button-group/DataProcessors/ГруппыКнопок/Forms/Форма/Ext/Form/Module.bsl
@@ -0,0 +1,19 @@
+#Область ОбработчикиСобытийФормы
+
+#КонецОбласти
+
+#Область ОбработчикиСобытийЭлементовФормы
+
+#КонецОбласти
+
+#Область ОбработчикиКомандФормы
+
+#КонецОбласти
+
+#Область ОбработчикиОповещений
+
+#КонецОбласти
+
+#Область СлужебныеПроцедурыИФункции
+
+#КонецОбласти
\ No newline at end of file
diff --git a/tests/skills/cases/form-compile/snapshots/button-group/Ext/ClientApplicationInterface.xml b/tests/skills/cases/form-compile/snapshots/button-group/Ext/ClientApplicationInterface.xml
new file mode 100644
index 00000000..3c1161b2
--- /dev/null
+++ b/tests/skills/cases/form-compile/snapshots/button-group/Ext/ClientApplicationInterface.xml
@@ -0,0 +1,18 @@
+
+
+
+
+ UUID-002
+
+
+
+
+ UUID-004
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/skills/cases/form-compile/snapshots/button-group/Languages/Русский.xml b/tests/skills/cases/form-compile/snapshots/button-group/Languages/Русский.xml
new file mode 100644
index 00000000..37c60d78
--- /dev/null
+++ b/tests/skills/cases/form-compile/snapshots/button-group/Languages/Русский.xml
@@ -0,0 +1,16 @@
+
+
+
+
+ Русский
+
+
+ ru
+ Русский
+
+
+
+ ru
+
+
+
\ No newline at end of file