Release 2.0.17 (#3992)
* prevent empty title for select options * removed css for unused sweetalert * fix isWeekend() check with DateTimeInterface * reset timesheet rates on "create copy" * wrap long names in multi-selects - fix #4001 * rename profile menus * show all possible links in user profile dropdown * check if plugin is compatible before displaying the buy link
This commit is contained in:
@@ -347,7 +347,13 @@ export default class KimaiFormSelect extends KimaiFormPlugin {
|
||||
--end;
|
||||
}
|
||||
|
||||
return (start > 0 || end < title.length) ? title.substring(start, end) : title;
|
||||
let result = (start > 0 || end < title.length) ? title.substring(start, end) : title;
|
||||
|
||||
if (result === '' && entity['name'] !== undefined) {
|
||||
return entity['name'];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
@import 'tables';
|
||||
@import 'calendar';
|
||||
@import 'ticktac';
|
||||
@import 'sweetalert';
|
||||
@import 'selectpicker';
|
||||
@import 'forms';
|
||||
@import 'modal';
|
||||
|
||||
@@ -9,9 +9,6 @@
|
||||
> input {
|
||||
min-width: unset;
|
||||
}
|
||||
.item {
|
||||
white-space: nowrap!important;
|
||||
}
|
||||
}
|
||||
|
||||
.ts-dropdown {
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
.swal2-popup {
|
||||
font-size: unset;
|
||||
}
|
||||
|
||||
body.swal2-toast-shown .swal2-container {
|
||||
// never block the top two bars double-bars display (smaller displays)
|
||||
@media only screen and (max-width: 768px) {
|
||||
top: 95px !important;
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
// never block the top bar on single-bar display (larger devices)
|
||||
@media only screen and (min-width: 768px) {
|
||||
top: 60px !important;
|
||||
}
|
||||
}
|
||||
@@ -2740,11 +2740,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Export/ExportFilename.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Export\\\\ExportFilename\\:\\:getFilename\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/Export/ExportFilename.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$customer of method App\\\\Export\\\\ExportFilename\\:\\:getCustomerName\\(\\) expects App\\\\Entity\\\\Customer, App\\\\Entity\\\\Customer\\|null given\\.$#"
|
||||
count: 1
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
public/build/app.c61734af.js
Normal file
2
public/build/app.c61734af.js
Normal file
File diff suppressed because one or more lines are too long
1
public/build/app.d3ccebf5.css
Normal file
1
public/build/app.d3ccebf5.css
Normal file
File diff suppressed because one or more lines are too long
@@ -3,10 +3,10 @@
|
||||
"app": {
|
||||
"js": [
|
||||
"/build/runtime.f0079159.js",
|
||||
"/build/app.902831bc.js"
|
||||
"/build/app.c61734af.js"
|
||||
],
|
||||
"css": [
|
||||
"/build/app.b10b16e5.css"
|
||||
"/build/app.d3ccebf5.css"
|
||||
]
|
||||
},
|
||||
"export-pdf": {
|
||||
@@ -63,8 +63,8 @@
|
||||
},
|
||||
"integrity": {
|
||||
"/build/runtime.f0079159.js": "sha384-H22sAW1aTvyIPqvHOvGXWSWTxf0y6mptp+MsVmyXCfjx/WJjBbhX9gbUZ+qIuihV",
|
||||
"/build/app.902831bc.js": "sha384-t6GwvEu6PBNMxOHW4JHSScxFmGE7tGus/IZoBBZHrGFdtDZtKjweNAqJ00VmSnSp",
|
||||
"/build/app.b10b16e5.css": "sha384-dwEgmHAQRm4PP7XTYkJfIoB+Iumd+0WuH5FyoC/+qC3WQ/e1gCTmlx9M2mIBxPuK",
|
||||
"/build/app.c61734af.js": "sha384-EP0ldSWtoYJlwRuaj2IjQCncdMT5rlz4cfZgDzciCd0i2pGn6MEijujB4bUU0PCP",
|
||||
"/build/app.d3ccebf5.css": "sha384-9ufQd+D9ebk0tkPhQvGxswVMeHGES5GgJGK5lsDFS9+dQmdKbxwB/58ZSCVA3N/2",
|
||||
"/build/export-pdf.587575e7.js": "sha384-J50GStmmfVwUTN4dIRQ02eg9hyzGFPSzpTtpPody92j0V6zCqw+s5l8+ZhVTugeW",
|
||||
"/build/export-pdf.d8a6c23b.css": "sha384-ztepocHE4rnGE9eKZ4kL6jTKaePUyiwiB9TjJjstjpf/ckcKg1HedrEOOk/8ElJg",
|
||||
"/build/invoice.c8ae95ad.js": "sha384-2eVY7MBiMQxo1vhfizU+fYfEZbz9bYUdzqxnpTQhxpYiLaxeSV4WnaObq2G7/Pks",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"build/app.css": "/build/app.b10b16e5.css",
|
||||
"build/app.js": "/build/app.902831bc.js",
|
||||
"build/app.css": "/build/app.d3ccebf5.css",
|
||||
"build/app.js": "/build/app.c61734af.js",
|
||||
"build/export-pdf.css": "/build/export-pdf.d8a6c23b.css",
|
||||
"build/export-pdf.js": "/build/export-pdf.587575e7.js",
|
||||
"build/invoice.css": "/build/invoice.d0ae14e1.css",
|
||||
|
||||
@@ -17,11 +17,11 @@ class Constants
|
||||
/**
|
||||
* The current release version
|
||||
*/
|
||||
public const VERSION = '2.0.16';
|
||||
public const VERSION = '2.0.17';
|
||||
/**
|
||||
* The current release: major * 10000 + minor * 100 + patch
|
||||
*/
|
||||
public const VERSION_ID = 20016;
|
||||
public const VERSION_ID = 20017;
|
||||
/**
|
||||
* The software name
|
||||
*/
|
||||
|
||||
@@ -202,6 +202,7 @@ abstract class TimesheetAbstractController extends AbstractController
|
||||
protected function duplicate(Timesheet $timesheet, Request $request): Response
|
||||
{
|
||||
$copyTimesheet = clone $timesheet;
|
||||
$copyTimesheet->resetRates();
|
||||
|
||||
$event = new TimesheetMetaDefinitionEvent($copyTimesheet);
|
||||
$this->dispatcher->dispatch($event);
|
||||
|
||||
@@ -615,6 +615,15 @@ class Timesheet implements EntityWithMetaFields, ExportableItem
|
||||
return $all;
|
||||
}
|
||||
|
||||
public function resetRates(): void
|
||||
{
|
||||
$this->setRate(0.00);
|
||||
$this->setInternalRate(null);
|
||||
$this->setHourlyRate(null);
|
||||
$this->setFixedRate(null);
|
||||
$this->setBillableMode(Timesheet::BILLABLE_AUTOMATIC);
|
||||
}
|
||||
|
||||
public function getMetaField(string $name): ?MetaTableTypeInterface
|
||||
{
|
||||
foreach ($this->meta as $field) {
|
||||
|
||||
@@ -997,7 +997,7 @@ class User implements UserInterface, EquatableInterface, ThemeUserInterface, Pas
|
||||
$this->password = $data['password'];
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
public function __toString(): string
|
||||
{
|
||||
return $this->getDisplayName();
|
||||
}
|
||||
|
||||
@@ -43,21 +43,22 @@ class UserDetailsSubscriber implements EventSubscriberInterface
|
||||
$event->setUser($user);
|
||||
|
||||
if ($this->auth->isGranted('view', $user)) {
|
||||
$event->addLink(
|
||||
new MenuItemModel('user_profile', 'my.profile', 'user_profile', ['username' => $user->getUserIdentifier()], 'fas fa-tachometer-alt')
|
||||
);
|
||||
$event->addLink(new MenuItemModel('user_profile', 'my.profile', 'user_profile', ['username' => $user->getUserIdentifier()]));
|
||||
}
|
||||
|
||||
if ($this->auth->isGranted('edit', $user)) {
|
||||
$event->addLink(
|
||||
new MenuItemModel('user_profile_edit', 'action.edit', 'user_profile_edit', ['username' => $user->getUserIdentifier()], 'fas fa-tachometer-alt')
|
||||
);
|
||||
$event->addLink(new MenuItemModel('user_profile_edit', 'action.edit', 'user_profile_edit', ['username' => $user->getUserIdentifier()]));
|
||||
}
|
||||
if ($this->auth->isGranted('password', $user)) {
|
||||
$event->addLink(new MenuItemModel('password', 'profile.password', 'user_profile_password', ['username' => $user->getUserIdentifier()]));
|
||||
}
|
||||
if ($this->auth->isGranted('2fa', $user)) {
|
||||
$event->addLink(new MenuItemModel('2fa', 'profile.2fa', 'user_profile_2fa', ['username' => $user->getUserIdentifier()]));
|
||||
}
|
||||
if ($this->auth->isGranted('api-token', $user)) {
|
||||
$event->addLink(new MenuItemModel('api-token', 'profile.api-token', 'user_profile_api_token', ['username' => $user->getUserIdentifier()]));
|
||||
}
|
||||
|
||||
if ($this->auth->isGranted('preferences', $user)) {
|
||||
$event->addLink(
|
||||
new MenuItemModel('user_profile_preferences', 'profile.preferences', 'user_profile_preferences', ['username' => $user->getUserIdentifier()], 'fas fa-tachometer-alt')
|
||||
);
|
||||
$event->addLink(new MenuItemModel('user_profile_preferences', 'profile.preferences', 'user_profile_preferences', ['username' => $user->getUserIdentifier()]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ final class ExportFilename
|
||||
return FileHelper::convertToAsciiFilename($filename);
|
||||
}
|
||||
|
||||
public function getFilename()
|
||||
public function getFilename(): string
|
||||
{
|
||||
if ($this->filename === null) {
|
||||
$filename = date('Ymd');
|
||||
@@ -91,7 +91,7 @@ final class ExportFilename
|
||||
return $this->filename;
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
public function __toString(): string
|
||||
{
|
||||
return $this->getFilename();
|
||||
}
|
||||
|
||||
@@ -17,29 +17,20 @@ final class RateResetCalculator implements CalculatorInterface
|
||||
public function calculate(Timesheet $record, array $changeset): void
|
||||
{
|
||||
// check if the rate was changed manually
|
||||
$changedRate = false;
|
||||
foreach (['hourlyRate', 'fixedRate', 'internalRate', 'rate'] as $field) {
|
||||
if (\array_key_exists($field, $changeset)) {
|
||||
$changedRate = true;
|
||||
break;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// if no manual rate changed was applied:
|
||||
// check if a field changed, that is relevant for the rate calculation: if one was changed =>
|
||||
// check if a field changed, that is relevant for the rate calculation
|
||||
// reset all rates, because most users do not even see their rates and would not be able
|
||||
// to fix or empty the rate, even if they knew that the changed project has another base rate
|
||||
if (!$changedRate) {
|
||||
foreach (['project', 'activity', 'user'] as $field) {
|
||||
if (\array_key_exists($field, $changeset)) {
|
||||
// this has room for minor improvements: entries with a manual rate might be changed
|
||||
$record->setRate(0.00);
|
||||
$record->setInternalRate(null);
|
||||
$record->setHourlyRate(null);
|
||||
$record->setFixedRate(null);
|
||||
$record->setBillableMode(Timesheet::BILLABLE_AUTOMATIC);
|
||||
break;
|
||||
}
|
||||
// to change the rate, even if they knew that the changed project has another base rate
|
||||
foreach (['project', 'activity', 'user'] as $field) {
|
||||
if (\array_key_exists($field, $changeset)) {
|
||||
$record->resetRates();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ final class LocaleFormatExtensions extends AbstractExtension implements LocaleAw
|
||||
|
||||
public function isWeekend(\DateTimeInterface|string|null $dateTime): bool
|
||||
{
|
||||
if (!$dateTime instanceof \DateTime) {
|
||||
if (!$dateTime instanceof \DateTimeInterface) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ final class SearchTerm
|
||||
return $this->originalTerm;
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
public function __toString(): string
|
||||
{
|
||||
return $this->originalTerm;
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
</td>
|
||||
<td class="{{ tables.data_table_column_class(tableName, columns, 'description') }}">{{ extension.description }}</td>
|
||||
<td class="{{ tables.data_table_column_class(tableName, columns, 'actions') }}">
|
||||
{% if extension.buy is defined and extension.buy is not empty %}
|
||||
{% if extension.buy is defined and extension.buy is not empty and (extension.minimum_version is not defined or (extension.minimum_version is not empty and constant('App\\Constants::VERSION') >= extension.minimum_version)) %}
|
||||
<a class="btn btn-icon btn-outline-secondary" href="{{ extension.buy }}" title="{{ 'buy'|trans({}, 'plugins') }}" target="_blank">{{ icon('shop') }}</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
|
||||
@@ -1406,7 +1406,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="FeFBn_3" resname="profile.2fa">
|
||||
<source>profile.2fa</source>
|
||||
<target state="translated">الاستيثاق بخطوتين (TOTP)</target>
|
||||
<target state="translated">الاستيثاق بخطوتين (2FA)</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Y0PRG9Z" resname="profile.2fa_confirmation">
|
||||
<source>profile.2fa_confirmation</source>
|
||||
|
||||
@@ -1252,7 +1252,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="FeFBn_3" resname="profile.2fa">
|
||||
<source>profile.2fa</source>
|
||||
<target state="translated">Dvoufázové (TOTP)</target>
|
||||
<target state="translated">Dvoufázové (2FA)</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="IRzPWmL" resname="login.2fa_intro">
|
||||
<source>login.2fa_intro</source>
|
||||
|
||||
@@ -564,7 +564,7 @@
|
||||
<!-- 2FA -->
|
||||
<trans-unit id="FeFBn_3" resname="profile.2fa">
|
||||
<source>profile.2fa</source>
|
||||
<target>Zwei-Faktor (TOTP)</target>
|
||||
<target>Zwei-Faktor (2FA)</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="hPY2VcD" resname="profile.2fa_intro">
|
||||
<source>profile.2fa_intro</source>
|
||||
@@ -585,7 +585,7 @@
|
||||
<!-- END 2FA -->
|
||||
<trans-unit id="Z34ZpjK" resname="profile.api-token">
|
||||
<source>profile.api-token</source>
|
||||
<target>API</target>
|
||||
<target>API Zugang</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="ygtTz8." resname="profile.roles">
|
||||
<source>profile.roles</source>
|
||||
|
||||
@@ -547,7 +547,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="Z34ZpjK" resname="profile.api-token">
|
||||
<source>profile.api-token</source>
|
||||
<target>API</target>
|
||||
<target>API Zugang</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="A6TLLQa" resname="profile.password">
|
||||
<source>profile.password</source>
|
||||
|
||||
@@ -564,7 +564,7 @@
|
||||
<!-- 2FA -->
|
||||
<trans-unit id="FeFBn_3" resname="profile.2fa">
|
||||
<source>profile.2fa</source>
|
||||
<target>Two-Factor (TOTP)</target>
|
||||
<target>Two-Factor (2FA)</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="hPY2VcD" resname="profile.2fa_intro">
|
||||
<source>profile.2fa_intro</source>
|
||||
@@ -585,7 +585,7 @@
|
||||
<!-- END 2FA -->
|
||||
<trans-unit id="Z34ZpjK" resname="profile.api-token">
|
||||
<source>profile.api-token</source>
|
||||
<target>API</target>
|
||||
<target>API Access</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="ygtTz8." resname="profile.roles">
|
||||
<source>profile.roles</source>
|
||||
|
||||
@@ -1316,7 +1316,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="FeFBn_3" resname="profile.2fa">
|
||||
<source>profile.2fa</source>
|
||||
<target state="translated">Dos factores (TOTP)</target>
|
||||
<target state="translated">Dos factores (2FA)</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Y0PRG9Z" resname="profile.2fa_confirmation">
|
||||
<source>profile.2fa_confirmation</source>
|
||||
|
||||
@@ -1253,7 +1253,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="FeFBn_3" resname="profile.2fa">
|
||||
<source>profile.2fa</source>
|
||||
<target state="translated">دو عاملی (TOTP)</target>
|
||||
<target state="translated">دو عاملی (2FA)</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Y0PRG9Z" resname="profile.2fa_confirmation">
|
||||
<source>profile.2fa_confirmation</source>
|
||||
|
||||
@@ -1292,7 +1292,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="FeFBn_3" resname="profile.2fa">
|
||||
<source>profile.2fa</source>
|
||||
<target state="translated">double facteur (TOTP)</target>
|
||||
<target state="translated">double facteur (2FA)</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="hPY2VcD" resname="profile.2fa_intro">
|
||||
<source>profile.2fa_intro</source>
|
||||
|
||||
@@ -1220,7 +1220,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="FeFBn_3" resname="profile.2fa">
|
||||
<source>profile.2fa</source>
|
||||
<target state="translated">דו־שלבי (TOTP)</target>
|
||||
<target state="translated">דו־שלבי (2FA)</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Y0PRG9Z" resname="profile.2fa_confirmation">
|
||||
<source>profile.2fa_confirmation</source>
|
||||
|
||||
@@ -1308,7 +1308,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="FeFBn_3" resname="profile.2fa">
|
||||
<source>profile.2fa</source>
|
||||
<target state="translated">Dvofaktorski (TOTP)</target>
|
||||
<target state="translated">Dvofaktorski (2FA)</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="hPY2VcD" resname="profile.2fa_intro">
|
||||
<source>profile.2fa_intro</source>
|
||||
|
||||
@@ -1283,7 +1283,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="FeFBn_3" resname="profile.2fa">
|
||||
<source>profile.2fa</source>
|
||||
<target state="translated">A due fattori (TOTP)</target>
|
||||
<target state="translated">A due fattori (2FA)</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="hPY2VcD" resname="profile.2fa_intro">
|
||||
<source>profile.2fa_intro</source>
|
||||
|
||||
@@ -1274,7 +1274,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="FeFBn_3" resname="profile.2fa">
|
||||
<source>profile.2fa</source>
|
||||
<target state="translated">To-faktor (TOTP)</target>
|
||||
<target state="translated">To-faktor (2FA)</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="oq1jcSQ" resname="help.billable">
|
||||
<source>help.billable</source>
|
||||
|
||||
@@ -1264,7 +1264,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="FeFBn_3" resname="profile.2fa">
|
||||
<source>profile.2fa</source>
|
||||
<target state="translated">Dwuskładnikowe (TOTP)</target>
|
||||
<target state="translated">Dwuskładnikowe (2FA)</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="o0hsx2H" resname="mark_as_open">
|
||||
<source>mark_as_open</source>
|
||||
|
||||
@@ -1228,7 +1228,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="FeFBn_3" resname="profile.2fa">
|
||||
<source>profile.2fa</source>
|
||||
<target state="translated">Dois fatores (TOTP)</target>
|
||||
<target state="translated">Dois fatores (2FA)</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="hPY2VcD" resname="profile.2fa_intro">
|
||||
<source>profile.2fa_intro</source>
|
||||
|
||||
@@ -1268,7 +1268,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="FeFBn_3" resname="profile.2fa">
|
||||
<source>profile.2fa</source>
|
||||
<target state="translated">Dois fatores (TOTP)</target>
|
||||
<target state="translated">Dois fatores (2FA)</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="hPY2VcD" resname="profile.2fa_intro">
|
||||
<source>profile.2fa_intro</source>
|
||||
|
||||
@@ -1176,7 +1176,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="FeFBn_3" resname="profile.2fa">
|
||||
<source>profile.2fa</source>
|
||||
<target state="translated">Doi factori (TOTP)</target>
|
||||
<target state="translated">Doi factori (2FA)</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="IRzPWmL" resname="login.2fa_intro">
|
||||
<source>login.2fa_intro</source>
|
||||
|
||||
@@ -1254,7 +1254,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="FeFBn_3" resname="profile.2fa">
|
||||
<source>profile.2fa</source>
|
||||
<target state="translated">Двухфакторная (TOTP)</target>
|
||||
<target state="translated">Двухфакторная (2FA)</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="IRzPWmL" resname="login.2fa_intro">
|
||||
<source>login.2fa_intro</source>
|
||||
|
||||
@@ -1292,7 +1292,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="FeFBn_3" resname="profile.2fa">
|
||||
<source>profile.2fa</source>
|
||||
<target state="translated">Tvåfaktor (TOTP)</target>
|
||||
<target state="translated">Tvåfaktor (2FA)</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="aGk9Aqt" resname="desktop">
|
||||
<source>desktop</source>
|
||||
|
||||
@@ -1244,7 +1244,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="FeFBn_3" resname="profile.2fa">
|
||||
<source>profile.2fa</source>
|
||||
<target state="translated">İki Adımlı (TOTP)</target>
|
||||
<target state="translated">İki Adımlı (2FA)</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="hPY2VcD" resname="profile.2fa_intro">
|
||||
<source>profile.2fa_intro</source>
|
||||
|
||||
@@ -1180,7 +1180,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="FeFBn_3" resname="profile.2fa">
|
||||
<source>profile.2fa</source>
|
||||
<target state="translated">Двофакторна аутентифікація (TOTP)</target>
|
||||
<target state="translated">Двофакторна аутентифікація (2FA)</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="IRzPWmL" resname="login.2fa_intro">
|
||||
<source>login.2fa_intro</source>
|
||||
|
||||
@@ -1224,7 +1224,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="FeFBn_3" resname="profile.2fa">
|
||||
<source>profile.2fa</source>
|
||||
<target state="translated">双因素 (TOTP)</target>
|
||||
<target state="translated">双因素 (2FA)</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="IRzPWmL" resname="login.2fa_intro">
|
||||
<source>login.2fa_intro</source>
|
||||
|
||||
Reference in New Issue
Block a user