From 047c0922fc8a0e7022f0a1483b39e4e93ca602a8 Mon Sep 17 00:00:00 2001 From: n1rwana Date: Mon, 24 Jul 2023 14:30:38 +0300 Subject: [PATCH] =?UTF-8?q?FAQ=20=D0=B2=20=D0=9F=D0=BE=D0=B4=D0=B4=D0=B5?= =?UTF-8?q?=D1=80=D0=B6=D0=BA=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Web/Models/Entities/FAQArticle.php | 44 ++++ Web/Models/Entities/FAQCategory.php | 50 +++++ Web/Models/Repositories/FAQArticles.php | 27 +++ Web/Models/Repositories/FAQCategories.php | 37 ++++ Web/Presenters/SupportPresenter.php | 198 +++++++++++++++++- .../templates/Support/FAQArticle.xml | 73 +++++++ .../templates/Support/FAQCategory.xml | 90 ++++++++ .../templates/Support/FAQNewArticle.xml | 57 +++++ .../templates/Support/FAQNewCategory.xml | 56 +++++ Web/Presenters/templates/Support/Index.xml | 50 +++++ Web/routes.yml | 12 ++ Web/static/img/faq_icons.png | Bin 0 -> 5163 bytes Web/static/img/sad.png | Bin 0 -> 1115 bytes install/sqls/00038-faq.sql | 37 ++++ locales/en.strings | 26 +++ locales/ru.strings | 25 +++ 16 files changed, 780 insertions(+), 2 deletions(-) create mode 100644 Web/Models/Entities/FAQArticle.php create mode 100644 Web/Models/Entities/FAQCategory.php create mode 100644 Web/Models/Repositories/FAQArticles.php create mode 100644 Web/Models/Repositories/FAQCategories.php create mode 100644 Web/Presenters/templates/Support/FAQArticle.xml create mode 100644 Web/Presenters/templates/Support/FAQCategory.xml create mode 100644 Web/Presenters/templates/Support/FAQNewArticle.xml create mode 100644 Web/Presenters/templates/Support/FAQNewCategory.xml create mode 100644 Web/static/img/faq_icons.png create mode 100644 Web/static/img/sad.png create mode 100644 install/sqls/00038-faq.sql diff --git a/Web/Models/Entities/FAQArticle.php b/Web/Models/Entities/FAQArticle.php new file mode 100644 index 00000000..a7d6f89e --- /dev/null +++ b/Web/Models/Entities/FAQArticle.php @@ -0,0 +1,44 @@ +getRecord()->id; + } + + function getTitle(): string + { + return $this->getRecord()->title; + } + + function getText(): string + { + return $this->getRecord()->text; + } + + function canSeeByUnloggedUsers(): bool + { + return (bool) $this->getRecord()->unlogged_can_see; + } + + function canSeeByUsers(): bool + { + return (bool) $this->getRecord()->users_can_see; + } + + function getCategory(): ?FAQCategory + { + return (new FAQCategories)->get($this->getRecord()->category); + } + + function getLanguage(): string + { + return $this->getRecord()->language; + } +} diff --git a/Web/Models/Entities/FAQCategory.php b/Web/Models/Entities/FAQCategory.php new file mode 100644 index 00000000..11789d98 --- /dev/null +++ b/Web/Models/Entities/FAQCategory.php @@ -0,0 +1,50 @@ +getRecord()->id; + } + + function getTitle(): string + { + return $this->getRecord()->title; + } + + function canSeeByUsers(): bool + { + return (bool) !$this->getRecord()->for_agents_only; + } + + function getIconBackgroundPosition(): int + { + return 28 * $this->getRecord()->icon; + } + + function getArticles(?int $limit = NULL, $isAgent): \Traversable + { + $filter = ["category" => $this->getId(), "deleted" => 0]; + if (!$isAgent) $filter["users_can_see"] = 1; + + $articles = DatabaseConnection::i()->getContext()->table("faq_articles")->where($filter)->limit($limit); + foreach ($articles as $article) { + yield new FAQArticle($article); + } + } + + function getIcon(): int + { + return $this->getRecord()->icon; + } + + function getLanguage(): string + { + return $this->getRecord()->language; + } +} diff --git a/Web/Models/Repositories/FAQArticles.php b/Web/Models/Repositories/FAQArticles.php new file mode 100644 index 00000000..a7070f35 --- /dev/null +++ b/Web/Models/Repositories/FAQArticles.php @@ -0,0 +1,27 @@ +context = DatabaseConnection::i()->getContext(); + $this->articles = $this->context->table("faq_articles"); + } + + function toFAQArticle(?ActiveRow $ar): ?FAQArticle + { + return is_null($ar) ? NULL : new FAQArticle($ar); + } + + function get(int $id): ?FAQArticle + { + return $this->toFAQArticle($this->articles->get($id)); + } +} diff --git a/Web/Models/Repositories/FAQCategories.php b/Web/Models/Repositories/FAQCategories.php new file mode 100644 index 00000000..2d74bfde --- /dev/null +++ b/Web/Models/Repositories/FAQCategories.php @@ -0,0 +1,37 @@ +context = DatabaseConnection::i()->getContext(); + $this->categories = $this->context->table("faq_categories"); + } + + function toFAQCategory(?ActiveRow $ar): ?FAQCategory + { + return is_null($ar) ? NULL : new FAQCategory($ar); + } + + function get(int $id): ?FAQCategory + { + return $this->toFAQCategory($this->categories->get($id)); + } + + function getList(string $language, bool $includeForAgents = false): \Traversable + { + $filter = ["deleted" => 0, "language" => $language]; + if (!$includeForAgents) $filter["for_agents_only"] = 0; + + foreach ($this->categories->where($filter) as $category) { + yield new FAQCategory($category); + } + } +} diff --git a/Web/Presenters/SupportPresenter.php b/Web/Presenters/SupportPresenter.php index c4d729ea..3d5259b4 100644 --- a/Web/Presenters/SupportPresenter.php +++ b/Web/Presenters/SupportPresenter.php @@ -1,7 +1,7 @@ assertUserLoggedIn(); $this->template->mode = in_array($this->queryParam("act"), ["faq", "new", "list"]) ? $this->queryParam("act") : "faq"; + $canEdit = $this->user->identity->getChandlerUser()->can("write")->model('openvk\Web\Models\Entities\TicketReply')->whichBelongsTo(0); if($this->template->mode === "faq") { + $this->template->categories = (new FAQCategories)->getList($canEdit ? $this->queryParam("lang") ?? Session::i()->get("lang", "ru") : Session::i()->get("lang", "ru"), $canEdit); + $this->template->canEditFAQ = $canEdit; + $lang = Session::i()->get("lang", "ru"); $base = OPENVK_ROOT . "/data/knowledgebase/faq"; if(file_exists("$base.$lang.md")) @@ -104,6 +108,9 @@ final class SupportPresenter extends OpenVKPresenter $this->flashFail("err", tr("error"), tr("you_have_not_entered_name_or_text")); } } + + $this->template->languages = getLanguages(); + $this->template->activeLang = $this->queryParam("lang") ?? Session::i()->get("lang", "ru"); } function renderList(): void @@ -396,4 +403,191 @@ final class SupportPresenter extends OpenVKPresenter $this->flashFail("succ", "Успех", "Профиль создан. Теперь пользователи видят Ваши псевдоним и аватарку вместо стандартных аватарки и номера."); } } + + function renderFAQArticle(int $id): void + { + $article = (new FAQArticles)->get($id); + if (!$article || $article->isDeleted()) + $this->notFound(); + + $category = $article->getCategory(); + + if ($category->isDeleted()) + $this->notFound(); + + if (!$article->canSeeByUnloggedUsers()) + $this->assertUserLoggedIn(); + + if (!$category->canSeeByUsers() || (!$article->canSeeByUsers() && !$article->canSeeByUnloggedUsers())) + $this->assertPermission("openvk\Web\Models\Entities\TicketReply", "write", 0); + + $canEdit = false; + if ($this->user->identity) + $canEdit = $this->user->identity->getChandlerUser()->can("write")->model('openvk\Web\Models\Entities\TicketReply')->whichBelongsTo(0); + + if ($_SERVER["REQUEST_METHOD"] === "POST") { + $this->assertNoCSRF(); + if (!$canEdit) { + $this->flashFail("err", tr("not_enough_permissions"), tr("not_enough_permissions_comment")); + } + + $cid = $this->postParam("category"); + if ($this->postParam("language") != $article->getLanguage()) { + $categories = iterator_to_array((new FAQCategories)->getList($this->postParam("language"))); + if (sizeof($categories) > 0) { + $cid = iterator_to_array((new FAQCategories)->getList($this->postParam("language")))[0]->getId(); + } else { + $this->flashFail("err", tr("error"), tr("support_cant_change_lang_no_cats")); + } + } + + $article->setTitle($this->postParam("title")); + $article->setText($this->postParam("text")); + $article->setUnlogged_Can_see(empty($this->postParam("unlogged_can_see") ? 0 : 1)); + $article->setUsers_Can_See(empty($this->postParam("users_can_see") ? 0 : 1)); + $article->setCategory($cid); + $article->setLanguage($this->postParam("language")); + $article->save(); + $this->flashFail("succ", tr("changes_saved")); + } else { + $this->template->mode = $canEdit ? in_array($this->queryParam("act"), ["view", "edit"]) ? $this->queryParam("act") : "view" : "view"; + $this->template->category = $category; + $this->template->article = $article; + $this->template->text = (new Parsedown())->text($article->getText()); + $this->template->canEditFAQ = $canEdit; + $this->template->categories = (new FAQCategories)->getList($this->queryParam("lang") ?? $article->getLanguage(), TRUE); + $this->template->languages = getLanguages(); + $this->template->activeLang = $this->queryParam("lang") ?? $article->getLanguage(); + } + } + + function renderFAQCategory(int $id): void + { + $category = (new FAQCategories)->get($id); + + if (!$category) + $this->notFound(); + + if (!$category->canSeeByUsers()) + $this->assertPermission("openvk\Web\Models\Entities\TicketReply", "write", 0); + + $canEdit = $this->user->identity->getChandlerUser()->can("write")->model('openvk\Web\Models\Entities\TicketReply')->whichBelongsTo(0); + + if ($_SERVER["REQUEST_METHOD"] === "POST") { + $this->assertNoCSRF(); + if (!$canEdit) { + $this->flashFail("err", tr("not_enough_permissions"), tr("not_enough_permissions_comment")); + } + + if ($this->queryParam("mode") === "copy") { + $orig_cat = $category; + $category = new FAQCategory; + } + + $category->setTitle($this->postParam("title")); + $category->setIcon($orig_cat->getIcon() ?? $this->postParam("icon")); + $category->setFor_Agents_Only(empty($this->postParam("for_agents_only") ? 0 : 1)); + $category->setLanguage($this->postParam("language")); + $category->save(); + + if ($this->queryParam("mode") === "copy" && !empty($this->postParam("copy_with_articles"))) { + $articles = $orig_cat->getArticles(NULL, TRUE); + foreach ($articles as $article) { + $_article = new FAQArticle; + $_article->setCategory($category->getId()); + $_article->setTitle($article->getTitle()); + $_article->setText($article->getText()); + $_article->setUsers_Can_See($article->canSeeByUsers()); + $_article->setUnlogged_Can_See($article->canSeeByUnloggedUsers()); + $_article->setLanguage($category->getLanguage()); + $_article->save(); + } + } + + $this->flashFail("succ", tr("changes_saved")); + } + + $this->template->mode = $canEdit ? in_array($this->queryParam("act"), ["view", "edit"]) ? $this->queryParam("act") : "view" : "view"; + $this->template->copyMode = $canEdit ? $this->queryParam("mode") === "copy" : FALSE; + $this->template->category = $category; + $this->template->canEditFAQ = $canEdit; + $this->template->languages = getLanguages(); + } + + function renderFAQNewArticle(): void + { + $this->assertPermission("openvk\Web\Models\Entities\TicketReply", "write", 0); + + if ($_SERVER["REQUEST_METHOD"] === "POST") { + if (!$this->postParam("category")) + $this->flashFail("err", tr("support_category_not_specified")); + + $article = new FAQArticle; + $article->setTitle($this->postParam("title")); + $article->setText($this->postParam("text")); + $article->setUnlogged_Can_see(empty($this->postParam("unlogged_can_see") ? 0 : 1)); + $article->setUsers_Can_See(empty($this->postParam("users_can_see") ? 0 : 1)); + $article->setCategory($this->postParam("category")); + $article->setLanguage(Session::i()->get("lang", "ru")); + $article->save(); + $this->redirect("/faq" . $article->getId()); + } else { + $this->template->categories = (new FAQCategories)->getList($this->queryParam("lang") ?? Session::i()->get("lang", "ru"), TRUE); + $this->template->category_id = $this->queryParam("cid"); + $this->template->activeLang = $this->queryParam("lang") ?? Session::i()->get("lang", "ru"); + $this->template->languages = getLanguages(); + } + } + + function renderFAQNewCategory(): void + { + $this->assertPermission("openvk\Web\Models\Entities\TicketReply", "write", 0); + + if ($_SERVER["REQUEST_METHOD"] === "POST") { + $category = new FAQCategory; + $category->setTitle($this->postParam("title")); + $category->setIcon($this->postParam("icon")); + $category->setFor_Agents_Only(empty($this->postParam("for_agents_only") ? 0 : 1)); + $category->setLanguage($this->postParam("language")); + $category->save(); + $this->redirect("/faqs" . $category->getId()); + } + + $this->template->activeLang = $this->queryParam("lang") ?? Session::i()->get("lang", "ru"); + $this->template->languages = getLanguages(); + } + + function renderFAQDeleteArticle(int $id): void + { + $this->assertNoCSRF(); + $this->assertPermission("openvk\Web\Models\Entities\TicketReply", "write", 0); + + $article = (new FAQArticles)->get($id); + if (!$article || $article->isDeleted()) + $this->notFound(); + + $cid = $article->getCategory()->getId(); + $article->delete(); + $this->redirect("/faqs" . $cid); + } + + function renderFAQDeleteCategory(int $id): void + { + $this->assertNoCSRF(); + $this->assertPermission("openvk\Web\Models\Entities\TicketReply", "write", 0); + + $category = (new FAQCategories)->get($id); + if (!$category || $category->isDeleted()) + $this->notFound(); + + if (!empty($this->postParam("delete_articles"))) { + $articles = $category->getArticles(NULL, TRUE); + foreach ($articles as $article) { + $article->delete(); + } + } + + $category->delete(); + $this->redirect("/support"); + } } diff --git a/Web/Presenters/templates/Support/FAQArticle.xml b/Web/Presenters/templates/Support/FAQArticle.xml new file mode 100644 index 00000000..14d64588 --- /dev/null +++ b/Web/Presenters/templates/Support/FAQArticle.xml @@ -0,0 +1,73 @@ +{extends "../@layout.xml"} + +{block title}{$title}{/block} + +{block header} + {_menu_help} + > {$category->getTitle()} + > {$article->getTitle()} +
{_support_article} ({_app_edit})
+
> {_support_edit_mode}
+{/block} + +{block content} + +
+

{$article->getTitle()}

+ {$text|noescape} +
+
+
+
+

+

+ {_support_unlogged_can_see} + {_support_users_can_see} + + + + + +
+ {_support_category}: + + +
+ + + + + +
+ {_support_language}: + + +
+ + +

+
+
+


+
+ + +
+

+{/block} diff --git a/Web/Presenters/templates/Support/FAQCategory.xml b/Web/Presenters/templates/Support/FAQCategory.xml new file mode 100644 index 00000000..0574b28b --- /dev/null +++ b/Web/Presenters/templates/Support/FAQCategory.xml @@ -0,0 +1,90 @@ +{extends "../@layout.xml"} + +{block title}{$title}{/block} + +{block header} + {_menu_help} +
> {_support_faq_category}
+
> {$category->getTitle()} > {_support_edit_mode}
+{/block} + +{block content} + {var $articles = iterator_to_array($category->getArticles(NULL, $canEditFAQ))} +
+

+
+ {$category->getTitle()} +
+ ({_support_edit}) + ({_support_copy}) + (+{_support_add_article}) +
+

+
+ +
+ +
{_support_empty}
+
+
+
+
+
+

+ {_support_for_agents_only} + {_support_copy_articles} +

+
+
+
+
+
+
+ + + + + +
+ {_support_language}: + + +
+ + + + +

+
+
+


+
+ + + {_support_delete_articles} +
+

+ +{/block} diff --git a/Web/Presenters/templates/Support/FAQNewArticle.xml b/Web/Presenters/templates/Support/FAQNewArticle.xml new file mode 100644 index 00000000..cd97a2a3 --- /dev/null +++ b/Web/Presenters/templates/Support/FAQNewArticle.xml @@ -0,0 +1,57 @@ +{extends "../@layout.xml"} + +{block title}{_support_new_article}{/block} + +{block header}{_menu_help} > {_support_create_article}{/block} + +{block content} + +
+
+ + + + + +
+ {_support_language}: + + +
+

+

+ {_support_unlogged_can_see} + {_support_users_can_see} + + + + + +
+ {_support_category}: + + +
+ {$test} + + +

+
+
+{/block} diff --git a/Web/Presenters/templates/Support/FAQNewCategory.xml b/Web/Presenters/templates/Support/FAQNewCategory.xml new file mode 100644 index 00000000..46ce815d --- /dev/null +++ b/Web/Presenters/templates/Support/FAQNewCategory.xml @@ -0,0 +1,56 @@ +{extends "../@layout.xml"} + +{block title}{_support_new_category}{/block} + +{block header}{_menu_help} > {_support_create_category}{/block} + +{block content} +
+
+ + + + + +
+ {_support_language}: + + +
+

+ {_support_for_agents_only} +

+
+ Иконка +
+
+
+
+
+
+

+ + + + +

+
+
+ +{/block} diff --git a/Web/Presenters/templates/Support/Index.xml b/Web/Presenters/templates/Support/Index.xml index acb52859..0bcea0dc 100644 --- a/Web/Presenters/templates/Support/Index.xml +++ b/Web/Presenters/templates/Support/Index.xml @@ -49,7 +49,57 @@ {/if} {if $isMain} +

{_support_faq}


+
+
+ {_create} + {_support_category_acc} + · + {_support_article_acc} +
+ + + + + +
+ {_support_language}: + + +
+
+
+
+

+

+ {var $articles = iterator_to_array($category->getArticles(3, $canEditFAQ))} + +
+ +
{_support_empty}
+
+
+
+

{$section[0]}
{$section[1]|noescape}
diff --git a/Web/routes.yml b/Web/routes.yml index d1a0e7ae..c4e563a4 100644 --- a/Web/routes.yml +++ b/Web/routes.yml @@ -43,6 +43,18 @@ routes: handler: "About->donate" - url: "/kb/{slug}" handler: "Support->knowledgeBaseArticle" + - url: "/faq{num}" + handler: "Support->FAQArticle" + - url: "/faqs{num}" + handler: "Support->FAQCategory" + - url: "/new_faq" + handler: "Support->FAQNewArticle" + - url: "/new_faq_cat" + handler: "Support->FAQNewCategory" + - url: "/al_helpdesk/{num}/delete" + handler: "Support->FAQDeleteArticle" + - url: "/al_helpdesk_cat/{num}/delete" + handler: "Support->FAQDeleteCategory" - url: "/about:{?!productName}" handler: "About->version" placeholders: diff --git a/Web/static/img/faq_icons.png b/Web/static/img/faq_icons.png new file mode 100644 index 0000000000000000000000000000000000000000..888942c70a545a8486a2b0d75caf360493590a6c GIT binary patch literal 5163 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 Z9KP49YHprs+^PTo002ovPDHLkV1jqne6s)m literal 0 HcmV?d00001 diff --git a/Web/static/img/sad.png b/Web/static/img/sad.png new file mode 100644 index 0000000000000000000000000000000000000000..715c43350396a01bdac41e56706d9edee594f3e6 GIT binary patch literal 1115 zcmeAS@N?(olHy`uVBq!ia0vp^ZXnFT3?e@WZDU|yiPp1did(vgV%T8y}R+~)wPGOf#TO5yt?@q$_8tB4OI`+1yu0(^^HfbuRni({mCbw z?Da=)uRj1Pczqox`1sxJCt&V_*S8y2(!80I8&r6^QlK`b?}Gx^@8kE{>>8=IP}n3@`%{Ixqk}%mOXoG zQMX~edG4LtdGCIuxxQ|H9DbSE|MXLihKq_DbpCZQFfc9hba4!+U|e#Qd6sgZNZZ5x zkFJT|-gf)W|5a@166&S*kGGy?mVL(Bw6H)$YWJ=#SLKHR1`l2)T{quep0jiJ-ksN2 z_f#mIj63Oa=W=DxOCGh^r^UOL7A+0Z6XpIHBR1J{c}ZIqZ$s7MmzmAibFMJ12rc!} zX20;RWNY~L%WN;UmW0$Z@VF<-n#l1sI>xvAE<2F3??PbrPo5cmB?pRF*Ss&i^j9iE zck6X$wu+idlJn#m&m6uNIInSf*SVld#(Cd+HlI20diJ?*-?(Nj-R2Ya;nzCuJ^K%3 z{hqV@z-+xwY(Co`u~uAcjce%rk;(gD<09@*xx@>X>@6egUncoypZGhy*I@T_{_n;= zW-nhUb>``5nJi7orHMNx=yxkFN!`QK^W-vz(Y(4Y=W3n#$8tMfFJ~!v63s4jjd{|A zsrj)Uao)Qccgb9NcqlHMHx2T{^A6uwHs{8&Hyv|t2;OeB-pIZELvhl>^pg*cOgb2JxpV2W z?_p=87!x%b7M|$P+p&A|gLm)vzT0!W%l$V+uQY%1^a(9aD$%FXR=?eMaNq9Bue4e> zwYpxp`MRF@SHcSyrB$LHyUzag|JAHBtt7=@VtAHEztqd;Pb!#r*>2q3Qggr1?7Z6g z?bmzt<=CT`b~``Yz3XjA$o`vodvD%*&plJ$q4Dn5yr$ptubXk+`FC*t!w)Wu3~Ft6 z3xDlDy>iReB!hW_gJ0 rl}D}d%nyT3Y3MHP*)T;ZG)4UP`@A_n3~rYI^8|yZtDnm{r-UW|b!~|K literal 0 HcmV?d00001 diff --git a/install/sqls/00038-faq.sql b/install/sqls/00038-faq.sql new file mode 100644 index 00000000..a77e7d82 --- /dev/null +++ b/install/sqls/00038-faq.sql @@ -0,0 +1,37 @@ +CREATE TABLE `faq_categories` +( + `id` bigint(20) UNSIGNED NOT NULL, + `title` tinytext NOT NULL, + `for_agents_only` tinyint(1) DEFAULT NULL, + `icon` int(11) NOT NULL, + `language` varchar(255) NOT NULL, + `deleted` tinyint(1) DEFAULT 0 +) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4; + +ALTER TABLE `faq_categories` + ADD PRIMARY KEY (`id`); + +ALTER TABLE `faq_categories` + MODIFY `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT; +COMMIT; + +CREATE TABLE `faq_articles` +( + `id` bigint(20) UNSIGNED NOT NULL, + `category` bigint(20) UNSIGNED DEFAULT NULL, + `title` mediumtext NOT NULL, + `text` longtext NOT NULL, + `users_can_see` tinyint(1) DEFAULT NULL, + `unlogged_can_see` tinyint(1) DEFAULT NULL, + `language` varchar(255) NOT NULL, + `deleted` tinyint(1) DEFAULT 0 +) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4; + +ALTER TABLE `faq_articles` + ADD PRIMARY KEY (`id`); + +ALTER TABLE `faq_articles` + MODIFY `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT; +COMMIT; diff --git a/locales/en.strings b/locales/en.strings index 4aaa4483..685cf861 100644 --- a/locales/en.strings +++ b/locales/en.strings @@ -913,6 +913,32 @@ "banned_in_support_1" = "Sorry, $1, but now you can't create tickets."; "banned_in_support_2" = "And the reason for this is simple: $1. Unfortunately, this time we had to take away this opportunity from you forever."; +"support_article" = "Article"; +"support_edit_mode" = "Editing"; +"support_faq_title_placeholder" = "A long time ago,"; +"support_faq_text_placeholder" = "In a galaxy far, far away..."; +"support_unlogged_can_see" = "Unauthorized users can see"; +"support_users_can_see" = "Users can see"; +"support_category" = "Category"; +"support_faq_category" = "FAQ Category"; +"support_edit" = "edit"; +"support_add_article" = "article"; +"support_empty" = "There's nothing here yet"; +"support_for_agents_only" = "Only for agents"; +"support_icon_number" = "Icon number"; +"support_create_article" = "Create an article"; +"support_create_category" = "Create a category"; +"support_new_article" = "New article"; +"support_new_category" = "New category"; +"support_article_acc" = "an article"; +"support_category_acc" = "a category"; +"support_language" = "Language"; +"support_category_not_specified" = "You didn't specify a category"; +"support_cant_change_lang_no_cats" = "In this localization, not a single category has been created yet to which the article could be moved"; +"support_copy" = "copy"; +"support_delete_articles" = "Delete articles"; +"support_copy_articles" = "Copy with articles"; + /* Invite */ "invite" = "Invite"; diff --git a/locales/ru.strings b/locales/ru.strings index 6faa5e2e..3a714f43 100644 --- a/locales/ru.strings +++ b/locales/ru.strings @@ -841,6 +841,31 @@ "ticket_changed_comment" = "Изменения вступят силу через несколько секунд."; "banned_in_support_1" = "Извините, $1, но теперь вам нельзя создавать обращения."; "banned_in_support_2" = "А причина этому проста: $1. К сожалению, на этот раз нам пришлось отобрать у вас эту возможность навсегда."; +"support_article" = "Статья"; +"support_edit_mode" = "Редактирование"; +"support_faq_title_placeholder" = "Давным-давно,"; +"support_faq_text_placeholder" = "В далёкой-далёкой галактике..."; +"support_unlogged_can_see" = "Могут видеть неавторизованные"; +"support_users_can_see" = "Могут видеть пользователи"; +"support_category" = "Категория"; +"support_faq_category" = "Категория FAQ"; +"support_edit" = "редактировать"; +"support_add_article" = "статья"; +"support_empty" = "Здесь пока ничего нет"; +"support_for_agents_only" = "Только для агентов"; +"support_icon_number" = "Номер иконки"; +"support_create_article" = "Создать статью"; +"support_create_category" = "Создать категорию"; +"support_new_article" = "Новая статья"; +"support_new_category" = "Новая категория"; +"support_article_acc" = "статью"; +"support_category_acc" = "категорию"; +"support_language" = "Язык"; +"support_category_not_specified" = "Вы не указали категорию"; +"support_cant_change_lang_no_cats" = "В этой локализации еще не создано ни одной категории, в которую можно было бы переместить статью"; +"support_copy" = "дублировать"; +"support_delete_articles" = "Удалить статьи"; +"support_copy_articles" = "Копировать со статьями"; /* Invite */