Commit dc530c14 authored by Sergey Shadrin's avatar Sergey Shadrin

[#124455] Update to core 11.2.3

- Updated dockerfile and docker compose files
- Updated all modules and core
- quickedit, pet, drush_language and paragraphs_browser_previewer just downloaded and patched because no d11 published versions exists. Later need to add in composer.json
parent 740ec626
...@@ -7,6 +7,7 @@ app/sites/*/settings.php ...@@ -7,6 +7,7 @@ app/sites/*/settings.php
# Exclude update module # Exclude update module
app/core/modules/update app/core/modules/update
!app/core/modules/update/update.info.yml !app/core/modules/update/update.info.yml
app/modules/contrib/upgrade_status
# Exclude IDE specific directories. # Exclude IDE specific directories.
.idea .idea
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "a883f65614d1e1faeacd42ed12105266", "content-hash": "ce257c13e8b88933505ca1a84be9a1a5",
"packages": [ "packages": [
{ {
"name": "asm89/stack-cors", "name": "asm89/stack-cors",
......
analyse
analysing
checkstyle
codeclimate
dekor
deprecatedfilter
endspaceless
extdata
Gábor
Hojtsy
inspectable
linecount
NOSORT
ONLYDIR
rescan
rupal
sandboxing
subcomponent
subextension
sublist
updatev
\ No newline at end of file
#
# DrupalCI includes.
#
include:
- project: $_GITLAB_TEMPLATES_REPO
ref: $_GITLAB_TEMPLATES_REF
file:
- '/includes/include.drupalci.main.yml'
- '/includes/include.drupalci.variables.yml'
- '/includes/include.drupalci.workflows.yml'
#
# Start custom overrides.
#
variables:
OPT_IN_TEST_CURRENT: 1
OPT_IN_TEST_PREVIOUS_MAJOR: 1
OPT_IN_TEST_NEXT_MAJOR: 1
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.
# Upgrade Status
Review Drupal major upgrade readiness of the environment and components of the site.
The module provides the following key features:
- Checks if you are using a version of Drupal that supports an upgrade.
- Checks if your system meets the next major version's system requirements.
- Integrates with the Update Status core module to inform you to update your contributed projects. Projects can be compatible with multiple major Drupal versions, so most projects can be updated on your existing site before doing the core major update.
- Runs phpstan checks and a whole set of other checks to find any compatibility issues with the next Drupal major version that may remain.
- Integrates with drush for command line usage and to plug into CI systems.
For a full description of the module, visit the
[project page](https://www.drupal.org/project/upgrade_status).
Submit bug reports and feature suggestions, or track changes in the
[issue queue](https://www.drupal.org/project/issues/upgrade_status).
## Requirements
This module requires no modules outside of Drupal core.
## Installation
You must use Composer to install all the required third party dependencies,
for example `composer require drupal/upgrade_status` then install as you would
normally install a contributed Drupal module. For further information, see:
[Installing Drupal Modules](https://www.drupal.org/docs/extending-drupal/installing-drupal-modules).
While the module takes an effort to categorize projects properly, installing
[Composer Deploy](https://www.drupal.org/project/composer_deploy) or
[Git Deploy](https://www.drupal.org/project/git_deploy) as appropriate to your
Drupal setup is suggested to identify custom vs. contributed projects more
accurately and gather version information leading to useful available update
information.
## Configuration
There are no configuration options. Go to Administration » Reports » Upgrade
status to use the module.
## Maintainers
- Gábor Hojtsy - [Gábor Hojtsy](https://www.drupal.org/u/g%C3%A1bor-hojtsy)
{
"name": "drupal/upgrade_status",
"type": "drupal-module",
"description": "Review Drupal major upgrade readiness of the environment and components of the site.",
"homepage": "http://drupal.org/project/upgrade_status",
"license": "GPL-2.0-or-later",
"require": {
"mglaman/phpstan-drupal": "^1.2.11|^2.0",
"phpstan/phpstan-deprecation-rules": "^1.0.0|^2.0",
"dekor/php-array-table": "^2.0",
"nikic/php-parser": "^4.0.0|^5.0.0",
"webflo/drupal-finder": "^1.2",
"symfony/process": "^3.4|^4.0|^5.0|^6.0|^7.0"
},
"require-dev": {
"drush/drush": "^11|^12|^13"
},
"minimum-stability": "dev",
"extra": {
"drush": {
"services": {
"drush.services.yml": "^9 || ^10"
}
}
}
}
upgrade_status.settings:
type: config_object
label: 'Upgrade status settings'
mapping:
paths_per_scan:
type: integer
label: 'Paths per iteration to scan'
/**
* @file
* Styles used by the Upgrade Status module.
*/
/* Upgrade Status summary of the whole site */
.upgrade-status-of-site tr:hover {
color: inherit;
background-color: inherit;
}
.upgrade-status-of-site th {
width: 33%;
}
.upgrade-status-of-site td {
vertical-align: top;
}
/* Make space for SVG circle */
.upgrade-status-of-site td:nth-child(3) .item-list ul li {
margin-right: 6em;
}
/* Upgrade Status environment table layout */
.upgrade-status-of-environment th.requirement-label {
width: 70%;
}
.upgrade-status-of-environment th.status-info {
width: 30%;
}
/* Upgrade Status next step table layout */
.upgrade-status-next-step th {
width: 10%;
}
.upgrade-status-next-step th.project-label {
width: 20%;
}
.upgrade-status-next-step th.select-all {
width: 1px;
}
/* Remove Gin borders on these tables. TH and TR don't line up. */
.upgrade-status-of-environment .gin-layer-wrapper tr,
.upgrade-status-next-step .gin-layer-wrapper tr,
.upgrade-status-project-result-group .gin-layer-wrapper tr {
border-left: 0;
}
/* Project specific results layout */
.upgrade-status-project-result-group h3 {
margin: 30px 0 0 0;
}
.upgrade-status-project-result-group tr td:nth-child(1),
.upgrade-status-project-result-group tr td:nth-child(3) {
width: 40%;
}
.upgrade-status-project-result-group tr td:nth-child(2) {
width: 10%;
}
.upgrade-status-of-environment td.requirement-label,
.upgrade-status-next-step td.project-label {
font-weight: bold;
}
.upgrade-status-project-result-group tr > td.status-info,
.upgrade-status-next-step tr > td.status-info,
.upgrade-status-of-environment tr > td.status-info {
padding-left: 35px; /* LTR */
background-repeat: no-repeat;
background-position-x: 10px; /* LTR */
background-position-y: center;
}
[dir="rtl"] .upgrade-status-project-result-group tr > td.status-info,
[dir="rtl"] .upgrade-status-next-step tr > td.status-info,
[dir="rtl"] .upgrade-status-of-environment tr > td.status-info {
padding-right: 35px; /* LTR */
padding-left: 0;
/* @todo x background position for RTL */
}
.upgrade-status-project-result-group tr.color-error > td.status-info,
.upgrade-status-of-environment tr.color-error > td.status-info {
background-image: url(../icons/error.svg);
}
.upgrade-status-project-result-group tr.color-warning > td.status-info,
.upgrade-status-next-step td.status-info-incompatible,
.upgrade-status-of-environment tr.color-warning > td.status-info {
background-image: url(../icons/warning.svg);
}
.upgrade-status-project-result-group
tr.color-warning.known-later
> td.status-info,
.upgrade-status-next-step td.status-info-na {
background-image: url(../icons/ex.svg);
}
.upgrade-status-project-result-group tr.color-success > td.status-info,
.upgrade-status-next-step td.status-info-compatible,
.upgrade-status-of-environment tr.color-success > td.status-info {
background-image: url(../icons/check.svg);
}
.upgrade-status-project-result-group
tr.color-warning.rector-covered
> td.status-info {
background-image: url(../icons/wrench.svg);
}
.upgrade-status-next-step td.status-info-unchecked {
background-image: url(../icons/questionmark-disc.svg);
}
html.gin--dark-mode .upgrade-status-next-step td.status-info-unchecked {
background-image: url(../icons/questionmark-disc-white.svg);
}
/* Result circle styling in the status of site summary */
.upgrade-status-of-site-circle {
display: block;
float: right;
height: 5em;
margin: 0 0 1em 1em;
}
.upgrade-status-of-site-circle .circle-bg {
fill: none;
stroke: #f5f5f2;
stroke-width: 3.8;
}
.upgrade-status-of-site-circle .circle {
fill: none;
stroke-width: 2.8;
stroke-linecap: round;
animation-duration: 1s;
animation-timing-function: ease-out;
animation-direction: forwards;
stroke: #325e1c;
}
.upgrade-status-of-site-circle .percentage {
font-size: 0.5em;
text-anchor: middle;
font-weight: bold;
}
html.gin--dark-mode .upgrade-status-of-site-circle .percentage {
fill: #fff;
}
/* Gin dialog does not have top and bottom padding by default */
.ui-dialog .ui-widget-content.ui-dialog-content {
padding-top: 1rem;
padding-bottom: 1rem;
}
# FROM mglaman/drupal-check/phpstan/deprecation_testing.neon
parameters:
drupal:
rules:
classExtendsInternalClassRule: false
parallel:
maximumNumberOfProcesses: 0
customRulesetUsed: true
ignoreErrors:
- '#\Drupal calls should be avoided in classes, use dependency injection instead#'
- '#Plugin definitions cannot be altered.#'
- '#Missing cache backend declaration for performance.#'
- '#Plugin manager has cache backend specified but does not declare cache tags.#'
# FROM mglaman/drupal-check/phpstan/base_config.neon
reportUnmatchedIgnoredErrors: false
excludePaths:
- */tests/Drupal/Tests/Listeners/Legacy/*
- */tests/fixtures/*.php
- */settings*.php
- */bower_components/*
- */node_modules/*
services:
upgrade_status.commands:
class: \Drupal\upgrade_status\Drush\Commands\UpgradeStatusCommands
arguments:
- '@upgrade_status.result_formatter'
- '@upgrade_status.project_collector'
- '@upgrade_status.deprecation_analyzer'
- '@date.formatter'
tags:
- { name: drush.command }
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="#73b355"><path d="M6.464 13.676c-.194.194-.513.194-.707 0l-4.96-4.955c-.194-.193-.194-.513 0-.707l1.405-1.407c.194-.195.512-.195.707 0l2.849 2.848c.194.193.513.193.707 0l6.629-6.626c.195-.194.514-.194.707 0l1.404 1.404c.193.194.193.513 0 .707l-8.741 8.736z"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="#e32700"><path d="M8.002 1c-3.868 0-7.002 3.134-7.002 7s3.134 7 7.002 7c3.865 0 7-3.134 7-7s-3.135-7-7-7zm4.025 9.284c.062.063.1.149.1.239 0 .091-.037.177-.1.24l-1.262 1.262c-.064.062-.15.1-.24.1s-.176-.036-.24-.1l-2.283-2.283-2.286 2.283c-.064.062-.15.1-.24.1s-.176-.036-.24-.1l-1.261-1.262c-.063-.062-.1-.148-.1-.24 0-.088.036-.176.1-.238l2.283-2.285-2.283-2.284c-.063-.064-.1-.15-.1-.24s.036-.176.1-.24l1.262-1.262c.063-.063.149-.1.24-.1.089 0 .176.036.24.1l2.285 2.284 2.283-2.284c.064-.063.15-.1.24-.1s.176.036.24.1l1.262 1.262c.062.063.1.149.1.24 0 .089-.037.176-.1.24l-2.283 2.284 2.283 2.284z"/></svg>
<svg height="16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3.51 13.925c.194.194.512.195.706.001l3.432-3.431c.194-.194.514-.194.708 0l3.432 3.431c.192.194.514.193.707-.001l1.405-1.417c.191-.195.189-.514-.002-.709l-3.397-3.4c-.192-.193-.192-.514-.002-.708l3.401-3.43c.189-.195.189-.515 0-.709l-1.407-1.418c-.195-.195-.513-.195-.707-.001l-3.43 3.431c-.195.194-.516.194-.708 0l-3.432-3.431c-.195-.195-.512-.194-.706.001l-1.407 1.417c-.194.195-.194.515 0 .71l3.403 3.429c.193.195.193.514-.001.708l-3.4 3.399c-.194.195-.195.516-.001.709l1.406 1.419z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#fff" d="M8.002 1c-3.868 0-7.002 3.134-7.002 7s3.134 7 7.002 7c3.865 0 7-3.134 7-7s-3.135-7-7-7zm3 5c0 .551-.16 1.085-.477 1.586l-.158.22c-.07.093-.189.241-.361.393-.168.148-.35.299-.545.447l-.203.189-.141.129-.096.17-.021.235v.63h-2.001v-.704c.026-.396.078-.73.204-.999.125-.269.271-.498.439-.688l.225-.21-.01-.015.176-.14.137-.128c.186-.139.357-.277.516-.417l.148-.18c.098-.152.168-.323.168-.518 0-.552-.447-1-1-1s-1.002.448-1.002 1h-2c0-1.657 1.343-3 3.002-3 1.656 0 3 1.343 3 3zm-1.75 6.619c0 .344-.281.625-.625.625h-1.25c-.345 0-.626-.281-.626-.625v-1.238c0-.344.281-.625.626-.625h1.25c.344 0 .625.281.625.625v1.238z"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#000000" d="M8.002 1c-3.868 0-7.002 3.134-7.002 7s3.134 7 7.002 7c3.865 0 7-3.134 7-7s-3.135-7-7-7zm3 5c0 .551-.16 1.085-.477 1.586l-.158.22c-.07.093-.189.241-.361.393-.168.148-.35.299-.545.447l-.203.189-.141.129-.096.17-.021.235v.63h-2.001v-.704c.026-.396.078-.73.204-.999.125-.269.271-.498.439-.688l.225-.21-.01-.015.176-.14.137-.128c.186-.139.357-.277.516-.417l.148-.18c.098-.152.168-.323.168-.518 0-.552-.447-1-1-1s-1.002.448-1.002 1h-2c0-1.657 1.343-3 3.002-3 1.656 0 3 1.343 3 3zm-1.75 6.619c0 .344-.281.625-.625.625h-1.25c-.345 0-.626-.281-.626-.625v-1.238c0-.344.281-.625.626-.625h1.25c.344 0 .625.281.625.625v1.238z"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="#e29700"><path d="M14.66 12.316l-5.316-10.633c-.738-1.476-1.946-1.476-2.685 0l-5.317 10.633c-.738 1.477.008 2.684 1.658 2.684h10.002c1.65 0 2.396-1.207 1.658-2.684zm-7.66-8.316h2.002v5h-2.002v-5zm2.252 8.615c0 .344-.281.625-.625.625h-1.25c-.345 0-.626-.281-.626-.625v-1.239c0-.344.281-.625.626-.625h1.25c.344 0 .625.281.625.625v1.239z"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#000000" d="M14.416 11.586l-.01-.008v-.001l-5.656-5.656c.15-.449.252-.921.252-1.421 0-2.485-2.016-4.5-4.502-4.5-.505 0-.981.102-1.434.255l2.431 2.431-.588 2.196-2.196.588-2.445-2.445c-.162.464-.268.956-.268 1.475 0 2.486 2.014 4.5 4.5 4.5.5 0 .972-.102 1.421-.251l5.667 5.665c.781.781 2.047.781 2.828 0s.781-2.047 0-2.828z"/></svg>
<?php
declare(strict_types=1);
namespace Drupal\upgrade_status;
use Drupal\Core\Extension\Extension;
use Drupal\Core\Site\Settings;
/**
* The route deprecation analyzer.
*/
final class CSSDeprecationAnalyzer {
/**
* Analyzes usages of deprecated CSS selectors in an extension.
*
* @param \Drupal\Core\Extension\Extension $extension
* The extension to be analyzed.
*
* @return \Drupal\upgrade_status\DeprecationMessage[]
* A list of deprecation messages.
*
* @throws \Exception
*/
public function analyze(Extension $extension): array {
$deprecations = [];
$css_files = $this->getAllCSSFiles(DRUPAL_ROOT . '/' . $extension->getPath());
foreach ($css_files as $css_file) {
$content = file_get_contents($css_file);
// Remove valid selectors for this check.
$content = str_replace('#drupal-off-canvas:not(.drupal-off-canvas-reset)', 'removed', $content);
$content = str_replace('#drupal-off-canvas-wrapper', 'removed', $content);
if (strpos($content, '#drupal-off-canvas')) {
$deprecations[] = new DeprecationMessage('The #drupal-off-canvas selector is deprecated in drupal:9.5.0 and is removed from drupal:10.0.0. See https://www.drupal.org/node/3305664.', $css_file, 0, 'CSSDeprecationAnalyzer');
}
}
return $deprecations;
}
/**
* Finds all .css files for non-test extensions under a path.
*
* @param string $path
* Base path to find all .css files in.
*
* @return array
* A list of paths to .css files found under the base path.
*/
private function getAllCSSFiles(string $path) {
$files = [];
$ignore_directories = Settings::get('file_scan_ignore_directories', ['bower_components', 'node_modules']);
foreach(array_filter(glob($path . '/*.css'), 'is_file') as $file) {
foreach ($ignore_directories as $ignore_directory) {
if (strpos($file, '/' . $ignore_directory . '/')) {
continue 2;
}
}
$files[] = $file;
}
foreach (glob($path . '/*', GLOB_ONLYDIR|GLOB_NOSORT) as $dir) {
foreach ($ignore_directories as $ignore_directory) {
if (strpos($dir, '/' . $ignore_directory . '/')) {
continue 2;
}
}
$files = array_merge($files, $this->getAllCSSFiles($dir));
}
return $files;
}
}
<?php
declare(strict_types=1);
namespace Drupal\upgrade_status;
use Drupal\Core\Extension\Extension;
/**
* Config schema deprecation analyzer.
*/
final class ConfigSchemaDeprecationAnalyzer {
/**
* Analyzes usages of deprecated config schema elements in an extension.
*
* @param \Drupal\Core\Extension\Extension $extension
* The extension to be analyzed.
*
* @return \Drupal\upgrade_status\DeprecationMessage[]
* A list of deprecation messages.
*
* @throws \Exception
*/
public function analyze(Extension $extension): array {
$deprecations = [];
$project_dir = DRUPAL_ROOT . '/' . $extension->getPath();
$config_files = $this->getViewsConfigFiles($project_dir);
foreach ($config_files as $config_file) {
$error_path = str_replace(DRUPAL_ROOT . '/', '', $config_file);
$file_contents = file_get_contents($config_file);
if (($line = $this->findKeyLine('default_argument_skip_url:', $file_contents)) !== 1) {
$deprecations[] = new DeprecationMessage("Support from all Views contextual filter settings for the default_argument_skip_url setting is removed from drupal:11.0.0. No replacement is provided. See https://www.drupal.org/node/3382316.", $error_path, $line, 'ConfigSchemaDeprecationAnalyzer');
}
}
return $deprecations;
}
/**
* Finds all views config files for extensions under a path.
*
* @param string $path
* Base path to find all views config files in.
*
* @return array
* A list of paths to views config files found under the base path.
*/
private function getViewsConfigFiles(string $path) {
$files = [];
foreach(glob($path . '/views.view.*.yml') as $file) {
$files[] = $file;
}
foreach (glob($path . '/*', GLOB_ONLYDIR|GLOB_NOSORT) as $dir) {
$files = array_merge($files, $this->getViewsConfigFiles($dir));
}
return $files;
}
/**
* Finds the line that contains the substring.
*
* @param string $substring
* The string to find.
* @param string $file_contents
* String contents of a file.
* @return
* Line number if found, 1 otherwise.
*/
private function findKeyLine($substring, $file_contents) {
$lines = explode("\n", $file_contents);
foreach ($lines as $num => $line) {
if (strpos($line, $substring) !== FALSE) {
return $num + 1;
}
}
return 1;
}
}
<?php
namespace Drupal\upgrade_status\Controller;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Render\RendererInterface;
use Drupal\upgrade_status\ProjectCollector;
use Drupal\upgrade_status\ScanResultFormatter;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
class ScanResultController extends ControllerBase {
/**
* The scan result formatter service.
*
* @var \Drupal\upgrade_status\ScanResultFormatter
*/
protected $resultFormatter;
/**
* The project collector service.
*
* @var \Drupal\upgrade_status\ProjectCollector
*/
protected $projectCollector;
/**
* The renderer service.
*
* @var \Drupal\Core\Render\RendererInterface
*/
protected $renderer;
/**
* Constructs a \Drupal\upgrade_status\Controller\ScanResultController.
*
* @param \Drupal\upgrade_status\ScanResultFormatter $result_formatter
* The scan result formatter service.
* @param \Drupal\upgrade_status\ProjectCollector $project_collector
* The project collector service.
* @param \Drupal\Core\Render\RendererInterface $renderer
* The renderer service.
*/
public function __construct(
ScanResultFormatter $result_formatter,
ProjectCollector $project_collector,
RendererInterface $renderer
) {
$this->resultFormatter = $result_formatter;
$this->projectCollector = $project_collector;
$this->renderer = $renderer;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('upgrade_status.result_formatter'),
$container->get('upgrade_status.project_collector'),
$container->get('renderer')
);
}
/**
* Builds content for the error list page/popup.
*
* @param string $project_machine_name
* The machine name of the project.
*
* @return array
* Build array.
*/
public function resultPage(string $project_machine_name) {
$extension = $this->projectCollector->loadProject($project_machine_name);
return $this->resultFormatter->formatResult($extension);
}
/**
* Generates single project export.
*
* @param string $project_machine_name
* The machine name of the project.
* @param string $format
* The format to use when exporting the data: html or ascii.
*
* @return \Symfony\Component\HttpFoundation\Response
* Response object.
*/
public function resultExport(string $project_machine_name, string $format) {
$extension = $this->projectCollector->loadProject($project_machine_name);
$result = $this->resultFormatter->getRawResult($extension);
// Sanitize user input.
if (!in_array($format, ['html', 'ascii'])) {
$format = 'html';
}
$build = ['#theme' => 'upgrade_status_' . $format . '_export' ];
$build['#projects'][$extension->info['upgrade_status_type'] == ProjectCollector::TYPE_CUSTOM ? 'custom' : 'contrib'] = [
$project_machine_name =>
$format == 'html' ?
$this->resultFormatter->formatResult($extension) :
$this->resultFormatter->formatAsciiResult($extension) ,
];
$fileDate = $this->resultFormatter->formatDateTime($result['date'], 'html_datetime');
$extension = $format == 'html' ? '.html' : '.txt';
$filename = 'single-export-' . $project_machine_name . '-' . $fileDate . $extension;
$response = new Response($this->renderer->renderRoot($build));
$response->headers->set('Content-Disposition', 'attachment; filename="' . $filename . '"');
return $response;
}
/**
* Analyze a specific project in its own HTTP request.
*
* @param string $project_machine_name
* The machine name of the project.
*
* @return \Symfony\Component\HttpFoundation\JsonResponse
* Response object.
*/
public function analyze(string $project_machine_name) {
if ($project_machine_name == 'upgrade_status_request_test') {
// Handle the special case of a request test which is testing the
// HTTP sandboxing capability.
return new JsonResponse(
['message' => 'Request test success']
);
}
else {
// Dealing with a real project.
$extension = $this->projectCollector->loadProject($project_machine_name);
\Drupal::service('upgrade_status.deprecation_analyzer')->analyze($extension);
return new JsonResponse(
['message' => $this->t('Scanned @project', ['@project' => $extension->getName()])]
);
}
}
}
<?php
// @phpcs:ignoreFile
namespace Drupal\upgrade_status;
use GuzzleHttp\Cookie\CookieJarInterface;
use GuzzleHttp\Cookie\SetCookie;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
/**
* Cookie jar that stores cookies as an array.
*
* Note: Copied from Guzzle 6 but adjusted to not trigger deprecations in
* PHP 8.1 during upgrade checks. Can be removed after Core allows Guzzle 7.
*/
class CookieJar implements CookieJarInterface
{
/** @var SetCookie[] Loaded cookie data */
private $cookies = [];
/** @var bool */
private $strictMode;
/**
* @param bool $strictMode Set to true to throw exceptions when invalid
* cookies are added to the cookie jar.
* @param array $cookieArray Array of SetCookie objects or a hash of
* arrays that can be used with the SetCookie
* constructor
*/
public function __construct($strictMode = false, $cookieArray = [])
{
$this->strictMode = $strictMode;
foreach ($cookieArray as $cookie) {
if (!($cookie instanceof SetCookie)) {
$cookie = new SetCookie($cookie);
}
$this->setCookie($cookie);
}
}
/**
* Create a new Cookie jar from an associative array and domain.
*
* @param array $cookies Cookies to create the jar from
* @param string $domain Domain to set the cookies to
*
* @return self
*/
public static function fromArray(array $cookies, $domain)
{
$cookieJar = new self();
foreach ($cookies as $name => $value) {
$cookieJar->setCookie(new SetCookie([
'Domain' => $domain,
'Name' => $name,
'Value' => $value,
'Discard' => true
]));
}
return $cookieJar;
}
/**
* @deprecated
*/
public static function getCookieValue($value)
{
return $value;
}
/**
* Evaluate if this cookie should be persisted to storage
* that survives between requests.
*
* @param SetCookie $cookie Being evaluated.
* @param bool $allowSessionCookies If we should persist session cookies
* @return bool
*/
public static function shouldPersist(
SetCookie $cookie,
$allowSessionCookies = false
) {
if ($cookie->getExpires() || $allowSessionCookies) {
if (!$cookie->getDiscard()) {
return true;
}
}
return false;
}
/**
* Finds and returns the cookie based on the name
*
* @param string $name cookie name to search for
* @return SetCookie|null cookie that was found or null if not found
*/
public function getCookieByName($name)
{
// don't allow a non string name
if ($name === null || !is_scalar($name)) {
return null;
}
foreach ($this->cookies as $cookie) {
if ($cookie->getName() !== null && strcasecmp($cookie->getName(), $name) === 0) {
return $cookie;
}
}
return null;
}
public function toArray(): array
{
return array_map(function (SetCookie $cookie) {
return $cookie->toArray();
}, $this->getIterator()->getArrayCopy());
}
public function clear($domain = null, $path = null, $name = null) :void
{
if (!$domain) {
$this->cookies = [];
return;
} elseif (!$path) {
$this->cookies = array_filter(
$this->cookies,
function (SetCookie $cookie) use ($domain) {
return !$cookie->matchesDomain($domain);
}
);
} elseif (!$name) {
$this->cookies = array_filter(
$this->cookies,
function (SetCookie $cookie) use ($path, $domain) {
return !($cookie->matchesPath($path) &&
$cookie->matchesDomain($domain));
}
);
} else {
$this->cookies = array_filter(
$this->cookies,
function (SetCookie $cookie) use ($path, $domain, $name) {
return !($cookie->getName() == $name &&
$cookie->matchesPath($path) &&
$cookie->matchesDomain($domain));
}
);
}
}
public function clearSessionCookies(): void
{
$this->cookies = array_filter(
$this->cookies,
function (SetCookie $cookie) {
return !$cookie->getDiscard() && $cookie->getExpires();
}
);
}
public function setCookie(SetCookie $cookie): bool
{
// If the name string is empty (but not 0), ignore the set-cookie
// string entirely.
$name = $cookie->getName();
if (!$name && $name !== '0') {
return false;
}
// Only allow cookies with set and valid domain, name, value
$result = $cookie->validate();
if ($result !== true) {
if ($this->strictMode) {
throw new \RuntimeException('Invalid cookie: ' . $result);
} else {
$this->removeCookieIfEmpty($cookie);
return false;
}
}
// Resolve conflicts with previously set cookies
foreach ($this->cookies as $i => $c) {
// Two cookies are identical, when their path, and domain are
// identical.
if ($c->getPath() != $cookie->getPath() ||
$c->getDomain() != $cookie->getDomain() ||
$c->getName() != $cookie->getName()
) {
continue;
}
// The previously set cookie is a discard cookie and this one is
// not so allow the new cookie to be set
if (!$cookie->getDiscard() && $c->getDiscard()) {
unset($this->cookies[$i]);
continue;
}
// If the new cookie's expiration is further into the future, then
// replace the old cookie
if ($cookie->getExpires() > $c->getExpires()) {
unset($this->cookies[$i]);
continue;
}
// If the value has changed, we better change it
if ($cookie->getValue() !== $c->getValue()) {
unset($this->cookies[$i]);
continue;
}
// The cookie exists, so no need to continue
return false;
}
$this->cookies[] = $cookie;
return true;
}
#[\ReturnTypeWillChange]
public function count()
{
return count($this->cookies);
}
#[\ReturnTypeWillChange]
public function getIterator()
{
return new \ArrayIterator(array_values($this->cookies));
}
public function extractCookies(
RequestInterface $request,
ResponseInterface $response
): void {
if ($cookieHeader = $response->getHeader('Set-Cookie')) {
foreach ($cookieHeader as $cookie) {
$sc = SetCookie::fromString($cookie);
if (!$sc->getDomain()) {
$sc->setDomain($request->getUri()->getHost());
}
if (0 !== strpos($sc->getPath(), '/')) {
$sc->setPath($this->getCookiePathFromRequest($request));
}
$this->setCookie($sc);
}
}
}
/**
* Computes cookie path following RFC 6265 section 5.1.4
*
* @link https://tools.ietf.org/html/rfc6265#section-5.1.4
*
* @param RequestInterface $request
* @return string
*/
private function getCookiePathFromRequest(RequestInterface $request)
{
$uriPath = $request->getUri()->getPath();
if ('' === $uriPath) {
return '/';
}
if (0 !== strpos($uriPath, '/')) {
return '/';
}
if ('/' === $uriPath) {
return '/';
}
if (0 === $lastSlashPos = strrpos($uriPath, '/')) {
return '/';
}
return substr($uriPath, 0, $lastSlashPos);
}
public function withCookieHeader(RequestInterface $request): RequestInterface
{
$values = [];
$uri = $request->getUri();
$scheme = $uri->getScheme();
$host = $uri->getHost();
$path = $uri->getPath() ?: '/';
foreach ($this->cookies as $cookie) {
if ($cookie->matchesPath($path) &&
$cookie->matchesDomain($host) &&
!$cookie->isExpired() &&
(!$cookie->getSecure() || $scheme === 'https')
) {
$values[] = $cookie->getName() . '='
. $cookie->getValue();
}
}
return $values
? $request->withHeader('Cookie', implode('; ', $values))
: $request;
}
/**
* If a cookie already exists and the server asks to set it again with a
* null value, the cookie must be deleted.
*
* @param SetCookie $cookie
*/
private function removeCookieIfEmpty(SetCookie $cookie)
{
$cookieValue = $cookie->getValue();
if ($cookieValue === null || $cookieValue === '') {
$this->clear(
$cookie->getDomain(),
$cookie->getPath(),
$cookie->getName()
);
}
}
}
<?php
namespace Drupal\upgrade_status;
use Drupal\Component\Datetime\TimeInterface;
use Drupal\Core\Extension\Extension;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\KeyValueStore\KeyValueFactoryInterface;
use DrupalFinder\DrupalFinder;
use GuzzleHttp\Client;
use Psr\Log\LoggerInterface;
use Symfony\Component\Process\PhpExecutableFinder;
use Symfony\Component\Process\Process;
final class DeprecationAnalyzer {
/**
* Upgrade status scan result storage.
*
* @var \Drupal\Core\KeyValueStore\KeyValueStoreInterface
*/
protected $scanResultStorage;
/**
* The logger service.
*
* @var \Drupal\Core\Logger\LoggerChannelInterface
*/
protected $logger;
/**
* Path to the PHPStan neon configuration.
*
* @var string
*/
protected $phpstanNeonPath;
/**
* Path to the vendor directory.
*
* @var string
*/
protected $vendorPath;
/**
* Path to the binaries.
*
* @var string
*/
protected $binPath;
/**
* Path to the PHP binary.
*
* @var string
*/
protected $phpPath;
/**
* Temporary directory to use for running phpstan.
*
* @var string
*/
protected $temporaryDirectory;
/**
* HTTP Client for drupal.org API calls.
*
* @var \GuzzleHttp\Client
*/
protected $httpClient;
/**
* File system service.
*
* @var \Drupal\Core\File\FileSystemInterface
*/
protected $fileSystem;
/**
* The Twig deprecation analyzer.
*
* @var \Drupal\upgrade_status\TwigDeprecationAnalyzer
*/
protected $twigDeprecationAnalyzer;
/**
* The library deprecation analyzer.
*
* @var \Drupal\upgrade_status\LibraryDeprecationAnalyzer
*/
protected $libraryDeprecationAnalyzer;
/**
* The theme function deprecation analyzer.
*
* @var \Drupal\upgrade_status\ThemeFunctionDeprecationAnalyzer
*/
protected $themeFunctionDeprecationAnalyzer;
/**
* The route deprecation analyzer.
*
* @var \Drupal\upgrade_status\RouteDeprecationAnalyzer
*/
protected $routeDeprecationAnalyzer;
/**
* The extension metadata deprecation analyzer.
*
* @var \Drupal\upgrade_status\ExtensionMetadataDeprecationAnalyzer
*/
protected $extensionMetadataDeprecationAnalyzer;
/**
* The config schema deprecation analyzer.
*
* @var \Drupal\upgrade_status\ConfigSchemaDeprecationAnalyzer
*/
protected $configSchemaDeprecationAnalyzer;
/**
* The CSS deprecation analyzer.
*
* @var \Drupal\upgrade_status\CSSDeprecationAnalyzer
*/
protected $CSSDeprecationAnalyzer;
/**
* The time service.
*
* @var \Drupal\Component\Datetime\TimeInterface
*/
protected $time;
/**
* Drupal project finder.
*
* @var \DrupalFinder\DrupalFinder
*/
protected $finder;
/**
* Whether the analyzer environment is initialized.
*
* @var bool
*/
protected $environmentInitialized = FALSE;
/**
* Constructs a deprecation analyzer.
*
* @param \Drupal\Core\KeyValueStore\KeyValueFactoryInterface $key_value_factory
* The key/value factory.
* @param \Psr\Log\LoggerInterface $logger
* The logger.
* @param \GuzzleHttp\Client $http_client
* HTTP client.
* @param \Drupal\Core\File\FileSystemInterface $file_system
* File system service.
* @param \Drupal\upgrade_status\TwigDeprecationAnalyzer $twig_deprecation_analyzer
* The Twig deprecation analyzer.
* @param \Drupal\upgrade_status\LibraryDeprecationAnalyzer $library_deprecation_analyzer
* The library deprecation analyzer.
* @param \Drupal\upgrade_status\ThemeFunctionDeprecationAnalyzer $theme_function_deprecation_analyzer
* The theme function deprecation analyzer.
* @param \Drupal\upgrade_status\RouteDeprecationAnalyzer $route_deprecation_analyzer
* The route deprecation analyzer.
* @param \Drupal\upgrade_status\ExtensionMetadataDeprecationAnalyzer $extension_metadata_analyzer
* The extension metadata analyzer.
* @param \Drupal\upgrade_status\ConfigSchemaDeprecationAnalyzer $config_schema_analyzer
* The config schema analyzer.
* @param \Drupal\upgrade_status\CSSDeprecationAnalyzer $css_deprecation_analyzer
* The CSS deprecation analyzer.
* @param \Drupal\Component\Datetime\TimeInterface $time
* The time service.
*/
public function __construct(
KeyValueFactoryInterface $key_value_factory,
LoggerInterface $logger,
Client $http_client,
FileSystemInterface $file_system,
TwigDeprecationAnalyzer $twig_deprecation_analyzer,
LibraryDeprecationAnalyzer $library_deprecation_analyzer,
ThemeFunctionDeprecationAnalyzer $theme_function_deprecation_analyzer,
RouteDeprecationAnalyzer $route_deprecation_analyzer,
ExtensionMetadataDeprecationAnalyzer $extension_metadata_analyzer,
ConfigSchemaDeprecationAnalyzer $config_schema_analyzer,
CSSDeprecationAnalyzer $css_deprecation_analyzer,
TimeInterface $time
) {
$this->scanResultStorage = $key_value_factory->get('upgrade_status_scan_results');
$this->logger = $logger;
$this->httpClient = $http_client;
$this->fileSystem = $file_system;
$this->twigDeprecationAnalyzer = $twig_deprecation_analyzer;
$this->libraryDeprecationAnalyzer = $library_deprecation_analyzer;
$this->themeFunctionDeprecationAnalyzer = $theme_function_deprecation_analyzer;
$this->routeDeprecationAnalyzer = $route_deprecation_analyzer;
$this->extensionMetadataDeprecationAnalyzer = $extension_metadata_analyzer;
$this->configSchemaDeprecationAnalyzer = $config_schema_analyzer;
$this->CSSDeprecationAnalyzer = $css_deprecation_analyzer;
$this->time = $time;
}
/**
* Initialize the external environment.
*
* @throws \Exception
* In case initialization failed. The analyzer will not work in this case.
*/
public function initEnvironment() {
if (!empty($this->environmentInitialized)) {
// Already successfully initialized, no need to do it again.
return;
}
$this->phpPath = $this->findPhpPath();
$this->finder = new DrupalFinder();
$this->finder->locateRoot(DRUPAL_ROOT);
// If a Drupal project is built with Composer scaffolding, the "name"
// property in composer.json MUST NOT be "drupal/drupal". If it is, the
// webflo/drupal-finder package will assume we are NOT in a Composer
// scaffolded project and assume Drupal core is in the root directory.
// @see https://www.drupal.org/project/upgrade_status/issues/3229725
if (!is_dir($this->finder->getDrupalRoot() . '/core')) {
$composer_json_path = dirname(DRUPAL_ROOT) . '/composer.json';
if (!file_exists($composer_json_path)) {
throw new \Exception('Could not find the composer.json file for your Drupal site, assumed: ' . $composer_json_path);
}
$composer_data = \json_decode(file_get_contents($composer_json_path), TRUE);
if ($composer_data['name'] === 'drupal/drupal') {
throw new \Exception('Change the "name" property in ' . $composer_json_path . ' from "drupal/drupal" to a custom value.');
}
else {
throw new \Exception('Could not detect the location of "drupal/core", please open an issue at https://www.drupal.org/project/issues/upgrade_status.');
}
}
$this->vendorPath = $this->finder->getVendorDir();
$this->binPath = $this->findBinPath();
$system_temporary = $this->fileSystem->getTempDirectory();
$this->temporaryDirectory = $system_temporary . '/upgrade_status';
if (!file_exists($this->temporaryDirectory)) {
$this->prepareTempDirectory();
}
$this->phpstanNeonPath = $this->temporaryDirectory . '/deprecation_testing.neon';
$this->createModifiedNeonFile();
$this->environmentInitialized = TRUE;
}
/**
* Finds bin-dir location.
*
* This can be set in composer.json via `bin-dir` config and may not be
* inside the vendor directory. The logic somewhat duplicates
* DrupalFinder's vendor directory detection for best developer guidance
* in case of errors.
*
* @return string
* Bin directory path if found.
*
* @throws \Exception
*/
protected function findBinPath() {
$composer_name = trim(getenv('COMPOSER')) ?: 'composer.json';
$composer_json_path = $this->finder->getComposerRoot() . '/' . $composer_name;
if ($composer_json_path && file_exists($composer_json_path)) {
$json = json_decode(file_get_contents($composer_json_path), TRUE);
if (is_null($json) || !is_array($json)) {
throw new \Exception('Unable to decode composer information from ' . $composer_json_path . '.');
}
}
else {
throw new \Exception('The composer.json file was not found at ' . $composer_json_path . '.');
}
// If a bin-dir is specified, that is most specific.
if (isset($json['config']['bin-dir'])) {
$binPath = $this->finder->getComposerRoot() . '/' . rtrim($json['config']['bin-dir'], '/');
if (file_exists($binPath . '/phpstan')) {
return $binPath;
}
else {
throw new \Exception('The PHPStan binary was not found in the bin-dir specified by ' . $composer_json_path . '. Attempted: ' . $binPath . '/phpstan.');
}
}
// If a vendor-dir is specified, that is slightly less specific.
if (isset($json['config']['vendor-dir'])) {
$binPath = $this->finder->getComposerRoot() . '/' . rtrim($json['config']['vendor-dir'], '/') . '/bin';
if (file_exists($binPath . '/phpstan')) {
return $binPath;
}
else {
throw new \Exception('The PHPStan binary was not found in the vendor-dir specified by ' . $composer_json_path . '. Attempted: ' . $binPath . '/phpstan.');
}
}
// Try the assumed default vendor directory as a last resort.
$binPath = $this->finder->getComposerRoot() . '/vendor/bin';
if (file_exists($binPath . '/phpstan')) {
return $binPath;
}
throw new \Exception('The PHPStan binary was not found in the default vendor directory based on the location of ' . $composer_json_path . '. You may need to configure a vendor-dir in composer.json. See https://getcomposer.org/doc/06-config.md#vendor-dir. Attempted: ' . $binPath . '/phpstan.');
}
/**
* Finds the PHP path.
*
* This ensures we execute PHPStan with the same PHP binary that is used by
* the web server.
*
* @return string
* PHP path if found.
*
* @throws \Exception
*/
protected function findPhpPath() {
$finder = new PhpExecutableFinder();
$binary = $finder->find();
if ($binary === FALSE) {
throw new \Exception('The PHP binary was not found.');
}
return $binary;
}
/**
* Analyze the codebase of an extension including all its sub-components.
*
* @param \Drupal\Core\Extension\Extension $extension
* The extension to analyze.
* @param array $options
* Options for the analysis. Only the phpstan-memory-limit key is used
* with a default value of 1500M.
*
* @return null
* Errors are logged to the logger, data is stored to keyvalue storage.
*/
public function analyze(Extension $extension, array $options = []) {
try {
$this->initEnvironment();
}
catch (\Exception $e) {
// Should not get here as integrations are expected to invoke
// initEnvironment() first by itself to ensure the environment
// is going to work when needed (and inform users about any
// issues). That said, if they did not do that and there was
// no issue with the environment, then they are lucky.
return;
}
$project_dir = DRUPAL_ROOT . '/' . $extension->getPath();
$this->logger->notice('Processing %path.', ['%path' => $project_dir]);
$memory_limit = $options['phpstan-memory-limit'] ?? '1500M';
$command = [
$this->phpPath,
$this->binPath . '/phpstan',
'analyse',
'--memory-limit=' . $memory_limit,
'--error-format=json',
'--configuration=' . $this->phpstanNeonPath,
$project_dir
];
$process = new Process($command, DRUPAL_ROOT, NULL, NULL, NULL);
$process->run();
// If there was an error about lack of files, that is fine for us, an
// extension does not necessarily need PHP files. Use a standard
// empty resultset for this case.
$stderr = trim($process->getErrorOutput()) ?: 'Empty.';
if (strpos($stderr, 'No files found to analyse.') !== FALSE) {
$json = [
'files' => [],
'errors' => [],
'totals' => [
'errors' => 0,
'file_errors' => 0,
],
];
}
else {
$json = json_decode($process->getOutput(), TRUE);
}
// If there was a JSON parsing error, that may be a fatal that
// PHPStan did not catch, so report the raw output as error.
if (json_last_error() !== JSON_ERROR_NONE) {
$stdout = trim($process->getOutput()) ?: 'Empty.';
$json = [
'files' => [],
'errors' => [],
'totals' => [
'errors' => 0,
'file_errors' => 0,
],
];
$formatted_error =
"<h6>PHPStan command failed:</h6> <p>" . implode(" ", $command) .
"</p> <h6>Command output:</h6> <p>" . $stdout .
"</p> <h6>Command error:</h6> <p>" . $stderr . '</p>';
$this->logger->error('%phpstan_fail', ['%phpstan_fail' => strip_tags($formatted_error)]);
// Add a failure message with the nonexistent 'PHPStan failed'
// filename, so the error conforms to the expected format.
$json['files']['PHPStan failed'] = [
'messages' => [
[
'message' => $formatted_error,
'line' => 0,
],
],
];
$json['totals']['errors']++;
$json['totals']['file_errors']++;
}
// Convert "non-file" errors to file errors
foreach ($json['errors'] as $error) {
if (preg_match('!^(.+) on line (\d+) while analysing file (.+)$!', $error, $parts)) {
$json['totals']['file_errors']++;
@$json['files'][$parts[3]]['messages'][] = [
'message' => $parts[1],
'line' => $parts[2],
];
}
}
// Add analyzer info.
foreach ($json['files'] as &$errors) {
foreach ($errors['messages'] as &$error) {
$error['analyzer'] = 'PHPStan';
}
}
$result = [
'date' => $this->time->getRequestTime(),
'data' => $json,
];
$metadataDeprecations = $this->extensionMetadataDeprecationAnalyzer->analyze($extension);
$result['data']['totals']['upgrade_status_split']['declared_ready'] = empty($metadataDeprecations);
// Run further deprecation analyzers and collect results.
$more_deprecations = array_merge(
$this->twigDeprecationAnalyzer->analyze($extension),
$this->libraryDeprecationAnalyzer->analyze($extension),
$this->routeDeprecationAnalyzer->analyze($extension),
$this->CSSDeprecationAnalyzer->analyze($extension),
$this->configSchemaDeprecationAnalyzer->analyze($extension),
$metadataDeprecations,
);
if (projectCollector::getDrupalCoreMajorVersion() < 10) {
// Theme function support is not present in Drupal 10 and cannot be checked.
$more_deprecations = array_merge($more_deprecations,
$this->themeFunctionDeprecationAnalyzer->analyze($extension),
);
}
foreach ($more_deprecations as $one_deprecation) {
$result['data']['files'][$one_deprecation->getFile()]['messages'][] = [
'message' => $one_deprecation->getMessage(),
'line' => $one_deprecation->getLine(),
'analyzer' => $one_deprecation->getAnalyzer(),
];
$result['data']['totals']['errors']++;
$result['data']['totals']['file_errors']++;
}
// Assume next step is to relax (there were no errors found).
$result['data']['totals']['upgrade_status_next'] = ProjectCollector::NEXT_RELAX;
foreach ($result['data']['files'] as &$errors) {
foreach ($errors['messages'] as &$error) {
// Overwrite message with processed text. Save category.
[$message, $category] = $this->categorizeMessage($error['message'], $extension);
$error['message'] = $message;
$error['upgrade_status_category'] = $category;
// If the category was 'rector' that means at least one error was
// identified as covered by rector, so next step should be to run
// rector on this project.
if ($category == 'rector') {
$result['data']['totals']['upgrade_status_next'] = ProjectCollector::NEXT_RECTOR;
}
// If the category was not rector, if the next step is still to
// relax, modify that to fix manually.
elseif ($result['data']['totals']['upgrade_status_next'] == ProjectCollector::NEXT_RELAX) {
$result['data']['totals']['upgrade_status_next'] = ProjectCollector::NEXT_MANUAL;
}
// Sum up the error based on the category it ended up in. Split the
// categories into two high level buckets needing attention now or
// later for compatibility with the next major version. Issues in the
// 'ignore' category are intentionally not counted in either.
@$result['data']['totals']['upgrade_status_category'][$category]++;
if (in_array($category, ['safe', 'old', 'rector'])) {
@$result['data']['totals']['upgrade_status_split']['error']++;
}
elseif (in_array($category, ['later', 'uncategorized'])) {
@$result['data']['totals']['upgrade_status_split']['warning']++;
}
}
}
// Store the analysis results in our storage bin.
$this->scanResultStorage->set($extension->getName(), $result);
}
/**
* Prepare temporary directories for Upgrade Status.
*
* The created directories in Drupal's temporary directory are needed to
* dynamically set a temporary directory for PHPStan's cache in the neon file
* provided by Upgrade Status.
*
* @throws \Exception
* If creating the temporary directory failed.
*/
protected function prepareTempDirectory() {
$success = $this->fileSystem->prepareDirectory($this->temporaryDirectory, FileSystemInterface::CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS);
if (!$success) {
throw new \Exception('Unable to create temporary directory for Upgrade Status at ' . $this->temporaryDirectory);
}
$phpstan_cache_directory = $this->temporaryDirectory . '/phpstan';
$success = $this->fileSystem->prepareDirectory($phpstan_cache_directory, FileSystemInterface::CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS);
if (!$success) {
throw new \Exception('Unable to create temporary directory for PHPStan at ' . $phpstan_cache_directory);
}
}
/**
* Creates the final config file in the temporary directory.
*
* @throws \Exception
* If the PHPStan configuration file cannot be written.
*/
protected function createModifiedNeonFile() {
if (function_exists('drupal_get_path')) {
// @todo remove compatibility layer with Drupal 9.3.0 when removing Drupal 9 compatibility.
$module_path = DRUPAL_ROOT . '/' . drupal_get_path('module', 'upgrade_status');
}
else {
$module_path = DRUPAL_ROOT . '/' . \Drupal::service('extension.list.module')->getPath('upgrade_status');
}
$config = file_get_contents($module_path . '/deprecation_testing_template.neon');
$config = str_replace(
'parameters:',
"parameters:\n\ttmpDir: '" . $this->temporaryDirectory . '/phpstan' . "'",
$config
);
if (!class_exists('PHPStan\ExtensionInstaller\GeneratedConfig')) {
$extension_neon = $this->vendorPath . '/mglaman/phpstan-drupal/extension.neon';
$rules_neon = $this->vendorPath . '/phpstan/phpstan-deprecation-rules/rules.neon';
if (!file_exists($extension_neon) || !file_exists($rules_neon)) {
throw new \Exception('Vendor source files were not found. You may need to configure a vendor-dir in composer.json. See https://getcomposer.org/doc/06-config.md#vendor-dir. Missing ' . $extension_neon . ' and ' . $rules_neon . '.');
}
$config .= "\nincludes:\n\t- '" . $extension_neon . "'\n\t- '" . $rules_neon . "'\n";
// phpstan-drupal 1.1.16 introduced a new rules.neon file, include it if
// it exists. phpstan-drupal 1.1.4 and earlier are the only versions that
// still support PHP 7.3 and earlier, and this file does not exist there.
$drupal_rules_neon = $this->vendorPath . '/mglaman/phpstan-drupal/rules.neon';
if (file_exists($drupal_rules_neon)) {
$config .= "\t- '" . $drupal_rules_neon . "'\n";
}
}
$success = file_put_contents($this->phpstanNeonPath, $config);
if (!$success) {
throw new \Exception('Unable to write configuration for PHPStan to ' . $this->phpstanNeonPath . '.');
}
}
/**
* Annotate and categorize the error message.
*
* @param string $error
* Error message as identified by phpstan.
* @param \Drupal\Core\Extension\Extension $extension
* Extension where the error was found.
*
* @return array
* Two item array. The reformatted error and the category.
*/
protected function categorizeMessage(string $error, Extension $extension) {
// Make the error more readable in case it has the deprecation text.
$error = preg_replace('!\s+!', ' ', trim($error));
$error = preg_replace('!:\s+(in|as of)!', '. Deprecated \1', $error);
$error = preg_replace('!(u|U)se \\\\Drupal!', '\1se Drupal', $error);
// TestBase and WebTestBase replacements are available at least from Drupal
// 8.6.0, so use that version number. Otherwise use the number from the
// message.
$version = '';
if (preg_match('!\\\\(Web|)TestBase. Deprecated in [Dd]rupal[ :]8\.8\.0 !', $error)) {
$version = '8.6.0';
$error .= " Replacement available from drupal:8.6.0.";
}
elseif (preg_match('!Deprecated (in|as of) [Dd]rupal[ :](\d+\.\d)!', $error, $version_found)) {
$version = $version_found[2];
}
// Set a default category for the messages we can't categorize.
$category = 'uncategorized';
if (!empty($version)) {
// Categorize deprecations for contributed projects based on
// community rules.
if (!empty($extension->info['project'])) {
// If the found deprecation is older or equal to the oldest
// supported core version, it should be old enough to update
// either way.
if (version_compare($version, ProjectCollector::getOldestSupportedMinor()) <= 0) {
$category = 'old';
}
// If the deprecation is not old and we are dealing with a contrib
// module, the deprecation should be dealt with later.
else {
$category = 'later';
}
}
// For custom projects, look at this site's version specifically.
else {
// If the found deprecation is older or equal to the current
// Drupal version on this site, it should be safe to update.
if (version_compare($version, \Drupal::VERSION) <= 0) {
$category = 'safe';
}
else {
$category = 'later';
}
}
}
// If the error is covered by rector, override the result.
if ($this->isRectorCovered($error)) {
$category = 'rector';
}
// Ignore the broken messages for EntityStorageInterface deprecation.
if (strpos($error, 'of interface Drupal\Core\Entity\EntityStorageInterface. Deprecated in drupal:10.1.0 and is removed from drupal:11.0.0. Use Drupal\Core\Entity\RevisionableStorageInterface') !== FALSE) {
$category = 'ignore';
}
// If the deprecation is already for after the next Drupal major, put it in the
// ignore category. This overwrites any categorization before intentionally.
if (preg_match('!(will be|is) removed (before|from) [Dd]rupal[ :](\d+)\.!', $error, $version_removed)) {
if ($version_removed[3] > ProjectCollector::getDrupalCoreMajorVersion() + 1) {
$category = 'ignore';
}
}
// Check for "guzzlehttp/guzzle:8.0" and ignore those errors. That major is not
// released yet, so compatibility cannot be proven. Stop ignoring this error from
// Drupal 11 as a safeguard.
if (strpos($error, 'guzzlehttp/guzzle:8.0') !== FALSE && ProjectCollector::getDrupalCoreMajorVersion() < 11) {
$category = 'ignore';
}
// Ignore twig 3.12 and 3.15 false positives (until core fixes them).
foreach ([3.12, 3.15] as $version) {
if (strpos($error, 'Since twig/twig ' . $version) !== FALSE && ProjectCollector::getDrupalCoreMajorVersion() < 11) {
$category = 'ignore';
}
}
return [$error, $category];
}
/**
* Checks whether an error message is covered by rector.
*
* @return bool
*/
protected function isRectorCovered($string) {
// Hardcoded lo-fi implementation for now. This should be the same as in
// https://git.drupalcode.org/project/deprecation_status/-/blob/script/stats.php
$rector_covered = [
// 0.3.3
'Call to deprecated function drupal_set_message(). Deprecated in drupal:8.5.0 and is removed from drupal:9.0.0. Use Drupal\Core\Messenger\MessengerInterface::addMessage() instead.',
'Call to deprecated method entityManager() of class Drupal. Deprecated in drupal:8.0.0 and is removed from drupal:9.0.0. Use Drupal::entityTypeManager() instead in most cases. If the needed method is not on \Drupal\Core\Entity\EntityTypeManagerInterface, see the deprecated \Drupal\Core\Entity\EntityManager to find the correct interface or service.',
'Call to deprecated method entityManager() of class Drupal\Core\Controller\ControllerBase. Deprecated in drupal:8.0.0 and is removed from drupal:9.0.0. Most of the time static::entityTypeManager() is supposed to be used instead.',
'Call to deprecated function db_insert(). Deprecated in drupal:8.0.0 and is removed from drupal:9.0.0. Instead, get a database connection injected into your service from the container and call insert() on it. For example,',
'Call to deprecated function db_select(). Deprecated in drupal:8.0.0 and is removed from drupal:9.0.0. Instead, get a database connection injected into your service from the container and call select() on it. For example,',
'Call to deprecated function db_query(). Deprecated in drupal:8.0.0 and is removed from drupal:9.0.0. Instead, get a database connection injected into your service from the container and call query() on it. For example,',
'Call to deprecated function file_prepare_directory(). Deprecated in drupal:8.7.0 and is removed from drupal:9.0.0. Use Drupal\Core\File\FileSystemInterface::prepareDirectory().',
'Call to deprecated method getMock() of class Drupal\Tests\BrowserTestBase. Deprecated in drupal:8.5.0 and is removed from drupal:9.0.0. Use Drupal\Tests\PhpunitCompatibilityTrait::createMock() instead.',
'Call to deprecated method getMock() of class Drupal\KernelTests\KernelTestBase. Deprecated in drupal:8.5.0 and is removed from drupal:9.0.0. Use Drupal\Tests\PhpunitCompatibilityTrait::createMock() instead.',
'Call to deprecated method getMock() of class Drupal\Tests\UnitTestCase. Deprecated in drupal:8.5.0 and is removed from drupal:9.0.0. Use Drupal\Tests\PhpunitCompatibilityTrait::createMock() instead.',
'Call to deprecated method url() of class Drupal. Deprecated in drupal:8.0.0 and is removed from drupal:9.0.0. Instead create a \Drupal\Core\Url object directly, for example using Url::fromRoute().',
// 0.4.0
'Call to deprecated function format_date(). Deprecated in drupal:8.0.0 and is removed from drupal:9.0.0. Use Drupal::service(\'date.formatter\')->format().',
'Call to deprecated method strtolower() of class Drupal\Component\Utility\Unicode. Deprecated in drupal:8.6.0 and is removed from drupal:9.0.0. Use mb_strtolower() instead.',
'Call to deprecated constant FILE_CREATE_DIRECTORY: Deprecated in drupal:8.7.0 and is removed from drupal:9.0.0. Use Drupal\Core\File\FileSystemInterface::CREATE_DIRECTORY.',
'Call to deprecated constant FILE_EXISTS_REPLACE: Deprecated in drupal:8.7.0 and is removed from drupal:9.0.0. Use Drupal\Core\File\FileSystemInterface::EXISTS_REPLACE.',
'Call to deprecated method l() of class Drupal. Deprecated in drupal:8.0.0 and is removed from drupal:9.0.0. Use Drupal\Core\Link::fromTextAndUrl() instead.',
'Call to deprecated function drupal_render(). Deprecated in drupal:8.0.0 and is removed from drupal:9.0.0. Use the',
'Call to deprecated function drupal_render_root(). Deprecated in drupal:8.0.0 and is removed from drupal:9.0.0. Use Drupal\Core\Render\RendererInterface::renderRoot() instead.',
// 0.5.0
'Call to deprecated function file_unmanaged_save_data(). Deprecated in drupal:8.7.0 and is removed from drupal:9.0.0. Use Drupal\Core\File\FileSystemInterface::saveData().',
// 0.5.1
'Call to deprecated constant FILE_MODIFY_PERMISSIONS: Deprecated in drupal:8.7.0 and is removed from drupal:9.0.0. Use Drupal\Core\File\FileSystemInterface::MODIFY_PERMISSIONS.',
'Call to deprecated function db_delete(). Deprecated in drupal:8.0.0 and is removed from drupal:9.0.0. Instead, get a database connection injected into your service from the container and call delete() on it. For example,',
// 0.5.2
'Call to deprecated function entity_get_form_display(). Deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Use EntityDisplayRepositoryInterface::getFormDisplay() instead.',
'Call to deprecated function entity_get_display(). Deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Use EntityDisplayRepositoryInterface::getViewDisplay() instead.',
'Call to deprecated constant REQUEST_TIME: Deprecated in drupal:8.3.0 and is removed from drupal:11.0.0. Use Drupal::time()->getRequestTime();',
'Call to deprecated method urlInfo() of class Drupal\Core\Entity\EntityInterface. Deprecated in drupal:8.0.0 and is removed from drupal:9.0.0. Use Drupal\Core\Entity\EntityInterface::toUrl() instead.',
'Call to deprecated function file_scan_directory(). Deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Use Drupal\Core\File\FileSystemInterface::scanDirectory() instead.',
'Call to deprecated function file_default_scheme(). Deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Use Drupal::config(\'system.file\')->get(\'default_scheme\') instead.',
'Call to deprecated function db_update(). Deprecated in drupal:8.0.0 and is removed from drupal:9.0.0. Instead, get a database connection injected into your service from the container and call update() on it. For example,',
// 0.5.3
'Call to deprecated method strtolower() of class Drupal\Component\Utility\Unicode. Deprecated in drupal:8.6.0 and is removed from drupal:9.0.0. Use mb_strtolower() instead.',
'Call to deprecated method strlen() of class Drupal\Component\Utility\Unicode. Deprecated in drupal:8.6.0 and is removed from drupal:9.0.0. Use mb_strlen() instead.',
'Call to deprecated method substr() of class Drupal\Component\Utility\Unicode. Deprecated in drupal:8.6.0 and is removed from drupal:9.0.0. Use mb_substr() instead.',
'Call to deprecated method link() of class Drupal\Core\Entity\EntityInterface. Deprecated in drupal:8.0.0 and is removed from drupal:9.0.0. Use Drupal\Core\EntityInterface::toLink()->toString() instead.',
'Call to deprecated function entity_load(). Deprecated in drupal:8.0.0 and is removed from drupal:9.0.0. Use the entity type storage\'s load() method.',
'Call to deprecated function node_load(). Deprecated in drupal:8.0.0 and is removed from drupal:9.0.0. Use Drupal\node\Entity\Node::load().',
'Call to deprecated function file_load(). Deprecated in drupal:8.0.0 and is removed from drupal:9.0.0. Use Drupal\file\Entity\File::load().',
'Call to deprecated function user_load(). Deprecated in drupal:8.0.0 and is removed from drupal:9.0.0. Use Drupal\user\Entity\User::load().',
'Call to deprecated function file_directory_temp(). Deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Use Drupal\Core\File\FileSystemInterface::getTempDirectory() instead.',
'Call to deprecated function file_directory_os_temp(). Deprecated in drupal:8.3.0 and is removed from drupal:9.0.0. Use Drupal\Component\FileSystem\FileSystem::getOsTemporaryDirectory().',
'Call to deprecated function drupal_realpath(). Deprecated in drupal:8.0.0 and is removed from drupal:9.0.0. Use Drupal\Core\File\FileSystem::realpath().',
'Call to deprecated function file_uri_target(). Deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Use Drupal\Core\StreamWrapper\StreamWrapperManagerInterface::getTarget() instead.',
// 0.5.4
'Call to deprecated method format() of class Drupal\Component\Utility\SafeMarkup. Deprecated in drupal:8.0.0 and is removed from drupal:9.0.0. Use Drupal\Component\Render\FormattableMarkup.',
'Call to deprecated constant FILE_EXISTS_RENAME: Deprecated in drupal:8.7.0 and is removed from drupal:9.0.0. Use Drupal\Core\File\FileSystemInterface::EXISTS_RENAME.',
// Covered below with the pattern.
//'Call to deprecated method l() of class [redacted]. Deprecated in drupal:8.0.0 and is removed from drupal:9.0.0. Use Drupal\Core\Link::fromTextAndUrl() instead.',
'Call to deprecated function entity_create(). Deprecated in drupal:8.0.0 and is removed from drupal:9.0.0. Use The method overriding Entity::create() for the entity type, e.g. \Drupal\node\Entity\Node::create() if the entity type is known. If the entity type is variable, use the entity storage\'s create() method to construct a new entity:',
// 0.5.5
// No new rules
// 0.5.6
'Call to deprecated constant DATETIME_STORAGE_TIMEZONE: Deprecated in drupal:8.5.0 and is removed from drupal:9.0.0. Use Drupal\datetime\Plugin\Field\FieldType\DateTimeItemInterface::STORAGE_TIMEZONE instead.',
'Call to deprecated constant DATETIME_DATETIME_STORAGE_FORMAT: Deprecated in drupal:8.5.0 and is removed from drupal:9.0.0. Use Drupal\datetime\Plugin\Field\FieldType\DateTimeItemInterface::DATETIME_STORAGE_FORMAT instead.',
'Call to deprecated constant DATETIME_DATE_STORAGE_FORMAT: Deprecated in drupal:8.5.0 and is removed from drupal:9.0.0. Use Drupal\datetime\Plugin\Field\FieldType\DateTimeItemInterface::DATE_STORAGE_FORMAT instead.',
// 0.10.0
'Call to deprecated method getLowercaseLabel() of class Drupal\Core\Entity\EntityTypeInterface. Deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Instead, you should call getSingularLabel(). See https://www.drupal.org/node/3075567',
'Call to deprecated function entity_delete_multiple(). Deprecated in drupal:8.0.0 and is removed from drupal:9.0.0. Use the entity storage\'s \Drupal\Core\Entity\EntityStorageInterface::delete() method to delete multiple entities:',
'Call to deprecated function entity_view(). Deprecated in drupal:8.0.0 and is removed from drupal:9.0.0. Use the entity view builder\'s view() method for creating a render array:',
// 0.11.0
// No new rules
// 0.11.1
'Call to deprecated method drupalPostForm() of class Drupal\Tests\BrowserTestBase. Deprecated in drupal:9.1.0 and is removed from drupal:10.0.0. Use $this->submitForm() instead.',
// 0.11.2
'Call to deprecated method assertText() of class Drupal\Tests\BrowserTestBase. Deprecated in drupal:8.2.0 and is removed from drupal:10.0.0. Use - $this->assertSession()->responseContains() for non-HTML responses, like XML or Json. - $this->assertSession()->pageTextContains() for HTML responses. Unlike the deprecated assertText(), the passed text should be HTML decoded, exactly as a human sees it in the browser.',
'Call to deprecated method assertEqual() of class Drupal\Tests\BrowserTestBase. Deprecated in drupal:8.0.0 and is removed from drupal:10.0.0. Use $this->assertEquals() instead.',
'Call to deprecated method assertEqual() of class Drupal\KernelTests\KernelTestBase. Deprecated in drupal:8.0.0 and is removed from drupal:10.0.0. Use $this->assertEquals() instead.',
'Call to deprecated method assertIdentical() of class Drupal\Tests\BrowserTestBase. Deprecated in drupal:8.0.0 and is removed from drupal:10.0.0. Use $this->assertSame() instead.',
'Call to deprecated method assertIdentical() of class Drupal\KernelTests\KernelTestBase. Deprecated in drupal:8.0.0 and is removed from drupal:10.0.0. Use $this->assertSame() instead.',
'Call to deprecated method assertResponse() of class Drupal\Tests\BrowserTestBase. Deprecated in drupal:8.2.0 and is removed from drupal:10.0.0. Use $this->assertSession()->statusCodeEquals() instead.',
'Call to deprecated method assertRaw() of class Drupal\Tests\BrowserTestBase. Deprecated in drupal:8.2.0 and is removed from drupal:10.0.0. Use $this->assertSession()->responseContains() instead.',
'Call to deprecated method assertFieldByName() of class Drupal\Tests\BrowserTestBase. Deprecated in drupal:8.2.0 and is removed from drupal:10.0.0. Use $this->assertSession()->fieldExists() or $this->assertSession()->buttonExists() or $this->assertSession()->fieldValueEquals() instead.',
'Call to deprecated method buildXPathQuery() of class Drupal\Tests\BrowserTestBase. Deprecated in drupal:8.2.0 and is removed from drupal:10.0.0. Use $this->assertSession()->buildXPathQuery() instead.',
'Call to deprecated method assertHeader() of class Drupal\Tests\BrowserTestBase. Deprecated in drupal:8.3.0 and is removed from drupal:10.0.0. Use $this->assertSession()->responseHeaderEquals() instead.',
'Call to deprecated method assertNoCacheTag() of class Drupal\Tests\BrowserTestBase. Deprecated in drupal:8.4.0 and is removed from drupal:10.0.0. Use $this->assertSession()->responseHeaderNotContains() instead.',
'Call to deprecated method assertCacheTag() of class Drupal\Tests\BrowserTestBase. Deprecated in drupal:8.2.0 and is removed from drupal:10.0.0. Use $this->assertSession()->responseHeaderContains() instead.',
'Call to deprecated method assertNoPattern() of class Drupal\Tests\BrowserTestBase. Deprecated in drupal:8.4.0 and is removed from drupal:10.0.0. Use $this->assertSession()->responseNotMatches() instead.',
'Call to deprecated method assertPattern() of class Drupal\Tests\BrowserTestBase. Deprecated in drupal:8.2.0 and is removed from drupal:10.0.0. Use $this->assertSession()->responseMatches() instead.',
'Call to deprecated method assertEscaped() of class Drupal\Tests\BrowserTestBase. Deprecated in drupal:8.2.0 and is removed from drupal:10.0.0. Use $this->assertSession()->assertEscaped() instead.',
'Call to deprecated method assertNoEscaped() of class Drupal\Tests\BrowserTestBase. Deprecated in drupal:8.2.0 and is removed from drupal:10.0.0. Use $this->assertSession()->assertNoEscaped() instead.',
'Call to deprecated method assertNotEqual() of class Drupal\Tests\BrowserTestBase. Deprecated in drupal:8.0.0 and is removed from drupal:10.0.0. Use $this->assertNotEquals() instead.',
'Call to deprecated method assertNotEqual() of class Drupal\KernelTests\KernelTestBase. Deprecated in drupal:8.0.0 and is removed from drupal:10.0.0. Use $this->assertNotEquals() instead.',
'Call to deprecated method assertNotIdentical() of class Drupal\Tests\BrowserTestBase. Deprecated in drupal:8.0.0 and is removed from drupal:10.0.0. Use $this->assertNotSame() instead.',
'Call to deprecated method assertNotIdentical() of class Drupal\KernelTests\KernelTestBase. Deprecated in drupal:8.0.0 and is removed from drupal:10.0.0. Use $this->assertNotSame() instead.',
'Call to deprecated method assertIdenticalObject() of class Drupal\Tests\BrowserTestBase. Deprecated in drupal:8.0.0 and is removed from drupal:10.0.0. Use $this->assertEquals() instead.',
'Call to deprecated method assertIdenticalObject() of class Drupal\KernelTests\KernelTestBase. Deprecated in drupal:8.0.0 and is removed from drupal:10.0.0. Use $this->assertEquals() instead.',
'Call to deprecated method assert() of class Drupal\Tests\BrowserTestBase. Deprecated in drupal:8.0.0 and is removed from drupal:10.0.0. Use $this->assertTrue() instead.',
'Call to deprecated method assert() of class Drupal\KernelTests\KernelTestBase. Deprecated in drupal:8.0.0 and is removed from drupal:10.0.0. Use $this->assertTrue() instead.',
'Call to deprecated method assertElementNotPresent() of class Drupal\Tests\BrowserTestBase. Deprecated in drupal:8.2.0 and is removed from drupal:10.0.0. Use $this->assertSession()->elementNotExists() instead.',
'Call to deprecated method assertElementPresent() of class Drupal\Tests\BrowserTestBase. Deprecated in drupal:8.2.0 and is removed from drupal:10.0.0. Use $this->assertSession()->elementExists() instead.',
'Call to deprecated method assertNoText() of class Drupal\Tests\BrowserTestBase. Deprecated in drupal:8.2.0 and is removed from drupal:10.0.0. Use - $this->assertSession()->responseNotContains() for non-HTML responses, like XML or Json. - $this->assertSession()->pageTextNotContains() for HTML responses. Unlike the deprecated assertNoText(), the passed text should be HTML decoded, exactly as a human sees it in the browser.',
'Call to deprecated method assertNoRaw() of class Drupal\Tests\BrowserTestBase. Deprecated in drupal:8.2.0 and is removed from drupal:10.0.0. Use $this->assertSession()->responseNotContains() instead.',
'Call to deprecated method assertTitle() of class Drupal\Tests\BrowserTestBase. Deprecated in drupal:8.2.0 and is removed from drupal:10.0.0. Use $this->assertSession()->titleEquals() instead.',
'Call to deprecated method assertNoLink() of class Drupal\Tests\BrowserTestBase. Deprecated in drupal:8.2.0 and is removed from drupal:10.0.0. Use $this->assertSession()->linkNotExists() instead.',
'Call to deprecated method assertLink() of class Drupal\Tests\BrowserTestBase. Deprecated in drupal:8.2.0 and is removed from drupal:10.0.0. Use $this->assertSession()->linkExists() instead.',
'Call to deprecated method assertLinkByHref() of class Drupal\Tests\BrowserTestBase. Deprecated in drupal:8.2.0 and is removed from drupal:10.0.0. Use $this->assertSession()->linkByHrefExists() instead.',
'Call to deprecated method assertNoLinkByHref() of class Drupal\Tests\BrowserTestBase. Deprecated in drupal:8.2.0 and is removed from drupal:10.0.0. Use $this->assertSession()->linkByHrefNotExists() instead.',
// 0.11.3
'Call to deprecated method pass() of class Drupal\Tests\BrowserTestBase. Deprecated in drupal:8.0.0 and is removed from drupal:10.0.0. PHPUnit interrupts a test as soon as a test assertion fails, so there is usually no need to call this method. If a test\'s logic relies on this method, refactor the test.',
'Call to deprecated method pass() of class Drupal\KernelTests\KernelTestBase. Deprecated in drupal:8.0.0 and is removed from drupal:10.0.0. PHPUnit interrupts a test as soon as a test assertion fails, so there is usually no need to call this method. If a test\'s logic relies on this method, refactor the test.',
'Call to deprecated method assertNoUniqueText() of class Drupal\Tests\BrowserTestBase. Deprecated in drupal:8.2.0 and is removed from drupal:10.0.0. Instead, use $this->getSession()->pageTextMatchesCount() if you know the cardinality in advance, or $this->getSession()->getPage()->getText() and substr_count().',
'Call to deprecated method assertUniqueText() of class Drupal\Tests\BrowserTestBase. Deprecated in drupal:8.2.0 and is removed from drupal:10.0.0. Use $this->getSession()->pageTextContainsOnce() or $this->getSession()->pageTextMatchesCount() instead.',
'Call to deprecated method assertNoFieldByName() of class Drupal\Tests\BrowserTestBase. Deprecated in drupal:8.2.0 and is removed from drupal:10.0.0. Use $this->assertSession()->fieldNotExists() or $this->assertSession()->buttonNotExists() or $this->assertSession()->fieldValueNotEquals() instead.',
'Call to deprecated method assertFieldChecked() of class Drupal\Tests\BrowserTestBase. Deprecated in drupal:8.2.0 and is removed from drupal:10.0.0. Use $this->assertSession()->checkboxChecked() instead.',
'Call to deprecated method assertNoFieldChecked() of class Drupal\Tests\BrowserTestBase. Deprecated in drupal:8.2.0 and is removed from drupal:10.0.0. Use $this->assertSession()->checkboxNotChecked() instead.',
'Call to deprecated method assertNoOption() of class Drupal\Tests\BrowserTestBase. Deprecated in drupal:8.2.0 and is removed from drupal:10.0.0. Use $this->assertSession()->optionNotExists() instead.',
'Call to deprecated method assertOptionByText() of class Drupal\Tests\BrowserTestBase. Deprecated in drupal:8.4.0 and is removed from drupal:10.0.0. Use $this->assertSession()->optionExists() instead.',
'Call to deprecated method assertOption() of class Drupal\Tests\BrowserTestBase. Deprecated in drupal:8.2.0 and is removed from drupal:10.0.0. Use $this->assertSession()->optionExists() instead.',
'Call to deprecated method assertUrl() of class Drupal\Tests\BrowserTestBase. Deprecated in drupal:8.2.0 and is removed from drupal:10.0.0. Use $this->assertSession()->addressEquals() instead.',
'Call to deprecated method constructFieldXpath() of class Drupal\Tests\BrowserTestBase. Deprecated in drupal:8.5.0 and is removed from drupal:10.0.0. Use $this->getSession()->getPage()->findField() instead.',
// getAllOptions: rule exists but no instance in contrib.
'Call to deprecated method getRawContent() of class Drupal\Tests\BrowserTestBase. Deprecated in drupal:8.2.0 and is removed from drupal:10.0.0. Use $this->getSession()->getPage()->getContent() instead.',
'Call to deprecated method assertFieldById() of class Drupal\Tests\BrowserTestBase. Deprecated in drupal:8.2.0 and is removed from drupal:10.0.0. Use $this->assertSession()->fieldExists() or $this->assertSession()->buttonExists() or $this->assertSession()->fieldValueEquals() instead.',
'Call to deprecated method assertField() of class Drupal\Tests\BrowserTestBase. Deprecated in drupal:8.2.0 and is removed from drupal:10.0.0. Use $this->assertSession()->fieldExists() or $this->assertSession()->buttonExists() instead.',
'Call to deprecated method assertNoFieldById() of class Drupal\Tests\BrowserTestBase. Deprecated in drupal:8.2.0 and is removed from drupal:10.0.0. Use $this->assertSession()->fieldNotExists() or $this->assertSession()->buttonNotExists() or $this->assertSession()->fieldValueNotEquals() instead.',
'Call to deprecated method assertNoField() of class Drupal\Tests\BrowserTestBase. Deprecated in drupal:8.2.0 and is removed from drupal:10.0.0. Use $this->assertSession()->fieldNotExists() or $this->assertSession()->buttonNotExists() instead.',
'Call to deprecated method assertOptionSelected() of class Drupal\Tests\BrowserTestBase. Deprecated in drupal:8.2.0 and is removed from drupal:10.0.0. Use $this->assertSession()->optionExists() instead and check the "selected" attribute yourself.',
// 0.12.1
'Call to deprecated function drupal_get_path(). Deprecated in drupal:9.3.0 and is removed from drupal:10.0.0. Use Drupal\Core\Extension\ExtensionPathResolver::getPath() instead.',
'Call to deprecated function file_create_url(). Deprecated in drupal:9.3.0 and is removed from drupal:10.0.0. Use the appropriate method on \Drupal\Core\File\FileUrlGeneratorInterface instead.',
'Call to deprecated function file_url_transform_relative(). Deprecated in drupal:9.3.0 and is removed from drupal:10.0.0. Use Drupal\Core\File\FileUrlGenerator::transformRelative() instead.',
'Call to deprecated function render(). Deprecated in drupal:9.3.0 and is removed from drupal:10.0.0. Use Drupal\Core\Render\RendererInterface::render() instead.',
// MetadataBag::clearCsrfTokenSeed()
'Call to deprecated function drupal_get_filename(). Deprecated in drupal:9.3.0 and is removed from drupal:10.0.0. Use Drupal\Core\Extension\ExtensionPathResolver::getPathname() instead.',
'Call to deprecated function file_copy(). Deprecated in drupal:9.3.0 and is removed from drupal:10.0.0. Use Drupal\file\FileRepositoryInterface::copy() instead.',
'Call to deprecated function file_move(). Deprecated in drupal:9.3.0 and is removed from drupal:10.0.0. Use Drupal\file\FileRepositoryInterface::move() instead.',
'Call to deprecated function file_save_data(). Deprecated in drupal:9.3.0 and is removed from drupal:10.0.0. Use Drupal\file\FileRepositoryInterface::writeData() instead.',
// 0.12.2
// No new rules
// 0.12.3
'Call to deprecated function user_password(). Deprecated in drupal:9.1.0 and is removed from drupal:10.0.0. Use Drupal\Core\Password\PasswordGeneratorInterface::generate() instead.',
// 0.12.4
'Call to deprecated function file_build_uri(). Deprecated in drupal:9.3.0 and is removed from drupal:10.0.0 without replacement.',
// 0.13.0
// No new rules
// 0.13.1
// Covers https://www.drupal.org/node/2909426 ($modules property in tests), but not identified in contrib by phpstan.
// 0.15.0
// No new rules
// 0.15.1
// No new rules
// 0.18.0
// Add TwigSetList::TWIG_240 to D9 deprecations (https://github.com/palantirnet/drupal-rector/pull/223) -- not tracking non-Drupal coverage here
// system_sort_modules_by_info_name: (https://www.drupal.org/node/3225999) -- not found in contrib
'Call to deprecated function module_load_install(). Deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. Use Drupal::moduleHandler()->loadInclude($module, \'install\') instead. Note, the replacement no longer allows including code from uninstalled modules.',
'Call to deprecated function watchdog_exception(). Deprecated in drupal:10.1.0 and is removed from drupal:11.0.0. Use Use Drupal\Core\Utility\Error::logException() instead.',
'Call to deprecated function taxonomy_vocabulary_get_names(). Deprecated in drupal:9.3.0 and is removed from drupal:10.0.0. Use Drupal::entityQuery(\'taxonomy_vocabulary\')->execute() instead.',
// taxonomy_term_uri
'Call to deprecated function taxonomy_term_load_multiple_by_name(). Deprecated in drupal:9.3.0 and is removed from drupal:10.0.0. Use Drupal::entityTypeManager()->getStorage(\'taxonomy_term\')->loadByProperties([\'name\' => $name, \'vid\' => $vid]) instead, to get a list of taxonomy term entities having the same name and keyed by their term ID.',
// taxonomy_terms_static_reset -- not found in contrib
// taxonomy_vocabulary_static_reset -- not found in contrib
'Call to deprecated function taxonomy_implode_tags(). Deprecated in drupal:9.3.0 and is removed from drupal:10.0.0. Use Drupal\Core\Entity\Element\EntityAutocomplete::getEntityLabels() instead.',
// taxonomy_term_title -- not found in contrib
// Drupal 9 rector now includes PHPUnit rector (PHPUnitLevelSetList::UP_TO_PHPUNIT_90)
// 0.18.1
'Drupal\Tests\BrowserTestBase::$defaultTheme is required in drupal:9.0.0 when using an install profile that does not set a default theme. See https://www.drupal.org/node/3083055, which includes recommendations on which theme to use.',
// 0.18.2
'Call to deprecated function system_time_zones(). Deprecated in drupal:10.1.0 and is removed from drupal:11.0.0. This function is no longer used in Drupal core. Use Drupal\Core\Datetime\TimeZoneFormHelper::getOptionsList() or \DateTimeZone::listIdentifiers() instead.',
// 0.18.3
'Missing call to parent::setUp() method.',
'Missing call to parent::tearDown() method.',
// 0.18.4
'Call to deprecated function module_load_include(). Deprecated in drupal:9.4.0 and is removed from drupal:11.0.0. Use Drupal::moduleHandler()->loadInclude($module, $type, $name = NULL). Note that including code from uninstalled extensions is no longer supported.',
'Call to deprecated function module_load_install(). Deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. Use Drupal::moduleHandler()->loadInclude($module, \'install\') instead. Note, the replacement no longer allows including code from uninstalled modules.',
// 0.18.5
'Call to deprecated constant FILE_STATUS_PERMANENT: Deprecated in drupal:9.3.0 and is removed from drupal:10.0.0. Use Drupal\file\FileInterface::STATUS_PERMANENT or \Drupal\file\FileInterface::setPermanent().',
'Call to deprecated method toInt() of class Drupal\Component\Utility\Bytes. Deprecated in drupal:9.1.0 and is removed from drupal:10.0.0. Use Drupal\Component\Utility\Bytes::toNumber() instead.',
// 0.18.6
// no new rules
// 0.19.0
'Call to deprecated function format_size(). Deprecated in drupal:10.2.0 and is removed from drupal:11.0.0. Use Drupal\Core\StringTranslation\ByteSizeMarkup::create($size, $langcode) instead.',
// 0.19.1
// no new rules
// 0.19.2
// no new rules
// 0.20.0
'Call to deprecated method getResource() of class Drupal\system\Plugin\ImageToolkit\GDToolkit. Deprecated in drupal:10.2.0 and is removed from drupal:11.0.0. Use Drupal\system\Plugin\ImageToolkit\GDToolkit::getImage() instead.',
'Call to deprecated method setResource() of class Drupal\system\Plugin\ImageToolkit\GDToolkit. Deprecated in drupal:10.2.0 and is removed from drupal:11.0.0. Use Drupal\system\Plugin\ImageToolkit\GDToolkit::setImage() instead.',
// Symfony level was added, adding support for multiple non-drupal deprecations
'Fetching deprecated class constant MASTER_REQUEST of interface Symfony\Component\HttpKernel\HttpKernelInterface: since symfony/http-kernel 5.3, use MAIN_REQUEST instead. To ease the migration, this constant won\'t be removed until Symfony 7.0.',
'Call to deprecated method getContentType() of class Symfony\Component\HttpFoundation\Request: since Symfony 6.2, use getContentTypeFormat() instead',
'Call to deprecated method enableAnnotationMapping() of class Symfony\Component\Validator\ValidatorBuilder: since Symfony 6.4, use "enableAttributeMapping()" instead.',
'Call to deprecated method attachPart() of class Symfony\Component\Mime\Email: since Symfony 6.2, use addPart() instead',
'Class [redacted] implements deprecated interface Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface: since Symfony 6.2, implement ValueResolverInterface instead',
// 0.20.1
'Symfony\Cmf\Component\Routing\RouteObjectInterface::ROUTE_OBJECT is deprecated and removed in Drupal 10. Use Drupal\Core\Routing\RouteObjectInterface::ROUTE_OBJECT instead.',
'Symfony\Cmf\Component\Routing\RouteObjectInterface::ROUTE_NAME is deprecated and removed in Drupal 10. Use Drupal\Core\Routing\RouteObjectInterface::ROUTE_NAME instead.',
'Symfony\Cmf\Component\Routing\RouteObjectInterface::CONTROLLER_NAME is deprecated and removed in Drupal 10. Use Drupal\Core\Routing\RouteObjectInterface::CONTROLLER_NAME instead.',
// 0.20.2
'Call to deprecated function _drupal_flush_css_js(). Deprecated in drupal:10.2.0 and is removed from drupal:11.0.0. Use Use Drupal\Core\Asset\AssetQueryStringInterface::reset() instead.',
'drupal_theme_rebuild() is deprecated in drupal:10.1.0 and is removed from drupal:11.0.0. Use theme.registry service reset() method instead. See https://www.drupal.org/node/3348853',
// 0.20.3
'Call to deprecated function file_icon_class(). Deprecated in drupal:10.3.0 and is removed from drupal:11.0.0. Use Drupal\file\IconMimeTypes::getIconClass() instead.',
'Call to deprecated method setMethods() of class PHPUnit\Framework\MockObject\MockBuilder: https://github.com/sebastianbergmann/phpunit/pull/3687',
];
return
in_array($string, $rector_covered) ||
strpos($string, 'Call to deprecated method l() of class Drupal') === 0;
}
}
<?php
declare(strict_types=1);
namespace Drupal\upgrade_status;
/**
* A value object containing a deprecation message with some metadata.
*/
class DeprecationMessage {
/**
* The message.
*
* @var string
*/
protected $message;
/**
* The line associated to the deprecation message.
*
* @var int
*/
protected $line;
/**
* The file related to the deprecation message.
*
* @var string
*/
protected $file;
/**
* The analyzer providing the message.
*
* @var string
*/
protected string $analyzer;
/**
* Constructs a new deprecation message.
*
* @param string $message
* The message.
* @param string $file
* The file related to the deprecation message.
* @param int $line
* The line associated to the deprecation message.
*/
public function __construct(string $message, string $file = '', int $line = 0, string $analyzer = '') {
$this->message = $message;
$this->file = $file;
$this->line = $line;
$this->analyzer = $analyzer;
}
/**
* Gets the message.
*
* @return string
*/
public function getMessage(): string {
return $this->message;
}
/**
* Gets the file.
*
* @return string
*/
public function getFile(): string {
return $this->file;
}
/**
* Gets the line.
*
* @return int
*/
public function getLine(): int {
return $this->line;
}
/**
* Sets the line value.
*
* @param int $line
* The line associated to the deprecation message.
*/
public function setLine(int $line) {
$this->line = $line;
}
/**
* Sets the file value.
*
* @param string $file
* The file related to the deprecation message.
*/
public function setFile(string $file) {
$this->file = $file;
}
/**
* Get analyzer providing the message.
*
* @return string
*/
public function getAnalyzer(): string {
return $this->analyzer;
}
}
<?php
namespace Drupal\upgrade_status\Drush\Commands;
use Consolidation\AnnotatedCommand\CommandResult;
use Drupal\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Datetime\DateFormatterInterface;
use Drupal\Core\Extension\Extension;
use Drupal\upgrade_status\DeprecationAnalyzer;
use Drupal\upgrade_status\ProjectCollector;
use Drupal\upgrade_status\ScanResultFormatter;
use Drush\Commands\DrushCommands;
use Drush\Drupal\DrupalUtil;
use Drush\Exceptions\CommandFailedException;
/**
* Upgrade Status Drush command
*/
class UpgradeStatusCommands extends DrushCommands {
/**
* The scan result formatter service.
*
* @var \Drupal\upgrade_status\ScanResultFormatter
*/
protected $resultFormatter;
/**
* The project collector service.
*
* @var \Drupal\upgrade_status\ProjectCollector
*/
protected $projectCollector;
/**
* The codebase analyzer service.
*
* @var \Drupal\upgrade_status\DeprecationAnalyzer
*/
protected $deprecationAnalyzer;
/**
* The date formatter service.
*
* @var \Drupal\Core\Datetime\DateFormatterInterface
*/
protected $dateFormatter;
/**
* Constructs a new UpgradeStatusCommands object.
*
* @param \Drupal\upgrade_status\ScanResultFormatter $result_formatter
* The scan result formatter service.
* @param \Drupal\upgrade_status\ProjectCollector $project_collector
* The project collector service.
* @param \Drupal\upgrade_status\DeprecationAnalyzer $deprecation_analyzer
* The codebase analyzer service.
* @param \Drupal\Core\Datetime\DateFormatterInterface $date_formatter
* The date formatter service.
*/
public function __construct(
ScanResultFormatter $result_formatter,
ProjectCollector $project_collector,
DeprecationAnalyzer $deprecation_analyzer,
DateFormatterInterface $date_formatter) {
$this->projectCollector = $project_collector;
$this->resultFormatter = $result_formatter;
$this->deprecationAnalyzer = $deprecation_analyzer;
$this->dateFormatter = $date_formatter;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container): self {
return new static(
$container->get('upgrade_status.result_formatter'),
$container->get('upgrade_status.project_collector'),
$container->get('upgrade_status.deprecation_analyzer'),
$container->get('date.formatter')
);
}
/**
* Analyze projects and output results in selected format.
*
* @param array $projects
* List of projects to analyze.
* @param array $options
* Additional options for the command.
* @return \Consolidation\AnnotatedCommand\CommandResult;
* Exit code of self::EXIT_SUCCESS if no errors found,
* self::EXIT_FAILURE_WITH_CLARITY if at least one error found.
*
* @command upgrade_status:analyze
* @option all Analyze all projects.
* @option skip-existing Return results from a previous scan of a project if available, otherwise start a new one.
* @option ignore-uninstalled Ignore uninstalled projects.
* @option ignore-contrib Ignore contributed projects.
* @option ignore-custom Ignore custom projects.
* @option ignore-list Ignore a list of comma-separated projects.
* @option phpstan-memory-limit Set memory limit for PHPStan.
* @option format Set the format: plain, checkstyle or codeclimate.
* @aliases us-a
*
* @throws \InvalidArgumentException
* Thrown when one of the passed arguments is invalid or no arguments were provided.
*/
public function analyze(array $projects, array $options = ['all' => FALSE, 'skip-existing' => FALSE, 'ignore-uninstalled' => FALSE, 'ignore-contrib' => FALSE, 'ignore-custom' => FALSE, 'ignore-list' => '', 'phpstan-memory-limit' => '1500M', 'format' => 'plain']) {
$extensions = $this->doAnalyze($projects, $options);
$found_issue = FALSE;
switch ($options['format']) {
case 'checkstyle':
$found_issue = $this->formatAllAsCheckStyle($extensions);
break;
case 'codeclimate':
$found_issue = $this->formatAllAsCodeClimate($extensions);
break;
default:
$found_issue = $this->formatAllAsPlain($extensions);
}
return CommandResult::exitCode($found_issue ? self::EXIT_FAILURE_WITH_CLARITY : self::EXIT_SUCCESS);
}
/**
* Analyze projects and output results in checkstyle XML.
*
* @param array $projects
* List of projects to analyze.
* @param array $options
* Additional options for the command.
*
* @command upgrade_status:checkstyle
* @option all Analyze all projects.
* @option skip-existing Return results from a previous scan of a project if available, otherwise start a new one.
* @option ignore-uninstalled Ignore uninstalled projects.
* @option ignore-contrib Ignore contributed projects.
* @option ignore-custom Ignore custom projects.
* @option ignore-list Ignore a list of comma-separated projects.
* @option phpstan-memory-limit Set memory limit for PHPStan.
* @aliases us-cs
*
* @throws \InvalidArgumentException
* Thrown when one of the passed arguments is invalid or no arguments were provided.
*/
public function checkstyle(array $projects, array $options = ['all' => FALSE, 'skip-existing' => FALSE, 'ignore-uninstalled' => FALSE, 'ignore-contrib' => FALSE, 'ignore-custom' => FALSE, 'ignore-list' => '', 'phpstan-memory-limit' => '1500M']) {
$this->logger()->notice('The checkstyle (us-cs) drush command is deprecated and will be removed. Use the analyze command with --format=checkstyle instead.');
$options['format'] = 'checkstyle';
return $this->analyze($projects, $options);
}
/**
* Formats command output as checkstyle XML.
*
* @param array $extensions
* Result data by extension.
* @return bool
* Whether issues were found.
*/
protected function formatAllAsCheckStyle(array $extensions) {
$xml = new \SimpleXMLElement("<?xml version='1.0'?><checkstyle/>");
$found_issue = FALSE;
foreach ($extensions as $list) {
foreach ($list as $name => $extension) {
$result = $this->resultFormatter->getRawResult($extension);
if (is_null($result)) {
$found_issue = TRUE;
$this->logger()->error('Project scan @name failed.', ['@name' => $name]);
continue;
}
foreach ($result['data']['files'] as $filepath => $errors) {
$found_issue = TRUE;
$short_path = str_replace(DRUPAL_ROOT . '/', '', $filepath);
$file_xml = $xml->addChild('file');
$file_xml->addAttribute('name', $short_path);
foreach ($errors['messages'] as $error) {
$severity = 'error';
if ($error['upgrade_status_category'] == 'ignore') {
$severity = 'info';
}
elseif ($error['upgrade_status_category'] == 'later') {
$severity = 'warning';
}
$error_xml = $file_xml->addChild('error');
$error_xml->addAttribute('line', $error['line']);
$error_xml->addAttribute('message', $error['message']);
$error_xml->addAttribute('severity', $severity);
}
}
}
}
$this->output()->writeln($xml->asXML());
return $found_issue;
}
/**
* Formats command output as plain text tables.
*
* @param array $extensions
* Result data by extension.
* @return bool
* Whether issues were found.
*/
protected function formatAllAsPlain(array $extensions) {
$found_issue = FALSE;
foreach ($extensions as $list) {
$this->output()->writeln('');
$this->output()->writeln(str_pad('', 80, '='));
foreach ($list as $name => $extension) {
$result = $this->resultFormatter->getRawResult($extension);
if (is_null($result)) {
$found_issue = TRUE;
$this->logger()->error('Project scan @name failed.', ['@name' => $name]);
continue;
}
$output = $this->formatExtensionAsPlain($extension, $result);
foreach ($output['table'] as $line) {
$this->output()->writeln($line);
}
// If we did not find an extension with an issue earlier, use the result
// from this extension.
if (!$found_issue) {
$found_issue = $output['found_issue'];
}
}
}
return $found_issue;
}
/**
* Analyzes projects and returns results for processed extensions.
*
* @param array $projects
* List of projects to analyze.
* @param array $options
* Additional options for the command.
*
* @throws \InvalidArgumentException
* Thrown when one of the passed arguments is invalid or no arguments were provided.
* @throws Drush\Exceptions\CommandFailedException
* Thrown when the environment is not ready to run the analysis.
*/
protected function doAnalyze(array $projects, array $options = ['all' => FALSE, 'skip-existing' => FALSE, 'ignore-uninstalled' => FALSE, 'ignore-contrib' => FALSE, 'ignore-custom' => FALSE, 'ignore-list' => '', 'phpstan-memory-limit' => '1500M']) {
try {
$this->deprecationAnalyzer->initEnvironment();
}
catch (\Exception $e) {
throw new CommandFailedException($e->getMessage() . ' ' . dt('Analysis is not possible until this is resolved.'));
}
$extensions = [];
$invalid_names = [];
if (empty($projects) && !$options['all']) {
$message = dt('You need to provide at least one installed project\'s machine_name.');
throw new \InvalidArgumentException($message);
}
// Gather project list grouped by custom and contrib projects.
$available_projects = $this->projectCollector->collectProjects();
if ($options['all']) {
$projects_to_ignore = explode(',', $options['ignore-list']);
foreach ($available_projects as $name => $project) {
if ($options['ignore-uninstalled'] && $project->status === 0) {
continue;
}
if ($options['ignore-contrib'] && $project->info['upgrade_status_type'] == ProjectCollector::TYPE_CONTRIB) {
continue;
}
if ($options['ignore-custom'] && $project->info['upgrade_status_type'] == ProjectCollector::TYPE_CUSTOM) {
continue;
}
if (in_array($name, $projects_to_ignore)) {
continue;
}
$extensions[$project->getType()][$name] = $project;
}
}
else {
foreach ($projects as $name) {
if (!isset($available_projects[$name])) {
$invalid_names[] = $name;
continue;
}
if ($options['ignore-uninstalled'] && $available_projects[$name]->status === 0) {
$invalid_names[] = $name;
continue;
}
if ($options['ignore-contrib'] && $available_projects[$name]->info['upgrade_status_type'] == ProjectCollector::TYPE_CONTRIB) {
$invalid_names[] = $name;
continue;
}
if ($options['ignore-custom'] && $available_projects[$name]->info['upgrade_status_type'] == ProjectCollector::TYPE_CUSTOM) {
$invalid_names[] = $name;
continue;
}
$extensions[$available_projects[$name]->getType()][$name] = $available_projects[$name];
}
}
if (!empty($invalid_names)) {
if (count($invalid_names) == 1) {
$message = dt('The project machine name @invalid_name is invalid. Is this a project on this site? (For community projects, use the machine name of the drupal.org project itself).', [
'@invalid_name' => $invalid_names[0],
]);
}
else {
$message = dt('The project machine names @invalid_names are invalid. Are these projects on this site? (For community projects, use the machine name of the drupal.org project itself).', [
'@invalid_names' => implode(', ', $invalid_names),
]);
}
throw new \InvalidArgumentException($message);
}
else {
$this->logger()->info(dt('Starting the analysis. This may take a while.'));
}
foreach ($extensions as $list) {
foreach ($list as $name => $extension) {
if ($options['skip-existing']) {
$scan_result = \Drupal::service('keyvalue')->get('upgrade_status_scan_results')->get($name);
if (!empty($scan_result)) {
$this->logger()->info(dt('Using previous results for @name.', ['@name' => $name]));
continue;
}
}
$this->logger()->info(dt('Processing @name.', ['@name' => $name]));
$this->deprecationAnalyzer->analyze($extension, $options);
}
}
return $extensions;
}
/**
* Format results output for an extension for Drush STDOUT usage.
*
* @param \Drupal\Core\Extension\Extension $extension
* Drupal extension objet.
* @param array $result
* Deprecation checking results.
*
* @return array
* Associative array with the 'table' key containing the ASCII
* output, and 'found_issue' key indicating whether issues were
* identified.
*/
protected function formatExtensionAsPlain(Extension $extension, array $result) {
$table = [];
$info = $extension->info;
$table[] = $info['name'] . ', ' . (!empty($info['version']) ? ' ' . $info['version'] : '--');
$table[] = dt('Scanned on @date', [
'@date' => $this->dateFormatter->format($result['date']),
]);
if (isset($result['data']['totals'])) {
$project_error_count = $result['data']['totals']['file_errors'];
}
else {
$project_error_count = 0;
}
if (!$project_error_count || !is_array($result['data']['files'])) {
$table[] = '';
$table[] = dt('No known issues found.');
$table[] = '';
return ['table' => $table, 'found_issue' => FALSE];
}
foreach ($result['data']['files'] as $filepath => $errors) {
// Remove the Drupal root directory name. If this is a composer setup,
// then the webroot is in a web/ directory, add that back in for easy
// path copy-pasting.
$short_path = str_replace(DRUPAL_ROOT . '/', '', $filepath);
if (preg_match('!/web$!', DRUPAL_ROOT)) {
$short_path = 'web/' . $short_path;
}
$short_path = wordwrap(dt('FILE: ') . $short_path, 80, "\n", TRUE);
$table[] = '';
$table[] = $short_path;
$table[] = '';
$title_level = str_pad(dt('STATUS'), 15, ' ');
$title_line = str_pad(dt('LINE'), 5, ' ');
$title_msg = str_pad(dt('MESSAGE'), 60, ' ', STR_PAD_BOTH);
$table[] = $title_level . $title_line . $title_msg;
foreach ($errors['messages'] as $error) {
$table[] = str_pad('', 80, '-');
$error['message'] = str_replace("\n", ' ', $error['message']);
$error['message'] = str_replace(' ', ' ', $error['message']);
$error['message'] = trim($error['message']);
$level_label = dt('Check manually');
if ($error['upgrade_status_category'] == 'ignore') {
$level_label = dt('Ignore');
}
elseif ($error['upgrade_status_category'] == 'later') {
$level_label = dt('Fix later');
}
elseif (in_array($error['upgrade_status_category'], ['safe', 'old'])) {
$level_label = dt('Fix now');
}
$linecount = 0;
$msg_parts = explode("\n", wordwrap($error['message'], 60, "\n", TRUE));
foreach ($msg_parts as $msg_part) {
$msg_part = str_pad($msg_part, 60, ' ');
if (!$linecount++) {
$level_label = str_pad(substr($level_label, 0, 15), '15', ' ');
$line = str_pad($error['line'], 5, ' ');
}
else {
$level_label = str_pad(substr('', 0, 15), '15', ' ');
$line = str_pad('', 5, ' ');
}
$table[] = $level_label . $line . $msg_part;
}
}
$table[] = str_pad('', 80, '-');
}
$table[] = '';
return ['table' => $table, 'found_issue' => TRUE];
}
/**
* Formats command output as Code Climate issues JSON.
*
* @param array $extensions
* Result data by extension.
* @return bool
* Whether issues were found.
*/
protected function formatAllAsCodeClimate(array $extensions): bool {
$found_issue = FALSE;
$report = [];
foreach ($extensions as $list) {
foreach ($list as $name => $extension) {
$result = $this->resultFormatter->getRawResult($extension);
if (is_null($result)) {
$found_issue = TRUE;
$this->logger()->error('Project scan @name failed.', ['@name' => $name]);
continue;
}
foreach ($result['data']['files'] as $filepath => $errors) {
$found_issue = TRUE;
$short_path = str_replace(DRUPAL_ROOT . '/', '', $filepath);
foreach ($errors['messages'] as $error) {
$severity = 'major';
// We downgrade to 'info' severity, if:
// - It has the ignore/later category, as these issues shouldn't be
// fixed now.
// - It is not an error, but something unable to detect.
if (
in_array($error['upgrade_status_category'], ['ignore', 'later'], TRUE) ||
str_contains($error['message'], 'Cannot decide if it is deprecated or not.') ||
str_contains($error['message'], 'Cannot check deprecated library use.')
) {
$severity = 'info';
}
// We downgrade to 'minor' severity, if:
// - The category is 'uncategorized', because we might not need to
// fix it now.
elseif ($error['upgrade_status_category'] == 'uncategorized') {
$severity = 'minor';
}
$description = $name . ' - ' . $error['message'];
$fingerprint = hash(
'sha256',
implode(
[
$filepath,
$error['line'],
$error['message'],
]
));
$report[] = [
'type' => 'issue',
'check_name' => $error['analyzer'],
'categories' => ['Compatibility'],
'description' => $description,
'fingerprint' => $fingerprint,
'severity' => $severity,
'location' => [
'path' => $short_path,
'lines' => [
'begin' => $error['line'] ?: 0,
],
],
];
}
}
}
}
$this->output()->writeln(json_encode($report, JSON_PRETTY_PRINT));
return $found_issue;
}
}
<?php
declare(strict_types=1);
namespace Drupal\upgrade_status;
use Drupal\Component\Serialization\Yaml;
use Drupal\Component\Serialization\Exception\InvalidDataTypeException;
use Drupal\Core\Extension\Extension;
/**
* The info.yml and composer deprecation analyzer.
*/
final class ExtensionMetadataDeprecationAnalyzer {
/**
* Analyzes usages of deprecated extension metadata in an extension.
*
* @param \Drupal\Core\Extension\Extension $extension
* The extension to be analyzed.
*
* @return \Drupal\upgrade_status\DeprecationMessage[]
* A list of deprecation messages.
*
* @throws \Exception
*/
public function analyze(Extension $extension): array {
$deprecations = [];
$project_dir = DRUPAL_ROOT . '/' . $extension->getPath();
$info_files = $this->getSubExtensionInfoFiles($project_dir);
foreach ($info_files as $info_file) {
try {
// Manually add on info file incompatibility to results. Reading
// .info.yml files directly, not from extension discovery because that
// is cached.
$file_contents = file_get_contents($info_file);
$info = Yaml::decode($file_contents) ?: [];
if (!empty($info['package']) && $info['package'] == 'Testing' && !strpos($info_file, '/upgrade_status_test')) {
// If this info file was for a testing project other than our own
// testing projects, ignore it.
continue;
}
$error_path = str_replace(DRUPAL_ROOT . '/', '', $info_file);
// Check for missing base theme key.
if ($info['type'] === 'theme') {
if (!isset($info['base theme'])) {
$deprecations[] = new DeprecationMessage("The now required 'base theme' key is missing. See https://www.drupal.org/node/3066038.", $error_path, 1, 'ExtensionMetadataDeprecationAnalyzer');
}
}
if (!isset($info['core_version_requirement'])) {
$deprecations[] = new DeprecationMessage("Add core_version_requirement to designate which Drupal versions is the extension compatible with. See https://drupal.org/node/3070687.", $error_path, 1, 'ExtensionMetadataDeprecationAnalyzer');
}
elseif (!ProjectCollector::isCompatibleWithNextMajorDrupal($info['core_version_requirement'])) {
$line = $this->findKeyLine('core_version_requirement:', $file_contents);
$deprecations[] = new DeprecationMessage("Value of core_version_requirement: {$info['core_version_requirement']} is not compatible with the next major version of Drupal core. See https://drupal.org/node/3070687.", $error_path, $line, 'ExtensionMetadataDeprecationAnalyzer');
}
// @todo
// Change values to ExtensionLifecycle class constants once at least
// Drupal 9.3 is required.
if (!empty($info['lifecycle'])) {
$line = $this->findKeyLine('lifecycle:', $file_contents);
$link = !empty($info['lifecycle_link']) ? $info['lifecycle_link'] : 'https://www.drupal.org/node/3215042';
if ($info['lifecycle'] == 'deprecated') {
$deprecations[] = new DeprecationMessage("This extension is deprecated. Don't use it. See $link.", $error_path, $line, 'ExtensionMetadataDeprecationAnalyzer');
}
elseif ($info['lifecycle'] == 'obsolete') {
$deprecations[] = new DeprecationMessage("This extension is obsolete. Obsolete extensions are usually uninstalled automatically when not needed anymore. You only need to do something about this if the uninstallation was unsuccessful. See $link.", $error_path, $line, 'ExtensionMetadataDeprecationAnalyzer');
}
}
} catch (InvalidDataTypeException $e) {
$deprecations[] = new DeprecationMessage('Parse error. ' . $e->getMessage(), $error_path, 1, 'ExtensionMetadataDeprecationAnalyzer');
}
// No need to check info files for PHP 8 compatibility information because
// they can only define minimal PHP versions not maximum or excluded PHP
// versions.
}
// Manually add on composer.json file incompatibility to results.
if (file_exists($project_dir . '/composer.json')) {
$error_path = $extension->getPath() . '/composer.json';
$composer_json = json_decode(file_get_contents($project_dir . '/composer.json'));
if (empty($composer_json) || !is_object($composer_json)) {
$deprecations[] = new DeprecationMessage("Parse error in composer.json. Having a composer.json is not a requirement in general, but if there is one, it should be valid. See https://drupal.org/node/2514612.", $error_path, 1, 'ExtensionMetadataDeprecationAnalyzer');
}
elseif (!empty($composer_json->require->{'drupal/core'}) && !projectCollector::isCompatibleWithNextMajorDrupal($composer_json->require->{'drupal/core'})) {
$deprecations[] = new DeprecationMessage("The drupal/core requirement is not compatible with the next major version of Drupal. Either remove it or update it to be compatible. See https://www.drupal.org/docs/develop/using-composer/add-a-composerjson-file#core-compatibility.", $error_path, 1, 'ExtensionMetadataDeprecationAnalyzer');
}
elseif (!empty($composer_json->require->{'php'}) && !projectCollector::isCompatibleWithPHP($composer_json->require->{'php'}, '8.1.0')) {
$deprecations[] = new DeprecationMessage("The PHP requirement is not compatible with PHP 8.1. Once the codebase is actually compatible, either remove this limitation or update it to be compatible.", $error_path, 1, 'ExtensionMetadataDeprecationAnalyzer');
}
}
return $deprecations;
}
/**
* Finds all .info.yml files for extensions under a path.
*
* @param string $path
* Base path to find all info.yml files in.
*
* @return array
* A list of paths to .info.yml files found under the base path.
*/
private function getSubExtensionInfoFiles(string $path) {
$files = [];
foreach(glob($path . '/*.info.yml') as $file) {
// Make sure the filename matches rules for an extension. There may be
// info.yml files in shipped configuration which would have more parts.
$parts = explode('.', basename($file));
if (count($parts) == 3) {
$files[] = $file;
}
}
foreach (glob($path . '/*', GLOB_ONLYDIR|GLOB_NOSORT) as $dir) {
$files = array_merge($files, $this->getSubExtensionInfoFiles($dir));
}
return $files;
}
/**
* Finds the line that contains the substring.
*
* @param string $substring
* The string to find.
* @param string $file_contents
* String contents of a file.
* @return
* Line number if found, 1 otherwise.
*/
private function findKeyLine($substring, $file_contents) {
$lines = explode("\n", $file_contents);
foreach ($lines as $num => $line) {
if (strpos($line, $substring) !== FALSE) {
return $num + 1;
}
}
return 1;
}
}
<?php
namespace Drupal\upgrade_status\Form;
use Drupal\Component\Serialization\Json;
use Drupal\Core\Datetime\DateFormatterInterface;
use Drupal\Core\DrupalKernelInterface;
use Drupal\Core\Extension\Extension;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Database\Connection;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\KeyValueStore\KeyValueExpirableFactoryInterface;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\Routing\RedirectDestinationInterface;
use Drupal\Core\State\StateInterface;
use Drupal\Core\Url;
use Drupal\upgrade_status\CookieJar;
use Drupal\upgrade_status\DeprecationAnalyzer;
use Drupal\upgrade_status\ProjectCollector;
use Drupal\upgrade_status\ScanResultFormatter;
use Drupal\user\Entity\Role;
use GuzzleHttp\Cookie\SetCookie;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Response;
use Psr\Log\LoggerInterface;
class UpgradeStatusForm extends FormBase {
/**
* The project collector service.
*
* @var \Drupal\upgrade_status\ProjectCollector
*/
protected $projectCollector;
/**
* Available releases store.
*
* @var \Drupal\Core\KeyValueStore\KeyValueStoreInterface|mixed
*/
protected $releaseStore;
/**
* The scan result formatter service.
*
* @var \Drupal\upgrade_status\ScanResultFormatter
*/
protected $resultFormatter;
/**
* The renderer service.
*
* @var \Drupal\Core\Render\RendererInterface
*/
protected $renderer;
/**
* The logger service.
*
* @var \Drupal\Core\Logger\LoggerChannelInterface
*/
protected $logger;
/**
* The module handler service.
*
* @var \Drupal\Core\Extension\ModuleHandlerInterface
*/
protected $moduleHandler;
/**
* The deprecation analyzer.
*
* @var \Drupal\upgrade_status\DeprecationAnalyzer
*/
protected $deprecationAnalyzer;
/**
* The state service.
*
* @var \Drupal\Core\State\StateInterface
*/
protected $state;
/**
* The date formatter.
*
* @var \Drupal\Core\Datetime\DateFormatterInterface
*/
protected $dateFormatter;
/**
* The destination service.
*
* @var \Drupal\Core\Routing\RedirectDestinationInterface
*/
protected $destination;
/**
* The next Drupal core major version.
*
* @var int
*/
protected $nextMajor;
/**
* Database connection.
*
* @var \Drupal\Core\Database\Connection
*/
protected $database;
/**
* Drupal kernel.
*
* @var \Drupal\Core\DrupalKernelInterface
*/
protected $kernel;
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('upgrade_status.project_collector'),
$container->get('keyvalue.expirable'),
$container->get('upgrade_status.result_formatter'),
$container->get('renderer'),
$container->get('logger.channel.upgrade_status'),
$container->get('module_handler'),
$container->get('upgrade_status.deprecation_analyzer'),
$container->get('state'),
$container->get('date.formatter'),
$container->get('redirect.destination'),
$container->get('database'),
$container->get('kernel')
);
}
/**
* Constructs a Drupal\upgrade_status\Form\UpgradeStatusForm.
*
* @param \Drupal\upgrade_status\ProjectCollector $project_collector
* The project collector service.
* @param \Drupal\Core\KeyValueStore\KeyValueExpirableFactoryInterface $key_value_expirable
* The expirable key/value storage.
* @param \Drupal\upgrade_status\ScanResultFormatter $result_formatter
* The scan result formatter service.
* @param \Drupal\Core\Render\RendererInterface $renderer
* The renderer service.
* @param \Psr\Log\LoggerInterface $logger
* The logger.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler.
* @param \Drupal\upgrade_status\DeprecationAnalyzer $deprecation_analyzer
* The deprecation analyzer.
* @param \Drupal\Core\State\StateInterface $state
* The state service.
* @param \Drupal\Core\Datetime\DateFormatterInterface $date_formatter
* The date formatter.
* @param \Drupal\Core\Routing\RedirectDestinationInterface $destination
* The destination service.
* @param \Drupal\Core\Database\Connection $connection
* The database connection.
* @param \Drupal\Core\DrupalKernelInterface $kernel
* The Drupal kernel.
*/
public function __construct(
ProjectCollector $project_collector,
KeyValueExpirableFactoryInterface $key_value_expirable,
ScanResultFormatter $result_formatter,
RendererInterface $renderer,
LoggerInterface $logger,
ModuleHandlerInterface $module_handler,
DeprecationAnalyzer $deprecation_analyzer,
StateInterface $state,
DateFormatterInterface $date_formatter,
RedirectDestinationInterface $destination,
Connection $database,
DrupalKernelInterface $kernel
) {
$this->projectCollector = $project_collector;
$this->releaseStore = $key_value_expirable->get('update_available_releases');
$this->resultFormatter = $result_formatter;
$this->renderer = $renderer;
$this->logger = $logger;
$this->moduleHandler = $module_handler;
$this->deprecationAnalyzer = $deprecation_analyzer;
$this->state = $state;
$this->dateFormatter = $date_formatter;
$this->destination = $destination;
$this->nextMajor = ProjectCollector::getDrupalCoreMajorVersion() + 1;
$this->database = $database;
$this->kernel = $kernel;
}
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'drupal_upgrade_status_summary_form';
}
/**
* Form constructor.
*
* @param array $form
* An associative array containing the structure of the form.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The current state of the form.
*
* @return array
* The form structure.
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$form['#attached']['library'][] = 'upgrade_status/upgrade_status.admin';
$analyzer_ready = TRUE;
try {
$this->deprecationAnalyzer->initEnvironment();
}
catch (\Exception $e) {
$analyzer_ready = FALSE;
// Message and impact description is not translated as the message
// is sourced from an exception thrown. Adding it to both the set
// of standard Drupal messages and to the bottom around the buttons.
$this->messenger()->addError($e->getMessage() . ' Scanning is not possible until this is resolved.');
$form['warning'] = [
[
'#theme' => 'status_messages',
'#message_list' => [
'error' => [$e->getMessage() . ' Scanning is not possible until this is resolved.'],
],
'#status_headings' => [
'error' => t('Error message'),
],
],
// Set weight lower than the "actions" element's 100.
'#weight' => 90,
];
}
if ($this->nextMajor == 12) {
$environment = $this->buildEnvironmentChecksFor12();
}
elseif ($this->nextMajor == 11) {
$environment = $this->buildEnvironmentChecksFor11();
}
else {
$environment = $this->buildEnvironmentChecksFor10();
}
$form['summary'] = $this->buildResultSummary($environment['status']);
$environment_description = $environment['description'];
unset($environment['status']);
unset($environment['description']);
$form['environment'] = [
'#type' => 'details',
'#title' => $this->t('Drupal core and hosting environment'),
'#description' => $environment_description,
'#open' => TRUE,
'#attributes' => ['class' => ['upgrade-status-of-environment']],
'data' => $environment,
'#tree' => TRUE,
];
// Gather project list with metadata.
$projects = $this->projectCollector->collectProjects();
$next_steps = $this->projectCollector->getNextStepInfo();
foreach ($next_steps as $next_step => $step_label) {
$sublist = [];
foreach ($projects as $name => $project) {
if ($project->info['upgrade_status_next'] == $next_step) {
$sublist[$name] = $project;
}
}
if (!empty($sublist)) {
$form[$next_step] = [
'#type' => 'details',
'#title' => $step_label[0],
'#description' => $step_label[1],
'#open' => TRUE,
'#attributes' => ['class' => ['upgrade-status-next-step']],
'data' => $this->buildProjectList($sublist, $next_step, $step_label),
'#tree' => TRUE,
];
}
}
$form['actions']['#type'] = 'actions';
$form['actions']['submit'] = [
'#type' => 'submit',
'#value' => $this->t('Scan selected'),
'#weight' => 2,
'#button_type' => 'primary',
'#disabled' => !$analyzer_ready,
];
$form['actions']['export'] = [
'#type' => 'submit',
'#value' => $this->t('Export selected as HTML'),
'#weight' => 5,
'#submit' => [[$this, 'exportReport']],
'#disabled' => !$analyzer_ready,
];
$form['actions']['export_ascii'] = [
'#type' => 'submit',
'#value' => $this->t('Export selected as text'),
'#weight' => 6,
'#submit' => [[$this, 'exportReportASCII']],
'#disabled' => !$analyzer_ready,
];
return $form;
}
/**
* Builds a list and status summary of projects.
*
* @param \Drupal\Core\Extension\Extension[] $projects
* Array of extensions representing projects.
* @param string $next_step
* The machine name of the suggested next step to take for these projects.
* @param array $step_label
* Labels and other metadata for the step.
*
* @return array
* Build array.
*/
protected function buildProjectList(array $projects, string $next_step, array $step_label) {
$header = [
'project' => ['data' => $this->t('Project'), 'class' => 'project-label'],
'type' => ['data' => $this->t('Type'), 'class' => 'type-label'],
'status' => ['data' => $this->t('Status'), 'class' => 'status-label'],
'version' => ['data' => $this->t('Local version'), 'class' => 'version-label'],
'ready' => ['data' => $this->t('Local ' . $this->nextMajor . '-ready'), 'class' => 'ready-label'],
'result' => ['data' => $this->t('Local scan result'), 'class' => 'scan-info'],
'updatev' => ['data' => $this->t('Drupal.org version'), 'class' => 'updatev-info'],
'update9' => ['data' => $this->t('Drupal.org ' . $this->nextMajor . '-ready'), 'class' => 'update9-info'],
'issues' => ['data' => $this->t('Drupal.org issues'), 'class' => 'issue-info'],
];
$build['list'] = [
'#type' => 'tableselect',
'#header' => $header,
'#weight' => 20,
'#options' => [],
];
foreach ($projects as $name => $extension) {
$option = [
'#attributes' => ['class' => 'project-' . $name . ' ' . $step_label[3]],
];
$option['project'] = [
'data' => [
'label' => [
'#type' => 'html_tag',
'#tag' => 'label',
'#value' => $extension->info['name'] . ' (' . $extension->getName() . ')',
'#attributes' => [
'for' => 'edit-' . $next_step . '-data-list-' . str_replace('_', '-', $name),
],
],
],
'class' => 'project-label',
];
$type = '';
if ($extension->info['upgrade_status_type'] == ProjectCollector::TYPE_CUSTOM) {
if ($extension->getType() == 'module') {
$type = $this->t('Custom module');
}
elseif ($extension->getType() == 'theme') {
$type = $this->t('Custom theme');
}
elseif ($extension->getType() == 'profile') {
$type = $this->t('Custom profile');
}
}
else {
if ($extension->getType() == 'module') {
$type = $this->t('Contributed module');
}
elseif ($extension->getType() == 'theme') {
$type = $this->t('Contributed theme');
}
elseif ($extension->getType() == 'profile') {
$type = $this->t('Contributed profile');
}
}
$option['type'] = [
'data' => [
'label' => [
'#type' => 'markup',
'#markup' => $type,
],
]
];
$option['status'] = [
'data' => [
'label' => [
'#type' => 'markup',
'#markup' => empty($extension->status) ? $this->t('Uninstalled') : $this->t('Installed'),
],
]
];
// Start of local version/readiness columns.
$option['version'] = [
'data' => [
'label' => [
'#type' => 'markup',
'#markup' => !empty($extension->info['version']) ? $extension->info['version'] : $this->t('N/A'),
],
]
];
$option['ready'] = [
'class' => 'status-info ' . (!empty($extension->info['upgrade_status_next_major_compatible']) ? 'status-info-compatible' : 'status-info-incompatible'),
'data' => [
'label' => [
'#type' => 'markup',
'#markup' => !empty($extension->info['upgrade_status_next_major_compatible']) ? $this->t('Compatible') : $this->t('Incompatible'),
],
]
];
$report = $this->projectCollector->getResults($name);
$result_summary = !empty($report) ? $this->t('No problems found') : $this->t('N/A');
if (!empty($report['data']['totals']['file_errors'])) {
$result_summary = $this->formatPlural(
$report['data']['totals']['file_errors'],
'@count problem',
'@count problems'
);
$option['result'] = [
'data' => [
'#type' => 'link',
'#title' => $result_summary,
'#url' => Url::fromRoute('upgrade_status.project', ['project_machine_name' => $name]),
'#attributes' => [
'class' => ['use-ajax'],
'data-dialog-type' => 'modal',
'data-dialog-options' => Json::encode([
'width' => 1024,
'height' => 568,
]),
],
],
'class' => 'scan-result',
];
}
else {
$option['result'] = [
'data' => [
'label' => [
'#type' => 'markup',
'#markup' => $result_summary,
],
],
'class' => 'scan-result',
];
}
// Start of drupal.org data columns.
$updatev = $this->t('Not applicable');
if (!empty($extension->info['upgrade_status_update_link'])) {
$option['updatev'] = [
'data' => [
'link' => [
'#type' => 'link',
'#title' => $extension->info['upgrade_status_update_version'],
'#url' => Url::fromUri($extension->info['upgrade_status_update_link']),
],
]
];
unset($updatev);
}
elseif (!empty($extension->info['upgrade_status_update'])) {
$updatev = $this->t('Unavailable');
if ($extension->info['upgrade_status_update'] == ProjectCollector::UPDATE_NOT_CHECKED) {
$updatev = $this->t('Unchecked');
}
elseif ($extension->info['upgrade_status_update'] == ProjectCollector::UPDATE_ALREADY_INSTALLED) {
$updatev = $this->t('Up to date');
}
}
if (!empty($updatev)) {
$option['updatev'] = [
'data' => [
'label' => [
'#type' => 'markup',
'#markup' => $updatev,
],
]
];
}
$update_class = 'status-info-na';
$update_info = $this->t('Not applicable');
if (isset($extension->info['upgrade_status_update'])) {
switch ($extension->info['upgrade_status_update']) {
case ProjectCollector::UPDATE_NOT_AVAILABLE:
$update_info = $this->t('Unavailable');
$update_class = 'status-info-na';
break;
case ProjectCollector::UPDATE_NOT_CHECKED:
$update_info = $this->t('Unchecked');
$update_class = 'status-info-unchecked';
break;
case ProjectCollector::UPDATE_AVAILABLE:
case ProjectCollector::UPDATE_ALREADY_INSTALLED:
if ($extension->info['upgrade_status_update_compatible']) {
$update_info = $this->t('Compatible');
$update_class = 'status-info-compatible';
}
else {
$update_info = $this->t('Incompatible');
$update_class = 'status-info-incompatible';
}
break;
}
}
$option['update9'] = [
'class' => 'status-info ' . $update_class,
'data' => [
'label' => [
'#type' => 'markup',
'#markup' => $update_info,
],
]
];
if ($extension->info['upgrade_status_type'] == ProjectCollector::TYPE_CUSTOM) {
$option['issues'] = [
'data' => [
'label' => [
'#type' => 'markup',
'#markup' => $this->t('Not applicable'),
],
]
];
}
else {
$option['issues'] = [
'data' => [
'label' => [
'#type' => 'markup',
// Use the project name from the info array instead of $key.
// $key is the local name, not necessarily the project name.
'#markup' => '<a href="https://drupal.org/project/issues/' . $extension->info['project'] . '?text=Drupal+' . $this->nextMajor . '&status=All">' . $this->t('Issues', [], ['context' => 'Drupal.org issues']) . '</a>',
],
]
];
}
$build['list']['#options'][$name] = $option;
}
return $build;
}
/**
* Preprocess function to add class to the header row of our table.
*/
function upgrade_status_preprocess_table_custom_header(array &$element) {
// Check if this is the table you want to target.
if (!empty($element['list']['#upgrade_status_step_class'])) {
// Add class to the header row.
$element['#header']['#attributes']['class'][] = $element['list']['#upgrade_status_step_class'];
}
}
/**
* Build a result summary table for quick overview display to users.
*
* @param bool|null $environment_status
* The status of the environment. Whether to put it into the Fix or Relax
* columns or omit it.
*
* @return array
* Render array.
*/
protected function buildResultSummary($environment_status = TRUE) {
$projects = $this->projectCollector->collectProjects();
$next_steps = $this->projectCollector->getNextStepInfo();
$last = $this->state->get('update.last_check') ?: 0;
if ($last == 0) {
$last_checked = $this->t('Never checked');
}
else {
$time = $this->dateFormatter->formatTimeDiffSince($last);
$last_checked = $this->t('Last checked @time ago', ['@time' => $time]);
}
// $update_time = [
// [
// '#type' => 'link',
// '#title' => $this->t('Check available updates'),
// '#url' => Url::fromRoute('update.manual_status', [], ['query' => $this->destination->getAsArray()]),
// ],
// [
// '#type' => 'markup',
// '#markup' => ' (' . $last_checked . ')',
// ],
// ];
$header = [
ProjectCollector::SUMMARY_ANALYZE => ['data' => $this->t('Gather data')],
ProjectCollector::SUMMARY_ACT => ['data' => $this->t('Fix incompatibilities')],
ProjectCollector::SUMMARY_RELAX => ['data' => $this->t('Relax')],
];
$build = [
'#type' => 'table',
'#attributes' => ['class' => ['upgrade-status-of-site']],
'#header' => $header,
'#rows' => [
[
'data' => [
ProjectCollector::SUMMARY_ANALYZE => ['data' => []],
ProjectCollector::SUMMARY_ACT => ['data' => []],
ProjectCollector::SUMMARY_RELAX => ['data' => []],
]
]
],
];
foreach ($header as $key => $value) {
$cell_data = $cell_items = [];
foreach($next_steps as $next_step => $step_label) {
// If this next step summary belongs in this table cell, collect it.
if ($step_label[2] == $key) {
foreach ($projects as $project) {
if ($project->info['upgrade_status_next'] == $next_step) {
@$cell_data[$next_step]++;
}
}
}
}
if ($key == ProjectCollector::SUMMARY_ANALYZE) {
// If neither Composer Deploy nor Git Deploy are available and installed, suggest installing one.
if (empty($projects['git_deploy']->status) && empty($projects['composer_deploy']->status)) {
$cell_items[] = [
'#markup' => $this->t('Install <a href=":composer_deploy">Composer Deploy</a> or <a href=":git_deploy">Git Deploy</a> as appropriate for accurate update recommendations', [':composer_deploy' => 'https://drupal.org/project/composer_deploy', ':git_deploy' => 'https://drupal.org/project/git_deploy'])
];
}
// Add available update info.
// $cell_items[] = $update_time;
}
if (($key == ProjectCollector::SUMMARY_ACT) && !is_null($environment_status) && !$environment_status) {
$cell_items[] = [
'#markup' => '<a href="#edit-environment">' . $this->t('Environment is incompatible') . '</a>',
];
}
if (count($cell_data)) {
foreach ($cell_data as $next_step => $count) {
$cell_items[] = [
'#markup' => '<a href="#edit-' . $next_step . '">' . $this->formatPlural($count, '@type: 1 project', '@type: @count projects', ['@type' => $next_steps[$next_step][0]]) . '</a>',
];
}
}
if ($key == ProjectCollector::SUMMARY_ANALYZE) {
$cell_items[] = [
'#markup' => 'Select any of the projects to rescan as needed below',
];
}
if ($key == ProjectCollector::SUMMARY_RELAX) {
// Calculate how done is this site assuming the environment as
// "one project" for simplicity.
$done_count = (!empty($cell_data[ProjectCollector::NEXT_RELAX]) ? $cell_data[ProjectCollector::NEXT_RELAX] : 0) + (int) $environment_status;
$percent = round($done_count / (count($projects) + 1) * 100);
$build['#rows'][0]['data'][$key]['data'][] = [
'#type' => 'markup',
'#allowed_tags' => ['svg', 'path', 'text'],
'#markup' => <<<MARKUP
<div class="upgrade-status-result-chart">
<svg viewBox="0 0 36 36" class="upgrade-status-of-site-circle">
<path class="circle-bg"
d="M18 2.0845
a 15.9155 15.9155 0 0 1 0 31.831
a 15.9155 15.9155 0 0 1 0 -31.831"
/>
<path class="circle"
stroke-dasharray="{$percent}, 100"
d="M18 2.0845
a 15.9155 15.9155 0 0 1 0 31.831
a 15.9155 15.9155 0 0 1 0 -31.831"
/>
<text x="18" y="20.35" class="percentage">{$percent}%</text>
</svg>
</div>
MARKUP
];
if (!empty($environment_status)) {
$cell_items[] = [
'#markup' => '<a href="#edit-environment">' . $this->t('Environment checks passed') . '</a>',
];
}
}
if (count($cell_items)) {
$build['#rows'][0]['data'][$key]['data'][] = [
'#theme' => 'item_list',
'#items' => $cell_items,
];
}
else {
$build['#rows'][0]['data'][$key]['data'][] = [
'#type' => 'markup',
'#markup' => $this->t('N/A'),
];
}
}
return $build;
}
/**
* Builds a list of environment checks for Drupal 10 compatibility.
*
* @return array
* Build array. The overall environment status (TRUE, FALSE or NULL) is
* indicated in the 'status' key, while a 'description' key explains the
* environment requirements on a high level.
*/
protected function buildEnvironmentChecksFor10() {
$status = TRUE;
$header = [
'requirement' => ['data' => $this->t('Requirement'), 'class' => 'requirement-label'],
'status' => ['data' => $this->t('Status'), 'class' => 'status-info'],
];
$build['data'] = [
'#type' => 'table',
'#header' => $header,
'#rows' => [],
];
$build['description'] = $this->t('Upgrades to Drupal 10 are supported from Drupal 9.4.x and Drupal 9.5.x. It is suggested to update to the latest Drupal 9 version available. <a href=":platform">Several hosting platform requirements have been raised for Drupal 10</a>.', [':platform' => 'https://www.drupal.org/node/3228686']);
// Check Drupal version. Link to update if available.
$core_version_info = [
'#type' => 'markup',
'#markup' => $this->t('Version @version.', ['@version' => \Drupal::VERSION]),
];
$has_core_update = FALSE;
$core_update_info = $this->releaseStore->get('drupal');
if (isset($core_update_info['releases']) && is_array($core_update_info['releases'])) {
// Find the latest release that are higher than our current and is not beta/alpha/rc/dev.
foreach ($core_update_info['releases'] as $version => $release) {
$major_version = explode('.', $version)[0];
if ($major_version === '9' && !strpos($version, '-') && (version_compare($version, \Drupal::VERSION) > 0)) {
$link = $core_update_info['link'] . '/releases/' . $version;
$core_version_info = [
'#type' => 'link',
'#title' => version_compare(\Drupal::VERSION, '9.4.0') >= 0 ?
$this->t('Version @current allows to upgrade but @new is available.', ['@current' => \Drupal::VERSION, '@new' => $version]) :
$this->t('Version @current does not allow to upgrade and @new is available.', ['@current' => \Drupal::VERSION, '@new' => $version]),
'#url' => Url::fromUri($link),
];
$has_core_update = TRUE;
break;
}
}
}
if (version_compare(\Drupal::VERSION, '9.4.0') >= 0) {
if (!$has_core_update) {
$class = 'color-success';
}
else {
$class = 'color-warning';
}
}
else {
$status = FALSE;
$class = 'color-error';
}
$build['data']['#rows'][] = [
'class' => $class,
'data' => [
'requirement' => [
'class' => 'requirement-label',
'data' => $this->t('Drupal core should be at least 9.4.x'),
],
'status' => [
'data' => $core_version_info,
'class' => 'status-info',
],
]
];
// Check PHP version.
$version = PHP_VERSION;
// The value of MINIMUM_PHP in Drupal 10.
$minimum_php = '8.1.0';
if (version_compare($version, $minimum_php) >= 0) {
$class = 'color-success';
}
else {
$class = 'color-error';
$status = FALSE;
}
$build['data']['#rows'][] = [
'class' => [$class],
'data' => [
'requirement' => [
'class' => 'requirement-label',
'data' => $this->t('PHP version should be at least @minimum_php. Before updating to PHP @minimum_php, use <code>$ composer why-not php @minimum_php</code> to check if any projects need updating for compatibility. Also check custom projects manually.', ['@minimum_php' => $minimum_php]),
],
'status' => [
'data' => $this->t('Version @version', ['@version' => $version]),
'class' => 'status-info',
],
]
];
// Check database version.
$database_type = $this->database->databaseType();
$version = $this->database->version();
$addendum = '';
if ($database_type == 'pgsql') {
$database_type_full_name = 'PostgreSQL';
$requirement = $this->t('When using PostgreSQL, minimum version is 12 <a href=":trgm">with the pg_trgm extension</a> created.', [':trgm' => 'https://www.postgresql.org/docs/10/pgtrgm.html']);
$has_trgm = $this->database->query("SELECT installed_version FROM pg_available_extensions WHERE name = 'pg_trgm'")->fetchField();
if (version_compare($version, '12') >= 0 && $has_trgm) {
$class = 'color-success';
$addendum = $this->t('Has pg_trgm extension.');
}
else {
$status = FALSE;
$class = 'color-error';
if (!$has_trgm) {
$addendum = $this->t('No pg_trgm extension.');
}
}
$build['data']['#rows'][] = [
'class' => [$class],
'data' => [
'requirement' => [
'class' => 'requirement-label',
'data' => [
'#type' => 'markup',
'#markup' => $requirement
],
],
'status' => [
'data' => trim($database_type_full_name . ' ' . $version . ' ' . $addendum),
'class' => 'status-info',
],
]
];
}
// Check JSON support in database.
$class = 'color-success';
$requirement = $this->t('Supported.');
try {
if (!method_exists($this->database, 'hasJson') || !$this->database->hasJson()) {
// A hasJson() method was added to Connection from Drupal 9.4.0
// but we cannot rely on being on Drupal 9.4.x+
$this->database->query($database_type == 'pgsql' ? 'SELECT JSON_TYPEOF(\'1\')' : 'SELECT JSON_TYPE(\'1\')');
}
}
catch (\Exception $e) {
$class = 'color-error';
$status = FALSE;
$requirement = $this->t('Not supported.');
}
$build['data']['#rows'][] = [
'class' => [$class],
'data' => [
'requirement' => [
'class' => 'requirement-label',
'data' => $this->t('Database JSON support required'),
],
'status' => [
'data' => $requirement,
'class' => 'status-info',
],
]
];
// Check user roles on the site for invalid permissions.
$class = 'color-success';
$requirement = [];
$user_roles = Role::loadMultiple();
$all_permissions = array_keys(\Drupal::service('user.permissions')->getPermissions());
foreach ($user_roles as $role) {
$role_permissions = $role->getPermissions();
$valid_role_permissions = array_intersect($role_permissions, $all_permissions);
$invalid_role_permissions = array_diff($role_permissions, $valid_role_permissions);
if (!empty($invalid_role_permissions)) {
$class = 'color-error';
$status = FALSE;
$requirement[] = [
'#theme' => 'item_list',
'#prefix' => $this->t('Permissions of user role: "@role":', ['@role' => $role->label()]),
'#items' => $invalid_role_permissions,
];
}
}
$build['data']['#rows'][] = [
'class' => [$class],
'data' => [
'requirement' => [
'class' => 'requirement-label',
'data' => $this->t('<a href=":url">Invalid permissions will trigger runtime exceptions in Drupal 10.</a> Permissions should be defined in a permissions.yml file or a permission callback.', [':url' => 'https://www.drupal.org/node/3193348']),
],
'status' => [
'data' => [
'#theme' => 'item_list',
'#items' => $requirement,
'#empty' => $this->t('None found.'),
],
'class' => 'status-info',
],
]
];
// Check for deprecated or obsolete core extensions.
$class = 'color-success';
$requirement = $this->t('None installed.');
$deprecated_or_obsolete = $this->projectCollector->collectCoreDeprecatedAndObsoleteExtensions();
if (!empty($deprecated_or_obsolete)) {
$class = 'color-error';
$status = FALSE;
$requirement = join(', ', $deprecated_or_obsolete);
}
$build['data']['#rows'][] = [
'class' => [$class],
'data' => [
'requirement' => [
'class' => 'requirement-label',
'data' => $this->t('Deprecated or obsolete core extensions installed. These will be removed in the next major version.'),
],
'status' => [
'data' => [
'#markup' => $requirement,
],
'class' => 'status-info',
],
]
];
// Check Drush. We only detect site-local drush for now.
if (class_exists('\\Drush\\Drush')) {
$version = call_user_func('\\Drush\\Drush::getMajorVersion');
if (version_compare($version, '11') >= 0) {
$class = 'color-success';
}
else {
$status = FALSE;
$class = 'color-error';
}
$label = $this->t('Version @version', ['@version' => $version]);
}
else {
$class = '';
$label = $this->t('Version cannot be detected, check manually.');
}
$build['data']['#rows'][] = [
'class' => $class,
'data' => [
'requirement' => [
'class' => 'requirement-label',
'data' => $this->t('When using Drush, minimum version is 11'),
],
'status' => [
'data' => $label,
'class' => 'status-info',
],
]
];
// Save the overall status indicator in the build array. It will be
// popped off later to be used in the summary table.
$build['status'] = $status;
return $build;
}
/**
* Builds a list of environment checks for Drupal 12 compatibility.
*
* @return array
* Build array. The overall environment status (TRUE, FALSE or NULL) is
* indicated in the 'status' key, while a 'description' key explains the
* environment requirements on a high level.
*/
protected function buildEnvironmentChecksFor12() {
return [
'description' => $this->t('<a href=":platform">Drupal 12 environment requirements are still to be defined</a>.', [':platform' => 'https://www.drupal.org/project/drupal/issues/3449806']),
// Checks neither passed, nor failed.
'status' => NULL,
];
}
/**
* Builds a list of environment checks for Drupal 11 compatibility.
*
* @return array
* Build array. The overall environment status (TRUE, FALSE or NULL) is
* indicated in the 'status' key, while a 'description' key explains the
* environment requirements on a high level.
*/
protected function buildEnvironmentChecksFor11() {
$status = TRUE;
$header = [
'requirement' => ['data' => $this->t('Requirement'), 'class' => 'requirement-label'],
'status' => ['data' => $this->t('Status'), 'class' => 'status-info'],
];
$build['data'] = [
'#type' => 'table',
'#header' => $header,
'#rows' => [],
];
$build['description'] = $this->t('Below are Drupal 11\'s system requirements. If you are working with multiple (dev, stage, live) environments, make sure to check the same requirements there.');
// Check Drupal version. Link to update if available.
$core_version_info = [
'#type' => 'markup',
'#markup' => $this->t('Version @version.', ['@version' => \Drupal::VERSION]),
];
$has_core_update = FALSE;
$core_update_info = $this->releaseStore->get('drupal');
if (isset($core_update_info['releases']) && is_array($core_update_info['releases'])) {
// Find the latest release that are higher than our current and is not beta/alpha/rc/dev.
foreach ($core_update_info['releases'] as $version => $release) {
$major_version = explode('.', $version)[0];
if ($major_version === '10' && !strpos($version, '-') && (version_compare($version, \Drupal::VERSION) > 0)) {
$link = $core_update_info['link'] . '/releases/' . $version;
$core_version_info = [
'#type' => 'link',
'#title' => version_compare(\Drupal::VERSION, '10.3.0') >= 0 ?
$this->t('Version @current allows to upgrade but @new is available.', ['@current' => \Drupal::VERSION, '@new' => $version]) :
$this->t('Version @current does not allow to upgrade and @new is available.', ['@current' => \Drupal::VERSION, '@new' => $version]),
'#url' => Url::fromUri($link),
];
$has_core_update = TRUE;
break;
}
}
}
if (version_compare(\Drupal::VERSION, '10.3.0') >= 0) {
if (version_compare(\Drupal::VERSION, '10.4.0') >= 0) {
$this->messenger()->addWarning('Drupal 11.0 is not a supported upgrade from Drupal 10.4. Make sure to upgrade to 11.1!');
}
if (!$has_core_update) {
$class = 'color-success';
}
else {
$class = 'color-warning';
}
}
else {
$status = FALSE;
$class = 'color-error';
}
$build['data']['#rows'][] = [
'class' => $class,
'data' => [
'requirement' => [
'class' => 'requirement-label',
'data' => $this->t('Drupal core should be at least 10.3.0'),
],
'status' => [
'data' => $core_version_info,
'class' => 'status-info',
],
]
];
// Check PHP version.
$version = PHP_VERSION;
$minimum_php = '8.3.0';
if (version_compare($version, $minimum_php) >= 0) {
$class = 'color-success';
}
else {
$class = 'color-error';
$status = FALSE;
}
$build['data']['#rows'][] = [
'class' => [$class],
'data' => [
'requirement' => [
'class' => 'requirement-label',
'data' => $this->t('PHP version should be at least @minimum_php. Before updating to PHP @minimum_php, use <code>$ composer why-not php @minimum_php</code> to check if any projects need updating for compatibility. Also check custom projects manually.', ['@minimum_php' => $minimum_php]),
],
'status' => [
'data' => $this->t('Version @version', ['@version' => $version]),
'class' => 'status-info',
],
]
];
// Check database version.
$database_type = $this->database->databaseType();
$version = $this->database->version();
$addendum = '';
if ($database_type == 'mysql') {
if ($this->database->isMariaDb()) {
$database_type_full_name = 'MariaDB';
$requirement = $this->t('When using MariaDB, minimum version is 10.6');
if (version_compare($version, '10.6') >= 0) {
$class = 'color-success';
}
elseif (version_compare($version, '10.3.7') >= 0) {
if ($this->moduleHandler->moduleExists('mysql57')) {
$class = 'color-warning';
$requirement .= ' ' . $this->t('Keep using <a href=":driver">the MariaDB 10.3 driver</a> for now, which is already installed.', [':driver' => 'https://www.drupal.org/project/mysql57']);
}
else {
$class = 'color-error';
$requirement .= ' ' . $this->t('Alternatively, <a href=":driver">install the MariaDB 10.3 driver</a> for now.', [':driver' => 'https://www.drupal.org/project/mysql57']);
}
}
else {
// Should not happen because Drupal 10 already required 10.3.7, but just to be sure.
$status = FALSE;
$class = 'color-error';
$requirement .= ' ' . $this->t('Once updated to at least 10.3.7, you can also <a href=":driver">install the MariaDB 10.3 driver</a> for now.', [':driver' => 'https://www.drupal.org/project/mysql57']);
}
}
else {
$database_type_full_name = 'MySQL or Percona Server';
$requirement = $this->t('When using MySQL/Percona, minimum version is 8.0');
if (version_compare($version, '8.0') >= 0) {
$class = 'color-success';
}
elseif (version_compare($version, '5.7.8') >= 0) {
if ($this->moduleHandler->moduleExists('mysql57')) {
$class = 'color-warning';
$requirement .= ' ' . $this->t('Keep using <a href=":driver">the MySQL 5.7 driver</a> for now, which is already installed.', [':driver' => 'https://www.drupal.org/project/mysql57']);
}
else {
$class = 'color-error';
$requirement .= ' ' . $this->t('Alternatively, <a href=":driver">install the MySQL 5.7 driver</a> for now.', [':driver' => 'https://www.drupal.org/project/mysql57']);
}
}
else {
// Should not happen because Drupal 10 already required 5.7.8, but just to be sure.
$status = FALSE;
$class = 'color-error';
$requirement .= ' ' . $this->t('Once updated to at least 5.7.8, you can also <a href=":driver">install the MySQL 5.7 driver</a> for now.', [':driver' => 'https://www.drupal.org/project/mysql57']);
}
}
}
elseif ($database_type == 'pgsql') {
$database_type_full_name = 'PostgreSQL';
$requirement = $this->t('When using PostgreSQL, minimum version is 16 <a href=":trgm">with the pg_trgm extension</a> created.', [':trgm' => 'https://www.postgresql.org/docs/10/pgtrgm.html']);
$has_trgm = $this->database->query("SELECT installed_version FROM pg_available_extensions WHERE name = 'pg_trgm'")->fetchField();
if (version_compare($version, '16') >= 0 && $has_trgm) {
$class = 'color-success';
$addendum = $this->t('Has pg_trgm extension.');
}
else {
$status = FALSE;
$class = 'color-error';
if (!$has_trgm) {
$addendum = $this->t('No pg_trgm extension.');
}
}
}
elseif ($database_type == 'sqlite') {
$database_type_full_name = 'SQLite';
$minimum_sqlite = '3.45';
$requirement = $this->t('When using SQLite, minimum version is @minimum_sqlite', ['@minimum_sqlite' => $minimum_sqlite]);
if (version_compare($version, $minimum_sqlite) >= 0) {
$class = 'color-success';
}
else {
$status = FALSE;
$class = 'color-error';
}
}
$build['data']['#rows'][] = [
'class' => [$class],
'data' => [
'requirement' => [
'class' => 'requirement-label',
'data' => [
'#type' => 'markup',
'#markup' => $requirement
],
],
'status' => [
'data' => $database_type_full_name . ' ' . $version,
'class' => 'status-info',
],
]
];
// Check JSON support in database.
$class = 'color-success';
$requirement = $this->t('Supported.');
if (!method_exists($this->database, 'hasJson') || !$this->database->hasJson()) {
$class = 'color-error';
$status = FALSE;
$requirement = $this->t('Not supported.');
}
$build['data']['#rows'][] = [
'class' => [$class],
'data' => [
'requirement' => [
'class' => 'requirement-label',
'data' => $this->t('Database JSON support required'),
],
'status' => [
'data' => $requirement,
'class' => 'status-info',
],
]
];
// Check for deprecated or obsolete core extensions.
$class = 'color-success';
$requirement = $this->t('None installed.');
$deprecated_or_obsolete = $this->projectCollector->collectCoreDeprecatedAndObsoleteExtensions();
if (!empty($deprecated_or_obsolete)) {
$class = 'color-error';
$status = FALSE;
$requirement = join(', ', $deprecated_or_obsolete);
}
$build['data']['#rows'][] = [
'class' => [$class],
'data' => [
'requirement' => [
'class' => 'requirement-label',
'data' => $this->t('Deprecated or obsolete core extensions installed. These will be removed in the next major version.'),
],
'status' => [
'data' => [
'#markup' => $requirement,
],
'class' => 'status-info',
],
]
];
// Check Drush. We only detect site-local drush for now.
if (class_exists('\\Drush\\Drush')) {
$version = call_user_func('\\Drush\\Drush::getMajorVersion');
if (version_compare($version, '13') >= 0) {
$class = 'color-success';
}
else {
$status = FALSE;
$class = 'color-error';
}
$label = $this->t('Version @version', ['@version' => $version]);
}
else {
$class = '';
$label = $this->t('Version cannot be detected, check manually.');
}
$build['data']['#rows'][] = [
'class' => $class,
'data' => [
'requirement' => [
'class' => 'requirement-label',
'data' => $this->t('When using Drush, minimum version is 13'),
],
'status' => [
'data' => $label,
'class' => 'status-info',
],
]
];
// Save the overall status indicator in the build array. It will be
// popped off later to be used in the summary table.
$build['status'] = $status;
return $build;
}
/**
* Form submission handler.
*
* @param array $form
* An associative array containing the structure of the form.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The current state of the form.
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
// Reset extension lists for better Drupal 9 compatibility info.
$this->projectCollector->resetLists();
$operations = $list = [];
$projects = $this->projectCollector->collectProjects();
$submitted = $form_state->getValues();
$next_steps = $this->projectCollector->getNextStepInfo();
foreach ($next_steps as $next_step => $step_label) {
if (!empty($submitted[$next_step]['data']['list'])) {
foreach ($submitted[$next_step]['data']['list'] as $item) {
if (isset($projects[$item])) {
$list[] = $projects[$item];
}
}
}
}
// It is not possible to make an HTTP request to this same webserver
// if the host server is PHP itself, because it is single-threaded.
// See https://www.php.net/manual/en/features.commandline.webserver.php
$use_http = php_sapi_name() != 'cli-server';
$php_server = !$use_http;
if ($php_server) {
// Log the selected processing method for project support purposes.
$this->logger->notice('Starting Upgrade Status on @count projects without HTTP sandboxing because the built-in PHP webserver does not allow for that.', ['@count' => count($list)]);
}
else {
// Attempt to do an HTTP request to the frontpage of this Drupal instance.
// If that does not work then we'll not be able to process projects over
// HTTP. Processing projects directly is less safe (in case of PHP fatal
// errors the batch process may halt), but we have no other choice here
// but to take a chance.
list(, $message, $data) = static::doHttpRequest('upgrade_status_request_test', 'upgrade_status_request_test');
if (empty($data) || !is_array($data) || ($data['message'] != 'Request test success')) {
$use_http = FALSE;
$this->logger->notice('Starting Upgrade Status on @count projects without HTTP sandboxing. @error', ['@error' => $message, '@count' => count($list)]);
}
}
if ($use_http) {
// Log the selected processing method for project support purposes.
$this->logger->notice('Starting Upgrade Status on @count projects with HTTP sandboxing.', ['@count' => count($list)]);
}
foreach ($list as $item) {
$operations[] = [
static::class . '::parseProject',
[$item, $use_http]
];
}
if (!empty($operations)) {
// Allow other modules to alter the operations to be run.
$this->moduleHandler->alter('upgrade_status_operations', $operations, $form_state);
}
if (!empty($operations)) {
$batch = [
'title' => $this->t('Scanning projects'),
'operations' => $operations,
'finished' => static::class . '::finishedParsing',
];
batch_set($batch);
}
else {
$this->messenger()->addError('No projects selected to scan.');
}
}
/**
* Form submission handler.
*
* @param array $form
* An associative array containing the structure of the form.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The current state of the form.
* @param string $format
* Either 'html' or 'ascii' depending on what the format should be.
*/
public function exportReport(array &$form, FormStateInterface $form_state, string $format = 'html') {
$extensions = [];
$projects = $this->projectCollector->collectProjects();
$submitted = $form_state->getValues();
$next_steps = $this->projectCollector->getNextStepInfo();
foreach ($next_steps as $next_step => $step_label) {
if (!empty($submitted[$next_step]['data']['list'])) {
foreach ($submitted[$next_step]['data']['list'] as $item) {
if (isset($projects[$item])) {
$type = $projects[$item]->info['upgrade_status_type'] == ProjectCollector::TYPE_CUSTOM ? 'custom' : 'contrib';
$extensions[$type][$item] =
$format == 'html' ?
$this->resultFormatter->formatResult($projects[$item]) :
$this->resultFormatter->formatAsciiResult($projects[$item]);
}
}
}
}
if (empty($extensions)) {
$this->messenger()->addError('No projects selected to export.');
return;
}
$build = [
'#theme' => 'upgrade_status_'. $format . '_export',
'#projects' => $extensions
];
$fileDate = $this->resultFormatter->formatDateTime(0, 'html_datetime');
$extension = $format == 'html' ? '.html' : '.txt';
$filename = 'upgrade-status-export-' . $fileDate . $extension;
$response = new Response($this->renderer->renderRoot($build));
$response->headers->set('Content-Disposition', 'attachment; filename="' . $filename . '"');
$form_state->setResponse($response);
}
/**
* Form submission handler.
*
* @param array $form
* An associative array containing the structure of the form.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The current state of the form.
*/
public function exportReportASCII(array &$form, FormStateInterface $form_state) {
$this->exportReport($form, $form_state, 'ascii');
}
/**
* Batch callback to analyze a project.
*
* @param \Drupal\Core\Extension\Extension $extension
* The extension to analyze.
* @param bool $use_http
* Whether to use HTTP to execute the processing or execute locally. HTTP
* processing could fail in some container setups. Local processing may
* fail due to timeout or memory limits.
* @param array $context
* Batch context.
*/
public static function parseProject(Extension $extension, $use_http, &$context) {
$context['message'] = t('Analysis complete for @project.', ['@project' => $extension->getName()]);
if (!$use_http) {
\Drupal::service('upgrade_status.deprecation_analyzer')->analyze($extension);
return;
}
// Do the HTTP request to run processing.
list($error, $message) = static::doHttpRequest($extension->getName());
if ($error !== FALSE) {
/** @var \Drupal\Core\KeyValueStore\KeyValueStoreInterface $key_value */
$key_value = \Drupal::service('keyvalue')->get('upgrade_status_scan_results');
$result = [];
$result['date'] = \Drupal::time()->getRequestTime();
$result['data'] = [
'totals' => [
'errors' => 1,
'file_errors' => 1,
'upgrade_status_split' => [
'warning' => 1,
]
],
'files' => [],
];
$result['data']['files'][$error] = [
'errors' => 1,
'messages' => [
[
'message' => $message,
'line' => 0,
],
],
];
$key_value->set($extension->getName(), $result);
}
}
/**
* Batch callback to finish parsing.
*
* @param $success
* TRUE if the batch operation was successful; FALSE if there were errors.
* @param $results
* An associative array of results from the batch operation.
*/
public static function finishedParsing($success, $results) {
$logger = \Drupal::logger('upgrade_status');
if ($success) {
$logger->notice('Finished Upgrade Status processing successfully.');
}
else {
$logger->notice('Finished Upgrade Status processing with errors.');
}
}
/**
* Do an HTTP request with the type and machine name.
*
* @param string $project_machine_name
* The machine name of the project.
*
* @return array
* A three item array with any potential errors, the error message and the
* returned data as the third item. Either of them will be FALSE if they are
* not applicable. Data may also be NULL if response JSON decoding failed.
*/
public static function doHttpRequest(string $project_machine_name) {
$error = $message = $data = FALSE;
// Prepare for a POST request to scan this project. The separate HTTP
// request is used to separate any PHP errors found from this batch process.
// We can store any errors and gracefully continue if there was any PHP
// errors in parsing.
$url = Url::fromRoute(
'upgrade_status.analyze',
[
'project_machine_name' => $project_machine_name
]
);
// Pass over authentication information because access to this functionality
// requires administrator privileges.
/** @var \Drupal\Core\Session\SessionConfigurationInterface $session_config */
$session_config = \Drupal::service('session_configuration');
$request = \Drupal::request();
$session_options = $session_config->getOptions($request);
// Unfortunately DrupalCI testbot does not have a domain that would normally
// be considered valid for cookie setting, so we need to work around that
// by manually setting the cookie domain in case there was none. What we
// care about is we get actual results, and cookie on the host level should
// suffice for that.
$cookie_domain = empty($session_options['cookie_domain']) ? '.' . $request->getHost() : $session_options['cookie_domain'];
$cookie_jar = new CookieJar();
$cookie = new SetCookie([
'Name' => $session_options['name'],
'Value' => $request->cookies->get($session_options['name']),
'Domain' => $cookie_domain,
'Secure' => $session_options['cookie_secure'],
]);
$cookie_jar->setCookie($cookie);
$options = [
'cookies' => $cookie_jar,
'timeout' => 0,
];
// Try a POST request with the session cookie included. We expect valid JSON
// back. In case there was a PHP error before that, we log that.
try {
$response = \Drupal::httpClient()->post($url->setAbsolute()->toString(), $options);
$data = json_decode((string) $response->getBody(), TRUE);
if (!$data) {
$error = 'PHP Fatal Error';
$message = (string) $response->getBody();
}
}
catch (\Exception $e) {
$error = 'Scanning exception';
$message = $e->getMessage();
}
return [$error, $message, $data];
}
/**
* Checks config directory settings for use of deprecated values.
*
* The $config_directories variable is deprecated in Drupal 8. However,
* the Settings object obscures the fact in Settings:initialize(), where
* it throws an error but levels the values in the deprecated location
* and $settings. So after that, it is not possible to tell if either
* were set in settings.php or not.
*
* Therefore we reproduce loading of settings and check the raw values.
*
* @return bool|NULL
* TRUE if the deprecated setting is used. FALSE if not used.
* NULL if both values are used.
*/
protected function isDeprecatedConfigDirectorySettingUsed() {
$app_root = $this->kernel->getAppRoot();
$site_path = $this->kernel->getSitePath();
if (is_readable($app_root . '/' . $site_path . '/settings.php')) {
// Reset the "global" variables expected to exist for settings.
$settings = [];
$config = [];
$databases = [];
$class_loader = require $app_root . '/autoload.php';
require $app_root . '/' . $site_path . '/settings.php';
}
if (!empty($config_directories)) {
if (!empty($settings['config_sync_directory'])) {
// Both are set. The $settings copy will prevail in Settings::initialize().
return NULL;
}
// Only the deprecated variable is set.
return TRUE;
}
// The deprecated variable is not set.
return FALSE;
}
/**
* Dynamic page title for the form to make the status target clear.
*/
public function getTitle() {
return $this->t('Drupal @version upgrade status', ['@version' => $this->nextMajor]);
}
}
<?php
declare(strict_types=1);
namespace Drupal\upgrade_status;
use Drupal\Core\Asset\LibraryDiscoveryParser;
use Drupal\Core\Extension\Extension;
use Drupal\Core\Extension\ExtensionList;
use Drupal\Core\Extension\ModuleExtensionList;
use Drupal\Core\Extension\ProfileExtensionList;
use Drupal\Core\Extension\ThemeExtensionList;
use Drupal\Core\Template\TwigEnvironment;
use Twig\Error\SyntaxError;
use Twig\Node\Expression\ConstantExpression;
use Twig\Node\Expression\FunctionExpression;
use Twig\Node\Node;
use Twig\Source;
use Twig\Util\TemplateDirIterator;
/**
* A library deprecation analyzer.
*/
final class LibraryDeprecationAnalyzer {
/**
* The library discovery parser.
*
* @var \Drupal\Core\Asset\LibraryDiscoveryParser
*/
protected $libraryDiscoveryParser;
/**
* The Twig environment.
*
* @var \Drupal\Core\Template\TwigEnvironment
*/
protected $twigEnvironment;
/**
* The list of available modules.
*
* @var \Drupal\Core\Extension\ModuleExtensionList
*/
protected $moduleExtensionList;
/**
* The list of available themes.
*
* @var \Drupal\Core\Extension\ThemeExtensionList
*/
protected $themeExtensionList;
/**
* The list of available profiles.
*
* @var \Drupal\Core\Extension\ProfileExtensionList
*/
protected $profileExtensionList;
/**
* Constructs a new library deprecation analyzer
*
* @param \Drupal\Core\Asset\LibraryDiscoveryParser $library_discovery_parser
* The library discovery parser.
* @param \Drupal\Core\Template\TwigEnvironment $twig_environment
* The Twig environment.
* @param \Drupal\Core\Extension\ModuleExtensionList $module_extension_list
* The module extension list service.
* @param \Drupal\Core\Extension\ThemeExtensionList $theme_extension_list
* The theme extension handler service.
* @param \Drupal\Core\Extension\ProfileExtensionList $profile_extension_list
* The profile extension handler service.
*/
public function __construct(LibraryDiscoveryParser $library_discovery_parser, TwigEnvironment $twig_environment, ModuleExtensionList $module_extension_list, ThemeExtensionList $theme_extension_list, ProfileExtensionList $profile_extension_list) {
$this->libraryDiscoveryParser = $library_discovery_parser;
$this->twigEnvironment = $twig_environment;
$this->moduleExtensionList = $module_extension_list;
$this->themeExtensionList = $theme_extension_list;
$this->profileExtensionList = $profile_extension_list;
}
/**
* Analyzes usages of deprecated libraries in an extension.
*
* @param \Drupal\Core\Extension\Extension $extension
* The extension to be analyzed.
*
* @return \Drupal\upgrade_status\DeprecationMessage[]
* A list of deprecation messages.
*
* @throws \Exception
*/
public function analyze(Extension $extension): array {
$deprecations = [];
$deprecations = array_merge($deprecations, $this->analyzeLibraryDependencies($extension));
if ($extension->getType() === 'theme') {
$deprecations = array_merge($deprecations, $this->analyzeThemeLibraryOverrides($extension));
$deprecations = array_merge($deprecations, $this->analyzeThemeLibraryExtends($extension));
}
$deprecations = array_merge($deprecations, $this->analyzeTwigLibraryDependencies($extension));
$deprecations = array_merge($deprecations, $this->analyzePhpLibraryReferences($extension));
return $deprecations;
}
/**
* Analyzes libraries for dependencies on deprecated libraries.
*
* @param \Drupal\Core\Extension\Extension $extension
* The extension to be analyzed.
*
* @return \Drupal\upgrade_status\DeprecationMessage[]
*/
private function analyzeLibraryDependencies(Extension $extension): array {
// Drupal\Core\Asset\LibraryDiscoveryParser::buildByExtension() assumes a
// disabled module is a theme and fails not finding it then, so check if
// the extension identified he is an installed module or theme. The library
// info will not be available otherwise.
$installed_modules = array_keys($this->moduleExtensionList->getAllInstalledInfo());
$installed_themes = array_keys($this->themeExtensionList->getAllInstalledInfo());
if (!in_array($extension->getName(), $installed_modules) && !in_array($extension->getName(), $installed_themes)) {
$message = sprintf("The '%s' extension is not installed. Cannot check deprecated library use.", $extension->getName());
return [new DeprecationMessage($message, $extension->getPath(), 0, 'LibraryDeprecationAnalyzer')];
}
try {
$libraries = $this->libraryDiscoveryParser->buildByExtension($extension->getName());
}
catch (\Exception $e) {
return [new DeprecationMessage($e->getMessage(), $extension->getPath(), 0, 'LibraryDeprecationAnalyzer')];
}
$libraries_with_dependencies = array_filter($libraries, function($library) {
return isset($library['dependencies']);
});
$deprecations = [];
$file = sprintf('%s/%s.libraries.yml', $extension->getPath(), $extension->getName());
foreach ($libraries_with_dependencies as $key => $library_with_dependency) {
foreach ($library_with_dependency['dependencies'] as $dependency) {
$is_deprecated = $this->isLibraryDeprecated($dependency);
if (is_null($is_deprecated)) {
$message = sprintf("The '%s' library (a dependency of '%s') is not defined because the defining extension is not installed. Cannot decide if it is deprecated or not.", $dependency, $key);
$deprecations[] = new DeprecationMessage($message, $file, 0, 'LibraryDeprecationAnalyzer');
}
elseif (!empty($is_deprecated)) {
if ($is_deprecated instanceof DeprecationMessage) {
$is_deprecated->setFile($file);
$deprecations[] = $is_deprecated;
}
else {
$message = sprintf("The '%s' library is depending on a deprecated library. %s", $key, $is_deprecated);
$deprecations[] = new DeprecationMessage($message, $file, 0, 'LibraryDeprecationAnalyzer');
}
}
}
}
return $deprecations;
}
/**
* Analyze library overrides in a theme.
*
* @param \Drupal\Core\Extension\Extension $extension
*
* @return \Drupal\upgrade_status\DeprecationMessage[]
* @throws \Exception
*/
private function analyzeThemeLibraryOverrides(Extension $extension): array {
if ($extension->getType() !== 'theme') {
throw new \Exception('Library overrides are only available in themes.');
}
if (!isset($extension->info['libraries-override'])) {
return [];
}
return array_reduce(array_keys($extension->info['libraries-override']), function($deprecated_libraries, $library) use($extension) {
$is_deprecated = $this->isLibraryDeprecated($library);
if (is_null($is_deprecated)) {
$message = sprintf("The '%s' library is not defined because the defining extension is not installed. Cannot decide if it is deprecated or not.", $library);
$deprecated_libraries[] = new DeprecationMessage($message, $extension->getFilename(), 0, 'LibraryDeprecationAnalyzer');
}
elseif (!empty($is_deprecated)) {
if ($is_deprecated instanceof DeprecationMessage) {
$is_deprecated->setFile($extension->getFilename());
$deprecated_libraries[] = $is_deprecated;
}
else {
$message = "Theme is overriding a deprecated library. $is_deprecated";
$deprecated_libraries[] = new DeprecationMessage($message, $extension->getFilename(), 0, 'LibraryDeprecationAnalyzer');
}
}
return $deprecated_libraries;
}, []);
}
/**
* Analyze library extends in a theme.
*
* @param \Drupal\Core\Extension\Extension $extension
*
* @return \Drupal\upgrade_status\DeprecationMessage[]
* @throws \Exception
*/
private function analyzeThemeLibraryExtends(Extension $extension): array {
if ($extension->getType() !== 'theme') {
throw new \Exception('Library extends are only available in themes.');
}
if (!isset($extension->info['libraries-extend'])) {
return [];
}
return array_reduce(array_keys($extension->info['libraries-extend']), function($deprecated_libraries, $library) use($extension) {
$is_deprecated = $this->isLibraryDeprecated($library);
if (is_null($is_deprecated)) {
$message = sprintf("The '%s' library is not defined because the defining extension is not installed. Cannot decide if it is deprecated or not.", $library);
$deprecated_libraries[] = new DeprecationMessage($message, $extension->getFilename(), 0, 'LibraryDeprecationAnalyzer');
}
elseif (!empty($is_deprecated)) {
if ($is_deprecated instanceof DeprecationMessage) {
$is_deprecated->setFile($extension->getFilename());
$deprecated_libraries[] = $is_deprecated;
}
else {
$message = "Theme is extending a deprecated library. $is_deprecated";
$deprecated_libraries[] = new DeprecationMessage($message, $extension->getFilename(), 0, 'LibraryDeprecationAnalyzer');
}
}
return $deprecated_libraries;
}, []);
}
/**
* Analyzes Twig library dependencies.
*
* At the moment we analyze only libraries attached using `library_attach()`.
* However, there could be other ways to attache a library in a template, such
* as generating and rendering a render array with `#attached`.
*
* @param \Drupal\Core\Extension\Extension $extension
*
* @return \Drupal\upgrade_status\DeprecationMessage[]
*/
private function analyzeTwigLibraryDependencies(Extension $extension): array {
$iterator = new TemplateDirIterator(
new TwigRecursiveIterator($extension->getPath())
);
$deprecations = [];
foreach ($iterator as $name => $contents) {
try {
$libraries = $this->findLibrariesAttachedInTemplate($this->twigEnvironment->parse($this->twigEnvironment->tokenize(new Source($contents, $name))));
foreach ($libraries as $library) {
$is_deprecated = $this->isLibraryDeprecated($library['library']);
if (is_null($is_deprecated)) {
$message = sprintf("The '%s' library is not defined because the defining extension is not installed. Cannot decide if it is deprecated or not.", $library['library']);
$deprecations[] = new DeprecationMessage($message, $name, $library['line'], 'LibraryDeprecationAnalyzer');
}
elseif (!empty($is_deprecated)) {
if ($is_deprecated instanceof DeprecationMessage) {
$is_deprecated->setFile($name);
$deprecations[] = $is_deprecated;
}
else {
$message = 'Template is attaching a deprecated library. ' . $is_deprecated;
$deprecations[] = new DeprecationMessage($message, $name, $library['line'], 'LibraryDeprecationAnalyzer');
}
}
}
} catch (SyntaxError $e) {
// Ignore templates containing syntax errors.
}
}
return $deprecations;
}
/**
* Finds libraries attached using `libraries_attach()` in a Twig template.
*
* @param \Twig\Node\Node $node
*
* @return string[]
*/
private function findLibrariesAttachedInTemplate(Node $node): array {
if (!is_iterable($node)) {
return [];
}
$libraries = [];
foreach ($node as $item) {
if ($item instanceof FunctionExpression) {
if ($item->getAttribute('name') === 'attach_library') {
foreach ($item->getNode('arguments') as $argument) {
if ($argument instanceof ConstantExpression && $argument->hasAttribute('value')) {
$libraries[] = [
'library' => $argument->getAttribute('value'),
'line' => $item->getTemplateLine(),
];
}
}
}
} else {
$libraries = array_merge($libraries, $this->findLibrariesAttachedInTemplate($item));
}
}
return $libraries;
}
/**
* Analyzes libraries referenced in PHP.
*
* This can only analyze statically attached libraries. We are not checking
* the context where the library is being referenced, so in some cases this
* could lead into false negatives. Testing the context would be possible, but
* could lead into not detecting all references to deprecated libraries.
*
* @param \Drupal\Core\Extension\Extension $extension
*
* @return \Drupal\upgrade_status\DeprecationMessage[]
*/
private function analyzePhpLibraryReferences(Extension $extension): array {
$iterator = new \RegexIterator(
new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($extension->getPath()), \RecursiveIteratorIterator::LEAVES_ONLY
), '/\.(php|module|theme|profile|inc)$/'
);
$deprecations = [];
foreach ($iterator as $file) {
if (fnmatch('*/tests/fixtures/*.php', $file->getPathName())) {
continue;
}
try {
$tokens = token_get_all(file_get_contents($file->getPathName()));
} catch (\ParseError $error) {
// Ignore syntax errors.
continue;
}
// Find nodes that look like attaching a library.
$potential_libraries = array_values(
array_map(
function($token) {
list(, $value, $line) = $token;
return [
'value' => substr($value, 1, -1),
'line' => $line,
];
},
array_filter($tokens, function($token) {
if (is_array($token)) {
list($type, $value) = $token;
return ($type === T_CONSTANT_ENCAPSED_STRING && preg_match('/^[\"\'][a-zA-Z0-9\.\-\_]+\/[a-zA-Z0-9\.\-\_]+[\"\']$/', $value));
}
return FALSE;
})
)
);
foreach ($potential_libraries as $potential_library) {
list($extension_name) = explode('/', $potential_library['value'], 2);
$extension_lists = [
$this->moduleExtensionList,
$this->themeExtensionList,
$this->profileExtensionList,
];
// Iterate through all extension lists to see if we have found a valid
// extension.
$valid_extension = array_reduce($extension_lists, function($valid_extension, ExtensionList $extension_list) use($extension_name) {
if ($valid_extension || $extension_list->exists($extension_name)) {
return TRUE;
}
return FALSE;
}, FALSE);
if ($valid_extension) {
$is_deprecated = $this->isLibraryDeprecated($potential_library['value']);
if (is_null($is_deprecated)) {
$message = sprintf("The '%s' library is not defined because the defining extension is not installed. Cannot decide if it is deprecated or not.", $potential_library['value']);
$deprecations[] = new DeprecationMessage($message, $file->getPathName(), $potential_library['line'], 'LibraryDeprecationAnalyzer');
}
elseif (!empty($is_deprecated)) {
if ($is_deprecated instanceof DeprecationMessage) {
$is_deprecated->setFile($file->getPathName());
$deprecations[] = $is_deprecated;
}
else {
$message = "The referenced library is deprecated. $is_deprecated";
$deprecations[] = new DeprecationMessage($message, $file->getPathName(), $potential_library['line'], 'LibraryDeprecationAnalyzer');
}
}
}
}
}
return $deprecations;
}
/**
* Tests if library is deprecated.
*
* @param string $library
* A string representing library. For example, 'node/drupal.node'.
*
* @return bool|string|NULL|DeprecationMessage
* FALSE if the library is not deprecated. NULL if the library's module
* is not enabled. Deprecation message string otherwise.
*/
private function isLibraryDeprecated($library) {
if (!strpos($library, '/')) {
return new DeprecationMessage('The ' . $library . ' library does not have an extension name and is therefore not valid.', '', 0,'LibraryDeprecationAnalyzer');
}
list($extension_name, $library_name) = explode('/', $library, 2);
// Drupal\Core\Asset\LibraryDiscoveryParser::buildByExtension() assumes a
// disabled module is a theme and fails not finding it then, so check if
// the extension identified he is an installed module or theme. The library
// info will not be available otherwise.
if ($extension_name != 'core') {
$installed_modules = array_keys($this->moduleExtensionList->getAllInstalledInfo());
$installed_themes = array_keys($this->themeExtensionList->getAllInstalledInfo());
if (!in_array($extension_name, $installed_modules) && !in_array($extension_name, $installed_themes)) {
return NULL;
}
}
try {
$dependency_libraries = $this->libraryDiscoveryParser->buildByExtension($extension_name);
}
catch (\Exception $e) {
return new DeprecationMessage($e->getMessage(), '', 0, 'LibraryDeprecationAnalyzer');
}
if (isset($dependency_libraries[$library_name]) && isset($dependency_libraries[$library_name]['deprecated'])) {
return str_replace('%library_id%', "$extension_name/$library_name", $dependency_libraries[$library_name]['deprecated']);
}
return FALSE;
}
}
<?php
namespace Drupal\upgrade_status;
use Composer\Semver\VersionParser;
use Composer\Semver\Constraint\Constraint;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Extension\ModuleExtensionList;
use Drupal\Core\Extension\ProfileExtensionList;
use Drupal\Core\Extension\ThemeExtensionList;
use Drupal\Core\Extension\Exception\UnknownExtensionException;
use Drupal\Core\KeyValueStore\KeyValueExpirableFactory;
use Drupal\Core\KeyValueStore\KeyValueExpirableFactoryInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
/**
* Collects projects and their associated metadata collated for Upgrade Status.
*/
class ProjectCollector {
use StringTranslationTrait;
/**
* The list of available modules.
*
* @var \Drupal\Core\Extension\ModuleExtensionList
*/
protected $moduleExtensionList;
/**
* The list of available themes.
*
* @var \Drupal\Core\Extension\ThemeExtensionList
*/
protected $themeExtensionList;
/**
* The list of available profiles.
*
* @var \Drupal\Core\Extension\ProfileExtensionList
*/
protected $profileExtensionList;
/**
* Available updates store.
*
* @var \Drupal\Core\KeyValueStore\KeyValueStoreInterface|mixed
*/
protected $availableUpdates;
/**
* Configuration factory.
*
* @var \Drupal\Core\Config\ConfigFactoryInterface
*/
protected $configFactory;
/**
* The current installation profile.
*
* @var string
*/
private $installProfile;
/**
* Update not checked for a project.
*/
const UPDATE_NOT_CHECKED = 0;
/**
* Update not available for a project.
*/
const UPDATE_NOT_AVAILABLE = 1;
/**
* Update available for a project.
*/
const UPDATE_AVAILABLE = 2;
/**
* The latest version is already being used.
*/
const UPDATE_ALREADY_INSTALLED = 3;
/**
* Custom project.
*/
const TYPE_CUSTOM = 'custom';
/**
* Contributed project.
*/
const TYPE_CONTRIB = 'contrib';
/**
* Suggest to relax.
*/
const NEXT_RELAX = 'relax';
/**
* Suggest to remove.
*/
const NEXT_REMOVE = 'remove';
/**
* Suggest to update.
*/
const NEXT_UPDATE = 'update';
/**
* Suggest to collaborate with maintainer.
*/
const NEXT_COLLABORATE = 'collaborate';
/**
* Suggest to scan for errors.
*/
const NEXT_SCAN = 'scan';
/**
* Suggest to fix with rector.
*/
const NEXT_RECTOR = 'rector';
/**
* Suggest to fix with manually.
*/
const NEXT_MANUAL = 'manual';
/**
* Summary category for things to analyze.
*/
const SUMMARY_ANALYZE = 'analyze';
/**
* Summary category for things to act on.
*/
const SUMMARY_ACT = 'act';
/**
* Summary category for things to act on.
*/
const SUMMARY_RELAX = 'relax';
/**
* Constructs a \Drupal\upgrade_status\ProjectCollector.
*
* @param \Drupal\Core\Extension\ModuleExtensionList $module_extension_list
* The module extension list service.
* @param \Drupal\Core\Extension\ThemeExtensionList $theme_extension_list
* The theme extension handler service.
* @param \Drupal\Core\Extension\ProfileExtensionList $profile_extension_list
* The profile extension handler service.
* @param \Drupal\Core\KeyValueStore\KeyValueExpirableFactoryInterface $key_value_expirable
* The expirable key/value storage.
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The configuration factory.
* @param string $install_profile
* The current installation profile.
*/
public function __construct(
ModuleExtensionList $module_extension_list,
ThemeExtensionList $theme_extension_list,
ProfileExtensionList $profile_extension_list,
KeyValueExpirableFactoryInterface $key_value_expirable,
ConfigFactoryInterface $config_factory,
$install_profile
) {
$this->moduleExtensionList = $module_extension_list;
$this->themeExtensionList = $theme_extension_list;
$this->profileExtensionList = $profile_extension_list;
$this->availableUpdates = $key_value_expirable->get('update_available_releases');
$this->configFactory = $config_factory;
$this->installProfile = $install_profile;
}
/**
* Reset all extension lists so their data is regenerated.
*/
public function resetLists() {
$this->moduleExtensionList->reset();
$this->themeExtensionList->reset();
$this->profileExtensionList->reset();
}
/**
* Collect projects of installed modules grouped by custom and contrib.
*
* @return \Drupal\Core\Extension\Extension[]
* An array keyed by project names. Extensions selected as projects
* without a defined project name get one based on their topmost parent
* extension and only that topmost extension gets included in the list.
*/
public function collectProjects() {
$projects = [];
$modules = $this->moduleExtensionList->getList();
$themes = $this->themeExtensionList->getList();
$profiles = $this->profileExtensionList->getList();
$extensions = array_merge($modules, $themes, $profiles);
unset($modules, $themes, $profiles);
$update_check_for_uninstalled = $this->configFactory->get('update.settings')->get('check.disabled_extensions');
/** @var \Drupal\Core\Extension\Extension $extension */
foreach ($extensions as $key => $extension) {
if ($extension->origin === 'core') {
// Ignore core extensions for the sake of upgrade status.
continue;
}
// If the project is already specified in this extension, use that.
$project = isset($extension->info['project']) ? $extension->info['project'] : '';
if (isset($projects[$project])) {
// If we already have a representative of this project in the list,
// don't add this extension.
// @todo Make sure to use the extension with the shortest file path.
// If the existing project was already Drupal 9 compatible, consider
// this subcomponent as well. If this component was enabled, it would
// affect how we consider the Drupal 9 compatibility.
if (!empty($projects[$project]->info['upgrade_status_next_major_compatible']) && !empty($extension->status)) {
// Overwrite compatibility. If this is still compatible, it will
// keep being TRUE, otherwise FALSE.
$projects[$project]->info['upgrade_status_next_major_compatible'] =
isset($extension->info['core_version_requirement']) &&
self::isCompatibleWithNextMajorDrupal($extension->info['core_version_requirement']);
}
continue;
}
if ((strpos($key, 'upgrade_status') === 0) && !drupal_valid_test_ua()) {
// Don't add the Upgrade Status modules to the list if not in tests.
// Upgrade status is a temporary site component and does have
// intentional deprecated API use for the sake of testing. Avoid
// distracting site owners with this.
continue;
}
// Attempt to identify if the project was contrib based on the directory
// structure it is in. Extension placement is not a mandatory requirement
// and theoretically this could lead to false positives, but if
// composer_deploy or git_deploy is not available (and/or did not
// identify the project for us), this is all we can do. Ignore our test
// modules for this scenario.
if (empty($project)) {
$type = self::TYPE_CUSTOM;
if (strpos($extension->getPath(), '/contrib/') && (strpos($key, 'upgrade_status_test_') !== 0)) {
$type = self::TYPE_CONTRIB;
}
}
// Extensions that have the 'drupal' project but did not have the 'core'
// origin assigned are custom extensions that are running in a Drupal
// core git checkout, so also categorize them as custom.
elseif ($project === 'drupal') {
$type = self::TYPE_CUSTOM;
}
else {
$type = self::TYPE_CONTRIB;
}
// Add additional information to the extension info for our tracking.
// Keep this on a cloned extension object so we are not polluting runtime
// extension information elsewhere.
$extdata = clone $extension;
$extdata->info['upgrade_status_type'] = $type;
$extdata->info['upgrade_status_next_major_compatible'] =
isset($extdata->info['core_version_requirement']) &&
self::isCompatibleWithNextMajorDrupal($extdata->info['core_version_requirement']);
// Save this as a possible project to consider.
$projects[$key] = $extdata;
}
// Collate extensions to projects, removing sub-extensions.
$projects = $this->collateExtensionsIntoProjects($projects);
// After the collation is done, assign project names based on the topmost
// extension. While this is not always right for drupal.org projects, this
// is the best guess we have.
foreach ($projects as $name => $extension) {
if (!isset($extension->info['project'])) {
$projects[$name]->info['project'] = $name;
}
// Add available update information to contrib projects found.
if ($extension->info['upgrade_status_type'] == self::TYPE_CONTRIB) {
// Look up by drupal.org project info not $name because the two may be different.
$project_update = $this->availableUpdates->get($extension->info['project']);
if (!isset($project_update['releases']) || is_null($project_update['releases'])) {
// Releases were either not checked or not available.
$projects[$name]->info['upgrade_status_update'] = $update_check_for_uninstalled ? self::UPDATE_NOT_AVAILABLE : self::UPDATE_NOT_CHECKED;
}
else {
// Add Drupal 9 compatibility info from the update's data.
$latest_release = reset($project_update['releases']);
$projects[$name]->info['upgrade_status_update_compatible'] = FALSE;
if (!empty($latest_release['core_compatibility']) && self::isCompatibleWithNextMajorDrupal($latest_release['core_compatibility'])) {
$projects[$name]->info['upgrade_status_update_compatible'] = TRUE;
}
// Denormalize update info into the extension info for our own use.
if ($extension->info['version'] !== $latest_release['version']) {
$projects[$name]->info['upgrade_status_update'] = self::UPDATE_AVAILABLE;
$link = $project_update['link'] . '/releases/' . $latest_release['version'];
$projects[$name]->info['upgrade_status_update_link'] = $link;
$projects[$name]->info['upgrade_status_update_version'] = $latest_release['version'];
}
else {
// If the current version is already the latest, store that.
$projects[$name]->info['upgrade_status_update'] = self::UPDATE_ALREADY_INSTALLED;
}
}
}
// Get scan results if there was any.
$scan_result = $this->getResults($name);
// Pick a suggested next step for this project.
if ($extension->info['upgrade_status_next_major_compatible'] && $extension->info['upgrade_status_type'] == self::TYPE_CONTRIB) {
// If the project was contrib and already Drupal 9 compatible, relax.
$extension->info['upgrade_status_next'] = self::NEXT_RELAX;
}
elseif (empty($extension->status) && ($name != $this->installProfile)) {
// Uninstalled extensions should be removed. Except if this is the
// profile. See https://www.drupal.org/project/drupal/issues/1170362
$extension->info['upgrade_status_next'] = self::NEXT_REMOVE;
}
elseif (isset($extension->info['upgrade_status_update']) && $extension->info['upgrade_status_update'] == self::UPDATE_AVAILABLE) {
// If there was a Drupal 9 compatible update or even a yet incompatible
// update to this project, the best course of action is to update to
// that, since that should move closer to Drupal 9 compatibility.
$extension->info['upgrade_status_next'] = self::NEXT_UPDATE;
}
elseif ($extension->info['upgrade_status_type'] == self::TYPE_CONTRIB) {
// For installed contributed modules that do not have compatible updates, collaborate.
$extension->info['upgrade_status_next'] = self::NEXT_COLLABORATE;
}
else {
// If there was no scanning result yet, next step is to scan this project.
if (empty($scan_result) || empty($scan_result['data']['totals']['upgrade_status_next'])) {
$extension->info['upgrade_status_next'] = self::NEXT_SCAN;
}
// If there were scanning results, carry over the next step suggestion from there.
else {
$extension->info['upgrade_status_next'] = $scan_result['data']['totals']['upgrade_status_next'];
}
}
}
return $projects;
}
/**
* Collect core modules that are installed and obsolete or deprecated.
*
* @return array
* An associated array of extension names keyed by extension machine names.
*/
public function collectCoreDeprecatedAndObsoleteExtensions() {
$deprecated_or_obsolete = [];
$modules = $this->moduleExtensionList->getList();
$themes = $this->themeExtensionList->getList();
$profiles = $this->profileExtensionList->getList();
$extensions = array_merge($modules, $themes, $profiles);
unset($modules, $themes, $profiles);
/** @var \Drupal\Core\Extension\Extension $extension */
foreach ($extensions as $key => $extension) {
if (!empty($extension->status) && $extension->origin === 'core' && !empty($extension->info['lifecycle']) && in_array($extension->info['lifecycle'], ['deprecated', 'obsolete'])) {
$prefix = '';
$suffix = '';
if (isset($extension->info['lifecycle_link'])) {
$prefix = '<a href="' . $extension->info['lifecycle_link'] . '">';
$suffix = ' (' . $this->t('read more') . ')</a>';
}
$deprecated_or_obsolete[$key] = $prefix . $extension->info['name'] . $suffix;
}
}
return $deprecated_or_obsolete;
}
/**
* Finds topmost extension for each extension and keeps only that.
*
* @param \Drupal\Core\Extension\Extension[] $extensions
* List of all enabled extensions.
*
* @return \Drupal\Core\Extension\Extension[]
* List of extensions, with only the topmost extension left for each
* extension that has a parent extension.
*/
protected function collateExtensionsIntoProjects(array $extensions) {
foreach ($extensions as $name_a => $extension_a) {
$path_a = $extension_a->getPath() . '/';
$path_a_length = strlen($path_a);
foreach ($extensions as $name_b => $extension_b) {
// Skip collation for test modules except where we test that.
if ((strpos($name_b, 'upgrade_status_test_') === 0) && ($name_b != 'upgrade_status_test_submodules_a') && ($name_b != 'upgrade_status_test_submodules_with_errors_a')) {
continue;
}
$path_b = $extension_b->getPath();
// If the extension is not the same but the beginning of paths match,
// remove this extension from the list as it is part of another one.
if ($name_b != $name_a && substr($path_b, 0, $path_a_length) === $path_a) {
// If the existing project was already Drupal 9 compatible, consider
// this subcomponent as well. If this component was enabled, it would
// affect how we consider the Drupal 9 compatibility.
if (!empty($extensions[$name_a]->info['upgrade_status_next_major_compatible']) && !empty($extension_b->status)) {
// Overwrite compatibility. If this is still compatible, it will
// keep being TRUE, otherwise FALSE.
$extensions[$name_a]->info['upgrade_status_next_major_compatible'] =
isset($extension_b->info['core_version_requirement']) &&
self::isCompatibleWithNextMajorDrupal($extension_b->info['core_version_requirement']);
}
// Remove the subextension.
unset($extensions[$name_b]);
}
}
}
return $extensions;
}
/**
* Returns a single extension based on type and machine name.
*
* @param string $project_machine_name
* Machine name for the extension.
*
* @return \Drupal\Core\Extension\Extension
* A project if exists.
*
* @throws \Drupal\Core\Extension\Exception\UnknownExtensionException
* If there was no identified project with the given name.
*/
public function loadProject(string $project_machine_name) {
$projects = $this->collectProjects();
if (!empty($projects[$project_machine_name])) {
return $projects[$project_machine_name];
}
throw new UnknownExtensionException("The {$project_machine_name} project does not exist.");
}
/**
* Get local scanning results for a project.
*
* @param string $project_machine_name
* Machine name for project.
*
* @return mixed
* - NULL if there was no result
* - Associative array of results otherwise
*/
public function getResults(string $project_machine_name) {
// Always use a fresh service. An injected service could get stale results
// because scan result saving happens in different HTTP requests for most
// cases (when analysis was successful).
return \Drupal::service('keyvalue')->get('upgrade_status_scan_results')->get($project_machine_name) ?: NULL;
}
/**
* Return list of possible next steps and their labels and descriptions.
*
* @return array
* Associative array keys by next step identifier. Values are arrays
* where the first item is a label an the second is a description.
*/
public function getNextStepInfo() {
return [
ProjectCollector::NEXT_REMOVE => [
$this->t('Remove'),
$this->t('The likely best action is to remove projects that are uninstalled. Why invest in updating them to be compatible if you are not using them?'),
ProjectCollector::SUMMARY_ACT,
'color-warning ' . ProjectCollector::NEXT_REMOVE
],
ProjectCollector::NEXT_UPDATE => [
$this->t('Update'),
$this->t('There is an update available. Even if that is not fully compatible with the next major Drupal core, it may be more compatible than what you have, so best to start with updating first.'),
ProjectCollector::SUMMARY_ACT,
'color-warning ' . ProjectCollector::NEXT_REMOVE
],
ProjectCollector::NEXT_SCAN => [
$this->t('Scan'),
$this->t('Status of this project cannot be determined without scanning the source code here. Use this form to run a scan on these.'),
ProjectCollector::SUMMARY_ANALYZE,
'color-warning ' . ProjectCollector::NEXT_REMOVE
],
ProjectCollector::NEXT_COLLABORATE => [
$this->t('Collaborate with maintainers'),
$this->t('There may be Drupal.org issues by contributors or even <a href=":drupal-bot">the Project Update Bot</a>. Work with the maintainer to get them committed, provide feedback if they worked.', [':drupal-bot' => 'https://www.drupal.org/u/project-update-bot']),
ProjectCollector::SUMMARY_ACT,
'color-warning ' . ProjectCollector::NEXT_REMOVE
],
ProjectCollector::NEXT_RECTOR => [
$this->t('Fix with rector'),
$this->t('Some or all problems found can be fixed automatically with <a href=":drupal-rector">drupal-rector</a>. Make the machine do the work.', [':drupal-rector' => 'https://www.drupal.org/project/rector']),
ProjectCollector::SUMMARY_ACT,
'color-error ' . ProjectCollector::NEXT_REMOVE
],
ProjectCollector::NEXT_MANUAL => [
$this->t('Fix manually'),
$this->t('It looks like there is no automated fixes for either problems found. Check the report for pointers on how to fix.'),
ProjectCollector::SUMMARY_ACT,
'color-error ' . ProjectCollector::NEXT_REMOVE
],
ProjectCollector::NEXT_RELAX => [
$this->t('Compatible with next major Drupal core version'),
$this->t('Well done. Congrats! Let\'s get everything else here!'),
ProjectCollector::SUMMARY_RELAX,
'color-success ' . ProjectCollector::NEXT_REMOVE
],
];
}
/**
* Checks constraint compatibility with the next major Drupal core version.
*
* A customized version of Semver::satisfies(), since that only works for
* a == condition.
*
* @param string $constraints
* Composer compatible constraints from core_version_requirement or
* drupal/core requirement.
*
* @return bool
*/
public static function isCompatibleWithNextMajorDrupal(string $constraints) {
$version_parser = new VersionParser();
$provider = new Constraint('>=', $version_parser->normalize((self::getDrupalCoreMajorVersion() + 1) . '.0.0'));
$parsed_constraints = $version_parser->parseConstraints($constraints);
return $parsed_constraints->matches($provider);
}
/**
* Checks constraint compatibility with a PHP version.
*
* A customized version of Semver::satisfies(), since that only works for
* a == condition.
*
* @param string $constraints
* Composer compatible constraints from a PHP version requirement.
* @param string $php
* Optional PHP version number. Defaults to 8.0.0.
*
* @return bool
*/
public static function isCompatibleWithPHP(string $constraints, string $php = '8.0.0') {
$version_parser = new VersionParser();
$provider = new Constraint('>=', $version_parser->normalize($php));
$parsed_constraints = $version_parser->parseConstraints($constraints);
return $parsed_constraints->matches($provider);
}
/**
* Return the oldest supported minor version for the current core major.
*
* @return string
* Oldest supported core version number.
*/
public static function getOldestSupportedMinor(): string {
$major = (int) \Drupal::VERSION;
switch ($major) {
case 9:
return '9.5';
case 10:
return '10.2';
case 11:
return '11.0';
}
return '';
}
/**
* Returns current core's major version.
*
* @return int
* Version converted to int.
*/
public static function getDrupalCoreMajorVersion(): int {
return (int) \Drupal::VERSION;
}
}
<?php
declare(strict_types=1);
namespace Drupal\upgrade_status;
use Drupal\Core\Extension\Extension;
/**
* The route deprecation analyzer.
*/
final class RouteDeprecationAnalyzer {
/**
* Analyzes usages of deprecated route elements in an extension.
*
* @param \Drupal\Core\Extension\Extension $extension
* The extension to be analyzed.
*
* @return \Drupal\upgrade_status\DeprecationMessage[]
* A list of deprecation messages.
*
* @throws \Exception
*/
public function analyze(Extension $extension): array {
$deprecations = [];
$routing_files = $this->getAllRoutingFiles(DRUPAL_ROOT . '/' . $extension->getPath());
foreach ($routing_files as $routing_file) {
$content = file_get_contents($routing_file);
if (strpos($content, '_access_node_revision')) {
$deprecations[] = new DeprecationMessage('The _access_node_revision routing requirement is deprecated in drupal:9.3.0 and is removed from drupal:10.0.0. Use _entity_access instead. See https://www.drupal.org/node/3161210.', $routing_file, 0, 'RouteDeprecationAnalyzer');
}
if (strpos($content, '_access_media_revision')) {
$deprecations[] = new DeprecationMessage('The _access_media_revision routing requirement is deprecated in drupal:9.3.0 and is removed from drupal:10.0.0. Use _entity_access instead. See https://www.drupal.org/node/3161210.', $routing_file, 0, 'RouteDeprecationAnalyzer');
}
}
return $deprecations;
}
/**
* Finds all .routing.yml files for non-test extensions under a path.
*
* @param string $path
* Base path to find all .routing.yml files in.
*
* @return array
* A list of paths to .routing.yml files found under the base path.
*/
private function getAllRoutingFiles(string $path) {
$files = [];
foreach(glob($path . '/*.routing.yml') as $file) {
// Make sure the filename matches rules for an extension. There may be
// routing.yml files in shipped configuration which would have more parts.
$parts = explode('.', basename($file));
if (count($parts) == 3) {
$files[] = $file;
}
}
foreach (glob($path . '/*', GLOB_ONLYDIR|GLOB_NOSORT) as $dir) {
$files = array_merge($files, $this->getAllRoutingFiles($dir));
}
return $files;
}
}
<?php
namespace Drupal\upgrade_status;
use Drupal\Component\Datetime\TimeInterface;
use Drupal\Core\Datetime\DateFormatterInterface;
use Drupal\Core\Extension\Extension;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\KeyValueStore\KeyValueFactoryInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\Url;
use dekor\ArrayToTextTable;
/**
* Format scan results for display or export.
*/
class ScanResultFormatter {
use StringTranslationTrait;
/**
* Upgrade status scan result storage.
*
* @var \Drupal\Core\KeyValueStore\KeyValueStoreInterface
*/
protected $scanResultStorage;
/**
* The date formatter service.
*
* @var \Drupal\Core\Datetime\DateFormatterInterface
*/
protected $dateFormatter;
/**
* The time service.
*
* @var \Drupal\Component\Datetime\TimeInterface
*/
protected $time;
/**
* The module handler.
*
* @var \Drupal\Core\Extension\ModuleHandlerInterface
*/
protected $moduleHandler;
/**
* Constructs a \Drupal\upgrade_status\Controller\ScanResultFormatter.
*
* @param \Drupal\Core\KeyValueStore\KeyValueFactoryInterface $key_value_factory
* The key/value factory.
* @param \Drupal\Core\Datetime\DateFormatterInterface $dateFormatter
* The date formatter service.
* @param \Drupal\Component\Datetime\TimeInterface $time
* The time service.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler.
*/
public function __construct(
KeyValueFactoryInterface $key_value_factory,
DateFormatterInterface $dateFormatter,
TimeInterface $time,
ModuleHandlerInterface $module_handler
) {
$this->scanResultStorage = $key_value_factory->get('upgrade_status_scan_results');
$this->dateFormatter = $dateFormatter;
$this->time = $time;
$this->moduleHandler = $module_handler;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('keyvalue'),
$container->get('date.formatter'),
$container->get('datetime.time'),
$container->get('module_handler')
);
}
/**
* Get scanning result for an extension.
*
* @param \Drupal\Core\Extension\Extension $extension
* Drupal extension object.
* @return null|array
* Scan results array or null if no scan results are saved.
*/
public function getRawResult(Extension $extension) {
return $this->scanResultStorage->get($extension->getName()) ?: NULL;
}
/**
* Format results output for an extension.
*
* @param \Drupal\Core\Extension\Extension $extension
* Drupal extension object.
*
* @return array
* Build array.
*/
public function formatResult(Extension $extension) {
$result = $this->getRawResult($extension);
$info = $extension->info;
$label = $info['name'] . (!empty($info['version']) ? ' ' . $info['version'] : '');
// This project was not yet scanned or the scan results were removed.
if (empty($result)) {
return [
'#title' => $label,
'result' => [
'#type' => 'markup',
'#markup' => $this->t(
'No deprecation scanning data available. <a href="@url">Go to the Upgrade Status form</a>.',
[
'@url' => Url::fromRoute('upgrade_status.report')->toString()
]
),
],
];
}
if (isset($result['data']['totals'])) {
$project_error_count = $result['data']['totals']['file_errors'];
}
else {
$project_error_count = 0;
}
$build = [
'#attached' => ['library' => ['upgrade_status/upgrade_status.admin']],
'#title' => $label,
'date' => [
'#type' => 'markup',
'#markup' => '<div class="list-description">' . $this->t('Scanned on @date.', ['@date' => $this->dateFormatter->format($result['date'])]) . '</div>',
'#weight' => -10,
],
];
// If this project had no known issues found, report that.
if ($project_error_count === 0) {
$build['data'] = [
'#type' => 'markup',
'#markup' => $this->t('No known issues found.'),
'#weight' => 5,
];
return $build;
}
// Otherwise prepare list of errors in groups.
$groups = [];
foreach ($result['data']['files'] as $filepath => $errors) {
foreach ($errors['messages'] as $error) {
// Remove the Drupal root directory. If this is a composer setup, then
// the webroot is in a web/ directory, add that back in for easy path
// copy-pasting.
$short_path = str_replace(DRUPAL_ROOT . '/', '', $filepath);
if (preg_match('!/web$!', DRUPAL_ROOT)) {
$short_path = 'web/' . $short_path;
}
// Allow paths and namespaces to wrap. Emphasize filename as it may
// show up in the middle of the info
$short_path = str_replace('/', '/<wbr>', $short_path);
if (strpos($short_path, 'in context of')) {
$short_path = preg_replace('!/([^/]+)( \(in context of)!', '/<strong>\1</strong>\2', $short_path);
$short_path = str_replace('\\', '\\<wbr>', $short_path);
}
else {
$short_path = preg_replace('!/([^/]+)$!', '/<strong>\1</strong>', $short_path);
}
// @todo could be more accurate with reflection but not sure it is even possible as the reflected
// code may not be in the runtime at this point (eg. functions in include files)
// see https://www.php.net/manual/en/reflectionfunctionabstract.getfilename.php
// see https://www.php.net/manual/en/reflectionclass.getfilename.php
// Link to documentation for a function in this specific Drupal version.
$api_version = preg_replace('!^(8\.\d+)\..+$!', '\1', \Drupal::VERSION) . '.x';
$api_link = 'https://api.drupal.org/api/drupal/' . $api_version . '/search/';
$formatted_error = preg_replace('!deprecated function ([^(]+)\(\)!', 'deprecated function <a target="_blank" href="' . $api_link . '\1">\1()</a>', $error['message']);
// Replace deprecated class links.
if (preg_match('!class (Drupal\\\\\S+)\.( |$)!', $formatted_error, $found)) {
if (preg_match('!Drupal\\\\([a-z_0-9A-Z]+)\\\\(.+)$!', $found[1], $namespace)) {
$path_parts = explode('\\', $namespace[2]);
$class = array_pop($path_parts);
if (in_array($namespace[1], ['Component', 'Core'])) {
$class_file = 'core!lib!Drupal!' . $namespace[1];
}
elseif (in_array($namespace[1], ['KernelTests', 'FunctionalTests', 'FunctionalJavascriptTests', 'Tests'])) {
$class_file = 'core!tests!Drupal!' . $namespace[1];
}
else {
$class_file = 'core!modules!' . $namespace[1] . '!src';
}
if (count($path_parts)) {
$class_file .= '!' . join('!', $path_parts);
}
$class_file .= '!' . $class . '.php';
$api_link = 'https://api.drupal.org/api/drupal/' . $class_file . '/class/' . $class . '/' . $api_version;
$formatted_error = str_replace($found[1], '<a target="_blank" href="' . $api_link . '">' . $found[1] . '</a>', $formatted_error);
}
}
// Allow error messages to wrap.
$formatted_error = str_replace('\\', '\\<wbr>', $formatted_error);
// Make drupal.org documentation links clickable.
$formatted_error = preg_replace('!See (https://(www.)?drupal.org\S*?)(\.|\s|$)!', 'See <a href="\1">\1</a>\3', $formatted_error);
// Format core_version_requirement message.
$formatted_error = preg_replace('!(core_version_requirement: .+) (to designate|is not)!', '<code>\1</code> \2', $formatted_error);
$category = 'uncategorized';
if (!empty($error['upgrade_status_category'])) {
if (in_array($error['upgrade_status_category'], ['safe', 'old'])) {
$category = 'now';
}
else {
$category = $error['upgrade_status_category'];
}
}
@$groups[$category][] = [
'filename' => [
'#type' => 'markup',
'#markup' => $short_path,
'#wrapper_attributes' => [
'class' => ['status-info'],
]
],
'line' => [
'#type' => 'markup',
'#markup' => $error['line'],
],
'issue' => [
'#type' => 'markup',
'#markup' => $formatted_error,
],
];
}
}
$build['groups'] = [
'#weight' => 100,
];
$group_help = [
'rector' => [
$this->t('Fix now with automation'),
'color-warning rector-covered',
$this->t('Avoid some manual work by using <a href="@drupal-rector">drupal-rector to fix issues automatically</a>.', ['@drupal-rector' => 'https://www.drupal.org/project/rector']),
],
'now' => [
$this->t('Fix now manually'),
'color-error',
$this->t('It does not seem like these are covered by automation yet. <a href="@drupal-rector">Contribute to drupal-rector to provide coverage</a>. Fix manually in the meantime.', ['@drupal-rector' => 'https://www.drupal.org/project/rector']),
],
'uncategorized' => [
$this->t('Check manually'),
'color-warning',
$this->t('Errors without Drupal source version numbers including parse errors and use of APIs from dependencies.'),
],
'later' => [
$this->t('Fix later'),
'color-warning known-later',
// Issues to fix later need different guidance based on whether they
// were found in a contributed project or a custom project.
!empty($extension->info['project']) ?
$this->t('Based on the Drupal deprecation version number of these, fixing them may make the contributed project incompatible with supported Drupal core versions.') :
$this->t('Based on the Drupal deprecation version number of these, fixing them will likely make them incompatible with your current Drupal version.')
],
'ignore' => [
$this->t('Ignore'),
'color-warning known-ignore',
$this->t('Deprecated API use for APIs removed in future Drupal major versions is not required to fix yet.'),
],
];
foreach ($group_help as $group_key => $group_info) {
if (empty($groups[$group_key])) {
// Skip this group if there was no error to display.
continue;
}
$build['groups'][$group_key] = [
'#prefix' => '<div class="upgrade-status-project-result-group">',
'#suffix' => '</div>',
'title' => [
'#type' => 'markup',
'#markup' => '<h3>' . $group_info[0] . '</h3>',
],
'description' => [
'#type' => 'markup',
'#markup' => '<div class="description">' . $group_info[2] . '</div>',
],
'errors' => [
'#type' => 'table',
'#header' => [
'filename' => $this->t('File name'),
'line' => $this->t('Line'),
'issue' => $this->t('Error'),
],
],
];
foreach ($groups[$group_key] as $item) {
$item['#attributes']['class'] = [$group_info[1]];
$build['groups'][$group_key]['errors'][] = $item;
}
// All modules (thinking of Upgrade Rector here primarily) to alter
// results display.
$this->moduleHandler->alter('upgrade_status_result', $build['groups'][$group_key], $extension, $group_key);
}
$summary = [];
if (!empty($result['data']['totals']['upgrade_status_split']['error'])) {
$summary[] = $this->formatPlural($result['data']['totals']['upgrade_status_split']['error'], '@count error found.', '@count errors found.');
}
if (!empty($result['data']['totals']['upgrade_status_split']['warning'])) {
$summary[] = $this->formatPlural($result['data']['totals']['upgrade_status_split']['warning'], '@count warning found.', '@count warnings found.');
}
$build['summary'] = [
'#type' => '#markup',
'#markup' => '<div class="list-description">' . join(' ', $summary) . '</div>',
'#weight' => 5,
];
$build['export'] = [
'#type' => 'link',
'#title' => $this->t('Export as HTML'),
'#name' => 'export',
'#url' => Url::fromRoute(
'upgrade_status.export',
[
'type' => $extension->getType(),
'project_machine_name' => $extension->getName(),
'format' => 'html',
]
),
'#attributes' => [
'class' => [
'button',
'button--primary',
],
],
'#weight' => 200,
];
$build['export_ascii'] = [
'#type' => 'link',
'#title' => $this->t('Export as text'),
'#name' => 'export_ascii',
'#url' => Url::fromRoute(
'upgrade_status.export',
[
'type' => $extension->getType(),
'project_machine_name' => $extension->getName(),
'format' => 'ascii',
]
),
'#attributes' => [
'class' => [
'button',
'button--primary',
],
],
'#weight' => 200,
];
return $build;
}
/**
* Format results output for an extension as ASCII.
*
* @return array
* Build array.
*/
public function formatAsciiResult(Extension $extension) {
$result = $this->getRawResult($extension);
$info = $extension->info;
$label = $info['name'] . (!empty($info['version']) ? ' ' . $info['version'] : '');
// This project was not yet scanned or the scan results were removed.
if (empty($result)) {
return [
'#title' => $label,
'data' => [
'#type' => 'markup',
'#markup' => $this->t('No deprecation scanning data available.'),
],
];
}
if (isset($result['data']['totals'])) {
$project_error_count = $result['data']['totals']['file_errors'];
}
else {
$project_error_count = 0;
}
$build = [
'#title' => $label,
'date' => [
'#type' => 'markup',
'#markup' => wordwrap($this->t('Scanned on @date.', ['@date' => $this->dateFormatter->format($result['date'])]), 80, "\n", true),
'#weight' => -10,
],
];
// If this project had no known issues found, report that.
if ($project_error_count === 0) {
$build['data'] = [
'#type' => 'markup',
'#markup' => $this->t('No known issues found.'),
'#weight' => 5,
];
return $build;
}
// Otherwise prepare list of errors in tables.
$tables = '';
$hasFixRector = FALSE;
foreach ($result['data']['files'] as $filepath => $errors) {
// Remove the Drupal root directory name. If this is a composer setup,
// then the webroot is in a web/ directory, add that back in for easy
// path copy-pasting.
$short_path = str_replace(DRUPAL_ROOT . '/', '', $filepath);
if (preg_match('!/web$!', DRUPAL_ROOT)) {
$short_path = 'web/' . $short_path;
}
$short_path = wordwrap($short_path, 80, "\n", TRUE);
$tables .= $short_path . ":\n";
$table = [];
foreach ($errors['messages'] as $error) {
$level_label = $this->t('Check manually');
if (!empty($error['upgrade_status_category'])) {
if ($error['upgrade_status_category'] == 'ignore') {
$level_label = $this->t('Ignore');
}
elseif ($error['upgrade_status_category'] == 'later') {
$level_label = $this->t('Fix later');
}
elseif (in_array($error['upgrade_status_category'], ['safe', 'old'])) {
$level_label = $this->t('Fix now');
}
elseif ($error['upgrade_status_category'] == 'rector') {
$level_label = $this->t('Fix with rector');
$hasFixRector = TRUE;
}
}
$message = str_replace("\n", ' ', $error['message']);
$table[] = [
'status' => wordwrap($level_label, 8, "\n", true),
'line' => wordwrap($error['line'], 7, "\n", true),
'message' => wordwrap($message . "\n", 60, "\n", true)
];
}
$asciiRenderer = new ArrayToTextTable($table);
$tables .= $asciiRenderer->render() . "\n";
}
$build['data'] = $tables;
$summary = [];
if (!empty($result['data']['totals']['upgrade_status_split']['error'])) {
$summary[] = $this->formatPlural($result['data']['totals']['upgrade_status_split']['error'], '@count error found.', '@count errors found.');
}
if (!empty($result['data']['totals']['upgrade_status_split']['warning'])) {
$summary[] = $this->formatPlural($result['data']['totals']['upgrade_status_split']['warning'], '@count warning found.', '@count warnings found.');
}
if ($hasFixRector) {
$summary[] = $this->t('Avoid some manual work by using drupal-rector for fixing issues automatically or Upgrade Rector to generate patches.');
}
$build['summary'] = [
'#type' => '#markup',
'#markup' => wordwrap(join(' ', $summary), 80, "\n", true),
'#weight' => 5,
];
return $build;
}
/**
* Format date/time.
*
* @param int $time
* (optional) Timestamp. Current time used if not specified.
* @param string $format
* (optional) Format identifier. Default format is used it not specified.
*
* @return string
* Formatted date/time.
*/
public function formatDateTime($time = 0, $format = '') {
if (empty($time)) {
$time = $this->time->getCurrentTime();
}
return $this->dateFormatter->format($time, $format);
}
}
<?php
declare(strict_types=1);
namespace Drupal\upgrade_status;
use Drupal\Core\Cache\NullBackend;
use Drupal\Core\Extension\Extension;
use Drupal\Core\Theme\Registry;
use PhpParser\Error;
use PhpParser\Node;
use PhpParser\NodeFinder;
use PhpParser\ParserFactory;
use PhpParser\PhpVersion;
use PhpParser\Node\Expr\ArrayDimFetch;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\Stmt\Function_;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* A theme function deprecation analyzer.
*
* @todo Remove once Drupal 8 to 9 deprecations are not a focus anymore.
* This is not dependent on Drupal 8 core itself though, so we can keep
* it in Drupal 9 to 10 for the sake of exposing extremely outdated code.
*/
final class ThemeFunctionDeprecationAnalyzer {
/**
* The service container.
*
* @var \Symfony\Component\DependencyInjection\ContainerInterface
*/
private $container;
/**
* Constructs a new theme function deprecation analyzer.
*
* @param \Symfony\Component\DependencyInjection\ContainerInterface $this->container
* The service container.
*/
public function __construct(ContainerInterface $container) {
$this->container = $container;
}
/**
* Analyzes theme functions in an extension.
*
* @param \Drupal\Core\Extension\Extension $extension
* The extension to be analyzed.
*
* @return \Drupal\upgrade_status\DeprecationMessage[]
*/
public function analyze(Extension $extension): array {
$deprecation_messages = [];
// Analyze hook_theme and hook_theme_registry_alter functions.
$deprecation_messages = array_merge($deprecation_messages, $this->analyzeFunction($extension->getName() . '_' . 'theme', $extension));
$deprecation_messages = array_merge($deprecation_messages, $this->analyzeFunction($extension->getName() . '_' . 'theme_registry_alter', $extension));
// If a theme is being analyzed, theme function overrides need to be
// analyzed.
if ($extension->getType() === 'theme') {
// Create new instance of theme registry to ensure that we have the most
// recent data without having to make changes to the production theme
// registry.
$theme_registry = new Registry($this->container->get('app.root'), new NullBackend('null'), $this->container->get('lock'), $this->container->get('module_handler'), $this->container->get('theme_handler'), $this->container->get('theme.initialization'), $extension->getName());
$theme_registry->setThemeManager($this->container->get('theme.manager'));
$theme_hooks = $theme_registry->get();
$theme_function_overrides = drupal_find_theme_functions($theme_hooks, [$extension->getName()]);
foreach ($theme_function_overrides as $machine_name => $theme_function_override) {
try {
$function = new \ReflectionFunction($extension->getName() . '_' . $machine_name);
$file = $function->getFileName();
$line = $function->getStartLine();
$deprecation_messages[$extension->getName() . '_' . $machine_name] = new DeprecationMessage(sprintf('The theme is overriding the "%s" theme function. Theme functions are deprecated. For more info, see https://www.drupal.org/node/2575445.', $machine_name), $file, $line, 'ThemeFunctionDeprecationAnalyzer');
} catch (\ReflectionException $e) {
// This should never happen because drupal_find_theme_functions()
// ensures that the function exists.
}
}
}
return $deprecation_messages;
}
/**
* Analyzes function for definition of theme functions.
*
* This doesn't recognize functions in all edge cases. For example, theme
* functions could be generated dynamically in a number of different ways.
* However, this will be useful in most use cases.
*
* @param $function
* The function to be analyzed.
* @param \Drupal\Core\Extension\Extension $extension
* The extension that is being tested.
*
* @return \Drupal\upgrade_status\DeprecationMessage[]
*/
private function analyzeFunction(string $function, Extension $extension): array {
$deprecation_messages = [];
try {
$function_reflection = new \ReflectionFunction($function);
} catch (\ReflectionException $e) {
// Not all extensions implement theme hooks.
return [];
}
$parser_factory = new ParserFactory();
if (method_exists($parser_factory, 'create')) {
$parser = $parser_factory->create(ParserFactory::PREFER_PHP7);
}
else {
$parser = $parser_factory->createForVersion(PhpVersion::fromString("7.4"));
}
try {
$ast = $parser->parse(file_get_contents($function_reflection->getFileName()));
} catch (Error $error) {
// The function cannot be evaluated because of a syntax error.
$deprecation_messages[] = new DeprecationMessage(sprintf('Parse error while processing the %s hook implementation.', $function), $function_reflection->getFileName(), $function_reflection->getStartLine(), 'ThemeFunctionDeprecationAnalyzer');
}
if (!is_iterable($ast)) {
return [];
}
$finder = new NodeFinder();
// Find the node for the function that is being analyzed.
$function_node = $finder->findFirst($ast, function (Node $node) use ($function) {
return ($node instanceof Function_ && isset($node->name) && $node->name->name === $function);
});
if (!$function_node) {
// This should never happen because the file has been loaded based on the
// existence of the function.
return [];
}
// Find theme functions that have been defined using the array syntax.
// @code
// function hook_theme() {
// return [
// 'theme_hook' => ['function' => theme_function'],
// ];
// }
// @endcode
$theme_function_nodes = $finder->find([$function_node], function(Node $node) {
return (isset($node->key) && $node->key instanceof String_ && $node->key->value === 'function');
});
foreach ($theme_function_nodes as $node) {
$theme_function = $node->value instanceof String_ ? sprintf('"%s"', $node->value->value) : 'an unknown';
$deprecation_messages[] = new DeprecationMessage(sprintf('The %s is defining %s theme function. Theme functions are deprecated. For more info, see https://www.drupal.org/node/2575445.', $extension->getType(), $theme_function), $function_reflection->getFileName(), $node->getStartLine(), 'ThemeFunctionDeprecationAnalyzer');
}
// Find theme functions that are being added to an existing array using
// the array square bracket syntax.
// @code
// function hook_theme_registry_alter(&$theme_registry) {
// $theme_registry['theme_hook']['function'] = 'another_theme_function';
// }
// @endcode
$theme_function_dim_nodes = $finder->find([$function_node], function(Node $node) {
return $node instanceof Assign && $node->var instanceof ArrayDimFetch && $node->var->dim instanceof String_ && $node->var->dim->value === 'function';
});
foreach ($theme_function_dim_nodes as $node) {
$theme_function = $node->expr instanceof String_ ? sprintf('"%s"', $node->expr->value) : 'an unknown';
$deprecation_messages[] = new DeprecationMessage(sprintf('The %s is defining %s theme function. Theme functions are deprecated. For more info, see https://www.drupal.org/node/2575445.', $extension->getType(), $theme_function), $function_reflection->getFileName(), $node->getStartLine(), 'ThemeFunctionDeprecationAnalyzer');
}
return $deprecation_messages;
}
}
<?php
namespace Drupal\upgrade_status;
use Drupal\Core\Extension\Extension;
use Drupal\Core\Template\TwigEnvironment;
use Twig\Error\SyntaxError;
use Twig\Source;
use Twig\Util\TemplateDirIterator;
class TwigDeprecationAnalyzer {
/**
* The Twig environment.
*
* @var \Drupal\Core\Template\TwigEnvironment
*/
protected $twigEnvironment;
public function __construct(TwigEnvironment $twig_environment) {
$this->twigEnvironment = $twig_environment;
}
/**
* Analyzes theme functions in an extension.
*
* This is based on Twig\Util\DeprecationCollector which is a final class
* and thus cannot be extended. While it did find non-twig runtime deprecated
* errors, it did not gave us the file/line information, so we needed to copy
* and modify that behavior. We folded in our twig file/line parsing inline
* then to make it simpler.
*
* @param \Drupal\Core\Extension\Extension $extension
* The extension to be analyzed.
*
* @return \Drupal\upgrade_status\DeprecationMessage[]
*/
public function analyze(Extension $extension): array {
$deprecations = [];
set_error_handler(function ($type, $msg, $file, $line) use (&$deprecations) {
if (\E_USER_DEPRECATED === $type) {
if (preg_match('!([a-zA-Z0-9\_\-\/]+.html\.twig)!', $msg, $file_matches)) {
// Caught a Twig syntax based deprecation, record file name and line
// number from the message we caught.
preg_match('/(\d+).?$/', $msg, $line_matches);
$msg = preg_replace('! in (.+)\.twig at line \d+\.!', '.', $msg);
$msg .= ' See https://drupal.org/node/3071078.';
$deprecations[] = new DeprecationMessage(
$msg,
$file_matches[1],
$line_matches[1] ?? 0,
'TwigDeprecationAnalyzer'
);
}
else {
// Otherwise record the deprecation from the original caught error.
$deprecations[] = new DeprecationMessage(
$msg,
$file,
$line,
'TwigDeprecationAnalyzer'
);
}
}
});
$iterator = new TemplateDirIterator(
new TwigRecursiveIterator($extension->getPath())
);
foreach ($iterator as $name => $contents) {
try {
$this->twigEnvironment->parse($this->twigEnvironment->tokenize(new Source($contents, $name)));
} catch (SyntaxError $e) {
// Report twig syntax error which stops us from parsing it.
$deprecations[] = new DeprecationMessage(
'Twig template ' . $name . ' contains a syntax error and cannot be parsed.',
$name,
$e->getTemplateLine(),
'TwigDeprecationAnalyzer'
);
}
}
restore_error_handler();
// Ensure files are sorted properly.
usort($deprecations, static function (DeprecationMessage $a, DeprecationMessage $b) {
return strcmp($a->getFile(), $b->getFile());
});
return $deprecations;
}
}
<?php
namespace Drupal\upgrade_status;
use Drupal\Core\Site\Settings;
/**
* Filters a RecursiveDirectoryIterator to discover Drupal twig template files.
*/
class TwigRecursiveIterator extends \RecursiveIteratorIterator {
/**
* TwigRecursiveIteratorIterator constructor.
*
* @param string $directory
* Directory to search files.
*/
public function __construct(string $directory) {
$exclude = Settings::get('file_scan_ignore_directories', []);
parent::__construct(new \RecursiveCallbackFilterIterator(
new \RecursiveDirectoryIterator($directory, \RecursiveDirectoryIterator::SKIP_DOTS),
function ($current) use ($exclude) {
$name = $current->getFilename();
// RecursiveDirectoryIterator::SKIP_DOTS only skips '.' and '..', but
// not hidden directories (like '.git').
return $name[0] !== '.' &&
(($current->isDir() && !in_array($name, $exclude, TRUE)) ||
($current->isFile() && substr($name, -10) === '.html.twig'));
}
), \RecursiveIteratorIterator::LEAVES_ONLY);
}
}
{% if projects.custom %}
{{ "CUSTOM PROJECTS"|t }}
{% for project in projects.custom %}
--------------------------------------------------------------------------------
{{ project.name }}
{{ project.date }}
{% if project.summary %}
{{ project.summary }}
{% endif %}
{{ project.data|raw }}
{% endfor %}
{% endif %}
{% if projects.contrib %}
{{ "CONTRIBUTED PROJECTS"|t }}
{% for project in projects.contrib %}
--------------------------------------------------------------------------------
{{ project.name }}
{{ project.date }}
{% if project.summary %}
{{ project.summary }}
{% endif %}
{{ project.data|raw }}
{% endfor %}
{% endif %}
\ No newline at end of file
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Upgrade status report</title>
<style>
body {
font-family: Helvetia, Arial, sans-serif;
}
table {
width: 100%;
}
th, td {
border-bottom: 1px solid #cdcdcd;
}
th:nth-child(1), td:nth-child(3) {
width: 40%;
}
th:nth-child(2) {
width: 10%;
}
.list-description {
margin-bottom: 1em;
}
</style>
</head>
<body>
<h1>Upgrade Status report</h1>
{% if projects.custom %}
<h2>Custom projects</h2>
{% for project in projects.custom %}
<h3>{{ project.name }}</h3>
{{ project.date }}
{{ project.summary }}
{{ project.groups }}
{% endfor %}
{% endif %}
{% if projects.contrib %}
<h2>Contributed projects</h2>
{% for project in projects.contrib %}
<h3>{{ project.name }}</h3>
{{ project.date }}
{{ project.summary }}
{{ project.groups }}
{% endfor %}
{% endif %}
</body>
</html>
<?php
function update_status_test_11_compatible_ignored() {
upgrade_status_test_contrib_error_function_8_to_9();
}
name: 'Upgrade status test 11 compatible'
type: module
description: 'Support module for upgrade status module testing.'
package: Testing
core_version_requirement: ^9 || ^10 || ^11
# Information added by Drupal.org packaging script on 2025-07-02
version: '4.3.8'
project: 'upgrade_status'
datestamp: 1751485117
name: 'Upgrade status test 12 compatible'
type: module
description: 'Support module for upgrade status module testing.'
package: Testing
core_version_requirement: ^9 || ^10 || ^11 || ^12
# Information added by Drupal.org packaging script on 2025-07-02
version: '4.3.8'
project: 'upgrade_status'
datestamp: 1751485117
name: 'Upgrade status test contrib 11 compatible'
type: module
description: 'Support module for upgrade status module testing.'
package: Testing
# Intentionally using a requirement that is slightly more specific to
# test handling of this case.
core_version_requirement: ^9.1 || ^10 || ^11
# Project name intentionally different from module name for testing.
# project: 'upgrade_status_test_contributed_11_compatible'
# Information added by Drupal.org packaging script on 2025-07-02
version: '4.3.8'
project: 'upgrade_status'
datestamp: 1751485117
<?php
namespace Drupal\upgrade_status_test_contrib_error\Controller;
use Drupal\Core\Controller\ControllerBase;
/**
* Test class which contains deprecation error.
*/
class UpgradeStatusTestContribErrorController extends ControllerBase {
public function content() {
upgrade_status_test_contrib_error_function_9_to_10();
upgrade_status_test_contrib_error_function_9_to_11();
upgrade_status_test_contrib_error_function_10_to_11();
upgrade_status_test_contrib_error_function_10_to_12();
upgrade_status_test_contrib_error_function_11_to_13();
}
}
name: 'Upgrade status test contrib error'
type: module
description: 'Support module for upgrade status module testing.'
package: Testing
# Project name is intentionally set to test this as a contrib project.
# project: 'upgrade_status_test_contrib_error'
# Information added by Drupal.org packaging script on 2025-07-02
version: '4.3.8'
project: 'upgrade_status'
datestamp: 1751485117
<?php
/**
* Tests function deprecation detection from Drupal 9 to 10.
*
* @deprecated in drupal:9.1.0 and is removed from drupal:10.0.0. Use the
* replacement instead.
*/
function upgrade_status_test_contrib_error_function_9_to_10() {
@trigger_error("upgrade_status_test_contrib_error_function_9_to_10() is deprecated in Drupal 9.1.0 and will be removed before Drupal 10.0.0. Use the replacement instead. See LINK", E_USER_DEPRECATED);
}
/**
* Tests function deprecation detection from Drupal 9 to 11.
*
* @deprecated in drupal:9.1.0 and is removed from drupal:11.0.0. Use the
* replacement instead.
*/
function upgrade_status_test_contrib_error_function_9_to_11() {
@trigger_error("upgrade_status_test_contrib_error_function_9_to_11() is deprecated in Drupal 9.1.0 and will be removed before Drupal 11.0.0. Use the replacement instead. See LINK", E_USER_DEPRECATED);
}
/**
* Tests function deprecation detection from Drupal 10.3 to 11.0.
*
* @deprecated in drupal:10.3.0 and is removed from drupal:11.0.0. Use the
* replacement instead.
*/
function upgrade_status_test_contrib_error_function_10_to_11() {
@trigger_error("upgrade_status_test_contrib_error_function_10_to_11() is deprecated in Drupal 10.3.0 and will be removed before Drupal 11.0.0. Use the replacement instead. See LINK", E_USER_DEPRECATED);
}
/**
* Tests function deprecation detection from Drupal 10.0 to 12.0.
*
* @deprecated in drupal:10.0.0 and is removed from drupal:12.0.0. Use the
* replacement instead.
*/
function upgrade_status_test_contrib_error_function_10_to_12() {
@trigger_error("upgrade_status_test_contrib_error_function_10_to_12() is deprecated in Drupal 10.0.0 and will be removed before Drupal 12.0.0. Use the replacement instead. See LINK", E_USER_DEPRECATED);
}
/**
* Tests function deprecation detection from Drupal 11.1 to 13.0
*
* @deprecated in drupal:11.1.0 and is removed from drupal:13.0.0. Use the
* replacement instead.
*/
function upgrade_status_test_contrib_error_function_11_to_13() {
@trigger_error("upgrade_status_test_contrib_error_function_11_to_13() is deprecated in Drupal 11.1.0 and will be removed before Drupal 13.0.0. Use the replacement instead. See LINK", E_USER_DEPRECATED);
}
name: 'Upgrade status test deprecated'
type: module
description: 'Support module for upgrade status module testing.'
package: Testing
core_version_requirement: ^9 || ^10 || ^11
lifecycle: deprecated
lifecycle_link: https://drupal.org/project/upgrade_status
# Information added by Drupal.org packaging script on 2025-07-02
version: '4.3.8'
project: 'upgrade_status'
datestamp: 1751485117
uuid: 6a7eb126-7ba9-493f-a209-e3aa0672b8f5
langcode: en
status: true
dependencies:
config:
- core.entity_view_mode.node.teaser
module:
- node
- taxonomy
- user
id: remove_default_argument_skip_url
label: 'Taxonomy term'
module: taxonomy
description: 'Content belonging to a certain taxonomy term.'
tag: default
base_table: node_field_data
base_field: nid
display:
default:
id: default
display_title: Default
display_plugin: default
position: 0
display_options:
fields: { }
pager:
type: mini
options:
offset: 0
items_per_page: 10
total_pages: 0
id: 0
tags:
next: ››
previous: ‹‹
expose:
items_per_page: false
items_per_page_label: 'Items per page'
items_per_page_options: '5, 10, 25, 50'
items_per_page_options_all: false
items_per_page_options_all_label: '- All -'
offset: false
offset_label: Offset
exposed_form:
type: basic
options:
submit_button: Apply
reset_button: false
reset_button_label: Reset
exposed_sorts_label: 'Sort by'
expose_sort_order: true
sort_asc_label: Asc
sort_desc_label: Desc
access:
type: perm
options:
perm: 'access content'
cache:
type: tag
options: { }
empty: { }
sorts:
sticky:
id: sticky
table: taxonomy_index
field: sticky
relationship: none
group_type: group
admin_label: ''
plugin_id: standard
order: DESC
expose:
label: ''
field_identifier: sticky
exposed: false
created:
id: created
table: taxonomy_index
field: created
relationship: none
group_type: group
admin_label: ''
plugin_id: date
order: DESC
expose:
label: ''
field_identifier: created
exposed: false
granularity: second
arguments:
tid:
id: tid
table: taxonomy_index
field: tid
relationship: none
group_type: group
admin_label: ''
plugin_id: taxonomy_index_tid
default_action: 'not found'
exception:
value: ''
title_enable: false
title: All
title_enable: true
title: '{{ arguments.tid }}'
default_argument_type: fixed
default_argument_options:
argument: ''
default_argument_skip_url: false
summary_options:
base_path: ''
count: true
override: false
items_per_page: 25
summary:
sort_order: asc
number_of_records: 0
format: default_summary
specify_validation: true
validate:
type: 'entity:taxonomy_term'
fail: 'not found'
validate_options:
bundles: { }
access: true
operation: view
multiple: 0
break_phrase: false
add_table: false
require_value: false
reduce_duplicates: false
filters:
langcode:
id: langcode
table: node_field_data
field: langcode
relationship: none
group_type: group
admin_label: ''
entity_type: node
entity_field: langcode
plugin_id: language
operator: in
value:
'***LANGUAGE_language_content***': '***LANGUAGE_language_content***'
group: 1
exposed: false
expose:
operator_id: ''
label: ''
description: ''
use_operator: false
operator: ''
operator_limit_selection: false
operator_list: { }
identifier: ''
required: false
remember: false
multiple: false
remember_roles:
authenticated: authenticated
reduce: false
is_grouped: false
group_info:
label: ''
description: ''
identifier: ''
optional: true
widget: select
multiple: false
remember: false
default_group: All
default_group_multiple: { }
group_items: { }
status:
id: status
table: taxonomy_index
field: status
relationship: none
group_type: group
admin_label: ''
plugin_id: boolean
operator: '='
value: '1'
group: 1
exposed: false
expose:
operator_id: ''
label: ''
description: ''
use_operator: false
operator: ''
operator_limit_selection: false
operator_list: { }
identifier: ''
required: false
remember: false
multiple: false
remember_roles:
authenticated: authenticated
is_grouped: false
group_info:
label: ''
description: ''
identifier: ''
optional: true
widget: select
multiple: false
remember: false
default_group: All
default_group_multiple: { }
group_items: { }
style:
type: default
options:
grouping: { }
row_class: ''
default_row_class: true
uses_fields: false
row:
type: 'entity:node'
options:
view_mode: teaser
query:
type: views_query
options:
query_comment: ''
disable_sql_rewrite: false
distinct: false
replica: false
query_tags: { }
relationships: { }
link_display: page_1
link_url: ''
header:
entity_taxonomy_term:
id: entity_taxonomy_term
table: views
field: entity_taxonomy_term
relationship: none
group_type: group
admin_label: ''
plugin_id: entity
empty: true
target: '{{ raw_arguments.tid }}'
view_mode: full
tokenize: true
bypass_access: false
footer: { }
display_extenders: { }
cache_metadata:
max-age: -1
contexts:
- 'languages:language_interface'
- url
- url.query_args
- 'user.node_grants:view'
- user.permissions
tags: { }
feed_1:
id: feed_1
display_title: Feed
display_plugin: feed
position: 2
display_options:
pager:
type: some
options:
offset: 0
items_per_page: 10
style:
type: rss
options:
grouping: { }
uses_fields: false
description: ''
row:
type: node_rss
options:
relationship: none
view_mode: default
query:
type: views_query
options: { }
display_extenders: { }
path: taxonomy/term/%/feed
displays:
page_1: page_1
default: '0'
cache_metadata:
max-age: -1
contexts:
- 'languages:language_interface'
- url
- 'user.node_grants:view'
- user.permissions
tags: { }
page_1:
id: page_1
display_title: Page
display_plugin: page
position: 1
display_options:
query:
type: views_query
options: { }
display_extenders: { }
path: taxonomy/term/%
cache_metadata:
max-age: -1
contexts:
- 'languages:language_interface'
- url
- url.query_args
- 'user.node_grants:view'
- user.permissions
tags: { }
\ No newline at end of file
<?php
namespace Drupal\upgrade_status_test_error\Controller;
use Drupal\Core\Controller\ControllerBase;
/**
* Test class which contains deprecation error.
*/
class UpgradeStatusTestErrorController extends ControllerBase {
public function content() {
upgrade_status_test_contrib_error_function_9_to_10();
}
}
<?php
namespace Drupal\upgrade_status_test_error;
/**
* A deprecated class to allow testing extension of deprecated classes.
*
* @group upgrade_status_test_error
*
* @deprecated in drupal:9.1.0 and is removed from drupal:10.0.0. Instead,
* use so and so. See https://www.drupal.org/project/upgrade_status.
*/
class DeprecatedBaseClass {
}
<?php
namespace Drupal\upgrade_status_test_error;
/**
* A dummy class to test that extension of a deprecated class is detected.
*
* @group upgrade_status_test_error
*/
class ExtendingClass extends DeprecatedBaseClass {
}
<?php
namespace Drupal\upgrade_status_test_error;
use Drupal\Core\Config\Entity\ConfigEntityBase;
/**
* Defines the UpgradeStatusTestErrorEntity configuration entity.
*
* @ConfigEntityType(
* id = "upgrade_status_test_error",
* label = @Translation("Test configuration"),
* )
*/
final class UpgradeStatusTestErrorEntity extends ConfigEntityBase {
}
#drupal-off-canvas:not(.drupal-off-canvas-reset) {
/* this will not be detected */
}
#drupal-off-canvas-wrapper {
/* this will also not be detected */
}
#drupal-off-canvas {
/* THIS will be detected however */
}
name: 'Upgrade status test error'
type: module
description: 'Support module for upgrade status module testing.'
package: Testing
dependencies:
-drupal:upgrade_status_contrib_error
# Information added by Drupal.org packaging script on 2025-07-02
version: '4.3.8'
project: 'upgrade_status'
datestamp: 1751485117
upgrade_status_test_error.node.version_history:
path: '/node/{node}/upgrade_status_test_error'
defaults:
_title: 'Revisions'
_controller: '\Drupal\node\Controller\NodeController::revisionOverview'
requirements:
_access_node_revision: 'view'
node: \d+
options:
_node_operation_route: TRUE
parameters:
node:
type: entity:node
name: 'Upgrade status test fatal'
type: module
description: 'Support module for upgrade status module testing.'
package: Testing
# Information added by Drupal.org packaging script on 2025-07-02
version: '4.3.8'
project: 'upgrade_status'
datestamp: 1751485117
name: 'Upgrade status test library'
type: module
description: 'Support module for upgrade status module testing.'
package: Testing
core_version_requirement: ^9 || ^10 || ^11
dependencies:
- drupal:upgrade_status_test_twig
# Information added by Drupal.org packaging script on 2025-07-02
version: '4.3.8'
project: 'upgrade_status'
datestamp: 1751485117
deprecated_library:
css:
component:
assets/test.css: {}
deprecated: The "%library_id%" asset library is deprecated for testing.
library:
css:
component:
assets/test2.css: {}
dependencies:
- upgrade_status_test_library/deprecated_library
- upgrade_status_test_twig/deprecated_library
deprecated: The "%library_id%" asset library is deprecated for testing.
<?php
/**
* Implements hook_preprocess_html().
*/
function upgrade_status_test_library_preprocess_html(&$variables) {
$variables['#attach']['libraries'] = [
'upgrade_status_test_library/deprecated_library',
];
$variables['#attach']['libraries'][] = 'upgrade_status_test_twig/deprecated_library';
// These should be skipped.
$library = 'deprecated_library';
$variables['#attach']['libraries'][] = "upgrade_status_test_library/$library";
}
name: 'Upgrade status test library exception'
type: module
description: 'Support module for upgrade status module testing.'
package: Testing
core_version_requirement: ^9 || ^10 || ^11
dependencies:
- drupal:upgrade_status_test_twig
# Information added by Drupal.org packaging script on 2025-07-02
version: '4.3.8'
project: 'upgrade_status'
datestamp: 1751485117
name: 'Upgrade status test submodule'
type: module
description: 'Support module for upgrade status module testing.'
package: Testing
core_version_requirement: ^9 || ^10 || ^11
dependencies:
- drupal:upgrade_status_test_submodules
# Information added by Drupal.org packaging script on 2025-07-02
version: '4.3.8'
project: 'upgrade_status'
datestamp: 1751485117
name: 'Upgrade status test root module'
type: module
description: 'Support module for update module testing.'
package: Testing
core_version_requirement: ^9 || ^10 || ^11
# Information added by Drupal.org packaging script on 2025-07-02
version: '4.3.8'
project: 'upgrade_status'
datestamp: 1751485117
name: 'Upgrade status test submodule with error'
type: module
description: 'Support module for upgrade status module testing.'
package: Testing
dependencies:
- upgrade_status:upgrade_status_test_submodules_with_error
# Information added by Drupal.org packaging script on 2025-07-02
version: '4.3.8'
project: 'upgrade_status'
datestamp: 1751485117
name: 'Upgrade status test root module with submodules with errors'
type: module
description: 'Support module for upgrade_status module testing for modules with submodules, both with errors.'
package: Testing
# Information added by Drupal.org packaging script on 2025-07-02
version: '4.3.8'
project: 'upgrade_status'
datestamp: 1751485117
name: 'Upgrade Status Test module with theme functions'
type: module
description: 'Test module for testing theme function deprecation messages'
core_version_requirement: ^9 || ^10 || ^11
package: Testing
# Information added by Drupal.org packaging script on 2025-07-02
version: '4.3.8'
project: 'upgrade_status'
datestamp: 1751485116
<?php
/**
* Implements hook_theme().
*/
function upgrade_status_test_theme_functions_theme() {
return [
'upgrade_status_test_theme_function' => [
'function' => 'upgrade_status_test_theme_function'
],
'upgrade_status_test_theme_function_another_function' => [],
'upgrade_status_test_theme_function_theme_function_override' => [],
];
}
/**
* Implements hook_theme_registry_alter().
*/
function upgrade_status_test_theme_functions_theme_registry_alter(&$theme_registry) {
$theme_registry['upgrade_status_test_theme_function_another_function']['function'] = 'upgrade_status_test_theme_function';
$theme_registry['upgrade_status_test_theme_function_non_existing_function']['function'] = sprintf('upgrade_status_test_theme_function');
}
/**
* Theme function used for testing.
*/
function upgrade_status_test_theme_function() {
return 'kitten';
}
<?php
namespace Drupal\upgrade_status_test_twig\TwigExtension;
use Twig\TwigFilter;
use Twig\Extension\AbstractExtension;
class DeprecatedFilter extends AbstractExtension {
public function getFilters() {
return [new TwigFilter('deprecatedfilter', 'strlen', ['deprecated' => TRUE])];
}
}
{{ attach_library('upgrade_status_test_library/deprecated_library') }}
{{ attach_library('core/dynamic_value_is_skipped'|raw, 'upgrade_status_test_twig/deprecated_library') }}
{# Moving the deprecated filter use to line 10 on purpose. #}
{% set kitten = 'Kitten' %}
{{kitten|deprecatedfilter}}
name: 'Upgrade status test Twig'
type: module
description: 'Support module for upgrade status module testing.'
package: Testing
core_version_requirement: ^9 || ^10 || ^11
# Information added by Drupal.org packaging script on 2025-07-02
version: '4.3.8'
project: 'upgrade_status'
datestamp: 1751485116
deprecated_library:
css:
component:
assets/test.css: {}
deprecated: The "%library_id%" asset library is deprecated for testing.
services:
upgrade_status_test_twig.twig_extension:
class: Drupal\upgrade_status_test_twig\TwigExtension\DeprecatedFilter
tags:
- { name: twig.extension }
<?php
namespace Drupal\Tests\upgrade_status\Functional;
use Drupal\Core\Url;
use Drupal\Tests\BrowserTestBase;
/**
* Tests the accessibility of the deprecation dashboard.
*
* @group upgrade_status
*/
class UpgradeStatusAccessTest extends BrowserTestBase {
/**
* Modules to install.
*
* @var array
*/
protected static $modules = ['upgrade_status'];
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'stark';
/**
* Tests access without permission.
*/
#[\ReturnTypeWillChange]
public function testDeprecationDashboardAccessUnprivileged() {
$this->drupalGet(Url::fromRoute('upgrade_status.report'));
$this->assertSession()->statusCodeEquals(403);
}
/**
* Tests access with user that has the correct permission.
*/
public function testDeprecationDashboardAccessPrivileged() {
$this->drupalLogin($this->drupalCreateUser(['administer software updates']));
$this->drupalGet(Url::fromRoute('upgrade_status.report'));
$this->assertSession()->statusCodeEquals(200);
}
}
<?php
namespace Drupal\Tests\upgrade_status\Functional;
/**
* Tests analysing sample projects.
*
* @group upgrade_status
*/
class UpgradeStatusAnalyzeTest extends UpgradeStatusTestBase {
public function testAnalyzer() {
$this->drupalLogin($this->drupalCreateUser(['administer software updates']));
$this->runFullScan();
/** @var \Drupal\Core\KeyValueStore\KeyValueStoreInterface $key_value */
$key_value = \Drupal::service('keyvalue')->get('upgrade_status_scan_results');
// Check if the project has scan result in the keyValueStorage.
$this->assertTrue($key_value->has('upgrade_status_test_error'));
$this->assertTrue($key_value->has('upgrade_status_test_fatal'));
$this->assertTrue($key_value->has('upgrade_status_test_11_compatible'));
$this->assertTrue($key_value->has('upgrade_status_test_12_compatible'));
$this->assertTrue($key_value->has('upgrade_status_test_submodules'));
$this->assertTrue($key_value->has('upgrade_status_test_submodules_with_error'));
$this->assertTrue($key_value->has('upgrade_status_test_contrib_error'));
$this->assertTrue($key_value->has('upgrade_status_test_contrib_11_compatible'));
$this->assertTrue($key_value->has('upgrade_status_test_twig'));
$this->assertTrue($key_value->has('upgrade_status_test_theme'));
$this->assertTrue($key_value->has('upgrade_status_test_library'));
$this->assertTrue($key_value->has('upgrade_status_test_deprecated'));
// The project upgrade_status_test_submodules_a shouldn't have scan result,
// because it's a submodule of 'upgrade_status_test_submodules',
// and we always want to run the scan on root modules.
$this->assertFalse($key_value->has('upgrade_status_test_submodules_a'));
$report = $key_value->get('upgrade_status_test_error');
$this->assertNotEmpty($report);
$this->assertEquals(7, $report['data']['totals']['file_errors']);
$this->assertCount(7, $report['data']['files']);
$file = reset($report['data']['files']);
$this->assertEquals('UpgradeStatusTestErrorController.php', basename(key($report['data']['files'])));
$message = $file['messages'][0];
$this->assertEquals("Call to deprecated function upgrade_status_test_contrib_error_function_9_to_10(). Deprecated in drupal:9.1.0 and is removed from drupal:10.0.0. Use the replacement instead.", $message['message']);
$this->assertEquals(13, $message['line']);
$file = next($report['data']['files']);
$this->assertEquals('ExtendingClass.php', basename(key($report['data']['files'])));
$message = $file['messages'][0];
$this->assertEquals("Class Drupal\upgrade_status_test_error\ExtendingClass extends deprecated class Drupal\upgrade_status_test_error\DeprecatedBaseClass. Deprecated in drupal:9.1.0 and is removed from drupal:10.0.0. Instead, use so and so. See https://www.drupal.org/project/upgrade_status.", $message['message']);
$this->assertEquals(10, $message['line']);
$file = next($report['data']['files']);
$this->assertEquals('UpgradeStatusTestErrorEntity.php', basename(key($report['data']['files'])));
$message = $file['messages'][0];
$this->assertEquals("Configuration entity must define a `config_export` key. See https://www.drupal.org/node/2481909", $message['message']);
$this->assertEquals(15, $message['line']);
$file = next($report['data']['files']);
$this->assertEquals('upgrade_status_test_error.routing.yml', basename(key($report['data']['files'])));
$message = $file['messages'][0];
$this->assertEquals("The _access_node_revision routing requirement is deprecated in drupal:9.3.0 and is removed from drupal:10.0.0. Use _entity_access instead. See https://www.drupal.org/node/3161210.", $message['message']);
$this->assertEquals(0, $message['line']);
$file = next($report['data']['files']);
$this->assertEquals('upgrade_status_test_error.css', basename(key($report['data']['files'])));
$message = $file['messages'][0];
$this->assertEquals("The #drupal-off-canvas selector is deprecated in drupal:9.5.0 and is removed from drupal:10.0.0. See https://www.drupal.org/node/3305664.", $message['message']);
$this->assertEquals(0, $message['line']);
$file = next($report['data']['files']);
$this->assertEquals('views.view.remove_default_argument_skip_url.yml', basename(key($report['data']['files'])));
$message = $file['messages'][0];
$this->assertEquals("Support from all Views contextual filter settings for the default_argument_skip_url setting is removed from drupal:11.0.0. No replacement is provided. See https://www.drupal.org/node/3382316.", $message['message']);
$this->assertEquals(109, $message['line']);
$file = next($report['data']['files']);
$this->assertEquals('upgrade_status_test_error.info.yml', basename(key($report['data']['files'])));
$message = $file['messages'][0];
$this->assertEquals("Add core_version_requirement to designate which Drupal versions is the extension compatible with. See https://drupal.org/node/3070687.", $message['message']);
$this->assertEquals(1, $message['line']);
$report = $key_value->get('upgrade_status_test_fatal');
$this->assertNotEmpty($report);
$this->assertEquals(2, $report['data']['totals']['file_errors']);
$this->assertCount(2, $report['data']['files']);
$file = reset($report['data']['files']);
$message = $file['messages'][0];
$this->assertEquals('fatal.php', basename(key($report['data']['files'])));
$this->assertEquals("Syntax error, unexpected T_STRING on line 5", $message['message']);
$this->assertEquals(5, $message['line']);
$file = next($report['data']['files']);
$this->assertEquals('upgrade_status_test_fatal.info.yml', basename(key($report['data']['files'])));
$message = $file['messages'][0];
$this->assertEquals("Add core_version_requirement to designate which Drupal versions is the extension compatible with. See https://drupal.org/node/3070687.", $message['message']);
$this->assertEquals(1, $message['line']);
// The Drupal 10 and 11 compatible test modules are not Drupal 12 compatible.
$test_compatibles = [
'upgrade_status_test_11_compatible' => ['^9 || ^10 || ^11', 5],
'upgrade_status_test_contrib_11_compatible' => ['^9.1 || ^10 || ^11', 7],
];
foreach ($test_compatibles as $name => $condition) {
$report = $key_value->get($name);
$this->assertNotEmpty($report);
if ($this->getDrupalCoreMajorVersion() < 11) {
$this->assertEquals(0, $report['data']['totals']['file_errors']);
$this->assertCount(0, $report['data']['files']);
}
else {
$this->assertEquals(1, $report['data']['totals']['file_errors']);
$this->assertCount(1, $report['data']['files']);
$file = reset($report['data']['files']);
$this->assertEquals($name . '.info.yml', basename(key($report['data']['files'])));
$message = $file['messages'][0];
$this->assertEquals("Value of core_version_requirement: $condition[0] is not compatible with the next major version of Drupal core. See https://drupal.org/node/3070687.", $message['message']);
$this->assertEquals($condition[1], $message['line']);
}
}
// The Drupal 12 compatible test module is also Drupal 10 and 11 compatible.
$report = $key_value->get('upgrade_status_test_12_compatible');
$this->assertNotEmpty($report);
$this->assertEquals(0, $report['data']['totals']['file_errors']);
$this->assertCount(0, $report['data']['files']);
$report = $key_value->get('upgrade_status_test_contrib_error');
$this->assertNotEmpty($report);
$this->assertEquals(6, $report['data']['totals']['file_errors']);
$this->assertCount(2, $report['data']['files']);
$file = reset($report['data']['files']);
$this->assertEquals('UpgradeStatusTestContribErrorController.php', basename(key($report['data']['files'])));
$message = $file['messages'][0];
$this->assertEquals("Call to deprecated function upgrade_status_test_contrib_error_function_9_to_10(). Deprecated in drupal:9.1.0 and is removed from drupal:10.0.0. Use the replacement instead.", $message['message']);
$this->assertEquals(13, $message['line']);
$this->assertEquals('old', $message['upgrade_status_category']);
$message = $file['messages'][1];
$this->assertEquals("Call to deprecated function upgrade_status_test_contrib_error_function_9_to_11(). Deprecated in drupal:9.1.0 and is removed from drupal:11.0.0. Use the replacement instead.", $message['message']);
$this->assertEquals(14, $message['line']);
$this->assertEquals($this->getDrupalCoreMajorVersion() < 10 ? 'ignore' : 'old', $message['upgrade_status_category']);
$message = $file['messages'][2];
$this->assertEquals("Call to deprecated function upgrade_status_test_contrib_error_function_10_to_11(). Deprecated in drupal:10.3.0 and is removed from drupal:11.0.0. Use the replacement instead.", $message['message']);
$this->assertEquals(15, $message['line']);
$this->assertEquals($this->getDrupalCoreMajorVersion() < 10 ? 'ignore' : ($this->getDrupalCoreMajorVersion() < 11 ? 'later' : 'old'), $message['upgrade_status_category']);
$message = $file['messages'][3];
$this->assertEquals("Call to deprecated function upgrade_status_test_contrib_error_function_10_to_12(). Deprecated in drupal:10.0.0 and is removed from drupal:12.0.0. Use the replacement instead.", $message['message']);
$this->assertEquals(16, $message['line']);
$this->assertEquals($this->getDrupalCoreMajorVersion() < 11 ? 'ignore' : 'old', $message['upgrade_status_category']);
$message = $file['messages'][4];
$this->assertEquals("Call to deprecated function upgrade_status_test_contrib_error_function_11_to_13(). Deprecated in drupal:11.1.0 and is removed from drupal:13.0.0. Use the replacement instead.", $message['message']);
$this->assertEquals(17, $message['line']);
$this->assertEquals($this->getDrupalCoreMajorVersion() < 12 ? 'ignore' : 'later', $message['upgrade_status_category']);
$file = next($report['data']['files']);
$this->assertEquals('upgrade_status_test_contrib_error.info.yml', basename(key($report['data']['files'])));
$message = $file['messages'][0];
$this->assertEquals("Add core_version_requirement to designate which Drupal versions is the extension compatible with. See https://drupal.org/node/3070687.", $message['message']);
$this->assertEquals(1, $message['line']);
$this->assertEquals('uncategorized', $message['upgrade_status_category']);
$report = $key_value->get('upgrade_status_test_twig');
$this->assertNotEmpty($report);
$this->assertEquals($this->getDrupalCoreMajorVersion() < 11 ? 5 : 6, $report['data']['totals']['file_errors']);
$this->assertCount($this->getDrupalCoreMajorVersion() < 11 ? 3 : 4, $report['data']['files']);
$file = array_shift($report['data']['files']);
if ($this->getDrupalCoreMajorVersion() > 9) {
// In Drupal 10, Twig 3.15 introduced some stuff.
$this->assertEquals('Since twig/twig 3.15: Using the "deprecated", "deprecating_package", and "alternative" options is deprecated, pass a "deprecation_info" one instead.', $file['messages'][0]['message']);
$file = array_shift($report['data']['files']);
}
$upgrade_status_test_twig_directory = $this->container->get('module_handler')->getModule('upgrade_status_test_twig')->getPath();
if ($this->getDrupalCoreMajorVersion() < 10) {
$this->assertEquals(sprintf('The spaceless tag in "%s/templates/spaceless.html.twig" at line 2 is deprecated since Twig 2.7, use the "spaceless" filter with the "apply" tag instead. See https://drupal.org/node/3071078.', $upgrade_status_test_twig_directory), $file['messages'][0]['message']);
}
else {
$this->assertEquals(sprintf('Twig template %s/templates/spaceless.html.twig contains a syntax error and cannot be parsed.', $upgrade_status_test_twig_directory), $file['messages'][0]['message']);
}
$file = array_shift($report['data']['files']);
$this->assertEquals('Since 1: Twig Filter "deprecatedfilter" is deprecated. See https://drupal.org/node/3071078.', $file['messages'][0]['message']);
$this->assertEquals(10, $file['messages'][0]['line']);
$this->assertEquals('Template is attaching a deprecated library. The "upgrade_status_test_library/deprecated_library" asset library is deprecated for testing.', $file['messages'][1]['message']);
$this->assertEquals(1, $file['messages'][1]['line']);
$this->assertEquals('Template is attaching a deprecated library. The "upgrade_status_test_twig/deprecated_library" asset library is deprecated for testing.', $file['messages'][2]['message']);
$this->assertEquals(2, $file['messages'][2]['line']);
if ($this->getDrupalCoreMajorVersion() > 10) {
// In Drupal 11, this module is not yet forward compatible.
$file = array_shift($report['data']['files']);
$this->assertEquals("Value of core_version_requirement: ^9 || ^10 || ^11 is not compatible with the next major version of Drupal core. See https://drupal.org/node/3070687.", $file['messages'][0]['message']);
$this->assertEquals(5, $file['messages'][0]['line']);
}
$report = $key_value->get('upgrade_status_test_theme');
$this->assertNotEmpty($report);
// The info file error only happens on post-10, theme function only on pre-10.
$this->assertEquals($this->getDrupalCoreMajorVersion() == 10 ? 5 : 6, $report['data']['totals']['file_errors']);
$this->assertCount($this->getDrupalCoreMajorVersion() == 10 ? 3 : 4, $report['data']['files']);
$file = reset($report['data']['files']);
if ($this->getDrupalCoreMajorVersion() > 9) {
// In Drupal 10, Twig 3.15 introduced some stuff.
$this->assertEquals('Since twig/twig 3.15: Using the "deprecated", "deprecating_package", and "alternative" options is deprecated, pass a "deprecation_info" one instead.', $file['messages'][0]['message']);
$file = next($report['data']['files']);
}
foreach ([0 => 2, 1 => 4] as $index => $line) {
$message = $file['messages'][$index];
$this->assertEquals('Since 1: Twig Filter "deprecatedfilter" is deprecated. See https://drupal.org/node/3071078.', $message['message']);
$this->assertEquals($line, $message['line']);
}
$file = next($report['data']['files']);
$this->assertEquals('Theme is overriding a deprecated library. The "upgrade_status_test_library/deprecated_library" asset library is deprecated for testing.', $file['messages'][0]['message']);
$this->assertEquals(0, $file['messages'][0]['line']);
$this->assertEquals('Theme is extending a deprecated library. The "upgrade_status_test_twig/deprecated_library" asset library is deprecated for testing.', $file['messages'][1]['message']);
$this->assertEquals(0, $file['messages'][1]['line']);
if ($this->getDrupalCoreMajorVersion() < 10) {
$file = next($report['data']['files']);
$this->assertEquals('The theme is overriding the "upgrade_status_test_theme_function_theme_function_override" theme function. Theme functions are deprecated. For more info, see https://www.drupal.org/node/2575445.', $file['messages'][0]['message']);
$this->assertEquals(6, $file['messages'][0]['line']);
}
elseif ($this->getDrupalCoreMajorVersion() > 10) {
// In Drupal 11 and 12, this theme is not yet forward compatible.
$file = next($report['data']['files']);
$this->assertEquals("Value of core_version_requirement: ^9 || ^10 || ^11 is not compatible with the next major version of Drupal core. See https://drupal.org/node/3070687.", $file['messages'][0]['message']);
$this->assertEquals(5, $file['messages'][0]['line']);
}
// @see https://www.drupal.org/project/upgrade_status/issues/3219968 base theme cannot be tested practically.
/*$file = next($report['data']['files']);
$this->assertEquals('upgrade_status_test_theme.info.yml', basename(key($report['data']['files'])));
$message = $file['messages'][0];
$this->assertEquals("The now required 'base theme' key is missing. See https://www.drupal.org/node/3066038.", $message['message']);
$this->assertEquals(0, $message['line']);*/
$report = $key_value->get('upgrade_status_test_theme_functions');
$this->assertNotEmpty($report);
if ($this->getDrupalCoreMajorVersion() < 10) {
$this->assertEquals(3, $report['data']['totals']['file_errors']);
$this->assertCount(1, $report['data']['files']);
$file = reset($report['data']['files']);
$this->assertEquals('The module is defining "upgrade_status_test_theme_function" theme function. Theme functions are deprecated. For more info, see https://www.drupal.org/node/2575445.', $file['messages'][0]['message']);
$this->assertEquals(9, $file['messages'][0]['line']);
$this->assertEquals('The module is defining "upgrade_status_test_theme_function" theme function. Theme functions are deprecated. For more info, see https://www.drupal.org/node/2575445.', $file['messages'][1]['message']);
$this->assertEquals(20, $file['messages'][1]['line']);
$this->assertEquals('The module is defining an unknown theme function. Theme functions are deprecated. For more info, see https://www.drupal.org/node/2575445.', $file['messages'][2]['message']);
$this->assertEquals(21, $file['messages'][2]['line']);
}
elseif ($this->getDrupalCoreMajorVersion() > 10) {
// In Drupal 11, this module is not yet forward compatible, but theme
// functions cannot be checked anymore as of Drupal 10 due to lack of support.
$this->assertEquals(1, $report['data']['totals']['file_errors']);
$this->assertCount(1, $report['data']['files']);
$file = reset($report['data']['files']);
$this->assertEquals("Value of core_version_requirement: ^9 || ^10 || ^11 is not compatible with the next major version of Drupal core. See https://drupal.org/node/3070687.", $file['messages'][0]['message']);
$this->assertEquals(4, $file['messages'][0]['line']);
}
else {
// In Drupal 10 no errors should be reported due to lack of checking.
$this->assertEquals(0, $report['data']['totals']['file_errors']);
$this->assertCount(0, $report['data']['files']);
}
// On at least Drupal 11, these projects will not be ready for the next major.
$base_info_error = (int) ($this->getDrupalCoreMajorVersion() >= 11);
$report = $key_value->get('upgrade_status_test_library');
$this->assertNotEmpty($report);
$this->assertEquals(4 + $base_info_error, $report['data']['totals']['file_errors']);
$this->assertCount(2 + $base_info_error, $report['data']['files']);
$file = reset($report['data']['files']);
$this->assertEquals("The 'library' library is depending on a deprecated library. The \"upgrade_status_test_library/deprecated_library\" asset library is deprecated for testing.", $file['messages'][0]['message']);
$this->assertEquals(0, $file['messages'][0]['line']);
$this->assertEquals("The 'library' library is depending on a deprecated library. The \"upgrade_status_test_twig/deprecated_library\" asset library is deprecated for testing.", $file['messages'][1]['message']);
$this->assertEquals(0, $file['messages'][1]['line']);
$file = $report['data']['files'][array_keys($report['data']['files'])[1]];
$this->assertEquals('The referenced library is deprecated. The "upgrade_status_test_library/deprecated_library" asset library is deprecated for testing.', $file['messages'][0]['message']);
$this->assertEquals(8, $file['messages'][0]['line']);
$this->assertEquals('The referenced library is deprecated. The "upgrade_status_test_twig/deprecated_library" asset library is deprecated for testing.', $file['messages'][1]['message']);
$this->assertEquals(10, $file['messages'][1]['line']);
$report = $key_value->get('upgrade_status_test_library_exception');
$this->assertNotEmpty($report);
$this->assertEquals(1 + $base_info_error, $report['data']['totals']['file_errors']);
$this->assertCount(1 + $base_info_error, $report['data']['files']);
$file = reset($report['data']['files']);
$this->assertEquals("Incomplete library definition for definition 'library_exception' in extension 'upgrade_status_test_library_exception'", $file['messages'][0]['message']);
// Module upgrade_status_test_submodules_with_error_a shouldn't have scan
// result, but its info.yml errors should appear in its parent scan.
$this->assertFalse($key_value->has('upgrade_status_test_submodules_with_error_a'));
$report = $key_value->get('upgrade_status_test_submodules_with_error');
$this->assertNotEmpty($report);
$this->assertEquals(2, $report['data']['totals']['file_errors']);
$this->assertCount(2, $report['data']['files']);
$report = $key_value->get('upgrade_status_test_deprecated');
$this->assertNotEmpty($report);
$this->assertEquals(1 + $base_info_error, $report['data']['totals']['file_errors']);
$this->assertCount(1, $report['data']['files']);
$file = reset($report['data']['files']);
$index = 0;
if ($this->getDrupalCoreMajorVersion() > 10) {
// In Drupal 11, this module is not yet forward compatible.
$this->assertEquals("Value of core_version_requirement: ^9 || ^10 || ^11 is not compatible with the next major version of Drupal core. See https://drupal.org/node/3070687.", $file['messages'][0]['message']);
$this->assertEquals(5, $file['messages'][0]['line']);
$index = 1;
}
$this->assertEquals("This extension is deprecated. Don't use it. See https://drupal.org/project/upgrade_status.", $file['messages'][$index]['message']);
$this->assertEquals(6, $file['messages'][$index]['line']);
}
}
<?php
namespace Drupal\Tests\upgrade_status\Functional;
use Drush\TestTraits\DrushTestTrait;
/**
* @coversDefaultClass \Drupal\upgrade_status\Drush\Commands\UpgradeStatusCommands
*
* @group upgrade_status
*/
class UpgradeStatusCommandsTest extends UpgradeStatusTestBase {
use DrushTestTrait;
/**
* Tests drush commands.
*/
public function testCommands() {
// Test a Drupal 10 and 11 compatible module.
if ($this->getDrupalCoreMajorVersion() < 11) {
$this->drush('us-a', ['upgrade_status_test_11_compatible'], [], null, null, 0);
$output = $this->getOutput();
$this->assertStringContainsString('No known issues found.', $output);
}
else {
$this->drush('upgrade_status:analyze', ['upgrade_status_test_11_compatible'], [], null, null, 3);
$output = $this->getOutput();
$this->assertStringContainsString('Value of core_version_requirement:', $output);
}
// Test a Drupal 12 compatible module.
$this->drush('upgrade_status:analyze', ['upgrade_status_test_12_compatible'], [], null, null, 0);
$output = $this->getOutput();
$this->assertStringContainsString('No known issues found.', $output);
// Test checkstyle output.
$this->drush('upgrade_status:analyze', ['upgrade_status_test_error'], ['format' => 'checkstyle'], null, null, 3);
$output = $this->getOutput();
$this->assertStringContainsString('<checkstyle', $output);
$this->assertStringContainsString('<file', $output);
$this->assertStringContainsString('<error', $output);
// Test codeclimate output.
$this->drush('upgrade_status:analyze', ['upgrade_status_test_error'], ['format' => 'codeclimate'], null, null, 3);
$output = $this->getOutput();
$this->assertStringContainsString('"type": "issue"', $output);
$this->assertStringContainsString('check_name', $output);
$this->assertStringContainsString('description', $output);
$this->assertStringContainsString('categories', $output);
$this->assertStringContainsString('Compatibility', $output);
$this->assertStringContainsString('location', $output);
$this->assertStringContainsString('fingerprint', $output);
$this->assertStringContainsString('severity', $output);
// Test deprecated checkstyle output.
$this->drush('upgrade_status:checkstyle', ['upgrade_status_test_error'], [], null, null, 3);
$output = $this->getOutput();
$this->assertStringContainsString('<checkstyle', $output);
$this->assertStringContainsString('<file', $output);
$this->assertStringContainsString('<error', $output);
$output = $this->getErrorOutput();
$this->assertStringContainsString('The checkstyle (us-cs) drush command is deprecated and will be removed.', $output);
}
}
<?php
namespace Drupal\Tests\upgrade_status\Functional;
use Drupal\Tests\BrowserTestBase;
/**
* Defines shared functions used by some of the functional tests.
*/
abstract class UpgradeStatusTestBase extends BrowserTestBase {
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'stark';
/**
* {@inheritdoc}
*/
protected static $modules = [
'upgrade_status',
'upgrade_status_test_error',
'upgrade_status_test_fatal',
'upgrade_status_test_11_compatible',
'upgrade_status_test_12_compatible',
'upgrade_status_test_submodules_a',
'upgrade_status_test_submodules_with_error',
'upgrade_status_test_contrib_error',
'upgrade_status_test_contrib_11_compatible',
'upgrade_status_test_theme_functions',
'upgrade_status_test_twig',
'upgrade_status_test_library',
'upgrade_status_test_library_exception',
'upgrade_status_test_deprecated',
];
/**
* {@inheritdoc}
*/
public function setUp(): void {
parent::setUp();
$this->container->get('theme_installer')->install(['upgrade_status_test_theme']);
}
/**
* Perform a full scan on all test modules.
*/
protected function runFullScan() {
$edit = [
'scan[data][list][upgrade_status_test_error]' => TRUE,
'scan[data][list][upgrade_status_test_fatal]' => TRUE,
'scan[data][list][upgrade_status_test_11_compatible]' => TRUE,
'scan[data][list][upgrade_status_test_12_compatible]' => TRUE,
'scan[data][list][upgrade_status_test_submodules]' => TRUE,
'scan[data][list][upgrade_status_test_submodules_with_error]' => TRUE,
'scan[data][list][upgrade_status_test_twig]' => TRUE,
'scan[data][list][upgrade_status_test_theme]' => TRUE,
'scan[data][list][upgrade_status_test_theme_functions]' => TRUE,
'scan[data][list][upgrade_status_test_library]' => TRUE,
'scan[data][list][upgrade_status_test_library_exception]' => TRUE,
'scan[data][list][upgrade_status_test_deprecated]' => TRUE,
'collaborate[data][list][upgrade_status_test_contrib_error]' => TRUE,
($this->getDrupalCoreMajorVersion() < 11 ? 'relax' : 'collaborate') . '[data][list][upgrade_status]' => TRUE,
($this->getDrupalCoreMajorVersion() < 11 ? 'relax' : 'collaborate') . '[data][list][upgrade_status_test_contrib_11_compatible]' => TRUE,
];
$this->drupalGet('admin/reports/upgrade-status');
$this->submitForm($edit, 'Scan selected');
}
/**
* Returns current core's major version.
*
* @return int
* Version converted to int.
*/
protected function getDrupalCoreMajorVersion(): int {
return (int) \Drupal::VERSION;
}
}
<?php
namespace Drupal\Tests\upgrade_status\Functional;
use Drupal\Core\Url;
use Drupal\user\Entity\Role;
/**
* Tests the UI before and after running scans.
*
* @group upgrade_status
*/
class UpgradeStatusUiTest extends UpgradeStatusTestBase {
/**
* {@inheritdoc}
*/
public function setUp(): void {
parent::setUp();
$this->drupalLogin($this->drupalCreateUser(['administer software updates']));
}
/**
* Test the user interface before running a scan.
*/
public function testUiBeforeScan() {
$this->drupalGet(Url::fromRoute('upgrade_status.report'));
$assert_session = $this->assertSession();
$assert_session->buttonExists('Scan selected');
$assert_session->buttonExists('Export selected as HTML');
// Scan result for every project should be 'N/A'.
$status = $this->getSession()->getPage()->findAll('css', 'td.scan-result');
$this->assertNotEmpty($status);
foreach ($status as $project_status) {
$this->assertSame('N/A', $project_status->getHtml());
}
}
/**
* Test the user interface after running a scan.
*/
public function testUiAfterScan() {
$this->runFullScan();
$page = $this->getSession()->getPage();
$assert_session = $this->assertSession();
$assert_session->buttonExists('Scan selected');
$assert_session->buttonExists('Export selected as HTML');
// Error and no-error test module results should show.
$this->assertSame('7 problems', strip_tags($page->find('css', 'tr.project-upgrade_status_test_error td.scan-result')->getHtml()));
$this->assertSame($this->getDrupalCoreMajorVersion() < 11 ? 'No problems found' : '1 problem', strip_tags($page->find('css', 'tr.project-upgrade_status_test_11_compatible td.scan-result')->getHtml()));
$this->assertSame('No problems found', strip_tags($page->find('css', 'tr.project-upgrade_status_test_12_compatible td.scan-result')->getHtml()));
// Parent module should show up without errors and submodule should not appear.
$this->assertSame($this->getDrupalCoreMajorVersion() < 11 ? 'No problems found' : '2 problems', strip_tags($page->find('css', 'tr.project-upgrade_status_test_submodules td.scan-result')->getHtml()));
$this->assertEmpty($page->find('css', 'tr.upgrade_status_test_submodules_a'));
// Contrib test modules should show with results.
$this->assertSame('6 problems', strip_tags($page->find('css', 'tr.project-upgrade_status_test_contrib_error td.scan-result')->getHtml()));
$this->assertSame($this->getDrupalCoreMajorVersion() < 11 ? 'No problems found' : '1 problem', strip_tags($page->find('css', 'tr.project-upgrade_status_test_contrib_11_compatible td.scan-result')->getHtml()));
// This contrib module has a different project name. Ensure the drupal.org link used that.
$next_major = $this->getDrupalCoreMajorVersion() + 1;
$this->assertSession()->linkByHrefExists('https://drupal.org/project/issues/upgrade_status_test_contributed_11_compatible?text=Drupal+' . $next_major . '&status=All');
// Check UI of results for the custom project.
$this->drupalGet('/admin/reports/upgrade-status/project/upgrade_status_test_error');
$this->assertSession()->pageTextContains('Upgrade status test error');
$this->assertSession()->pageTextContains('2 errors found. ' . ($this->getDrupalCoreMajorVersion() < 10 ? '4' : '5') . ' warnings found.');
$this->assertSession()->pageTextContains('Call to deprecated function upgrade_status_test_contrib_error_function_9_to_10(). Deprecated in drupal:9.1.0 and is removed from drupal:10.0.0. Use the replacement instead.');
// Go forward to the export page and assert that still contains the results
// as well as an export specific title.
$this->clickLink('Export as HTML');
$this->assertSession()->pageTextContains('Upgrade Status report');
$this->assertSession()->pageTextContains('Upgrade status test error');
$this->assertSession()->pageTextContains('Custom projects');
$this->assertSession()->pageTextNotContains('Contributed projects');
$this->assertSession()->pageTextContains('2 errors found. ' . ($this->getDrupalCoreMajorVersion() < 10 ? '4' : '5') . ' warnings found.');
$this->assertSession()->pageTextContains('Call to deprecated function upgrade_status_test_contrib_error_function_9_to_10(). Deprecated in drupal:9.1.0 and is removed from drupal:10.0.0. Use the replacement instead.');
// Go back to the results page and click over to exporting in single ASCII.
$this->drupalGet('/admin/reports/upgrade-status/project/upgrade_status_test_error');
$this->clickLink('Export as text');
$this->assertSession()->pageTextContains('Upgrade status test error');
$this->assertSession()->pageTextContains('CUSTOM PROJECTS');
$this->assertSession()->pageTextNotContains('CONTRIBUTED PROJECTS');
$this->assertSession()->pageTextContains('2 errors found. ' . ($this->getDrupalCoreMajorVersion() < 10 ? '4' : '5') . ' warnings found.');
$this->assertSession()->pageTextContains('Call to deprecated function upgrade_status_test_contrib_error_function_9_to_10(). Deprecated in drupal:9.1.0 and is removed from drupal:10.0.0. Use the replacement instead.');
// Run partial export of multiple projects.
$edit = [
'manual[data][list][upgrade_status_test_error]' => TRUE,
($this->getDrupalCoreMajorVersion() < 11 ? 'relax' : 'manual') . '[data][list][upgrade_status_test_11_compatible]' => TRUE,
'collaborate[data][list][upgrade_status_test_contrib_error]' => TRUE,
];
$expected = [
'Export selected as HTML' => ['Contributed projects', 'Custom projects'],
'Export selected as text' => ['CONTRIBUTED PROJECTS', 'CUSTOM PROJECTS'],
];
foreach ($expected as $button => $assert) {
$this->drupalGet('admin/reports/upgrade-status');
$this->submitForm($edit, $button);
$this->assertSession()->pageTextContains($assert[0]);
$this->assertSession()->pageTextContains($assert[1]);
$this->assertSession()->pageTextContains('Upgrade status test contrib error');
$this->assertSession()->pageTextContains('Upgrade status test 11 compatible');
$this->assertSession()->pageTextContains('Upgrade status test error');
$this->assertSession()->pageTextNotContains('Upgrade status test root module');
$this->assertSession()->pageTextNotContains('Upgrade status test contrib 11 compatible');
$this->assertSession()->pageTextContains('2 errors found. ' . ($this->getDrupalCoreMajorVersion() < 10 ? '4' : '5') . ' warnings found.');
$this->assertSession()->pageTextContains('Call to deprecated function upgrade_status_test_contrib_error_function_9_to_10(). Deprecated in drupal:9.1.0 and is removed from drupal:10.0.0. Use the replacement instead.');
}
}
/**
* Test the user interface for role checking.
*/
public function testRoleChecking() {
if ($this->getDrupalCoreMajorVersion() == 9) {
$authenticated = Role::load('authenticated');
$authenticated->grantPermission('upgrade status invalid permission test');
$authenticated->save();
$this->drupalGet(Url::fromRoute('upgrade_status.report'));
$this->assertSession()->pageTextContains('Permissions of user role: "Authenticated user":upgrade status invalid permission test');
}
}
}
<?php
namespace Drupal\Tests\upgrade_status\Kernel;
use Drupal\KernelTests\KernelTestBase;
use Drupal\upgrade_status\CSSDeprecationAnalyzer;
/**
* Tests analysing CSS files.
*
* @group upgrade_status
* @coversDefaultClass \Drupal\upgrade_status\CSSDeprecationAnalyzer
*/
class CSSDeprecationAnalyzerTest extends KernelTestBase {
/**
* The temporary directory path.
*/
protected $tempPath;
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$this->tempPath = @tempnam($this->root, 'upgrade_status_test');
if (file_exists($this->tempPath)) {
$this->container->get('file_system')->deleteRecursive($this->tempPath);
}
mkdir($this->tempPath);
}
/**
* {@inheritdoc}
*/
protected function tearDown(): void {
$this->container->get('file_system')->deleteRecursive($this->tempPath);
parent::tearDown();
}
/**
* @covers ::getAllCSSFiles
*/
public function testGetAllCSSFiles() {
touch($this->tempPath . '/test.css');
mkdir($this->tempPath . '/subdir');
touch($this->tempPath . '/subdir/test.css');
// Edge case: a directory with a .css extension.
mkdir($this->tempPath . '/subdir.css');
touch($this->tempPath . '/subdir.css/test.txt');
touch($this->tempPath . '/subdir.css/test.css');
// Directories are ignored from file_scan_ignore_directories.
mkdir($this->tempPath . '/node_modules');
touch($this->tempPath . '/node_modules/test.css');
mkdir($this->tempPath . '/bower_components');
touch($this->tempPath . '/bower_components/test.css');
mkdir($this->tempPath . '/subdir.css/node_modules');
touch($this->tempPath . '/subdir.css/node_modules/test.css');
$class = new \ReflectionClass(CSSDeprecationAnalyzer::class);
$method = $class->getMethod('getAllCSSFiles');
$method->setAccessible(TRUE);
$expected = [
$this->tempPath . '/subdir/test.css',
$this->tempPath . '/subdir.css/test.css',
$this->tempPath . '/test.css',
];
$actual = $method->invokeArgs(new CSSDeprecationAnalyzer(), [$this->tempPath]);
$this->assertEmpty(array_diff($expected, $actual), 'Checking for missing files.');
$this->assertEmpty(array_diff($actual, $expected), 'Checking for extra files.');
}
}
<?php
namespace Drupal\Tests\upgrade_status\Kernel;
use Drupal\KernelTests\KernelTestBase;
use Drupal\upgrade_status\DeprecationMessage;
use DrupalFinder\DrupalFinder;
/**
* Tests analysing Twig templates.
*
* @group upgrade_status
*/
final class TwigDeprecationAnalyzerTest extends KernelTestBase {
protected static $modules = [
'upgrade_status',
'upgrade_status_test_twig',
];
public function testDeprecationReport() {
$extension = $this->container->get('module_handler')->getModule('upgrade_status_test_twig');
$templates_directory = $extension->getPath() . '/templates';
$sut = $this->container->get('upgrade_status.twig_deprecation_analyzer');
$twig_deprecations = $sut->analyze($extension);
$this->assertCount(3, $twig_deprecations, var_export($twig_deprecations, TRUE));
$this->assertContainsEquals(new DeprecationMessage(
'Since 1: Twig Filter "deprecatedfilter" is deprecated. See https://drupal.org/node/3071078.',
$templates_directory . '/test.html.twig',
'10',
'TwigDeprecationAnalyzer'
), $twig_deprecations);
// Later than Drupal 10.0.0.
if (version_compare('10.0.0', \Drupal::VERSION) === -1) {
// Twig 3.15 issues with deprecated options.
$finder = new DrupalFinder();
$finder->locateRoot(DRUPAL_ROOT);
$vendor_path = $finder->getVendorDir();
$this->assertContainsEquals(new DeprecationMessage(
'Since twig/twig 3.15: Using the "deprecated", "deprecating_package", and "alternative" options is deprecated, pass a "deprecation_info" one instead.',
$vendor_path . '/symfony/deprecation-contracts/function.php',
'25',
'TwigDeprecationAnalyzer'
), $twig_deprecations);
// Use of spaceless leads to syntax error in Drupal 10.
$this->assertContainsEquals(new DeprecationMessage(
sprintf('Twig template %s/spaceless.html.twig contains a syntax error and cannot be parsed.', $templates_directory),
$templates_directory . '/spaceless.html.twig',
'2',
'TwigDeprecationAnalyzer'
), $twig_deprecations);
}
else {
// Spaceless deprecation exists in Twig 2 which is in Drupal 9.
$this->assertContainsEquals(new DeprecationMessage(
sprintf('The spaceless tag in "%s/spaceless.html.twig" at line 2 is deprecated since Twig 2.7, use the "spaceless" filter with the "apply" tag instead. See https://drupal.org/node/3071078.', $templates_directory),
$templates_directory . '/spaceless.html.twig',
0,
'TwigDeprecationAnalyzer'
), $twig_deprecations);
}
}
}
{% set kitten = 'Kitten' %}
{{kitten|deprecatedfilter}}
{% set panda = 'Panda' %}
{{panda|deprecatedfilter}}
name: 'Upgrade status test theme'
type: theme
description: 'Theme for testing deprecations in themes'
base theme: false
core_version_requirement: ^9 || ^10 || ^11
libraries-override:
upgrade_status_test_library/deprecated_library:
css:
component:
assets/test.css: assets/test.css
libraries-extend:
upgrade_status_test_twig/deprecated_library:
- upgrade_status_test_theme/library
# Information added by Drupal.org packaging script on 2025-07-02
version: '4.3.8'
project: 'upgrade_status'
datestamp: 1751485116
<?php
/**
* Theme function override for testing purposes.
*/
function upgrade_status_test_theme_upgrade_status_test_theme_function_theme_function_override() {
}
<?php
/**
* @file
* Hooks defined by Upgrade Status.
*/
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Extension\Extension;
/**
* @addtogroup hooks
* @{
*/
/**
* Alter the operations run on projects on the Upgrade Status UI.
*
* @param array $operations
* Batch operations array to be altered.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The submitted state of the upgrade status form.
*/
function hook_upgrade_status_operations_alter(array &$operations, FormStateInterface $form_state) {
// Duplicate each operation with another one that runs rector on the
// same extension.
if (!empty($form_state->getValue('run_rector'))) {
$keys = array_keys($operations);
foreach ($keys as $key) {
$operations[] = [
'update_rector_run_rector_batch',
[$operations[$key][1][0]],
];
}
}
}
/**
* Alter the build array for an upgrade status result group.
*
* @param array $build
* A render array with build results, including a 'title', 'description',
* 'errors', etc. keys.
* @param \Drupal\Core\Extension\Extension $extension
* Drupal extension object.
* @param string $group_key
* The key for the result group. One of 'rector', 'now', 'uncategorized',
* 'later' or 'ignore'.
*/
function hook_upgrade_status_result_alter(array &$build, Extension $extension, $group_key) {
if ($group_key == 'rector') {
$build['description']['#markup'] = t('Here is your patch...');
}
}
/**
* @} End of "addtogroup hooks".
*/
type: module
name: 'Upgrade Status'
description: 'Review Drupal major upgrade readiness of the environment and components of the site.'
configure: upgrade_status.report
package: Administration
core_version_requirement: ^9 || ^10 || ^11
dependencies:
- drupal:update
# Information added by Drupal.org packaging script on 2025-07-02
version: '4.3.8'
project: 'upgrade_status'
datestamp: 1751485117
<?php
/**
* @file
* Install, update, and uninstall functions for the Upgrade Status module.
*/
/**
* Implements hook_requirements().
*/
function upgrade_status_requirements($phase) {
if ($phase == 'install') {
// Check if the Drupal Finder is available. This will attempt to autoload
// the class, so we can bail out as soon as possible.
if (!class_exists('DrupalFinder\DrupalFinder')) {
return [
'upgrade_status' => [
'description' => t('External dependencies for Upgrade Status are not available. Composer must be used to download the module with dependencies. See <a href="@url">the Upgrade Status project page</a> for instructions.', ['@url' => 'https://drupal.org/project/upgrade_status']),
'severity' => REQUIREMENT_ERROR,
],
];
}
}
return [];
}
/**
* Implements hook_uninstall().
*/
function upgrade_status_uninstall() {
\Drupal::keyValue('upgrade_status_scan_results')->deleteAll();
}
/**
* Delete old state information that is not anymore relevant or valid.
*
* You will need to scan modules again to get your results back (now in
* the new format).
*/
function upgrade_status_update_8101() {
\Drupal::state()->delete('upgrade_status.number_of_jobs');
\Drupal::state()->delete('upgrade_status.last_scan');
\Drupal::state()->delete('upgrade_status.scanning_job_fatal');
\Drupal::keyValue('upgrade_status_scan_results')->deleteAll();
// Drop the 'queue_inspectable' table if it exists. The module used
// to come with a custom queue implementation of this name.
$db = \Drupal::database();
$schema = $db->schema();
if ($schema->tableExists('queue_inspectable')) {
if (!$db->select('queue_inspectable')->countQuery()->execute()->fetchField()) {
$schema->dropTable('queue_inspectable');
}
else {
return t("Most legacy Upgrade Status data was cleaned up, however the 'queue_inspectable' table remains because it had values in it. This will not cause issues with the module, but will linger around as old unused data in the database. It may become a problem in the future if another module chooses to use the same queue type name. Please remove manually.");
}
}
}
/**
* Delete old state information so the changed storage format can be used.
*/
function upgrade_status_update_8301() {
\Drupal::keyValue('upgrade_status_scan_results')->deleteAll();
}
/**
* Delete state, because PHPStan fail state was incorrectly formatted.
*/
function upgrade_status_update_8302() {
\Drupal::keyValue('upgrade_status_scan_results')->deleteAll();
}
upgrade_status.admin:
css:
theme:
css/upgrade_status.admin.theme.css: {}
dependencies:
- core/drupal.dialog.ajax
upgrade_status.report:
title: 'Upgrade status'
description: 'Review Drupal major upgrade readiness of the environment and components of the site.'
route_name: upgrade_status.report
parent: system.admin_reports
<?php
/**
* @file
* The base module for upgrade status.
*/
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Extension\Extension;
use Drupal\upgrade_status\ProjectCollector;
/**
* Implements hook_help().
*/
function upgrade_status_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'upgrade_status.report':
$help = '<p>' . t('Run the report to find out if there are detectable compatibility errors with the modules and themes installed on your site.');
// @todo Link to a relevant page for the Drupal 9 to 10 process when available.
if (ProjectCollector::getDrupalCoreMajorVersion() < 9) {
$help .= ' ' . t('<a href=":prepare">Read more about preparing your site for Drupal 9</a>.', [':prepare' => 'https://www.drupal.org/docs/9/how-to-prepare-your-drupal-7-or-8-site-for-drupal-9/prepare-a-drupal-8-site-for-drupal-9']);
}
$help .= '</p>';
return $help;
case 'help.page.upgrade_status':
$help = '';
$help .= '<h3>' . t('About') . '</h3>';
$help .= '<p>' . t('Upgrade Status scans the code of installed contributed and custom projects on the site, and reports any deprecated code that must be replaced before the next major version. Available project updates are also suggested to keep your site up to date as projects will resolve deprecation errors over time.') . '</p>';
$help .= '<h3>' . t('How to use') . '</h3>';
$help .= '<p>' . t('There are no configuration options on Upgrade Status, now that is installed go to <a href=":upgrade_status_report">Administration » Reports » Upgrade status</a> to use', [':upgrade_status_report' => '/admin/reports/upgrade-status']) . '</p>';
$help .= '<ul>';
$help .= '<li>' . t('For a full description, visit the <a href="!project_page">project page</a>', ['!project_page' => 'https://www.drupal.org/project/upgrade_status']) . '</li>';
$help .= '<li>' . t('To submit bug reports and feature suggestions, or to track changes, visit the <a href="!project_issue_queue">project issue queue</a>', ['!project_issue_queue' => 'https://www.drupal.org/project/issues/upgrade_status']) . '</li>';
$help .= '</ul>';
return $help;
}
}
/**
* Implements hook_theme().
*/
function upgrade_status_theme($existing, $type, $theme, $path) {
return [
'upgrade_status_html_export' => [
'variables' => [
'projects' => [],
],
],
'upgrade_status_ascii_export' => [
'variables' => [
'projects' => [],
],
],
'upgrade_status_summary_counter' => [
'variables' => [
'summary' => [],
],
],
];
}
/**
* Preprocess project list for HTML export.
*
* @param array $variables
* Array of template variables.
*/
function template_preprocess_upgrade_status_html_export(array &$variables) {
$projects = $variables['projects'];
$types = ['custom', 'contrib'];
foreach ($types as $type) {
if (!empty($projects[$type])) {
foreach ($projects[$type] as $key => $project) {
$variables['projects'][$type][$key]['name'] = $projects[$type][$key]['#title'];
}
}
}
}
/**
* Preprocess project list for ASCII export.
*
* @param array $variables
* Array of template variables.
*/
function template_preprocess_upgrade_status_ascii_export(array &$variables) {
template_preprocess_upgrade_status_html_export($variables);
}
/**
* Implements hook_system_info_alter().
*/
function upgrade_status_system_info_alter(array &$info, Extension $extension, $type) {
// Always mark upgrade_status as a contrib project regardless of how it was
// obtained. This makes testing the module results reliably consistent.
if ($extension->getName() == 'upgrade_status') {
$info['project'] = $extension->getName();
}
}
upgrade_status.report:
path: '/admin/reports/upgrade-status'
defaults:
_form: '\Drupal\upgrade_status\Form\UpgradeStatusForm'
_title_callback: '\Drupal\upgrade_status\Form\UpgradeStatusForm::getTitle'
requirements:
_permission: 'administer software updates'
upgrade_status.project:
path: '/admin/reports/upgrade-status/project/{project_machine_name}'
defaults:
_controller: '\Drupal\upgrade_status\Controller\ScanResultController::resultPage'
_title: 'Upgrade status'
requirements:
_permission: 'administer software updates'
upgrade_status.export:
path: '/admin/reports/upgrade-status/export/{project_machine_name}/{format}'
defaults:
_controller: '\Drupal\upgrade_status\Controller\ScanResultController::resultExport'
_title: 'Upgrade status'
requirements:
_permission: 'administer software updates'
upgrade_status.analyze:
path: '/admin/reports/upgrade-status/analyze/{project_machine_name}'
defaults:
_controller: '\Drupal\upgrade_status\Controller\ScanResultController::analyze'
requirements:
_permission: 'administer software updates'
# Support only POST so nothing accidental happens on GET.
methods:
- POST
services:
upgrade_status.deprecation_analyzer:
class: Drupal\upgrade_status\DeprecationAnalyzer
arguments:
- '@keyvalue'
- '@logger.channel.upgrade_status'
- '@http_client'
- '@file_system'
- '@upgrade_status.twig_deprecation_analyzer'
- '@upgrade_status.library_deprecation_analyzer'
- '@upgrade_status.theme_function_deprecation_analyzer'
- '@upgrade_status.route_deprecation_analyzer'
- '@upgrade_status.extension_metadata_deprecation_analyzer'
- '@upgrade_status.config_schema_deprecation_analyzer'
- '@upgrade_status.css_deprecation_analyzer'
- '@datetime.time'
upgrade_status.library_deprecation_analyzer:
class: Drupal\upgrade_status\LibraryDeprecationAnalyzer
arguments:
- '@library.discovery.parser'
- '@twig'
- '@extension.list.module'
- '@extension.list.theme'
- '@extension.list.profile'
upgrade_status.theme_function_deprecation_analyzer:
class: Drupal\upgrade_status\ThemeFunctionDeprecationAnalyzer
arguments: ['@service_container']
upgrade_status.twig_deprecation_analyzer:
class: Drupal\upgrade_status\TwigDeprecationAnalyzer
arguments: ['@twig']
upgrade_status.route_deprecation_analyzer:
class: Drupal\upgrade_status\RouteDeprecationAnalyzer
upgrade_status.css_deprecation_analyzer:
class: Drupal\upgrade_status\CSSDeprecationAnalyzer
upgrade_status.extension_metadata_deprecation_analyzer:
class: Drupal\upgrade_status\ExtensionMetadataDeprecationAnalyzer
upgrade_status.config_schema_deprecation_analyzer:
class: Drupal\upgrade_status\ConfigSchemaDeprecationAnalyzer
upgrade_status.project_collector:
class: Drupal\upgrade_status\ProjectCollector
arguments:
- '@extension.list.module'
- '@extension.list.theme'
- '@extension.list.profile'
- '@keyvalue.expirable'
- '@config.factory'
- '%install_profile%'
upgrade_status.result_formatter:
class: Drupal\upgrade_status\ScanResultFormatter
arguments: ['@keyvalue', '@date.formatter', '@datetime.time', '@module_handler']
logger.channel.upgrade_status:
parent: logger.channel_base
arguments: ['upgrade_status']
menu_depth: 4 menu_depth: 4
hoverintent_behavior:
enabled: true
timeout: 500
enable_toggle_shortcut: false
_core: _core:
default_config_hash: AAmWcgwzGYbXfR6wfEfMyoi3r5QZwlpxvq5dHbupnJo default_config_hash: AAmWcgwzGYbXfR6wfEfMyoi3r5QZwlpxvq5dHbupnJo
display_menu_item: 0 display_menu_item: false
enable_keyboard_shortcut: true
max_bundle_number: 20 max_bundle_number: 20
hoverintent_functionality: true
uuid: d929921b-3668-49b2-86b2-6404fe4009f7
langcode: ru
status: true
dependencies:
config:
- system.menu.account
module:
- system
theme:
- bartik
_core:
default_config_hash: mdceJE7ob2aDa6hPTtn6NJdF86-ffpqdOEuPxyC-ubo
id: bartik_account_menu
theme: bartik
region: secondary_menu
weight: 0
provider: null
plugin: 'system_menu_block:account'
settings:
id: 'system_menu_block:account'
label: 'Меню учётной записи пользователя'
label_display: '0'
provider: system
level: 1
depth: 1
expand_all_items: false
visibility: { }
uuid: 50f1e261-7c2d-4963-9ea0-68e28a8135bd
langcode: ru
status: true
dependencies:
module:
- system
theme:
- bartik
_core:
default_config_hash: VbOaUx_g-_D_VyQiDjo1c5XlUfRU7nERL20lS0IL3Sg
id: bartik_branding
theme: bartik
region: header
weight: 0
provider: null
plugin: system_branding_block
settings:
id: system_branding_block
label: 'Брендинг сайта'
label_display: '0'
provider: system
use_site_logo: true
use_site_name: true
use_site_slogan: true
visibility: { }
uuid: a6f24324-835d-4135-b2d3-b9609ec5b98c
langcode: ru
status: true
dependencies:
module:
- system
theme:
- bartik
_core:
default_config_hash: '-hcn9asTypFoAD7jp_AioNadYluTGJ9kDEVntWvzWug'
id: bartik_breadcrumbs
theme: bartik
region: breadcrumb
weight: 0
provider: null
plugin: system_breadcrumb_block
settings:
id: system_breadcrumb_block
label: 'Строка навигации'
label_display: '0'
provider: system
visibility: { }
uuid: 2b25fe9c-e2ec-473b-ad42-5e60f25f4ff9
langcode: ru
status: true
dependencies:
module:
- system
theme:
- bartik
_core:
default_config_hash: twveVxaUEntAcNs_pbfSXLkeeZqhC9pXHG6IDalcSPA
id: bartik_content
theme: bartik
region: content
weight: 0
provider: null
plugin: system_main_block
settings:
id: system_main_block
label: 'Содержимое страницы'
label_display: '0'
provider: system
visibility: { }
uuid: 4c440be9-6f80-47cb-bcd3-da6ac4b833ba
langcode: ru
status: true
dependencies:
config:
- system.menu.footer
module:
- system
theme:
- bartik
_core:
default_config_hash: 88AG9_3h66aaXhQGnkAlifgFQ43uS0MkldSW6vSLsMA
id: bartik_footer
theme: bartik
region: footer_fifth
weight: 0
provider: null
plugin: 'system_menu_block:footer'
settings:
id: 'system_menu_block:footer'
label: 'Меню в подвале'
label_display: '0'
provider: system
level: 1
depth: 0
expand_all_items: false
visibility: { }
uuid: 74a7d250-16b3-4938-9dc7-67d35b518be7
langcode: ru
status: true
dependencies:
module:
- help
theme:
- bartik
_core:
default_config_hash: 1gHie90c8bKujQLe9qwIjxoko3WhzUis_xVO8QNKLTY
id: bartik_help
theme: bartik
region: content
weight: -30
provider: null
plugin: help_block
settings:
id: help_block
label: Справка
label_display: '0'
provider: help
visibility: { }
uuid: 2019ffb5-58ff-496f-be67-f86c2cc3efc4
langcode: ru
status: true
dependencies:
theme:
- bartik
_core:
default_config_hash: JmlnnUyO_ILGmlkWz4HgqsKBOEop5Brgbgmbe0guhME
id: bartik_local_actions
theme: bartik
region: content
weight: -20
provider: null
plugin: local_actions_block
settings:
id: local_actions_block
label: 'Основные действия администратора'
label_display: '0'
provider: core
visibility: { }
uuid: a616012e-30c7-494a-aaec-0dbb2f65a0e5
langcode: ru
status: true
dependencies:
theme:
- bartik
_core:
default_config_hash: _gc79d0d-miDNL43EWvXf82vwra2Q8QLh6-aTOV7m8w
id: bartik_local_tasks
theme: bartik
region: content
weight: -40
provider: null
plugin: local_tasks_block
settings:
id: local_tasks_block
label: Вкладки
label_display: '0'
provider: core
primary: true
secondary: true
visibility: { }
uuid: c195ee81-7e40-4c3c-87cf-778eed248b44
langcode: ru
status: true
dependencies:
config:
- system.menu.main
module:
- system
theme:
- bartik
_core:
default_config_hash: fZWr_cJs1U7rpCeXw_k286IabEADqIAUodEqiWU_8JU
id: bartik_main_menu
theme: bartik
region: primary_menu
weight: 0
provider: null
plugin: 'system_menu_block:main'
settings:
id: 'system_menu_block:main'
label: 'Основная навигация'
label_display: '0'
provider: system
level: 1
depth: 1
expand_all_items: false
visibility: { }
uuid: ca8a7ce3-a601-42e2-b5e4-789351ebfe29
langcode: ru
status: true
dependencies:
module:
- system
theme:
- bartik
_core:
default_config_hash: _1gahyrkJ24hNxdFzlI0unBHEGOr7jPUxv3PQPTUOqs
id: bartik_messages
theme: bartik
region: highlighted
weight: 0
provider: null
plugin: system_messages_block
settings:
id: system_messages_block
label: 'Сообщения статуса'
label_display: '0'
provider: system
visibility: { }
uuid: 2cacd8a4-213b-4347-bbf0-61ea7b4ae331
langcode: ru
status: true
dependencies:
theme:
- bartik
_core:
default_config_hash: Yxc7CzPXq6DsdLS2JPMafX1mgh0NJjxFe6O3V6lYtV4
id: bartik_page_title
theme: bartik
region: content
weight: -50
provider: null
plugin: page_title_block
settings:
id: page_title_block
label: 'Заголовок страницы'
label_display: '0'
provider: core
visibility: { }
uuid: 59226979-8be6-49ca-b0e5-9f8a5d24ac28
langcode: ru
status: true
dependencies:
module:
- search
theme:
- bartik
_core:
default_config_hash: 7_4tW7IyyStAHllx4PVvzpJjt7X_UTl14wg8JJtfWxU
id: bartik_search
theme: bartik
region: sidebar_first
weight: -1
provider: null
plugin: search_form_block
settings:
id: search_form_block
label: Поиск
label_display: visible
provider: search
page_id: ''
visibility: { }
uuid: 01733fed-60fe-45a5-8b65-d7960a076963
langcode: ru
status: true
dependencies:
config:
- system.menu.tools
module:
- system
theme:
- bartik
_core:
default_config_hash: g5acIjoPcFnaSC_iJo1J6wiEuGlMdmpchMglPRrwOTE
id: bartik_tools
theme: bartik
region: sidebar_first
weight: 0
provider: null
plugin: 'system_menu_block:tools'
settings:
id: 'system_menu_block:tools'
label: Инструменты
label_display: visible
provider: system
level: 1
depth: 0
expand_all_items: false
visibility: { }
...@@ -22,6 +22,6 @@ settings: ...@@ -22,6 +22,6 @@ settings:
label_display: '0' label_display: '0'
provider: system provider: system
level: 1 level: 1
depth: 0 depth: null
expand_all_items: false expand_all_items: false
visibility: { } visibility: { }
...@@ -19,5 +19,5 @@ settings: ...@@ -19,5 +19,5 @@ settings:
label: Поиск label: Поиск
label_display: visible label_display: visible
provider: search provider: search
page_id: '' page_id: null
visibility: { } visibility: { }
...@@ -22,6 +22,6 @@ settings: ...@@ -22,6 +22,6 @@ settings:
label_display: visible label_display: visible
provider: system provider: system
level: 1 level: 1
depth: 0 depth: null
expand_all_items: false expand_all_items: false
visibility: { } visibility: { }
...@@ -22,6 +22,6 @@ settings: ...@@ -22,6 +22,6 @@ settings:
label_display: '0' label_display: '0'
provider: system provider: system
level: 1 level: 1
depth: 0 depth: null
expand_all_items: false expand_all_items: false
visibility: { } visibility: { }
...@@ -19,5 +19,5 @@ settings: ...@@ -19,5 +19,5 @@ settings:
label: Поиск label: Поиск
label_display: visible label_display: visible
provider: search provider: search
page_id: '' page_id: null
visibility: { } visibility: { }
...@@ -22,6 +22,6 @@ settings: ...@@ -22,6 +22,6 @@ settings:
label_display: visible label_display: visible
provider: system provider: system
level: 1 level: 1
depth: 0 depth: null
expand_all_items: false expand_all_items: false
visibility: { } visibility: { }
...@@ -19,5 +19,5 @@ settings: ...@@ -19,5 +19,5 @@ settings:
label: 'Форма поиска (узкая)' label: 'Форма поиска (узкая)'
label_display: '0' label_display: '0'
provider: search provider: search
page_id: '' page_id: null
visibility: { } visibility: { }
...@@ -19,5 +19,5 @@ settings: ...@@ -19,5 +19,5 @@ settings:
label: 'Форма поиска (широкая)' label: 'Форма поиска (широкая)'
label_display: '0' label_display: '0'
provider: search provider: search
page_id: '' page_id: null
visibility: { } visibility: { }
uuid: 605e5315-262d-46c0-b14a-94932785482f
langcode: ru
status: true
dependencies:
module:
- system
theme:
- seven
_core:
default_config_hash: n9_o2DRCQtz39AWL3uT7yaRpMMu84C65GgGe5Asg-Q0
id: seven_breadcrumbs
theme: seven
region: breadcrumb
weight: 0
provider: null
plugin: system_breadcrumb_block
settings:
id: system_breadcrumb_block
label: 'Строка навигации'
label_display: '0'
provider: system
visibility: { }
uuid: 4320ac51-3d3e-4c42-818f-da885cfdb5b6
langcode: ru
status: true
dependencies:
module:
- system
theme:
- seven
_core:
default_config_hash: g7QEtlb0k2TYqtyCKSm7ugPspEcwuTsJurF1_dV_gWA
id: seven_content
theme: seven
region: content
weight: 0
provider: null
plugin: system_main_block
settings:
id: system_main_block
label: 'Содержимое страницы'
label_display: '0'
provider: system
visibility: { }
uuid: d548614a-0ac9-468d-bf1b-823bb56e0178
langcode: ru
status: true
dependencies:
module:
- help
theme:
- seven
_core:
default_config_hash: 5pIiv4-EgVE9alli1X6q4WH9dN1DE9SGilfIOzFk758
id: seven_help
theme: seven
region: help
weight: 0
provider: null
plugin: help_block
settings:
id: help_block
label: Справка
label_display: '0'
provider: help
visibility: { }
uuid: caf1985f-76aa-4203-93fe-25943f77616b
langcode: ru
status: true
dependencies:
theme:
- seven
_core:
default_config_hash: xfhzFR8oJQ4W4eZB9nLmR2jiaiyi0Q9omqqcVrf4y-s
id: seven_local_actions
theme: seven
region: content
weight: -10
provider: null
plugin: local_actions_block
settings:
id: local_actions_block
label: 'Основные действия администратора'
label_display: '0'
provider: core
visibility: { }
uuid: 8d4b0115-ff2b-4f53-9ba2-e80c1f6baf25
langcode: ru
status: true
dependencies:
module:
- user
theme:
- seven
_core:
default_config_hash: B54JmKNbGywI-yLlPqwQTHn8RNUzVQ4vgMNALbB-W4M
id: seven_login
theme: seven
region: content
weight: 10
provider: null
plugin: user_login_block
settings:
id: user_login_block
label: 'Вход на сайт'
label_display: visible
provider: user
visibility: { }
uuid: df6262dd-e383-4fc6-a240-9b1a5e976b5a
langcode: ru
status: true
dependencies:
module:
- system
theme:
- seven
_core:
default_config_hash: xid_6IxtCt-aOeyeNuSoy6cS02WI8H2NrxYv8WdRzBg
id: seven_messages
theme: seven
region: highlighted
weight: 0
provider: null
plugin: system_messages_block
settings:
id: system_messages_block
label: 'Сообщения статуса'
label_display: '0'
provider: system
visibility: { }
uuid: 85bd49fe-3b3e-4939-9adb-c8204f804eda
langcode: ru
status: true
dependencies:
theme:
- seven
_core:
default_config_hash: K755nxl8BiqoQ9WqGk8im_570h5sEZvdulHRpeL0YMI
id: seven_page_title
theme: seven
region: header
weight: -30
provider: null
plugin: page_title_block
settings:
id: page_title_block
label: 'Заголовок страницы'
label_display: '0'
provider: core
visibility: { }
uuid: 4eb65874-9007-445a-a3b1-0e4d54818960
langcode: ru
status: true
dependencies:
theme:
- seven
_core:
default_config_hash: J3cC98TPbTxYK3dSGo6tdy9ElwhKNn8GgeRlAMAiYTQ
id: seven_primary_local_tasks
theme: seven
region: header
weight: 0
provider: null
plugin: local_tasks_block
settings:
id: local_tasks_block
label: 'Главные вкладки'
label_display: '0'
provider: core
primary: true
secondary: false
visibility: { }
uuid: d51176f1-2ef4-4606-876f-786f79ddb686
langcode: ru
status: true
dependencies:
theme:
- seven
_core:
default_config_hash: p95zbImHKTVQtugrm_9Jzr8bDwwmJp6eOwMMhJH7wvE
id: seven_secondary_local_tasks
theme: seven
region: pre_content
weight: 0
provider: null
plugin: local_tasks_block
settings:
id: local_tasks_block
label: 'Вторичные вкладки'
label_display: '0'
provider: core
primary: false
secondary: true
visibility: { }
...@@ -8,6 +8,6 @@ _core: ...@@ -8,6 +8,6 @@ _core:
default_config_hash: N1WvAaJ9xicIbfyJ21L7PuHjQ55qBKXOcy21WOALIOo default_config_hash: N1WvAaJ9xicIbfyJ21L7PuHjQ55qBKXOcy21WOALIOo
id: user.register id: user.register
label: Регистрация label: Регистрация
description: '' description: null
targetEntityType: user targetEntityType: user
cache: true cache: true
uuid: 6904af13-a00b-4c2a-b930-65331f9931dd
langcode: ru
status: true
dependencies:
module:
- tour
id: tour.token
label: Token
description: ''
targetEntityType: tour
cache: true
...@@ -111,7 +111,6 @@ module: ...@@ -111,7 +111,6 @@ module:
text: 0 text: 0
token: 0 token: 0
toolbar: 0 toolbar: 0
tour: 0
twig_attributes: 0 twig_attributes: 0
twig_field_value: 0 twig_field_value: 0
twig_tweak: 0 twig_tweak: 0
...@@ -136,8 +135,6 @@ module: ...@@ -136,8 +135,6 @@ module:
theme: theme:
bootstrap: 0 bootstrap: 0
dar_simple: 0 dar_simple: 0
bartik: 0
seven: 0
claro: 0 claro: 0
olivero: 0 olivero: 0
profile: dar profile: dar
...@@ -2,5 +2,6 @@ _core: ...@@ -2,5 +2,6 @@ _core:
default_config_hash: SeixqdFz2l17tm6zgUQxPReSU5tESNDD8kNo-FdCR9o default_config_hash: SeixqdFz2l17tm6zgUQxPReSU5tESNDD8kNo-FdCR9o
tabs: true tabs: true
path: false path: false
descriptions_show: false
enabled_filters: enabled_filters:
permissions: true permissions: true
third_party_settings:
shortcut:
module_link: true
...@@ -2,5 +2,4 @@ _core: ...@@ -2,5 +2,4 @@ _core:
default_config_hash: rWJa83LHFLZP1lNC8DfdZaKeG1de11Jae0B3hnAYPz8 default_config_hash: rWJa83LHFLZP1lNC8DfdZaKeG1de11Jae0B3hnAYPz8
allow_insecure_uploads: false allow_insecure_uploads: false
default_scheme: public default_scheme: public
path: { }
temporary_maximum_age: 21600 temporary_maximum_age: 21600
uuid: 538964dd-1b63-4ed0-9bfa-88a8f24afb56
langcode: ru
status: true
dependencies:
module:
- honeypot
_core:
default_config_hash: A_dlRbNEX9_hOqUkQ5m4AskEmat7VEA8qvFt7tVeufQ
id: honeypot
label: Honeypot
module: honeypot
routes:
-
route_name: honeypot.config
tips:
honeypot-configuration:
id: honeypot-configuration
plugin: text
label: Honeypot
weight: -10
position: top-start
body: "Congratulations on installing Honeypot on your site! With just a few clicks, you can have your site well-protected against automated spam bots.\r\n\r\nClick Next to be guided through this configuration page."
protect-all-forms:
id: protect-all-forms
plugin: text
label: 'Protect all forms'
weight: -9
position: bottom-start
selector: '#edit-protect-all-forms'
body: "Protecting all the forms is the easiest way to quickly cut down on spam on your site, but doing this disables Drupal's caching for every page where a form is displayed.\r\n\r\nNote: If you have the honeypot time limit enabled, this option may cause issues with Drupal Commerce product forms or similarly-sparse forms that are able to be completed in a very short time."
log-blocked-form-submissions:
id: log-blocked-form-submissions
plugin: text
label: 'Log blocked form submissions'
weight: -8
position: bottom-start
selector: '#edit-log'
body: 'Check this box to log every form submission using watchdog. If you have Database Logging enabled, you can view these log entries in the Recent log messages page under Reports.'
honeypot-element-name:
id: honeypot-element-name
plugin: text
label: 'Honeypot Element Name'
weight: -7
position: top-start
selector: '#edit-element-name'
body: "Spam bots typically fill out any field they believe will help get links back to their site, so tempting them with a field named something like 'url', 'homepage', or 'link' makes it hard for them to resist filling in the field—and easy to catch them in the trap and reject their submissions!"
honeypot-time-limit:
id: honeypot-time-limit
plugin: text
label: 'Honeypot Time Limit'
weight: -6
position: top-start
selector: '#edit-time-limit'
body: "If you enter a positive value, Honeypot will require that all protected forms take at least that many seconds long to fill out. Most forms take at least 5-10 seconds to complete (if you're a human), so setting this to a value < 5 will help protect against spam bots. Set to 0 to disable."
honeypot-expire:
id: honeypot-expire
plugin: text
label: 'Honeypot Expire'
weight: -5
position: top-start
selector: '#edit-expire'
body: "If you enter a positive value, Honeypot will require that all protected forms take at least that many seconds long to fill out. Most forms take at least 5-10 seconds to complete (if you're a human), so setting this to a value < 5 will help protect against spam bots. Set to 0 to disable."
honeypot-form-specific-settings:
id: honeypot-form-specific-settings
plugin: text
label: 'Honeypot form-specific settings'
weight: -4
position: top-start
selector: '#edit-form-settings'
body: 'If you would like to choose particular forms to be protected by Honeypot, check the forms you wish to protect in this section. Most common types of forms are available for protection.'
uuid: e7890609-7337-40f8-ae05-cb0647c90073
langcode: ru
status: true
dependencies:
module:
- language
_core:
default_config_hash: gzDsFq-NjI5-b8Akk9GopPb58xcxTdEQOyp1AqfEGqo
id: language-add
label: 'Добавление языков'
module: language
routes:
-
route_name: language.add
tips:
language-add-overview:
id: language-add-overview
plugin: text
label: 'Добавление языков'
weight: 1
body: '<p>Эта страница предоставляет возможность добавить на сайт общеизвестные языки.</p><p>Если необходимый язык отсутствует, можно добавить собственный язык.</p>'
language-add-choose:
id: language-add-choose
plugin: text
label: 'Выберите язык'
weight: 2
body: '<p>Выберите язык из списка, или выберите пункт "Собственный язык...", который находится в конце списка.</p><p>После выбора языка, нажмите кнопку "Добавить язык" .</p><p>При добавлении собственного языка, появится дополнительная форма, где будет необходимо ввести название, код и направление языка.</p>'
selector: '#edit-predefined-langcode'
language-add-continue:
id: language-add-continue
plugin: text
label: Продолжение
weight: 3
body: '<p>Now that you have an overview of the "Add languages" feature, you can continue by:<ul><li>Adding a language</li><li>Adding a custom language</li><li><a href="[site:url]admin/config/regional/language">Viewing configured languages</a></li></ul></p>'
uuid: a7956e76-fe7f-459a-be94-af7e0c256fee
langcode: ru
status: true
dependencies:
module:
- language
_core:
default_config_hash: fARuNTkiS8PtyYDEcsL0cOsn78swMv-2DjnSYjbYdSE
id: language-edit
label: 'Редактирование языков'
module: language
routes:
-
route_name: entity.configurable_language.edit_form
tips:
language-edit-overview:
id: language-edit-overview
plugin: text
label: 'Редактирование языков'
weight: 1
body: '<p>Эта страница предоставляет возможность редактировать язык на вашем сайте, включая собственные языки.</p>'
language-edit-langcode:
id: language-edit-langcode
plugin: text
label: 'Код языка'
weight: 2
body: '<p>Невозможно изменить код языка сайта, так как он используется системой для отслеживания языка.</p>'
selector: '#edit-langcode-view'
language-edit-label:
id: language-edit-label
plugin: text
label: 'Название языка'
weight: 3
body: 'Название языка используется по всему сайту для всех пользователей и пишется на английском языке. Названия встроенных языков могут быть переведены с помощью модуля Interface Translation, а названия встроенных и собственных языков могут быть переведены с помощью модуля Configuration Translation.'
selector: '#edit-label'
language-edit-direction:
id: language-edit-direction
plugin: text
label: 'Направление языка'
weight: 4
body: '<p>Выберите направление языка - "Слева-направо" или "Справа-налево".</p><p>Обратите внимание, что не все темы поддерживают направление "Справа-налево", поэтому проверьте свою тему перед использованием направления "Справа-налево".</p>'
selector: '#edit-direction--wrapper--description'
language-edit-continue:
id: language-edit-continue
plugin: text
label: Продолжение
weight: 5
body: '<p>Now that you have an overview of the "Edit language" feature, you can continue by:<ul><li>Editing a language</li><li><a href="[site:url]admin/config/regional/language">Viewing configured languages</a></li></ul></p>'
uuid: 27f4b3b1-f4e2-44b0-8b96-7f553e2a3c1c
langcode: ru
status: true
dependencies:
module:
- language
_core:
default_config_hash: 5aT8miVsOaELOqImwK2AGc58inm6ttUPMPoG_1hvGu4
id: language
label: Язык
module: language
routes:
-
route_name: entity.configurable_language.collection
tips:
language-overview:
id: language-overview
plugin: text
label: Языки
weight: 1
body: '<p>Страница "Языки" позволяет вам добавлять, редактировать, удалять, и упорядочивать языки для сайта.</p>'
language-add:
id: language-add
plugin: text
label: 'Добавление языков'
weight: 2
body: '<p>Для добавления языков на ваш сайт, нажмите кнопку "Добавить язык".</p><p>Добавленные языки будут отображаться в списке языков и потом могут быть отредактированы или удалены.</p>'
selector: .button-action
language-reorder:
id: language-reorder
plugin: text
label: 'Переупорядочивание языков'
weight: 3
body: '<p>Чтобы изменить порядок языков на сайте, используйте иконки перемещения рядом с каждым языком.</p><p>В указанной здесь последовательности языки будут отображаться в списках языков на сайте, например в блоках переключения языков, которые предоставляются модулями Перевод Интерфейса и Перевод Материалов.</p><p>После окончания изменения порядка языков, нажмите на кнопку "Сохранить конфигурацию" чтобы изменения вступили в силу.</p>'
selector: .draggable
language-default:
id: language-default
plugin: text
label: 'Установить языком по умолчанию'
weight: 4
body: '<p>Вы можете выбрать язык сайта по умолчанию, выбрав один из настроенных языков языком по умолчанию. Сайт будет использовать язык по умолчанию в ситуациях, когда выбор не сделан, но язык должен быть установлен, например язык отображаемого интерфейса.</p>'
selector: .js-form-item-site-default-language
language-operations:
id: language-operations
plugin: text
label: 'Изменение языков'
weight: 5
body: '<p>Операции предназначенные для редактирования и удаления ваших языков.</p><p>Вы можете отредактировать имя и направление языка.</p><p>Удалённые языки можно вернуть обратно позже. Удаление языка удалит все переводы интерфейса связанные с ним, и для всех материалов на этом языке будет установлен нейтральный язык. Обратите внимание, что вы не можете удалить язык установленный по умолчанию для сайта.</p>'
selector: .dropbutton-wrapper
language-continue:
id: language-continue
plugin: text
label: Продолжение
weight: 6
body: '<p>Now that you have an overview of the "Languages" page, you can continue by:<ul><li><a href="[site:url]admin/config/regional/language/add">Adding a language</a></li><li>Reordering languages</li><li>Editing a language</li><li>Deleting a language</li></ul></p>'
uuid: 6ad947b3-e70a-4ab3-a49e-c280481a96bf
langcode: ru
status: true
dependencies:
module:
- locale
_core:
default_config_hash: j37WXJhppplgaN9gVcWddV_zlsCozbxxEkIkCon2olQ
id: locale
label: Перевод
module: locale
routes:
-
route_name: locale.translate_page
tips:
locale-overview:
id: locale-overview
plugin: text
label: 'Перевод пользовательского интерфейса'
weight: 1
body: 'На данной странице вы можете перевести пользовательский интерфейс или изменить существующий перевод. Если вы изначально установили сайт на Английском, перед началом использования этой страницы, вам необходимо добавить другой язык на странице <a href="[site:url]admin/config/regional/language">Языки</a>.'
locale-language:
id: locale-language
plugin: text
label: 'Язык перевода'
weight: 2
body: 'Выберите язык, который вы хотите перевести.'
selector: '#edit-langcode'
locale-search:
id: locale-search
plugin: text
label: Поиск
weight: 3
body: 'Введите опредёленное слово или предложение, которое необходимо перевести. Можно ввести только часть слова.'
selector: '#edit-string'
locale-filter:
id: locale-filter
plugin: text
label: 'Фильтрация результатов поиска'
weight: 4
body: 'Вы можете искать непереведённые строки, если вы хотите перевести что-нибудь ещё непереведённое. Если вы хотите изменить существующий перевод, вы можете искать только переведённые строки.'
selector: '#edit-translation'
locale-submit:
id: locale-submit
plugin: text
label: 'Применить критерий поиска'
weight: 5
body: 'Для применения выбранного критерия поиска, нажмите кнопку <em>Фильтр</em>.'
selector: '#edit-submit'
locale-translate:
id: locale-translate
plugin: text
label: Переводы
weight: 6
body: 'Вы можете написать свой собственный вариант перевода в текстовых полях правой колонки. Попробуйте выяснить, в каком контексте будет использоваться текст для того, чтобы перевести его как можно точнее.'
selector: .js-form-type-textarea
locale-validate:
id: locale-validate
plugin: text
label: 'Подтверждение перевода'
weight: 7
body: 'После завершения ваших переводов нажмите кнопку <em>Сохранить переводы</em>. Необходимо сохранять переводы каждый раз перед изменением страницы или выполнением нового поиска.'
selector: '#edit-submit--2'
locale-continue:
id: locale-continue
plugin: text
label: Продолжение
weight: 8
body: 'Выполненные здесь переводы будут использоваться в пользовательском интерфейсе сайта. Если их необходимо использовать на другом сайте или отредактировать во внешнем редакторе переводов, <a href="[site:url]admin/config/regional/translate/export">экспортируйте их</a> в po-файл, а затем <a href="[site:url]admin/config/regional/translate/import">импортируйте их</a>.'
uuid: f40a2c6c-4c27-41c1-be87-c68eea43e492
langcode: ru
status: true
dependencies:
module:
- views_ui
_core:
default_config_hash: 2uu1-EemI4WHASQmaiRHlUBUBdIuR7h6zLZxHRGTL7A
id: views-ui
label: 'Страница редактирования представления'
module: views_ui
routes:
-
route_name: entity.view.edit_form
-
route_name: entity.view.edit_display_form
tips:
views-main:
id: views-main
plugin: text
label: 'Управление настройками представления'
weight: 1
body: 'Просмотр или редактирование конфигурации.'
views-ui-displays:
id: views-ui-displays
plugin: text
label: 'Отображения в этом представлении'
weight: 2
body: 'Отображение - это способ вывода результатов, например, в виде страницы или блока. Представление может содержать несколько отображений, которые перечислены здесь. Активное отображение подсвечено.'
selector: '#views-display-top'
views-ui-view-admin:
id: views-ui-view-admin
plugin: text
label: 'Администрирование представления'
weight: 3
body: 'Выполнение административных задач, включающие добавление описания и создание копии. Нажмите раскрывающуюся кнопку для просмотра доступных действий.'
selector: '#views-display-extra-actions'
position: left-start
views-ui-format:
id: views-ui-format
plugin: text
label: 'Формат вывода'
weight: 4
body: 'Выберите способ вывода результатов. Например, выберите <em>Содержимое</em>, для вывода каждого элемента полностью, используя настроенные параметры отображения. Или выберите <em>Поля</em>, с помощью которых можно выводить только определённые поля для каждого результата. Дополнительные форматы могут быть добавлены с помощью установки модулей для <em>расширения</em> функциональности ДАР CMS.'
selector: .views-ui-display-tab-bucket.format
views-ui-fields:
id: views-ui-fields
plugin: text
label: Поля
weight: 5
body: 'Если это представление использует поля, они будут перечислены здесь. Нажмите на поле для того, чтобы настроить его.'
selector: .views-ui-display-tab-bucket.field
views-ui-filter:
id: views-ui-filter
plugin: text
label: 'Фильтрация представления'
weight: 6
body: 'Добавьте фильтры для ограничения вывода результатов. Например, для отображения только <em>опубликованных</em> материалов, необходимо добавить фильтр <em>Опубликовано</em> и выбрать <em>Да</em>'
selector: .views-ui-display-tab-bucket.filter
views-ui-filter-operations:
id: views-ui-filter-operations
plugin: text
label: 'Действия с фильтрами'
weight: 7
body: 'Добавить, упорядочить или удалить фильтры.'
selector: '.views-ui-display-tab-bucket.filter .dropbutton-widget'
views-ui-sorts:
id: views-ui-sorts
plugin: text
label: 'Критерий сортировки'
weight: 8
body: 'Управляйте порядком вывода результатов. Нажмите на активное правило сортировки для его настройки.'
selector: .views-ui-display-tab-bucket.sort
views-ui-sorts-operations:
id: views-ui-sorts-operations
plugin: text
label: 'Действия сортировки'
weight: 9
body: 'Добавление, упорядочивание и удаление правил сортировки.'
selector: '.views-ui-display-tab-bucket.sort .dropbutton-widget'
views-ui-preview:
id: views-ui-preview
plugin: text
label: Предпросмотр
weight: 10
body: 'Показать предварительный просмотр вывода представления.'
selector: '#preview-submit'
position: left-start
_core:
default_config_hash: BqkUHiXXGvu2L7NR_nblxtP6f03MdD16XSMWwVM0QEc
paths_per_scan: 30
...@@ -359,8 +359,6 @@ display: ...@@ -359,8 +359,6 @@ display:
multiple: false multiple: false
remember_roles: remember_roles:
authenticated: authenticated authenticated: authenticated
anonymous: '0'
administrator: '0'
is_grouped: false is_grouped: false
group_info: group_info:
label: '' label: ''
...@@ -401,8 +399,6 @@ display: ...@@ -401,8 +399,6 @@ display:
multiple: false multiple: false
remember_roles: remember_roles:
authenticated: authenticated authenticated: authenticated
anonymous: '0'
administrator: '0'
reduce: false reduce: false
is_grouped: false is_grouped: false
group_info: group_info:
...@@ -503,6 +499,7 @@ display: ...@@ -503,6 +499,7 @@ display:
empty_table: true empty_table: true
caption: '' caption: ''
description: '' description: ''
class: ''
row: row:
type: fields type: fields
query: query:
......
...@@ -667,8 +667,6 @@ display: ...@@ -667,8 +667,6 @@ display:
multiple: false multiple: false
remember_roles: remember_roles:
authenticated: authenticated authenticated: authenticated
anonymous: '0'
administrator: '0'
is_grouped: false is_grouped: false
group_info: group_info:
label: '' label: ''
...@@ -707,8 +705,6 @@ display: ...@@ -707,8 +705,6 @@ display:
multiple: false multiple: false
remember_roles: remember_roles:
authenticated: authenticated authenticated: authenticated
anonymous: '0'
administrator: '0'
is_grouped: false is_grouped: false
group_info: group_info:
label: '' label: ''
...@@ -752,8 +748,6 @@ display: ...@@ -752,8 +748,6 @@ display:
multiple: false multiple: false
remember_roles: remember_roles:
authenticated: authenticated authenticated: authenticated
anonymous: '0'
administrator: '0'
reduce: false reduce: false
is_grouped: false is_grouped: false
group_info: group_info:
...@@ -832,6 +826,7 @@ display: ...@@ -832,6 +826,7 @@ display:
empty_table: true empty_table: true
caption: '' caption: ''
description: '' description: ''
class: ''
row: row:
type: fields type: fields
query: query:
...@@ -1486,8 +1481,6 @@ display: ...@@ -1486,8 +1481,6 @@ display:
multiple: false multiple: false
remember_roles: remember_roles:
authenticated: authenticated authenticated: authenticated
anonymous: '0'
administrator: '0'
is_grouped: false is_grouped: false
group_info: group_info:
label: '' label: ''
...@@ -1526,8 +1519,6 @@ display: ...@@ -1526,8 +1519,6 @@ display:
multiple: false multiple: false
remember_roles: remember_roles:
authenticated: authenticated authenticated: authenticated
anonymous: '0'
administrator: '0'
is_grouped: false is_grouped: false
group_info: group_info:
label: '' label: ''
...@@ -1571,8 +1562,6 @@ display: ...@@ -1571,8 +1562,6 @@ display:
multiple: false multiple: false
remember_roles: remember_roles:
authenticated: authenticated authenticated: authenticated
anonymous: '0'
administrator: '0'
reduce: false reduce: false
is_grouped: false is_grouped: false
group_info: group_info:
......
...@@ -311,8 +311,6 @@ display: ...@@ -311,8 +311,6 @@ display:
multiple: false multiple: false
remember_roles: remember_roles:
authenticated: authenticated authenticated: authenticated
anonymous: '0'
administrator: '0'
is_grouped: false is_grouped: false
group_info: group_info:
label: '' label: ''
...@@ -353,8 +351,6 @@ display: ...@@ -353,8 +351,6 @@ display:
multiple: false multiple: false
remember_roles: remember_roles:
authenticated: authenticated authenticated: authenticated
anonymous: '0'
administrator: '0'
reduce: false reduce: false
is_grouped: false is_grouped: false
group_info: group_info:
...@@ -444,8 +440,6 @@ display: ...@@ -444,8 +440,6 @@ display:
multiple: false multiple: false
remember_roles: remember_roles:
authenticated: authenticated authenticated: authenticated
anonymous: '0'
administrator: '0'
reduce: false reduce: false
is_grouped: false is_grouped: false
group_info: group_info:
...@@ -568,6 +562,7 @@ display: ...@@ -568,6 +562,7 @@ display:
empty_table: true empty_table: true
caption: '' caption: ''
description: '' description: ''
class: ''
row: row:
type: fields type: fields
query: query:
......
...@@ -541,8 +541,6 @@ display: ...@@ -541,8 +541,6 @@ display:
multiple: false multiple: false
remember_roles: remember_roles:
authenticated: authenticated authenticated: authenticated
anonymous: '0'
administrator: '0'
is_grouped: false is_grouped: false
group_info: group_info:
label: '' label: ''
...@@ -583,8 +581,6 @@ display: ...@@ -583,8 +581,6 @@ display:
multiple: false multiple: false
remember_roles: remember_roles:
authenticated: authenticated authenticated: authenticated
anonymous: '0'
administrator: '0'
is_grouped: false is_grouped: false
group_info: group_info:
label: '' label: ''
...@@ -625,8 +621,6 @@ display: ...@@ -625,8 +621,6 @@ display:
multiple: false multiple: false
remember_roles: remember_roles:
authenticated: authenticated authenticated: authenticated
anonymous: '0'
administrator: '0'
reduce: false reduce: false
is_grouped: false is_grouped: false
group_info: group_info:
...@@ -719,6 +713,7 @@ display: ...@@ -719,6 +713,7 @@ display:
empty_table: true empty_table: true
caption: '' caption: ''
description: '' description: ''
class: ''
row: row:
type: fields type: fields
query: query:
...@@ -1110,6 +1105,7 @@ display: ...@@ -1110,6 +1105,7 @@ display:
empty_table: true empty_table: true
caption: '' caption: ''
description: '' description: ''
class: ''
row: row:
type: fields type: fields
options: { } options: { }
......
...@@ -346,6 +346,7 @@ display: ...@@ -346,6 +346,7 @@ display:
summary: '' summary: ''
order: asc order: asc
empty_table: false empty_table: false
class: ''
row: row:
type: fields type: fields
options: options:
......
...@@ -620,8 +620,6 @@ display: ...@@ -620,8 +620,6 @@ display:
multiple: false multiple: false
remember_roles: remember_roles:
authenticated: authenticated authenticated: authenticated
anonymous: '0'
administrator: '0'
is_grouped: false is_grouped: false
group_info: group_info:
label: '' label: ''
...@@ -748,8 +746,6 @@ display: ...@@ -748,8 +746,6 @@ display:
multiple: false multiple: false
remember_roles: remember_roles:
authenticated: authenticated authenticated: authenticated
anonymous: '0'
administrator: '0'
reduce: false reduce: false
is_grouped: false is_grouped: false
group_info: group_info:
...@@ -865,6 +861,7 @@ display: ...@@ -865,6 +861,7 @@ display:
empty_table: true empty_table: true
caption: '' caption: ''
description: '' description: ''
class: ''
row: row:
type: fields type: fields
query: query:
...@@ -1467,8 +1464,6 @@ display: ...@@ -1467,8 +1464,6 @@ display:
multiple: false multiple: false
remember_roles: remember_roles:
authenticated: authenticated authenticated: authenticated
anonymous: '0'
administrator: '0'
is_grouped: false is_grouped: false
group_info: group_info:
label: '' label: ''
...@@ -2168,8 +2163,6 @@ display: ...@@ -2168,8 +2163,6 @@ display:
multiple: false multiple: false
remember_roles: remember_roles:
authenticated: authenticated authenticated: authenticated
anonymous: '0'
administrator: '0'
is_grouped: false is_grouped: false
group_info: group_info:
label: '' label: ''
...@@ -2869,8 +2862,6 @@ display: ...@@ -2869,8 +2862,6 @@ display:
multiple: false multiple: false
remember_roles: remember_roles:
authenticated: authenticated authenticated: authenticated
anonymous: '0'
administrator: '0'
is_grouped: false is_grouped: false
group_info: group_info:
label: '' label: ''
...@@ -2959,8 +2950,6 @@ display: ...@@ -2959,8 +2950,6 @@ display:
multiple: false multiple: false
remember_roles: remember_roles:
authenticated: authenticated authenticated: authenticated
anonymous: '0'
administrator: '0'
reduce: false reduce: false
is_grouped: false is_grouped: false
group_info: group_info:
...@@ -3571,8 +3560,6 @@ display: ...@@ -3571,8 +3560,6 @@ display:
multiple: false multiple: false
remember_roles: remember_roles:
authenticated: authenticated authenticated: authenticated
anonymous: '0'
administrator: '0'
is_grouped: false is_grouped: false
group_info: group_info:
label: '' label: ''
...@@ -3729,8 +3716,6 @@ display: ...@@ -3729,8 +3716,6 @@ display:
multiple: false multiple: false
remember_roles: remember_roles:
authenticated: authenticated authenticated: authenticated
anonymous: '0'
administrator: '0'
is_grouped: false is_grouped: false
group_info: group_info:
label: '' label: ''
...@@ -3771,8 +3756,6 @@ display: ...@@ -3771,8 +3756,6 @@ display:
multiple: false multiple: false
remember_roles: remember_roles:
authenticated: authenticated authenticated: authenticated
anonymous: '0'
administrator: '0'
reduce: false reduce: false
is_grouped: false is_grouped: false
group_info: group_info:
...@@ -3862,8 +3845,6 @@ display: ...@@ -3862,8 +3845,6 @@ display:
multiple: false multiple: false
remember_roles: remember_roles:
authenticated: authenticated authenticated: authenticated
anonymous: '0'
administrator: '0'
reduce: false reduce: false
is_grouped: false is_grouped: false
group_info: group_info:
......
...@@ -397,7 +397,6 @@ display: ...@@ -397,7 +397,6 @@ display:
multiple: false multiple: false
remember_roles: remember_roles:
authenticated: authenticated authenticated: authenticated
anonymous: '0'
reduce: false reduce: false
is_grouped: false is_grouped: false
group_info: group_info:
...@@ -439,7 +438,6 @@ display: ...@@ -439,7 +438,6 @@ display:
multiple: false multiple: false
remember_roles: remember_roles:
authenticated: authenticated authenticated: authenticated
anonymous: '0'
is_grouped: false is_grouped: false
group_info: group_info:
label: '' label: ''
...@@ -480,7 +478,6 @@ display: ...@@ -480,7 +478,6 @@ display:
multiple: false multiple: false
remember_roles: remember_roles:
authenticated: authenticated authenticated: authenticated
anonymous: '0'
reduce: false reduce: false
is_grouped: false is_grouped: false
group_info: group_info:
......
...@@ -304,8 +304,6 @@ display: ...@@ -304,8 +304,6 @@ display:
multiple: false multiple: false
remember_roles: remember_roles:
authenticated: authenticated authenticated: authenticated
anonymous: '0'
administrator: '0'
is_grouped: false is_grouped: false
group_info: group_info:
label: '' label: ''
...@@ -346,8 +344,6 @@ display: ...@@ -346,8 +344,6 @@ display:
multiple: false multiple: false
remember_roles: remember_roles:
authenticated: authenticated authenticated: authenticated
anonymous: '0'
administrator: '0'
is_grouped: false is_grouped: false
group_info: group_info:
label: '' label: ''
...@@ -391,8 +387,6 @@ display: ...@@ -391,8 +387,6 @@ display:
multiple: false multiple: false
remember_roles: remember_roles:
authenticated: authenticated authenticated: authenticated
anonymous: '0'
administrator: '0'
is_grouped: true is_grouped: true
group_info: group_info:
label: 'Status code' label: 'Status code'
...@@ -482,8 +476,6 @@ display: ...@@ -482,8 +476,6 @@ display:
multiple: false multiple: false
remember_roles: remember_roles:
authenticated: authenticated authenticated: authenticated
anonymous: '0'
administrator: '0'
reduce: false reduce: false
is_grouped: false is_grouped: false
group_info: group_info:
...@@ -564,6 +556,7 @@ display: ...@@ -564,6 +556,7 @@ display:
empty_table: false empty_table: false
caption: '' caption: ''
description: '' description: ''
class: ''
row: row:
type: fields type: fields
query: query:
......
...@@ -412,6 +412,7 @@ display: ...@@ -412,6 +412,7 @@ display:
empty_table: false empty_table: false
caption: '' caption: ''
description: '' description: ''
class: ''
row: row:
type: fields type: fields
query: query:
......
...@@ -552,8 +552,6 @@ display: ...@@ -552,8 +552,6 @@ display:
multiple: false multiple: false
remember_roles: remember_roles:
authenticated: authenticated authenticated: authenticated
anonymous: '0'
administrator: '0'
is_grouped: false is_grouped: false
group_info: group_info:
label: '' label: ''
...@@ -597,8 +595,6 @@ display: ...@@ -597,8 +595,6 @@ display:
multiple: false multiple: false
remember_roles: remember_roles:
authenticated: authenticated authenticated: authenticated
anonymous: '0'
administrator: '0'
is_grouped: true is_grouped: true
group_info: group_info:
label: Статус label: Статус
...@@ -645,8 +641,6 @@ display: ...@@ -645,8 +641,6 @@ display:
multiple: false multiple: false
remember_roles: remember_roles:
authenticated: authenticated authenticated: authenticated
anonymous: '0'
administrator: '0'
reduce: false reduce: false
is_grouped: false is_grouped: false
group_info: group_info:
...@@ -687,8 +681,6 @@ display: ...@@ -687,8 +681,6 @@ display:
multiple: false multiple: false
remember_roles: remember_roles:
authenticated: authenticated authenticated: authenticated
anonymous: '0'
administrator: '0'
reduce: false reduce: false
is_grouped: false is_grouped: false
group_info: group_info:
...@@ -862,6 +854,7 @@ display: ...@@ -862,6 +854,7 @@ display:
sticky: false sticky: false
summary: '' summary: ''
empty_table: true empty_table: true
class: ''
row: row:
type: fields type: fields
query: query:
......
...@@ -526,8 +526,6 @@ display: ...@@ -526,8 +526,6 @@ display:
multiple: true multiple: true
remember_roles: remember_roles:
authenticated: authenticated authenticated: authenticated
anonymous: '0'
administrator: '0'
reduce: false reduce: false
is_grouped: false is_grouped: false
group_info: group_info:
...@@ -567,8 +565,6 @@ display: ...@@ -567,8 +565,6 @@ display:
multiple: true multiple: true
remember_roles: remember_roles:
authenticated: authenticated authenticated: authenticated
anonymous: '0'
administrator: '0'
reduce: false reduce: false
is_grouped: false is_grouped: false
group_info: group_info:
...@@ -663,6 +659,7 @@ display: ...@@ -663,6 +659,7 @@ display:
empty_table: false empty_table: false
caption: '' caption: ''
description: '' description: ''
class: ''
row: row:
type: fields type: fields
query: query:
......
...@@ -567,6 +567,7 @@ display: ...@@ -567,6 +567,7 @@ display:
empty_table: false empty_table: false
caption: '' caption: ''
description: '' description: ''
class: ''
row: row:
type: fields type: fields
options: options:
...@@ -1234,8 +1235,6 @@ display: ...@@ -1234,8 +1235,6 @@ display:
multiple: false multiple: false
remember_roles: remember_roles:
authenticated: authenticated authenticated: authenticated
anonymous: '0'
administrator: '0'
is_grouped: false is_grouped: false
group_info: group_info:
label: '' label: ''
...@@ -1276,8 +1275,6 @@ display: ...@@ -1276,8 +1275,6 @@ display:
multiple: false multiple: false
remember_roles: remember_roles:
authenticated: authenticated authenticated: authenticated
anonymous: '0'
administrator: '0'
is_grouped: false is_grouped: false
group_info: group_info:
label: '' label: ''
...@@ -1318,9 +1315,6 @@ display: ...@@ -1318,9 +1315,6 @@ display:
multiple: false multiple: false
remember_roles: remember_roles:
authenticated: authenticated authenticated: authenticated
anonymous: '0'
administrator: '0'
demo_region: '0'
is_grouped: false is_grouped: false
group_info: group_info:
label: '' label: ''
...@@ -1430,6 +1424,7 @@ display: ...@@ -1430,6 +1424,7 @@ display:
empty_table: false empty_table: false
caption: '' caption: ''
description: '' description: ''
class: ''
row: row:
type: fields type: fields
options: options:
...@@ -1517,6 +1512,7 @@ display: ...@@ -1517,6 +1512,7 @@ display:
empty_table: false empty_table: false
caption: '' caption: ''
description: '' description: ''
class: ''
row: row:
type: fields type: fields
options: options:
...@@ -2228,8 +2224,6 @@ display: ...@@ -2228,8 +2224,6 @@ display:
multiple: false multiple: false
remember_roles: remember_roles:
authenticated: authenticated authenticated: authenticated
anonymous: '0'
administrator: '0'
is_grouped: false is_grouped: false
group_info: group_info:
label: '' label: ''
...@@ -2270,8 +2264,6 @@ display: ...@@ -2270,8 +2264,6 @@ display:
multiple: false multiple: false
remember_roles: remember_roles:
authenticated: authenticated authenticated: authenticated
anonymous: '0'
administrator: '0'
is_grouped: false is_grouped: false
group_info: group_info:
label: '' label: ''
...@@ -2312,9 +2304,6 @@ display: ...@@ -2312,9 +2304,6 @@ display:
multiple: false multiple: false
remember_roles: remember_roles:
authenticated: authenticated authenticated: authenticated
anonymous: '0'
administrator: '0'
demo_region: '0'
is_grouped: false is_grouped: false
group_info: group_info:
label: '' label: ''
...@@ -2424,6 +2413,7 @@ display: ...@@ -2424,6 +2413,7 @@ display:
empty_table: false empty_table: false
caption: '' caption: ''
description: '' description: ''
class: ''
row: row:
type: fields type: fields
options: options:
...@@ -3027,8 +3017,6 @@ display: ...@@ -3027,8 +3017,6 @@ display:
multiple: false multiple: false
remember_roles: remember_roles:
authenticated: authenticated authenticated: authenticated
anonymous: '0'
administrator: '0'
is_grouped: false is_grouped: false
group_info: group_info:
label: '' label: ''
...@@ -3069,8 +3057,6 @@ display: ...@@ -3069,8 +3057,6 @@ display:
multiple: false multiple: false
remember_roles: remember_roles:
authenticated: authenticated authenticated: authenticated
anonymous: '0'
administrator: '0'
is_grouped: false is_grouped: false
group_info: group_info:
label: '' label: ''
...@@ -3111,9 +3097,6 @@ display: ...@@ -3111,9 +3097,6 @@ display:
multiple: false multiple: false
remember_roles: remember_roles:
authenticated: authenticated authenticated: authenticated
anonymous: '0'
administrator: '0'
demo_region: '0'
is_grouped: false is_grouped: false
group_info: group_info:
label: '' label: ''
...@@ -3223,6 +3206,7 @@ display: ...@@ -3223,6 +3206,7 @@ display:
empty_table: false empty_table: false
caption: '' caption: ''
description: '' description: ''
class: ''
row: row:
type: fields type: fields
options: options:
......
...@@ -154,8 +154,6 @@ display: ...@@ -154,8 +154,6 @@ display:
multiple: false multiple: false
remember_roles: remember_roles:
authenticated: authenticated authenticated: authenticated
anonymous: '0'
administrator: '0'
is_grouped: false is_grouped: false
group_info: group_info:
label: '' label: ''
......
...@@ -333,7 +333,6 @@ libraries: ...@@ -333,7 +333,6 @@ libraries:
requirements: requirements:
cdn: true cdn: true
clientside_validation: true clientside_validation: true
bootstrap: true
spam: true spam: true
third_party_settings: third_party_settings:
captcha: captcha:
......
...@@ -131,10 +131,7 @@ dependencies: ...@@ -131,10 +131,7 @@ dependencies:
- xls_serialization - xls_serialization
themes: themes:
- bartik
- bootstrap - bootstrap
- claro - claro
- classy
- dar_simple - dar_simple
- seven
- stable - stable
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
* Install, update and uninstall functions for the profilename install profile. * Install, update and uninstall functions for the profilename install profile.
*/ */
use Drupal\Core\Config\FileStorage;
use Drupal\node\Entity\Node; use Drupal\node\Entity\Node;
/** /**
...@@ -27,69 +26,8 @@ function dar_install() { ...@@ -27,69 +26,8 @@ function dar_install() {
} }
/** /**
* Update configs and install some new modules. * Implements hook_update_last_removed().
*/ */
function dar_update_10001(&$sandbox) { function dar_update_last_removed() {
$install_modules = [ return 10001;
'ban',
'better_exposed_filters',
'ckeditor5',
'ckeditor5_plugin_pack',
'ckeditor5_plugin_pack',
'ckeditor5_plugin_pack_auto_image',
'ckeditor5_plugin_pack_find_and_replace',
'ckeditor5_plugin_pack_font',
'ckeditor5_plugin_pack_highlight',
'ckeditor5_plugin_pack_indent_block',
'ckeditor5_plugin_pack_page_break',
'ckeditor5_plugin_pack_text_transformation',
'ckeditor5_plugin_pack_todo_document_list',
'ckeditor5_plugin_pack_word_count',
'csv_serialization',
'editor_advanced_link',
'field_group',
'flag',
'flood_control',
'honeypot',
'media_bulk_upload_dropzonejs',
'media_file_delete',
'menu_admin_per_menu',
'menu_link_content',
'menu_per_role',
'mobile_detect',
'optional_end_date',
'pathauto',
'select2',
'svg_image',
'taxonomy_access_fix',
'twig_attributes',
'twig_field_value',
'twig_tweak',
'ultimate_cron',
'views_aggregator',
'views_bulk_operations',
'xls_serialization',
];
\Drupal::service('module_installer')->install($install_modules);
$config_path = \Drupal::service('extension.list.module')->getPath('dar') . '/config/install';
$source = new FileStorage($config_path);
$config_storage = \Drupal::service('config.storage');
$configs_to_update = [
'bootstrap.settings',
'ckeditor5_plugin_pack.settings',
'editor.editor.basic_html',
'editor.editor.full_html',
'editor.editor.webform_default',
'filter.format.basic_html',
'filter.format.full_html',
'filter.format.plain_text',
'filter.format.restricted_html',
'filter.format.webform_default',
'filter.settings',
'media_file_delete.settings',
];
foreach ($configs_to_update as $config_to_update) {
$config_storage->write($config_to_update, $source->read($config_to_update));
}
} }
# Russian translation of Admin Toolbar (3.6.2)
# Copyright (c) 2025 by the Russian translation team
#
msgid ""
msgstr ""
"Project-Id-Version: Admin Toolbar (3.6.2)\n"
"POT-Creation-Date: 2025-07-29 22:46+0000\n"
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=((((n%10)==1)&&((n%100)!=11))?(0):(((((n%10)>=2)&&((n%10)<=4))&&(((n%100)<10)||((n%100)>=20)))?(1):2));\n"
msgid "Delete"
msgstr "Удалить"
msgid "Development"
msgstr "Разработка"
msgid "Disabled"
msgstr "Отключено"
msgid "Enabled"
msgstr "Включено"
msgid "Administration"
msgstr "Администрирование"
msgid "Edit"
msgstr "Редактировать"
msgid "Search"
msgstr "Поиск"
msgid "Settings"
msgstr "Настройки"
msgid "Import"
msgstr "Импортировать"
msgid "Export"
msgstr "Экспортировать"
msgid "Update"
msgstr "Обновить"
msgid "Views"
msgstr "Представление"
msgid "Menu"
msgstr "Меню"
msgid "Advanced settings"
msgstr "Расширенные настройки"
msgid "Files"
msgstr "Файлы"
msgid "Add content"
msgstr "Добавить материал"
msgid "Add view"
msgstr "Добавить представление"
msgid "Roles"
msgstr "Роли"
msgid "Search settings"
msgstr "Настройки поиска"
msgid "Media"
msgstr "Мультимедиа"
msgid "Tools"
msgstr "Инструменты"
msgid "Logout"
msgstr "Выход"
msgid "Add user"
msgstr "Добавить пользователя"
msgid "Add menu"
msgstr "Добавить меню"
msgid "Toolbar settings"
msgstr "Настройки панели инструментов"
msgid "Missing"
msgstr "Отсутствует"
msgid "Permissions"
msgstr "Права доступа"
msgid "Plugin"
msgstr "Плагин"
msgid "Blocks"
msgstr "Блоки"
msgid "Add vocabulary"
msgstr "Добавить словарь"
msgid "Manage fields"
msgstr "Управление полями"
msgid "Index"
msgstr "Индекс"
msgid "Hide"
msgstr "Скрыть"
msgid "Render cache"
msgstr "Кэш рендеринга."
msgid "Reinstall modules"
msgstr "Переустановка модулей"
msgid "Session viewer"
msgstr "Просмотрщик сессии"
msgid "Devel"
msgstr "Devel"
msgid "All types"
msgstr "Все типы"
msgid "Add role"
msgstr "Добавить роль"
msgid "About"
msgstr "Информация"
msgid "Rebuild menu"
msgstr "Перестроить меню"
msgid "Run cron"
msgstr "Запустить cron"
msgid "Run updates"
msgstr "Запустить обновления"
msgid "Uses"
msgstr "Использование"
msgid "Execute PHP Code"
msgstr "Выполнить PHP код"
msgid "Theme registry"
msgstr "Реестр темы"
msgid "Devel settings"
msgstr "Настройки Devel"
msgid "Add language"
msgstr "Добавить язык"
msgid "Add link"
msgstr "Добавить ссылку"
msgid "Add content type"
msgstr "Добавить тип материала"
msgid "Cron ran successfully."
msgstr "Запуск <em>cron</em> выполнен."
msgid "Flush all caches"
msgstr "Очистить все кэши"
msgid "Menu depth"
msgstr "Глубина меню"
msgid "Manage display"
msgstr "Управление отображением"
msgid "Detection and selection"
msgstr "Определение и выбор"
msgid "Add media"
msgstr "Добавить медиа"
msgid "Edit permissions"
msgstr "Редактировать права доступа"
msgid "Install new module"
msgstr "Установить новый модуль"
msgid "Install new theme"
msgstr "Установить новую тему"
msgid "Entity info"
msgstr "Информация о сущности"
msgid "Add view mode"
msgstr "Добавить режим просмотра"
msgid "Manage form display"
msgstr "Управление отображением формы"
msgid "Rebuild theme registry"
msgstr "Перестроить реестр темы"
msgid "Twig"
msgstr "Twig"
msgid "Manage permissions"
msgstr "Управление разрешениями"
msgid "Used in views"
msgstr "Используется в представлениях"
msgid "Block types"
msgstr "Типы блоков"
msgid "All caches cleared."
msgstr "Все кэши очищены."
msgid "Add form mode"
msgstr "Добавить режим формы"
msgid "Add contact form"
msgstr "Добавить контактную форму"
msgid "Admin Toolbar"
msgstr "Панель администратора"
msgid "Admin Toolbar Tools"
msgstr "Инструменты панели администратора"
msgid "Static caches"
msgstr "Статические кеши"
msgid "CSS and JavaScript cache cleared."
msgstr "Кэш CSS и JS очищен."
msgid "Media library"
msgstr "Медиа-библиотека"
msgid "Admin Toolbar Extra Tools"
msgstr ""
"Дополнительные инструменты панели "
"администратора"
msgid "Config editor"
msgstr "Редактор конфигураций"
msgid "State editor"
msgstr "Редактор системных переменных"
msgid "Uninstall module"
msgstr "Удалить модуль"
msgid "Element Info"
msgstr "Информация об элементе"
msgid "Flush plugins cache"
msgstr "Очистить кэш плагинов"
msgid "Flush static cache"
msgstr "Очистить кэш статики"
msgid "Flush routing and links cache"
msgstr "Очистить кэш путей и ссылок"
msgid "Flush render cache"
msgstr "Очистить кэш рендера"
msgid "Plugins cache cleared."
msgstr "Кэш плагинов очищен."
msgid "Static cache cleared."
msgstr "Статичный кэш очищен."
msgid "Routing and links cache cleared."
msgstr "Кэш маршрутизации и ссылок очищен."
msgid "Render cache cleared."
msgstr "Рендер-кэш очищен."
msgid "Devel Toolbar Settings"
msgstr "Настройки панели инструментов Devel"
msgid "Add media type"
msgstr "Добавить тип медиа"
msgid "Flush views cache"
msgstr "Очистить кэш представлений"
msgid "Views cache cleared."
msgstr "Кэш представлений сброшен."
msgid ""
"The Admin Toolbar module enhances the <a href=\":toolbar\">Toolbar</a> "
"module by providing fast access to all the administrative links at the "
"top of your site. Admin Toolbar remains a very \"lightweight\" module "
"by closely integrating with all Toolbar functionality. It can be used "
"in conjunction with all the sub modules included on Admin Toolbar, for "
"quick access to system commands such as Flush all caches, <a "
"href=\":automated_cron\">Run cron</a>, Run Updates, etc."
msgstr ""
"Модуль Admin Toolbar расширяет возможности "
"модуля <a href=\":toolbar\">Toolbar</a>, "
"предоставляя быстрый доступ ко всем "
"административным ссылкам в верхней "
"части вашего сайта. Admin Toolbar остается "
"очень простым модулем, тесно "
"интегрированным со всеми функциями "
"Toolbar. Его можно использовать в "
"сочетании со всеми вспомогательными "
"модулями для быстрого доступа к "
"системным командам, таким как очистка "
"всех кэшей, <a href=\":automated_cron\">запуск "
"cron</a>, запуск обновлений и т. д."
msgid ""
"The Admin Toolbar greatly improves the user experience for those who "
"regularly interact with the site Toolbar by providing fast, full "
"access to all links in the site Toolbar without having to click to get "
"there."
msgstr ""
"Admin Toolbar значительно облегчает жизнь "
"тем, кто регулярно взаимодействует с "
"панелью инструментов сайта, "
"предоставляя быстрый и полный доступ "
"ко всем ссылкам панели инструментов "
"сайта без необходимости делать лишние "
"щелчки, чтобы добраться до нужного "
"пункта."
msgid ""
"The Admin Toolbar Links Access Filter module provides a workaround for "
"the common problem that users with <em>Use the administration pages "
"and help</em> permission see menu links they done not have access "
"permission for."
msgstr ""
"Модуль Admin Toolbar Links Access Filter "
"обеспечивает решение "
"распространённой проблемы, когда "
"пользователи с правом <em>Использовать "
"страницы администрирования и "
"справку</em> видят ссылки в меню, на "
"доступ к которым у них нет прав."
msgid ""
"To use Admin Toolbar Extra Tools just install it like any other "
"module. There is no other configuration required."
msgstr ""
"Для того чтобы использовать "
"дополнительные инструменты панели "
"администратора просто установите "
"модуль, как и любой другой. Никак "
"других конфигураций не требуется."
msgid "Flush twig cache"
msgstr "Очистить кэш twig"
msgid "Twig cache cleared."
msgstr "Кэш twig очищен."
msgid "Provides an improved drop-down menu interface to the site Toolbar."
msgstr ""
"Предоставляет улучшенное "
"раскрывающееся меню панели "
"администратора."
msgid "Admin Toolbar Search"
msgstr "Поиск в панели администратора"
msgid ""
"The Admin Toolbar Extra Tools module comes packaged with the <a "
"href=\":admin-toolbar\">Admin Toolbar</a> module and adds "
"functionality to it. The additional functionality is accessed through "
"extra links on the main administration Toolbar. Some links to Admin "
"Toolbar Extra Tools administration pages are located at the bottom of "
"this page.</a>"
msgstr ""
"Модуль Admin Toolbar Extra Tools поставляется в "
"комплекте с модулем <a href=\":admin-toolbar\">Admin "
"Toolbar</a> и расширяет его "
"функциональность. Доступ к "
"дополнительному функционалу "
"осуществляется по дополнительным "
"ссылкам на главной панели "
"администрирования. Некоторые из этих "
"ссылок можно увидеть внизу этой "
"страницы.</a>"
msgid "All menus"
msgstr "Все меню"
msgid "Use Admin Toolbar search"
msgstr ""
"Использовать поиск на панели "
"администратора"
msgid "Theme Rebuild"
msgstr "Пересобрать тему"
msgid "Provides search of Admin Toolbar items."
msgstr ""
"Предоставляет поиск элементов в "
"панели администратора."
msgid ""
"Adds menu links like Flush cache, Run cron, Run updates, and Logout "
"under Drupal icon."
msgstr ""
"Добавляет в пункт меню со значком Drupal "
"такие ссылки как Очистить кэш, "
"Запустить крон, Запустить обновления "
"и Выйти."
msgid "Flush CSS and JavaScript"
msgstr "Очистить CSS и JavaScript"
msgid "Configure the Admin Toolbar Tools module."
msgstr "Настроить модуль Admin Toolbar Tools."
msgid "Number of bundles per entity type to display"
msgstr ""
"Количество отображаемых подтипов "
"сущности для каждого типа."
msgid "Maximum number of bundle sub-menus to display"
msgstr ""
"Максимальное количество подтипов, "
"которое нужно показывать во вложенных "
"меню."
msgid "Menus > @menu_label"
msgstr "Меню > @menu_label"
msgid "Configure the Admin Toolbar module."
msgstr "Настроить модуль Admin Toolbar."
msgid "Admin Toolbar settings"
msgstr "Настройки Admin Toolbar"
msgid "Configure the Admin Toolbar Search module."
msgstr "Настроить модуль Admin Toolbar Search."
msgid "Admin Toolbar Search settings"
msgstr "Настройки Admin Toolbar Search"
msgid "Display the search input as a menu item."
msgstr "Отображать поле поиска как пункт меню."
msgid "Depth of displayed menu"
msgstr "Глубина отображаемого меню"
msgid "Menus > @menu_label > Add link"
msgstr "Меню > @menu_label > Добавить ссылку"
msgid "Menus > @menu_label > Delete"
msgstr "Меню > @menu_label > Удалить"
msgid "Menus > @menu_label > Devel"
msgstr "Меню > @menu_label > Разработка"
msgid "How the search input will be displayed"
msgstr "Как будут отображаться строка поиска"
msgid ""
"If set, instead of displaying a text input field, it displays a menu "
"item in the toolbar so the user has to click on it to toggle the "
"search input."
msgstr ""
"Если включено, то вместо текстового "
"поля будет отображаться пункт меню в "
"панели администратора, на который "
"пользователь может нажать, чтобы "
"увидеть строку поиска."
msgid "Show local tasks in toolbar"
msgstr ""
"Показывать локальные задачи на панели "
"инструментов"
msgid "Enable/Disable local tasks display"
msgstr ""
"Включить / Отключить отображение "
"локальных задач"
msgid "Local tasks such as node edit and delete."
msgstr ""
"Локальные задачи, например, "
"редактирование и удаление материала."
msgid "Add content block"
msgstr "Добавить контент-блок"
msgid ""
"Provides a workaround for the common problem that users with 'Use the "
"administration pages and help' permission see menu links they don't "
"have access permission for. Deprecated from Drupal 10.3 and above."
msgstr ""
"Обеспечивает решение "
"распространенной проблемы, при "
"которой пользователи с правом "
"\"Использовать страницы "
"администрирования и справку\" видят "
"ссылки меню, на доступ к которым у них "
"нет разрешения. Устарело с Drupal 10.3 и "
"выше."
msgid "Admin Toolbar Search (Alt+a)"
msgstr "Искать в админке (Alt+a)"
# Russian translation of Better Exposed Filters (7.0.5)
# Copyright (c) 2025 by the Russian translation team
#
msgid ""
msgstr ""
"Project-Id-Version: Better Exposed Filters (7.0.5)\n"
"POT-Creation-Date: 2025-01-31 20:46+0000\n"
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=((((n%10)==1)&&((n%100)!=11))?(0):(((((n%10)>=2)&&((n%10)<=4))&&(((n%100)<10)||((n%100)>=20)))?(1):2));\n"
msgid "Advanced options"
msgstr "Дополнительные настройки"
msgid "Links"
msgstr "Ссылки"
msgid "None"
msgstr "Нет"
msgid "Number"
msgstr "Число"
msgid "Default"
msgstr "По умолчанию"
msgid "Views"
msgstr "Представление"
msgid "Horizontal"
msgstr "Горизонтально"
msgid "Vertical"
msgstr "Вертикально"
msgid "Custom"
msgstr "Собственная"
msgid "Maximum"
msgstr "Максимум"
msgid "Select None"
msgstr "Снять выбор"
msgid "Filters"
msgstr "Фильтры"
msgid "Hidden"
msgstr "Скрытый"
msgid "Orientation"
msgstr "Ориентация"
msgid "Animation speed"
msgstr "Скорость анимации"
msgid "Max"
msgstr "Макс"
msgid "Minimum"
msgstr "Минимум"
msgid "About"
msgstr "Информация"
msgid "Radio Buttons"
msgstr "Радиокнопки"
msgid "Step"
msgstr "Шаг"
msgid "Select All"
msgstr "Выбрать все"
msgid "Hide submit button"
msgstr "Скрыть кнопку отправки"
msgid "Uses"
msgstr "Использование"
msgid "Sort options"
msgstr "Настройка сортировки"
msgid "Min"
msgstr "Мин"
msgid "Checkboxes/Radio Buttons"
msgstr "Флажки/Радио-кнопки"
msgid "Better Exposed Filters"
msgstr "Better Exposed Filters"
msgid "Input required"
msgstr "Требуется ввод"
msgid "Add select all/none links"
msgstr ""
"Добавить ссылку Выбрать все/Снять "
"выбор"
msgid "Animation speed in milliseconds"
msgstr "Скорость анимации в миллисекундах"
msgid "Combine sort order with sort by"
msgstr ""
"Объединить поля \"сортировать по\" с "
"\"порядок сортировки\""
msgid "Advanced sort options"
msgstr "Расширенные настройки сортировки"
msgid "Placeholder text"
msgstr "Текст заполнителя"
msgid "Global replacement patterns (for description field only)"
msgstr ""
"Глобальные шаблоны замены (только для "
"поля описания)"
msgid "Exposed Sort Settings"
msgstr "Настройки раскрытой сортировки"
# Russian translation of Blazy (3.0.13)
# Copyright (c) 2025 by the Russian translation team
#
msgid ""
msgstr ""
"Project-Id-Version: Blazy (3.0.13)\n"
"POT-Creation-Date: 2025-05-29 17:26+0000\n"
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=((((n%10)==1)&&((n%100)!=11))?(0):(((((n%10)>=2)&&((n%10)<=4))&&(((n%100)<10)||((n%100)>=20)))?(1):2));\n"
msgid "Title"
msgstr "Заголовок"
msgid "Delete"
msgstr "Удалить"
msgid "Description"
msgstr "Описание"
msgid "Yes"
msgstr "Да"
msgid "No"
msgstr "Нет"
msgid "Tag"
msgstr "Тег"
msgid "- None -"
msgstr "- Не указано -"
msgid "Link"
msgstr "Ссылка"
msgid "Image"
msgstr "Изображение"
msgid "Settings"
msgstr "Настройки"
msgid "Preview"
msgstr "Предпросмотр"
msgid "Background"
msgstr "Фон"
msgid "tag"
msgstr "тег"
msgid "Layout"
msgstr "Макет"
msgid "Configure"
msgstr "Настроить"
msgid "Custom"
msgstr "Собственная"
msgid "Global settings"
msgstr "Глобальные настройки"
msgid "Fields"
msgstr "Поля"
msgid "Thumbnail"
msgstr "Миниатюра"
msgid "Media"
msgstr "Мультимедиа"
msgid "Colors"
msgstr "Цвета"
msgid "Attributes"
msgstr "Атрибуты"
msgid "Cache"
msgstr "Кэш"
msgid "Tokens"
msgstr "Токены"
msgid "Delimiter"
msgstr "Разделитель"
msgid "Extras"
msgstr "Дополнительные"
msgid "Caption"
msgstr "Подпись"
msgid "Content title"
msgstr "Заголовок"
msgid "Duplicate"
msgstr "Дубликат"
msgid "Display style"
msgstr "Стиль отображения"
msgid "Automatic"
msgstr "Автоматически"
msgid "No caching"
msgstr "Без кэша"
msgid "Classes"
msgstr "Классы"
msgid "Layouts"
msgstr "Макеты"
msgid "Title text"
msgstr "Текст в Title"
msgid "Skin"
msgstr "Обложка"
msgid "Offset"
msgstr "Пропустить"
msgid "No name"
msgstr "Без имени"
msgid "@title"
msgstr "@title"
msgid "Extra settings"
msgstr "Дополнительные настройки"
msgid "Region name"
msgstr "Название области"
msgid "Permanent"
msgstr "Постоянный"
msgid "Thumbnail image"
msgstr "Миниатюра изображения"
msgid "Alt text"
msgstr "Alt текст"
msgid "Placeholder"
msgstr "Заполнитель"
msgid "Aspect ratio"
msgstr "Соотношение сторон"
msgid "Styles"
msgstr "Стили"
msgid "SVG"
msgstr "SVG"
msgid "Image linked to content"
msgstr "Изображение со ссылкой на содержимое"
msgid "Image style"
msgstr "Стиль изображения"
msgid "Alt"
msgstr "Alt"
msgid "Wrapper"
msgstr "Обёртка"
msgid "Preload"
msgstr "Предварительная нагрузка"
msgid "View mode"
msgstr "Режим просмотра"
msgid "Use field template"
msgstr "Использовать шаблон поля"
msgid "Responsive image"
msgstr "Адаптивное изображение"
msgid "Image convert failed using the %toolkit toolkit on %path (%mimetype)"
msgstr ""
"Ошибка преобразования изображения с "
"помощью средства %toolkit в %path (%mimetype)"
msgid ""
"Recursive rendering detected when rendering entity @entity_type "
"@entity_id. Aborting rendering."
msgstr ""
"Во время генерирования сущности "
"@entity_type @entity_id обнаружена рекурсия. "
"Генерирование прервано."
msgid "Item class"
msgstr "Класс пункта"
msgid "Row classes"
msgstr "Класс строки"
# Russian translation of Bootstrap (8.x-3.38)
# Copyright (c) 2025 by the Russian translation team
#
msgid ""
msgstr ""
"Project-Id-Version: Bootstrap (8.x-3.38)\n"
"POT-Creation-Date: 2025-08-04 03:38+0000\n"
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=((((n%10)==1)&&((n%100)!=11))?(0):(((((n%10)>=2)&&((n%10)<=4))&&(((n%100)<10)||((n%100)>=20)))?(1):2));\n"
msgid "Forms"
msgstr "Формы"
msgid "Home"
msgstr "Главная"
msgid "Images"
msgstr "Изображения"
msgid "Previous"
msgstr "Назад"
msgid "Next"
msgstr "Вперёд"
msgid "Save configuration"
msgstr "Сохранить конфигурацию"
msgid "title"
msgstr "заголовок"
msgid "Delete"
msgstr "Удалить"
msgid "Submit"
msgstr "Отправить"
msgid "Content"
msgstr "Содержимое"
msgid "content"
msgstr "содержимое"
msgid "Confirm"
msgstr "Подтвердить"
msgid "Cancel"
msgstr "Отмена"
msgid "Remove"
msgstr "Удалить"
msgid "Description"
msgstr "Описание"
msgid "Disable"
msgstr "Отключить"
msgid "Disabled"
msgstr "Отключено"
msgid "Enabled"
msgstr "Включено"
msgid "ERROR"
msgstr "ОШИБКА"
msgid "Download"
msgstr "Скачать"
msgid "Version"
msgstr "Версия"
msgid "Edit"
msgstr "Редактировать"
msgid "Search"
msgstr "Поиск"
msgid "Reset"
msgstr "Сбросить"
msgid "None"
msgstr "Нет"
msgid "Container"
msgstr "Контейнер"
msgid "Settings"
msgstr "Настройки"
msgid "Go to previous page"
msgstr "На предыдущую страницу"
msgid "Go to next page"
msgstr "На следующую страницу"
msgid "Import"
msgstr "Импортировать"
msgid "Export"
msgstr "Экспортировать"
msgid "container"
msgstr "контейнер"
msgid "Preview"
msgstr "Предпросмотр"
msgid "Save"
msgstr "Сохранить"
msgid "Help"
msgstr "Справка"
msgid "Default"
msgstr "По умолчанию"
msgid "Update"
msgstr "Обновить"
msgid "Small"
msgstr "Маленький"
msgid "Large"
msgstr "Большой"
msgid "Add"
msgstr "Добавить"
msgid "Manage"
msgstr "Управление"
msgid "Visible"
msgstr "Видимый"
msgid "Theme"
msgstr "Тема"
msgid "Components"
msgstr "Компоненты"
msgid "Upload"
msgstr "Закачать"
msgid "Configure"
msgstr "Настроить"
msgid "file"
msgstr "файл"
msgid "Options"
msgstr "Опции"
msgid "Create"
msgstr "Создать"
msgid "Last post"
msgstr "Последняя публикация"
msgid "Page title"
msgstr "Заголовок страницы"
msgid "Page"
msgstr "Страница"
msgid "Never"
msgstr "Никогда"
msgid "Footer"
msgstr "Подвал"
msgid "Custom"
msgstr "Собственная"
msgid "Filter"
msgstr "Фильтр"
msgid "Normal"
msgstr "Нормальный"
msgid "Advanced"
msgstr "Расширенные"
msgid "Thumbnail"
msgstr "Миниатюра"
msgid "next"
msgstr "вперёд"
msgid "General"
msgstr "Общий"
msgid "Forum"
msgstr "Форум"
msgid "Navigation"
msgstr "Навигация"
msgid "Log in"
msgstr "Войти"
msgid "JavaScript"
msgstr "JavaScript"
msgid "Provider"
msgstr "Поставщик"
msgid "Uninstall"
msgstr "Удалить"
msgid "Install"
msgstr "Установить"
msgid "Tools"
msgstr "Инструменты"
msgid "HTML"
msgstr "HTML"
msgid "bottom"
msgstr "снизу"
msgid "top"
msgstr "сверху"
msgid "left"
msgstr "слева"
msgid "right"
msgstr "справа"
msgid "Static"
msgstr "Статическая"
msgid "Close"
msgstr "Закрыть"
msgid "show"
msgstr "показать"
msgid "Hidden"
msgstr "Скрытый"
msgid "Topics"
msgstr "Темы"
msgid "first"
msgstr "первое"
msgid "Posts"
msgstr "Сообщения"
msgid "Buttons"
msgstr "Кнопки"
msgid "White"
msgstr "Белый"
msgid "Included"
msgstr "Включено"
msgid "archive"
msgstr "архив"
msgid "Schema"
msgstr "Схема"
msgid "previous"
msgstr "предыдущий"
msgid "last"
msgstr "последний"
msgid "image"
msgstr "изображение"
msgid "Loading..."
msgstr "Загрузка..."
msgid "Automatic"
msgstr "Автоматически"
msgid "Tabs"
msgstr "Вкладки"
msgid "Next page"
msgstr "Следующая страница"
msgid "Apply"
msgstr "Применить"
msgid "Go to first page"
msgstr "На первую страницу"
msgid "Go to last page"
msgstr "На последнюю страницу"
msgid "Enter the terms you wish to search for."
msgstr "Введите ключевые слова для поиска."
msgid "Add another item"
msgstr "Добавить ещё"
msgid "video"
msgstr "видео"
msgid "Restore"
msgstr "Восстановить"
msgid "Rebuild"
msgstr "Перестроить"
msgid "Skip to main content"
msgstr "Перейти к основному содержанию"
msgid "Breadcrumb visibility"
msgstr "Видимость хлебных крошек"
msgid "Error message"
msgstr "Сообщение об ошибке"
msgid "Main navigation"
msgstr "Основная навигация"
msgid "Warning message"
msgstr "Предупреждение"
msgid "Tables"
msgstr "Таблицы"
msgid "Primary tabs"
msgstr "Главные вкладки"
msgid "Secondary tabs"
msgstr "Дополнительные вкладки"
msgid "Primary"
msgstr "Первичный"
msgid "click"
msgstr "Переход"
msgid "Secondary"
msgstr "Вторичный"
msgid "Broken"
msgstr "Прервано"
msgid "‹‹"
msgstr "‹‹"
msgid "››"
msgstr "››"
msgid "Circle"
msgstr "Круг"
msgid "Download feature"
msgstr "Загрузить особенность"
msgid "Drag to re-order"
msgstr ""
"Для изменения порядка перетащите "
"мышкой"
msgid "Pagination"
msgstr "Нумерация страниц"
msgid "Powered by Drupal"
msgstr "Сделано на Drupal"
msgid "Sort descending"
msgstr "Сортировать по убыванию"
msgid "Sort ascending"
msgstr "Сортировать по возрастанию"
msgid "Breadcrumbs"
msgstr "Строка навигации"
msgid "Page top"
msgstr "Верх страницы"
msgid "Page bottom"
msgstr "Низ страницы"
msgid "Status messages"
msgstr "Системные сообщения"
msgid "Main page content"
msgstr "Содержимое страницы"
msgid "(active tab)"
msgstr "(активная вкладка)"
msgid "Status message"
msgstr "Статус"
msgid "Hide summary"
msgstr "Скрыть краткое содержание"
msgid "Edit summary"
msgstr "Редактировать краткое содержание"
msgid "Update style"
msgstr "Обновить стиль"
msgid "Add effect"
msgstr "Добавить эффект"
msgid "Bootstrap"
msgstr "Bootstrap"
msgid "Current page"
msgstr "Текущая страница"
msgid "Highlighted"
msgstr "Подсвеченные"
msgid "Previous page"
msgstr "Предыдущая страница"
msgid "Re-order rows by numerical weight instead of dragging."
msgstr ""
"Упорядочить строки по весу вместо "
"перетаскивания."
msgid "Forever"
msgstr "Навсегда"
msgid "Footer menu"
msgstr "Меню в подвале"
msgid "Add and configure"
msgstr "Добавить и настроить"
msgid "Last page"
msgstr "Последняя страница"
msgid "You have unsaved changes."
msgstr "Есть несохранённые изменения."
msgid "Unlimited number of files can be uploaded to this field."
msgstr ""
"Это поле позволяет загрузить "
"неограниченное количество файлов."
msgid "Responsive Tables"
msgstr "Отзывчивые таблицы"
msgid "Bootstrap settings"
msgstr "Настройки библиотеки Bootstrap"
msgid "Bootstrap Settings"
msgstr "Настройки библиотеки Bootstrap"
msgid "One file only."
msgid_plural "Maximum @count files."
msgstr[0] "Только один файл."
msgstr[1] "Максимум @count файла."
msgstr[2] "Максимум @count[2] файлов."
msgid "Site branding"
msgstr "Брендинг сайта"
msgid "Responsive tables"
msgstr "Отзывчивые таблицы"
msgid "First page"
msgstr "Первая страница"
msgid "Allowed types: @extensions."
msgstr "Допустимые типы: @extensions."
msgid "Install and set as default"
msgstr "Включить и установить по умолчанию"
msgid "Images must be exactly <strong>@size</strong> pixels."
msgstr ""
"Изображения должны быть ровно "
"<strong>@size</strong> пикселей."
msgid ""
"Images must be larger than <strong>@min</strong> pixels. Images larger "
"than <strong>@max</strong> pixels will be resized."
msgstr ""
"Изображения должны быть больше "
"<strong>@min</strong> пикселей. Изображения "
"превышающие <strong>@max</strong> пикселей "
"будут уменьшены."
msgid "Images must be larger than <strong>@min</strong> pixels."
msgstr ""
"Изображения должны быть более "
"<strong>@min</strong> пикселей."
msgid "Images larger than <strong>@max</strong> pixels will be resized."
msgstr ""
"Изображения более <strong>@max</strong> "
"пикселей будут отмаcштабированы."
msgid "Submitted by @author_name on @date"
msgstr "Опубликовано @author_name - @date"
msgid "Primary admin actions"
msgstr "Основные действия администратора"
msgid "User account menu"
msgstr "Меню учётной записи пользователя"
msgid "@size limit."
msgstr "Ограничение @size."
msgid "Show or hide the Breadcrumbs"
msgstr "Скрыть или показать Строку навигации"
msgid "Go to page @key"
msgstr "Перейти на страницу @key"
# Russian translation of CKEditor 5 Plugin Pack (1.4.0)
# Copyright (c) 2025 by the Russian translation team
#
msgid ""
msgstr ""
"Project-Id-Version: CKEditor 5 Plugin Pack (1.4.0)\n"
"POT-Creation-Date: 2025-07-02 16:34+0000\n"
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=((((n%10)==1)&&((n%100)!=11))?(0):(((((n%10)>=2)&&((n%10)<=4))&&(((n%100)<10)||((n%100)>=20)))?(1):2));\n"
msgid "Status"
msgstr "Статус"
msgid "Groups"
msgstr "Группы"
msgid "Group"
msgstr "Группа"
msgid "Type"
msgstr "Тип"
msgid "Remove"
msgstr "Удалить"
msgid "Description"
msgstr "Описание"
msgid "Disabled"
msgstr "Отключено"
msgid "Enabled"
msgstr "Включено"
msgid "None"
msgstr "Нет"
msgid "Weight"
msgstr "Вес"
msgid "Center"
msgstr "Центр"
msgid "Label"
msgstr "Метка"
msgid "Font Size"
msgstr "Размер шрифта"
msgid "Default"
msgstr "По умолчанию"
msgid "Background Color"
msgstr "Цвет фона"
msgid "Top"
msgstr "Вверху"
msgid "Advanced settings"
msgstr "Расширенные настройки"
msgid "ID"
msgstr "ID"
msgid "Options"
msgstr "Опции"
msgid "Bottom"
msgstr "Снизу"
msgid "Medium"
msgstr "Средний"
msgid "Colors"
msgstr "Цвета"
msgid "Color"
msgstr "Цвет"
msgid "Attributes"
msgstr "Атрибуты"
msgid "right"
msgstr "справа"
msgid "Add group"
msgstr "Добавить группу"
msgid "Default height"
msgstr "Высота по умолчанию"
msgid "Default width"
msgstr "Ширина по умолчанию"
msgid "Middle"
msgstr "По центру"
msgid "Marker"
msgstr "Маркер"
msgid "Left"
msgstr "Слева"
msgid "Right"
msgstr "Справа"
msgid "Font Family"
msgstr "Семейство шрифтов"
msgid "Formats"
msgstr "Форматы"
msgid "Double"
msgstr "Удвоить"
msgid "Dotted"
msgstr "Пунктир"
msgid "Dashed"
msgstr "Штрих"
msgid "Solid"
msgstr "Сплошной"
msgid "Groove"
msgstr "Выступ"
msgid "Inset"
msgstr "Внутрь"
msgid "RGB"
msgstr "RGB"
msgid "Machine name"
msgstr "Машинное имя"
msgid "Light"
msgstr "Светлая"
msgid "Icon preview"
msgstr "Пред просмотр иконки"
msgid "Default alignment"
msgstr "Выравнивание по умолчанию"
msgid "Justify"
msgstr "По ширине"
msgid "Font Color"
msgstr "Цвет шрифта"
msgid "Dropdown"
msgstr "Выпадающий"
msgid "HTML Code"
msgstr "HTML Code"
msgid "Dialog"
msgstr "Диалог"
msgid "Dark"
msgstr "Темный"
msgid "Custom classes"
msgstr "Пользовательские классы"
msgid "Link attributes"
msgstr "Атрибуты ссылки"
# Russian translation of Color backport (2.0.0-alpha1)
# Copyright (c) 2025 by the Russian translation team
#
msgid ""
msgstr ""
"Project-Id-Version: Color backport (2.0.0-alpha1)\n"
"POT-Creation-Date: 2025-07-02 05:46+0000\n"
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=((((n%10)==1)&&((n%100)!=11))?(0):(((((n%10)>=2)&&((n%10)<=4))&&(((n%100)<10)||((n%100)>=20)))?(1):2));\n"
msgid "Preview"
msgstr "Предпросмотр"
msgid "Core"
msgstr "Ядро"
msgid "Custom"
msgstr "Собственная"
msgid "Color"
msgstr "Цвет"
msgid "Appearance"
msgstr "Оформление"
msgid "Goal"
msgstr "Цель"
msgid "Not installed"
msgstr "Не установлено"
msgid "Color scheme"
msgstr "Цветовая схема"
msgid "Color set"
msgstr "Установки цвета"
msgid "About"
msgstr "Информация"
msgid "Steps"
msgstr "Шаги"
msgid "Uses"
msgstr "Использование"
msgid "Lock"
msgstr "Заблокировать"
msgid "Changing colors"
msgstr "Изменение цветов"
msgid "Unlock"
msgstr "Разблокировать"
msgid "GD library PNG support"
msgstr "Библиотека GD — поддержка PNG"
msgid "Logo path"
msgstr "Путь к логотипу"
msgid "You must enter a valid hexadecimal color value for %name."
msgstr ""
"Необходимо ввести действительное "
"шестнадцатеричное значение цвета для "
"%name."
msgid "Additional resources"
msgstr "Дополнительные ресурсы"
msgid "Color theme settings"
msgstr "Настройки цвета темы"
msgid "Palette settings"
msgstr "Настройки палитры"
msgid ""
"The Color module saves a modified copy of the theme's specified "
"stylesheets in the files directory. If you make any manual changes to "
"your theme's stylesheet, <em>you must save your color settings again, "
"even if you haven't changed the colors</em>. This step is required "
"because the module stylesheets in the files directory need to be "
"recreated to reflect your changes."
msgstr ""
"Модуль Color сохраняет измененную копию "
"указанных таблиц стилей темы в "
"каталоге файлов. Если вы вносите "
"какие-либо ручные изменения в таблицу "
"стилей своей темы, <em> вы должны снова "
"сохранить настройки цвета, даже если "
"вы не меняли цвета </em>. Этот шаг "
"необходим, потому что таблицы стилей "
"модуля в каталоге файлов должны быть "
"воссозданы, чтобы отразить ваши "
"изменения."
msgid ""
"The Color module allows users with the <em>Administer site "
"configuration</em> permission to change the color scheme (color of "
"links, backgrounds, text, and other theme elements) of compatible "
"themes. For more information, see the <a href=\":color_do\">online "
"documentation for the Color module</a>."
msgstr ""
"Модуль Color позволяет пользователям с "
"правами <em>Управление настройками "
"сайта</em> изменять цветовую схему "
"(цвет ссылок, фона, текста, и других "
"элементов) совместимых тем. "
"Дополнительную информацию смотрите <a "
"href=\":color_do\">онлайн документацию модуля "
"Color</a>."
msgid ""
"To change the color settings, select the <em>Settings</em> link for "
"your theme on the <a href=\":appearance\">Appearance</a> page. If the "
"color picker does not appear then the theme is not compatible with the "
"Color module."
msgstr ""
"Чтобы изменить настройки цвета, "
"выберите <em>Настройки</em> для своей "
"темы на странице <a href=\":appearance\">Внешний "
"вид</a>. Если палитра цветов не "
"отображается, тема не совместима с "
"модулем Color."
msgid ""
"There is not enough memory available to PHP to change this theme's "
"color scheme. You need at least %size more. Check the <a "
"href=\"http://php.net/manual/ini.core.php#ini.sect.resource-limits\">PHP "
"documentation</a> for more information."
msgstr ""
"PHP недостаточно памяти для изменения "
"цветовой схемы в теме оформления. "
"Необходимо как минимум ещё %size. За "
"дополнительной информацией "
"обратитесь к <a "
"href=\"http://php.net/manual/ini.core.php#ini.sect.resource-limits\">документации "
"PHP</a>."
msgid ""
"The GD library for PHP is enabled, but was compiled without PNG "
"support. Check the <a href=\"http://php.net/manual/ref.image.php\">PHP "
"image documentation</a> for information on how to correct this."
msgstr ""
"Библиотека GD для PHP работает, но "
"скомпилирована без поддержки PNG. "
"Обратитесь к <a "
"href=\"http://php.net/manual/ref.image.php\">документации "
"PHP по работе с изображениями</a>, чтобы "
"получить информацию об устранении "
"этой ошибки."
msgid ""
"The GD library for PHP is missing or outdated. Check the <a "
"href=\"http://php.net/manual/book.image.php\">PHP image "
"documentation</a> for information on how to correct this."
msgstr ""
"Библиотека GD для PHP отсутствует или "
"устарела. Обратитесь к <a "
"href=\"http://php.net/manual/book.image.php\">документации "
"PHP по работе с изображениями</a>, чтобы "
"получить информацию об устранении "
"этой ошибки."
msgid "A color variable for a theme."
msgstr "Переменная цвета для темы оформления."
msgid "The value of a color variable."
msgstr "Значение переменной цвета."
msgid "Allows users to change the color scheme of compatible themes."
msgstr ""
"Позволяет пользователям изменять "
"цветовую схему совместимых тем."
msgid ""
"Change the colors for links, backgrounds, and text in a theme that "
"supports the Color module. Color-specific stylesheets will be "
"generated and saved; you will need to follow these steps again to "
"regenerate the stylesheets if you make any changes to the base "
"stylesheets of your theme."
msgstr ""
"Измените цвета для ссылок, фона и "
"текста в теме, поддерживающей модуль "
"«Цвет». Таблицы стилей для конкретных "
"цветов будут созданы и сохранены; вам "
"нужно будет повторить эти шаги еще "
"раз, чтобы восстановить таблицы "
"стилей, если вы внесете какие-либо "
"изменения в базовые таблицы стилей "
"своей темы."
msgid ""
"Click the <em>Settings</em> link for the theme you want to change the "
"colors of."
msgstr ""
"Перейдите по ссылке<em>Настройки</em> для "
"темы, у которой вы хотите изменить "
"цвета."
msgid ""
"In the <em>Color scheme</em> section, choose new colors for the "
"backgrounds, text, and links that your theme defines colors for. "
"However, if you do not see color settings, then your theme does not "
"support the Color module."
msgstr ""
"В разделе <em>Цветовая схема</em> укажите "
"цвета для фонов, текста и ссылок, "
"которые будут использованы вашей "
"темой. Если вы не видите настроек "
"цвета, ваша тема не поддерживает "
"модуль Color."
msgid ""
"Click <em>Save configuration</em>. Color-specific stylesheets will be "
"generated and saved in the file system."
msgstr ""
"Нажмите <em>Сохранить настройки</em>. "
"Стили, использующие новые цвета, будут "
"сохранены в файловой системе."
msgid "Color module overview"
msgstr "Обзор модуля Color."
msgid "Changing the color palette of a theme"
msgstr "Изменение палитры цветов темы"
# Russian translation of Config Pages (8.x-2.18)
# Copyright (c) 2025 by the Russian translation team
#
msgid ""
msgstr ""
"Project-Id-Version: Config Pages (8.x-2.18)\n"
"POT-Creation-Date: 2025-07-30 16:42+0000\n"
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=((((n%10)==1)&&((n%100)!=11))?(0):(((((n%10)>=2)&&((n%10)<=4))&&(((n%100)<10)||((n%100)>=20)))?(1):2));\n"
msgid "Delete"
msgstr "Удалить"
msgid "Value"
msgstr "Значение"
msgid "Type"
msgstr "Тип"
msgid "Cancel"
msgstr "Отмена"
msgid "Description"
msgstr "Описание"
msgid "Language"
msgstr "Язык"
msgid "Edit"
msgstr "Редактировать"
msgid "None"
msgstr "Нет"
msgid "Weight"
msgstr "Вес"
msgid "Name"
msgstr "Название"
msgid "Import"
msgstr "Импортировать"
msgid "Label"
msgstr "Метка"
msgid "Save"
msgstr "Сохранить"
msgid "Path"
msgstr "Путь"
msgid "Menu"
msgstr "Меню"
msgid "ID"
msgstr "ID"
msgid "Is less than"
msgstr "Меньше, чем"
msgid "Is less than or equal to"
msgstr "Меньше либо равно"
msgid "Is equal to"
msgstr "Равно"
msgid "Is greater than or equal to"
msgstr "Больше или равно"
msgid "Is greater than"
msgstr "Больше, чем"
msgid "Is not equal to"
msgstr "Не равно"
msgid "Operator"
msgstr "Оператор"
msgid "Full"
msgstr "Полный"
msgid "Token"
msgstr "Токен"
msgid "Entity"
msgstr "Сущность"
msgid "Changed"
msgstr "Изменение"
msgid "Context"
msgstr "Контекст"
msgid "UUID"
msgstr "UUID"
msgid "@type: added %info."
msgstr "@type: добавлен %info."
msgid "@type: updated %info."
msgstr "@type: обновлён %info."
# Russian translation of Configuration Split (2.0.2)
# Copyright (c) 2025 by the Russian translation team
#
msgid ""
msgstr ""
"Project-Id-Version: Configuration Split (2.0.2)\n"
"POT-Creation-Date: 2025-02-12 17:48+0000\n"
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=((((n%10)==1)&&((n%100)!=11))?(0):(((((n%10)>=2)&&((n%10)<=4))&&(((n%100)<10)||((n%100)>=20)))?(1):2));\n"
msgid "Delete"
msgstr "Удалить"
msgid "Operations"
msgstr "Операции"
msgid "List"
msgstr "Список"
msgid "Edit"
msgstr "Редактировать"
msgid "Name"
msgstr "Название"
msgid "Import"
msgstr "Импортировать"
msgid "Export"
msgstr "Экспортировать"
msgid "View"
msgstr "Просмотр"
msgid "Active"
msgstr "Активно"
msgid "New"
msgstr "Новое"
msgid "Activate"
msgstr "Активировать"
msgid "Deactivate"
msgstr "Деактивировать"
msgid "Import all"
msgstr "Импортировать всё"
msgid "Another request may be synchronizing configuration already."
msgstr ""
"Другой запрос возможно уже "
"синхронизирует конфигурацию."
msgid "@count new"
msgid_plural "@count new"
msgstr[0] "@count новый"
msgstr[1] "@count новых"
msgstr[2] "@count[2] новых"
msgid "@count changed"
msgid_plural "@count changed"
msgstr[0] "@count изменён"
msgstr[1] "@count изменено"
msgstr[2] "@count[2] изменено"
msgid "@count removed"
msgid_plural "@count removed"
msgstr[0] "@count удалён"
msgstr[1] "@count удалено"
msgstr[2] "@count[2] удалено"
msgid "View differences"
msgstr "Просмотр различий"
msgid "View changes of @config_file"
msgstr "Просмотр изменений @config_file"
msgid ""
"The staged configuration cannot be imported, because it originates "
"from a different site than this site. You can only synchronize "
"configuration between cloned instances of this site."
msgstr ""
"Переносимая конфигурация не может "
"быть импортирована, потому что берет "
"начало с отличного от текущего сайта. "
"Вы можете только синхронизировать "
"конфигурации между копиями этого "
"сайта."
msgid "Synchronizing configuration"
msgstr "Синхронизация конфигурации"
msgid "Starting configuration synchronization."
msgstr "Запуск синхронизации конфигурации."
msgid "Configuration synchronization has encountered an error."
msgstr ""
"При синхронизации конфигурации "
"возникла ошибка."
msgid "@count renamed"
msgid_plural "@count renamed"
msgstr[0] "@count переименован"
msgstr[1] "@count переименовано"
msgstr[2] "@count[2] переименовано"
msgid ""
"The configuration cannot be imported because it failed validation for "
"the following reasons:"
msgstr ""
"Конфигурация не может быть "
"импортирована, поскольку не прошла "
"проверку по следующим причинам:"
msgid "Staged"
msgstr "Подготовленная"
msgid "@collection configuration collection"
msgstr "Конфигурационная коллекция @collection"
msgid "@source_name to @target_name"
msgstr "@source_name в @target_name"
msgid "Completed step @current of @total."
msgstr "Завершён этап @current из @total."
# Russian translation of CSV Serialization (4.0.1)
# Copyright (c) 2024 by the Russian translation team
#
msgid ""
msgstr ""
"Project-Id-Version: CSV Serialization (4.0.1)\n"
"POT-Creation-Date: 2024-08-12 14:46+0000\n"
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=((((n%10)==1)&&((n%100)!=11))?(0):(((((n%10)>=2)&&((n%10)<=4))&&(((n%100)<10)||((n%100)>=20)))?(1):2));\n"
msgid "Web services"
msgstr "Веб-службы"
# Russian translation of Chaos Tool Suite (ctools) (4.1.0)
# Copyright (c) 2024 by the Russian translation team
#
msgid ""
msgstr ""
"Project-Id-Version: Chaos Tool Suite (ctools) (4.1.0)\n"
"POT-Creation-Date: 2024-12-11 08:02+0000\n"
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=((((n%10)==1)&&((n%100)!=11))?(0):(((((n%10)>=2)&&((n%10)<=4))&&(((n%100)<10)||((n%100)>=20)))?(1):2));\n"
msgid "Previous"
msgstr "Назад"
msgid "Next"
msgstr "Вперёд"
msgid "Delete"
msgstr "Удалить"
msgid "Operations"
msgstr "Операции"
msgid "Cancel"
msgstr "Отмена"
msgid "Description"
msgstr "Описание"
msgid "Edit"
msgstr "Редактировать"
msgid "None"
msgstr "Нет"
msgid "This action cannot be undone."
msgstr "Это действие нельзя отменить."
msgid "Weight"
msgstr "Вес"
msgid "Settings"
msgstr "Настройки"
msgid "Label"
msgstr "Метка"
msgid "Save"
msgstr "Сохранить"
msgid "Summary"
msgstr "Сводка"
msgid "Region"
msgstr "Область"
msgid "ID"
msgstr "ID"
msgid "Options"
msgstr "Опции"
msgid "Data type"
msgstr "Тип данных"
msgid "Inline"
msgstr "В линию"
msgid "Data Type"
msgstr "Тип данных"
msgid "Order"
msgstr "Порядок"
msgid "Hidden"
msgstr "Скрытый"
msgid "Revision"
msgstr "Редакция"
msgid "Relationship"
msgstr "Связь"
msgid "Information"
msgstr "Информация"
msgid "Blocks"
msgstr "Блоки"
msgid "Above"
msgstr "Сверху"
msgid "Hide"
msgstr "Скрыть"
msgid "Context"
msgstr "Контекст"
msgid "Pager"
msgstr "Постраничный навигатор"
msgid "Add required context"
msgstr "Добавить требуемый контекст"
msgid "Finish"
msgstr "Готово"
msgid "About"
msgstr "Информация"
msgid "Formatter"
msgstr "Форматер"
msgid "Context type"
msgstr "Тип контекста"
msgid "@description"
msgstr "@description"
msgid "Chaos tool suite"
msgstr "Набор инструментов Chaos"
msgid "@label"
msgstr "@label"
msgid "Items per page"
msgstr "Элементов на страницу"
msgid "Sort descending"
msgstr "Сортировать по убыванию"
msgid "Sort ascending"
msgstr "Сортировать по возрастанию"
msgid "Add a relationship"
msgstr "Добавление отношений"
msgid "Allow settings"
msgstr "Применить настройки"
msgid "Field formatter"
msgstr "Форматер поля"
msgid "Pager type"
msgstr "Тип постраничного навигатора"
msgid "Display all items"
msgstr "Отображать все элементы"
msgid "Display a specified number of items"
msgstr ""
"Отображать указанное количество "
"элементов"
msgid "Machine Name"
msgstr "Машинное имя"
msgid "UUID"
msgstr "UUID"
msgid "View mode"
msgstr "Режим просмотра"
msgid "Weight for @title"
msgstr "Вес @title"
msgid "Third party settings"
msgstr "Сторонние настройки"
msgid ""
"For example, set this to 3 and the first 3 items will not be "
"displayed."
msgstr ""
"Например, установите это значение "
"равное 3 и первые 3 элемента не будут "
"отображаться."
msgid "Context assignments"
msgstr "Присвоения контекста"
msgid "Format type machine name"
msgstr "Машинное имя типа форматирования"
msgid "Label setting machine name"
msgstr "Машинное имя для настройки метки"
msgid "Visually Hidden"
msgstr "Визуально скрыт"
msgid "Entity view (@label)"
msgstr "Сущность (@label)"
msgid "Plugin Id"
msgstr "Плагин"
# Russian translation of Devel (5.4.0)
# Copyright (c) 2025 by the Russian translation team
#
msgid ""
msgstr ""
"Project-Id-Version: Devel (5.4.0)\n"
"POT-Creation-Date: 2025-07-07 19:46+0000\n"
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=((((n%10)==1)&&((n%100)!=11))?(0):(((((n%10)>=2)&&((n%10)<=4))&&(((n%100)<10)||((n%100)>=20)))?(1):2));\n"
msgid "Delete"
msgstr "Удалить"
msgid "Operations"
msgstr "Операции"
msgid "Value"
msgstr "Значение"
msgid "Username"
msgstr "Имя пользователя"
msgid "content"
msgstr "содержимое"
msgid "Development"
msgstr "Разработка"
msgid "Closed"
msgstr "Закрыто"
msgid "Confirm"
msgstr "Подтвердить"
msgid "Cancel"
msgstr "Отмена"
msgid "Description"
msgstr "Описание"
msgid "Language"
msgstr "Язык"
msgid "Comments"
msgstr "Комментарии"
msgid "Priority"
msgstr "Приоритет"
msgid "Edit"
msgstr "Редактировать"
msgid "Search"
msgstr "Поиск"
msgid "None"
msgstr "Нет"
msgid "This action cannot be undone."
msgstr "Это действие нельзя отменить."
msgid "Category"
msgstr "Категория"
msgid "Settings"
msgstr "Настройки"
msgid "Name"
msgstr "Название"
msgid "Label"
msgstr "Метка"
msgid "Save"
msgstr "Сохранить"
msgid "Open"
msgstr "Открыть"
msgid "Icon"
msgstr "Иконка"
msgid "Path"
msgstr "Путь"
msgid "Vocabularies"
msgstr "Словари"
msgid "ID"
msgstr "ID"
msgid "Content type"
msgstr "Тип материала"
msgid "Configure"
msgstr "Настроить"
msgid "User ID"
msgstr "ID Пользователя"
msgid "vocabularies"
msgstr "словари"
msgid "Role ID"
msgstr "ID роли"
msgid "Filter"
msgstr "Фильтр"
msgid "Session ID"
msgstr "ID сессии"
msgid "Variable name"
msgstr "Имя переменной"
msgid "Fields"
msgstr "Поля"
msgid "Nodes"
msgstr "Материалы"
msgid "Load"
msgstr "Загрузить"
msgid "Events"
msgstr "Мероприятия"
msgid "Now"
msgstr "Сейчас"
msgid "Class"
msgstr "Класс"
msgid "External"
msgstr "Внешний"
msgid "Users"
msgstr "Пользователи"
msgid "Provider"
msgstr "Поставщик"
msgid "Clear cache"
msgstr "Очистить кэш"
msgid "Hidden"
msgstr "Скрытый"
msgid "Switch"
msgstr "Переключить"
msgid "ago"
msgstr "тому назад"
msgid "Front page"
msgstr "Главная страница"
msgid "Definition"
msgstr "Определение"
msgid "Parameters"
msgstr "Параметры"
msgid "Path alias"
msgstr "Синоним пути"
msgid "terms"
msgstr "термины"
msgid "Enter username"
msgstr "Введите имя пользователя"
msgid "Username not found"
msgstr "Имя пользователя не найдено"
msgid "users"
msgstr "пользователи"
msgid "Layouts"
msgstr "Макеты"
msgid "Services"
msgstr "Службы"
msgid "1 user"
msgid_plural "@count users"
msgstr[0] "@count пользователь"
msgstr[1] "@count пользователя"
msgstr[2] "@count[2] пользователей"
msgid "Here are the contents of your <code>$_SESSION</code> variable."
msgstr ""
"Содержимое Вашей переменной "
"<code>$_SESSION</code>."
msgid "Reinstall modules"
msgstr "Переустановка модулей"
msgid "Session viewer"
msgstr "Просмотрщик сессии"
msgid "Switch user"
msgstr "Сменить пользователя"
msgid "Devel"
msgstr "Devel"
msgid "Number of users to display in the list"
msgstr ""
"Количество пользователей, которые "
"нужно показать в списке."
msgid "This user can switch back."
msgstr ""
"Пользователь сможет переключиться "
"обратно."
msgid "New value"
msgstr "Новое значение"
msgid "Session name"
msgstr "Имя сессии"
msgid "Generate a given number of users. Optionally delete current users."
msgstr ""
"Создать заданное количество "
"пользователей. Опционально можно "
"удалить текущих пользователей."
msgid "How many users would you like to generate?"
msgstr ""
"Сколько пользователей Вы хотите "
"создать?"
msgid "How many nodes would you like to generate?"
msgstr ""
"Сколько материалов должно быть "
"создано?"
msgid "Various blocks, pages, and functions for developers."
msgstr ""
"Различные инструменты (блоки, "
"страницы и функции) для разработчиков."
msgid "Alias"
msgstr "Синоним"
msgid "Rebuild"
msgstr "Перестроить"
msgid "About"
msgstr "Информация"
msgid "Role(s)"
msgstr "Роли"
msgid "Regions"
msgstr "Области"
msgid "Field Info"
msgstr "Информация о поле"
msgid "Cache cleared."
msgstr "Кэш очищен."
msgid "Generate"
msgstr "Создать"
msgid "Run cron"
msgstr "Запустить cron"
msgid "Instances"
msgstr "Экземпляры"
msgid "Bundles"
msgstr "Наборы"
msgid "Uses"
msgstr "Использование"
msgid "Finished with an error."
msgstr "Завершено с ошибкой"
msgid "Rebuild the theme registry on every page load"
msgstr ""
"Перестраивать кэш темы при каждой "
"загрузке страницы"
msgid "Reinstall"
msgstr "Переустановка"
msgid "PHPinfo()"
msgstr "PHPinfo()"
msgid "Theme registry"
msgstr "Реестр темы"
msgid "Devel settings"
msgstr "Настройки Devel"
msgid "Delete all users (except user id 1) before generating new users."
msgstr ""
"Удалить всех пользователей (кроме "
"пользователя с id 1) перед генерацией "
"новых пользователей."
msgid "How old should user accounts be?"
msgstr ""
"Насколько старыми должны быть учётные "
"записи пользователей?"
msgid ""
"User ages will be distributed randomly from the current time, back to "
"the selected time."
msgstr ""
"Возрасты пользователей будут "
"распределены случайным образом "
"начиная с текущего времени, уходя в "
"прошлое до выбранного времени."
msgid "Requires path.module"
msgstr "Требуется модуль Path"
msgid "Add an url alias for each node."
msgstr ""
"Добавить синоним для каждого "
"материала."
msgid "Rebuild Menu"
msgstr "Перестроить меню"
msgid "Invalid input"
msgstr "Ошибочный ввод"
msgid "Block Content"
msgstr "Содержимое блока"
msgid "No modules selected."
msgstr "Ни один модуль не выбран."
msgid "No modules are available to uninstall."
msgstr "Нет доступных для удаления модулей."
msgid "Render"
msgstr "Показать"
msgid "Field types"
msgstr "Типы полей"
msgid "Switch users"
msgstr "Переключить пользователя"
msgid "Field info"
msgstr "Информация о поле"
msgid "Which roles should the users receive?"
msgstr ""
"Какую роль должны получить "
"пользователи?"
msgid "Users always receive the <em>authenticated user</em> role."
msgstr ""
"Пользователи всегда получают роль "
"<em>зарегистрированный "
"пользователь</em>."
msgid "Maximum number of comments per node."
msgstr ""
"Максимально количество комментариев "
"для материала"
msgid "media"
msgstr "медиа"
msgid "Requires locale.module"
msgstr "Требуется модуль Locale"
msgid "Entity info"
msgstr "Информация о сущности"
msgid "Generate a given number of terms. Optionally delete current terms."
msgstr ""
"Создает заданное количество терминов. "
"Опционально можно удалить текущие "
"термины."
msgid ""
"Generate a given number of vocabularies. Optionally delete current "
"vocabularies."
msgstr ""
"Создает заданное количество словарей. "
"Опционально можно удалить текущие "
"словари."
msgid "Media type"
msgstr "Тип медиа"
msgid "Cache clear"
msgstr "Очистить кэш"
msgid "Standard Drupal"
msgstr "Стандартный Drupal"
msgid "Maximum number of words in titles"
msgstr ""
"Максимальное количество слов в "
"заголовке"
msgid "Routes"
msgstr "Маршруты"
msgid "Enter a part of the module name or description to filter by."
msgstr ""
"Для фильтрации, введите часть имени "
"или описания модуля."
msgid "Toolbar items"
msgstr "Элементы панели инструментов"
msgid "menus"
msgstr "меню"
msgid "Route Name"
msgstr "Название маршрута"
msgid "Callable"
msgstr "Вызываемый"
msgid "%type: @message in %function (line %line of %file)."
msgstr "%type: @message in %function (line %line of %file)."
msgid "Config editor"
msgstr "Редактор конфигураций"
msgid "Reinstall Modules"
msgstr "Переустановить модули"
msgid "State editor"
msgstr "Редактор системных переменных"
msgid "Entity Info"
msgstr "Информация о сущностях"
msgid "View Session"
msgstr "Просмотр сессий"
msgid "Element Info"
msgstr "Информация об элементе"
msgid ""
"The theme information is being rebuilt on every request. Remember to "
"<a href=\":url\">turn off</a> this feature on production websites."
msgstr ""
"Информация о теме перестраивается при "
"каждом запросе. Не забудьте <a "
"href=\":url\">отключить</a> эту функцию на "
"рабочих сайтах."
msgid "Devel module enabled"
msgstr "Модуль Devel включен"
msgid "Container Info"
msgstr "Информация о контейнере"
msgid "Routes Info"
msgstr "Информация о роутах"
msgid "Current route info"
msgstr "Информация о текущем роуте"
msgid "Events Info"
msgstr "Информация о событиях"
msgid "Devel Toolbar Settings"
msgstr "Настройки панели инструментов Devel"
msgid "Devel Toolbar settings"
msgstr "Настройки панели инструментов Devel"
msgid "Menu items always visible"
msgstr "Постоянно видимые пункты меню"
# Russian translation of DropzoneJS (8.x-2.11)
# Copyright (c) 2024 by the Russian translation team
#
msgid ""
msgstr ""
"Project-Id-Version: DropzoneJS (8.x-2.11)\n"
"POT-Creation-Date: 2024-08-11 13:46+0000\n"
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=((((n%10)==1)&&((n%100)!=11))?(0):(((((n%10)>=2)&&((n%10)<=4))&&(((n%100)<10)||((n%100)>=20)))?(1):2));\n"
msgid "Edit"
msgstr "Редактировать"
msgid "Remove file"
msgstr "Удалить файл"
msgid "Media"
msgstr "Мультимедиа"
msgid "GB"
msgstr "ГБ"
msgid "or"
msgstr "или"
msgid "MB"
msgstr "МБ"
msgid "Allowed file extensions"
msgstr "Допустимые расширения файлов"
msgid "File upload error. Could not move uploaded file."
msgstr ""
"Ошибка закачки файла. Невозможно "
"переместить закачанный файл."
msgid "KB"
msgstr "КБ"
msgid "About"
msgstr "Информация"
msgid "Crop"
msgstr "Обрезка"
msgid "For security reasons, your upload has been renamed to %filename."
msgstr ""
"Ваш файл был переименован в %filename из "
"соображений безопасности."
msgid "The specified file %name could not be uploaded."
msgstr ""
"Указанный файл %name не может быть "
"загружен."
msgid ""
"Upload error. Could not move uploaded file %file to destination "
"%destination."
msgstr ""
"Ошибка закачки. Невозможно "
"переместить загруженный файл %file в "
"место назначения %destination."
msgid "Maximum height"
msgstr "Максимальная высота"
msgid "Maximum width"
msgstr "Максимальная ширина"
msgid "Form mode"
msgstr "Режим формы"
msgid "File upload"
msgstr "Загрузка файла"
msgid "Submit button text"
msgstr "Текст кнопки отправки"
msgid "Max width"
msgstr "Максимальная ширина"
msgid "Max height"
msgstr "Максимальная высота"
msgid "TB"
msgstr "ТБ"
msgid "Media type"
msgstr "Тип медиа"
msgid ""
"The file could not be uploaded because the destination %destination is "
"invalid."
msgstr ""
"Невозможно загрузить файл так как "
"путь сохранения %destination некорректный."
msgid "Drop files here to upload them"
msgstr ""
"Перетащите файлы сюда, чтобы "
"загрузить их"
msgid "A maximum of @count files can be uploaded."
msgstr ""
"Максимум @count файлов могут быть "
"загружены."
msgid "Select file"
msgid_plural "Select files"
msgstr[0] "Выберите файл"
msgstr[1] "Выберите файлы"
msgstr[2] "Выберите файлы"
msgid "Drop file here to upload it"
msgid_plural "Drop files here to upload them"
msgstr[0] ""
"Перетащите файл сюда, чтобы загрузить "
"его"
msgstr[1] ""
"Перетащите файлы сюда, чтобы "
"загрузить их"
msgstr[2] ""
"Перетащите файлы сюда, чтобы "
"загрузить их"
This source diff could not be displayed because it is too large. You can view the blob instead.
# Russian translation of Editor Advanced link (2.3.1)
# Copyright (c) 2025 by the Russian translation team
#
msgid ""
msgstr ""
"Project-Id-Version: Editor Advanced link (2.3.1)\n"
"POT-Creation-Date: 2025-07-08 13:46+0000\n"
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=((((n%10)==1)&&((n%100)!=11))?(0):(((((n%10)>=2)&&((n%10)<=4))&&(((n%100)<10)||((n%100)>=20)))?(1):2));\n"
msgid "Title"
msgstr "Заголовок"
msgid "ID"
msgstr "ID"
msgid "Advanced"
msgstr "Расширенные"
msgid "CSS classes"
msgstr "CSS классы"
msgid "Open in new window"
msgstr "Открыть в новом окне"
msgid ""
"Populates the title attribute of the link, usually shown as a small "
"tooltip on hover."
msgstr ""
"Заполняет атрибут title ссылки, обычно "
"отображаемый в виде небольшой "
"всплывающей подсказки при наведении."
msgid "Open in new window/tab"
msgstr "Открывать в новом окне/вкладке"
msgid "Link relationship"
msgstr "Отношение ссылки"
# Russian translation of Embed (8.x-1.10)
# Copyright (c) 2025 by the Russian translation team
#
msgid ""
msgstr ""
"Project-Id-Version: Embed (8.x-1.10)\n"
"POT-Creation-Date: 2025-01-23 20:46+0000\n"
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=((((n%10)==1)&&((n%100)!=11))?(0):(((((n%10)>=2)&&((n%10)<=4))&&(((n%100)<10)||((n%100)>=20)))?(1):2));\n"
msgid "List"
msgstr "Список"
msgid "None"
msgstr "Нет"
msgid "Settings"
msgstr "Настройки"
msgid "Name"
msgstr "Название"
msgid "Label"
msgstr "Метка"
msgid "Icon"
msgstr "Иконка"
msgid "Unknown"
msgstr "Неизвестно"
msgid "Filters"
msgstr "Фильтры"
msgid "Machine name"
msgstr "Машинное имя"
msgid "File directory"
msgstr "Каталог файлов"
msgid "Embed"
msgstr "Вставить"
msgid "Upload destination"
msgstr "Хранилище"
msgid ""
"Optional subdirectory within the upload destination where files will "
"be stored. Do not include preceding or trailing slashes."
msgstr ""
"Необязательный каталог внутри "
"каталога для загрузок, который будет "
"создан для хранения файлов этого поля. "
"Не добавляйте косую черту в начале и в "
"конце пути."
msgid "Embed button"
msgstr "Кнопка встраивания"
# Russian translation of Entity Browser (8.x-2.13)
# Copyright (c) 2025 by the Russian translation team
#
msgid ""
msgstr ""
"Project-Id-Version: Entity Browser (8.x-2.13)\n"
"POT-Creation-Date: 2025-02-16 10:42+0000\n"
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=((((n%10)==1)&&((n%100)!=11))?(0):(((((n%10)>=2)&&((n%10)<=4))&&(((n%100)<10)||((n%100)>=20)))?(1):2));\n"
msgid "Title"
msgstr "Заголовок"
msgid "Status"
msgstr "Статус"
msgid "Delete"
msgstr "Удалить"
msgid "Operations"
msgstr "Операции"
msgid "Type"
msgstr "Тип"
msgid "Actions"
msgstr "Действия"
msgid "Remove"
msgstr "Удалить"
msgid "Description"
msgstr "Описание"
msgid "Edit"
msgstr "Редактировать"
msgid "Reset"
msgstr "Сбросить"
msgid "- None -"
msgstr "- Не указано -"
msgid "Weight"
msgstr "Вес"
msgid "Name"
msgstr "Название"
msgid "Label"
msgstr "Метка"
msgid "Preview"
msgstr "Предпросмотр"
msgid "Save"
msgstr "Сохранить"
msgid "Default"
msgstr "По умолчанию"
msgid "Open"
msgstr "Открыть"
msgid "View"
msgstr "Просмотр"
msgid "Path"
msgstr "Путь"
msgid "Filename"
msgstr "Имя файла"
msgid "Display"
msgstr "Отображение"
msgid "ID"
msgstr "ID"
msgid "Upload"
msgstr "Закачать"
msgid "Created"
msgstr "Создано"
msgid "File size"
msgstr "Размер файла"
msgid "Multiple values"
msgstr "Множественный выбор"
msgid ", "
msgstr ", "
msgid "Media"
msgstr "Мультимедиа"
msgid "Desc"
msgstr "По убыванию"
msgid "OR"
msgstr "ИЛИ"
msgid "General"
msgstr "Общий"
msgid "General Settings"
msgstr "Основные параметры"
msgid "Link text"
msgstr "Текст ссылки"
msgid "Append"
msgstr "Добавить"
msgid "Sort by"
msgstr "Сортировать по"
msgid "Authored on"
msgstr "Создан в"
msgid "Change"
msgstr "Изменить"
msgid "‹ previous"
msgstr "‹ предыдущая"
msgid "next ›"
msgstr "следующая ›"
msgid "Replace"
msgstr "Заменить"
msgid "AND"
msgstr "И"
msgid "Metadata"
msgstr "Метаданные"
msgid "Allowed file extensions"
msgstr "Допустимые расширения файлов"
msgid "‹ Previous"
msgstr "‹ Предыдущий"
msgid "Next ›"
msgstr "Следующий ›"
msgid "Tabs"
msgstr "Вкладки"
msgid "Apply"
msgstr "Применить"
msgid "Form"
msgstr "Форма"
msgid "« first"
msgstr "« первая"
msgid "last »"
msgstr "последняя »"
msgid "Offset"
msgstr "Пропустить"
msgid "Machine name"
msgstr "Машинное имя"
msgid "Skip to main content"
msgstr "Перейти к основному содержанию"
msgid "About"
msgstr "Информация"
msgid "Page path"
msgstr "Путь страницы"
msgid "Entity type"
msgstr "Тип сущности"
msgid "iFrame"
msgstr "iFrame"
msgid "Widgets"
msgstr "Виджеты"
msgid ""
"The image was resized to fit within the maximum allowed dimensions of "
"%dimensions pixels."
msgstr ""
"Размеры изображения были изменены для "
"соответствия максимально допустимым "
"размерам в %dimensions пикселей."
msgid "The image is too small; the minimum dimensions are %dimensions pixels."
msgstr ""
"Изображение слишком мало. Минимальный "
"размер - %dimensions пикселей."
msgid "Bundle"
msgstr "Набор"
msgid "Created on"
msgstr "Создано"
msgid "Allowed extensions"
msgstr "Допустимые расширения файлов"
msgid "Form mode"
msgstr "Режим формы"
msgid "Uses"
msgstr "Использование"
msgid ""
"This text will be used by screen readers, search engines, or when the "
"image cannot be loaded."
msgstr ""
"Этот текст будет использован "
"программами для чтения с экрана, "
"поисковыми системами, или когда "
"изображение не может быть загружено."
msgid "Submit button text"
msgstr "Текст кнопки отправки"
msgid "Use AJAX"
msgstr "Использовать AJAX"
msgid "Items per page"
msgstr "Элементов на страницу"
msgid "- All -"
msgstr "- Все -"
msgid ""
"The title is used as a tool tip when the user hovers the mouse over "
"the image."
msgstr ""
"Заголовок будет использован для "
"всплывающей подсказки при наведении "
"мыши."
msgid "Alternative text"
msgstr "Альтернативный текст"
msgid ""
"The list of allowed extensions is not valid, be sure to exclude "
"leading dots and to separate extensions with a comma or space."
msgstr ""
"Список допустимых расширений не "
"верен. Удостоверьтесь что в списке нет "
"ведущей точки у каждого расширения и "
"что расширения разделены запятыми или "
"пробелами"
msgid "Include file in display"
msgstr "Включить файл в отображение"
msgid "The description may be used as the label of the link to the file."
msgstr ""
"Описание может использоваться как "
"текст ссылки на файл."
msgid "Preview image style"
msgstr "Стиль изображения при предпросмотре"
msgid "Image style"
msgstr "Стиль изображения"
msgid "Bundle ID"
msgstr "ID связки"
msgid "Upload files"
msgstr "Загрузить файлы"
msgid ""
"Separate extensions with a space or comma and do not include the "
"leading dot."
msgstr ""
"Введите расширения через пробел или "
"запятую. Не используйте точку перед "
"расширением."
msgid "Save entity"
msgstr "Сохранить сущность"
msgid "Modal"
msgstr "Модальное окно"
msgid "View mode"
msgstr "Режим просмотра"
msgid "Weight for row @number"
msgstr "Вес строки @number"
msgid "Choose a file"
msgstr "Выберите файл"
msgid "Asc"
msgstr "По возрастанию"
msgid "Select files"
msgstr "Выберите файлы"
msgid "Master"
msgstr "Основной"
msgid "File view mode"
msgstr "Режим просмотра файла"
msgid "Rendered entity"
msgstr "Готовая к выводу сущность"
msgid "@name field is required."
msgstr "Поле \"@name\" обязательно для заполнения."
msgid "Media type"
msgstr "Тип медиа"
msgid "@view : @display"
msgstr "@view : @display"
msgid "Entity label"
msgstr "Метка сущности"
msgid "The selected @label has already been added."
msgstr "Выбранный @label уже добавлен."
msgctxt "Sort order"
msgid "Order"
msgstr "Порядок"
msgid "Preview image style: @style"
msgstr ""
"Предварительный просмотр стиля "
"изображения: @style"
msgid "Display plugin"
msgstr "Плагин отображения"
msgid "Fallback value"
msgstr "Резервное значение"
msgid "Entity Browser"
msgstr "Браузер сущностей"
msgid "Entity browser"
msgstr "Обозреватель сущностей"
msgid "Select entities"
msgstr "Выбрать сущности"
msgid "Entity browsers"
msgstr "Обозреватели сущностей"
msgid "Entity Browsers"
msgstr "Обозреватели сущностей"
msgid "Use selected"
msgstr "Использовать выбранное"
msgid "Yes (Forced)"
msgstr "Да (Принудительно)"
msgid "No files yet"
msgstr "Пока нет файлов"
msgid "You can select one @entity_type."
msgstr "Вы можете выбрать один(ну) @entity_type."
msgid "You can select up to @maximum @entity_type (@remaining left)."
msgstr ""
"Вы можете выбрать до @maximum @entity_type "
"(@remaining осталось)."
msgid ""
"The image was resized to fit within the maximum allowed dimensions of "
"%dimensions pixels. The new dimensions of the resized image are "
"%new_widthx%new_height pixels."
msgstr ""
"Размер изображения был изменён в "
"соответствии с максимально "
"допустимыми размерами (%dimensions px). "
"Текущий размер изображения: "
"%new_widthx%new_height px."
msgid ""
"The image was resized to fit within the maximum allowed height of "
"%height pixels. The new dimensions of the resized image are "
"%new_widthx%new_height pixels."
msgstr ""
"Размер изображения был изменён в "
"соответствии с максимально "
"допустимой высотой (%height px).Текущий "
"размер изображения: %new_widthx%new_height px."
msgid ""
"The image was resized to fit within the maximum allowed width of "
"%width pixels. The new dimensions of the resized image are "
"%new_widthx%new_height pixels."
msgstr ""
"Размер изображения был изменён в "
"соответствии с максимально "
"допустимой шириной (%width px). Текущий "
"размер изображения: %new_widthx%new_height px."
# Russian translation of Entity Embed (8.x-1.7)
# Copyright (c) 2025 by the Russian translation team
#
msgid ""
msgstr ""
"Project-Id-Version: Entity Embed (8.x-1.7)\n"
"POT-Creation-Date: 2025-02-02 22:22+0000\n"
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=((((n%10)==1)&&((n%100)!=11))?(0):(((((n%10)>=2)&&((n%10)<=4))&&(((n%100)<10)||((n%100)>=20)))?(1):2));\n"
msgid "Title"
msgstr "Заголовок"
msgid "Next"
msgstr "Вперёд"
msgid "Description"
msgstr "Описание"
msgid "File"
msgstr "Файл"
msgid "None"
msgstr "Нет"
msgid "Image"
msgstr "Изображение"
msgid "Center"
msgstr "Центр"
msgid "Back"
msgstr "Назад"
msgid "Label"
msgstr "Метка"
msgid "Node"
msgstr "Материал"
msgid "Align"
msgstr "Выравнивание"
msgid "Filters"
msgstr "Фильтры"
msgid "Entity"
msgstr "Сущность"
msgid "Caption"
msgstr "Подпись"
msgid "Left"
msgstr "Слева"
msgid "Right"
msgstr "Справа"
msgid "Alternate text"
msgstr "Альтернативный текст"
msgid "Display as"
msgstr "Показать, как"
msgid "About"
msgstr "Информация"
msgid "Embed"
msgstr "Вставить"
msgid "Entity type"
msgstr "Тип сущности"
msgid "Bundles"
msgstr "Наборы"
msgid "Bundle"
msgstr "Набор"
msgid "Uses"
msgstr "Использование"
msgid ""
"This text will be used by screen readers, search engines, or when the "
"image cannot be loaded."
msgstr ""
"Этот текст будет использован "
"программами для чтения с экрана, "
"поисковыми системами, или когда "
"изображение не может быть загружено."
msgid ""
"The title is used as a tool tip when the user hovers the mouse over "
"the image."
msgstr ""
"Заголовок будет использован для "
"всплывающей подсказки при наведении "
"мыши."
msgid "The description may be used as the label of the link to the file."
msgstr ""
"Описание может использоваться как "
"текст ссылки на файл."
msgid "Entity Reference"
msgstr "Ссылка на сущность"
msgid "Enter caption here"
msgstr "Введите надпись здесь"
msgid "If none are selected, all are allowed."
msgstr ""
"Если ничего не выбрано, будет доступно "
"всё."
msgid ""
"Alternative text is required.<br />(Only in rare cases should this be "
"left empty. To create empty alternative text, enter <code>\"\"</code> "
"— two double quotes without any content)."
msgstr ""
"Требуется альтернативный текст. <br /> "
"(Только в редких случаях его следует "
"оставлять пустым. Чтобы создать "
"пустой альтернативный текст, введите "
"<code>\"\"</code> - две двойные кавычки без "
"содержимого)."
msgid ""
"Type label and pick the right one from suggestions. Note that the "
"unique ID will be saved."
msgstr ""
"Введите метку и выберите подходящий "
"из предложенных вариантов. Обратите "
"внимание, что уникальный "
"идентификатор будет сохранен."
msgid "Selected entity"
msgstr "Выбранная сущность"
msgid "Entity browser"
msgstr "Обозреватель сущностей"
msgid "Entity browser settings"
msgstr "Настройки обозревателя сущностей"
msgid "Replace selection"
msgstr "Заменить выбранное"
msgid "Preview failed"
msgstr "Ошибка предварительного просмотра"
# Russian translation of Entity Reference Revisions (8.x-1.12)
# Copyright (c) 2024 by the Russian translation team
#
msgid ""
msgstr ""
"Project-Id-Version: Entity Reference Revisions (8.x-1.12)\n"
"POT-Creation-Date: 2024-08-04 21:46+0000\n"
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=((((n%10)==1)&&((n%100)!=11))?(0):(((((n%10)>=2)&&((n%10)<=4))&&(((n%100)<10)||((n%100)>=20)))?(1):2));\n"
msgid "Value"
msgstr "Значение"
msgid "Type"
msgstr "Тип"
msgid "Label"
msgstr "Метка"
msgid "Revision ID"
msgstr "ID редакции"
msgid "Filter by"
msgstr "Фильтровать по"
msgid "Role"
msgstr "Роль"
msgid "Sort by"
msgstr "Сортировать по"
msgid "Search fields"
msgstr "Поля для поиска"
msgid "Default value"
msgstr "Значение по умолчанию"
msgid "types"
msgstr "типы"
msgid "About"
msgstr "Информация"
msgid "Sort direction"
msgstr "Направление сортировки"
msgid "No link"
msgstr "Ссылки нет"
msgid "Autocomplete"
msgstr "Автодополнение"
msgid "Uses"
msgstr "Использование"
msgid "Filter settings"
msgstr "Параметры фильтров"
msgid "Displays the fields with an optional template."
msgstr ""
"Отображает поля с дополнительным "
"шаблоном."
msgid "Restrict to the selected roles"
msgstr "Ограничить для выбранных ролей"
msgid "Field types"
msgstr "Типы полей"
msgid "An error occurred while processing @operation with arguments : @args"
msgstr ""
"Возникла ошибка в процессе @operation с "
"аргументами: @args"
msgid "View mode"
msgstr "Режим просмотра"
msgid "Appears in: @bundles."
msgstr "Местонахождение: @bundles."
msgid "An autocomplete text field."
msgstr "Текстовое поле с автодополнением."
msgid "Rendered entity"
msgstr "Готовая к выводу сущность"
msgid "Display the referenced entities rendered by entity_view()."
msgstr ""
"Отображать связанные сущности с "
"помощью entity_view()."
msgid "Link label to the referenced entity"
msgstr "Сделать метку ссылкой на сущность"
msgid "Link to the referenced entity"
msgstr "Ссылка на указанную сущность"
msgid "Rendered as @mode"
msgstr "Отрендерено в режиме @mode"
msgid "Other…"
msgstr "Другое..."
msgid ""
"<strong>Note:</strong> In 'Entity Reference' displays, all fields will "
"be displayed inline unless an explicit selection of inline fields is "
"made here."
msgstr ""
"<strong>Обратите внимание:</strong> In 'Entity "
"Reference' displays, all fields will be displayed inline unless an "
"explicit selection of inline fields is made here."
msgid ""
"Select the field(s) that will be searched when using the autocomplete "
"widget."
msgstr ""
"Выберите поле(я), по которому(ым) будет "
"вестись поиск при использовании "
"виджета автодополнения."
msgid "@field_name"
msgstr "@field_name"
msgid "Type of item to reference"
msgstr "Тип элемента для ссылки"
msgid "Create referenced entities if they don't already exist"
msgstr ""
"Создать сущность если она ещё не "
"создана"
msgid "Entity Reference inline fields"
msgstr "Ссылка на сущность встроенные поля"
msgid "Returns results as a PHP array of labels and rendered rows."
msgstr ""
"Возвращает результат как PHP массив "
"меток и готовых к выводу строк."
msgid "Managing and displaying entity reference fields"
msgstr ""
"Управление полями ссылок на сущность "
"и их отображение"
msgid "Selecting reference type"
msgstr "Выбор типа ссылки"
msgid ""
"In the field settings you can select which entity type you want to "
"create a reference to."
msgstr ""
"В настройках поля вы можете выбрать "
"тип сущности, на который хотите "
"создать ссылку."
msgid "Filtering and sorting reference fields"
msgstr "Фильтрация и сортировка полей ссылок"
msgid ""
"Depending on the chosen entity type, additional filtering and sorting "
"options are available for the list of entities that can be referred "
"to, in the field settings. For example, the list of users can be "
"filtered by role and sorted by name or ID."
msgstr ""
"В зависимости от выбранного типа "
"объекта в настройках поля доступны "
"дополнительные параметры фильтрации "
"и сортировки для списка объектов, на "
"которые можно ссылаться. Например, "
"список пользователей может быть "
"отфильтрован по роли и отсортирован "
"по имени или идентификатору."
msgid "Displaying a reference"
msgstr "Отображение ссылки"
msgid ""
"An entity reference can be displayed as a simple label with or without "
"a link to the entity. Alternatively, the referenced entity can be "
"displayed as a teaser (or any other available view mode) inside the "
"referencing entity."
msgstr ""
"Ссылка на сущность может отображаться "
"в виде простой метки со ссылкой на "
"сущность или без нее. В качестве "
"альтернативы ссылочный объект может "
"отображаться в виде тизера (или любого "
"другого доступного режима просмотра) "
"внутри ссылающегося объекта."
msgid "View handler settings"
msgstr "Настройки обработчика представления"
msgid "Sort settings"
msgstr "Настройки сортировки"
msgid "Search field"
msgstr "Поле поиска"
msgid "@label referenced from @field_name"
msgstr ""
"Сущность \"@label\", на которую ссылаются с "
"поля \"@field_name\""
msgid "@field_name: @label"
msgstr "@field_name: @label"
msgid "Target UUID"
msgstr "Целевой UUID"
msgid ""
"Recursive rendering detected when rendering entity @entity_type "
"@entity_id. Aborting rendering."
msgstr ""
"Во время генерирования сущности "
"@entity_type @entity_id обнаружена рекурсия. "
"Генерирование прервано."
msgid "@entity using @field_name"
msgstr "@entity использует @field_name"
msgid "Relate each @entity with a @field_name set to the @label."
msgstr "Связать каждую @entity с @field_name с @label."
msgid ""
"The <em>settings</em> and the <em>display</em> of the entity reference "
"field can be configured separately. See the <a "
"href=\":field_ui\">Field UI help</a> for more information on how to "
"manage fields and their display."
msgstr ""
"<em>Настройки</em> и <em>отображение</em> "
"поля ссылки на сущность можно "
"настроить отдельно. См. <a "
"href=\":field_ui\">справку по "
"пользовательскому интерфейсу поля</a> "
"для получения дополнительной "
"информации об управлении полями и их "
"отображением."
msgid "Reference revisions"
msgstr "Ревизии ссылки"
msgid "Entity Reference Revisions"
msgstr "Редакции ссылки на сущность"
msgid "Entity Reference Revisions list"
msgstr "Список редакций ссылки на сущность"
msgid "Entity reference revisions"
msgstr "Редакции ссылки на сущность"
msgid "Entity Revision"
msgstr "Редакция сущности"
msgid "An entity field containing an entity reference to a specific revision."
msgstr ""
"Поле, ссылающееся на конкретную "
"ревизию сущности."
msgid "Delete orphaned composite entities"
msgstr ""
"Удалить осиротевшие составные "
"сущности"
msgid "Delete orphan revisions"
msgstr "Удалить осиротевшие редакции"
msgid "Removing orphaned entities."
msgstr "Удаление осиротевших сущностей."
msgid ""
"@label: Deleted @revision_count revisions (@entity_count entities) in "
"@interval."
msgstr ""
"@label: Удалено @revision_count редакций (@entity_count "
"сущности) за @interval."
msgid ""
"The submission of the current form can cause the deletion of entities "
"that are still used, backup all data first."
msgstr ""
"Отправка текущей формы может привести "
"к удалению объектов, которые всё ещё "
"используются, сначала сделайте "
"резервную копию всех данных."
msgid ""
"Delete orphaned composite entities revisions that are no longer "
"referenced. If there are no revisions left, the entity will be deleted "
"as long as it is not used."
msgstr ""
"Удаление редакций потерянных "
"составных сущностей, на которые "
"больше нет ссылок. Если редакций не "
"осталось, сущность будет удалена до "
"тех пор, пока она не будет "
"использоваться."
msgid "Select the entity types to check for orphans"
msgstr ""
"Выберите типы сущностей для проверки "
"на наличие сирот"
msgid "Delete orphaned composite revisions"
msgstr ""
"Удалить потерянные составные "
"редакции"
# Russian translation of Field Group (8.x-3.6)
# Copyright (c) 2024 by the Russian translation team
#
msgid ""
msgstr ""
"Project-Id-Version: Field Group (8.x-3.6)\n"
"POT-Creation-Date: 2024-10-18 15:18+0000\n"
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=((((n%10)==1)&&((n%100)!=11))?(0):(((((n%10)>=2)&&((n%10)<=4))&&(((n%100)<10)||((n%100)>=20)))?(1):2));\n"
msgid "delete"
msgstr "удалить"
msgid "Delete"
msgstr "Удалить"
msgid "Cancel"
msgstr "Отмена"
msgid "Description"
msgstr "Описание"
msgid "Yes"
msgstr "Да"
msgid "No"
msgstr "Нет"
msgid "Edit"
msgstr "Редактировать"
msgid "None"
msgstr "Нет"
msgid "Weight"
msgstr "Вес"
msgid "Label"
msgstr "Метка"
msgid "Update"
msgstr "Обновить"
msgid "Region"
msgstr "Область"
msgid "ID"
msgstr "ID"
msgid "Horizontal"
msgstr "Горизонтально"
msgid "Vertical"
msgstr "Вертикально"
msgid "Fields"
msgstr "Поля"
msgid "Details"
msgstr "Подробности"
msgid "Group name"
msgstr "Название группы"
msgid "Attributes"
msgstr "Атрибуты"
msgid "Clone"
msgstr "Клонировать"
msgid "Tab"
msgstr "Вкладка"
msgid "Default state"
msgstr "Состояние по умолчанию"
msgid "Collapsible"
msgstr "Сворачиваемое"
msgid "Slow"
msgstr "Медленно"
msgid "Fast"
msgstr "Быстро"
msgid "Tabs"
msgstr "Вкладки"
msgid "Identifier"
msgstr "Идентификатор"
msgid "Data"
msgstr "Данные"
msgid "About"
msgstr "Информация"
msgid "Element"
msgstr "Элемент"
msgid "Effect"
msgstr "Эффект"
msgid "Speed"
msgstr "Скорость"
msgid "Entity type"
msgstr "Тип сущности"
msgid "Add a new group"
msgstr "Добавить новую группу"
msgid "Direction"
msgstr "Направление"
msgid "Save and continue"
msgstr "Сохранить и продолжить"
msgid "Migration"
msgstr "Миграция"
msgid "Create group"
msgstr "Создать группу"
msgid "Bundle"
msgstr "Набор"
msgid "Fieldset"
msgstr "Fieldset"
msgid "Field group label"
msgstr "Метка группы полей"
msgid "Bounce slide"
msgstr "Упругое скольжение"
msgid "More Information"
msgstr "Больше информации"
msgid "Label element"
msgstr "Элемент метки"
msgid "View mode"
msgstr "Режим просмотра"
msgid "HTML element"
msgstr "HTML-элемент"
msgid "Field group format:"
msgstr "Формат группы полей:"
msgid ""
"The css class must include only letters, numbers, underscores and "
"dashes."
msgstr ""
"CSS-класс может включать в себя только "
"буквы, цифры, знак подчеркивания и "
"тире."
msgid "Are you sure you want to delete the group %group?"
msgstr ""
"Вы уверены, что хотите удалить группу "
"%group?"
msgid "The group %group has been deleted from the %type content type."
msgstr ""
"Группа %group удалена из типа материала "
"%type content."
msgid "This fieldgroup renders child groups as jQuery accordion."
msgstr ""
"Эта группа полей создает дочерние "
"группы в виде \"аккордеона\" jQuery"
msgid "This fieldgroup renders the content in a div, part of accordion group."
msgstr ""
"Эта группа полей создает содержимое в "
"div'е - части группы \"аккордеона\""
msgid "Extra CSS classes"
msgstr "Дополнительные классы CSS"
msgid "Horizontal Tabs"
msgstr "Горизонтальные вкладки"
msgid "Fieldgroups"
msgstr "Группы полей"
msgid ""
"<p class=\"fieldgroup-help\">Fields can be dragged into groups with "
"unlimited nesting. Each fieldgroup format comes with a configuration "
"form, specific for that format type.<br />Note that some formats come "
"in pair. These types have a html wrapper to nest its fieldgroup "
"children. E.g. Place accordion items into the accordion, vertical tabs "
"in vertical tab group and horizontal tabs in the horizontal tab group. "
"There is one exception to this rule, you can use a vertical tab "
"without a wrapper when the additional settings tabs are available. "
"E.g. node forms.</p>"
msgstr ""
"<p class=\"fieldgroup-help\">Поля могут быть "
"перетащены в группы с неограниченным "
"вложением. Каждый формат группы полей "
"выступает в роли формы конфигурации, "
"определенной для этого типа формата.<br "
"/>Обратите внимание, что некоторые "
"форматы добавляются в паре. Эти типы "
"имеют HTML-обертку для своих потомков. "
"Это, например, относится к "
"\"аккордеонам\", вертикальным и "
"горизонтальным вкладкам. Из этого "
"правила есть одно исключение: вы "
"можете использовать вертикальные "
"вкладки без обертки, когда включены "
"дополнительные настройки вкладок. "
"Например, в формах материалов.</p>"
msgid "New group %label successfully created."
msgstr "Новая группа %label успешно создана."
msgid "The field name"
msgstr "Имя поля"
msgid "Weight: @weight"
msgstr "Вес: @weight"
msgid ""
"Fieldgroup @group is not cloned since a group already exists with the "
"same name."
msgstr ""
"Группа полей @group не клонирована, "
"потому что уже существует группа с "
"таким же именем."
msgid "Fieldgroup @group cloned successfully."
msgstr ""
"Группа полей @group успешно "
"склонирована."
msgid "Show label"
msgstr "Показать метку"
msgid "Add field group"
msgstr "Добавить группу полей"
msgid ""
"A unique machine-readable name containing letters, numbers, and "
"underscores."
msgstr ""
"Уникальное машинное имя, содержащее "
"буквы, цифры и знак подчеркивания."
msgid "Field Group"
msgstr "Группа полей"
msgid "A field group"
msgstr "Группа полей"
msgid "The weight of the group"
msgstr "Вес группы"
msgid "show the label"
msgstr "показать метку"
msgid "Effect : @effect"
msgstr "Эффект : @effect"
msgid "Mark as required"
msgstr "Пометить как обязательное"
msgid "Description : @description"
msgstr "Описание : @description"
msgid "Default state open"
msgstr "Состояние по умолчанию открыто"
msgid "Default state closed"
msgstr "Состояние по умолчанию закрыто"
msgid "Element: @element"
msgstr "Элемент: @element"
msgid "Label element: @element"
msgstr "Метка элемента: @element"
msgid "Attributes: @attributes"
msgstr "Атрибуты: @attributes"
msgid "Direction: @direction"
msgstr "Направление: @direction"
msgid ""
"Display this field group even if the contained fields are currently "
"empty."
msgstr ""
"Отобразить эту группу полей, даже если "
"содержащиеся в ней поля пусты."
# Russian translation of Flag (8.x-4.0-beta7)
# Copyright (c) 2025 by the Russian translation team
#
msgid ""
msgstr ""
"Project-Id-Version: Flag (8.x-4.0-beta7)\n"
"POT-Creation-Date: 2025-04-05 17:26+0000\n"
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=((((n%10)==1)&&((n%100)!=11))?(0):(((((n%10)>=2)&&((n%10)<=4))&&(((n%100)<10)||((n%100)>=20)))?(1):2));\n"
msgid "Status"
msgstr "Статус"
msgid "Enable"
msgstr "Включить"
msgid "Disable"
msgstr "Отключить"
msgid "Disabled"
msgstr "Отключено"
msgid "Enabled"
msgstr "Включено"
msgid "Edit"
msgstr "Редактировать"
msgid "Reset"
msgstr "Сбросить"
msgid "None"
msgstr "Нет"
msgid "Weight"
msgstr "Вес"
msgid "Name"
msgstr "Название"
msgid "Label"
msgstr "Метка"
msgid "Update"
msgstr "Обновить"
msgid "User"
msgstr "Пользователь"
msgid "Continue"
msgstr "Продолжить"
msgid "User ID"
msgstr "ID Пользователя"
msgid "Created"
msgstr "Создано"
msgid "All"
msgstr "Все"
msgid "Roles"
msgstr "Роли"
msgid "Comment"
msgstr "Комментарий"
msgid "Session ID"
msgstr "ID сессии"
msgid "Display options"
msgstr "Настройки отображения"
msgid "By"
msgstr "Автор:"
msgid "Flag"
msgstr "Пометить флагом"
msgid "Messages"
msgstr "Сообщения"
msgid "Entity"
msgstr "Сущность"
msgid "Bookmark"
msgstr "Закладки"
msgid "Link type"
msgstr "Тип ссылки"
msgid "Scope"
msgstr "Ограничение"
msgid "flag"
msgstr "отметить"
msgid "Any user"
msgstr "Любой пользователь"
msgid "Global"
msgstr "Глобальный"
msgid "Machine name"
msgstr "Машинное имя"
msgid "Unflag"
msgstr "Снять пометку"
msgid "Flagged"
msgstr "Помечено"
msgid "Flags"
msgstr "Флаги"
msgid "Display link on user profile page"
msgstr ""
"Отображать ссылку на странице учётной "
"записи пользователя"
msgid "Normal link"
msgstr "Обычная ссылка"
msgid ""
"The <a href=\"@flag-handbook-url\">Flag module handbook</a> contains "
"extensive <a href=\"@customize-url\">documentation on creating "
"customized views</a> using flags."
msgstr ""
"<a href=\"@flag-handbook-url\">Руководство по "
"модулю Flag</a> содержит <a "
"href=\"@customize-url\">документацию по созданию "
"индивидуальных представлений</a>, "
"использующих флаги."
msgid "Flagging an item may trigger <a href=\"@rules-url\">rules</a>."
msgstr ""
"Отметить пункт можно триггером <a "
"href=\"@rules-url\">правила</a>."
msgid ""
"To learn about the various ways to use flags, please check out the <a "
"href=\"@handbook-url\">Flag module handbook</a>."
msgstr ""
"Для изучения различных путей "
"использования флагов посетите, "
"пожалуйста, <a href=\"@handbook-url\">руководство "
"по модулю Flag</a>."
msgid "Flag name"
msgstr "Имя флага"
msgid "Flag link text"
msgstr "Постановка флага: текст ссылки"
msgid "The text for the \"flag this\" link for this flag."
msgstr ""
"Текст ссылки постановки флага. Пример: "
"<em>Добавить в закладки</em>."
msgid "Flag link description"
msgstr "Постановка флага: описание"
msgid ""
"The description of the \"flag this\" link. Usually displayed on "
"mouseover."
msgstr ""
"Описание ссылки постановки флага. "
"Отображается при наведении курсора."
msgid "Flag confirmation message"
msgstr "Предупреждающее сообщение флага"
msgid ""
"Message displayed if the user has clicked the \"flag this\" link and "
"confirmation is required. Usually presented in the form of a question "
"such as, \"Are you sure you want to flag this content?\""
msgstr ""
"Текст подтверждения. Пример: <em>Вы "
"действительно хотите добавить эту "
"страницу в закладки?</em>"
msgid "Flagged message"
msgstr "Сообщение после установки флага"
msgid ""
"Message displayed after flagging content. If JavaScript is enabled, it "
"will be displayed below the link. If not, it will be displayed in the "
"message area."
msgstr ""
"Сообщение после постановки "
"показывается после нажатия на ссылку. "
"Если JavaScript включен, то сообщение будет "
"показываться под флажком, если JavaScript "
"выключен, то сообщение будет "
"показываться в стандартной области "
"сообщений."
msgid "Unflag link text"
msgstr "Снятие флага: текст ссылки"
msgid "The text for the \"unflag this\" link for this flag."
msgstr ""
"Текст ссылки постановки флага. Пример: "
"<em>Удалить из закладок</em>."
msgid "Unflag link description"
msgstr "Снятие флага: описание"
msgid ""
"The description of the \"unflag this\" link. Usually displayed on "
"mouseover."
msgstr ""
"Описание ссылки снятия флага. "
"Отображается при наведении курсора."
msgid "Unflag confirmation message"
msgstr ""
"Подтверждающее сообщение снятия "
"флага"
msgid ""
"Message displayed if the user has clicked the \"unflag this\" link and "
"confirmation is required. Usually presented in the form of a question "
"such as, \"Are you sure you want to unflag this content?\""
msgstr ""
"Текст подтверждения. Пример: <em>Вы "
"действительно хотите удалить эту "
"страницу из закладок?</em>"
msgid "Unflagged message"
msgstr "Сообщение после снятия флага"
msgid ""
"Message displayed after content has been unflagged. If JavaScript is "
"enabled, it will be displayed below the link. If not, it will be "
"displayed in the message area."
msgstr ""
"Сообщение после снятия показывается "
"после нажатия на ссылку. Если JavaScript "
"включен, то сообщение будет "
"показываться под флажком, если JavaScript "
"выключен, то сообщение будет "
"показываться в стандартной области "
"сообщений."
msgid "Flag actions"
msgstr "Действия Flag"
msgid "The current count total for this flag."
msgstr "Текущее общий счётчик для этого флага."
msgid "Total flag count for flag @flag"
msgstr "Итоговый счётчик флагов для флага @flag"
msgid "Filter to ensure content has or has not been flagged."
msgstr ""
"Фильтр для указания того, отмечено ли "
"содержимое флагом или нет."
msgid "Flag link"
msgstr "Ссылка флага"
msgid "Display flag/unflag link."
msgstr ""
"Отображать ссылку \"пометить/снять "
"пометку\"."
msgid "Flag counter"
msgstr "Счетчик флага"
msgid "The number of times a piece of content is flagged by any user."
msgstr ""
"Количество отметок флагом "
"содержимого различными "
"пользователями"
msgid "Not flagged"
msgstr "Не помечено"
msgid "The name of the selected flag makes a good label."
msgstr ""
"Имя флага придает флагу аккуратный "
"вид"
msgid "Current user"
msgstr "Текущий пользователь"
msgid "Include only flagged content"
msgstr "Включить только помеченные материалы"
msgid ""
"If checked, only content that has this flag will be included. Leave "
"unchecked to include all content; or, in combination with the "
"<em>Flagged</em> filter, <a href=\"@unflagged-url\">to limit the "
"results to specifically unflagged content</a>."
msgstr ""
"Если установлено, будет включено "
"только содержимое отмеченное этим "
"флагом. Оставьте отключенным для "
"включения всего содержимого; или "
"совместно с <em>Flagged</em> фильтром, <a "
"href=\"@unflagged-url\">для ограничения "
"результата не отмеченным "
"содержимым</a>."
msgid "Following"
msgstr "Подписаны"
msgid "No flags"
msgstr "Нет флагов"
msgid "Dialog"
msgstr "Диалог"
msgid "Entity Type"
msgstr "Тип сущности"
msgid "Show on form"
msgstr "Показывать в форме"
msgid ""
"A normal non-JavaScript request will be made and the current page will "
"be reloaded."
msgstr ""
"Будет сделан обычный запрос (не JavaScript) "
"и текущая страница перезагрузится."
msgid "Flag access"
msgstr "Доступ к флагам"
msgid "Unflag not allowed text"
msgstr "Текст запрета снятия флага"
msgid ""
"If a user is allowed to flag but not unflag, this text will be "
"displayed after flagging. Often this is the past-tense of the link "
"text, such as \"flagged\"."
msgstr ""
"Если пользователю позволено помечать "
"флагом, но не разрешено его снимать, "
"отобразится этот текст. Зачастую "
"используется текст в прошедшем "
"времени, например: \"Уже помечено\"."
msgid ""
"No %type flags exist. You must first <a href=\"@create-url\">create a "
"%type flag</a> before being able to use this relationship type."
msgstr ""
"Нет флагов типа %type. Сначала вы должны "
"<a href=\"@create-url\">создать флаг</a>, прежде "
"чем использовать этот тип отношения."
msgid "Entity ID"
msgstr "Идентификатор сущности"
msgid "Exposed"
msgstr "Раскрытый"
msgid "Tokens related to flag data."
msgstr ""
"Токены, связанные с информацией о "
"флагах"
msgid "The flag machine-readable name."
msgstr "Машинное имя флага."
msgid "Flag title"
msgstr "Заголовок флага"
msgid "The human-readable flag title."
msgstr "Удобочитаемый заголовок флага."
msgid ""
"Tokens available in response to a flag action being executed by a "
"user."
msgstr ""
"Токены, доступные в ответе на действие "
"флагирования, выполненное "
"пользователем."
msgid "Flag action"
msgstr "Действия с флагами"
msgid "The flagging action taking place, either \"flag\" or \"unflag\"."
msgstr ""
"Действие флагирования имеет место. "
"\"Пометить флагом\" или \"снять флаг\"."
msgid "Flag count"
msgstr "Количество отметок"
msgid "@flag flag count"
msgstr "@flag счётчик флагов"
msgid "UUID"
msgstr "UUID"
msgid "View mode"
msgstr "Режим просмотра"
msgid ""
"This page lists all the <em>flags</em> that are currently defined on "
"this system."
msgstr ""
"На этой странице находится список "
"всех флагов, определенных в системе."
msgid ""
"Flagging an item may trigger <em>rules</em>. However, you don't have "
"the <a href=\"@rules-url\">Rules</a> module enabled, so you won't be "
"able to enjoy this feature. The Rules module is a more extensive "
"solution than Flag actions."
msgstr ""
"Флагирование элементов может "
"управляться посредством <em>правил</em>. "
"Однако, модуль <a href=\"@rules-url\">Rules</a> "
"отсутствует или отключен, поэтому вы "
"не можете использовать эту "
"возможность. Модуль Rules также "
"предоставляет более обширные "
"возможности, нежели просто действия "
"Flag."
msgid ""
"Configure flags for marking content with arbitrary information (such "
"as <em>offensive</em> or <em>bookmarked</em>)."
msgstr ""
"Конфигурировать флаги для создания "
"содержимого с произвольной "
"информацией (такой как "
"<em>оскорбительная</em> или "
"<em>закладки</em>)."
msgid ""
"The machine-name for this flag. It may be up to 32 characters long and "
"may only contain lowercase letters, underscores, and numbers. It will "
"be used in URLs and in all API calls."
msgstr ""
"Машинное имя для этого флага. Может "
"иметь длину не более 32 символов и "
"содержать только строчные буквы, "
"цифры и символы подчеркивания. Это "
"будет использовано в URL и API-вызовах."
msgid "@flag flag link"
msgstr "Ссылка флага @flag"
msgid "Flag/unflag link for @flag"
msgstr "Отметить/снять флаг @flag со ссылки"
msgid "@entity_label flag"
msgstr "@entity_label флаг"
msgid ""
"Limit results to only those entity flagged by a certain flag; Or "
"display information about the flag set on a entity."
msgstr ""
"Ограничить результат только теми "
"сущностями, которые отмечены флагом; "
"Или показать информацию о флаге "
"установленном на сущности."
msgid "Add flag"
msgstr "Добавить флаг"
msgid "Time last flagged"
msgstr "Время последней отметки флагом"
msgid "The time a piece of content was most recently flagged by any user."
msgstr ""
"Самое ближайшее время, когда часть "
"содержимого была отмечена флагом "
"любым пользователем."
msgid "Display in contextual links"
msgstr "Показывать в контекстных ссылках"
msgid "Display checkbox on entity edit form"
msgstr ""
"Отображать флажок в форме "
"редактирования сущности"
msgid "Checkboxes for toggling flags"
msgstr "Флажки для переключения флагов"
msgid "flagging"
msgstr "отметка флагом"
msgid "Flaggings"
msgstr "Отметки флагом"
msgid "Tokens related to flaggings."
msgstr "Токены, связанные с отметками флагами."
msgid "Flagging date"
msgstr "Дата отметки флагом."
msgid "The date an item was flagged."
msgstr ""
"Дата, когда элемент был отмечен "
"флагом."
msgid "Flag entity URL"
msgstr "URL сущности-флага"
msgid "The URL of the entity being flagged."
msgstr "URL сущности, бывшей помеченной флагом."
msgid "Flag entity title"
msgstr "Заголовок сущности для отметки"
msgid "The title of the entity being flagged."
msgstr ""
"Заголовок сущности, бывшей помеченной "
"флагом."
msgid "Flag entity type"
msgstr "Тип сущности для отметки"
msgid ""
"The type of entity being flagged, such as <em>node</em> or "
"<em>comment</em>."
msgstr ""
"Тип сущности, бывшей отмеченной "
"флагом, такой как <em>материал</em> или "
"<em>комментарий</em>."
msgid "Flag entity ID"
msgstr "ID сущности для отметки"
msgid "The ID of entity being flagged, such as a nid or cid."
msgstr ""
"ID сущности, бывшей помеченной, такой "
"как nid или cid."
msgid "Flagging"
msgstr "Работа с флагами"
msgid "Create customized flags that users can set on entities."
msgstr ""
"Создать индивидуальные флаги, "
"которыми пользователи могут отмечать "
"сущности."
msgid "Flag Bookmark"
msgstr "Flag Bookmark"
msgid "Provides an example bookmark flag and supporting views."
msgstr ""
"Предоставляет пример флага закладок и "
"соответствующие представления."
msgid "Flag this item"
msgstr "Отметить флагом"
msgid "Unflag this item"
msgstr "Снять флаг"
msgid "Flaggable types"
msgstr "Типы, доступные для флагов"
msgid "Flag %flag_title"
msgstr "Отметить флагом %flag_title"
msgid "Unflag %flag_title"
msgstr "Снять флаг %flag_title"
msgid "A boolean field to show whether the flag is set or not."
msgstr ""
"Логическое поле, показывающее "
"установлен флаг или нет."
msgid "Sort by whether entities have or have not been flagged."
msgstr ""
"Сортировка по тому, отмечена ли "
"сущность флагом или нет."
msgid "Entity Bundles"
msgstr "Бандлы сущности"
msgid "Display on @name view mode"
msgstr ""
"Отображать в режиме просмотра для "
"\"@name\""
msgid "Display in entity links"
msgstr "Отображение в ссылках сущностей"
msgid "Show the flag link with the other links on the entity."
msgstr ""
"Отображать ссылку флага с другими "
"ссылками в сущности."
msgid "Show the link formatted as a user profile element."
msgstr ""
"Отображать ссылку в формате элемента "
"учётной записи пользователя"
msgid "Administer Flags"
msgstr "Управлять флагами"
msgid "Individual flag link"
msgstr "Индивидуальная ссылка флага"
msgid "Display link as field"
msgstr "Отображать ссылку как поле"
msgid "Select the type of flag to create."
msgstr "Выберите тип создаваемого флага"
msgid "Edit Flag"
msgstr "Редактировать флаг"
msgid "Flag Type"
msgstr "Тип флага"
msgid ""
"Type of item to reference. This cannot be changed once the flag is "
"created."
msgstr ""
"Тип элемента. Эта опция не может быть "
"изменена после создания флага."
msgid "Save Flag"
msgstr "Сохранить флаг"
msgid "Flag %label has been updated."
msgstr "Флаг \"%label\" был обновлён."
msgid "AJAX link"
msgstr "AJAX ссылка"
msgid "Confirm Form"
msgstr "Форма подтверждения"
msgid "Administer Flaggings"
msgstr "Управлять установленными флагами"
msgid "An AJAX JavaScript request will be made without reloading the page."
msgstr ""
"AJAX JavaScript запрос будет произведён без "
"перезагрузки страницы"
msgid "Redirects the user to a confirmation form."
msgstr ""
"Перенаправляет пользователя на формy "
"подтверждения."
msgid "Redirects the user to a field entry form."
msgstr ""
"Перенаправляет пользователя на формy "
"добавления полей."
# Russian translation of Flood control (3.0.0)
# Copyright (c) 2024 by the Russian translation team
#
msgid ""
msgstr ""
"Project-Id-Version: Flood control (3.0.0)\n"
"POT-Creation-Date: 2024-09-27 10:46+0000\n"
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=((((n%10)==1)&&((n%100)!=11))?(0):(((((n%10)>=2)&&((n%10)<=4))&&(((n%100)<10)||((n%100)>=20)))?(1):2));\n"
msgid "Status"
msgstr "Статус"
msgid "Administration"
msgstr "Администрирование"
msgid "Login"
msgstr "Логин"
msgid "Event"
msgstr "Событие"
msgid "Timestamp"
msgstr "Время"
msgid "Filter"
msgstr "Фильтр"
msgid "Amount"
msgstr "Сумма"
msgid "Expiration"
msgstr "Срок действия"
msgid "Blocked"
msgstr "Заблокировано"
msgid "Identifier"
msgstr "Идентификатор"
msgid "Infinite"
msgstr "Бесконечность"
msgid "Contact forms"
msgstr "Контактные формы"
msgid "Flood control"
msgstr "Флуд контроль"
msgid "Not blocked"
msgstr "Не заблокирован"
# Russian translation of Honeypot (2.2.2)
# Copyright (c) 2025 by the Russian translation team
#
msgid ""
msgstr ""
"Project-Id-Version: Honeypot (2.2.2)\n"
"POT-Creation-Date: 2025-02-18 05:46+0000\n"
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=((((n%10)==1)&&((n%100)!=11))?(0):(((((n%10)>=2)&&((n%10)<=4))&&(((n%100)<10)||((n%100)>=20)))?(1):2));\n"
msgid "Preview"
msgstr "Предпросмотр"
msgid "Timestamp"
msgstr "Время"
msgid "Honeypot"
msgstr "Honeypot"
msgid "Expiration"
msgstr "Срок действия"
msgid "seconds"
msgstr "секунд"
msgid "Spam control"
msgstr "Защита от спама"
msgid "About"
msgstr "Информация"
msgid "Uses"
msgstr "Использование"
msgid "@name comment form"
msgstr "Форма комментариев @name"
msgid "Honeypot Configuration"
msgstr "Настройка Honeypot"
msgid "Protect all forms with Honeypot"
msgstr "Защитить с Honeypot все формы"
msgid "Honeypot element name"
msgstr "Имя элемента Honeypot"
msgid "Honeypot time limit"
msgstr "Период времени Honeypot"
msgid "Honeypot Enabled Forms"
msgstr "Формы с включенной защитой Honeypot"
msgid ""
"Check the boxes next to individual forms on which you'd like Honeypot "
"protection enabled."
msgstr ""
"Установите флажки рядом с отдельными "
"формами, для которых вы хотите "
"включить защиту Honeypot."
msgid "User Registration form"
msgstr "Форма регистрации пользователей"
msgid "Leave this field blank"
msgstr "Оставьте это поле пустым"
msgid ""
"There was a problem with your form submission. Please refresh the page "
"and try again."
msgstr ""
"Произошла ошибка с отправкой вашей "
"формы. Пожалуйста, обновите страницу и "
"попробуйте ещё раз."
msgid "Honeypot configuration"
msgstr "Настройка Honeypot"
msgid ""
"Configure Honeypot spam prevention and the forms on which Honeypot "
"will be used."
msgstr ""
"Настройте Honeypot спам защиту и формы, на "
"которых она будет использована."
msgid "Mitigates spam form submissions using the honeypot method."
msgstr ""
"Уменьшает количество спама через HTML "
"формы c помощью honeypot метода."
msgid "Bypass Honeypot protection"
msgstr "Обход защиты Honeypot"
msgid "Bypass Honeypot form protection."
msgstr "Обход защиты форм Honeypot."
msgid ""
"There was a problem with your form submission. Please wait @limit "
"seconds and try again."
msgstr ""
"Произошла ошибка с отправкой вашей "
"формы. Пожалуйста, подождите @limit сек. и "
"попробуйте ещё раз."
msgid "Log blocked form submissions"
msgstr ""
"Записывать в системный журнал "
"заблокированные запросы"
msgid "Log submissions that are blocked due to Honeypot protection."
msgstr ""
"Журнализирование передач, которые "
"заблокированы в связи с защитой Honeypot."
msgid "submission of a value in the honeypot field"
msgstr "заполнение поля honeypot"
msgid "submission of the form in less than minimum required time"
msgstr ""
"заполнение формы менее, чем за "
"минимальное требуемое время"
msgid "Blocked submission of %form due to @cause."
msgstr "Заблокирована отправка %form из-за @cause."
msgid "The element name cannot contain spaces or other special characters."
msgstr ""
"Имя элемента не может содержать "
"пробелы либо другие спец. символы. "
"Только английские буквы и цифры "
"разрешены."
# Russian translation of Linkit (7.0.8)
# Copyright (c) 2025 by the Russian translation team
#
msgid ""
msgstr ""
"Project-Id-Version: Linkit (7.0.8)\n"
"POT-Creation-Date: 2025-08-05 15:46+0000\n"
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=((((n%10)==1)&&((n%100)!=11))?(0):(((((n%10)>=2)&&((n%10)<=4))&&(((n%100)<10)||((n%100)>=20)))?(1):2));\n"
msgid "User interface"
msgstr "Интерфейс пользователя"
msgid "E-mail"
msgstr "E-mail"
msgid "Delete"
msgstr "Удалить"
msgid "Operations"
msgstr "Операции"
msgid "Content"
msgstr "Содержимое"
msgid "Description"
msgstr "Описание"
msgid "Yes"
msgstr "Да"
msgid "No"
msgstr "Нет"
msgid "File"
msgstr "Файл"
msgid "Edit"
msgstr "Редактировать"
msgid "None"
msgstr "Нет"
msgid "Weight"
msgstr "Вес"
msgid "Name"
msgstr "Название"
msgid "Taxonomy term"
msgstr "Термин таксономии"
msgid "Save"
msgstr "Сохранить"
msgid "Default"
msgstr "По умолчанию"
msgid "File extensions"
msgstr "Расширения файла"
msgid "User"
msgstr "Пользователь"
msgid "Email"
msgstr "Email"
msgid "System"
msgstr "Система"
msgid "Unlimited"
msgstr "Неограничено"
msgid "External"
msgstr "Внешний"
msgid "Save changes"
msgstr "Сохранить изменения"
msgid "Update profile"
msgstr "Обновить профиль"
msgid "Profile"
msgstr "Профиль"
msgid "Front page"
msgstr "Главная страница"
msgid "Available tokens"
msgstr "Доступные токены"
msgid "Limit"
msgstr "Предел"
msgid "Entity"
msgstr "Сущность"
msgid "Metadata"
msgstr "Метаданные"
msgid "Allowed file extensions"
msgstr "Допустимые расширения файлов"
msgid "Unpublished nodes"
msgstr "Материалы, снятые с публикации"
msgid "Edit profile"
msgstr "Редактировать профиль"
msgid "About"
msgstr "Информация"
msgid "Profile Name"
msgstr "Название профиля"
msgid "Delete profile"
msgstr "Удалить профиль"
msgid "Save and continue"
msgstr "Сохранить и продолжить"
msgid "Uses"
msgstr "Использование"
msgid "No results"
msgstr "Нет результатов"
msgid "Restrict to the selected roles"
msgstr "Ограничить для выбранных ролей"
msgid "Contact form"
msgstr "Контактная форма"
msgid "Image file settings"
msgstr "Настройки файлов изображений"
msgid "Canonical URL"
msgstr "Канонический URL"
msgid "Blocked users"
msgstr "Блокированный пользователь"
msgid "Saved %label configuration."
msgstr "Настройки %label сохранены."
msgid ""
"Separate extensions with a space or comma and do not include the "
"leading dot."
msgstr ""
"Введите расширения через пробел или "
"запятую. Не используйте точку перед "
"расширением."
msgid "Weight for @title"
msgstr "Вес @title"
msgid "Thumbnail image style"
msgstr "Стиль миниатюрных изображений"
msgid "Drupal link"
msgstr "Ссылка Drupal"
msgid "Start typing to find content."
msgstr ""
"Начните вводить название, чтобы найти "
"содержимое."
msgid "No content suggestions found. This URL will be used as is."
msgstr ""
"Предложения по содержанию не найдены. "
"Этот URL будет использоваться как есть."
# Russian translation of Mail System (8.x-4.5)
# Copyright (c) 2024 by the Russian translation team
#
msgid ""
msgstr ""
"Project-Id-Version: Mail System (8.x-4.5)\n"
"POT-Creation-Date: 2024-08-11 12:46+0000\n"
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=((((n%10)==1)&&((n%100)!=11))?(0):(((((n%10)>=2)&&((n%10)<=4))&&(((n%100)<10)||((n%100)>=20)))?(1):2));\n"
msgid "Remove"
msgstr "Удалить"
msgid "Default"
msgstr "По умолчанию"
msgid "Add"
msgstr "Добавить"
msgid "Mail"
msgstr "Почта"
msgid "All"
msgstr "Все"
msgid "Default settings"
msgstr "Настройки по умолчанию"
msgid "Module"
msgstr "Модуль"
msgid "Sender"
msgstr "Отправитель"
msgid "Current"
msgstr "Текущий"
msgid "Key"
msgstr "Ключ"
msgid "About"
msgstr "Информация"
msgid "Domain Theme"
msgstr "Тема Домена"
msgid "- Select -"
msgstr "- Выберите -"
msgid "Formatter"
msgstr "Форматер"
msgid "Uses"
msgstr "Использование"
msgid "Mail System"
msgstr "Почтовая система"
msgid "Administer Mail System"
msgstr "Управление почтовой системой"
msgid "- Default -"
msgstr "- По умолчанию -"
msgid "Theme to render the emails"
msgstr ""
"Тема для формирования почтовых "
"сообщений"
msgid "Configure the Mail System"
msgstr "Настройка почтовой системы"
msgid "List of modules"
msgstr "Список модулей"
msgid "Default Mail System"
msgstr "Почтовая система по умолчанию"
msgid "Module-specific configuration"
msgstr "Настройки для конкретного модуля"
msgid "Formatter plugin"
msgstr "Плагин форматера"
msgid "Sender plugin"
msgstr "Плагин отправки"
# Russian translation of Media Bulk Upload (3.0.4)
# Copyright (c) 2025 by the Russian translation team
#
msgid ""
msgstr ""
"Project-Id-Version: Media Bulk Upload (3.0.4)\n"
"POT-Creation-Date: 2025-06-10 03:46+0000\n"
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=((((n%10)==1)&&((n%100)!=11))?(0):(((((n%10)>=2)&&((n%10)<=4))&&(((n%100)<10)||((n%100)>=20)))?(1):2));\n"
msgid "Delete"
msgstr "Удалить"
msgid "Submit"
msgstr "Отправить"
msgid "List"
msgstr "Список"
msgid "Edit"
msgstr "Редактировать"
msgid "- None -"
msgstr "- Не указано -"
msgid "Label"
msgstr "Метка"
msgid "ID"
msgstr "ID"
msgid "Fields"
msgstr "Поля"
msgid "Media"
msgstr "Мультимедиа"
msgid "Are you sure you want to delete %name?"
msgstr "Вы уверены, что хотите удалить %name?"
msgid "File Upload"
msgstr "Загрузка файла"
msgid "Information"
msgstr "Информация"
msgid "Machine name"
msgstr "Машинное имя"
msgid "About"
msgstr "Информация"
msgid "Media Types"
msgstr "Типы медиа"
msgid "An error occurred while processing @operation with arguments : @args"
msgstr ""
"Возникла ошибка в процессе @operation с "
"аргументами: @args"
msgid "Add a new @entity_type."
msgstr "Добавить новый тип сущности @entity_type."
msgid "There is no @entity_type yet. @add_link"
msgstr ""
"Тип сущности \"@entity_type\" пока "
"отсутствует. @add_link"
msgid "No media types available. <a href=\":url\">Add media type</a>."
msgstr ""
"Нет доступных типов медиа. <a href=\":url\"> "
"Добавить тип медиа </a>."
# Russian translation of Media Entity Browser (3.0.0)
# Copyright (c) 2025 by the Russian translation team
#
msgid ""
msgstr ""
"Project-Id-Version: Media Entity Browser (3.0.0)\n"
"POT-Creation-Date: 2025-01-06 05:46+0000\n"
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=((((n%10)==1)&&((n%100)!=11))?(0):(((((n%10)>=2)&&((n%10)<=4))&&(((n%100)<10)||((n%100)>=20)))?(1):2));\n"
msgid "Language"
msgstr "Язык"
msgid "Reset"
msgstr "Сбросить"
msgid "Name"
msgstr "Название"
msgid "True"
msgstr "Истина"
msgid "Published"
msgstr "Опубликовано"
msgid ", "
msgstr ", "
msgid "Media"
msgstr "Мультимедиа"
msgid "Desc"
msgstr "По убыванию"
msgid "Provider"
msgstr "Поставщик"
msgid "Sort by"
msgstr "Сортировать по"
msgid "‹ Previous"
msgstr "‹ Предыдущий"
msgid "Next ›"
msgstr "Следующий ›"
msgid "Unpublished"
msgstr "Снято с публикации"
msgid "Apply"
msgstr "Применить"
msgid "Offset"
msgstr "Пропустить"
msgid "Newest first"
msgstr "Новые сначала"
msgid "Upload new image"
msgstr "Загрузить новое"
msgid "Media Browser"
msgstr "Медиабраузер"
msgid "Items per page"
msgstr "Элементов на страницу"
msgid "- All -"
msgstr "- Все -"
msgid "Publishing status"
msgstr "Статус публикации"
msgid "« First"
msgstr "« Первая"
msgid "Last »"
msgstr "Последняя »"
msgid "Media browser"
msgstr "Медиабраузер"
msgid "Asc"
msgstr "По возрастанию"
msgid "Master"
msgstr "Основной"
msgid "Media type"
msgstr "Тип медиа"
msgid "Select media"
msgstr "Выбор медиа"
msgid "Media name"
msgstr "Название медиа"
msgid "Media Entity Embed"
msgstr "Встраивание медиа-объекта"
msgid "Name (A-Z)"
msgstr "Имя (А-Я)"
msgid "Name (Z-A)"
msgstr "Имя (Я-А)"
# Russian translation of Media file delete (1.3.1)
# Copyright (c) 2024 by the Russian translation team
#
msgid ""
msgstr ""
"Project-Id-Version: Media file delete (1.3.1)\n"
"POT-Creation-Date: 2024-07-19 11:03+0000\n"
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=((((n%10)==1)&&((n%100)!=11))?(0):(((((n%10)>=2)&&((n%10)<=4))&&(((n%100)<10)||((n%100)>=20)))?(1):2));\n"
msgid "Delete any file"
msgstr "Удалять любые файлы"
# Russian translation of Menu Admin per Menu (8.x-1.7)
# Copyright (c) 2025 by the Russian translation team
#
msgid ""
msgstr ""
"Project-Id-Version: Menu Admin per Menu (8.x-1.7)\n"
"POT-Creation-Date: 2025-06-18 17:30+0000\n"
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=((((n%10)==1)&&((n%100)!=11))?(0):(((((n%10)>=2)&&((n%10)<=4))&&(((n%100)<10)||((n%100)>=20)))?(1):2));\n"
msgid "Administration"
msgstr "Администрирование"
msgid "List links"
msgstr "Список ссылок"
msgid "Add link"
msgstr "Добавить ссылку"
# Russian translation of Menu Per Role (8.x-1.8)
# Copyright (c) 2024 by the Russian translation team
#
msgid ""
msgstr ""
"Project-Id-Version: Menu Per Role (8.x-1.8)\n"
"POT-Creation-Date: 2024-09-22 02:10+0000\n"
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=((((n%10)==1)&&((n%100)!=11))?(0):(((((n%10)>=2)&&((n%10)<=4))&&(((n%100)<10)||((n%100)>=20)))?(1):2));\n"
msgid "Access control"
msgstr "Контроль доступа"
msgid "Always"
msgstr "Всегда"
msgid "Never"
msgstr "Никогда"
msgid "Configuration"
msgstr "Конфигурация"
msgid "About"
msgstr "Информация"
msgid "Menu Per Role"
msgstr "Меню по Роли"
msgid "Allows restricting access to menu items per role."
msgstr ""
"Позволяет разграничивать доступ к "
"пунктам меню относительно ролей."
msgid "Select what is shown when editing menu items"
msgstr ""
"Выберите что изображено при "
"редактировании элементов меню"
msgid "Hide and Show check boxes"
msgstr ""
"Управление на основе Прятать / "
"Отображать пункт меню"
msgid "Only Hide check boxes"
msgstr "Управление на основе скрытия"
msgid "Only Show check boxes"
msgstr "Управление на основе отображения"
msgid ""
"By default, both list of check boxes are shown when editing a menu "
"item (in the menu administration area or while editing a node.) This "
"option let you choose to only show the \"Show menu item only to "
"selected roles\" or \"Hide menu item from selected roles\". WARNING: "
"changing this option does not change the existing selection. This "
"means some selection will become invisible when you hide one of the "
"set of check boxes..."
msgstr ""
"По умолчанию, как перечень опций "
"управления показываются во время "
"редактировании пункта меню (в области "
"управления меню или при "
"редактировании материала.) Этот "
"параметр дает возможность скрывать "
"или отображать пункт меню для "
"определенных ролей. ПРЕДУПРЕЖДЕНИЕ: "
"изменение этого параметра не изменяет "
"существующий выбор. Это означает, что "
"некоторые выбранные ранее опции "
"станут невидимыми, когда вы "
"отключаете один из множества флажков "
"..."
# Russian translation of Metatag (2.1.1)
# Copyright (c) 2025 by the Russian translation team
#
msgid ""
msgstr ""
"Project-Id-Version: Metatag (2.1.1)\n"
"POT-Creation-Date: 2025-07-06 21:54+0000\n"
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=((((n%10)==1)&&((n%100)!=11))?(0):(((((n%10)>=2)&&((n%10)<=4))&&(((n%100)<10)||((n%100)>=20)))?(1):2));\n"
msgid "Title"
msgstr "Заголовок"
msgid "Status"
msgstr "Статус"
msgid "Delete"
msgstr "Удалить"
msgid "Submit"
msgstr "Отправить"
msgid "Operations"
msgstr "Операции"
msgid "Content"
msgstr "Содержимое"
msgid "Username"
msgstr "Имя пользователя"
msgid "Email address"
msgstr "E-mail адрес"
msgid "Group"
msgstr "Группа"
msgid "Type"
msgstr "Тип"
msgid "Author"
msgstr "Автор"
msgid "Subject"
msgstr "Тема"
msgid "Cancel"
msgstr "Отмена"
msgid "Description"
msgstr "Описание"
msgid "Language"
msgstr "Язык"
msgid "Audience"
msgstr "Аудитория"
msgid "Disabled"
msgstr "Отключено"
msgid "Tags"
msgstr "Теги"
msgid "Yes"
msgstr "Да"
msgid "No"
msgstr "Нет"
msgid "License"
msgstr "Лицензия"
msgid "Tag"
msgstr "Тег"
msgid "Edit"
msgstr "Редактировать"
msgid "Date"
msgstr "Дата"
msgid "- None -"
msgstr "- Не указано -"
msgid "Weight"
msgstr "Вес"
msgid "Link"
msgstr "Ссылка"
msgid "Image"
msgstr "Изображение"
msgid "Multiple"
msgstr "Множественная"
msgid "Settings"
msgstr "Настройки"
msgid "Name"
msgstr "Название"
msgid "Taxonomy term"
msgstr "Термин таксономии"
msgid "Label"
msgstr "Метка"
msgid "Add"
msgstr "Добавить"
msgid "View"
msgstr "Просмотр"
msgid "Format"
msgstr "Формат"
msgid "URL"
msgstr "URL"
msgid "Refresh"
msgstr "Обновить"
msgid "Region"
msgstr "Область"
msgid "Display"
msgstr "Отображение"
msgid "Keywords"
msgstr "Ключевые слова"
msgid "ID"
msgstr "ID"
msgid "User"
msgstr "Пользователь"
msgid "Content type"
msgstr "Тип материала"
msgid "Separator"
msgstr "Разделитель"
msgid "Active"
msgstr "Активно"
msgid "Page title"
msgstr "Заголовок страницы"
msgid "Site name"
msgstr "Название сайта"
msgid "Locale"
msgstr "Язык"
msgid "Page URL"
msgstr "URL страницы"
msgid "Fields"
msgstr "Поля"
msgid "Overridden"
msgstr "Переопределён"
msgid "Advanced"
msgstr "Расширенные"
msgid "Date Created"
msgstr "Дата создания"
msgid "Date Modified"
msgstr "Дата изменения"
msgid "Thumbnail"
msgstr "Миниатюра"
msgid "Medium"
msgstr "Средний"
msgid "Media"
msgstr "Мультимедиа"
msgid "Id"
msgstr "Id"
msgid "Color"
msgstr "Цвет"
msgid "First name"
msgstr "Имя"
msgid "Last name"
msgstr "Фамилия"
msgid "Image URL"
msgstr "URL изображения"
msgid "Arguments"
msgstr "Аргументы"
msgid "Expires"
msgstr "Истекает"
msgid "Property"
msgstr "Свойство"
msgid "Latitude"
msgstr "Широта"
msgid "Longitude"
msgstr "Долгота"
msgid "Fax number"
msgstr "Номер факса"
msgid "Phone number"
msgstr "Номер телефона"
msgid "Gender"
msgstr "Пол"
msgid "Department"
msgstr "Департамент"
msgid "Are you sure you want to delete %name?"
msgstr "Вы уверены, что хотите удалить %name?"
msgid "Facebook"
msgstr "Facebook"
msgid "Google"
msgstr "Google"
msgid "Source"
msgstr "Источник"
msgid "Front page"
msgstr "Главная страница"
msgid "Replacement patterns"
msgstr "Подстановочные шаблоны"
msgid "Revert"
msgstr "Вернуть"
msgid "See also"
msgstr "См. также"
msgid "Street address"
msgstr "Адрес"
msgid "Video width"
msgstr "Ширина видео"
msgid "Video height"
msgstr "Высота видео"
msgid "Locality"
msgstr "Местоположение"
msgid "Default value"
msgstr "Значение по умолчанию"
msgid "Select"
msgstr "Выбрать"
msgid "Publisher"
msgstr "Издатель"
msgid "Global"
msgstr "Глобальный"
msgid "Abstract"
msgstr "Абстрактный"
msgid "Yandex"
msgstr "Яндекс"
msgid "ISBN"
msgstr "ISBN"
msgid "Provided by"
msgstr "Предоставлено"
msgid "Generator"
msgstr "Генератор"
msgid "Identifier"
msgstr "Идентификатор"
msgid "About"
msgstr "Информация"
msgid "Zoom"
msgstr "Масштабировать"
msgid "Translate"
msgstr "Переводы"
msgid "Entity type"
msgstr "Тип сущности"
msgid "Rating"
msgstr "Рейтинг"
msgid "Creator"
msgstr "Автор"
msgid "Meta"
msgstr "Meta"
msgid "Metatags"
msgstr "Мета-теги"
msgid "Meta tags"
msgstr "Мета-теги"
msgid "Bundle"
msgstr "Набор"
msgid "Default icon"
msgstr "Иконка по умолчанию"
msgid "Image height"
msgstr "Высота изображения"
msgid "Image width"
msgstr "Ширина изображения"
msgid "Country name"
msgstr "Название страны"
msgid "Origin"
msgstr "принадлежность"
msgid "SEO"
msgstr "Поисковая оптимизация"
msgid "Name attribute"
msgstr "Атрибут Name"
msgid "Image type"
msgstr "Тип изображения"
msgid "Dublin Core"
msgstr "Дублинское Ядро"
msgid "Release date"
msgstr "Дата выхода"
msgid "Application name"
msgstr "Название приложения"
msgid "References"
msgstr "Ссылки"
msgid "Canonical URL"
msgstr "Канонический URL"
msgid "Book author"
msgstr "Автор книги"
msgid "Robots"
msgstr "Robots"
msgid "Site verification"
msgstr "Проверка сайта"
msgid "length"
msgstr "длина"
msgid "@argument title"
msgstr "@argument заголовок"
msgid "@argument input"
msgstr "@argument ввод"
msgid "Bing"
msgstr "Bing"
msgid "Date Available"
msgstr "Доступная дата"
msgid "Facebook App ID"
msgstr "ID приложения Facebook"
msgid "Document status"
msgstr "Статус документа"
msgid "Default shortcut icon"
msgstr "Значок по умолчанию"
msgid "Access Rights"
msgstr "Права доступа"
msgid "Video URL"
msgstr "URL-адрес видео"
msgid "Rights"
msgstr "Права на материал"
msgid "Contributor"
msgstr "Участник"
msgid "Image alternative text"
msgstr "Альтернативный текст изображения"
msgid "Cache control"
msgstr "Управление кэшем"
msgid "Facebook Application ID"
msgstr "ID приложения Facebook"
msgid "Theme Color"
msgstr "Цвет темы"
msgid "HTML element"
msgstr "HTML-элемент"
msgid "Use replacement tokens from the first row"
msgstr ""
"Использовать шаблон подстановки из "
"первой строки"
msgid "404 page not found"
msgstr "404 страница не найдена"
msgid "Shortlink URL"
msgstr "Короткая ссылка"
msgid "Add default meta tags"
msgstr "Добавить мета-теги по умолчанию"
msgid ""
"Provides search engines with specific directions for what to do when "
"this page is indexed."
msgstr ""
"Предоставляет поисковым системам "
"определенные указания, что делать, "
"когда эта страница индексируется."
msgid ""
"Describes the name and version number of the software or publishing "
"tool used to create the page."
msgstr ""
"Описывает название и номер версии "
"программного обеспечения или "
"публикующего инструмента "
"используемого для создания страницы."
msgid "Using defaults"
msgstr "Использовать по умолчанию"
msgid "Select the type of default meta tags you would like to add."
msgstr ""
"Выберите тип мета-тега по умолчанию, "
"который хотите добавить."
msgid "Pinterest"
msgstr "Pinterest"
msgid "List of @type values"
msgstr "Список значений @type"
msgid "Tokens for lists of @type values."
msgstr "Токены для списков значений @type."
msgid "Set Cookie"
msgstr "Установить cookie"
msgid "Video type"
msgstr "Тип видео"
msgid "Original source"
msgstr "Оригинальный источник"
msgid "Mobile Optimized"
msgstr ""
"Оптимизировано для мобильных "
"устройств"
msgid ""
"An image associated with this page, for use as a thumbnail in social "
"networks and other services."
msgstr ""
"Изображение ассоциирующееся с этой "
"страницей, для использования в "
"качестве иконки в социальных сетях и "
"других сервисах."
msgid "Metatag"
msgstr "Мета-тег"
msgid "Basic tags"
msgstr "Основные теги"
msgid "The name given to the resource."
msgstr "Имя, данное ресурсу."
msgid ""
"An entity primarily responsible for making the resource. Examples of a "
"Creator include a person, an organization, or a service. Typically, "
"the name of a Creator should be used to indicate the entity."
msgstr ""
"Субъект, в первую очередь "
"ответственный за создание ресурса. В "
"качестве создателя могут выступать "
"физическое лицо, организация или "
"сервис. Как правило, для обозначения "
"субъекта следует использовать "
"имя/название создателя."
msgid ""
"The topic of the resource. Typically, the subject will be represented "
"using keywords, key phrases, or classification codes. Recommended best "
"practice is to use a controlled vocabulary. To describe the spatial or "
"temporal topic of the resource, use the Coverage element."
msgstr ""
"Тема ресурса. Как правило, тема "
"указывается с помощью ключевых слов, "
"ключевых фраз или классификационных "
"кодов. Рекомендуется использовать "
"контролируемый словарь. Чтобы описать "
"пространственную или временную тему "
"ресурса, используйте элемент \"Охват\"."
msgid ""
"Information about rights held in and over the resource. Typically, "
"rights information includes a statement about various property rights "
"associated with the resource, including intellectual property rights."
msgstr ""
"Информация о правах, связанных с "
"сайтом и компанией. Как правило, она "
"включает в себя сведения о различных "
"правах собственности, связанных с "
"сайтом, в том числе правах "
"интеллектуальной собственности."
msgid "Facebook Admins"
msgstr "Администраторы Facebook"
msgid "Twitter card type"
msgstr "Тип карточки Twitter"
msgid "Site's Twitter account"
msgstr "Учётная запись сайта в Twitter"
msgid ""
"The @username for the website, which will be displayed in the Card's "
"footer; must include the @ symbol."
msgstr ""
"@username для сайта, которое будет "
"отображаться в нижней части карточки, "
"должно содержать символ @."
msgid "Creator's Twitter account"
msgstr "Аккаунт создателя в Twitter"
msgid ""
"The @username for the content creator / author for this page, "
"including the @ symbol."
msgstr ""
"@username создателя материала / автора "
"этой страницы, включая символ @."
msgid ""
"A description that concisely summarizes the content of the page, as "
"appropriate for presentation within a Tweet. Do not re-use the title "
"text as the description, or use this field to describe the general "
"services provided by the website. The string will be truncated, by "
"Twitter, at the word to 200 characters."
msgstr ""
"Описание, кратко излагающее "
"содержание страницы и подходящее для "
"твита. Не используйте в качестве "
"описания текст заголовка. Или "
"используйте это поле для описания "
"общих услуг, предоставляемых сайтом. "
"Твиттер ограничит длину строки до 200 "
"символов."
msgid "Media player URL"
msgstr "URL медиа-плеера"
msgid "Media player width"
msgstr "Ширина медиа-плеера"
msgid "Media player height"
msgstr "Высота медиа-плеера"
msgid "MP4 media stream URL"
msgstr "URL медиапотока MP4"
msgid "Audio type"
msgstr "Тип аудио"
msgid "Book Tags"
msgstr "ключевые слова для Книг"
msgid "Table Of Contents"
msgstr "Содержание"
msgid "Site's Twitter account ID"
msgstr "ID учётной записи сайта в Twitter"
msgid ""
"The numerical Twitter account ID for the website, which will be "
"displayed in the Card's footer."
msgstr ""
"Цифровой ID учётной записи Twitter для "
"веб-сайта, который будет отображаться "
"в нижней части карточки."
msgid "Creator's Twitter account ID"
msgstr "ID учётной записи Создателя в Twitter"
msgid ""
"The numerical Twitter account ID for the content creator / author for "
"this page."
msgstr ""
"Числовой ID учётной записи Twitter для "
"автора материала этой страницы."
msgid "The meta tags for this display"
msgstr "Мета-теги для данного отображения"
msgid "Configure Metatag defaults."
msgstr "Настройка мета-тегов по умолчанию"
msgid "Metatag: Twitter Cards"
msgstr "Metatag: Twitter карты"
msgid "Metatag: Views"
msgstr "Мета-тег: Представления"
msgid "No Referrer"
msgstr "Нет ссылки"
msgid ""
"Used to indicate the URL that broke the story, and can link to either "
"an internal URL or an external source. If the full URL is not known it "
"is acceptable to use a partial URL or just the domain name."
msgstr ""
"Используется для указания URL, который "
"послужил источником для материала. "
"Может быть ссылкой на любой "
"внутренний URL или внешний источник. "
"Если полный URL не известен, допустимо "
"указать частичный или просто имя "
"домена."
msgid "Administer meta tags"
msgstr "Управление параметрами мета-тега"
msgid "Revisit After"
msgstr "Пересмотреть после"
msgid "Configuration type"
msgstr "Тип конфигурации"
msgid "@language (original)"
msgstr "@language (оригинал)"
msgid "Successfully updated @language translation."
msgstr "Перевод @language успешно обновлен."
msgid "403 access denied"
msgstr "403 доступ запрещен"
msgid "Should replacement tokens be used from the first row"
msgstr ""
"Использовать ли токены замены из "
"первой строки"
msgid ""
"Details about intellectual property, such as copyright or trademarks; "
"does not automatically protect the site's content or intellectual "
"property."
msgstr ""
"Подробная информация об "
"интеллектуальной собственности, "
"такой как авторское право или "
"товарные знаки; автоматически не "
"защищает содержимое или "
"интеллектуальную собственность "
"сайта."
msgid "A brief URL, often created by a URL shortening service."
msgstr ""
"Короткий URL, часто создаётся с помощью "
"сервиса сокращения ссылок."
msgid "Postal/ZIP code"
msgstr "Почтовый код"
msgid "Referrer policy"
msgstr "Ссылка на оригинал"
msgid "Unsafe URL"
msgstr "Небезопасный URL"
msgid "Previous page URL"
msgstr "Ссылка на предыдущую страницу"
msgid "Next page URL"
msgstr "Ссылка на следующую страницу"
msgid "No Referrer When Downgrade"
msgstr "Нет ссылки на более раннюю версию"
msgid "Origin When Cross-Origin"
msgstr ""
"Оригинал при перекрёстном "
"происхождении"
msgid "A location's formal name."
msgstr "Официальное название местоположения."
msgid "ICBM"
msgstr "ICBM адрес"
msgid ""
"The following tokens are available. You may use Twig syntax in this "
"field."
msgstr ""
"Доступны следующие токены. Также в "
"этом поле можно использовать "
"синтаксис Twig."
msgid "Manage meta tags for all entities."
msgstr ""
"Управление мета-тегами для всех "
"сущностей."
msgid "Metatag settings"
msgstr "Настройки Metatag"
msgid "This field stores code meta tags."
msgstr ""
"В этом поле хранятся значения "
"мета-тегов."
msgid "Advanced meta tags form"
msgstr "Форма дополнительных мета-тегов"
msgid "Simple meta tags."
msgstr "Основные мета-теги."
msgid "Metatag defaults"
msgstr "Мета-теги по-умолчанию"
msgid "Created the %label Metatag defaults."
msgstr "Мета-тег \"%label\" создан."
msgid "Delete default meta tags"
msgstr "Удалить мета-теги по-умолчанию"
msgid "Revert default meta tags"
msgstr "Вернуть мета-теги по-умолчанию"
msgid "Shortlink"
msgstr "Короткая ссылка"
msgid "Inherits meta tags from: @inherits"
msgstr "Метатеги наследуются от: @inherits"
msgid "[site:url]"
msgstr "[site:url]"
msgid "[current-page:title] | [site:name]"
msgstr "[current-page:title] | [site:name]"
msgid "[node:title] | [site:name]"
msgstr "[node:title] | [site:name]"
msgid "[node:summary]"
msgstr "[node:summary]"
msgid "[term:name] | [site:name]"
msgstr "[term:name] | [site:name]"
msgid "[term:description]"
msgstr "[term:description]"
msgid "@label tokens."
msgstr "@label токены."
msgid "Geographical region"
msgstr "Географический регион"
msgid "Geographical place name"
msgstr "Географическое название"
msgid "Geographical position"
msgstr "Географическая позиция"
msgid ""
"If the top-level configuration is not specific enough, additional "
"default meta tag configurations can be added for a specific entity "
"type or entity bundle, e.g. for a specific content type."
msgstr ""
"Если конфигурация верхнего уровня "
"ещё не указана, можно добавить "
"дополнительные конфигурации "
"мета-тегов по умолчанию для "
"определённого типа сущности или "
"пакета сущностей, например, для "
"определённого типа материала."
msgid ""
"Meta tags can be further refined on a per-entity basis, e.g. for "
"individual nodes, by adding the \"Metatag\" field to that entity type "
"through its normal field settings pages."
msgstr ""
"Мета-теги могут быть дополнительно "
"уточнены для каждого объекта, "
"например, для отдельных материалов, "
"путём добавления поля «Мета-тег» к "
"этому типу объекта на странице "
"настроек полей."
msgid ""
"Configure global meta tag default values below. Meta tags may be left "
"as the default."
msgstr ""
"Настройте значения по умолчанию для "
"мета-тегов. Мета-теги могут быть "
"оставлены по умолчанию."
msgid ""
"Meta tag patterns are passed down from one level to the next unless "
"they are overridden. To view a summary of the individual meta tags and "
"the pattern for a specific configuration, click on its name below."
msgstr ""
"Шаблоны настроек метатегов будут "
"действовать и для дочерних элементов, "
"если они не были переопределены. Для "
"просмотра сводку настроек нажмите на "
"элементы ниже."
msgid "Metatags for @view : @display have been saved."
msgstr "Мета-теги для @view : @display сохранены."
msgid "Metatag settings for this view."
msgstr ""
"Настройки Metatag для этого "
"представления."
msgid ""
"A brief and concise summary of the page's content, preferably 150 "
"characters or less. Where as the description meta tag may be used by "
"search engines to display a snippet about the page in search results, "
"the abstract tag may be used to archive a summary about the page. This "
"meta tag is <em>no longer</em> supported by major search engines."
msgstr ""
"Метатег \"Abstract\" алогично метатегу "
"\"Description\" но рекомендуемая длина "
"строки равна 150 символов. Если метатег "
"\"Description\" используется поисковыми "
"системами в результатах выдачи, то "
"данный метатег может быть использован "
"для архивирования краткого "
"информации о странице. Данный метатег "
"не поддерживается основными "
"поисковыми системами"
msgid ""
"A comma-separated list of keywords about the page. This meta tag is "
"<em>no longer</em> supported by most search engines."
msgstr ""
"Список ключевых слов для страницы, "
"разделенных запятыми. Этот метатег не "
"поддерживают большинство поисковых "
"систем."
msgid ""
"The text to display in the title bar of a visitor's web browser when "
"they view this page. This meta tag may also be used as the title of "
"the page when a visitor bookmarks or favorites this page, or as the "
"page title in a search engine result. It is common to append "
"'[site:name]' to the end of this, so the site's name is automatically "
"added. It is recommended that the title is no greater than 55 - 65 "
"characters long, including spaces."
msgstr ""
"Данный текст будет использован в "
"строке заголовка браузера. Так же "
"может быть использован в качестве "
"заголовка страницы, когда "
"пользователь добавляет страницу в "
"избранное или как заголовок страницы "
"в результатах поисковой выдачи. "
"Обычно в конец строки добавляют "
"'[site:name]' поэтому имя сайта добавляется "
"автоматически. Рекомендуется, чтобы "
"длина заголовка не превышала 55–65 "
"символов, включая пробелы."
msgid "Schema.org Metatag is recommended"
msgstr "Рекомендуется модуль Schema.org Metatag"
msgid ""
"The <a href=\"@module\">Schema.org Metatag</a> module is highly "
"recommended to add <a href=\"@jsonld\">JSON-LD</a> -formatted <a "
"href=\"@schema\">schema.org</a> compatible data structures to the "
"site."
msgstr ""
"Модуль <a href=\"@module\">Schema.org Metatag</a> "
"настоятельно рекомендуется для "
"добавления поддержки <a "
"href=\"@jsonld\">JSON-LD</a> -форматированных <a "
"href=\"@schema\">schema.org</a> совместимых "
"структур данных для сайта."
msgid "Schema.org Metatag is installed"
msgstr "Schema.org Metatag установлен"
msgid "The <a href=\"@module\">Schema.org Metatag</a> module is installed."
msgstr ""
"Модуль <a href=\"@module\">Schema.org Metatag</a> "
"установлен."
msgid "URL for a version of this page in %langcode"
msgstr ""
"Адрес для версии этой страницы на "
"%langcode"
msgid "Hreflang per language"
msgstr "Hreflang для языка"
msgid ""
"This plugin will be cloned from these settings for each enabled "
"language."
msgstr ""
"Этот плагин будет клонирован на "
"основе этих настроек для каждого "
"включенного языка."
msgid "Set cookie"
msgstr "Установить cookie"
msgid ""
"<a href='https://www.metatags.org/meta_http_equiv_set_cookie'>Sets a "
"cookie</a> on the visitor's browser. Can be in either NAME=VALUE "
"format, or a more verbose format including the path and expiration "
"date; see the link for full details on the syntax."
msgstr ""
"<a "
"href='https://www.metatags.org/meta_http_equiv_set_cookie'>Сохраняет "
"cookie</a> в браузере посетителя. Может "
"быть в формате NAME=VALUE или в более "
"развёрнутом формате, включая путь и "
"срока действия. Полную информацию о "
"синтаксисе см. по ссылке."
msgid "Enables metatags for custom routes"
msgstr ""
"Включает метатеги для "
"пользовательских адресов"
msgid "Add meta tag for custom route"
msgstr ""
"Добавить метатег для произвольного "
"пути"
msgid "Add custom metatag"
msgstr "Добавить метатег"
msgid "The path must begin with /"
msgstr "Путь должен начинаться с /"
msgid "The admin routes should not have metatags."
msgstr ""
"Страницы администратора не должны "
"иметь метатегов."
msgid "There are already metatags created for this route."
msgstr "Для этого пути уже созданы метатеги."
msgid "The path does not exist as an internal Drupal route."
msgstr ""
"Такого внутреннего пути Drupal не "
"существует."
msgid "Created metatags for the path: @url. Internal route: @route."
msgstr ""
"Созданы метатеги для пути: @url. "
"Внутренний адрес: @route."
msgid "The metatags could not be created for the path: @url."
msgstr ""
"Не удалось создать метатеги для пути: "
"@url."
msgid "Dublin Core: Date Modified"
msgstr "Dublin Core: Дата изменения"
msgid "Dublin Core: Provenance"
msgstr "Dublin Core: Происхождение"
msgid "Dublin Core: Replaces"
msgstr "Dublin Core: Заменяет"
msgid "Dublin Core: Requires"
msgstr "Dublin Core: Требует"
msgid "Dublin Core: Rights Holder"
msgstr "Dublin Core: Правообладатель"
msgid "Dublin Core: Table Of Contents"
msgstr "Dublin Core: Оглавление"
msgid "Dublin Core: Date Valid"
msgstr "Dublin Core: Действительно до"
msgid "Book Author"
msgstr "Автор книги"
msgid "Book ISBN"
msgstr "ISBN книги"
msgid "Book Release Date"
msgstr "Дата выхода книги"
msgid ""
"Links a book to an author's Facebook profile, should be either URLs to "
"the author's profile page or their Facebook profile IDs."
msgstr ""
"Связывает книгу с профилем автора в "
"Facebook. Должно быть либо адресом "
"страницы профиля, либо ID профиля в "
"Facebook."
msgid "The Book's ISBN"
msgstr "ISBN книги"
msgid "The date the book was released."
msgstr "Дата когда книга была выпущена."
msgid "Book tag(s)"
msgstr "Тег(и) книги"
msgid ""
"The URL of an image which should represent the content. The image must "
"be at least 200 x 200 pixels in size; 600 x 316 pixels is a "
"recommended minimum size, and for best results use an image least 1200 "
"x 630 pixels in size. Supports PNG, JPEG and GIF formats. Should not "
"be used if og:image:url is used. Note: if multiple images are added "
"many services (e.g. Facebook) will default to the largest image, not "
"specifically the first one."
msgstr ""
"URL изображения, которое иллюстрирует "
"страницу. Размер изображения должен "
"быть не менее 200 x 200 пикселей; "
"рекомендуемый минимальный размер — 600 "
"x 316 пикселей, а для достижения "
"наилучших результатов используйте "
"изображение размером не менее 1200 x 630 "
"пикселей. Поддерживает форматы PNG, JPEG и "
"GIF. Не следует использовать, если уже "
"используется og:image:url. Примечание: если "
"добавлено несколько изображений, "
"многие сервисы (например, Facebook) по "
"умолчанию будут использовать самое "
"большое изображение, а не первое."
msgid "Open Graph Product: Price amount"
msgstr "Open Graph Product: Цена"
msgid "Open Graph Product: Price currency"
msgstr "Open Graph Product: Валюта"
msgid "Product price amount"
msgstr "Цена товара"
msgid "The price amount of the product."
msgstr "Цена товара."
msgid "Product price currency"
msgstr "Валюта"
msgid "The price currency of the product."
msgstr "Валюта, в которой указана цена товара."
msgid "Provides support for Pinterest's custom meta tags."
msgstr ""
"Обеспечивает поддержку метатегов "
"Pinterest."
msgid "Pinterest: Description"
msgstr "Pinterest: Описание"
msgid "Pinterest: ID"
msgstr "Pinterest: ID"
msgid ""
"A set of meta tags used to control how the site's content is consumed "
"by <a href='https://pinterest.com/'>Pinterest</a>."
msgstr ""
"Набор метатегов, используемых для "
"управления тем, как материалы сайта "
"воспринимаются <a "
"href='https://pinterest.com/'>Pinterest</a>."
msgid "The URL of media which should represent the content."
msgstr ""
"URL изображения которое должно "
"иллюстрировать материал."
msgid ""
"Do not show hovering Save or Search buttons, generated by the "
"Pinterest browser extensions."
msgstr ""
"Не показывать кнопки Сохранить или "
"Поиск при наведении курсора, которые "
"создаются расширениями Pinterest для "
"браузера."
msgid "Do not allow Pinterest visual search to happen from this page."
msgstr ""
"Запретить визуальный поиск Pinterest на "
"этой странице."
msgid "The URL which should represent the content."
msgstr "URL материала."
msgid ""
"The custom admin pages for managing Views meta tags at "
"/admin/config/search/metatag/views have been disabled for now, "
"hopefully they'll be back in a future release. Until then, the meta "
"tags can be managed directly on each individual view via the \"Meta "
"tags\" section."
msgstr ""
"Страницы администратора для "
"управления метатегами представлений "
"по адресу /admin/config/search/metatag/views на данный "
"момент отключены. Надеемся, что они "
"вернутся в будущих версиях. До тех пор "
"метатегами можно управлять "
"непосредственно в каждом отдельном "
"представлении в разделе \"Метатеги\"."
msgid ""
"To view a list of displays with meta tags set up, click on a view "
"name. To view a summary of meta tags configuration for a particular "
"display, click on the display name. If you need to set meta tags for a "
"specific view, choose Add views meta tags. Reverting the meta tags "
"removes the specific configuration and falls back to defaults."
msgstr ""
"Чтобы просмотреть список отображений "
"с настроенными метатегами, щёлкните "
"на название представления. Чтобы "
"просмотреть сводную информацию о "
"конфигурации метатегов для "
"конкретного отображения, нажмите на "
"его название. Если вам нужно настроить "
"метатеги для конкретного "
"представления, выберите \"Добавить "
"метатеги представления\". При откате "
"метатегов конфигурация удаляется и "
"используются настройки по умолчанию."
msgid "Do you want to revert meta tags for @view_name : @display_name?"
msgstr ""
"Вы желаете вернуть мета-теги для @view_name "
": @display_name?"
msgid ""
"You are about to revert the custom meta tags for the %display_name "
"display on the %view_name view. This action cannot be undone."
msgstr ""
"Вы собираетесь удалить метатеги для "
"отображения %display_name в представлении "
"%view_name. Это действие нельзя отменить."
msgid "Reverted meta tags for @view_name : @display_name"
msgstr ""
"Возвращенные мета-теги для @view_name : "
"@display_name"
msgid ""
"Any relative or protocol-relative URLs will be converted to absolute "
"URLs."
msgstr ""
"Любые относительные URL будут "
"преобразованы в абсолютные адреса."
msgid "Configure the Metatag module"
msgstr "Настроить модуль мета-тегов"
msgid "Metatag groups that apply to each entity type"
msgstr ""
"Группы метатегов, применимые к "
"каждому типу сущности"
msgid ""
"A URL to a manifest.json file that describes the application. The <a "
"href='https://developer.mozilla.org/en-US/docs/Web/Manifest'>JSON-based "
"manifest</a> provides developers with a centralized place to put "
"metadata associated with a web application."
msgstr ""
"URL файла manifest.json, описывающего "
"приложение. <a "
"href='https://developer.mozilla.org/en-US/docs/Web/Manifest'>JSON "
"манифест</a> представляет собой "
"централизованное место, где "
"разработчики могут хранить "
"метаданные, связанных с "
"веб-приложением."
msgid "Open Graph: Image alt"
msgstr ""
"Open Graph: Альтернативный текст "
"изображения"
msgid "Image 'alt'"
msgstr "Альтернативный текст изображения"
msgid ""
"A description of what is in the image, not a caption. If the page "
"specifies an og:image it should specify og:image:alt."
msgstr ""
"Описание того, что изображено на "
"картинке, а не заголовок. Если на "
"странице указано og:image, то должно быть "
"указано и og:image:alt."
msgid "Provides metatag support for Page Manager variants."
msgstr ""
"Обеспечивает поддержку метатегов для "
"вариантов Page Manager."
msgid "Entity type / Group Mapping"
msgstr "Типы сущностей / Группа соответствий"
msgid ""
"Identify which metatag groups should be available on which entity type "
"/ bundle combination. Unselected groups will not appear on the "
"configuration form for that entity type, reducing the size of the form "
"and increasing performance. If no groups are selected for a type, all "
"groups will appear."
msgstr ""
"Укажите, какие группы метатегов "
"должны быть доступны для каждой "
"комбинации сущность(entity_type) / тип "
"сущности(bundle) . Не выбранные группы не "
"будут отображаться в форме настроек "
"для этой сущности, что уменьшит размер "
"формы и повысит производительность. "
"Если для сущности/типа сущности не "
"выбрано ни одной группы, то будут "
"показаны все."
msgid ""
"This meta tag communicates with Google. There are currently two "
"directives supported: 'nositelinkssearchbox' to not to show the "
"sitelinks search box, and 'notranslate' to ask Google not to offer a "
"translation of the page. Both options may be added, just separate them "
"with a comma. See <a "
"href='https://support.google.com/webmasters/answer/79812?hl=en'>meta "
"tags that Google understands</a> for further details."
msgstr ""
"Этот метатег для Google. В настоящее "
"время поддерживаются две директивы: "
"'nositelinkssearchbox' - не отображать поле "
"поиска по ссылкам и 'notranslate' - просит "
"Google не предлагать переводить "
"страницу. Можно добавить обе "
"директивы, просто разделив их запятой. "
"Дополнительные сведения см. в разделе "
"<a href='@docs'>метатеги, которые понимает "
"Google</a>."
msgid "Site validation: Pocket"
msgstr "Проверка сайта: Pocket"
msgid ""
"Warning: disabling the Global default metatag will prevent any "
"metatags from being used."
msgstr ""
"Предупреждение: отключение "
"глобального метатега по умолчанию "
"приведёт к невозможности "
"использования любых метатегов."
msgid ""
"Set the maximum size of an image preview for this page in a search "
"results."
msgstr ""
"Задайте максимальный размер "
"изображения в результатах поиска для "
"этой страницы."
msgid "None - no image preview is to be shown."
msgstr ""
"Нет - изображение отображаться не "
"будет."
msgid "Standard - a default image preview may be shown."
msgstr ""
"Стандартное - может быть показано "
"изображение по умолчанию."
msgid ""
"Large - a larger image preview, up to the width of the viewport, may "
"be shown."
msgstr ""
"Большое - может быть показано "
"изображение увеличенное до ширины "
"страницы (максимум)."
msgid "Label / Description"
msgstr "Название / Описание"
msgid "index - Allow search engines to index this page (assumed)."
msgstr ""
"index - Попросить поисковые системы "
"индексировать эту страницу (по "
"умолчанию)."
msgid "follow - Allow search engines to follow links on this page (assumed)."
msgstr ""
"follow - Просит поисковые системы "
"переходить по ссылкам на этой "
"странице (по умолчанию)."
msgid "noindex - Prevents search engines from indexing this page."
msgstr ""
"noindex - Просит поисковые системы не "
"индексировать эту страницу."
msgid "nofollow - Prevents search engines from following links on this page."
msgstr ""
"nofollow - Просит поисковые системы не "
"переходить по ссылкам на этой "
"странице."
msgid ""
"noarchive - Prevents cached copies of this page from appearing in "
"search results."
msgstr ""
"noarchive - Просит не показывать "
"кэшированные копий этой страницы в "
"результатах поиска."
msgid ""
"nosnippet - Prevents descriptions from appearing in search results, "
"and prevents page caching."
msgstr ""
"nosnippet - Просит не показывать описание "
"этой страницы в результатах поиска, а "
"также просит не кэшировать."
msgid ""
"noimageindex - Prevent search engines from indexing images on this "
"page."
msgstr ""
"noimageindex - Просит поисковые системы не "
"индексировать изображения на этой "
"странице."
msgid ""
"notranslate - Prevent search engines from offering to translate this "
"page in search results."
msgstr ""
"notranslate - Просит поисковые системы не "
"предлагать перевести эту страницу в "
"результатах поиска."
msgid "Not enabled while in maintenance mode"
msgstr "Не включено в режиме обслуживания"
msgid ""
"Please note that while the site is in maintenance mode none of the "
"usual meta tags will be output."
msgstr ""
"Обратите внимание, что пока сайт "
"находится в режиме обслуживания, ни "
"один из обычных метатегов не "
"выводится."
msgid "Metatag plugins"
msgstr "Плагины метатегов"
msgid "Overview of plugins used in metatag."
msgstr ""
"Обзор плагинов, используемых в "
"метатеге."
msgid "Metatag: Favicons"
msgstr "Metatag: Favicons"
msgid ""
"Provides an absolute URL to a specially formatted version of the "
"current page designed for 'feature phones', mobile phones that do not "
"support modern browser standards. See the <a "
"href='https://developers.google.com/webmasters/mobile-sites/mobile-seo/other-devices?hl=en#feature_phones'>official "
"Google Mobile SEO Guide</a> for details on how the page should be "
"formatted."
msgstr ""
"Предоставляет абсолютный URL "
"специально отформатированной версии "
"текущей страницы, предназначенной для "
"\"простых телефонов\" - мобильных "
"устройств, которые не поддерживают "
"современные стандарты браузеров. "
"Подробнее о том, как должна быть "
"отформатирована страница, см. в <a "
"href='https://developers.google.com/webmasters/mobile-sites/mobile-seo/other-devices?hl=ru#feature_phones'>официальном "
"руководстве Google по мобильному SEO</a>."
msgid "Open Graph: Video duration"
msgstr "Open Graph: Продолжительность видео"
msgid ""
"The date this content will expire, with an optional time value. Needs "
"to be in <a href='https://en.wikipedia.org/wiki/ISO_8601'>ISO 8601</a> "
"format."
msgstr ""
"Дата истечения срока этого материала, "
"может содержать время. Должно быть в "
"формате <a href='https://ru.wikipedia.org/wiki/ISO_8601'>ISO "
"8601</a>."
msgid ""
"The date this content was last modified, with an optional time value. "
"Needs to be in <a href='https://en.wikipedia.org/wiki/ISO_8601'>ISO "
"8601</a> format."
msgstr ""
"Дата последнего изменения, "
"дополнительно может содержать время. "
"Значение должно быть в формате <a "
"href='https://ru.wikipedia.org/wiki/ISO_8601'>ISO 8601</a>."
msgid ""
"The date this content was published on, with an optional time value. "
"Needs to be in <a href='https://en.wikipedia.org/wiki/ISO_8601'>ISO "
"8601</a> format."
msgstr ""
"Дата публикации, дополнительно может "
"содержать время. Значение должно быть "
"в формате <a href='https://ru.wikipedia.org/wiki/ISO_8601'>ISO "
"8601</a>."
msgid ""
"The date this content was last modified, with an optional time value. "
"Needs to be in <a href='https://en.wikipedia.org/wiki/ISO_8601'>ISO "
"8601</a> format. Can be the same as the 'Article modification date' "
"tag."
msgstr ""
"Дата последнего изменения "
"содержимого, дополнительно может "
"содержать время. Значение должно быть "
"в формате <a href='https://r.wikipedia.org/wiki/ISO_8601'>ISO "
"8601</a>. Может совпадать со значением "
"тега \"Дата изменения статьи\"."
msgid ""
"Preferred page location or URL to help eliminate duplicate content for "
"search engines, e.g., <em>https://www.imdb.com/title/tt0117500/</em>."
msgstr ""
"Предпочтительный адрес страницы, "
"используется поисковыми системами "
"для устранения дублей страниц. "
"Например: <em>https://www.imdb.com/title/tt0117500/</em>."
msgid "Site validation: Zoom"
msgstr "Проверка сайта: Масштабирование"
msgid "All meta tags in the \"@group\" group."
msgstr "Все метатеги в группе \"@group\"."
msgid ""
"Used to control whether a browser caches a specific page locally. Not "
"commonly used. Should be used in conjunction with the Pragma meta tag."
msgstr ""
"Используется для управления "
"локальным кэшированием определённой "
"страницы в браузере. Применяется "
"нечасто. Следует использовать в "
"сочетании с метатегом Pragma."
msgid "Used for paginated content by providing URL with rel='next' link."
msgstr ""
"Используется для постраничного "
"контента путём указания URL со ссылкой "
"rel=\"next\"."
msgid ""
"Used to control whether a browser caches a specific page locally. Not "
"commonly used. Should be used in conjunction with the Cache-Control "
"meta tag."
msgstr ""
"Используется для управления "
"локальным кэшированием конкретной "
"страницы в браузере. Применяется "
"нечасто. Следует использовать в "
"сочетании с метатегом Cache-Control."
msgid "Used for paginated content by providing URL with rel='prev' link."
msgstr ""
"Используется для многостраничных "
"разделов путём указания адреса со "
"ссылкой rel=\"prev\"."
msgid ""
"Tell search engines when to index the page again. Very few search "
"engines support this tag, it is more useful to use an <a "
"href='https://www.drupal.org/project/xmlsitemap'>XML Sitemap</a> file."
msgstr ""
"Сообщите поисковым системам, когда "
"нужно снова проиндексировать "
"страницу. Очень немногие поисковые "
"системы поддерживают этот тег, "
"поэтому полезнее использовать файл <a "
"href='https://www.drupal.org/project/xmlsitemap'>XML Sitemap</a>."
msgid "Place field in sidebar"
msgstr "Разместить поле в боковой панели"
msgid ""
"Provides the fifteen <a "
"href=\"https://dublincore.org/documents/dces/\">Dublin Core Metadata "
"Element Set 1.1</a> meta tags from the <a "
"href=\"https://dublincore.org/\">Dublin Core Metadata Institute</a>."
msgstr ""
"Предоставляет пятнадцать метатегов <a "
"href=\"https://dublincore.org/documents/dces/\">Dublin Core Metadata "
"Element Set 1.1</a> от <a href=\"https://dublincore.org/\">Dublin "
"Core Metadata Institute</a>."
msgid ""
"Provides forty additional meta tags from the <a "
"href=\"https://dublincore.org/\">Dublin Core Metadata Institute</a>."
msgstr ""
"Предоставляет сорок дополнительных "
"метатегов от <a href=\"https://dublincore.org/\">Dublin "
"Core Metadata Institute</a>."
msgid "Metatag: Hreflang"
msgstr "Метатег: Hreflang"
msgid ""
"A semi-colon -separated string that must contain the 'polling-uri=' "
"value with the full URL to a <a "
"href='https://go.microsoft.com/fwlink/p/?LinkID=314019'>Badge Schema "
"XML file</a>. May also contain 'frequency=' value set to either 30, "
"60, 360, 720 or 1440 (default) which specifies (in minutes) how often "
"the URL should be polled."
msgstr ""
"Разделенная точкой с запятой строка, "
"которая должна содержать значение "
"'polling-uri=' с полным URL-адресом для <a "
"href='https://go.microsoft.com/fwlink/p/?LinkID=314019'>XML-файла "
"схемы значков</a>. Также может "
"содержать значение 'frequency=' со "
"значением 30, 60, 360, 720 или 1440 (по "
"умолчанию), которое указывает (в "
"минутах), как часто следует "
"запрашивать URL."
msgid ""
"The secure URL (HTTPS) of an image which should represent the content. "
"The image must be at least 200 x 200 pixels in size; 600 x 316 pixels "
"is a recommended minimum size, and for best results use an image least "
"1200 x 630 pixels in size. Supports PNG, JPEG and GIF formats."
msgstr ""
"Безопасный адрес (HTTPS) изображения, "
"которое иллюстрирует материал. Размер "
"изображения должен быть не менее 200 x 200 "
"пикселей; рекомендуемый минимальный "
"размер — 600 x 316 пикселей, а для "
"достижения наилучших результатов "
"используйте изображение размером не "
"менее 1200 x 630 пикселей. Поддерживаются "
"форматы PNG, JPEG и GIF."
msgid "The secure URL (HTTPS) of an video which should represent the content."
msgstr ""
"Безопасный адрес (HTTPS) видео, которое "
"иллюстрирует материал."
msgid "Metatag: Page Manager"
msgstr "Метатег: Менеджер страниц"
msgid "If checked, the field will be placed in the sidebar on entity forms."
msgstr ""
"Если включено, поле будет размещено на "
"боковой панели в формах "
"редактирования сущностей."
msgid "Use sidebar: Yes"
msgstr "Использовать боковую панель: Да"
msgid "Use sidebar: No"
msgstr "Использовать боковую панель: Нет"
msgid ""
"A brief and concise summary of the page's content that is a maximum of "
"160 characters in length. The description meta tag may be used by "
"search engines to display a snippet about the page in search results."
msgstr ""
"Краткое описание содержимого "
"страницы, длиной не более 160 символов. "
"Данный метатег может быть использован "
"поисковыми системами в качестве "
"краткого описания страницы в "
"результатах поисковой выдачи."
msgid ""
"Control when the browser's internal cache of the current page should "
"expire. The date must to be an <a "
"href='https://www.csgnetwork.com/timerfc1123calc.html'>RFC-1123</a>-compliant "
"date string that is represented in Greenwich Mean Time (GMT), e.g. "
"'Thu, 01 Sep 2016 00:12:56 GMT'. Set to '0' to stop the page being "
"cached entirely."
msgstr ""
"Контролируйте, когда должен истекать "
"срок хранения внутреннего кэша "
"текущей страницы в браузере. Дата "
"должна быть строкой, соответствующей "
"стандарту <a "
"href='https://www.csgnetwork.com/timerfc1123calc.html'>RFC-1123</a>, "
"содержащей среднее время по Гринвичу "
"(GMT). Например: \"Thu, 01 Sep 2016 00:12:56 GMT\". "
"Задайте \"0\", чтобы полностью отключить "
"кэширование страницы."
msgid ""
"Any URLs which start with \"http://\" will be converted to "
"\"https://\"."
msgstr ""
"Все адреса, начинающиеся с \"http://\", "
"будут преобразованы в \"https://\"."
msgid ""
"The number of seconds to wait before refreshing the page. May also "
"force redirect to another page using the format '5; "
"url=https://example.com/', which would be triggered after five "
"seconds."
msgstr ""
"Количество секунд ожидания перед "
"обновлением страницы. Может быть "
"также использовано для "
"принудительного перенаправления на "
"другую страницу, например: '5; "
"url=https://example.com/' - сработает через пять "
"секунд."
msgid ""
"The sites's caches will need to be rebuild to ensure Metatag works as "
"intended."
msgstr ""
"Кэш сайта необходимо будет "
"перестроить, чтобы метатеги работали "
"должным образом."
msgid "Tag words"
msgstr "Слова для тегов"
msgid ""
"The secure URL to an audio file that complements this object. All "
"'http://' URLs will automatically be converted to 'https://'."
msgstr ""
"Безопасный URL аудиофайла, "
"дополняющего этот объект. Все адреса с "
"протоколом 'http://' будут автоматически "
"преобразованы в 'https://'."
msgid ""
"The MIME type of the audio file. Examples include 'application/mp3' "
"for an MP3 file."
msgstr ""
"Тип MIME аудиофайла. Например: 'application/mp3' "
"для файла MP3."
msgid "Tokens related to Metatags."
msgstr "Токены, относящиеся к метатегам."
msgid "Metatag values for the current page."
msgstr ""
"Значения метатегов для текущей "
"страницы."
msgid "Metatags (Hidden field for JSON support)"
msgstr ""
"Мета-теги (скрытое поле для поддержки "
"JSON)"
msgid "Metatag Extended Permissions"
msgstr "Расширенные права доступа к метатегам"
msgid ""
"A color in hexadecimal format, e.g. '#0000ff' for blue; must include "
"the '#' symbol. Used by some browsers to control the background color "
"of the toolbar, the color used with an icon, etc."
msgstr ""
"Цвет в шестнадцатеричном формате, "
"например, '#0000ff' для синего цвета; "
"должен начинаться с '#'. Используется в "
"некоторых браузерах для цвета фона "
"панели инструментов, цвета значка и т. "
"д."
msgid ""
"The <a href='https://ogp.me/'>Open Graph meta tags</a> are used to "
"control how Facebook, Pinterest, LinkedIn and other social networking "
"sites interpret the site's content.<br><br>The Facebook <a "
"href='https://developers.facebook.com/tools/debug/'>Sharing "
"Debugger</a> lets you preview how your content will look when it's "
"shared to Facebook and debug any issues with your Open Graph tags."
msgstr ""
"<a href='https://ogp.me/'>Метатеги Open Graph</a> "
"используются для управления тем, как "
"Facebook, Pinterest, LinkedIn и другие социальные "
"сети интерпретируют материалы сайта. "
"<br><br><a "
"href='https://developers.facebook.com/tools/debug/'>Отладчик "
"Facebook</a> позволяет просмотреть, как "
"будет выглядеть ваш материал при "
"публикации в Facebook, и устранить любые "
"проблемы с тегами Open Graph."
msgid ""
"These <a href='https://ogp.me/'>Open Graph meta tags</a> are for "
"describing products.<br><br>The Facebook <a "
"href='https://developers.facebook.com/tools/debug/'>Sharing "
"Debugger</a> lets you preview how your content will look when it's "
"shared to Facebook and debug any issues with your Open Graph tags."
msgstr ""
"Эти <a href='https://ogp.me/'>метатеги Open Graph</a> "
"предназначены для описания товаров. "
"<br><br><a "
"href='https://developers.facebook.com/tools/debug/'>Отладчик "
"Facebook</a> позволяет просмотреть, как "
"будет выглядеть ваш материал при "
"публикации в Facebook, и устранить любые "
"проблемы с тегами Open Graph."
msgid ""
"The URL to a unique image representing the content of the page. Do not "
"use a generic image such as your website logo, author photo, or other "
"image that spans multiple pages. Images larger than 120x120px will be "
"resized and cropped square based on longest dimension. Images smaller "
"than 60x60px will not be shown. If the 'type' is set to Photo then the "
"image must be at least 280x150px."
msgstr ""
"URL уникального изображения, "
"иллюстрирующего содержимое страницы. "
"Не используйте общие изображения, "
"такие как логотип сайта, фотография "
"автора или изображение, которое "
"занимает несколько страниц. "
"Изображения размером более 120x120 "
"пикселей будут уменьшены и обрезаны "
"до квадрата. Изображения размером "
"менее 60x60 пикселей не будут "
"отображаться. Если для параметра "
"\"тип\" установлено значение \"Фото\", то "
"изображение должно быть не менее 280x150 "
"пикселей."
msgid ""
"The full URL for an MP4 video (h.264) or audio (AAC) stream, takes "
"precedence over the other media player field."
msgstr ""
"Полный URL видео MP4 (h.264) или аудио (AAC). "
"Имеет приоритет над другими потоками "
"медиаплеера."
msgid "Site validation: Facebook"
msgstr "Проверка сайта: Facebook"
msgid "Configure the meta tags below."
msgstr "Настройте мета-теги ниже."
msgid ""
"Use tokens to avoid redundant meta data and search engine "
"penalization. For example, a 'keyword' value of \"example\" will be "
"shown on all content using this configuration, whereas using the "
"[node:field_keywords] automatically inserts the \"keywords\" values "
"from the current entity (node, term, etc)."
msgstr ""
"Используйте токены, чтобы избежать "
"избыточных метаданных и пессимизации "
"от поисковых систем. Например, в теге "
"'ключевые слова' значение \"пример\" "
"будет отображаться во всём контенте с "
"использованием этой конфигурации, "
"тогда как использование [node:field_keywords] "
"автоматически вставляет значения "
"\"ключевых слов\" из текущей сущности "
"(материал, термин и т. д.)."
msgid ""
"To use tokens to image fields, the image field on that entity bundle "
"(content type, term, etc) must have the \"Token\" display settings "
"enabled, the image field must not be hidden, and it must be set to "
"output as an image, e.g. using the \"Thumbnail\" field formatter. It "
"is also recommended to use an appropriate image style that resizes the "
"image rather than output the original image; see individual meta tag "
"descriptions for size recommendations."
msgstr ""
"Чтобы использовать изображения как "
"токены, в соответствующем подтипе "
"сущности (типе материала, термине и т. "
"д.) должно быть включено отображение "
"\"Token\", поле изображения в нём не должно "
"быть скрыто и должно быть настроено "
"для вывода в виде изображения, "
"например, как \"Миниатюра\". "
"Рекомендуется использовать "
"подходящий стиль изображения, который "
"изменяет размер изображения, а не "
"выводит исходное изображение. "
"Рекомендации по размеру см. в описании "
"метатегов."
msgid ""
"This will be able to extract the URL from an image field if the field "
"is configured properly."
msgstr ""
"Это позволит извлечь адрес из поля с "
"изображением, если оно настроено "
"правильно."
msgid ""
"Used to rate content for audience appropriateness. This tag has little "
"known influence on search engine rankings, but can be used by "
"browsers, browser extensions, and apps. The <a "
"href='https://www.metatags.org/meta_name_rating'>most common "
"options</a> are general, mature, restricted, 14 years, safe for kids. "
"If you follow the <a "
"href='https://www.rtalabel.org/index.php?content=howto'>RTA "
"Documentation</a> you should enter RTA-5042-1996-1400-1577-RTA"
msgstr ""
"Используется для того, чтобы оценить "
"подходящую аудиторию для страницы. "
"Этот тег мало влияет на рейтинг в "
"поисковых системах, но может "
"использоваться браузерами, "
"расширениями браузера и другими "
"приложениями. <a "
"href='https://www.metatags.org/meta_name_rating'>Наиболее "
"распространенные варианты</a>: общий, "
"для взрослых, с ограничением, 14 лет, "
"безопасный для детей. Если вы следуете "
"<a "
"href='http://www.rtalabel.org/index.php?content=howto'>документации "
"по RTA</a>, вам стоит ввести "
"RTA-5042-1996-1400-1577-RTA"
msgid "@label of @type"
msgstr "@label типа @type"
msgid "@label of @type @entity-type-label"
msgstr "@label типа @type @entity-type-label"
msgid "This plugin will be cloned from these settings for each custom tag."
msgstr ""
"Этот плагин будет клонирован на "
"основе этих настроек для каждого тега."
msgid "Place field in collapsed details container"
msgstr "Поместить поле в свернутый контейнер"
msgid "Trim method for trimmable tags."
msgstr "Метод обрезки для обрезаемых тегов."
msgid "Tag-specific maximum length"
msgstr ""
"Максимальная длина для конкретного "
"тега"
msgid "Tag maximum length in characters"
msgstr "Максимальная длина тега в символах"
msgid ""
"Adds individual permissions for each meta tag, allowing for "
"fine-grained access to the meta tags. Note: this may lead to "
"performance issues on the permissions admin page, please see the "
"included README.txt file for details."
msgstr ""
"Добавляет отдельные разрешения для "
"каждого метатега, обеспечивая "
"настраиваемый доступ к метатегам. "
"Примечание: это может привести к "
"проблемам с производительностью на "
"странице разрешений. Пожалуйста, "
"ознакомьтесь с прилагаемым файлом "
"README.txt для получения подробной "
"информации."
msgid "Mask icon color"
msgstr "Цвет значка маски"
msgid ""
"Color attribute for SVG (mask) icon in hexadecimal format, e.g. "
"'#0000ff'. Setting it will break HTML validation. If not set macOS "
"Safari ignores the Mask Icon entirely, making the Icon: SVG completely "
"useless."
msgstr ""
"Атрибут цвета для значка SVG (маски) в "
"шестнадцатеричном формате, например: "
"'#0000ff'. Если его не установить, это "
"чревато ошибками проверки HTML. Если его "
"не установить, macOS Safari проигнорирует "
"значок маски полностью, что делает "
"значок SVG совершенно бесполезным."
msgid "Mask icon (SVG)"
msgstr "Значок маски (SVG)"
msgid "Open Graph Product: Product condition"
msgstr "Open Graph Product: Состояние товара"
msgid "Open Graph Product: Retailer Item ID"
msgstr "Open Graph Product: ID товара у продавца"
msgid "The availability of the product."
msgstr "Доступность товара."
msgid "Product condition"
msgstr "Состояние товара"
msgid "The condition of the product."
msgstr "Состояние товара."
msgid "Retailer Item ID"
msgstr ""
"Идентификатор товара розничного "
"продавца"
msgid "The ID of the product as provided by the retailer."
msgstr ""
"ID продукта, предоставленный "
"продавцом."
msgid ""
"Empty update script to clear the site's caches so the new token "
"replacement functionality will work."
msgstr ""
"Пустой скрипт обновления для очистки "
"кэша сайта, чтобы новый функционал "
"замены токенов заработал."
msgid "Edit default meta tags for @path"
msgstr ""
"Редактировать метатеги по умолчанию "
"для @path"
msgid "Metatag Trimming Options"
msgstr "Варианты обрезки метатегов"
msgid ""
"Many Meta-Tags can be trimmed on a specific length for search engine "
"optimization.<br/>If the value is set to '0' or left empty, the whole "
"Metatag will be untrimmed."
msgstr ""
"Многие метатеги могут быть обрезаны "
"до определённой длины для оптимизации "
"под поисковые системы.<br/> Задайте '0' "
"или оставьте пустым, чтобы не обрезать "
"метатег."
msgid "Meta Tags:"
msgstr "Метатеги:"
msgid "Trim the Meta Tag after the word on the given value"
msgstr "Обрезать метатег после слова"
msgid "Trim the Meta Tag on the given value"
msgstr ""
"Обрезать метатег по заданному "
"значению"
msgid "Trim the Meta Tag before the word on the given value"
msgstr "Обрезать метатег перед словом"
msgid "Wrap the meta tags in a collapsed details container."
msgstr ""
"Обернуть метатеги в раскрывающийся "
"контейнер"
msgid ""
"If checked, the contents of the field will be placed inside a "
"collapsed details container."
msgstr ""
"Если включено, содержимое поля будет "
"помещено в свернутый контейнер."
msgid "Use details container: Yes"
msgstr ""
"Использовать раскрывающийся "
"контейнер: да"
msgid "Use details container: No"
msgstr ""
"Использовать раскрывающийся "
"контейнер: нет"
msgid ""
"Geo-spatial information in 'latitude; longitude' format, e.g. "
"'50.167958; -97.133185'; <a "
"href='https://en.wikipedia.org/wiki/Geographic_coordinate_system' "
"aria-label='see Wikipedia for details on the geographic coordinate "
"system'>see Wikipedia for details</a>."
msgstr ""
"Геопространственная информация в "
"формате 'широта; долгота', например "
"'50.167958; -97.133185'; <a "
"href=\"https://ru.wikipedia.org/wiki/Географические_координаты\" "
"aria-label=\"Подробнее о географической "
"системе координат читайте в "
"Википедии\">подробнее см. в "
"Википедии</a>."
msgid ""
"Geo-spatial information in 'latitude, longitude' format, e.g. "
"'50.167958, -97.133185'; <a "
"href='https://en.wikipedia.org/wiki/ICBM_address' aria-label='see "
"Wikipedia for details on ICBM addresses'>see Wikipedia for "
"details</a>."
msgstr ""
"Геопространственная информация в "
"формате 'широта, долгота', например "
"'50.167958, -97.133185'; <a "
"href=\"https://ru.wikipedia.org/wiki/Географические_координаты\" "
"aria-label=\"Подробнее о географической "
"системе координат читайте в "
"Википедии\">подробнее см. в "
"Википедии</a>."
msgid "Add max height value"
msgstr "Добавить максимальную высоту"
msgid "Route / Path"
msgstr "Маршрут / Путь"
msgid ""
"Enter the route (path) for this new configuration, starting with a "
"leading slash.<br />Note: this must already exist as a path in Drupal."
msgstr ""
"Введите маршрут (путь) для этой новой "
"конфигурации, начиная с дроби.<br "
"/>Примечание: этот путь должен "
"существовать в Drupal."
msgid "Site validation: SIWECOS"
msgstr "Проверка сайта: SIWECOS"
msgid "Google Site Verification"
msgstr "Проверка сайта Google"
msgid "Metatag widget options"
msgstr "Параметры виджета Metatag"
msgid ""
"Various options for the field widget used on entity forms, e.g. on "
"content type forms."
msgstr ""
"Различные варианты виджета поля, "
"используемого в формах сущностей, "
"например, в формах типов материала."
msgid "Scroll maximum height"
msgstr "Максимальная высота прокрутки"
msgid "eg 500px or 8rem"
msgstr "например, 500px или 8rem"
msgid ""
"To enable scrolling please enter a value and its units, e.g. 500px, "
"8rem, etc. Removing this value will remove the scroll."
msgstr ""
"Чтобы включить прокрутку, введите "
"значение, например: 500px, 8rem и т. д. Если "
"удалить это значение, прокрутка будет "
"отключена."
msgid "Define the author of a page."
msgstr "Задайте автора страницы."
msgid ""
"The <a href=\"@module\">Token OR module</a> is suggested for when the "
"basic content tokens are not flexible enough, e.g. to make a meta tag "
"show the contents of one field if it is filled in or another if the "
"first one is empty."
msgstr ""
"Модуль <a href=\"@module\">Token OR</a> "
"рекомендуется использовать, когда "
"базовые токены материала не "
"обеспечивают достаточную гибкость, "
"например, чтобы метатег отображал "
"содержимое одного поля, если оно "
"заполнено, или другого, если первое "
"поле пустое."
msgid "Href per language"
msgstr "Href для каждого языка"
msgid ""
"This was expected to be an array but it is not: \n"
"%value"
msgstr ""
"Ожидалось, что это будет массив, но это "
"не так: \r\n"
"%value"
msgid ""
"This could not be unserialized: \n"
"%value"
msgstr ""
"Это не может быть несериализовано: \r\n"
"%value"
msgid "Metatag Field Diff"
msgstr "Различие в поле метатега"
msgid "Use Maxlength module to force these limits?"
msgstr ""
"Использовать модуль Maxlength для "
"введения этих ограничений?"
msgid "Install the Maxlength module to enable this option."
msgstr ""
"Установите модуль Maxlength, чтобы "
"включить эту опцию."
msgid "Intended workflow"
msgstr "Предполагаемый рабочий процесс"
msgid ""
"Allows assigning meta tags to be used on custom routes, equivalent to "
"custom paths."
msgstr ""
"Позволяет задавать метатеги для "
"пользовательских путей, аналогичных "
"пользовательским адресам."
msgid ""
"Indicate to search engines and other page scrapers whether or not "
"links should be followed. See <a "
"href='https://w3c.github.io/webappsec/specs/referrer-policy/'>the W3C "
"specifications</a> for further details. Note: this serves the same "
"purpose as the HTTP header by the same name."
msgstr ""
"Указывает поисковым системам и другим "
"программам, следует ли переходить по "
"ссылкам на странице. См. <a "
"href='https://w3c.github.io/webappsec/specs/referrer-policy/'>спецификации "
"W3C</a> для получения более подробной "
"информации. Примечание: этот параметр "
"служит той же цели, что и одноимённый "
"HTTP-заголовок."
msgid "Max Snippet"
msgstr "Максимальный фрагмент"
msgid ""
"Use a number character as a textual snippet for this search result. "
"\"0\" equals \"nosnippet\". \"-1\" will let the search engine decide "
"the most effective length."
msgstr ""
"Использовать указанное количество "
"символов в качестве текстового "
"фрагмента, отображаемого в "
"результатах поиска. \"0\" означает \"без "
"фрагмента\". \"-1\" - позволить поисковой "
"системе самой выбрать наиболее "
"эффективную длину."
msgid ""
"Use a maximum of number seconds as a video snippet for videos on this "
"page in search results. \"0\" will use a static a image. \"-1\" means "
"there is no limit."
msgstr ""
"Максимальное количество секунд в "
"качестве фрагмента видео на этой "
"странице в результатах поиска. \"0\" - "
"использовать статичное изображение. "
"\"-1\" означает отсутствие ограничений."
msgid "Unavailable after date"
msgstr "Недоступно после даты"
msgid "Do not show this page in search results after the specified date"
msgstr ""
"Не показывать эту страницу в "
"результатах поиска после указанной "
"даты"
msgid ""
"There were no overridden Metatag records that needed to be updated to "
"store the data using JSON."
msgstr ""
"Не найдено переопределённых записей "
"метатегов, которые нужно было бы "
"обновить для хранения данных в "
"формате JSON."
msgid ""
"Processed @processed of @total updating Metatag records with the "
"Publisher or Name meta tags."
msgstr ""
"Обработано @processed из @total записей с "
"метатегами Publisher или Name."
msgid "There were no Metatag records to update."
msgstr "Нет записей метатегов для обновления."
msgid "Removed meta tags from the @config Metatag configuration."
msgstr "Удалены метатеги из конфигурации @config."
msgid "Metatag: Google Plus is not enabled, nothing to do."
msgstr ""
"Metatag: Google Plus отключен, ничего не нужно "
"делать."
msgid "Metatag: Google Plus has been uninstalled."
msgstr "Metatag: Google Plus удален."
msgid ""
"Corrected the Twitter Card \"type\" value in the @config Metatag "
"configuration."
msgstr ""
"Исправлено значение \"тип\" Карточки "
"Twitter в конфигурации @config."
msgid "The computed meta tags for the entity."
msgstr "Вычисленные метатеги для сущности."
msgid "Deprecated module, do not use. Will be removed in 3.0.0."
msgstr ""
"Устаревший модуль, не использовать. "
"Будет удален в версии 3.0.0."
msgid ""
"Notes:<ul><li>no other fields are required for a Summary "
"card</li><li>Media player card requires the 'title', 'description', "
"'media player URL', 'media player width', 'media player height' and "
"'image' fields,</li><li>Summary Card with Large Image card requires "
"the 'Summary' field and the 'image' field,</li><li>App Card requires "
"the 'iPhone app ID' field, the 'iPad app ID' field and the 'Google "
"Play app ID' field,</li></ul>"
msgstr ""
"Примечания:<ul><li>другие поля для "
"Сводной карточки не требуются</li><li>для "
"Карточки плеера требуются поля "
"\"заголовок\", \"описание\", \"URL "
"медиаплеера\", \"ширина медиаплеера\", "
"\"высота медиаплеера\" и "
"\"изображение\",</li><li>для Сводной "
"карточки с большим изображением "
"требуются поля \"сводка\" и "
"\"изображение\",</li><li>для Карточки "
"приложения требуются поля \"ID "
"приложения iPhone\", \"ID приложения iPad\" и "
"\"ID приложения Google Play\",</li></ul>"
msgid "Separator used with multiple values"
msgstr ""
"Разделитель, используемый для "
"нескольких значений"
msgid ""
"Controls the separator used when a meta tag allows multiple values. "
"Multiple characters can be used together, it does not have to be one "
"single character long. Defaults to \":default\"."
msgstr ""
"Задаёт разделитель, который "
"используется, когда метатег допускает "
"несколько значений. Разделитель может "
"состоять из нескольких символов, он не "
"обязательно должен быть в один символ "
"длиной. По умолчанию используется "
"\":default\"."
msgid "Meta tags (computed)"
msgstr "Метатеги (вычисляемые)"
msgid "Computed meta tags"
msgstr "Вычисляемые метатеги"
msgid ""
"Multiple values may be used, separated by `:delimiter`. Note: Tokens "
"that return multiple values will be handled automatically."
msgstr ""
"Может использоваться несколько "
"значений, разделенных `:delimiter`. "
"Примечание: токены, возвращающие "
"несколько значений, будут "
"обрабатываться автоматически."
msgid ""
"The full URL for loading a media player, specifically an iframe for an "
"embedded video rather than the URL to a page that contains a player. "
"Required when using the Player Card type."
msgstr ""
"Полный URL-адрес для загрузки "
"медиаплеера, например, iframe для "
"встроенного видео, а не URL-адрес "
"страницы, содержащей плеер. Требуется "
"при использовании типа Карточка "
"плеера."
msgid ""
"The height of the media player iframe, in pixels. Required when using "
"the Player Card type."
msgstr ""
"Высота iframe медиаплеера в пикселях. "
"Требуется при использовании типа "
"Карточка плеера."
msgid ""
"The width of the media player iframe, in pixels. Required when using "
"the Player Card type."
msgstr ""
"Ширина iframe медиаплеера в пикселях. "
"Требуется при использовании типа "
"Карточка плеера."
msgid ""
"This will be truncated to a maximum of %max characters after any "
"tokens are processed."
msgstr ""
"После обработки любых токенов будет "
"урезано максимум до %max символов."
msgid ""
"Because of how tokens are processed in meta tags, use of the Maxlength "
"module may not provide an accurate representation of the actual "
"current length of each meta tag, so it may cause more problem than it "
"is worth."
msgstr ""
"Из-за особенностей обработки токенов "
"в метатегах использование модуля "
"Maxlength может не давать точного "
"представления о фактической длине "
"каждого метатега, из-за чего может "
"быть больше проблем, чем пользы."
msgid "This module provides support to define and manage custom meta tags."
msgstr ""
"Этот модуль предоставляет функционал "
"для создания и настройки "
"пользовательских метатегов."
msgid "Configure Custom tags below."
msgstr "Настройте теги ниже."
msgid "Metatag: Custom Tags"
msgstr "Метатег: Пользовательские теги"
msgid "Add Custom tag"
msgstr "Добавить тег"
msgid "Configure Custom tags."
msgstr "Настроить пользовательские теги."
msgid "Administer Custom tags"
msgstr "Управление пользовательскими тегами"
msgid "Control the main settings pages and modify custom tags."
msgstr ""
"Управляйте основными страницами "
"настроек и изменяйте "
"пользовательские теги."
msgid "Delete Custom tag"
msgstr "Удалить тег"
msgid "Element of the html tag. e.g. meta, link, etc."
msgstr "Элемент HTML-тега. Например, meta, link и т.д."
msgid ""
"The attribute this tag uses for the name. e.g. name, property, "
"http-equiv, itemprop, rel, etc."
msgstr ""
"Атрибут, который этот тег использует "
"для имени. Например, name, property, http-equiv, "
"itemprop, rel и т.д."
msgid "The value of the html name attribute. e.g. content, href, etc."
msgstr ""
"Значение атрибута name в html. Например, "
"content, href и т.д."
msgid "Specify the name of the custom tag."
msgstr "Укажите название тега."
msgid "Specify the description of the Custom tag."
msgstr "Укажите описание тега."
msgid "Select the HTML element of the Custom tag."
msgstr "Выберите HTML элемент для тега."
msgid "Created %label Custom tag."
msgstr "Создан тег %label."
msgid "Updated %label Custom tag."
msgstr "Обновлён тег %label."
msgid "Edit Custom tag @label"
msgstr "Редактировать тег @label"
msgid ""
"These custom tags are designed to use the custom purpose on the "
"website."
msgstr ""
"Эти теги предназначены для "
"использования на сайте в различных "
"целях."
msgid ""
"Meta tag configuration, stored as either a serialized array or a "
"JSON-encoded string."
msgstr ""
"Конфигурация метатега в виде "
"сериализованного массива или JSON."
# Russian translation of Mobile Detect (4.0.0)
# Copyright (c) 2025 by the Russian translation team
#
msgid ""
msgstr ""
"Project-Id-Version: Mobile Detect (4.0.0)\n"
"POT-Creation-Date: 2025-05-18 21:42+0000\n"
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=((((n%10)==1)&&((n%100)!=11))?(0):(((((n%10)>=2)&&((n%10)<=4))&&(((n%100)<10)||((n%100)>=20)))?(1):2));\n"
msgid "Phone"
msgstr "Телефон"
msgid "Experimental"
msgstr "Экспериментальный"
msgid "Desktop"
msgstr "Десктоп"
msgid "Tablet"
msgstr "Планшет"
# Russian translation of Module Filter (5.0.4)
# Copyright (c) 2025 by the Russian translation team
#
msgid ""
msgstr ""
"Project-Id-Version: Module Filter (5.0.4)\n"
"POT-Creation-Date: 2025-06-23 19:46+0000\n"
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=((((n%10)==1)&&((n%100)!=11))?(0):(((((n%10)>=2)&&((n%10)<=4))&&(((n%100)<10)||((n%100)>=20)))?(1):2));\n"
msgid "Description"
msgstr "Описание"
msgid "Disabled"
msgstr "Отключено"
msgid "Enabled"
msgstr "Включено"
msgid "Administration"
msgstr "Администрирование"
msgid "Name"
msgstr "Название"
msgid "All"
msgstr "Все"
msgid "Update available"
msgstr "Доступно обновление"
msgid "Filters"
msgstr "Фильтры"
msgid "Extend"
msgstr "Расширения"
msgid "Enabled filters"
msgstr "Включённые фильтры"
msgid "Permissions"
msgstr "Права доступа"
msgid "Installed"
msgstr "Установлено"
msgid "Security update"
msgstr "Обновление безопасности"
msgid "Unavailable"
msgstr "Недоступно"
msgid "Unsupported"
msgstr "Не поддерживается"
msgid "Module filter"
msgstr "Фильтр модулей"
msgid "Filter the modules list."
msgstr "Фильтрует список модулей."
msgid "No results"
msgstr "Нет результатов"
msgid "All modules"
msgstr "Все модули"
msgid "Filter modules"
msgstr "Фильтр модулей"
msgid "Administer Module Filter"
msgstr "Управление фильтром модулей"
msgid "Configure how Module Filter performs."
msgstr "Настройте работу фильтра модулей."
msgid "No modules added within the last week."
msgstr ""
"Нет модулей, добавленных за последнюю "
"неделю."
msgid "@enabled of @total"
msgstr "@enabled из @total"
msgid "Version: @module-version"
msgstr "Версия: @module-version"
msgid "Requires: @module-list"
msgstr "Требует: @module-list"
msgid "Required by: @module-list"
msgstr "Требуется для: @module-list"
msgid "Recently enabled"
msgstr "Недавно включённые"
msgid "Newly available"
msgstr "Недавно добавленные"
msgid "No modules installed or uninstalled within the last week."
msgstr ""
"Модули не устанавливались и не "
"удалялись за последнюю неделю."
msgid "Settings for the Module Filter module."
msgstr "Настройки модуля Module Filter."
msgid "Filter by project"
msgstr "Фильтровать по проекту"
msgid "Filter by module name or description"
msgstr ""
"Фильтровать по названию или описанию "
"модуля"
msgid "Filter by module name, description or machine name"
msgstr ""
"Фильтровать по названию, описанию или "
"машинному имени модуля"
msgid "Filter by module or permission"
msgstr ""
"Фильтровать по модулю или по праву "
"доступа"
# Russian translation of Optional End Date (8.x-1.4)
# Copyright (c) 2024 by the Russian translation team
#
msgid ""
msgstr ""
"Project-Id-Version: Optional End Date (8.x-1.4)\n"
"POT-Creation-Date: 2024-09-13 07:46+0000\n"
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=((((n%10)==1)&&((n%100)!=11))?(0):(((((n%10)>=2)&&((n%10)<=4))&&(((n%100)<10)||((n%100)>=20)))?(1):2));\n"
msgid "Fields"
msgstr "Поля"
msgid "End date"
msgstr "Дата окончания"
msgid "Date range settings"
msgstr "Настройки диапазона даты"
# Russian translation of Paragraphs (8.x-1.19)
# Copyright (c) 2025 by the Russian translation team
#
msgid ""
msgstr ""
"Project-Id-Version: Paragraphs (8.x-1.19)\n"
"POT-Creation-Date: 2025-07-06 15:10+0000\n"
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=((((n%10)==1)&&((n%100)!=11))?(0):(((((n%10)>=2)&&((n%10)<=4))&&(((n%100)<10)||((n%100)>=20)))?(1):2));\n"
msgid "Images"
msgstr "Изображения"
msgid "Delete"
msgstr "Удалить"
msgid "Operations"
msgstr "Операции"
msgid "Type"
msgstr "Тип"
msgid "Closed"
msgstr "Закрыто"
msgid "List"
msgstr "Список"
msgid "Cancel"
msgstr "Отмена"
msgid "Remove"
msgstr "Удалить"
msgid "Description"
msgstr "Описание"
msgid "Language"
msgstr "Язык"
msgid "Enabled"
msgstr "Включено"
msgid "Action"
msgstr "Действие"
msgid "Edit"
msgstr "Редактировать"
msgid "None"
msgstr "Нет"
msgid "Weight"
msgstr "Вес"
msgid "Multiple"
msgstr "Множественная"
msgid "Label"
msgstr "Метка"
msgid "Preview"
msgstr "Предпросмотр"
msgid "Summary"
msgstr "Сводка"
msgid "Open"
msgstr "Открыть"
msgid "Icon"
msgstr "Иконка"
msgid "View"
msgstr "Просмотр"
msgid "Text"
msgstr "Текст"
msgid "ID"
msgstr "ID"
msgid "User"
msgstr "Пользователь"
msgid "All"
msgstr "Все"
msgid "Published"
msgstr "Опубликовано"
msgid "Revisions"
msgstr "Редакции"
msgid "Warning"
msgstr "Предупреждение"
msgid "Authored by"
msgstr "Автор"
msgid "Authored on"
msgstr "Создан в"
msgid "French"
msgstr "Французский"
msgid "Select list"
msgstr "Список выбора"
msgid "Revert"
msgstr "Вернуть"
msgid "Buttons"
msgstr "Кнопки"
msgid "Convert"
msgstr "Преобразовать"
msgid "Revision"
msgstr "Редакция"
msgid "Duplicate"
msgstr "Дубликат"
msgid "Changed"
msgstr "Изменение"
msgid "Revision of %title from %date"
msgstr "Редакция %title от %date"
msgid "Unpublished"
msgstr "Снято с публикации"
msgid "Plugins"
msgstr "Плагины"
msgid "Language code"
msgstr "Код языка"
msgid "Restore"
msgstr "Восстановить"
msgid "German"
msgstr "Немецкий"
msgid "Machine name"
msgstr "Машинное имя"
msgid "Paragraph"
msgstr "Параграф"
msgid "About"
msgstr "Информация"
msgid "Add @type"
msgstr "Добавить @type"
msgid "Behavior settings"
msgstr "Настройки поведения"
msgid "Collapse all"
msgstr "Cвернуть все"
msgid "Default icon"
msgstr "Иконка по умолчанию"
msgid "Uses"
msgstr "Использование"
msgid "Parent ID"
msgstr "ID родителя"
msgid "Title: @title"
msgstr "Заголовок: @title"
msgid "Copy of the revision from %date."
msgstr "Копия редакции от %date."
msgid "Current revision"
msgstr "Текущая редакция"
msgid "Revision log message"
msgstr "Сообщение в журнал о редакции"
msgid "Collapse"
msgstr "Свернуть"
msgid "all languages"
msgstr "все языки"
msgid "Weight for row @number"
msgstr "Вес строки @number"
msgid "Paragraph field"
msgstr "Поле параграфа"
msgid "Modal form"
msgstr "Модальная форма"
msgid "@name field is required."
msgstr "Поле \"@name\" обязательно для заполнения."
msgid "Paragraphs"
msgstr "Параграфы"
msgid "Default translation"
msgstr "Перевод по умолчанию"
msgid "Revision user"
msgstr "Пользователь ревизии"
msgid "Save and manage fields"
msgstr "Сохранить и перейти к настройке полей"
msgid "The time that the current revision was created."
msgstr "Время создания текущей редакции"
msgid "The user ID of the author of the current revision."
msgstr ""
"Идентификатор пользователя, который "
"является автором текущей редакции."
msgid "Editorial"
msgstr "В редактировании"
msgid "Paragraph type"
msgstr "Тип параграфа"
msgid ""
"Label to appear as title on the button as \"Add new [title]\", this "
"label is translatable"
msgstr ""
"Метка, появляющаяся в качестве "
"заголовка кнопки \"Добавить новый "
"[заголовок]\". Это значение переводимо."
msgid "The log entry explaining the changes in this revision."
msgstr ""
"Запись в журнале, объясняющая "
"изменения в этой редакции."
msgid "Dropdown button"
msgstr "Выпадающая кнопка"
msgid "Title in its plural form."
msgstr "Заголовок во множественном числе."
msgid "%type_name: View content"
msgstr "%type_name: Просмотр материалов"
msgid "%type_name: Create content"
msgstr "%type_name: Создание материалов"
msgid "%type_name: Edit content"
msgstr "%type_name: Редактирование материалов"
msgid "%type_name: Delete content"
msgstr "%type_name: Удаление материалов"
msgid "Paragraphs types"
msgstr "Типы параграфов"
msgid "Administer Paragraphs types"
msgstr "Управление типами параграфов"
msgid "Allow to define the existing Paragraphs types and their Fields"
msgstr ""
"Разрешить настраивать существующие "
"типы параграфов и их поля"
msgid "Paragraphs type config"
msgstr "Настройка типов параграфов"
msgid "Paragraphs Type Permissions"
msgstr "Разрешения типа параграфа"
msgid "The paragraphs entity language code."
msgstr "Язык параграфов."
msgid "Paragraphs type"
msgstr "Тип параграфа"
msgid "Label for the Paragraphs type."
msgstr "Название типа параграфа."
msgid "Saved the %label Paragraphs type."
msgstr "Тип параграфа \"%label\" сохранён."
msgid "Edit mode"
msgstr "Режим редактирования"
msgid "Form display mode"
msgstr "Режим отображения формы"
msgid "Plural title: @title_plural"
msgstr ""
"Заголовок во множественном числе: "
"@title_plural"
msgid "Edit mode: @edit_mode"
msgstr "Режим редактирования: @edit_mode"
msgid "Add mode: @add_mode"
msgstr "Режим добавления: @add_mode"
msgid "Form display mode: @form_display_mode"
msgstr "Режим отображения формы: @form_display_mode"
msgid "Confirm removal"
msgstr "Подтверждение удаления"
msgid "Paragraph types"
msgstr "Типы параграфов"
msgid "Weight for type @type"
msgstr "Вес для типа @type"
msgid "The time that the Paragraph was created."
msgstr "Время создания параграфа."
msgid "Paragraph Title"
msgstr "Заголовок параграфа"
msgid "Plural Paragraph Title"
msgstr ""
"Заголовок параграфа во множественном "
"числе"
msgid "The form display mode to use when rendering the paragraph form."
msgstr ""
"Режим отображения формы, используемый "
"при редактировании параграфа."
msgid "A flag indicating whether this is the default translation."
msgstr ""
"Флаг, указывающий, является ли этот "
"перевод - переводом по умолчанию."
msgid ""
"Revisions allow you to track differences between multiple versions of "
"your content, and revert to older versions."
msgstr ""
"Редакции позволяют отслеживать "
"отличия между несколькими версиями "
"материалов и возвращаться к старым "
"версиям."
msgid "@label (@type)"
msgstr "@label (@type)"
msgid "Basic HTML"
msgstr "Базовый HTML"
msgid "You are not allowed to edit this @title."
msgstr ""
"У вас нет прав, чтобы редактировать "
"этот @title."
msgid "You are not allowed to remove this @title."
msgstr "У вас нет прав, чтобы удалить этот @title."
msgid "You are not allowed to edit or remove this @title."
msgstr ""
"У вас нет прав, чтобы редактировать "
"или удалить этот @title."
msgid "You are not allowed to view this @title."
msgstr "Вы не можете просматривать @title."
msgid "@title type"
msgstr "Тип @title"
msgid "Add @title"
msgstr "Добавить @title"
msgid "Add another @title"
msgstr "Добавить другой @title"
msgid "You are not allowed to add any of the @title types."
msgstr ""
"У вас нет прав, чтобы добавить ни один "
"из типов @title."
msgid "You did not add any @title types yet."
msgstr "Вы ещё не добавили никаких типов @title."
msgid "Revision create time"
msgstr "Время создания редакции"
msgid "The ID of the parent entity of which this entity is referenced."
msgstr ""
"ID родительской сущности, на которую "
"ссылается эта сущность."
msgid "The entity parent type to which this entity is referenced."
msgstr ""
"Тип сущности родителя, с которой "
"связана данная сущность."
msgid "Parent field name"
msgstr "Название родительского поля"
msgid "The entity parent field name to which this entity is referenced."
msgstr ""
"Название поля, через куоторое данная "
"сущность связана с родительской."
msgid "Paragraphs Demo"
msgstr "Демо параграфов"
msgid ""
"<strong>Note:</strong> Field options do not appear until a type has "
"been chosen and saved."
msgstr ""
"<strong>Примечание:</strong> параметры полей "
"не отображаются до тех пор, пока не "
"будет выбран и сохранён тип."
msgid "Not yet configured."
msgstr "Еще не настроено."
msgid "Using the %field field on a %type paragraph."
msgstr "Используем поле %field в параграфе %type."
msgid "Edit %title paragraph type"
msgstr "Редактировать тип параграфа \"%title\""
msgid "No @title added yet."
msgstr "Ещё не добавлен ни один @title"
msgid " to %type"
msgstr " в %type"
msgid "Nested Paragraph"
msgstr "Вложенный параграф"
msgid "Paragraphed article"
msgstr "Статья с параграфами"
msgid "Image + Text"
msgstr "Изображение + Текст"
msgid "Text + Image"
msgstr "Текст + Изображение"
msgid "Paragraphs demo index"
msgstr "Индекс демо параграфов"
msgid "Paragraphs demo server"
msgstr "Сервер демо параграфов"
msgid ""
"Paragraphs fields do not support translation. See the <a "
"href=\":documentation\">online documentation</a>."
msgstr ""
"Поле параграфа не поддерживает "
"перевод. Смотрите <a "
"href=\":documentation\">онлайн документацию</a>."
msgid ""
"(* unsupported) Paragraphs fields do not support translation. See the "
"<a href=\":documentation\">online documentation</a>."
msgstr ""
"(* не поддерживается) Поле параграфа не "
"поддерживает перевод. Смотрите <a "
"href=\":documentation\">онлайн документацию</a>."
msgid ""
"%type Paragraphs type is used by 1 piece of content on your site. You "
"can not remove this %type Paragraphs type until you have removed all "
"from the content."
msgid_plural ""
"%type Paragraphs type is used by @count pieces of content on your "
"site. You may not remove %type Paragraphs type until you have removed "
"all from the content."
msgstr[0] ""
"Тип параграфа %type используется в 1 "
"материале на вашем сайте. Вы не можете "
"удалить этот тип, пока не удалите его "
"из материалов."
msgstr[1] ""
"Тип параграфа %type используется в @count "
"материалах на вашем сайте. Вы не "
"можете удалить этот тип, пока не "
"удалите его из материалов."
msgstr[2] ""
"Тип параграфа %type используется в @count "
"материалах на вашем сайте. Вы не "
"можете удалить этот тип, пока не "
"удалите его из материалов."
msgid "Deleted @title: %type"
msgstr "Удаление @title: %type"
msgid "No widget available for: %label."
msgstr "Нет доступных виджетов для: %label."
msgid "Set as current revision"
msgstr "Установить как текущую редакцию"
msgid "Enables the creation of paragraphs entities."
msgstr "Позволяет создавать параграфы."
msgid "Default paragraph type"
msgstr "Тип параграфа по умолчанию"
msgid "When creating a new host entity, a paragraph of this type is added."
msgstr ""
"Параграф указанного типа добавляется, "
"когда создаётся родительская "
"сущность."
msgid "Default paragraph type: @default_paragraph_type"
msgstr ""
"Тип параграфа по умолчанию: "
"@default_paragraph_type"
msgid "You have unsaved changes on this @title item."
msgstr ""
"У вас есть несохранённые изменения в "
"\"@title\""
msgid ""
"The Paragraphs module provides a field type that can contain several "
"other fields and thereby allows users to break content up on a page. "
"Administrators can predefine <em>Paragraphs types</em> (for example a "
"simple text block, a video, or a complex and configurable slideshow). "
"Users can then place them on a page in any order instead of using a "
"text editor to add and configure such elements. For more information, "
"see the <a href=\":online\">online documentation for the Paragraphs "
"module</a>."
msgstr ""
"Модуль Paragraphs предоставляет тип поля, "
"которое может содержать несколько "
"других полей и тем самым позволяет "
"пользователям разбивать материал на "
"странице на части. Администраторы "
"могут заранее определить <em>типы "
"параграфов</em> (например, простой "
"текстовый блок, видео или сложное и "
"настраиваемое слайд-шоу). Затем "
"пользователи могут добавлять их на "
"страницу в любом порядке вместо того, "
"чтобы использовать текстовый "
"редактор для добавления и настройки "
"таких элементов. Дополнительную "
"информацию см. в <a "
"href=\":online\">онлайн-документации по "
"модулю Paragraphs</a>."
msgid "Creating Paragraphs types"
msgstr "Создание типов параграфов"
msgid ""
"<em>Paragraphs types</em> can be created by clicking <em>Add "
"Paragraphs type</em> on the <a href=\":paragraphs\">Paragraphs types "
"page</a>. By default a new Paragraphs type does not contain any "
"fields."
msgstr ""
"<em>Типы параграфов</em> можно создать, "
"нажав <em>Добавить тип параграфа</em> на "
"странице <a href=\":paragraphs\">Типы "
"параграфов</a>. По умолчанию новый тип "
"параграфа не содержит полей."
msgid "Configuring Paragraphs types"
msgstr "Настройка типов параграфов"
msgid ""
"Administrators can add fields to a <em>Paragraphs type</em> on the <a "
"href=\":paragraphs\">Paragraphs types page</a> if the <a "
"href=\":field_ui\">Field UI</a> module is enabled. The form display "
"and the display of the Paragraphs type can also be managed on this "
"page. For more information on fields and entities, see the <a "
"href=\":field\">Field module help page</a>."
msgstr ""
"Администраторы могут добавлять поля к "
"<em>типу параграфа</em> на странице <a "
"href=\":paragraphs\">Типы параграфов</a>, если "
"включен модуль <a href=\":field_ui\">Field UI</a>. На "
"этой странице также можно управлять "
"отображением формы и внешнего вида "
"параграфа. Для получения "
"дополнительной информации о полях и "
"сущностях см. <a href=\":field\">Страницу "
"справки по модулю Field</a>."
msgid "Creating content with Paragraphs"
msgstr "Создание материала с параграфами"
msgid ""
"Administrators can add a <em>Paragraph</em> field to content types or "
"other entities, and configure which <em>Paragraphs types</em> to "
"include. When users create content, they can then add one or more "
"paragraphs by choosing the appropriate type from the dropdown list. "
"Users can also dragdrop these paragraphs. This allows users to add "
"structure to a page or other content (for example by adding an image, "
"a user reference, or a differently formatted block of text) more "
"easily then including it all in one text field or by using fields in a "
"pre-defined order."
msgstr ""
"Администраторы могут добавить поле "
"<em>Параграф</em> к типам материала или "
"другим сущностям и настроить, какие "
"<em>типы параграфов</em> следует "
"включить. Когда пользователи создают "
"материал, они могут добавить один или "
"несколько параграфов, выбрав "
"соответствующий тип из выпадающего "
"списка. Пользователи также могут "
"перетаскивать эти параграфы. Это "
"позволит им структурировать страницу "
"(например, добавив изображение, ссылку "
"на пользователя или блок текста с "
"другим форматированием) более простым "
"способом, чем включать все это в одно "
"текстовое поле или использовать поля "
"в заданном порядке."
msgid "@field_label (* unsupported)"
msgstr "@field_label (* не поддерживается)"
msgid "Add paragraph type"
msgstr "Добавить тип параграфа"
msgid "Create and manage Paragraph types."
msgstr ""
"Создание и управление типами "
"параграфов."
msgid "Add Paragraphs type"
msgstr "Добавить тип параграфа"
msgid "Icon uuid"
msgstr "Uuid значка"
msgid ""
"The Paragraphs Demo module provides several <em>Paragraphs types</em> "
"for the <a href=\":paragraphs\">Paragraphs module</a>, but no separate "
"user interface. For more information, see the <a "
"href=\":online\">online documentation for the Paragraphs module</a>."
msgstr ""
"Модуль Paragraphs Demo предоставляет "
"несколько <em>типов параграфов</em> для <a "
"href=\":paragraphs\">модуля Paragraphs</a>, но не имеет "
"отдельного пользовательского "
"интерфейса. Дополнительную "
"информацию см. в <a "
"href=\":online\">онлайн-документации по "
"модулю Paragraphs</a>."
msgid "Changing demo Paragraphs types"
msgstr ""
"Редактирование демонстрационных "
"типов параграфов"
msgid ""
"Administrators can edit the provided <em>Paragraphs types</em> on the "
"<a href=\":paragraphs\">Paragraphs types page</a> if the <a "
"href=\":field_ui\">Field UI</a> module is enabled. For more "
"information on fields and entities, see the <a href=\":field\">Field "
"module help page</a>."
msgstr ""
"Администраторы могут редактировать "
"имеющиеся <em>типы параграфов</em> на "
"странице <a href=\":paragraphs\">Типы "
"параграфов</a>, если модуль <a "
"href=\":field_ui\">Field UI</a> включен. "
"Дополнительную информацию о полях и "
"сущностях см. на странице справки по "
"модулю <a href=\":field\">Field</a>."
msgid "Deleting demo Paragraphs types"
msgstr ""
"Удаление демонстрационных типов "
"параграфов"
msgid ""
"The provided <em>demo Paragraph types</em> stay available even when "
"the Paragraphs Demo module is uninstalled. They can be deleted "
"individually on the <a href=\":paragraphs\">Paragraphs types page</a>."
msgstr ""
"Предоставленные <em>демонстрационные "
"типы параграфов</em> остаются даже "
"после удаления Демо модуля. Их можно "
"удалить по отдельности на странице <a "
"href=\":paragraphs\">Типы параграфов</a>."
msgid ""
"Administrators can configure the permissions to view, create, edit, "
"and delete each <em>Paragraphs type</em> individually on the <a "
"href=\":permissions\">Permissions page</a>."
msgstr ""
"Администраторы могут настроить права "
"на просмотр, создание, редактирование "
"и удаление каждого <em>типа "
"параграфов</em> на странице <a "
"href=\":permissions\">Права доступа</a>."
msgid "Allows users to configure permissions for individual Paragraphs types."
msgstr ""
"Позволяет пользователям настраивать "
"права доступа для отдельных типов "
"параграфов."
msgid "Bypass Paragraphs type content access control"
msgstr ""
"Обходить проверку прав доступа к "
"параграфам"
msgid "Is able to administer content for all Paragraph types"
msgstr ""
"Может редактировать и удалять "
"параграфы любых типов."
msgid "Is able to view Paragraphs content of type %type_name"
msgstr ""
"Может просматривать параграфы типа "
"%type_name"
msgid "Is able to create Paragraphs content of type %type_name"
msgstr "Может создавать параграфы типа %type_name"
msgid "Is able to update Paragraphs content of type %type_name"
msgstr ""
"Может редактировать параграфы типа "
"%type_name"
msgid "Is able to delete Paragraphs content of type %type_name"
msgstr "Может удалять параграфы типа %type_name"
msgid "Paragraph type icon"
msgstr "Иконка параграфа этого типа"
msgid "This text will be displayed on the <em>Add new paragraph</em> page."
msgstr ""
"Этот текст будет показан на странице "
"<em>Добавить новый параграф</em>."
msgid "Exclude the selected below"
msgstr "Исключить выбранное ниже"
msgid "Include the selected below"
msgstr "Включить выбранное ниже"
msgid "Which Paragraph types should be allowed?"
msgstr ""
"Какие типы параграфов должны быть "
"разрешены?"
msgid ""
"Selection of Paragraph types for this field. Select none to allow all "
"Paragraph types."
msgstr ""
"Выбор типов параграфов для этого поля. "
"Оставьте пустым, чтобы разрешить все."
msgid ""
"You did not add any Paragraph types yet, click <a "
"href=\":here\">here</a> to add one."
msgstr ""
"У вас нет ещё ни одного типа параграфа, "
"чтобы добавить нажмите <a "
"href=\":here\">здесь</a>."
msgid "Paragraph summary"
msgstr "Краткое содержание параграфа"
msgid "The way to add new Paragraphs."
msgstr "Способ добавить новый параграф"
msgid "The mode the paragraph is in by default."
msgstr "Режим параграфа по умолчанию."
msgid "Closed mode"
msgstr "Режим закрытия"
msgid ""
"How to display the paragraphs, when the widget is closed. Preview will "
"render the paragraph in the preview view mode and typically needs a "
"custom admin theme."
msgstr ""
"Как отображать параграф, когда виджет "
"закрыт. Параграф будет отображаться в "
"режиме предварительного просмотра, "
"что обычно требует использования "
"специальной темы администратора."
msgid "Autocollapse"
msgstr "Автоматическое свёртывание"
msgid "When a paragraph is opened for editing, close others."
msgstr ""
"Закрыть остальные, когда параграф "
"открыт для редактирования."
msgid "Closed mode: @closed_mode"
msgstr "Режим закрытия: @closed_mode"
msgid "Autocollapse: @autocollapse"
msgstr "Автоматическое свёртывание: @autocollapse"
msgid "Current path for @number"
msgstr "Текущий путь для @number"
msgid "to %type"
msgstr "в %type"
msgid "Edit all"
msgstr "Редактировать все"
msgid "Edit All"
msgstr "Редактировать все"
msgid "Revision from %revision-date has been deleted."
msgstr "Редакция от %revision-date была удалена."
msgid "Paragraphs settings"
msgstr "Настройки параграфов"
msgid "View unpublished paragraphs"
msgstr "Просмотр неопубликованных параграфов"
msgid "Users with this permission can view paragraphs that are unpublished"
msgstr ""
"Пользователи с этим правом могут "
"просматривать неопубликованные "
"параграфы"
msgid "Administer Paragraphs settings"
msgstr "Управление настройками параграфов"
msgid ""
"Allow users with \"View unpublished paragraphs\" permission to see "
"unpublished paragraphs."
msgstr ""
"Позволить пользователям с правом "
"\"Просмотр неопубликованных "
"параграфов\" просматривать "
"неопубликованные параграфы."
msgid "Add above"
msgstr "Добавить над"
msgid "Unlink from library"
msgstr "Отсоединить от библиотеки"
msgid "Paragraphs Library"
msgstr "Библиотека параграфов"
msgid "Provides a library for reusing paragraphs."
msgstr ""
"Предоставляет библиотеку для "
"повторного использования параграфов."
msgid "Add library item"
msgstr "Добавить элемент в библиотеку"
msgid "Manage paragraphs library items."
msgstr ""
"Управление элементами библиотеки "
"параграфов"
msgid "Administer Paragraphs library"
msgstr "Управление библиотекой параграфов"
msgid "Paragraph %label has been created."
msgstr "Был создан параграф \"%label\" ."
msgid "Show unpublished Paragraphs"
msgstr ""
"Показывать неопубликованные "
"параграфы"
msgid "Enable widget features"
msgstr "Включить функции виджета"
msgid "Collapse / Edit all"
msgstr "Развернуть / Редактировать все"
msgid "Paragraphs library items"
msgstr "Элементы библиотеки параграфов"
msgid "Closed mode threshold"
msgstr "Предел режима закрытия"
msgid "Closed, show nested"
msgstr "Закрыто, показывать вложенные"
msgid "Closed mode threshold: @mode_limit"
msgstr "Предел режима закрытия: @mode_limit"
msgctxt "paragraphs"
msgid "Behaviors"
msgstr "Поведение"
msgctxt "paragraphs"
msgid "Behavior"
msgstr "Поведение"
msgid "From library"
msgstr "Из библиотеки"
msgctxt "Workflow state label"
msgid "Archived"
msgstr "Заархивированный"
msgctxt "Workflow state label"
msgid "Draft"
msgstr "Черновик"
msgctxt "Workflow state label"
msgid "Published"
msgstr "Опубликовано"
msgctxt "Workflow transition label"
msgid "Archive"
msgstr "Архивировать"
msgctxt "Workflow transition label"
msgid "Restore to Draft"
msgstr "Восстановить из Черновика"
msgctxt "Workflow transition label"
msgid "Restore"
msgstr "Восстановить"
msgctxt "Workflow transition label"
msgid "Create New Draft"
msgstr "Создать новый черновик"
msgctxt "Workflow transition label"
msgid "Publish"
msgstr "Опубликовать"
msgctxt "paragraphs"
msgid "Behavior plugins are only supported by the stable paragraphs widget."
msgstr ""
"Плагины поведения параграфов "
"поддерживаются только в стабильном "
"виджете."
msgid "Paragraphs Legacy"
msgstr "Устаревшие параграфы"
msgid "Paragraphs (stable)"
msgstr "Параграфы (стабильный)"
msgid "Allow promoting to library"
msgstr "Разрешить помещать в библиотеку"
# Russian translation of Paragraphs Browser (8.x-1.3)
# Copyright (c) 2024 by the Russian translation team
#
msgid ""
msgstr ""
"Project-Id-Version: Paragraphs Browser (8.x-1.3)\n"
"POT-Creation-Date: 2024-11-13 02:14+0000\n"
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=((((n%10)==1)&&((n%100)!=11))?(0):(((((n%10)>=2)&&((n%10)<=4))&&(((n%100)<10)||((n%100)>=20)))?(1):2));\n"
msgid "Delete"
msgstr "Удалить"
msgid "Content"
msgstr "Содержимое"
msgid "Groups"
msgstr "Группы"
msgid "Cancel"
msgstr "Отмена"
msgid "Edit"
msgstr "Редактировать"
msgid "Search"
msgstr "Поиск"
msgid "Label"
msgstr "Метка"
msgid "Save"
msgstr "Сохранить"
msgid "Add"
msgstr "Добавить"
msgid "ID"
msgstr "ID"
msgid "Upload image"
msgstr "Загрузка изображения"
msgid "Save changes"
msgstr "Сохранить изменения"
msgid "Add group"
msgstr "Добавить группу"
msgid "Browse"
msgstr "Обзор"
msgid "Map"
msgstr "Карта"
msgid "Confirm Deletion"
msgstr "Подтвердите Удаление"
msgid "Image Settings"
msgstr "Настройки изображения"
msgid "Add Group"
msgstr "Добавить Группу"
msgid "Delete Group"
msgstr "Удалить Группу"
msgid "Machine name"
msgstr "Машинное имя"
msgid "About"
msgstr "Информация"
msgid "The changes were successfully saved."
msgstr "Изменения успешно сохранены."
msgid "Paragraphs"
msgstr "Параграфы"
msgid "Add :title"
msgstr "Добавить :title"
# Russian translation of Pathauto (8.x-1.13)
# Copyright (c) 2024 by the Russian translation team
#
msgid ""
msgstr ""
"Project-Id-Version: Pathauto (8.x-1.13)\n"
"POT-Creation-Date: 2024-12-27 15:30+0000\n"
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=((((n%10)==1)&&((n%100)!=11))?(0):(((((n%10)>=2)&&((n%10)<=4))&&(((n%100)<10)||((n%100)>=20)))?(1):2));\n"
msgid "Remove"
msgstr "Удалить"
msgid "Language"
msgstr "Язык"
msgid "Enable"
msgstr "Включить"
msgid "Disable"
msgstr "Отключить"
msgid "Enabled"
msgstr "Включено"
msgid "Weight"
msgstr "Вес"
msgid "Settings"
msgstr "Настройки"
msgid "Label"
msgstr "Метка"
msgid "Update"
msgstr "Обновить"
msgid "ID"
msgstr "ID"
msgid "Separator"
msgstr "Разделитель"
msgid "URL alias"
msgstr "Синоним URL"
msgid "Conditions"
msgstr "Условия"
msgid "Verbose"
msgstr "Подробности"
msgid "Display alias changes (except during bulk updates)."
msgstr ""
"Показать изменения синонимов (кроме "
"пакетного обновления)"
msgid "Replace by separator"
msgstr "Заменять разделителем"
msgid "Maximum alias length"
msgstr "Максимальная длина синонима"
msgid "Maximum component length"
msgstr "Максимальная длина компонента"
msgid "Update action"
msgstr "Действие при обновлении"
msgid "Strings to Remove"
msgstr "Строки для удаления"
msgid "Pathauto"
msgstr "Pathauto"
msgid ""
"Provides a mechanism for modules to automatically generate aliases for "
"the content they manage."
msgstr ""
"Обеспечивает для модулей механизм "
"автоматической генерации синонимов "
"для материала, которым они управляют."
msgid "Forum"
msgstr "Форум"
msgid "Pattern"
msgstr "Шаблон"
msgid "Languages"
msgstr "Языки"
msgid "Period"
msgstr "Период"
msgid "Asterisk"
msgstr "Asterisk"
msgid "Duplicate"
msgstr "Дубликат"
msgid "Relationship"
msgstr "Связь"
msgid ""
"The automatically generated alias %original_alias conflicted with an "
"existing alias. Alias changed to %alias."
msgstr ""
"Автоматически сформированный "
"%original_alias конфликтует с существующим "
"адресом. Синоним изменён на %alias."
msgid "Delete aliases"
msgstr "Удалить синонимы"
msgid "Automatic alias"
msgstr "Автоматический синоним"
msgid ""
"Character used to separate words in titles. This will replace any "
"spaces and punctuation characters. Using a space or + character can "
"cause unexpected results."
msgstr ""
"Символ, разделяющий слова в "
"заголовках. Им заменяются все пробелы "
"и символы пунктуации. Использование "
"пробела или символа + может привести к "
"непредвиденным результатам."
msgid "Character case"
msgstr "Регистр символов"
msgid "Do nothing. Leave the old alias intact."
msgstr ""
"Ничего не делать. Оставить старый "
"синоним нетронутым."
msgid "Create a new alias. Leave the existing alias functioning."
msgstr ""
"Создать новый синоним. Оставить "
"существующий синоним рабочим."
msgid "Create a new alias. Delete the old alias."
msgstr ""
"Создать новый синоним. Удалить старый "
"синоним."
msgid "Transliterate prior to creating alias"
msgstr ""
"Транслитерировать перед созданием "
"синонима"
msgid ""
"Filters the new alias to only letters and numbers found in the "
"ASCII-96 set."
msgstr ""
"Отметьте это поле, чтобы при "
"транслитерации из адресов "
"исключались знаки, не входящие в ASCII-96."
msgid "No action (do not replace)"
msgstr "Нет действия (не заменять)"
msgid "Delete all aliases. Number of aliases which will be deleted: %count."
msgstr ""
"Удалить все синонимы. Количество "
"синонимов, которые будут удалены: %count."
msgid ""
"Delete aliases for all @label. Number of aliases which will be "
"deleted: %count."
msgstr ""
"Удалить синонимы для всех @label. Число "
"синонимов, которые будут удалены: %count."
msgid "Delete aliases now!"
msgstr "Удалить синонимы сейчас!"
msgid "All of your path aliases have been deleted."
msgstr "Все ваши синонимы путей были удалены."
msgid "About"
msgstr "Информация"
msgid "Patterns"
msgstr "Шаблоны"
msgid "Colon"
msgstr "двоеточие"
msgid "Path pattern"
msgstr "Шаблон пути"
msgid "Context definitions"
msgstr "Определения контекста"
msgid "Comma"
msgstr "Запятая"
msgid "Semicolon"
msgstr "Точка с запятой"
msgid "Uses"
msgstr "Использование"
msgid "Slash"
msgstr "Косая черта"
msgid "Alias: @alias"
msgstr "Синоним: @alias"
msgid "No alias"
msgstr "Синоним не задан"
msgid "Punctuation"
msgstr "Пунктуация"
msgid "Broken"
msgstr "Прервано"
msgid "Ampersand"
msgstr "Амперсанд"
msgid "Pathauto Settings"
msgstr "Настройки Pathauto"
msgid ""
"What should Pathauto do when updating an existing content item which "
"already has an alias?"
msgstr ""
"Выберите действие, которое будет "
"использовать модуль Pathauto в том случае, "
"когда альтернативный адрес уже "
"существует."
msgid "Reduce strings to letters and numbers"
msgstr "Сокращать строки до букв и цифр"
msgid ""
"Words to strip out of the URL alias, separated by commas. Do not use "
"this to remove punctuation."
msgstr ""
"Слова для исключения из путей, "
"разделенные запятыми. Не используйте "
"это поле для удаления знаков "
"пунктуации."
msgid "Choose aliases to delete"
msgstr "Выберите синонимы для удаления"
msgid "All aliases"
msgstr "Все синонимы"
msgid "Ignoring alias %alias because it is the same as the internal path."
msgstr ""
"Игнорируется синоним %alias, потому что "
"он такой же, как и внутренний путь."
msgid "Created new alias %alias for %source, replacing %old_alias."
msgstr ""
"Создан новый синоним %alias для %source, "
"заменивший %old_alias."
msgid "Created new alias %alias for %source."
msgstr "Создан новый синоним %alias для %source."
msgid "Administer pathauto"
msgstr "Управление настройками Pathauto"
msgid "Notify of Path Changes"
msgstr ""
"Получать уведомления об изменениях "
"путей"
msgid "Determines whether or not users are notified."
msgstr ""
"Определяет, требуется ли уведомление "
"пользователя."
msgid "Bulk updating URL aliases"
msgstr "Массовое обновление псевдонимов URL"
msgid "An error occurred while processing @operation with arguments : @args"
msgstr ""
"Возникла ошибка в процессе @operation с "
"аргументами: @args"
msgid "Generated 1 URL alias."
msgid_plural "Generated @count URL aliases."
msgstr[0] "Создан 1 псевдоним."
msgstr[1] "Создано @count псевдонима."
msgstr[2] "Создано @count псевдонимов."
msgid "Update URL alias"
msgstr "Обновить URL-синоним"
msgid "Underscore"
msgstr "Подчёркивание"
msgid "No new URL aliases to generate."
msgstr "Новые синонимы URL не созданы."
msgid "Double quotation marks"
msgstr "Двойные кавычки"
msgid "Single quotation marks (apostrophe)"
msgstr "Апостроф"
msgid "Back tick"
msgstr "Обратный апостроф"
msgid "Hyphen"
msgstr "дефис"
msgid "Vertical bar (pipe)"
msgstr "Вертикальная черта"
msgid "Left curly bracket"
msgstr "Левая фигурная скобка"
msgid "Left square bracket"
msgstr "Левая квадратная скобка"
msgid "Right curly bracket"
msgstr "Правая фигурная скобка"
msgid "Right square bracket"
msgstr "Правая квадратная скобка"
msgid "Plus sign"
msgstr "Знак \"плюс\""
msgid "Equal sign"
msgstr "Знак \"равно\""
msgid "Percent sign"
msgstr "Знак процента"
msgid "Caret"
msgstr "Знак вставки"
msgid "Dollar sign"
msgstr "Знак доллара"
msgid "Number sign (pound sign, hash)"
msgstr "Знак решетки"
msgid "At sign"
msgstr "Знак \"@\""
msgid "Exclamation mark"
msgstr "Восклицательный знак"
msgid "Tilde"
msgstr "Тильда"
msgid "Left parenthesis"
msgstr "Левая круглая скобка"
msgid "Right parenthesis"
msgstr "Правая круглая скобка"
msgid "Question mark"
msgstr "Знак вопроса"
msgid "Less-than sign"
msgstr "Знак \"меньше\""
msgid "Greater-than sign"
msgstr "Знак \"больше\""
msgid "Backslash"
msgstr "Обратная косая черта"
msgid "Generate automatic URL alias"
msgstr "Создать синоним URL автоматически"
msgid "Uncheck this to create a custom alias below."
msgstr ""
"Снимите флажок, чтобы создать "
"псевдоним URL вручную."
msgid "Joined path"
msgstr "Объединённые пути"
msgid ""
"The array values each cleaned by Pathauto and then joined with the "
"slash into a string that resembles an URL."
msgstr ""
"Значения массива, очищенные Pathauto, а "
"затем объединенные косой чертой в "
"строку, похожую на URL."
msgid "Selection criteria"
msgstr "Критерий выбора"
msgid "Bulk generate"
msgstr "Массовая генерация"
msgid "Broken/Missing"
msgstr "Повреждён/Отсутствует"
msgid "Selection logic"
msgstr "Логика выбора"
msgid "Pattern type"
msgstr "Тип шаблона"
msgid "Delete options"
msgstr "Опции удаления"
msgid "All of your %label path aliases have been deleted."
msgstr "Удалены все синонимы пути %label."
msgid "See <a href=\":pathauto-help\">Pathauto help</a> for details."
msgstr ""
"Смотри подробности в<a "
"href=\":pathauto-help\">справке Pathauto</a>."
msgid ""
"Maximum length of aliases to generate. 100 is the recommended length. "
"@max is the maximum possible length."
msgstr ""
"Максимальная длина генерируемых "
"синонимов. Рекомендуемая длина - 100. @max "
"- максимально возможная длина."
msgid ""
"Maximum text length of any component in the alias (e.g., [title]). 100 "
"is the recommended length. @max is the maximum possible length."
msgstr ""
"Максимальная длина любого из "
"компонентов в синониме адреса "
"(например, [title]). 100 - рекомендуемая "
"длина. @max - максимально возможная "
"длина."
msgid ""
"The <a href=\":url\">Redirect module settings</a> affect whether a "
"redirect is created when an alias is deleted."
msgstr ""
"<a href=\":url\">Настройки переадресации "
"модуля</a> влияют на то, будет ли "
"создаваться переадресация при "
"удалении синонима."
msgid ""
"Considering installing the <a href=\":url\">Redirect module</a> to get "
"redirects when your aliases change."
msgstr ""
"Рассмотрите вариант установки <a "
"href=\":url\">модуля Redirect</a> для создания "
"перенаправлений при изменении "
"синонимов."
msgid ""
"Uncheck this to create a custom alias below. <a "
"href=\"@admin_link\">Configure URL alias patterns.</a>"
msgstr ""
"Снимите флажок, чтобы создать "
"псевдоним URL вручную. <a "
"href=\"@admin_link\">Настройки шаблонов "
"URL-синонимов.</a>"
msgid "Selection condition"
msgstr "Условие выбора"
msgid ""
"Entity of type @type was not processed. It defines the following "
"patterns: @patterns"
msgstr ""
"Не была обработана сущность типа @type. "
"Она предоставляет следующие шаблоны: "
"@patterns"
msgid ""
"Unrecognized entity bundle @entity:@bundle was not processed. It "
"defines the following patterns: @patterns"
msgstr ""
"Не был обработан неопознанный подтип "
"сущности @entity:@bundle. Он предоставляет "
"следующие шаблоны: @patterns"
msgid "Add Pathauto pattern"
msgstr "Добавить шаблон"
msgid "Pathauto pattern config"
msgstr "Настройка шаблона"
msgid "Whether an automated alias should be created or not."
msgstr ""
"Должен ли создаваться синоним "
"автоматически или нет."
msgid "Pathauto pattern"
msgstr "Шаблон Pathauto"
msgid ""
"Check to which types this pattern should be applied. Leave empty to "
"allow any."
msgstr ""
"Выберите, к каким типам следует "
"применить этот шаблон. Оставьте "
"пустым, чтобы разрешить для всех."
msgid ""
"Check to which languages this pattern should be applied. Leave empty "
"to allow any."
msgstr ""
"Выберите, к каким языкам следует "
"применить этот шаблон. Оставьте поле "
"пустым, чтобы использовать для любого "
"языка."
msgid "Updated alias for %label @id."
msgstr "Обновлен синоним для %label @id."
msgid "Updated 1 %label URL alias."
msgid_plural "Updated @count %label URL aliases."
msgstr[0] "Обновлен 1 %label URL синоним."
msgstr[1] "Обновлено @count %label URL синонимов."
msgid ""
"When a pattern includes certain characters (such as those with "
"accents) should Pathauto attempt to transliterate them into the "
"US-ASCII alphabet?"
msgstr ""
"Если шаблон содержит определённые "
"символы (например, с диакритическими "
"знаками), следует ли Pathauto пытаться "
"транслитерировать их в алфавит US-ASCII?"
msgid ""
"This page provides a list of all patterns on the site and allows you "
"to edit and reorder them."
msgstr ""
"На этой странице представлен список "
"всех шаблонов на сайте, и вы можете "
"редактировать и изменять их порядок."
msgid ""
"The %element-title is using the following invalid characters: "
"@invalid-characters."
msgstr ""
"%element-title - используются недопустимые "
"символы: @invalid-characters."
msgid "Convert token values to lowercase."
msgstr ""
"Конвертировать значения токенов в "
"нижний регистр."
msgid "Are you sure you want to disable the pattern %label?"
msgstr ""
"Вы уверены, что хотите отключить "
"шаблон %label?"
msgid "Disabled patterns are ignored when generating aliases."
msgstr ""
"Отключенные шаблоны игнорируются при "
"создании синонимов."
msgid "Disabled pattern %label."
msgstr "Отключен шаблон %label."
msgid "Are you sure you want to enable the pattern %label?"
msgstr ""
"Вы уверены, что хотите включить шаблон "
"%label?"
msgid "Enabled pattern %label."
msgstr "Включён шаблон %label."
msgid "Update URL alias of an entity"
msgstr "Обновить синоним URL сущности"
msgid ""
"The Pathauto module provides a mechanism to automate the creation of "
"<a href=\"path\">path</a> aliases. This makes URLs more readable and "
"helps search engines index content more effectively. For more "
"information, see the <a href=\":online\">online documentation for "
"Pathauto</a>."
msgstr ""
"Модуль Pathauto предоставляет механизм "
"для автоматизации создания синонимов "
"<a href=\"path\">адресов</a>. Это делает "
"URL-адреса более удобочитаемыми и "
"помогает поисковым системам более "
"эффективно индексировать контент. Для "
"получения дополнительной информации "
"ознакомьтесь с <a "
"href=\":online\">онлайн-документацией по "
"Pathauto</a>."
msgid ""
"Pathauto is accessed from the tabs it adds to the list of <a "
"href=\":aliases\">URL aliases</a>."
msgstr ""
"Доступ к Pathauto осуществляется через "
"вкладки, которые он добавляет в список "
"<a href=\":aliases\">синонимов URL</a>."
msgid "Creating Pathauto Patterns"
msgstr "Создание шаблонов"
msgid ""
"The <a href=\":pathauto_pattern\">\"Patterns\"</a> page is used to "
"configure automatic path aliasing. New patterns are created here "
"using the <a href=\":add_form\">Add Pathauto pattern</a> button which "
"presents a form to simplify pattern creation thru the use of <a "
"href=\"token\">available tokens</a>. The patterns page provides a list "
"of all patterns on the site and allows you to edit and reorder them. "
"An alias is generated for the first pattern that applies."
msgstr ""
"Страница <a href=\":pathauto_pattern\">\"Шаблоны\"</a> "
"используется для настройки "
"автоматического создания синонимов "
"адресов. Новые шаблоны можно создать, "
"нажав на кнопку <a href=\":add_form\">Добавить "
"шаблон Pathauto</a>, которая открывает "
"форму, упрощающую создание шаблонов с "
"помощью <a href=\"token\">токенов</a>. На "
"странице шаблонов представлен список "
"всех доступных на сайте шаблонов, а "
"также возможность их редактирования и "
"изменения порядка. Синоним будет "
"генерироваться из первого "
"подходящего шаблона."
msgid ""
"The <a href=\":settings\">\"Settings\"</a> page is used to customize "
"global Pathauto settings for automated pattern creation."
msgstr ""
"Страница <a href=\":settings\">Настройки</a> "
"используется для изменения "
"глобальных параметров Pathauto для "
"автоматического создания шаблонов."
msgid "Bulk Generation"
msgstr "Массовая генерация"
msgid ""
"The <a href=\":pathauto_bulk\">\"Bulk Generate\"</a> page allows you "
"to create URL aliases for items that currently have no aliases. This "
"is typically used when installing Pathauto on a site that has existing "
"un-aliased content that needs to be aliased in bulk."
msgstr ""
"Страница <a href=\":pathauto_bulk\">Массовой "
"генерации</a> позволяет создавать "
"синонимы URL для элементов, у которых "
"ещё нет синонимов. Обычно это "
"используется при установке Pathauto на "
"сайте, на котором уже есть материалы, "
"для которых необходимо массово "
"создать синонимы."
msgid "Delete Aliases"
msgstr "Удалить синонимы"
msgid ""
"The <a href=\":pathauto_delete\">\"Delete Aliases\"</a> page allows "
"you to remove URL aliases from items that have previously been "
"assigned aliases using pathauto."
msgstr ""
"Страница <a href=\":pathauto_delete\">Удалить "
"синонимы</a> позволяет удалять "
"синонимы URL-адресов у элементов, для "
"которых они ранее были сгенерированы "
"с помощью pathauto."
msgid ""
"You need to select a pattern type, then a pattern and filter, and a "
"label. Additional types can be enabled on the <a "
"href=\":settings\">Settings</a> page."
msgstr ""
"Необходимо выбрать тип шаблона, затем "
"шаблон и фильтр, а также название. "
"Дополнительные типы можно включить на "
"странице <a href=\":settings\">настроек</a>."
msgid "Enabled entity types"
msgstr "Включённые типы сущностей"
msgid ""
"Enable to add a path field and allow to define alias patterns for the "
"given type. Disabled types already define a path field themselves or "
"currently have a pattern."
msgstr ""
"Включите, чтобы добавить поле пути и "
"разрешить определять шаблоны "
"псевдонимов для данного типа. "
"Отключенные типы уже сами определяют "
"поле пути или в настоящее время имеют "
"шаблон."
msgid "Broken type"
msgstr "Некорректный тип"
msgid ""
"Bulk generation can be used to generate URL aliases for items that "
"currently have no aliases. This is typically used when installing "
"Pathauto on a site that has existing un-aliased content that needs to "
"be aliased in bulk."
msgstr ""
"Массовая генерация может быть "
"использована для создания синоним "
"URL-адресов для элементов, у которых ещё "
"нет синонимов. Обычно это "
"используется при установке Pathauto на "
"сайт, где уже есть материалы, которым "
"необходимо массово создать синонимы."
msgid ""
"It can also be used to regenerate URL aliases for items that have an "
"old alias and for which the Pathauto pattern has been changed."
msgstr ""
"Это также можно использовать для "
"перегенерации синонимов URL-адресов "
"элементов, у которых есть старые "
"синонимы и для которых шаблон Pathauto был "
"изменен."
msgid ""
"Note that this will only affect items which are configured to have "
"their URL alias automatically set. Items whose URL alias is manually "
"set are not affected."
msgstr ""
"Обратите внимание, что это повлияет "
"только на элементы, для которых "
"настроена автоматическая генерация "
"синонима URL. При этом не будут "
"затронуты элементы, у которых синоним "
"задан вручную."
msgid "The %element-title doesn't allow the patterns ending with whitespace."
msgstr ""
"В %element-title не допускаются шаблоны с "
"пробелами в конце."
msgid "Select the types of paths for which to generate URL aliases"
msgstr ""
"Выберите типы путей, для которых нужно "
"создать псевдонимы URL."
msgid "Select which URL aliases to generate"
msgstr ""
"Выберите, какие псевдонимы URL "
"генерировать"
msgid "Generate a URL alias for un-aliased paths only"
msgstr ""
"Генерировать псевдоним URL только для "
"путей без псевдонимов"
msgid ""
"<a href=\":url\">Pathauto settings</a> are set to ignore paths which "
"already have a URL alias. You can only create URL aliases for paths "
"having none."
msgstr ""
"<a href=\":url\">Pathauto настроен</a> так, что "
"пути, у которых уже есть синоним, будут "
"игнорироваться. Создавать синонимы URL "
"можно только для путей, у которых его "
"нет."
msgid "Update the URL alias for paths having an old URL alias"
msgstr ""
"Обновить псевдоним URL для путей со "
"старым псевдонимом URL"
msgid "Regenerate URL aliases for all paths"
msgstr ""
"Повторное создание псевдонимов URL для "
"всех путей"
msgid "A short name to help you identify this pattern in the patterns list."
msgstr ""
"Краткое имя, для идентификации этого "
"шаблона в списке шаблонов."
msgid "Only delete automatically generated aliases"
msgstr ""
"Удалять только автоматически "
"сгенерированные псевдонимы"
msgid ""
"When checked, aliases which have been manually set are not affected by "
"this mass-deletion."
msgstr ""
"Когда выбрано, псевдонимы, "
"установленные вручную, не будут "
"затронуты этим массовым удалением."
msgid "Bulk deleting URL aliases"
msgstr "Массовое удаления URL синонимов"
msgid "All of your automatically generated path aliases have been deleted."
msgstr ""
"Все автоматически сгенерированные "
"синонимы будут удалены."
msgid ""
"All of your automatically generated %label path aliases have been "
"deleted."
msgstr ""
"%label: все автоматически "
"сгенерированные синонимы будут "
"удалены."
msgid "Tokens that are safe to use and do not need to be cleaned."
msgstr ""
"Токены, которые безопасны в "
"использовании и не нуждаются в "
"очистке."
msgid "Safe tokens"
msgstr "Безопасные токены"
msgid ""
"List of tokens that are safe to use in alias patterns and do not need "
"to be cleaned. For example urls, aliases, machine names. Separated "
"with a comma."
msgstr ""
"Список токенов, которые безопасно "
"использовать в шаблонах синонимов и "
"которые не нуждаются в очистке. "
"Например: URL-адреса, синонимы, машинные "
"имена. Должны быть разделены запятой."
msgid "Pattern %label saved."
msgstr "Шаблон %label сохранён."
msgid "Duplicate Pathauto pattern"
msgstr "Дублировать шаблон Pathauto"
msgid "Choose the action to perform."
msgstr "Выберите действие."
msgid ""
"Choose the alias type(s). Separate multiple choices with commas, e.g. "
"\"1,2,4\", or choose \"0\" for all types."
msgstr ""
"Выберите тип(ы) синонима. Несколько "
"вариантов разделяйте запятыми, "
"например \"1,2,4\", или выберите \"0\" для "
"всех типов."
msgid ""
"Invalid action argument \"@invalid_action\". Please use one of: "
"@valid_actions"
msgstr ""
"Неверный аргумент действия "
"\"@invalid_action\". Пожалуйста, используйте "
"один из: @valid_actions"
msgid ""
"Invalid type argument \"@invalid_types\". Please choose from the "
"following: @valid_types"
msgstr ""
"Неверный аргумент типа \"@invalid_types\". "
"Пожалуйста, выберите один из: @valid_types"
msgid "Generate a URL alias for un-aliased paths only."
msgstr ""
"Генерировать псевдоним URL только для "
"путей без псевдонимов."
msgid "Update the URL alias for paths having an old URL alias."
msgstr ""
"Обновить псевдоним URL для путей со "
"старым псевдонимом URL."
msgid "Regenerate URL aliases for all paths."
msgstr ""
"Повторное создание псевдонимов URL для "
"всех путей."
msgid "The name of the pattern's variable."
msgstr "Имя переменной шаблона."
msgid "The value of the pattern's variable."
msgstr "Значение переменной шаблона."
msgid ""
"The <strong>maximum alias length</strong> and <strong>maximum "
"component length</strong> values default to 100 and have a limit of "
"@max from Pathauto. You should enter a value that is the length of the "
"\"alias\" column of the path_alias database table minus the length of "
"any strings that might get added to the end of the URL. The "
"recommended and default value is 100."
msgstr ""
"Значения <strong>максимальной длины "
"синонима</strong> и <strong>максимальной "
"длины компонента</strong> по умолчанию "
"равны 100 и ограничены @max в Pathauto. "
"Следует ввести значение, равное длине "
"столбца \"alias\" в таблице базы данных "
"path_alias за вычетом длины любых строк, "
"которые могут быть добавлены в конец "
"URL-адреса. Рекомендуемое значение - 100."
msgid ""
"<strong>Note:</strong> there is no confirmation. Be sure of your "
"action before clicking the \"Delete aliases now!\" button.<br />You "
"may want to make a backup of the database and/or the path_alias and "
"path_alias_revision tables prior to using this feature."
msgstr ""
"<strong>Помните:</strong> действие невозможно "
"отменить. Убедитесь в правильности "
"своих действий до того, как нажмёте "
"кнопку \"Удалить синонимы!\".<br />Если не "
"уверены в правильности действий, "
"сделайте резервную копию таблиц path_alias "
"и path_alias_revision или всей БД."
msgid ""
"Allows a user to configure pathauto settings, configure patterns for "
"automated aliases, bulk update and delete URL-aliases."
msgstr ""
"Позволяет пользователю менять "
"настройки pathauto, настраивать шаблоны "
"для автоматического создания "
"синонимов, массово обновлять и "
"удалять синонимы URL."
msgid "Bulk update aliases"
msgstr "Массово обновлять синонимы"
msgid "Allows a user to bulk update aliases."
msgstr ""
"Разрешить пользователю массово "
"обновлять синонимы."
msgid "Bulk delete aliases"
msgstr "Массово удалять синонимы"
msgid "Allows a user to bulk delete aliases."
msgstr ""
"Разрешить пользователю массово "
"удалять синонимы."
# Russian translation of Resource Description Framework (RDF) (3.0.0-beta2)
# Copyright (c) 2024 by the Russian translation team
#
msgid ""
msgstr ""
"Project-Id-Version: Resource Description Framework (RDF) (3.0.0-beta2)\n"
"POT-Creation-Date: 2024-07-21 21:46+0000\n"
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=((((n%10)==1)&&((n%100)!=11))?(0):(((((n%10)>=2)&&((n%10)<=4))&&(((n%100)<10)||((n%100)>=20)))?(1):2));\n"
msgid "Types"
msgstr "Типы"
msgid "ID"
msgstr "ID"
msgid "Data type"
msgstr "Тип данных"
msgid "Arguments"
msgstr "Аргументы"
msgid "RDF"
msgstr "RDF"
msgid "About"
msgstr "Информация"
msgid "Web services"
msgstr "Веб-службы"
msgid "Properties"
msgstr "Свойства"
msgid "Bundle"
msgstr "Набор"
msgid "RDF mapping"
msgstr "RDF сопоставление"
msgid ""
"Enriches your content with metadata to let other applications (e.g. "
"search engines, aggregators) better understand its relationships and "
"attributes."
msgstr ""
"Дополняет материал метаданными, что "
"позволяет другим приложениям (таким, "
"как поисковые системы, сборщики лент) "
"лучше распознавать связи и атрибуты "
"материала."
msgid "Field mappings"
msgstr "Соотвествие полей"
msgid "Mapping type"
msgstr "Соответсвующий тип"
msgid "Target entity type"
msgstr "Целевой тип сущности"
msgid "Data type callback"
msgstr "Тип данных обратного вызова"
msgid "Callable"
msgstr "Вызываемый"
msgid "Interaction type"
msgstr "Тип взаимодействия"
msgid ""
"The RDF module enriches your content with metadata to let other "
"applications (e.g., search engines, aggregators, and so on) better "
"understand its relationships and attributes. This semantically "
"enriched, machine-readable output for your website uses the <a "
"href=\":rdfa\">RDFa specification</a>, which allows RDF data to be "
"embedded in HTML markup. Other modules can define mappings of their "
"data to RDF terms, and the RDF module makes this RDF data available to "
"the theme. The core modules define RDF mappings for their data model, "
"and the core themes output this RDF metadata information along with "
"the human-readable visual information. For more information, see the "
"<a href=\":rdf\">online documentation for the RDF module</a>."
msgstr ""
"Модуль RDF обогащает ваш контент "
"метаданными, чтобы позволить другим "
"приложениям (например, поисковым "
"системам, агрегаторам и т. д.) Лучше "
"понять его взаимосвязи и атрибуты. "
"Этот семантически обогащенный, "
"машиночитаемый вывод для вашего "
"веб-сайта использует <a "
"href=\":rdfa\">спецификацию RDFa</a>, которая "
"позволяет встраивать данные RDF в "
"разметку HTML. Другие модули могут "
"определять сопоставления своих "
"данных с терминами RDF, а модуль RDF "
"делает эти данные RDF доступными для "
"темы. Базовые модули определяют "
"отображения RDF для своей модели "
"данных, а основные темы выводят эту "
"информацию метаданных RDF вместе с "
"понятной для человека визуальной "
"информацией. Для получения "
"дополнительной информации см. <a "
"href=\":rdf\">онлайн-документацию для "
"модуля RDF</a>."
msgid "RDF mapping item"
msgstr "Элемент отображения RDF"
msgid "RDF mappings items"
msgstr "Элементы отображения RDF"
msgid "The name of the bundle a mapping applies to."
msgstr ""
"Имя набора, к которому применяется "
"сопоставление."
msgid "The serialized mapping of the bundle type and fields to RDF terms."
msgstr ""
"Сериализованное отображение наборов "
"и полей пакета в термины RDF."
msgid "RDF types."
msgstr "Типы RDF."
msgid "RDF field mappings."
msgstr "Соответствие полей RDF."
msgid ""
"The name of the entity type a mapping applies to (node, user, comment, "
"etc.)"
msgstr ""
"Имя типа сущности, к которой "
"применяется сопоставление (материал, "
"пользователь, комментарий и т.д.)"
msgid "RDF module"
msgstr "Модуль RDF"
# Russian translation of Redirect (8.x-1.11)
# Copyright (c) 2025 by the Russian translation team
#
msgid ""
msgstr ""
"Project-Id-Version: Redirect (8.x-1.11)\n"
"POT-Creation-Date: 2025-07-08 00:50+0000\n"
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=((((n%10)==1)&&((n%100)!=11))?(0):(((((n%10)>=2)&&((n%10)<=4))&&(((n%100)<10)||((n%100)>=20)))?(1):2));\n"
msgid "Delete"
msgstr "Удалить"
msgid "Operations"
msgstr "Операции"
msgid "Type"
msgstr "Тип"
msgid "Language"
msgstr "Язык"
msgid "Reset"
msgstr "Сбросить"
msgid "Settings"
msgstr "Настройки"
msgid "Save"
msgstr "Сохранить"
msgid "Access"
msgstr "Доступ"
msgid "Path"
msgstr "Путь"
msgid "Timestamp"
msgstr "Время"
msgid "Add another"
msgstr "Добавить еще"
msgid "User ID"
msgstr "ID Пользователя"
msgid "Created"
msgstr "Создано"
msgid "All"
msgstr "Все"
msgid "Page"
msgstr "Страница"
msgid "To"
msgstr "Кому"
msgid "From"
msgstr "От"
msgid "Filter"
msgstr "Фильтр"
msgid "Count"
msgstr "Количество"
msgid ", "
msgstr ", "
msgid "Desc"
msgstr "По убыванию"
msgid "Ignore"
msgstr "Игнорировать"
msgid "Destination"
msgstr "Место назначения"
msgid "Redirect"
msgstr "Переадресация"
msgid "UID"
msgstr "UID"
msgid "Sort by"
msgstr "Сортировать по"
msgid "‹ previous"
msgstr "‹ предыдущая"
msgid "next ›"
msgstr "следующая ›"
msgid "Source"
msgstr "Источник"
msgid "Query"
msgstr "Запрос"
msgid "Add redirect"
msgstr "Добавить перенаправление"
msgid "301 Moved Permanently"
msgstr "301 Перемещёно Окончательно"
msgid "307 Temporary Redirect"
msgstr "307 Временно перемещено"
msgid "Status Code"
msgstr "Код состояния"
msgid "URL redirects"
msgstr "Перенаправления url-адресов"
msgid ""
"You are attempting to redirect the page to itself. This will result in "
"an infinite loop."
msgstr ""
"Вы пытаетесь переадресовать страницу "
"саму на себя. Это приведёт к "
"бесконечному циклу."
msgid "300 Multiple Choices"
msgstr "300 Множество Выборов"
msgid "302 Found"
msgstr "302 Найдено"
msgid "303 See Other"
msgstr "303 Смотреть Другое"
msgid "304 Not Modified"
msgstr "304 Не Изменялось"
msgid "305 Use Proxy"
msgstr "305 Использовать Прокси"
msgid "Redirect users from one URL to another."
msgstr ""
"Перенаправление пользователей с "
"одного адреса на другой."
msgid "« first"
msgstr "« первая"
msgid "last »"
msgstr "последняя »"
msgid "Offset"
msgstr "Пропустить"
msgid "About"
msgstr "Информация"
msgid "Menu Access Checking"
msgstr "Проверка доступа к меню"
msgid "Uses"
msgstr "Использование"
msgid "All languages"
msgstr "Все языки"
msgid "Items per page"
msgstr "Элементов на страницу"
msgid "‹‹"
msgstr "‹‹"
msgid "››"
msgstr "››"
msgid "- All -"
msgstr "- Все -"
msgid ""
"A redirect set for a specific language will always be used when "
"requesting this page in that language, and takes precedence over "
"redirects set for <em>All languages</em>."
msgstr ""
"Установки перенаправлений на "
"конкретный язык всегда будут "
"использоваться при запросе страницы "
"на этом языке, и имеют приоритет над "
"установками перенаправлений на "
"странице <em>Все языки</em>."
msgid "Redirect status"
msgstr "Состояние перенаправления"
msgid "Display a warning message to users when they are redirected."
msgstr ""
"Показывать пользователям при "
"переадресации предупреждающее "
"сообщение."
msgid "Automatically create redirects when URL aliases are changed."
msgstr ""
"Автоматически создавать "
"перенаправления, при изменении "
"синонимов URL."
msgid "Default redirect status"
msgstr "Состояние переадресации по умолчанию"
msgid "Delete redirect"
msgstr "Удалить перенаправление"
msgid "Configure behavior for URL redirects."
msgstr ""
"Настроить поведение перенаправлений "
"адресов (URL)."
msgid "Status code"
msgstr "Код состояния"
msgid "Fragment"
msgstr "Фрагмент"
msgid ""
"You can find more information about HTTP redirect status codes at <a "
"href=\"@status-codes\">@status-codes</a>."
msgstr ""
"Вы можете найти более подробную "
"информацию о статусах кодов HTTP "
"перенаправления на <a "
"href=\"@status-codes\">@status-codes</a>."
msgid "The redirect has been saved."
msgstr "Перенаправление было сохранено."
msgid "No URL redirects available."
msgstr "Переадресаций нет."
msgid ""
"The source path %source is already being redirected. Do you want to <a "
"href=\"@edit-page\">edit the existing redirect</a>?"
msgstr ""
"Путь источника %source уже "
"перенаправляется. Вы хотите <a "
"href=\"@edit-page\">редактировать "
"существующее перенаправление</a>?"
msgid "Output machine name"
msgstr "Машинное имя \"на выходе\""
msgid "UUID"
msgstr "UUID"
msgid ""
"The base source path %source is already being redirected. Do you want "
"to <a href=\"@edit-page\">edit the existing redirect</a>?"
msgstr ""
"Источник базового исходного пути %source "
"уже перенаправляется. Вы хотите <a "
"href=\"@edit-page\">редактировать "
"существующее перенаправление</a>?"
msgid ""
"Are you sure you want to delete the URL redirect from %source to "
"%redirect?"
msgstr ""
"Действительно хотите удалить "
"перенаправление с %source на %redirect?"
msgid "Retain query string through redirect."
msgstr ""
"Сохранять строку запроса при "
"перенаправлении."
msgid "(formerly Global Redirect features)"
msgstr "(функции из Global Redirect)"
msgid "Last accessed"
msgstr "Последний доступ"
msgid "Filter 404s"
msgstr "Фильтровать страницы 404"
msgid "Fix 404 pages"
msgstr "Исправление 404 страниц"
msgid "Add redirects for 404 pages."
msgstr ""
"Добавить перенаправления для "
"отсутствующих (404) страниц."
msgid "Fix 404 pages with URL redirects"
msgstr "Исправить ошибки 404 на переадресации"
msgid "Redirect ID"
msgstr "ID переадресации"
msgid "Redirect type"
msgstr "Тип перенаправления"
msgid "Hash"
msgstr "Хэш"
msgid "Asc"
msgstr "По возрастанию"
msgid "Master"
msgstr "Основной"
msgid "Redirect module form elements"
msgstr "Форма модуля перенаправлений"
msgid "Domain redirects"
msgstr "Переадресации домена"
msgid "From domain"
msgstr "С домена"
msgid "Add URL redirect"
msgstr "Добавить переадресацию"
msgid "URL Redirects"
msgstr "Перенаправления url-адресов"
msgid "Redirect settings"
msgstr "Настройка переадресации"
msgid "Original language"
msgstr "Язык оригинала"
msgid "The URL %url is not valid."
msgstr "URL %url не корректный."
msgid "With selection"
msgstr "С выделенным"
msgid "The redirect ID."
msgstr "ID переадресации."
msgid "The redirect language."
msgstr "Язык перенаправления."
msgid "Global redirects"
msgstr "Глобальные перенаправления"
msgid "Check access to the redirected page"
msgstr ""
"Проверять доступ к перенаправляемой "
"странице"
msgid "There is no redirect yet."
msgstr "Перенаправлений пока нет."
msgid ""
"Specify pages by using their paths. Enter one path per line. The '*' "
"character is a wildcard. An example path is %user-wildcard for every "
"user page. %front is the front page."
msgstr ""
"Укажите адреса страниц. Укажите по "
"одному адресу на строку. Знак '*' "
"означает любой набор символов после "
"него. Например, путь %user-wildcard страницы "
"всех пользователей. %front - главная "
"страница."
msgid "Deleted @count redirects."
msgstr "Удалено @count перенаправлений."
msgid "Are you sure you want to delete this redirect?"
msgid_plural "Are you sure you want to delete these redirects?"
msgstr[0] ""
"Действительно удалить это "
"перенаправление?"
msgstr[1] ""
"Действительно удалить эти "
"перенаправления?"
msgstr[2] ""
"Действительно удалить эти "
"перенаправления?"
msgid "Deleted 1 redirect."
msgid_plural "Deleted @count redirects."
msgstr[0] "Удалён @count перенаправление."
msgstr[1] "Удалено @count перенаправления."
msgstr[2] "Удалено @count перенаправлений."
msgid "Enforce clean and canonical URLs."
msgstr ""
"Использовать только чистые и "
"каноничные URL."
msgid "Sub path"
msgstr "Путь"
msgid "- All languages -"
msgstr "- Все языки -"
msgid "Ignore redirections on admin paths."
msgstr ""
"Игнорировать перенаправления на "
"административных страницах."
msgid "Daily count"
msgstr "Кол-во за день"
# Russian translation of Select 2 (2.0.0)
# Copyright (c) 2025 by the Russian translation team
#
msgid ""
msgstr ""
"Project-Id-Version: Select 2 (2.0.0)\n"
"POT-Creation-Date: 2025-01-09 21:18+0000\n"
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=((((n%10)==1)&&((n%100)!=11))?(0):(((((n%10)>=2)&&((n%10)<=4))&&(((n%100)<10)||((n%100)>=20)))?(1):2));\n"
msgid "User interface"
msgstr "Интерфейс пользователя"
msgid "On"
msgstr "Вкл"
msgid "Search"
msgstr "Поиск"
msgid "- None -"
msgstr "- Не указано -"
msgid "Off"
msgstr "Выкл"
msgid "Contains"
msgstr "Содержит"
msgid "unlimited"
msgstr "неограничено"
msgid "About"
msgstr "Информация"
msgid "- Select -"
msgstr "- Выберите -"
msgid "Number of results"
msgstr "Количество результатов"
msgid "Autocomplete matching"
msgstr "Совпадение автодополнения"
msgid "Starts with"
msgstr "Начинается с"
msgid "Autocomplete"
msgstr "Автодополнение"
msgid "@name field is required."
msgstr "Поле \"@name\" обязательно для заполнения."
msgid "Placeholder text"
msgstr "Текст заполнителя"
msgid ""
"Select the method used to collect autocomplete suggestions. Note that "
"<em>Contains</em> can cause performance issues on sites with thousands "
"of entities."
msgstr ""
"Выберите способ подбора подсказок "
"автодополнения. Обратите внимание, "
"что способ <em>Содержит</em> может "
"привести к проблемам со скоростью на "
"сайтах с тысячами сущностей."
msgid "Autocomplete matching: @match_operator"
msgstr "Автодополнение совпадает: @match_operator"
msgid "Select2 library found"
msgstr "Библиотека Select2 найдена"
msgid "Drag to re-order @entity_types."
msgstr ""
"Перетащите для изменения порядка для "
"\"@entity_types\"."
msgid "Maximum number of autocomplete suggestions."
msgstr ""
"Максимальное количество предложений "
"автозаполнения."
msgid ""
"The number of suggestions that will be listed. Use <em>0</em> to "
"remove the limit."
msgstr ""
"Количество предложений, которые будут "
"перечислены. Используйте <em>0</em>, чтобы "
"снять ограничение."
msgid "Autocomplete suggestion list size: @size"
msgstr "Число пунктов в автодополнении: @size"
# Russian translation of Slick Carousel (3.0.4)
# Copyright (c) 2024 by the Russian translation team
#
msgid ""
msgstr ""
"Project-Id-Version: Slick Carousel (3.0.4)\n"
"POT-Creation-Date: 2024-12-11 08:22+0000\n"
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=((((n%10)==1)&&((n%100)!=11))?(0):(((((n%10)>=2)&&((n%10)<=4))&&(((n%100)<10)||((n%100)>=20)))?(1):2));\n"
msgid "Title"
msgstr "Заголовок"
msgid "Previous"
msgstr "Назад"
msgid "Next"
msgstr "Вперёд"
msgid "Group"
msgstr "Группа"
msgid "List"
msgstr "Список"
msgid "Edit"
msgstr "Редактировать"
msgid "None"
msgstr "Нет"
msgid "- None -"
msgstr "- Не указано -"
msgid "Weight"
msgstr "Вес"
msgid "Settings"
msgstr "Настройки"
msgid "Name"
msgstr "Название"
msgid "Label"
msgstr "Метка"
msgid "Default"
msgstr "По умолчанию"
msgid "Top"
msgstr "Вверху"
msgid "Main"
msgstr "Основная"
msgid "ID"
msgstr "ID"
msgid "Options"
msgstr "Опции"
msgid "Vertical"
msgstr "Вертикально"
msgid "All"
msgstr "Все"
msgid "Thumbnail"
msgstr "Миниатюра"
msgid "Rows"
msgstr "Строки"
msgid "Randomize"
msgstr "Случайно"
msgid "Left"
msgstr "Слева"
msgid "Right"
msgstr "Справа"
msgid "Fade"
msgstr "Плавное появление"
msgid "RTL"
msgstr "RTL"
msgid "Autoplay"
msgstr "Автовоспроизведение"
msgid "Skin"
msgstr "Обложка"
msgid "Overlay"
msgstr "Перекрытие"
msgid "Pause on hover"
msgstr "Пауза при наведении курсора"
msgid "Accessibility"
msgstr "Доступность"
msgid "Speed"
msgstr "Скорость"
msgid "Draggable"
msgstr "Перетаскивание"
msgid "Infinite"
msgstr "Бесконечность"
msgid "Library"
msgstr "Библиотека"
msgid "override"
msgstr "переопределить"
msgid "Alt"
msgstr "Alt"
msgid "Dots"
msgstr "Точки"
msgid "UUID"
msgstr "UUID"
msgid "Use field template"
msgstr "Использовать шаблон поля"
msgid "Responsive settings"
msgstr "Адаптивные настройки"
msgid "Responsive"
msgstr "Адаптивный"
msgid "Use CSS"
msgstr "Использовать CSS"
msgid "Breakpoint"
msgstr "Точка останова"
msgid "Breakpoints"
msgstr "Точки останова"
msgid "Slick library"
msgstr "Библиотека Slick"
msgid "@name library installed at @path"
msgstr "Библиотека @name установлена в @path"
# Russian translation of Svg Image (3.2.1)
# Copyright (c) 2025 by the Russian translation team
#
msgid ""
msgstr ""
"Project-Id-Version: Svg Image (3.2.1)\n"
"POT-Creation-Date: 2025-01-14 14:42+0000\n"
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=((((n%10)==1)&&((n%100)!=11))?(0):(((((n%10)>=2)&&((n%10)<=4))&&(((n%100)<10)||((n%100)>=20)))?(1):2));\n"
msgid "Image"
msgstr "Изображение"
msgid "Width"
msgstr "Ширина"
msgid "Height"
msgstr "Высота"
msgid "Media"
msgstr "Мультимедиа"
msgid "URL to image"
msgstr "URL изображения"
msgid "Responsive image"
msgstr "Адаптивное изображение"
msgid "SVG Images dimensions (attributes)"
msgstr "Размеры SVG изображения (атрибуты)"
msgid ""
"Overrides the standard image formatter and widget to support SVG "
"files."
msgstr ""
"Переопределяет стандартные форматтер "
"и виджет изображения для поддержки SVG "
"файлов."
msgid "Render SVG image as &lt;img&gt;"
msgstr "Выводить SVG изображение как &lt;img&gt;"
msgid "Render SVG images as usual image in IMG tag instead of &lt;svg&gt; tag"
msgstr ""
"Выводить SVG изображения как обычное "
"изображение с помощью тега &lt;img&gt; "
"вместо &lt;svg&gt;"
msgid "Overrides the responsive image formatter to support SVG files."
msgstr ""
"Переопределяет отзывчивый форматтер "
"изображения для поддержки SVG файлов."
# Russian translation of Taxonomy access fix (4.0.2)
# Copyright (c) 2025 by the Russian translation team
#
msgid ""
msgstr ""
"Project-Id-Version: Taxonomy access fix (4.0.2)\n"
"POT-Creation-Date: 2025-01-10 11:46+0000\n"
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=((((n%10)==1)&&((n%100)!=11))?(0):(((((n%10)>=2)&&((n%10)<=4))&&(((n%100)<10)||((n%100)>=20)))?(1):2));\n"
msgid "Taxonomy"
msgstr "Таксономия"
msgid "Reset to alphabetical"
msgstr "Сортировать по алфавиту"
# Russian translation of Token (8.x-1.15)
# Copyright (c) 2025 by the Russian translation team
#
msgid ""
msgstr ""
"Project-Id-Version: Token (8.x-1.15)\n"
"POT-Creation-Date: 2025-01-05 10:42+0000\n"
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=((((n%10)==1)&&((n%100)!=11))?(0):(((((n%10)>=2)&&((n%10)<=4))&&(((n%100)<10)||((n%100)>=20)))?(1):2));\n"
msgid "Title"
msgstr "Заголовок"
msgid "Value"
msgstr "Значение"
msgid "Author"
msgstr "Автор"
msgid "Description"
msgstr "Описание"
msgid "Language"
msgstr "Язык"
msgid "Content types"
msgstr "Типы материалов"
msgid "Number"
msgstr "Число"
msgid "Parent"
msgstr "Родитель"
msgid "Parents"
msgstr "Родители"
msgid "Name"
msgstr "Название"
msgid "Book"
msgstr "Книга"
msgid "URL"
msgstr "URL"
msgid "Path"
msgstr "Путь"
msgid "Menu"
msgstr "Меню"
msgid "format"
msgstr "формат"
msgid "Content type"
msgstr "Тип материала"
msgid "The name of the menu."
msgstr "Имя меню."
msgid "Menu link"
msgstr "Ссылка меню"
msgid "Roles"
msgstr "Роли"
msgid "File size"
msgstr "Размер файла"
msgid "Count"
msgstr "Количество"
msgid "Width"
msgstr "Ширина"
msgid "Height"
msgstr "Высота"
msgid "Domain"
msgstr "Домен"
msgid "Last"
msgstr "Последний"
msgid "Arguments"
msgstr "Аргументы"
msgid "Random"
msgstr "Случайно"
msgid "Root"
msgstr "Корень"
msgid "Tokens"
msgstr "Токены"
msgid "Token"
msgstr "Токен"
msgid "Available tokens"
msgstr "Доступные токены"
msgid "First"
msgstr "Первый"
msgid "Reversed"
msgstr "Оборот"
msgid "URI"
msgstr "URI"
msgid "Menus"
msgstr "Меню"
msgid "Language code"
msgstr "Код языка"
msgid "Extension"
msgstr "Расширение"
msgid "Keys"
msgstr "Ключи"
msgid "Interface language"
msgstr "Язык интерфейса"
msgid "Node count"
msgstr "Количество материалов"
msgid "About"
msgstr "Информация"
msgid "Content language"
msgstr "Язык содержимого"
msgid "Path prefix"
msgstr "Префикс пути"
msgid "Direction"
msgstr "Направление"
msgid "IP address"
msgstr "IP-адрес"
msgid "Root term"
msgstr "Корневой термин"
msgid "Uses"
msgstr "Использование"
msgid "MIME type"
msgstr "MIME-тип"
msgid "Menu links"
msgstr "Ссылки меню"
msgid "Current date"
msgstr "Текущая дата"
msgid "Machine-readable name"
msgstr "Машинное имя"
msgid "Array"
msgstr "Массив"
msgid "Language name"
msgstr "Название языка"
msgid "Link ID"
msgstr "ID ссылки."
msgid "Base name"
msgstr "Основное имя"
msgid "Edit URL"
msgstr "Редактировать URL"
msgid "Revision log message"
msgstr "Сообщение в журнал о редакции"
msgid "No tokens available."
msgstr "Нет доступных токенов."
msgid "Click a token to insert it into the field you've last clicked."
msgstr ""
"Кликните для вставки токена в "
"последнее выбранное поле."
msgid "Translation source node"
msgstr "Перевод исходного материала"
msgid ""
"Provides a user interface for the Token API and some missing core "
"tokens."
msgstr ""
"Обеспечивает пользовательский "
"интерфейс для Token API и некоторые "
"пропущенные токены ядра."
msgid "Insert this token into your form"
msgstr "Вставить этот токен в вашу форму"
msgid "First click a text field to insert your tokens into."
msgstr ""
"Сначала кликните в текстовое поле, "
"чтобы вставить токены."
msgid "Current page"
msgstr "Текущая страница"
msgid "The explanation of the most recent changes made to the node."
msgstr ""
"Разъяснение самых последних "
"изменений, внесенных в материал."
msgid "The title of the current page."
msgstr "Заголовок текущей страницы."
msgid "The URL of the current page."
msgstr "URL текущей страницы."
msgid "The page number of the current page when viewing paged lists."
msgstr ""
"Номер текущей страницы при показе "
"списка страниц."
msgid "The source node for this current node's translation set."
msgstr ""
"Исходный материал для данного набора "
"переводов материала."
msgid "Account cancellation URL"
msgstr "URL аннулирования учётной записи"
msgid "The URL of the confirm delete page for the user account."
msgstr ""
"URL подтверждения удаления страницы "
"для пользовательской учётной записи."
msgid "One-time login URL"
msgstr "URL одноразового входа"
msgid "The URL of the one-time login page for the user account."
msgstr ""
"URL страницы одноразового входа для "
"пользовательской учётной записи."
msgid "Tokens related to menu links."
msgstr "Токены, связанные со ссылками меню."
msgid "The unique ID of the menu link."
msgstr "Уникальный ID ссылки меню."
msgid "The title of the menu link."
msgstr "Заголовок ссылки меню."
msgid "The URL of the menu link."
msgstr "URL ссылки меню."
msgid "The menu link's parent."
msgstr "Родитель ссылки меню."
msgid "Tokens related to the current page request."
msgstr ""
"Токены, связанные с запросом текущей "
"страницы."
msgid "Page number"
msgstr "Номер страницы"
msgid "The book page associated with the node."
msgstr ""
"Страница подшивки, связанная с этим "
"материалом."
msgid "The menu link for this node."
msgstr "Ссылка в меню для этого материала."
msgid "The menu link's root."
msgstr "Корень ссылки меню."
msgid "Hash"
msgstr "Хэш"
msgid "The extension of the file."
msgstr "Расширение файла."
msgid "Tokens related to the current date and time."
msgstr ""
"Токены, связанные с текущей датой и "
"временем."
msgid "The URL of the @entity."
msgstr "URL @entity."
msgid "The content type of the node."
msgstr "Тип этого материала."
msgid "Tokens related to content types."
msgstr "Токены, связанные с типами материалов."
msgid "The name of the content type."
msgstr "Имя типа материала."
msgid "The unique machine-readable name of the content type."
msgstr ""
"Уникальное машинное имя типа "
"материала."
msgid "The optional description of the content type."
msgstr ""
"Необязательное описание типа "
"содержимого."
msgid "The number of nodes belonging to the content type."
msgstr ""
"Количество материалов определенного "
"типа."
msgid "The URL of the content type's edit page."
msgstr ""
"URL страницы редактирования типа "
"содержимого"
msgid "The URL of the taxonomy term's edit page."
msgstr ""
"URL страницы редактирования термина "
"таксономии."
msgid "The unique machine-readable name of the vocabulary."
msgstr "Уникальное машинное имя словаря."
msgid "The URL of the vocabulary's edit page."
msgstr "URL страницы редактирования словаря."
msgid ""
"The specific argument of the current page (e.g. 'arg:1' on the page "
"'node/1' returns '1')."
msgstr ""
"Определенный аргумент текущей "
"страницы (например, 'arg:1' на странице "
"'node/5' вернет '5')."
msgid "Tokens related to URLs."
msgstr "Токены, связанные с URL."
msgid "Relative URL"
msgstr "Относительный URL"
msgid "The relative URL."
msgstr "Относительный URL-адрес."
msgid "Absolute URL"
msgstr "Абсолютный URL"
msgid "The absolute URL."
msgstr "Абсолютный URL-адрес."
msgid "Tokens related to menus."
msgstr "Токены, связанные с меню."
msgid "The unique machine-readable name of the menu."
msgstr "Уникальное машинное имя меню"
msgid "The optional description of the menu."
msgstr "Необязательное описание меню."
msgid "Menu link count"
msgstr "Счетчик ссылок меню"
msgid "The number of menu links belonging to the menu."
msgstr "Количество пунктов меню"
msgid "The URL of the menu's edit page."
msgstr "URL страницы редактирования меню."
msgid "The menu of the menu link."
msgstr "Меню, принадлежащее ссылке меню."
msgid "The URL of the menu link's edit page."
msgstr ""
"URL страницы редактирования ссылки "
"меню."
msgid "The user roles associated with the user account."
msgstr ""
"Роли, относящиеся к учётной записи "
"пользователя."
msgid "Brief URL"
msgstr "Короткий URL"
msgid "The URL without the protocol and trailing backslash."
msgstr "URL без протокола и закрывающего слэша"
msgid "Tokens related to arrays of strings."
msgstr "Токены, связанные с массивами строк."
msgid "The first element of the array."
msgstr "Первый элемент массива."
msgid "The last element of the array."
msgstr "Последний элемент массива."
msgid "The number of elements in the array."
msgstr "Количество элементов в массиве."
msgid "The array reversed."
msgstr "Массив пересортирован."
msgid "The array of keys of the array."
msgstr "Массив ключей массива."
msgid "Imploded"
msgstr "Разбито"
msgid ""
"The values of the array joined together with a custom string "
"in-between each value."
msgstr ""
"Значения массива объединились с "
"пользовательской строкой в/между "
"каждым значением."
msgid "A date in '@type' format. (%date)"
msgstr "Дата в формате '@type'. (%date)"
msgid "The root term of the taxonomy term."
msgstr ""
"Корневой термин дерева терминов "
"таксономии."
msgid "File byte size"
msgstr "Размер файла в байтах"
msgid "The size of the file, in bytes."
msgstr "Размер файла, в байтах."
msgid "Query string value"
msgstr "Значение строки запроса"
msgid "The value of a specific query string field of the current page."
msgstr ""
"Значение определенного поля строки "
"запроса текущей страницы."
msgid "A random number from 0 to @max."
msgstr "Случайное число от 0 до @max."
msgid "A random hash. The possible hashing algorithms are: @hash-algos."
msgstr ""
"Случайный хэш. Возможные алгоритмы "
"хэширования: @hash-algos."
msgid ""
"Attempting to perform token replacement for token type %type without "
"required data"
msgstr ""
"Попытка выполнить замену токена для "
"типа токенов %type без необходимой "
"информации"
msgid "@type field."
msgstr "Поле @type."
msgid "No tokens available"
msgstr "Нет доступных токенов"
msgid "Token registry caches cleared."
msgstr "Кэши реестра токенов очищены."
msgid "The path component of the URL."
msgstr "Компонент пути URL."
msgid "Unaliased URL"
msgstr "URL без синонима"
msgid "The unaliased URL."
msgstr "URL, лишенный синонима."
msgid "The specific value of the array."
msgstr "Определенное значение массива."
msgid ""
"The list of available tokens that can be used in e-mails is provided "
"below."
msgstr ""
"Список доступных токенов, которые "
"могут быть использованы в email-адресах, "
"представлены ниже."
msgid "An array of all the term's parents, starting with the root."
msgstr ""
"Массив всех родительских терминов "
"таксономии, начиная с корневого."
msgid "An array of all the menu link's parents, starting with the root."
msgstr ""
"Массив всех родительских ссылок меню, "
"начиная с корневой."
msgid "Original @entity"
msgstr "Первоначальный @entity"
msgid "The original @entity data if the @entity is being updated or saved."
msgstr ""
"Оригинальный @entity, когда @entity "
"обновляется или сохраняется."
msgid "The base name of the file."
msgstr "Основное имя файла."
msgid "This field supports tokens."
msgstr "Это поле поддерживает токены."
msgid "List of @type values"
msgstr "Список значений @type"
msgid "Tokens for lists of @type values."
msgstr "Токены для списков значений @type."
msgid "Browse available tokens."
msgstr "Просмотр доступных токенов."
msgid ""
"Available variables are: [site:name], [site:url], [user:display-name], "
"[user:account-name], [user:mail], [site:login-url], [site:url-brief], "
"[user:edit-url], [user:one-time-login-url], [user:cancel-url]."
msgstr ""
"Допустимые переменные: [site:name], [site:url], "
"[user:display-name], [user:account-name], [user:mail], "
"[site:login-url], [site:url-brief], [user:edit-url], "
"[user:one-time-login-url], [user:cancel-url]."
msgid "The language code."
msgstr "Код языка."
msgid "@type field. Also known as %labels."
msgstr "Поле @type. Также известное как %labels."
msgid "Tokens or token types not defined as arrays"
msgstr ""
"Токены или типы токенов, не являющиеся "
"массивами."
msgid "Tokens or token types missing name property"
msgstr ""
"У токенов или типов токенов "
"отсутствует название."
msgid "Token types do not have any tokens defined"
msgstr ""
"Для типов токенов не задано ни одного "
"токена."
msgid "Token types are not defined but have tokens"
msgstr ""
"Типы токенов не определены, но имеют "
"токены"
msgid "Token or token types are defined by multiple modules"
msgstr ""
"Токен или тип токена задан в "
"нескольких модулях."
msgid "Image with image style"
msgstr "Изображение со стилем"
msgid "The MIME type (image/png, image/bmp, etc.) of the image."
msgstr "Тип MIME (image/png, image/bmp и т.п.) изображения."
msgid "The file size of the image."
msgstr "Размер файла изображения"
msgid "The height the image, in pixels."
msgstr "Высота изображения, в пикселях."
msgid "The width of the image, in pixels."
msgstr "Ширина изображения, в пикселях."
msgid "The URI to the image."
msgstr "URI изображения."
msgid "The URL to the image."
msgstr "URL изображения."
msgid "@label tokens."
msgstr "@label токены."
msgid "Represents the image in the given image style."
msgstr ""
"Представляет изображение в данном "
"стиле."
msgid ""
"The <a href=\":project\">Token</a> module provides a user interface "
"for the site token system. It also adds some additional tokens that "
"are used extensively during site development. Tokens are specially "
"formatted chunks of text that serve as placeholders for a dynamically "
"generated value. For more information, covering both the token system "
"and the additional tools provided by the Token module, see the <a "
"href=\":online\">online documentation</a>."
msgstr ""
"Модуль <a href=\":project\">Token</a> предоставляет "
"пользовательский интерфейс для "
"системы токенов. Он также добавляет "
"токены, которые широко используются "
"при разработке сайта. Токены - это "
"специально отформатированные "
"фрагменты текста, которые служат "
"заполнителями для динамически "
"генерируемого значения. Для получения "
"дополнительной информации, "
"касающейся как системы токенов, так и "
"дополнительных инструментов, "
"предоставляемых модулем Token, смотрите "
"<a href=\":online\">онлайн-документацию</a>."
msgid ""
"Your website uses a shared token system for exposing and using "
"placeholder tokens and their appropriate replacement values. This "
"allows for any module to provide placeholder tokens for strings "
"without having to reinvent the wheel. It also ensures consistency in "
"the syntax used for tokens, making the system as a whole easier for "
"end users to use."
msgstr ""
"Ваш сайт использует общую систему для "
"предоставления токенов и "
"использования их значений. Это "
"позволяет любому модулю "
"предоставлять токены без "
"необходимости изобретать велосипед. "
"Это также обеспечивает "
"согласованность синтаксиса, "
"используемого для токенов, что "
"упрощает использование системы в "
"целом конечными пользователями."
msgid ""
"The list of the currently available tokens on this site are shown "
"below."
msgstr ""
"Список доступных в данный момент на "
"этом сайте токенов приведен ниже."
msgid "%name is using the following invalid tokens: @invalid-tokens."
msgstr ""
"%name использует следующие недопустимые "
"токены: @invalid-tokens."
msgid "Computed menu link for the node (only available during node saving)."
msgstr ""
"Вычисленная ссылка на меню для "
"материала (доступна только во время "
"сохранения материала)."
msgid "%name must contain at least one token."
msgid_plural "%name must contain at least @count tokens."
msgstr[0] ""
"%name должен содержать хотя бы один "
"токен."
msgstr[1] ""
"%name должен содержать хотя бы @count "
"токена."
msgstr[2] ""
"%name должен содержать хотя бы @count "
"токенов."
msgid "%name must contain at most one token."
msgid_plural "%name must contain at most @count tokens."
msgstr[0] ""
"%name должен содержать не более одного "
"токена."
msgstr[1] ""
"%name должно содержать не более @count "
"токенов."
msgstr[2] ""
"%name должно содержать не более @count "
"токенов."
msgid "Tokens related to books."
msgstr "Токены, связанные с книгами."
msgid "Title of the book."
msgstr "Название книги."
msgid "The author of the book."
msgstr "Автор книги."
msgid "Top level of the book."
msgstr "Верхний уровень книги."
msgid "Parent of the current page."
msgstr "Родитель текущей страницы."
msgid "An array of all the node's parents, starting with the root."
msgstr ""
"Массив всех родителей материала, "
"начиная с корневого."
msgid "This field supports tokens. @browse_tokens_link"
msgstr ""
"Это поле поддерживает токены. "
"@browse_tokens_link"
msgid "Tokens related to random data."
msgstr ""
"Токены, связанные со случайными "
"данными."
msgid "The IP address of the current user."
msgstr "IP адрес текущего пользователя."
msgid "The language of the @entity."
msgstr "Язык @entity."
msgid "Tokens related to site language."
msgstr "Токены, связанные с языком сайта."
msgid "The language name."
msgstr "Название языка."
msgid ""
"Whether the language is written left-to-right (ltr) or right-to-left "
"(rtl)."
msgstr ""
"Написание в языке слева-на-право (ltr) "
"или справа-на-лево (rtl)."
msgid "The domain name to use for the language."
msgstr "Название домена для языка."
# Russian translation of Twig Tweak (3.4.1)
# Copyright (c) 2025 by the Russian translation team
#
msgid ""
msgstr ""
"Project-Id-Version: Twig Tweak (3.4.1)\n"
"POT-Creation-Date: 2025-05-29 21:34+0000\n"
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=((((n%10)==1)&&((n%100)!=11))?(0):(((((n%10)>=2)&&((n%10)<=4))&&(((n%100)<10)||((n%100)>=20)))?(1):2));\n"
msgid "Provides some extra Twig functions and filters."
msgstr ""
"Обеспечивает некоторые "
"дополнительные функции и фильтры "
"твига."
# Russian translation of Ultimate Cron (8.x-2.0-beta1)
# Copyright (c) 2024 by the Russian translation team
#
msgid ""
msgstr ""
"Project-Id-Version: Ultimate Cron (8.x-2.0-beta1)\n"
"POT-Creation-Date: 2024-11-29 04:14+0000\n"
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=((((n%10)==1)&&((n%100)!=11))?(0):(((((n%10)>=2)&&((n%10)<=4))&&(((n%100)<10)||((n%100)>=20)))?(1):2));\n"
msgid "Title"
msgstr "Заголовок"
msgid "Status"
msgstr "Статус"
msgid "Enable"
msgstr "Включить"
msgid "Disable"
msgstr "Отключить"
msgid "Disabled"
msgstr "Отключено"
msgid "Enabled"
msgstr "Включено"
msgid "Logs"
msgstr "Системные журналы"
msgid "Message"
msgstr "Сообщение"
msgid "Weight"
msgstr "Вес"
msgid "Name"
msgstr "Название"
msgid "Time"
msgstr "Время"
msgid "ID"
msgstr "ID"
msgid "User"
msgstr "Пользователь"
msgid "Database"
msgstr "База данных"
msgid "Module"
msgstr "Модуль"
msgid "Never"
msgstr "Никогда"
msgid "Throttle"
msgstr "Регулятор"
msgid "Severity"
msgstr "Важность"
msgid "N/A"
msgstr "Н/Д"
msgid "Serial"
msgstr "Последовательность"
msgid "Method"
msgstr "Метод"
msgid "Cache"
msgstr "Кэш"
msgid "Cron settings"
msgstr "Настройки cron"
msgid "anonymous"
msgstr "аноним"
msgid "Expiration"
msgstr "Срок действия"
msgid "Duration"
msgstr "Продолжительность"
msgid "Threshold"
msgstr "Пороговое значение"
msgid "Rules"
msgstr "Правила"
msgid "Start Time"
msgstr "Время начала"
msgid "End Time"
msgstr "Время окончания"
msgid "Missing"
msgstr "Отсутствует"
msgid "Cron"
msgstr "Cron"
msgid "by"
msgstr "автор"
msgid "Run"
msgstr "Запустить"
msgid "Select"
msgstr "Выбрать"
msgid "Simple"
msgstr "Простой"
msgid "Thread"
msgstr "Тема обсуждения"
msgid "Last Run"
msgstr "Последний запуск"
msgid "Check for updates"
msgstr "Проверка обновлений"
msgid "Started"
msgstr "Начало"
msgid "Time until expiration"
msgstr "Время до истечения срока"
msgid "Run cron"
msgstr "Запустить cron"
msgid "Queue"
msgstr "Очередь"
msgid "Scheduled"
msgstr "Запланировано"
msgid "Callback"
msgstr "Обратный вызов"
msgid "Machine-readable name"
msgstr "Машинное имя"
msgid "Update translations"
msgstr "Обновить переводы"
msgid "Module Name"
msgstr "Имя модуля"
msgid "Unlock"
msgstr "Разблокировать"
msgid ""
"This will appear in the administrative interface to easily identify "
"it."
msgstr ""
"Это будет отображаться в интерфейсе "
"администратора, чтобы легко "
"идентифицировать."
msgid "Run cron every"
msgstr "Запускать cron каждые"
msgid "Remove expired log messages and flood control events"
msgstr ""
"Удалите просроченные сообщения "
"журнала и события контроля флуда"
msgid "@count job is behind schedule"
msgid_plural "@count jobs are behind schedule"
msgstr[0] "@count задание отстаёт от графика"
msgstr[1] "@count задания отстаёт от графика"
msgstr[2] "@count заданий отстаёт от графика"
msgid "@name not found"
msgstr "@name не найдено"
msgid ""
"Some jobs are behind their schedule. Please check if <a "
"href=\":system_cron_url\">Cron</a> is running properly."
msgstr ""
"Некоторые задания отстают от графика. "
"Пожалуйста, проверьте, правильно ли "
"работает <a href=\":system_cron_url\">Cron</a>."
# Russian translation of Upgrade Status (4.3.8)
# Copyright (c) 2025 by the Russian translation team
#
msgid ""
msgstr ""
"Project-Id-Version: Upgrade Status (4.3.8)\n"
"POT-Creation-Date: 2025-07-02 19:46+0000\n"
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=((((n%10)==1)&&((n%100)!=11))?(0):(((((n%10)>=2)&&((n%10)<=4))&&(((n%100)<10)||((n%100)>=20)))?(1):2));\n"
msgid "Status"
msgstr "Статус"
msgid "Type"
msgstr "Тип"
msgid "Remove"
msgstr "Удалить"
msgid "Administration"
msgstr "Администрирование"
msgid "Project"
msgstr "Проект"
msgid "Update"
msgstr "Обновить"
msgid "read more"
msgstr "подробнее"
msgid "Error"
msgstr "Ошибка"
msgid "Check manually"
msgstr "Проверить вручную"
msgid "Up to date"
msgstr "Актуально"
msgid "File name"
msgstr "Имя файла"
msgid "N/A"
msgstr "Н/Д"
msgid "Line"
msgstr "Линия"
msgid "Ignore"
msgstr "Игнорировать"
msgid "Installed"
msgstr "Установлено"
msgid "Unavailable"
msgstr "Недоступно"
msgid "About"
msgstr "Информация"
msgid "Scan"
msgstr "Сканировать"
msgid "Error message"
msgstr "Сообщение об ошибке"
msgid "Not applicable"
msgstr "Не применимо"
msgid "LINE"
msgstr "ЛИНИЯ"
msgid "Export as HTML"
msgstr "Экспорт в HTML"
msgid "Unchecked"
msgstr "Невыбранный"
msgid "Uninstalled"
msgstr "Удалено"
msgid "Compatible"
msgstr "Совместимость"
msgid "Scanning projects"
msgstr "Сканирование проектов"
msgid "Analysis complete for @project."
msgstr "Выполнен анализ для @project."
# Russian translation of Video Embed Field (3.0.0-beta2)
# Copyright (c) 2025 by the Russian translation team
#
msgid ""
msgstr ""
"Project-Id-Version: Video Embed Field (3.0.0-beta2)\n"
"POT-Creation-Date: 2025-05-13 09:42+0000\n"
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=((((n%10)==1)&&((n%100)!=11))?(0):(((((n%10)>=2)&&((n%10)<=4))&&(((n%100)<10)||((n%100)>=20)))?(1):2));\n"
msgid "Content"
msgstr "Содержимое"
msgid "- None -"
msgstr "- Не указано -"
msgid "Settings"
msgstr "Настройки"
msgid "Save"
msgstr "Сохранить"
msgid "Default Settings"
msgstr "Настройки по умолчанию"
msgid "Width"
msgstr "Ширина"
msgid "Height"
msgstr "Высота"
msgid "Thumbnail"
msgstr "Миниатюра"
msgid "Defaults"
msgstr "По умолчанию"
msgid "Video"
msgstr "Видео"
msgid "Autoplay"
msgstr "Автовоспроизведение"
msgid "Children"
msgstr "Потомки"
msgid "About"
msgstr "Информация"
msgid "YouTube"
msgstr "YouTube"
msgid "Vimeo"
msgstr "Vimeo"
msgid "Video URL"
msgstr "URL-адрес видео"
msgid "Link image to"
msgstr "Изображение как ссылка на"
msgid "Image Style"
msgstr "Стиль изображения"
msgid "Responsive"
msgstr "Адаптивный"
msgid "Provider URL"
msgstr "URL источника"
# Russian translation of Views Aggregator Plus (2.1.1)
# Copyright (c) 2024 by the Russian translation team
#
msgid ""
msgstr ""
"Project-Id-Version: Views Aggregator Plus (2.1.1)\n"
"POT-Creation-Date: 2024-11-09 04:14+0000\n"
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=((((n%10)==1)&&((n%100)!=11))?(0):(((((n%10)>=2)&&((n%10)<=4))&&(((n%100)<10)||((n%100)>=20)))?(1):2));\n"
msgid "None"
msgstr "Нет"
msgid "Field"
msgstr "Поле"
msgid "Views"
msgstr "Представление"
msgid "Aggregation"
msgstr "Сбор новостей"
msgid "Separator"
msgstr "Разделитель"
msgid "Maximum"
msgstr "Максимум"
msgid "Sortable"
msgstr "Может быть отсортирован"
msgid "Align"
msgstr "Выравнивание"
msgid "Position"
msgstr "Позиция"
msgid "Percentage"
msgstr "Процент"
msgid "Minimum"
msgstr "Минимум"
msgid "Precision"
msgstr "Точность"
msgid "Default order"
msgstr "Порядок по умолчанию"
msgid "Default sort"
msgstr "Сортировка по умолчанию"
msgid "Parameter"
msgstr "Параметр"
msgid "Sum"
msgstr "Сумма"
msgid "100%"
msgstr "100%"
msgid "Hide empty column"
msgstr "Скрыть пустую колонку"
msgid "Responsive"
msgstr "Адаптивный"
msgid "Columns info"
msgstr "Информация о столбцах"
msgid "Column info"
msgstr "Информация о столбце"
# Russian translation of Views Bulk Operations (VBO) (4.3.4)
# Copyright (c) 2025 by the Russian translation team
#
msgid ""
msgstr ""
"Project-Id-Version: Views Bulk Operations (VBO) (4.3.4)\n"
"POT-Creation-Date: 2025-03-10 11:46+0000\n"
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=((((n%10)==1)&&((n%100)!=11))?(0):(((((n%10)>=2)&&((n%10)<=4))&&(((n%100)<10)||((n%100)>=20)))?(1):2));\n"
msgid "Title"
msgstr "Заголовок"
msgid "Cancel"
msgstr "Отмена"
msgid "Action"
msgstr "Действие"
msgid "Weight"
msgstr "Вес"
msgid "Default"
msgstr "По умолчанию"
msgid "Views"
msgstr "Представление"
msgid "Access denied"
msgstr "Доступ запрещён"
msgid "No items selected."
msgstr "Нет выбранных элементов."
msgid "Apply"
msgstr "Применить"
msgid "Examples"
msgstr "Примеры"
msgid "Batch size"
msgstr "Размер пакета"
msgid "(any)"
msgstr "(любой)"
msgid "NOTE"
msgstr "ВНИМАНИЕ"
msgid "Skipped"
msgstr "Пропущено"
msgid "Views Bulk Operations"
msgstr "Массовые операции"
msgid "No items"
msgstr "Без элементов"
msgid "Clear selection"
msgstr "Очистить выделение"
msgid "Cancelling user account"
msgstr ""
"Удаление пользовательской учётной "
"записи"
msgid "Cancel the selected user accounts"
msgstr "Удалить выбранные учётные записи"
msgid "When cancelling these accounts"
msgstr "При удалении данных учётных записей"
msgid "Override label"
msgstr "Перезаписать метку"
msgid "Example setting"
msgstr "Настройка образца"
msgid "Delete entities"
msgstr "Удалить сущности"
msgid "Selected actions"
msgstr "Выбранные действия"
msgid "Delete translations"
msgstr "Удалить переводы"
msgid "Action title"
msgstr "Заголовок действия"
msgid "The title shown above the actions dropdown."
msgstr ""
"Заголовок, показанный над списком "
"действий."
msgid ""
"When enabled, the user must confirm the account cancellation via "
"email."
msgstr ""
"Когда включено, пользователь должен "
"подтвердить отмену учётной записи по "
"электронной почте."
msgid ""
"When enabled, the user will receive an email notification after the "
"account has been canceled."
msgstr ""
"Если включено, пользователь получит "
"уведомление по электронной почте "
"после удаления учётной записи."
msgid "Notify user when account is canceled"
msgstr ""
"Уведомить пользователя когда учётная "
"запись будет удалена."
msgid "Require email confirmation to cancel account"
msgstr ""
"Требовать подтверждение по "
"электронной почте при удалении "
"учётной записи"
msgid "Apply to selected items"
msgstr "Применить к отмеченным позициям"
msgid "Views bulk operations"
msgstr "Массовые операции"
msgid ""
"Adds an ability to perform bulk operations on selected entities from "
"view results."
msgstr ""
"Добавляет возможность выполнения "
"массовых операций над выбранными в "
"представлении сущностями."
msgid "Views Bulk Operations example"
msgstr "Views Bulk Operations пример"
msgid "Defines an example action with all possible options."
msgstr ""
"Определяет пример действия со всеми "
"возможными опциями."
msgid "Example setting pre-execute"
msgstr "Предварительный пример настройки"
msgid "Configure \"%action\" action applied to the selection"
msgstr ""
"Настроить действие \"%action\", "
"применяемое к выделенным элементам"
msgid "Execute action"
msgstr "Выполнить действие"
msgid "Process in a batch operation"
msgstr "Выполнять в пакетном режиме"
msgid "Only applicable if results are processed in a batch operation."
msgstr ""
"Применимо только в том случае, если "
"результаты обрабатываются в пакетном "
"режиме."
msgid "Configuration form on new page (configurable actions)"
msgstr ""
"Форма конфигурации на новой странице "
"(настраиваемые действия)"
msgid "Preconfiguration for \"@action\""
msgstr "Предварительная настройка для \"@action\""
msgid "Leave empty for the default label."
msgstr ""
"Оставьте пустым для метки "
"по-умолчанию."
msgid "-- Select action --"
msgstr "-- Выберите действие --"
msgid "Please select an action to perform."
msgstr "Выберите действие для выполнения."
msgid "Form error occurred, please try again."
msgstr "Произошла ошибка, попытайтесь снова."
msgid "Entity type not supported"
msgstr "Тип сущности не поддерживается"
msgid "Process selected entities in a batch operation"
msgstr ""
"Обработка выбранных сущностей в "
"пакетной операции"
msgid "Size of the processing batch"
msgstr "Размер партии обработки"
msgid "Display configuration form on a separate page"
msgstr ""
"Показать форму конфигурации на "
"отдельной странице"
msgid "Title of the action selector form element"
msgstr ""
"Заголовок элемента формы выбора "
"действия"
msgid "Actions Permissions"
msgstr "Права доступа к действиям"
msgid ""
"Adds access permissions on all actions allowing admins to restrict "
"access on a per-role basis."
msgstr ""
"Добавляет права доступа ко всем "
"действиям, позволяя администраторам "
"ограничивать доступ для каждой роли."
msgid "all entity types"
msgstr "все типы сущностей"
msgid "Execute the %action action on %type."
msgstr "Выполнить %action действие для %type."
msgid "Are you sure you wish to perform \"%action\" action on 1 entity?"
msgid_plural ""
"Are you sure you wish to perform \"%action\" action on %count "
"entities?"
msgstr[0] ""
"Выполнить действие \"%action\" для 1 "
"объекта?"
msgstr[1] ""
"Выполнить действие \"%action\" для %count "
"объектов?"
msgstr[2] ""
"Выполнить действие \"%action\" для %count "
"объектов?"
msgid "Display action options as buttons"
msgstr "Показать опции действий как кнопки"
msgid "Select / deselect all"
msgstr "Выбрать / отменить выбор всего"
msgid "Display selectable actions as buttons."
msgstr ""
"Показать выбираемые действия как "
"кнопки"
msgid "Initialization time: @time ms."
msgstr "Время инициализации: @time мс."
msgid "Entity list generation time: @time ms."
msgstr ""
"Время генерации списка сущностей: @time "
"мс."
msgid "Execution time: @time ms."
msgstr "Время выполения: @time мс."
msgid "Clear selection when exposed filters change."
msgstr ""
"Очистить выбор при изменении "
"фильтров."
msgid "Canceled \"%action\"."
msgstr "Отменено \"%action\"."
msgid "Clear selection when exposed filters change"
msgstr ""
"Очистить выбор при изменении открытых "
"фильтров"
msgid "..plus @count more.."
msgstr "..плюс ещё @count.."
msgid "Selected actions data array"
msgstr "Массив данных выбранных действий"
msgid "Form error occurred, Unavailable action selected."
msgstr ""
"Произошла ошибка формы. Выбрано "
"недоступное действие."
msgid "Delete selected entities / translations"
msgstr "Удалить выбранные объекты/переводы"
msgid "Items selected:"
msgstr "Выбранные элементы:"
msgid "Selected all items except:"
msgstr "Выбраны все элементы, кроме:"
msgid "Always show selection info"
msgstr "Всегда показывать информацию о выборе"
msgid ""
"Should the selection info fieldset be shown above the view even if "
"there is only one page of results and full selection can be seen in "
"the view itself?"
msgstr ""
"Следует ли отображать набор полей с "
"информацией о выборе над "
"представлением, даже если имеется "
"только одна страница результатов и "
"полный выбор можно увидеть в самом "
"представлении?"
msgid "Add confirmation step"
msgstr "Добавить этап подтверждения"
msgid "Should the selection information always be displayed?"
msgstr ""
"Всегда ли должна отображаться "
"информация о выборе?"
msgid "Select / deselect all results (all pages, @count total)"
msgstr ""
"Выбрать/отменить выбор всех "
"результатов (все страницы, всего @count)"
msgid "Should a confirmation step be added?"
msgstr "Стоит ли добавить этап подтверждения?"
msgid "Action label override"
msgstr "Переопределение метки действия"
msgid "Configuration array for the plugin"
msgstr "Массив конфигурации для плагина"
msgid "Example preliminary configuration"
msgstr "Пример предварительной конфигурации"
msgid "No items selected. Go back and try again."
msgstr ""
"Ни один элемент не выбран. Вернитесь и "
"попробуйте еще раз."
msgid "Action will be executed on all items in the view."
msgstr ""
"Действие будет выполнено для всех "
"элементов представления."
msgid "Access denied: @reason"
msgstr "Нет доступа: @reason"
msgid "Selected 1 item"
msgid_plural "Selected @count items"
msgstr[0] "Выбран 1 элемент"
msgstr[1] "Выбрано @count элемента"
msgstr[2] "Выбрано @count элементов"
# Russian translation of Webform (6.3.0-beta4)
# Copyright (c) 2025 by the Russian translation team
#
msgid ""
msgstr ""
"Project-Id-Version: Webform (6.3.0-beta4)\n"
"POT-Creation-Date: 2025-07-29 20:35+0000\n"
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=((((n%10)==1)&&((n%100)!=11))?(0):(((((n%10)>=2)&&((n%10)<=4))&&(((n%100)<10)||((n%100)>=20)))?(1):2));\n"
msgid "Forms"
msgstr "Формы"
msgid "Home"
msgstr "Главная"
msgid "Title"
msgstr "Заголовок"
msgid "Body"
msgstr "Содержимое"
msgid "Images"
msgstr "Изображения"
msgid "Pages"
msgstr "Страницы"
msgid "Save configuration"
msgstr "Сохранить конфигурацию"
msgid "enabled"
msgstr "включено"
msgid "delete"
msgstr "удалить"
msgid "Status"
msgstr "Статус"
msgid "Register"
msgstr "Регистрация"
msgid "Suffix"
msgstr "Суффикс"
msgid "Delete"
msgstr "Удалить"
msgid "Submit"
msgstr "Отправить"
msgid "Operations"
msgstr "Операции"
msgid "Content"
msgstr "Содержимое"
msgid "Value"
msgstr "Значение"
msgid "Username"
msgstr "Имя пользователя"
msgid "Item"
msgstr "Элемент"
msgid "Private"
msgstr "Приватный"
msgid "Development"
msgstr "Разработка"
msgid "Groups"
msgstr "Группы"
msgid "Type"
msgstr "Тип"
msgid "Author"
msgstr "Автор"
msgid "Closed"
msgstr "Закрыто"
msgid "List"
msgstr "Список"
msgid "Subject"
msgstr "Тема"
msgid "Send email"
msgstr "Отправить письмо"
msgid "closed"
msgstr "закрыто"
msgid "Actions"
msgstr "Действия"
msgid "Email notification"
msgstr "Уведомления по email"
msgid "disabled"
msgstr "отключено"
msgid "Cancel"
msgstr "Отмена"
msgid "Remove"
msgstr "Удалить"
msgid "Subscribe"
msgstr "Подписаться"
msgid "Manager"
msgstr "Менеджер"
msgid "Description"
msgstr "Описание"
msgid "Language"
msgstr "Язык"
msgid "Log"
msgstr "Журнал"
msgid "Enable"
msgstr "Включить"
msgid "Disable"
msgstr "Отключить"
msgid "optional"
msgstr "опционально"
msgid "required"
msgstr "обязательно"
msgid "Email settings"
msgstr "Настройки электронной почты"
msgid "Disabled"
msgstr "Отключено"
msgid "Enabled"
msgstr "Включено"
msgid "Administration"
msgstr "Администрирование"
msgid "More"
msgstr "Ещё"
msgid "Action"
msgstr "Действие"
msgid "On"
msgstr "Вкл"
msgid "error"
msgstr "ошибка"
msgid "Tags"
msgstr "Теги"
msgid "Yes"
msgstr "Да"
msgid "No"
msgstr "Нет"
msgid "Homepage"
msgstr "Домашняя страница"
msgid "License"
msgstr "Лицензия"
msgid "Resources"
msgstr "Ресурсы"
msgid "Categories"
msgstr "Категории"
msgid "Download"
msgstr "Скачать"
msgid "Version"
msgstr "Версия"
msgid "view"
msgstr "представление"
msgid "updated"
msgstr "обновлено"
msgid "created"
msgstr "создано"
msgid "all"
msgstr "все"
msgid "File"
msgstr "Файл"
msgid "Edit"
msgstr "Редактировать"
msgid "Date"
msgstr "Дата"
msgid "Size"
msgstr "Размер"
msgid "Search"
msgstr "Поиск"
msgid "Reset"
msgstr "Сбросить"
msgid "None"
msgstr "Нет"
msgid "This action cannot be undone."
msgstr "Это действие нельзя отменить."
msgid "Test"
msgstr "Тест"
msgid "Number"
msgstr "Число"
msgid "Message"
msgstr "Сообщение"
msgid "No log messages available."
msgstr "В системном журнале нет сообщений."
msgid "Password"
msgstr "Пароль"
msgid "- None -"
msgstr "- Не указано -"
msgid "Country"
msgstr "Страна"
msgid "Weight"
msgstr "Вес"
msgid "B"
msgstr "Б"
msgid "Link"
msgstr "Ссылка"
msgid "Image"
msgstr "Изображение"
msgid "Break"
msgstr "перерыв"
msgid "Container"
msgstr "Контейнер"
msgid "Help text"
msgstr "Справочный текст"
msgid "Admin title"
msgstr "Административный заголовок"
msgid "Types"
msgstr "Типы"
msgid "Multiple"
msgstr "Множественная"
msgid "Required"
msgstr "Обязательно"
msgid "Parent"
msgstr "Родитель"
msgid "none"
msgstr "нет"
msgid "Category"
msgstr "Категория"
msgid "Containers"
msgstr "Контейнеры"
msgid "Settings"
msgstr "Настройки"
msgid "One"
msgstr "Один"
msgid "Name"
msgstr "Название"
msgid "Go to previous page"
msgstr "На предыдущую страницу"
msgid "Go to next page"
msgstr "На следующую страницу"
msgid "Import"
msgstr "Импортировать"
msgid "Export"
msgstr "Экспортировать"
msgid "General settings"
msgstr "Основные настройки"
msgid "Field"
msgstr "Поле"
msgid "Label"
msgstr "Метка"
msgid "Preview"
msgstr "Предпросмотр"
msgid "Save"
msgstr "Сохранить"
msgid "Help"
msgstr "Справка"
msgid "Image settings"
msgstr "Настройки изображений"
msgid "Default"
msgstr "По умолчанию"
msgid "Summary"
msgstr "Сводка"
msgid "Download PDF"
msgstr "Скачать PDF"
msgid "Update"
msgstr "Обновить"
msgid "Open"
msgstr "Открыть"
msgid "Sunday"
msgstr "воскресенье"
msgid "Monday"
msgstr "понедельник"
msgid "Tuesday"
msgstr "вторник"
msgid "Wednesday"
msgstr "среда"
msgid "Thursday"
msgstr "четверг"
msgid "Friday"
msgstr "пятница"
msgid "Saturday"
msgstr "суббота"
msgid "Archive"
msgstr "Архив"
msgid "Time"
msgstr "Время"
msgid "Access"
msgstr "Доступ"
msgid "Add"
msgstr "Добавить"
msgid "View"
msgstr "Просмотр"
msgid "hidden"
msgstr "скрыто"
msgid "URL"
msgstr "URL"
msgid "Dimensions"
msgstr "Размеры"
msgid "API"
msgstr "API"
msgid "Section"
msgstr "Раздел"
msgid "Manage"
msgstr "Управление"
msgid "Visible"
msgstr "Видимый"
msgid "link"
msgstr "ссылка"
msgid "Display"
msgstr "Отображение"
msgid "Advanced settings"
msgstr "Расширенные настройки"
msgid "Teaser"
msgstr "Анонс"
msgid "Notes"
msgstr "Примечания"
msgid "Updated"
msgstr "Обновлено"
msgid "Text"
msgstr "Текст"
msgid "Total"
msgstr "Итого"
msgid "Status:"
msgstr "Состояние:"
msgid "Submitted by"
msgstr "Добавлено пользователем"
msgid "ID"
msgstr "ID"
msgid "Default status"
msgstr "Состояние по умолчанию"
msgid "#"
msgstr "#"
msgid "Issue"
msgstr "Проблема"
msgid "States"
msgstr "Состояния"
msgid "Upload"
msgstr "Закачать"
msgid "Titles"
msgstr "Названия"
msgid "Mail"
msgstr "Почта"
msgid "Before"
msgstr "До"
msgid "After"
msgstr "После"
msgid "User"
msgstr "Пользователь"
msgid "Content type"
msgstr "Тип материала"
msgid "Continue"
msgstr "Продолжить"
msgid "Email"
msgstr "Email"
msgid "Error"
msgstr "Ошибка"
msgid "Options"
msgstr "Опции"
msgid "Contact"
msgstr "Контакт"
msgid "Created"
msgstr "Создано"
msgid "Node"
msgstr "Материал"
msgid "Add page"
msgstr "Добавить страницу"
msgid "Link Title"
msgstr "Заголовок ссылки"
msgid "Expanded"
msgstr "Развёрнутый"
msgid "All"
msgstr "Все"
msgid "Default settings"
msgstr "Настройки по умолчанию"
msgid "days"
msgstr "дней"
msgid "To:"
msgstr "Кому:"
msgid "Active"
msgstr "Активно"
msgid "submit"
msgstr "отправить"
msgid "Access denied"
msgstr "Доступ запрещён"
msgid "Year"
msgstr "Год"
msgid "Date format"
msgstr "Формат даты"
msgid "General information"
msgstr "Общая информация"
msgid "Page"
msgstr "Страница"
msgid "View arguments"
msgstr "Аргументы представления"
msgid "Submission information"
msgstr "Информация об отправлении"
msgid "Breadcrumb"
msgstr "Строка навигации"
msgid "User settings"
msgstr "Настройки пользователя"
msgid "Database"
msgstr "База данных"
msgid "Url"
msgstr "Url-адрес"
msgid "PHP"
msgstr "PHP"
msgid "Off"
msgstr "Выкл"
msgid "Ignored"
msgstr "Проигнорировано"
msgid "Header"
msgstr "Шапка"
msgid "Footer"
msgstr "Подвал"
msgid "Inline"
msgstr "В линию"
msgid "Sender"
msgstr "Отправитель"
msgid "To"
msgstr "Кому"
msgid "Preview message"
msgstr "Предпросмотр сообщения"
msgid "From"
msgstr "От"
msgid "Source URL"
msgstr "Источник"
msgid "Custom"
msgstr "Собственная"
msgid "Visibility"
msgstr "Видимость"
msgid "Roles"
msgstr "Роли"
msgid "Published"
msgstr "Опубликовано"
msgid "Signature"
msgstr "Подпись"
msgid "Filter"
msgstr "Фильтр"
msgid "Location"
msgstr "Место"
msgid "Promoted to front page"
msgstr "Помещено на главную страницу"
msgid "File ID"
msgstr "ID файла"
msgid "File name"
msgstr "Имя файла"
msgid "Vocabulary"
msgstr "Словарь"
msgid "Message type"
msgstr "Тип сообщения"
msgid "Contains"
msgstr "Содержит"
msgid "Average"
msgstr "В среднем"
msgid "Overridden"
msgstr "Переопределён"
msgid "Conditions"
msgstr "Условия"
msgid "item"
msgstr "пункт"
msgid "items"
msgstr "объектов"
msgid "Mode"
msgstr "Режим"
msgid "Normal"
msgstr "Нормальный"
msgid "Warning"
msgstr "Предупреждение"
msgid "N/A"
msgstr "Н/Д"
msgid "Nodes"
msgstr "Материалы"
msgid "Authored by"
msgstr "Автор"
msgid "sources"
msgstr "Источники"
msgid "Advanced"
msgstr "Расширенные"
msgid "Demo"
msgstr "Демо"
msgid "Width"
msgstr "Ширина"
msgid "Height"
msgstr "Высота"
msgid "Textfield"
msgstr "Текстовое поле"
msgid "Maximum"
msgstr "Максимум"
msgid "Range"
msgstr "Диапазон"
msgid "Scale"
msgstr "Масштабирование"
msgid "Plain text"
msgstr "Простой текст"
msgid "Honeypot"
msgstr "Honeypot"
msgid "Details"
msgstr "Подробности"
msgid "Introduction"
msgstr "Введение"
msgid "Unlimited"
msgstr "Неограничено"
msgid "Current"
msgstr "Текущий"
msgid "Phone"
msgstr "Телефон"
msgid "Address"
msgstr "Адрес"
msgid "State"
msgstr "Состояние"
msgid "email"
msgstr "email"
msgid "Code"
msgstr "Код"
msgid "Inactive"
msgstr "Неактивно"
msgid "Company"
msgstr "Компания"
msgid "General"
msgstr "Общий"
msgid "Example"
msgstr "Пример"
msgid "Method"
msgstr "Метод"
msgid "Week"
msgstr "Неделя"
msgid "Day"
msgstr "День"
msgid "Table"
msgstr "Таблица"
msgid "Start"
msgstr "Начало"
msgid "reCAPTCHA"
msgstr "reCAPTCHA"
msgid "Configuration"
msgstr "Конфигурация"
msgid "Other"
msgstr "Другое"
msgid "(Disabled)"
msgstr "(Отключено)"
msgid "Integration"
msgstr "Интеграция"
msgid "Navigation"
msgstr "Навигация"
msgid "Color"
msgstr "Цвет"
msgid "Link URL"
msgstr "URL ссылки"
msgid "Role"
msgstr "Роль"
msgid "Select all"
msgstr "Выделить все"
msgid "A"
msgstr "A"
msgid "Email subject"
msgstr "Тема сообщения"
msgid "First name"
msgstr "Имя"
msgid "Last name"
msgstr "Фамилия"
msgid "Destination"
msgstr "Место назначения"
msgid "Counter"
msgstr "Счётчик"
msgid "reset"
msgstr "сбросить"
msgid "External"
msgstr "Внешний"
msgid "Users"
msgstr "Пользователи"
msgid "Choices"
msgstr "Варианты"
msgid "JavaScript"
msgstr "JavaScript"
msgid "Square"
msgstr "Квадратный"
msgid "Last"
msgstr "Последний"
msgid "Rows"
msgstr "Строки"
msgid "Create content"
msgstr "Добавить материал"
msgid "Anonymous"
msgstr "Гость"
msgid "Provider"
msgstr "Поставщик"
msgid "Override"
msgstr "Переопределить"
msgid "Empty text"
msgstr "Текст, если пусто"
msgid "Handler"
msgstr "Обработчик"
msgid "Option"
msgstr "Опция"
msgid "Operator"
msgstr "Оператор"
msgid "Optional"
msgstr "Необязательно"
msgid "Order"
msgstr "Порядок"
msgid "HTML"
msgstr "HTML"
msgid "CSS"
msgstr "CSS"
msgid "Remaining"
msgstr "Оставшиеся"
msgid "Pattern"
msgstr "Шаблон"
msgid "Send to"
msgstr "Получатель"
msgid "Latest"
msgstr "Последнее"
msgid "Template"
msgstr "Шаблон"
msgid "module"
msgstr "модуль"
msgid "Authenticated users"
msgstr "Зарегистрированные пользователи"
msgid "Close"
msgstr "Закрыть"
msgid "IMCE"
msgstr "IMCE"
msgid "Save settings"
msgstr "Сохранить настройки"
msgid "Flag"
msgstr "Пометить флагом"
msgid "Operation"
msgstr "Действие"
msgid "Postal code"
msgstr "Почтовый индекс"
msgid "State/Province"
msgstr "Область/Район"
msgid "Collapsed"
msgstr "Свернуто"
msgid "Applications"
msgstr "Приложения"
msgid "Labels"
msgstr "Метки"
msgid "Sort by"
msgstr "Сортировать по"
msgid "Created date"
msgstr "Дата создания"
msgid "Full name"
msgstr "Полное имя"
msgid "Gender"
msgstr "Пол"
msgid "Male"
msgstr "Мужской"
msgid "Female"
msgstr "Женский"
msgid "Birthday"
msgstr "День рождения"
msgid "Confirmation"
msgstr "Подтверждение"
msgid "Share"
msgstr "Поделиться"
msgid "share"
msgstr "поделиться"
msgid "Size of textfield"
msgstr "Размер текстового поля"
msgid "Hidden"
msgstr "Скрытый"
msgid "Attachments"
msgstr "Вложения"
msgid "Default configuration"
msgstr "Настройки по умолчанию"
msgid "Key"
msgstr "Ключ"
msgid "submissions"
msgstr "Результаты заполнения"
msgid "Change"
msgstr "Изменить"
msgid "Messages"
msgstr "Сообщения"
msgid "Token"
msgstr "Токен"
msgid "Time format"
msgstr "Формат времени"
msgid "Delimiter"
msgstr "Разделитель"
msgid "Clear"
msgstr "Очистить"
msgid "No items selected."
msgstr "Нет выбранных элементов."
msgid "update"
msgstr "обновить"
msgid "Source"
msgstr "Источник"
msgid "Message:"
msgstr "Сообщение:"
msgid "Deleted"
msgstr "Удалено"
msgid "Languages"
msgstr "Языки"
msgid "Parameters"
msgstr "Параметры"
msgid "Return value"
msgstr "Возвращаемое значение"
msgid "Available tokens"
msgstr "Доступные токены"
msgid "First"
msgstr "Первый"
msgid "Middle"
msgstr "По центру"
msgid "Limit"
msgstr "Предел"
msgid "Minimum height"
msgstr "Минимальная высота"
msgid "Minimum width"
msgstr "Минимальная ширина"
msgid "Date/time"
msgstr "Дата/время"
msgid "one"
msgstr "один"
msgid "Hour"
msgstr "Час"
msgid "Minute"
msgstr "Минута"
msgid "Second"
msgstr "Секунда"
msgid "Select list"
msgstr "Список выбора"
msgid "Text field"
msgstr "Текстовое поле"
msgid "Workflow"
msgstr "Порядок действий"
msgid "%label has been deleted."
msgstr "%label было удалено."
msgid "Empty"
msgstr "Пусто"
msgid "Greater than"
msgstr "Больше чем"
msgid "Less than"
msgstr "Меньше чем"
msgid "any"
msgstr "любой"
msgid "Buttons"
msgstr "Кнопки"
msgid "Days"
msgstr "Дни"
msgid "Months"
msgstr "Месяцы"
msgid "Selector"
msgstr "Селектор"
msgid "Purge"
msgstr "Очистить"
msgid "Maxlength"
msgstr "Максимальная длина"
msgid "characters"
msgstr "символов"
msgid "All roles"
msgstr "Все роли"
msgid "Left"
msgstr "Слева"
msgid "Right"
msgstr "Справа"
msgid "Your message has been sent."
msgstr "Ваше сообщение отправлено."
msgid "Hours"
msgstr "Часы"
msgid "Seconds"
msgstr "Секунды"
msgid "Email body"
msgstr "Текст письма"
msgid "Info"
msgstr "Инфо"
msgid "Fade"
msgstr "Плавное появление"
msgid "Slide"
msgstr "Слайд"
msgid "From email address"
msgstr "E-mail адрес отправителя"
msgid "or"
msgstr "или"
msgid "Results"
msgstr "Результаты"
msgid "open"
msgstr "открыто"
msgid "Convert"
msgstr "Преобразовать"
msgid "Requirements"
msgstr "Требования"
msgid "Customize"
msgstr "Настроить"
msgid "Schema"
msgstr "Схема"
msgid "Permissions"
msgstr "Права доступа"
msgid "Promotions"
msgstr "Промоакции"
msgid "Duplicate"
msgstr "Дубликат"
msgid "options"
msgstr "параметры"
msgid "Email confirmation"
msgstr "Подтверждение почтой"
msgid "Confirmation URL"
msgstr "URL для подтверждения"
msgid "No results found"
msgstr "Результаты не найдены"
msgid "From:"
msgstr "От:"
msgid "Subject:"
msgstr "Тема:"
msgid "Changed"
msgstr "Изменение"
msgid "Date created"
msgstr "Дата создания"
msgid "Completed"
msgstr "Завершено"
msgid "Card expiry date"
msgstr "Дата окончания срока действия карты"
msgid "Testing"
msgstr "Тестирование"
msgid "completed"
msgstr "завершено"
msgid "404 Not Found"
msgstr "404 Не найдено"
msgid "User Profile"
msgstr "Профиль пользователя"
msgid "Templates"
msgstr "Шаблоны"
msgid "Not published"
msgstr "Не опубликовано"
msgid "File settings"
msgstr "Настройки файла"
msgid "Formats"
msgstr "Форматы"
msgid "Allowed file extensions"
msgstr "Допустимые расширения файлов"
msgid "summary"
msgstr "Сводка"
msgid "Percentage"
msgstr "Процент"
msgid "Relationship"
msgstr "Связь"
msgid "Migrate"
msgstr "Миграция"
msgid "image"
msgstr "изображение"
msgid "images"
msgstr "изображения"
msgid "Translations"
msgstr "Переводы"
msgid "Multilingual"
msgstr "Многоязычность"
msgid "Minutes"
msgstr "Минуты"
msgid "Default sender name"
msgstr "Имя отправителя по умолчанию"
msgid "Join"
msgstr "Присоединиться"
msgid "Locality"
msgstr "Местоположение"
msgid "Loading..."
msgstr "Загрузка..."
msgid "Automatic"
msgstr "Автоматически"
msgid "Excluded"
msgstr "Исключено"
msgid "Sticky"
msgstr "Прикреплено"
msgid "Limit to"
msgstr "Ограничить по"
msgid "Read/write"
msgstr "Чтение/запись"
msgid "Processed"
msgstr "Обработано"
msgid "Complete"
msgstr "Завершён"
msgid "Temporary directory"
msgstr "Временный каталог"
msgid "date"
msgstr "дата"
msgid "File upload error. Could not move uploaded file."
msgstr ""
"Ошибка закачки файла. Невозможно "
"переместить закачанный файл."
msgid "Submissions"
msgstr "Отправления"
msgid "webform"
msgstr "веб-форма"
msgid "Webforms"
msgstr "Веб-формы"
msgid "Webform"
msgstr "Веб-форма"
msgid "ever"
msgstr "всегда"
msgid "every hour"
msgstr "каждый час"
msgid "every day"
msgstr "каждый день"
msgid "every week"
msgstr "еженедельно"
msgid "Check this option if the user must enter a value."
msgstr ""
"Отметьте, если хотите сделать это поле "
"обязательным."
msgid "Previous submission"
msgstr "Предыдущее заполнение"
msgid "Next submission"
msgstr "Следующее заполнение"
msgid "Default value"
msgstr "Значение по умолчанию"
msgid "Questions"
msgstr "Вопросы"
msgid "Enable debugging"
msgstr "Включить отладку"
msgid "Apply"
msgstr "Применить"
msgid "Select"
msgstr "Выбрать"
msgid "Challenge type"
msgstr "Тип теста"
msgid "CAPTCHA"
msgstr "CAPTCHA"
msgid "Place a CAPTCHA here for untrusted users."
msgstr ""
"Добавить сюда CAPTCHA для "
"неблагонадежных пользователей."
msgid "Color settings"
msgstr "Настройки цвета"
msgid "Administrators"
msgstr "Администраторы"
msgid "Plugins"
msgstr "Плагины"
msgid "5 minutes"
msgstr "5 минут"
msgid "10 minutes"
msgstr "10 минут"
msgid "15 minutes"
msgstr "15 минут"
msgid "20 minutes"
msgstr "20 минут"
msgid "30 minutes"
msgstr "30 минут"
msgid "Above"
msgstr "Сверху"
msgid "Overrides"
msgstr "Переопределенные"
msgid "Text area"
msgstr "Текстовая область"
msgid "collapsed"
msgstr "свёрнуто"
msgid "Decimal"
msgstr "Десятичное число"
msgid "Minimum"
msgstr "Минимум"
msgid "Form"
msgstr "Форма"
msgid "Debug"
msgstr "Отладка"
msgid "1 minute"
msgstr "1 минута"
msgid "Raw value"
msgstr "Сырое значение"
msgid "Permission"
msgstr "Право доступа"
msgid "test"
msgstr "тест"
msgid "Hide"
msgstr "Скрыть"
msgid "< Previous"
msgstr "< Предыдущая страница"
msgid "Submission settings"
msgstr "Настройки отправления"
msgid "Two"
msgstr "Два"
msgid "Three"
msgstr "Три"
msgid "Audio file"
msgstr "Аудио файл"
msgid "Language code"
msgstr "Код языка"
msgid "Display message"
msgstr "Просмотр сообщений"
msgid "Filter by category"
msgstr "Фильтр по категории"
msgid "URL path settings"
msgstr "Настройки адресов"
msgid "Mapping"
msgstr "Соответствия"
msgid "Installation"
msgstr "Установка"
msgid "From name"
msgstr "Имя отправителя"
msgid "Uppercase"
msgstr "Верхний регистр"
msgid "Description:"
msgstr "Описание:"
msgid "Space"
msgstr "Пробел"
msgid "Drafts"
msgstr "Черновики"
msgid "Provided by"
msgstr "Предоставлено"
msgid "Export format"
msgstr "Формат экспорта"
msgid "video"
msgstr "видео"
msgid "Address settings"
msgstr "Настройки адреса"
msgid "Execute"
msgstr "Выполнить"
msgid "Feedback"
msgstr "Обратная связь"
msgid "Family name"
msgstr "Фамилия"
msgid "Organization"
msgstr "Организация"
msgid "Telephone"
msgstr "Телефон"
msgid "All users"
msgstr "Все пользователи"
msgid "Values"
msgstr "Значения"
msgid "Country code"
msgstr "Код страны"
msgid "Build"
msgstr "Конструктор"
msgid "Years"
msgstr "Годы"
msgid "Email addresses"
msgstr "Адреса электронной почты"
msgid "Identifier"
msgstr "Идентификатор"
msgid "Keyword"
msgstr "Ключевое слово"
msgid "Hide all"
msgstr "Спрятать все"
msgid "Show all"
msgstr "Показать все"
msgid "Page settings"
msgstr "Настройки страницы"
msgid "Edit '@title'"
msgstr "Редактировать '@title'"
msgid "Results per page"
msgstr "Результатов на странице"
msgid "Machine name"
msgstr "Машинное имя"
msgid "Unlocked"
msgstr "Разблокировано"
msgid "Locked"
msgstr "Заблокировано"
msgid "Resend"
msgstr "Отправить повторно"
msgid "Data"
msgstr "Данные"
msgid "Any"
msgstr "Любой"
msgid "modules"
msgstr "Модули"
msgid "Validation"
msgstr "Проверка"
msgid "Thank you for registering."
msgstr "Спасибо за регистрацию"
msgid "ZIP Code"
msgstr "Почтовый индекс"
msgid "Emails"
msgstr "Адреса электронной почты"
msgid "deleted"
msgstr "удалено"
msgid "Custom CSS"
msgstr "Пользовательский CSS"
msgid "Ordered list"
msgstr "Пронумерованный список"
msgid "Unordered list"
msgstr "Маркированный список"
msgid "New password"
msgstr "Новый пароль"
msgid "About"
msgstr "Информация"
msgid "Reports"
msgstr "Отчёты"
msgid "Contribute"
msgstr "Предоставлять"
msgid "Cardinality"
msgstr "Количество элементов"
msgid "and"
msgstr "и"
msgid "- Select -"
msgstr "- Выберите -"
msgid "SMTP Authentication Support"
msgstr "Поддержка SMTP аутентификации"
msgid "Form element"
msgstr "Элемент формы"
msgid "Notification"
msgstr "Уведомление"
msgid "Bcc"
msgstr "Скрытая копия"
msgid "View settings"
msgstr "Настройки представления"
msgid "Translate"
msgstr "Переводы"
msgid "Step"
msgstr "Шаг"
msgid "Image file"
msgstr "Файл изображения"
msgid "Admin mode"
msgstr "Режим Admin"
msgid "Steps"
msgstr "Шаги"
msgid "Answers"
msgstr "Ответы"
msgid "Element"
msgstr "Элемент"
msgid "Radios"
msgstr "Радиокнопка"
msgid "Web services"
msgstr "Веб-службы"
msgid "Route"
msgstr "Маршрут"
msgid "Output"
msgstr "Вывод"
msgid "Embed"
msgstr "Вставить"
msgid "Error message"
msgstr "Сообщение об ошибке"
msgid "Test settings"
msgstr "Настройки тестирования"
msgid "Below"
msgstr "Внизу"
msgid "For security reasons, your upload has been renamed to %filename."
msgstr ""
"Ваш файл был переименован в %filename из "
"соображений безопасности."
msgid "Entity type"
msgstr "Тип сущности"
msgid "notice"
msgstr "замечание"
msgid "Rating"
msgstr "Рейтинг"
msgid "Congratulations!"
msgstr "Поздравляем!"
msgid "Admins"
msgstr "Администраторы"
msgid "pixels"
msgstr "пикселей"
msgid "Recommended"
msgstr "Рекомендовано"
msgid "Direction"
msgstr "Направление"
msgid "Registration"
msgstr "Регистрация"
msgid "Configuration settings"
msgstr "Настройки конфигурации"
msgid "Card type"
msgstr "Тип карты"
msgid "Card number"
msgstr "Номер карты"
msgid "button"
msgstr "кнопка"
msgid "expanded"
msgstr "развернуто"
msgid "Format settings"
msgstr "Настройки форматов"
msgid "Webform submissions"
msgstr "Отправленные формы"
msgid "Warning message"
msgstr "Предупреждение"
msgid "Words"
msgstr "Слова"
msgid "Characters"
msgstr "Символы"
msgid "The file %file could not be saved. An unknown error has occurred."
msgstr ""
"Файл %file не удается сохранить. "
"Возникла неизвестная ошибка."
msgid "The specified file %name could not be uploaded."
msgstr ""
"Указанный файл %name не может быть "
"загружен."
msgid ""
"Upload error. Could not move uploaded file %file to destination "
"%destination."
msgstr ""
"Ошибка закачки. Невозможно "
"переместить загруженный файл %file в "
"место назначения %destination."
msgid "Flagged"
msgstr "Помечено"
msgid "Response message:"
msgstr "Текст ответа:"
msgid "Table settings"
msgstr "Настройка таблицы"
msgid "Date settings"
msgstr "Настройки даты"
msgid "IP address"
msgstr "IP-адрес"
msgid "Maximum height"
msgstr "Максимальная высота"
msgid "Maximum width"
msgstr "Максимальная ширина"
msgid "Autocomplete matching"
msgstr "Совпадение автодополнения"
msgid "Starts with"
msgstr "Начинается с"
msgid "Variants"
msgstr "Варианты"
msgid "Properties"
msgstr "Свойства"
msgid "Select menu"
msgstr "Выбор меню"
msgid "Autocomplete"
msgstr "Автодополнение"
msgid "Maximum image resolution"
msgstr "Максимальное разрешение изображения"
msgid "Expand all"
msgstr "Развернуть все"
msgid "Collapse all"
msgstr "Cвернуть все"
msgid "Delimited text"
msgstr "Текст с разделителями"
msgid "Comma (,)"
msgstr "Запятая (,)"
msgid "Tab (\\t)"
msgstr "Табуляция (\\t)"
msgid "Semicolon (;)"
msgstr "Точка с запятой (;)"
msgid "Colon (:)"
msgstr "Двоеточие (:)"
msgid "Pipe (|)"
msgstr "Вертикальная черта (|)"
msgid "Period (.)"
msgstr "Точка (.)"
msgid "Space ( )"
msgstr "Пробел ( )"
msgid "close"
msgstr "закрыть"
msgid "Additional settings"
msgstr "Дополнительные настройки"
msgid "Two columns"
msgstr "Две колонки"
msgid "Country name"
msgstr "Название страны"
msgid "Link to form"
msgstr "Ссылка на форму"
msgid "Comma"
msgstr "Запятая"
msgid "Semicolon"
msgstr "Точка с запятой"
msgid "‹"
msgstr "‹"
msgid "›"
msgstr "›"
msgid "Current user"
msgstr "Текущий пользователь"
msgid "Access type"
msgstr "Тип доступа"
msgid "City/Town"
msgstr "Город (Населенный пункт)"
msgid "Config"
msgstr "Конфигурация"
msgid "Video file"
msgstr "Видео файл"
msgid "File upload"
msgstr "Загрузка файла"
msgid "Preview settings"
msgstr "Настройки просмотра"
msgid "Link title"
msgstr "Заголовок ссылки"
msgid "Finished with an error."
msgstr "Завершено с ошибкой"
msgid "Sort options"
msgstr "Настройка сортировки"
msgid "Per user"
msgstr "По пользователям"
msgid "The file could not be uploaded."
msgstr "Файл не может быть загружен."
msgid "Edit configuration"
msgstr "Редактировать конфигурацию"
msgid "Draft"
msgstr "Черновик"
msgid "Save Draft"
msgstr "Сохранить черновик"
msgid "Scheduled"
msgstr "Запланировано"
msgid "answer"
msgstr "ответ"
msgid "Checkbox"
msgstr "Флажок"
msgid "Date year range"
msgstr "Диапазон годов даты"
msgid "Trigger"
msgstr "Триггер"
msgid "Yes/No"
msgstr "Да/Нет"
msgid "Select date"
msgstr "Выберите дату"
msgid "Cc"
msgstr "Копия"
msgid "Autocomplete limit"
msgstr "Предел автозаполнения"
msgid "Vertical tabs"
msgstr "Вертикальные вкладки"
msgid "Vertical Tabs"
msgstr "Вертикальные вкладки"
msgid "question"
msgstr "вопрос"
msgid "questions"
msgstr "вопросов"
msgid "Card"
msgstr "Карточка"
msgid "SID"
msgstr "SID"
msgid ""
"The default sender name which is used along with the default from "
"address."
msgstr ""
"Имя отправителя по умолчанию, которое "
"используется вместе с адресом по "
"умолчанию."
msgid "Webform submission"
msgstr "Отправление веб-форм"
msgid "Leaving blank will use the default size."
msgstr ""
"Оставьте пустым, чтобы использовать "
"размер по умолчанию."
msgid "Submitted values are:"
msgstr "Заполненные значения:"
msgid "Lowercase"
msgstr "Нижний регистр"
msgid "Display on"
msgstr "Показывать на"
msgid "Education"
msgstr "Обучение"
msgid "Horizontal rule"
msgstr "Горизонтальная черта"
msgid "Current date"
msgstr "Текущая дата"
msgid "And"
msgstr "И"
msgid "Broken"
msgstr "Прервано"
msgid "View name"
msgstr "Имя представления"
msgid "Attachment settings"
msgstr "Настройки вложения"
msgid "Enable Drupal style \"sticky\" table headers (Javascript)"
msgstr ""
"Включить \"липкие\" заголовки таблицы "
"(JavaScript)"
msgid "Placeholder"
msgstr "Заполнитель"
msgid "Allowed formats"
msgstr "Доступные форматы"
msgid "Tooltip"
msgstr "Подсказка"
msgid "Circle"
msgstr "Круг"
msgid "Fieldset"
msgstr "Fieldset"
msgid "Checkboxes"
msgstr "Блоки флажков"
msgid "Textarea"
msgstr "Текстовая область"
msgid "h2"
msgstr "h2"
msgid "Webform Block"
msgstr "Блок опросника"
msgid "Auto detect"
msgstr "Автоматическое определение"
msgid "Table header"
msgstr "Заголовок таблицы"
msgid "Notes:"
msgstr "Примечания:"
msgid "Author information"
msgstr "Информация об авторе"
msgid "Date and time"
msgstr "Дата и время"
msgid "Signature settings"
msgstr "Настройки подписи"
msgid "File extension"
msgstr "Расширение файла"
msgid "@type (from module @module)"
msgstr "@type (из модуля @module)"
msgid "Default challenge type"
msgstr "Тип проверки по умолчанию"
msgid "Throbber"
msgstr ""
"Троббер (индикатор без указания "
"прогресса выполнения)"
msgid "Address 2"
msgstr "Адрес 2"
msgid "Preferred language"
msgstr "Предпочтительный язык"
msgid "Maps"
msgstr "Карты"
msgid "Text format"
msgstr "Текстовый формат"
msgid "Sort descending"
msgstr "Сортировать по убыванию"
msgid "Sort ascending"
msgstr "Сортировать по возрастанию"
msgid "Alternatives"
msgstr "Варианты"
msgid "Add variant"
msgstr "Добавить вариант"
msgid "Variant type"
msgstr "Тип варианта"
msgid "Administrative description"
msgstr "Административное описание"
msgid "Name is required."
msgstr "Имя обязательно для заполнения."
msgid "Variant"
msgstr "Вариант"
msgid "Dialog"
msgstr "Диалог"
msgid "is empty"
msgstr "если пусто"
msgid "Page theme"
msgstr "Тема страницы"
msgid "References"
msgstr "Ссылки"
msgid "Edit element"
msgstr "Редактировать элемент"
msgid "Delete element"
msgstr "Удалить элемент"
msgid "Elements"
msgstr "Элементы"
msgid "Add element"
msgstr "Добавить элемент"
msgid "Field prefix"
msgstr "Префикс поля"
msgid "Field suffix"
msgstr "Суффикс поля"
msgid "Remove selected"
msgstr "Удалить выбранное"
msgid "Lock"
msgstr "Заблокировать"
msgid "Limited"
msgstr "Ограничено"
msgid "Structure"
msgstr "Структура"
msgid "Progress"
msgstr "Прогресс"
msgid "Sender email address"
msgstr "E-mail адрес отправителя"
msgid "Unique"
msgstr "Уникальный"
msgid "Node status"
msgstr "Статус материала"
msgid "Form display"
msgstr "Отображение формы"
msgid "Progress bar"
msgstr "Прогресс бар"
msgid "Maximum file size"
msgstr "Максимальный размер файла"
msgid "[none]"
msgstr "[нет]"
msgid "Message settings"
msgstr "Настройки сообщений"
msgid "Libraries"
msgstr "Библиотеки"
msgid "(unknown)"
msgstr "(неизвестно)"
msgid "Randomize questions"
msgstr "Вопросы в случайном порядке"
msgid "Language select"
msgstr "Выбор языка"
msgid "Form validation"
msgstr "Проверка формы"
msgid "Webform Validation"
msgstr "Проверка Веб-форм"
msgid "Rename files"
msgstr "Переименовать файлы"
msgid "Dependencies"
msgstr "Зависимости"
msgid "Serial number"
msgstr "Серийный номер"
msgid "Email from address"
msgstr "Электронный адрес отправителя"
msgid "destinations"
msgstr "места назначений"
msgid "destination"
msgstr "место назначения"
msgid "Starred"
msgstr "Отмечено звёздочкой"
msgid "Before title"
msgstr "До заголовка"
msgid "After title"
msgstr "После заголовка"
msgid "Not restricted"
msgstr "Без ограничений"
msgid "Date changed"
msgstr "Дата изменения"
msgid "Sender name"
msgstr "Имя отправителя"
msgid "Sender email"
msgstr "E-mail адрес отправителя"
msgid "Custom settings"
msgstr "Пользовательские настройки"
msgid "Archived"
msgstr "Архив"
msgid "Default tab"
msgstr "Вкладка по умолчанию"
msgid ""
"The file %source could not be uploaded because a file by that name "
"already exists in the destination %directory."
msgstr ""
"Файл %source не может быть загружен "
"потому что файл с таким именем уже "
"существует в каталоге %directory."
msgid "Status message"
msgstr "Статус"
msgid "Minimum image resolution"
msgstr "Минимальное разрешение изображения"
msgid "no preview"
msgstr "нет предпросмотра"
msgid "Date type"
msgstr "Тип даты"
msgid "Time zones"
msgstr "Часовые пояса"
msgid "The directory %directory does not exist and could not be created."
msgstr ""
"Каталог %directory не существует и не может "
"быть создан."
msgid ""
"The directory %directory exists but is not writable and could not be "
"made writable."
msgstr ""
"Каталог %directory уже существует, но "
"недоступен для записи и не может стать "
"таким."
msgid "Entity ID"
msgstr "Идентификатор сущности"
msgid "Unlock"
msgstr "Разблокировать"
msgid "Webform settings"
msgstr "Настройки Webform"
msgid "Randomize options"
msgstr "Случайные варианты"
msgid "Confirmation message"
msgstr "Сообщение о подтверждении"
msgid "Submission limit"
msgstr "Предел отправки формы"
msgid "Submission Number"
msgstr "Номер результата"
msgid "Submission ID"
msgstr "ID отправления"
msgid "draft"
msgstr "черновик"
msgid "Current password"
msgstr "Текущий пароль"
msgid "Read-only"
msgstr "Только чтение"
msgid "Remote URL"
msgstr "Внешний URL-адрес"
msgid "subject"
msgstr "тема"
msgid "CodeMirror"
msgstr "CodeMirror"
msgid "Wrapper"
msgstr "Обёртка"
msgid "Autocomplete settings"
msgstr "Настройки автодополнения"
msgid "Submitter"
msgstr "Отправитель"
msgid "visible"
msgstr "видимый"
msgid ""
"Provides a user interface for the Token API and some missing core "
"tokens."
msgstr ""
"Обеспечивает пользовательский "
"интерфейс для Token API и некоторые "
"пропущенные токены ядра."
msgid "Four"
msgstr "Четыре"
msgid "Current page"
msgstr "Текущая страница"
msgid "Confirm email"
msgstr "Подтверждающий email"
msgid "The email address %mail is not valid."
msgstr "Некорректный email адрес %mail."
msgid "Invisible"
msgstr "Невидимый"
msgid "Unsaved"
msgstr "Не сохранено"
msgid ""
"Separate extensions with a space or comma and do not include the "
"leading dot."
msgstr ""
"Введите расширения через пробел или "
"запятую. Не используйте точку перед "
"расширением."
msgid "Chosen"
msgstr "Выбранный(е)"
msgid "Original Image"
msgstr "Оригинальное изображение"
msgid "UUID"
msgstr "UUID"
msgid "Time settings"
msgstr "Установки времени"
msgid "Contact Us"
msgstr "Связаться с нами"
msgid "Modal"
msgstr "Модальное окно"
msgid "Organization name"
msgstr "Название организации"
msgid "Learn more"
msgstr "Просмотреть"
msgid "View mode"
msgstr "Режим просмотра"
msgid "Title display"
msgstr "Отображение заголовка"
msgid "Available countries"
msgstr "Доступные страны"
msgid "If no countries are selected, all countries will be available."
msgstr ""
"Если ни одна из стран не выбрана, то "
"будут доступны все страны."
msgid "Changed date"
msgstr "Дата изменения"
msgid "elements"
msgstr "элементы"
msgid "Include files as attachments"
msgstr "Добавлять файлы как вложения"
msgid "Watch video"
msgstr "Смотреть видео"
msgid ""
"A unique machine-readable name. Can only contain lowercase letters, "
"numbers, and underscores."
msgstr ""
"Уникальное машинное имя. Оно может "
"содержать только латинские буквы "
"нижнего регистра, цифры и символы "
"подчёркивания."
msgid "Weight for @title"
msgstr "Вес @title"
msgid "sent"
msgstr "отправлен"
msgid "Message ID"
msgstr "№ сообщения"
msgid "Slides"
msgstr "Слайды"
msgid "Theme name"
msgstr "Название темы"
msgid "Full screen"
msgstr "Во весь экран"
msgid "Header title"
msgstr "Название в шапке"
msgid "One column"
msgstr "Одна колонка"
msgid "C"
msgstr "C"
msgid "Add webform"
msgstr "Добавить веб-форму"
msgid "Mail System"
msgstr "Почтовая система"
msgid "There are no templates available."
msgstr "Нет доступных шаблонов."
msgid "Entity id"
msgstr "ID сущности"
msgid "Address line 1"
msgstr "Адрес"
msgid "Address line 2"
msgstr "Адрес (дополнительно)"
msgid "Submission"
msgstr "Отправление"
msgid "- Default -"
msgstr "- По умолчанию -"
msgid "Reply to"
msgstr "Ответить"
msgid "Link attributes"
msgstr "Атрибуты ссылки"
msgid "Element type"
msgstr "Тип элемента"
msgid "Mitigates spam form submissions using the honeypot method."
msgstr ""
"Уменьшает количество спама через HTML "
"формы c помощью honeypot метода."
msgid "An autocomplete text field."
msgstr "Текстовое поле с автодополнением."
msgid "Ajax effect"
msgstr "Эффект Ajax"
msgid "Entity reference"
msgstr "Ссылка на сущность"
msgid "@name field is required."
msgstr "Поле \"@name\" обязательно для заполнения."
msgid "Wide"
msgstr "Широкий"
msgid "Header 1"
msgstr "Заголовок 1"
msgid "Header 2"
msgstr "Заголовок 2"
msgid "Add images"
msgstr "Добавить изображения"
msgid "Response status code"
msgstr "Код состояния ответа"
msgid "Other…"
msgstr "Другое..."
msgid "The file %file could not be saved because the upload did not complete."
msgstr ""
"Невозможно сохранить файл %file, так как "
"загрузка не была завершена."
msgid "Third party settings"
msgstr "Сторонние настройки"
msgid "Twig"
msgstr "Twig"
msgid "@title settings"
msgstr "@title настройки"
msgid "Current page title"
msgstr "Заголовок текущей страницы"
msgid "Save elements"
msgstr "Сохранить элементы"
msgid "Add layout"
msgstr "Добавить макет"
msgid "The URL %url is not valid."
msgstr "URL %url не корректный."
msgid "Filled"
msgstr "Заполнено"
msgid "Development settings"
msgstr "Настройки разработки"
msgid ""
"The file %file could not be saved because it exceeds %maxsize, the "
"maximum allowed size for uploads."
msgstr ""
"Файл %file не может быть сохранён. "
"Максимально допустимый размер %maxsize."
msgid ""
"The file could not be uploaded because the destination %destination is "
"invalid."
msgstr ""
"Невозможно загрузить файл так как "
"путь сохранения %destination некорректный."
msgid "%name field is not in the right format."
msgstr "%name поле имеет неправильный формат."
msgid "Form status"
msgstr "Состояние формы"
msgid "Additional resources"
msgstr "Дополнительные ресурсы"
msgid "Langcode"
msgstr "Код языка"
msgid "Source entity"
msgstr "Исходная сущность"
msgid "Source entity type"
msgstr "Тип исходной сущности"
msgid "Hide empty"
msgstr "Скрывать пустые"
msgid "Signature format"
msgstr "Формат подписи"
msgid "Selected actions"
msgstr "Выбранные действия"
msgid "%action was applied to @count item."
msgid_plural "%action was applied to @count items."
msgstr[0] "%action было применено @count элементу."
msgstr[1] "%action было применено @count элементам."
msgstr[2] "%action было применено @count[2] элементам."
msgid "AM/PM"
msgstr "AM/PM"
msgid "Type of item to reference"
msgstr "Тип элемента для ссылки"
msgid "Reference method"
msgstr "Способ выбора"
msgid "Allowed number of values"
msgstr "Допустимое количество значений"
msgid "Caption for the table"
msgstr "Заголовок таблицы"
msgid "Antibot"
msgstr "Антибот"
msgid "Show the notification about previous submissions"
msgstr ""
"Показывать уведомление о предыдущих "
"отправлениях"
msgid "Are you sure you want to delete the %label @entity-type?"
msgstr ""
"Вы уверены, что хотите удалить %label "
"@entity-type?"
msgid "Filter submissions"
msgstr "Фильтрация отправлений"
msgid "CAPTCHA settings"
msgstr "Настройки CAPTCHA"
msgid "results per page"
msgstr "результатов на странице"
msgid ""
"The \"@name\" option must contain a valid value. You may either leave "
"the text field empty or enter a string like \"512\" (bytes), \"80 KB\" "
"(kilobytes) or \"50 MB\" (megabytes)."
msgstr ""
"Опция \"@name\" должна содержать "
"допустимое значение. Вы можете "
"оставить текстовое поле пустым или "
"ввести строку, такую как «512» (байты), "
"«80 KB» (килобайты) или «50 MB» (мегабайты)."
msgid "Next submission number"
msgstr "Номер следующего отправления"
msgid ""
"The minimum allowed image size expressed as WIDTH×HEIGHT (e.g. "
"640×480). Leave blank for no restriction. If a smaller image is "
"uploaded, it will be rejected."
msgstr ""
"Минимально допустимый размер "
"изображения, выраженный как "
"ШИРИНА×ВЫСОТА (например, 640×480). "
"Оставьте пустым без ограничений. Если "
"загружено меньшее изображение, оно "
"будет отклонено."
msgid "Broken/Missing"
msgstr "Повреждён/Отсутствует"
msgid "Filename: %name"
msgstr "Имя файла: %name"
msgid "Select a @context value:"
msgstr "Выберите значение @context:"
msgid "No access to execute %action on the @entity_type_label %entity_label."
msgstr ""
"Нет доступа для выполнения действия "
"%action над сущностью @entity_type_label %entity_label."
msgid "Entity reference field settings"
msgstr "Настройки поля ссылки на сущность"
msgid "Entity reference selection plugin settings"
msgstr ""
"Настройки плагина выбора ссылки на "
"сущность"
msgid "File link"
msgstr "Ссылка на файл"
msgid "Date completed"
msgstr "Дата заполнения"
msgid "Reply-to"
msgstr "Ответить"
msgid ""
"A title semantically associated with your table for increased "
"accessibility."
msgstr ""
"Заголовок, семантически связанный с "
"таблицей для улучшения доступности."
msgid "Basic HTML"
msgstr "Базовый HTML"
msgid ""
"@name cannot be longer than %max characters but is currently %length "
"characters long."
msgstr ""
"@name не может превышать %max символов, а "
"сейчас он длинной %length символов."
msgid "Single item"
msgstr "Один элемент"
msgid "Both a height and width value must be specified in the @name field."
msgstr ""
"Значения высоты и ширина должны быть "
"указаны в поле @name."
msgid "Sorting code"
msgstr "Код сортировки"
msgid "- No override -"
msgstr "- Не переопределять -"
msgid "Narrow"
msgstr "Узкий"
msgid "@title type"
msgstr "Тип @title"
msgid "Add @title"
msgstr "Добавить @title"
msgid "Options (YAML)"
msgstr "Настройки (YAML)"
msgid "Entity select"
msgstr "Выбор сущности"
msgid "Data (YAML)"
msgstr "Данные (YAML)"
msgid "Submission updated in %form."
msgstr "Обновлено отправление %form."
msgid "New submission added to %form."
msgstr "Заполнена новая форма %form."
msgid "Submitted to"
msgstr "Отправлено в"
msgid "Back to form"
msgstr "Вернуться к форме"
msgid "Submission UUID"
msgstr "UUID отправления"
msgid "Submission URI"
msgstr "URI отправления"
msgid "Remote IP address"
msgstr "Удалённый IP адрес"
msgid "Submitted to: Entity ID"
msgstr "Отправлено в: ID сущности"
msgid "Format options"
msgstr "Параметры формата"
msgid "Defaults to: %value"
msgstr "По умолчанию: %value"
msgid "Submitted to: Entity title"
msgstr "Отправлено в: Заголовок сущности"
msgid "Submitted to: Entity URL"
msgstr "Отправлено в: URL сущности"
msgid "Form closed message"
msgstr "Сообщение о закрытии формы"
msgid "Form exception message"
msgstr "Сообщение об ошибке в форме"
msgid "Is draft"
msgstr "Черновик"
msgid ""
"Enter a <a href=\":form_api_href\">Form API (FAPI)</a> and/or a <a "
"href=\":render_api_href\">Render Array</a> as <a "
"href=\":yaml_href\">YAML</a>."
msgstr ""
"Введите <a href=\":form_api_href\">Form API (FAPI)</a> "
"и/или <a href=\":render_api_href\">Рендер Массив</a>, "
"как <a href=\":yaml_href\">YAML</a>."
msgid ""
"Please review your submission. Your submission is not complete until "
"you press the \"Submit\" button!"
msgstr ""
"Пожалуйста, просмотрите ваше "
"отправление, оно не будет завершено, "
"пока вы не нажмёте кнопку \"Отправить\"!"
msgid "No more submissions are permitted."
msgstr ""
"Больше никаких отправлений не "
"разрешено."
msgid ""
"A user-defined date format. See the <a "
"href=\"http://php.net/manual/function.date.php\">PHP manual</a> for "
"available options."
msgstr ""
"Формат даты, заданный пользователем. "
"Смотрите доступные опции в <a "
"href=\"http://php.net/manual/function.date.php\">PHP "
"справочнике</a>."
msgid ""
"The maximum allowed image size expressed as WIDTH×HEIGHT (e.g. "
"640×480). Leave blank for no restriction. If a larger image is "
"uploaded, it will be resized to reflect the given width and height. "
"Resizing images on upload will cause the loss of <a "
"href=\"http://wikipedia.org/wiki/Exchangeable_image_file_format\">EXIF "
"data</a> in the image."
msgstr ""
"Максимально допустимый размер "
"изображения, выраженный как "
"ШИРИНА×ВЫСОТА (например, 640×480). "
"Оставьте пустым без ограничений. Если "
"загружено большее изображение, оно "
"будет изменено, чтобы отразить "
"заданную ширину и высоту. Изменение "
"размера изображений при загрузке "
"приведет к потере <a "
"href=\"http://wikipedia.org/wiki/Exchangeable_image_file_format\"> "
"данных EXIF </a> в изображении."
msgid ""
"Sends the message as plain text or HTML, using PHP's native mail() "
"function."
msgstr ""
"Отправляет сообщения как обычный "
"текст или HTML, используя встроенную "
"функцию PHP mail()."
msgid "- Select operation -"
msgstr "- Выберите операцию -"
msgid "Elements (YAML)"
msgstr "Элементы (YAML)"
msgid "Select an element"
msgstr "Выберите элемент"
msgid "Filter by element name"
msgstr "Фильтровать по имени элемента"
msgid "Element settings"
msgstr "Настройки элемента"
msgid "All [@total]"
msgstr "Все [@total]"
msgid "Open [@total]"
msgstr "Открыто [@total]"
msgid "Starred [@total]"
msgstr "Отмечены [@total]"
msgid "Unstarred [@total]"
msgstr "Не отмечены [@total]"
msgid "Administrative notes"
msgstr "Административные заметки"
msgid ""
"Enter notes about this submission. These notes are only visible to "
"submission administrators."
msgstr ""
"Введите заметки об этом отправлении. "
"Эти заметки видны только "
"администраторам отправления."
msgid "Filter by submitted data and/or notes"
msgstr ""
"Фильтрация по отправлениям и/или "
"примечаниям"
msgid "Customize table"
msgstr "Настроить таблицу"
msgid "Ascending (ASC)"
msgstr "По возрастанию (ASC)"
msgid "Descending (DESC)"
msgstr "По убыванию (DESC)"
msgid "Use as default configuration"
msgstr ""
"Использовать в качестве конфигурации "
"по умолчанию"
msgid "Disable client-side validation"
msgstr "Отключить проверку на стороне клиента"
msgid "Apply to selected items"
msgstr "Применить к отмеченным позициям"
msgid "Element info"
msgstr "Информация об элементе"
msgid "Display collapse/expand all details link"
msgstr ""
"Отображать ссылку "
"свернуть/развернуть все детали"
msgid "Private file system is set."
msgstr ""
"Приватная файловая система "
"установлена."
msgid "Private file system is not set."
msgstr ""
"Приватная файловая система не "
"установлена."
msgid ""
"This must be changed in <a "
"href=\"https://www.drupal.org/documentation/modules/file\">settings.php</a>. "
"For more information see: <a "
"href=\"https://www.drupal.org/psa-2016-003\">DRUPAL-PSA-2016-003</a>"
msgstr ""
"Это необходимо изменить в <a "
"href=\"https://www.drupal.org/documentation/modules/file\">settings.php</a>. "
"Дополнительную информацию см: <a "
"href=\"https://www.drupal.org/psa-2016-003\">DRUPAL-PSA-2016-003</a>"
msgid "Form CSS classes"
msgstr "CSS классы формы"
msgid "Form attributes"
msgstr "Атрибуты формы"
msgid "Provided by the @module module."
msgstr "Предоставлено модулем @module."
msgid "Warn users about unsaved changes"
msgstr ""
"Предупреждать пользователей о "
"несохранённых изменениях"
msgid "Disable back button"
msgstr "Отключить кнопку \"Назад\""
msgid "Confirmation page URL alias"
msgstr ""
"Псевдоним URL-адреса страницы "
"подтверждения"
msgid "@title CSS classes"
msgstr "CSS классы @title"
msgid "@title CSS style"
msgstr "CSS стили @title"
msgid "Webform: HTML email support"
msgstr ""
"Вебформа: поддержка HTML в электронной "
"почте"
msgid "Webform: Private files"
msgstr "Вебформа: Личные файлы"
msgid "Administer webforms"
msgstr "Администрирование веб-форм"
msgid "Delete webform"
msgstr "Удалить веб-форму"
msgid "Add webform options"
msgstr "Добавить настройки веб-формы"
msgid "Please add elements to this webform."
msgstr "Добавьте элементы на эту вебформу."
msgid "Webform %label elements saved."
msgstr "Элемент вебформы %label сохранён."
msgid "Webform URL alias"
msgstr "Псевдоним URL-адреса веб-формы"
msgid "Disable back button for all webforms"
msgstr ""
"Отключить кнопку \"Назад\" для всех "
"веб-форм"
msgid "Disable client-side validation for all webforms"
msgstr ""
"Отключить проверку на стороне клиента "
"для всех веб-форм"
msgid "Filter webforms"
msgstr "Фильтровать веб-формы"
msgid ""
"If checked, the above settings will be used as the default "
"configuration for all associated Webform nodes."
msgstr ""
"Если флажок установлен, вышеуказанные "
"настройки будут использоваться в "
"качестве конфигурации по умолчанию "
"для всех связанных сущностей Webform."
msgid "Unable to display this webform. Please contact the site administrator."
msgstr ""
"Невозможно отобразить эту веб-форму. "
"Обратитесь к администратору сайта."
msgid "New submission added to [webform:title]."
msgstr "Заполнена новая форма [webform:title]."
msgid "Basic email contact webform."
msgstr ""
"Основная веб-форма для связи по "
"электронной почте."
msgid "Submission serial number"
msgstr "Серийный номер отправления"
msgid ""
"Submitted on [webform_submission:created]\n"
"Submitted by: [webform_submission:user]\n"
"\n"
"Submitted values are:\n"
"[webform_submission:values]\n"
msgstr ""
"Отправлено [webform_submission:created]\r\n"
"Отправитель: [webform_submission:user]\r\n"
"\r\n"
"Отправленная информация:\r\n"
"[webform_submission:values]\n"
msgid ""
"<p>Submitted on [webform_submission:created]</p>\n"
"<p>Submitted by: [webform_submission:user]</p>\n"
"<p>Submitted values are:</p>\n"
"[webform_submission:values]\n"
msgstr ""
"<p>Отправлено [webform_submission:created]</p>\r\n"
"<p>Отправитель: [webform_submission:user]</p>\r\n"
"<p>Отправленная информация:</p>\r\n"
"[webform_submission:values]\n"
msgid "In draft"
msgstr "Черновик"
msgid "Prevent duplicate submissions"
msgstr ""
"Предотвращать дублирования "
"отправлений"
msgid "Delete submission"
msgstr "Удалить отправление"
msgid "Disable autocompletion"
msgstr "Отключить автозавершение"
msgid "A basic page with a webform attached."
msgstr "Страница с прикреплённой веб-формой."
msgid "Scheduled [@total]"
msgstr "Запланировано [@total]"
msgid "Form open message"
msgstr "Сообщение об открытии формы"
msgid ""
"A message to be displayed notifying the user that the webform is going "
"to be opening to submissions. The opening message will only be "
"displayed when a webform is scheduled to be opened."
msgstr ""
"Сообщение, которое будет "
"отображаться, уведомляя пользователя "
"о том, что веб-форма будет открыта для "
"отправки. Сообщение об открытии будет "
"отображаться только тогда, когда "
"веб-форма запланирована к открытию."
msgid ""
"A message to be displayed notifying the user that the webform is "
"closed. The closed message will be displayed when a webform's status "
"is closed or a submission limit is reached."
msgstr ""
"Сообщение, уведомляющее пользователя "
"о том, что веб-форма закрыта. Сообщение "
"о закрытии будет отображаться, когда "
"статус веб-формы будет закрыт или "
"будет достигнут лимит отправки."
msgid "Form behaviors"
msgstr "Поведения формы"
msgid "The username of the user that submitted the webform."
msgstr ""
"Имя пользователя, отправившего "
"веб-форму."
msgid "This form has not yet been opened to submissions."
msgstr "Эта форма ещё не открыта для отправки."
msgid "Star/Flag submission"
msgstr "Отметить отправление звездой/флагом"
msgid "Unstar/unflag submission"
msgstr ""
"Снять отметку отправления "
"звездой/флагом"
msgid "Submit button(s)"
msgstr "Кнопка(и) отправки"
msgid "Prevent forms from being submitted without JavaScript enabled."
msgstr ""
"Предотвращает отправку форм без "
"включенного JavaScript."
msgid "Prevent duplicate submissions for all webforms"
msgstr ""
"Предотвращать дублирования "
"отправлений для всех веб-форм"
msgid "Warn users about unsaved changes for all webforms"
msgstr ""
"Предупреждать пользователей о "
"несохранённых изменениях во всех "
"веб-формах"
msgid "[webform:title]: Preview"
msgstr "[webform:title]: Просмотр"
msgid "Ajax settings"
msgstr "Настройки Ajax"
msgid "Submission title"
msgstr "Заголовок отправления"
msgid ""
"[webform_submission:submitted-to]: Submission "
"#[webform_submission:serial]"
msgstr ""
"[webform_submission:submitted-to]: Отправление "
"№[webform_submission:serial]"
msgid "Display reset button"
msgstr "Отображать кнопку сброса"
msgid "Webform settings %label has been saved."
msgstr "Настройки вебформы %label сохранены."
msgid "Webform settings @label has been saved."
msgstr "Настройки вебформы @label сохранены."
msgid "Webform: External libraries"
msgstr "Вебформа: внешние библиотеки"
msgid ""
"@total libraries (@installed installed; @excluded excluded; @missing "
"CDN)"
msgstr ""
"@total библиотек (@installed установлено; "
"@excluded исключено; @missing CDN)"
msgid "Set default value"
msgstr "Установить значение по умолчанию"
msgid ""
"The (View) <strong>Source</strong> page allows developers to edit a "
"webform's render array using YAML markup."
msgstr ""
"Страница (Просмотр) "
"<strong>Источника</strong> позволяет "
"разработчикам редактировать массив "
"рендеринга веб-формы с помощью "
"разметки YAML."
msgid ""
"The <strong>Elements</strong> page allows users to add, update, "
"duplicate and delete elements and wizard pages."
msgstr ""
"Страница <strong>Элементы</strong> позволяет "
"пользователям добавлять, обновлять, "
"дублировать и удалять элементы и "
"мастера страниц."
msgid ""
"The <strong>General</strong> settings page allows a webform's "
"administrative information, paths, behaviors and third-party settings "
"to be customized."
msgstr ""
"Страница <strong>Общие</strong> настройки "
"позволяет настраивать "
"административную информацию "
"веб-формы, пути, поведение и сторонние "
"настройки."
msgid ""
"The <strong>Submissions</strong> page displays a customizable overview "
"of a webform's submissions."
msgstr ""
"На странице <strong>Отправления</strong> "
"отображается настраиваемый обзор "
"отправлений веб-формы."
msgid ""
"The <strong>Download</strong> page allows a webform's submissions to "
"be exported into a customizable CSV (Comma Separated Values) file and "
"other common data formats."
msgstr ""
"Страница <strong>Скачать</strong> позволяет "
"экспортировать данные из веб-формы в "
"настраиваемый файл CSV (Comma Separated Values) и "
"другие распространённые форматы "
"данных."
msgid ""
"The <strong>View</strong> page displays a submission's general "
"information and data."
msgstr ""
"На странице <strong>Просмотр</strong> "
"отображается общая информация и "
"данные об отправлении."
msgid ""
"The <strong>Table</strong> page displays a submission's general "
"information and data using tabular layout."
msgstr ""
"На странице <strong>Таблица</strong> "
"отображается общая информация и "
"данные об отправлении в виде таблицы."
msgid ""
"The <strong>Plain text</strong> page displays a submission's general "
"information and data as plain text."
msgstr ""
"На странице <strong>Простой текст</strong> "
"отображается общая информация и "
"данные об отправлении в виде простого "
"текста."
msgid "Submission: Data (YAML)"
msgstr "Отправление: Данные (YAML)"
msgid ""
"The <strong>Data (YAML)</strong> page displays a submission's raw data "
"as YAML."
msgstr ""
"На странице <strong>Данные (YAML)</strong> "
"отображаются исходные данные "
"отправки в формате YAML."
msgid "Star/flag the status of this submission"
msgstr ""
"Отметить звёздочкой/флажком статус "
"этой заявки"
msgid "Autofocus the first element"
msgstr "Автофокусировка на первом элементе"
msgid "Allow this webform to be used as a template"
msgstr ""
"Разрешить использовать эту веб-форму "
"в качестве шаблона"
msgid "Disable saving of submissions"
msgstr "Отключить сохранение отправлений"
msgid "Allow users to post submissions from a dedicated URL"
msgstr ""
"Разрешить пользователям размещать "
"отправления с выделенного URL-адреса"
msgctxt "Show {limit} results per page"
msgid "Show"
msgstr "Показать"
msgid "Display collapse/expand all details link on all webforms"
msgstr ""
"Отображать ссылку "
"свернуть/развернуть все детали для "
"всех веб-форм"
msgid "Submit previous page when browser back button is clicked"
msgstr ""
"Отправка предыдущей страницы при "
"нажатии кнопки \"Назад\" в браузере"
msgid ""
"Submit previous page when browser back button is clicked for all "
"webforms"
msgstr ""
"Отправка предыдущей страницы при "
"нажатии кнопки \"Назад\" в браузере для "
"всех веб-форм"
msgid "Flagged/Starred"
msgstr "Отмечено флагом/звёздочкой"
msgid "Display required indicator"
msgstr ""
"Отключить индикатор обязательного "
"элемента"
msgid "Display required indicator label"
msgstr ""
"Отображать метку индикатора "
"обязательного элемента"
msgid "Locked [@total]"
msgstr "Заблокировано [@total]"
msgid "Unlocked [@total]"
msgstr "Не заблокировано [@total]"
msgid "If checked, this submissions will be starred when reviewing results."
msgstr ""
"Если флажок установлен, то при "
"просмотре результатов это "
"отправление будет отмечено "
"звёздочкой."
msgid "Lock this submission"
msgstr "Заблокировать это отправление"
msgid "If checked, users will not be able to update this submission."
msgstr ""
"Если флажок установлен, пользователи "
"не смогут обновлять это "
"представление."
msgid "Display required indicator on all webforms"
msgstr ""
"Отключить индикатор обязательного "
"элемента"
msgid "Indicates required field"
msgstr "Указывает обязательное поле"
msgid "Are you sure you want to delete this @item?"
msgid_plural "Are you sure you want to delete these @items?"
msgstr[0] ""
"Вы действительно хотите удалить этот "
"@item?"
msgstr[1] ""
"Вы действительно хотите удалить эти "
"@items?"
msgstr[2] ""
"Вы действительно хотите удалить эти "
"@items?"
msgid "Disable inline form errors"
msgstr "Отключить ошибки внутри форм"
msgid "Maximum @max characters"
msgstr "Максимум @max символов"
msgid "Disable inline form errors for all webforms"
msgstr ""
"Отключить ошибки внутри форм для всех "
"веб-форм"
msgid "Field overrides"
msgstr "Переопределения поля"
msgid "Dialog title"
msgstr "Заголовок диалога"
msgid "Archived [@total]"
msgstr "Архивировано [@total]"
msgid "@count result for @label"
msgid_plural "@count results for @label"
msgstr[0] "@count результат для @label"
msgstr[1] "@count результата для@label"
msgstr[2] "@count результатов для @label"
msgid "Filter by keyword"
msgstr "Фильтровать по ключевому слову"
msgid "Enter other…"
msgstr "Введите другое…"
msgid "On Ajax load, scroll to the top of the…"
msgstr ""
"При Ajax-загрузке прокрутить страницу в "
"верхнюю часть..."
msgid "Filter by submitted to"
msgstr "Фильтрация по отправленным в"
msgid "Element description/help/more"
msgstr "Описание элемента/помощь/прочее"
msgid "Default form open message"
msgstr ""
"Сообщение об открытии формы по "
"умолчанию"
msgid "Filter by keyword."
msgstr "Фильтровать по ключевому слову."
msgid "Save + Add element"
msgstr "Сохранить и добавить элементы"
msgid "Select an element to add to \"@parent\""
msgstr ""
"Выберите элемент, чтобы добавить в "
"\"@parent\""
msgid "Lock submission"
msgstr "Заблокировать отправление"
msgid "Unlock submission"
msgstr "Разблокировать отправление"
msgid "Form title display"
msgstr "Отображение заголовка формы"
msgid "Source entity: Webform"
msgstr "Исходная сущность: Веб-форма"
msgid "This action will…"
msgstr "Это действие будет выполнять..."
msgid "Remove @total %label @submissions"
msgstr "Удаление @total %label @submissions"
msgid "Take a few minutes to complete"
msgstr "Займёт несколько минут на выполнение"
msgid "Yes, I want to clear all %label submissions"
msgstr ""
"Да, я хочу очистить все отправления "
"%label."
msgid "Archive this webform"
msgstr "Заархивировать эту веб-форму"
msgid "Form general settings"
msgstr "Основные настройки формы"
msgid "Sorry… This form is closed to new submissions."
msgstr ""
"Извините... Эта форма закрыта для новых "
"отправлений."
msgid "Ajax progress type"
msgstr "Тип прогресса Ajax"
msgid "Default Ajax progress type"
msgstr "Тип прогресса Ajax по умолчанию"
msgid "Default Ajax effect"
msgstr "Эффект Ajax по умолчанию"
msgid "Leave blank to hide this message."
msgstr ""
"Оставьте пустым, чтобы скрыть это "
"сообщение."
msgid "Label / Description"
msgstr "Название / Описание"
msgid "Webform submission from: [webform_submission:source-title]"
msgstr ""
"Отправка веб-формы от: "
"[webform_submission:source-title]"
msgid "Enter @none to hide this message."
msgstr ""
"Введите @none, чтобы скрыть это "
"сообщение."
msgid "Enter @none or @none_translated to hide this message."
msgstr ""
"Введите @none или @none_translated, чтобы скрыть "
"это сообщение."
msgid "Form Ajax settings"
msgstr "Настройки Ajax в форме"
msgid ""
"Setting autocomplete to off will disable autocompletion for this "
"element. Select 'Autofill' to use semantic attribute values for "
"collecting certain types of user information."
msgstr ""
"Установка значения \"Автозаполнение\" "
"отключит автозаполнение для этого "
"элемента. Выберите \"Автозаполнение\", "
"чтобы использовать значения "
"семантических атрибутов для сбора "
"определенных типов пользовательской "
"информации."
msgid "Allow users to customize the submission results table"
msgstr ""
"Разрешить пользователям настраивать "
"таблицу результатов отправки"
msgid ""
"If checked, users can customize the submission results table for this "
"webform."
msgstr ""
"Если флажок установлен, пользователи "
"могут настраивать таблицу "
"результатов отправки для этой "
"веб-формы."
msgid "@count submission"
msgid_plural "@count submissions"
msgstr[0] "@count отправление"
msgstr[1] "@count отправления"
msgstr[2] "@count отправлений"
msgid "@count webform"
msgid_plural "@count webforms"
msgstr[0] "@count веб-форма"
msgstr[1] "@count веб-формы"
msgstr[2] "@count веб-форм"
msgid "Remove @item @number"
msgstr "Удаление @item @number"
msgid "Provided by the @plugin_id mail plugin."
msgstr ""
"Предоставлено почтовым плагином "
"@plugin_id."
msgid "The phone number is not valid. (e.g. @example)"
msgstr ""
"Номер телефона неверный. (например, "
"@example)"
msgid "The phone number is not valid."
msgstr "Номер телефона неверный."
msgid "Open webform configuration"
msgstr "Открыть настройки веб-формы"
msgid "Archive webform"
msgstr "Архивировать веб-форму"
msgid "Close webform"
msgstr "Закрыть веб-форму"
msgid "Open webform"
msgstr "Открыть веб-форму"
msgid "Star/flag submission"
msgstr "Отметить отправление звездой/флагом"
msgid "Webform: Spam protection"
msgstr "Вебформа: защита от спама"
msgid "Webform Spam protection module installed."
msgstr ""
"Модуль защиты вебформы от спама "
"установлен."
msgid "This webform has no elements added to it."
msgstr "Эта веб-форма не имеет элементов."
msgid "Allow users to post submissions from a dedicated URL for all webform"
msgstr ""
"Разрешить пользователям размещать "
"отправления с выделенного URL-адреса "
"для всех веб-форм"
# Russian translation of Excel Serialization (2.0.3)
# Copyright (c) 2025 by the Russian translation team
#
msgid ""
msgstr ""
"Project-Id-Version: Excel Serialization (2.0.3)\n"
"POT-Creation-Date: 2025-01-27 01:22+0000\n"
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=((((n%10)==1)&&((n%100)!=11))?(0):(((((n%10)>=2)&&((n%10)<=4))&&(((n%100)<10)||((n%100)>=20)))?(1):2));\n"
msgid "Title"
msgstr "Заголовок"
msgid "Subject"
msgstr "Тема"
msgid "Manager"
msgstr "Менеджер"
msgid "Description"
msgstr "Описание"
msgid "Category"
msgstr "Категория"
msgid "Format"
msgstr "Формат"
msgid "Filename"
msgstr "Имя файла"
msgid "Keywords"
msgstr "Ключевые слова"
msgid "Company"
msgstr "Компания"
msgid "Operator"
msgstr "Оператор"
msgid "Bold"
msgstr "Жирный"
msgid "Italic"
msgstr "Курсив"
msgid "Web services"
msgstr "Веб-службы"
msgid "Rule"
msgstr "Правило"
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment