mirror of
https://github.com/Part-DB/Part-DB-server.git
synced 2026-01-13 05:39:33 +00:00
Merge remote-tracking branch 'upstream/master' into bulk-edit-tags
This commit is contained in:
commit
858c7a6e0f
20 changed files with 1218 additions and 808 deletions
|
|
@ -47,6 +47,7 @@
|
|||
PassEnv PROVIDER_REICHELT_ENABLED PROVIDER_REICHELT_CURRENCY PROVIDER_REICHELT_COUNTRY PROVIDER_REICHELT_LANGUAGE PROVIDER_REICHELT_INCLUDE_VAT
|
||||
PassEnv PROVIDER_POLLIN_ENABLED
|
||||
PassEnv EDA_KICAD_CATEGORY_DEPTH
|
||||
PassEnv SHOW_PART_IMAGE_OVERLAY
|
||||
|
||||
# For most configuration files from conf-available/, which are
|
||||
# enabled or disabled at a global level, it is possible to
|
||||
|
|
|
|||
3
.env
3
.env
|
|
@ -305,6 +305,9 @@ FIXER_API_KEY=CHANGEME
|
|||
# When this is empty the content of config/banner.md is used as banner
|
||||
BANNER=""
|
||||
|
||||
# Enable the part image overlay which shows name and filename of the picture
|
||||
SHOW_PART_IMAGE_OVERLAY=1
|
||||
|
||||
APP_ENV=prod
|
||||
APP_SECRET=a03498528f5a5fc089273ec9ae5b2849
|
||||
|
||||
|
|
|
|||
2
VERSION
2
VERSION
|
|
@ -1 +1 @@
|
|||
1.17.1
|
||||
1.17.3
|
||||
|
|
|
|||
|
|
@ -33,7 +33,10 @@ export default class extends Controller {
|
|||
{
|
||||
let value = "";
|
||||
if (this.unitValue) {
|
||||
value = "\\mathrm{" + this.inputTarget.value + "}";
|
||||
//Escape percentage signs
|
||||
value = this.inputTarget.value.replace(/%/g, '\\%');
|
||||
|
||||
value = "\\mathrm{" + value + "}";
|
||||
} else {
|
||||
value = this.inputTarget.value;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,7 +85,9 @@ export default class extends Controller
|
|||
tmp += '<span>' + katex.renderToString(data.symbol) + '</span>'
|
||||
}
|
||||
if (data.unit) {
|
||||
tmp += '<span class="ms-2">' + katex.renderToString('[' + data.unit + ']') + '</span>'
|
||||
let unit = data.unit.replace(/%/g, '\\%');
|
||||
unit = "\\mathrm{" + unit + "}";
|
||||
tmp += '<span class="ms-2">' + katex.renderToString('[' + unit + ']') + '</span>'
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
1755
composer.lock
generated
1755
composer.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -21,6 +21,7 @@ twig:
|
|||
available_themes: '%partdb.available_themes%'
|
||||
saml_enabled: '%partdb.saml.enabled%'
|
||||
part_preview_generator: '@App\Services\Attachments\PartPreviewGenerator'
|
||||
img_overlay: '%partdb.show_part_image_overlay%'
|
||||
|
||||
when@test:
|
||||
twig:
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ parameters:
|
|||
# Miscellaneous
|
||||
######################################################################################################################
|
||||
partdb.demo_mode: '%env(bool:DEMO_MODE)%' # If set to true, all potentially dangerous things are disabled (like changing passwords of the own user)
|
||||
partdb.show_part_image_overlay: '%env(bool:SHOW_PART_IMAGE_OVERLAY)%' # If set to false, the filename overlay of the part image will be disabled
|
||||
|
||||
# Set the themes from which the user can choose from in the settings.
|
||||
# Themes commented here by default, are not really usable, because of display problems. Enable them at your own risk!
|
||||
|
|
|
|||
|
|
@ -95,6 +95,8 @@ bundled with Part-DB. Set `DATABASE_MYSQL_SSL_VERIFY_CERT` if you want to accept
|
|||
particularly for securing and protecting various aspects of your application. It's a secret key that is used for
|
||||
cryptographic operations and security measures (session management, CSRF protection, etc..). Therefore this
|
||||
value should be handled as confidential data and not shared publicly.
|
||||
* `SHOW_PART_IMAGE_OVERLAY`: Set to 0 to disable the part image overlay, which appears if you hover over an image in the
|
||||
part image gallery
|
||||
|
||||
### E-Mail settings
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@
|
|||
"@ckeditor/ckeditor5-block-quote": "^44.0.0",
|
||||
"@ckeditor/ckeditor5-code-block": "^44.0.0",
|
||||
"@ckeditor/ckeditor5-dev-translations": "^43.0.1",
|
||||
"@ckeditor/ckeditor5-dev-utils": "^43.0.1",
|
||||
"@ckeditor/ckeditor5-dev-utils": "43.0.*",
|
||||
"@ckeditor/ckeditor5-editor-classic": "^44.0.0",
|
||||
"@ckeditor/ckeditor5-essentials": "^44.0.0",
|
||||
"@ckeditor/ckeditor5-find-and-replace": "^44.0.0",
|
||||
|
|
|
|||
|
|
@ -217,7 +217,7 @@ abstract class AbstractParameter extends AbstractNamedDBElement implements Uniqu
|
|||
|
||||
$str = '';
|
||||
$bracket_opened = false;
|
||||
if ($this->value_typical) {
|
||||
if ($this->value_typical !== null) {
|
||||
$str .= $this->getValueTypicalWithUnit($latex_formatted);
|
||||
if ($this->value_min || $this->value_max) {
|
||||
$bracket_opened = true;
|
||||
|
|
@ -225,11 +225,11 @@ abstract class AbstractParameter extends AbstractNamedDBElement implements Uniqu
|
|||
}
|
||||
}
|
||||
|
||||
if ($this->value_max && $this->value_min) {
|
||||
if ($this->value_max !== null && $this->value_min !== null) {
|
||||
$str .= $this->getValueMinWithUnit($latex_formatted).' ... '.$this->getValueMaxWithUnit($latex_formatted);
|
||||
} elseif ($this->value_max) {
|
||||
} elseif ($this->value_max !== null) {
|
||||
$str .= 'max. '.$this->getValueMaxWithUnit($latex_formatted);
|
||||
} elseif ($this->value_min) {
|
||||
} elseif ($this->value_min !== null) {
|
||||
$str .= 'min. '.$this->getValueMinWithUnit($latex_formatted);
|
||||
}
|
||||
|
||||
|
|
@ -449,7 +449,10 @@ abstract class AbstractParameter extends AbstractNamedDBElement implements Uniqu
|
|||
if (!$with_latex) {
|
||||
$unit = $this->unit;
|
||||
} else {
|
||||
$unit = '$\mathrm{'.$this->unit.'}$';
|
||||
//Escape the percentage sign for convenience (as latex uses it as comment and it is often used in units)
|
||||
$escaped = preg_replace('/\\\\?%/', "\\\\%", $this->unit);
|
||||
|
||||
$unit = '$\mathrm{'.$escaped.'}$';
|
||||
}
|
||||
|
||||
return $str.' '.$unit;
|
||||
|
|
@ -457,7 +460,7 @@ abstract class AbstractParameter extends AbstractNamedDBElement implements Uniqu
|
|||
|
||||
return $str;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the class of the element that is allowed to be associated with this attachment.
|
||||
* @return string
|
||||
|
|
|
|||
|
|
@ -112,12 +112,12 @@ class AttachmentURLGenerator
|
|||
/**
|
||||
* Returns a URL to a thumbnail of the attachment file.
|
||||
* For external files the original URL is returned.
|
||||
* @return string|null The URL or null if the attachment file is not existing
|
||||
* @return string|null The URL or null if the attachment file is not existing or is invalid
|
||||
*/
|
||||
public function getThumbnailURL(Attachment $attachment, string $filter_name = 'thumbnail_sm'): ?string
|
||||
{
|
||||
if (!$attachment->isPicture()) {
|
||||
throw new InvalidArgumentException('Thumbnail creation only works for picture attachments!');
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!$attachment->hasInternal()){
|
||||
|
|
|
|||
|
|
@ -237,6 +237,49 @@ class KiCadHelper
|
|||
$result["fields"]["Part-DB IPN"] = $this->createField($part->getIpn());
|
||||
}
|
||||
|
||||
// Add supplier information from orderdetails (include obsolete orderdetails)
|
||||
if ($part->getOrderdetails(false)->count() > 0) {
|
||||
$supplierCounts = [];
|
||||
|
||||
foreach ($part->getOrderdetails(false) as $orderdetail) {
|
||||
if ($orderdetail->getSupplier() !== null && $orderdetail->getSupplierPartNr() !== '') {
|
||||
$supplierName = $orderdetail->getSupplier()->getName();
|
||||
|
||||
$supplierName .= " SPN"; // Append "SPN" to the supplier name to indicate Supplier Part Number
|
||||
|
||||
if (!isset($supplierCounts[$supplierName])) {
|
||||
$supplierCounts[$supplierName] = 0;
|
||||
}
|
||||
$supplierCounts[$supplierName]++;
|
||||
|
||||
// Create field name with sequential number if more than one from same supplier (e.g. "Mouser", "Mouser 2", etc.)
|
||||
$fieldName = $supplierCounts[$supplierName] > 1
|
||||
? $supplierName . ' ' . $supplierCounts[$supplierName]
|
||||
: $supplierName;
|
||||
|
||||
$result["fields"][$fieldName] = $this->createField($orderdetail->getSupplierPartNr());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Add fields for KiCost:
|
||||
if ($part->getManufacturer() !== null) {
|
||||
$result["fields"]["manf"] = $this->createField($part->getManufacturer()->getName());
|
||||
}
|
||||
if ($part->getManufacturerProductNumber() !== "") {
|
||||
$result['fields']['manf#'] = $this->createField($part->getManufacturerProductNumber());
|
||||
}
|
||||
|
||||
//For each supplier, add a field with the supplier name and the supplier part number for KiCost
|
||||
if ($part->getOrderdetails(false)->count() > 0) {
|
||||
foreach ($part->getOrderdetails(false) as $orderdetail) {
|
||||
if ($orderdetail->getSupplier() !== null && $orderdetail->getSupplierPartNr() !== '') {
|
||||
$fieldName = mb_strtolower($orderdetail->getSupplier()->getName()) . '#';
|
||||
|
||||
$result["fields"][$fieldName] = $this->createField($orderdetail->getSupplierPartNr());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ class EntityImporter
|
|||
/**
|
||||
* Creates many entries at once, based on a (text) list of name.
|
||||
* The created entities are not persisted to database yet, so you have to do it yourself.
|
||||
* It returns all entities in the hierachy chain (even if they are already persisted).
|
||||
*
|
||||
* @template T of AbstractNamedDBElement
|
||||
* @param string $lines The list of names seperated by \n
|
||||
|
|
@ -132,32 +133,38 @@ class EntityImporter
|
|||
//We can only use the getNewEntityFromPath function, if the repository is a StructuralDBElementRepository
|
||||
if ($repo instanceof StructuralDBElementRepository) {
|
||||
$entities = $repo->getNewEntityFromPath($new_path);
|
||||
$entity = end($entities);
|
||||
if ($entity === false) {
|
||||
if ($entities === []) {
|
||||
throw new InvalidArgumentException('getNewEntityFromPath returned an empty array!');
|
||||
}
|
||||
} else { //Otherwise just create a new entity
|
||||
$entity = new $class_name;
|
||||
$entity->setName($name);
|
||||
$entities = [$entity];
|
||||
}
|
||||
|
||||
|
||||
//Validate entity
|
||||
$tmp = $this->validator->validate($entity);
|
||||
//If no error occured, write entry to DB:
|
||||
if (0 === count($tmp)) {
|
||||
$valid_entities[] = $entity;
|
||||
} else { //Otherwise log error
|
||||
$errors[] = [
|
||||
'entity' => $entity,
|
||||
'violations' => $tmp,
|
||||
];
|
||||
foreach ($entities as $entity) {
|
||||
$tmp = $this->validator->validate($entity);
|
||||
//If no error occured, write entry to DB:
|
||||
if (0 === count($tmp)) {
|
||||
$valid_entities[] = $entity;
|
||||
} else { //Otherwise log error
|
||||
$errors[] = [
|
||||
'entity' => $entity,
|
||||
'violations' => $tmp,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$last_element = $entity;
|
||||
$last_element = end($entities);
|
||||
if ($last_element === false) {
|
||||
$last_element = null;
|
||||
}
|
||||
}
|
||||
|
||||
return $valid_entities;
|
||||
//Only return objects once
|
||||
return array_values(array_unique($valid_entities));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -49,8 +49,8 @@ class PollinProvider implements InfoProviderInterface
|
|||
{
|
||||
return [
|
||||
'name' => 'Pollin',
|
||||
'description' => 'Webscrapping from pollin.de to get part information',
|
||||
'url' => 'https://www.reichelt.de/',
|
||||
'description' => 'Webscraping from pollin.de to get part information',
|
||||
'url' => 'https://www.pollin.de/',
|
||||
'disabled_help' => 'Set PROVIDER_POLLIN_ENABLED env to 1'
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ class ReicheltProvider implements InfoProviderInterface
|
|||
{
|
||||
return [
|
||||
'name' => 'Reichelt',
|
||||
'description' => 'Webscrapping from reichelt.com to get part information',
|
||||
'description' => 'Webscraping from reichelt.com to get part information',
|
||||
'url' => 'https://www.reichelt.com/',
|
||||
'disabled_help' => 'Set PROVIDER_REICHELT_ENABLED env to 1'
|
||||
];
|
||||
|
|
|
|||
|
|
@ -63,7 +63,8 @@ class TreeViewGenerator
|
|||
private readonly UrlGeneratorInterface $router,
|
||||
protected bool $rootNodeExpandedByDefault,
|
||||
protected bool $rootNodeEnabled,
|
||||
|
||||
//TODO: Make this configurable in the future
|
||||
protected bool $rootNodeRedirectsToNewEntity = false,
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
@ -174,10 +175,7 @@ class TreeViewGenerator
|
|||
}
|
||||
|
||||
if (($mode === 'list_parts_root' || $mode === 'devices') && $this->rootNodeEnabled) {
|
||||
//We show the root node as a link to the list of all parts
|
||||
$show_all_parts_url = $this->router->generate('parts_show_all');
|
||||
|
||||
$root_node = new TreeViewNode($this->entityClassToRootNodeString($class), $show_all_parts_url, $generic);
|
||||
$root_node = new TreeViewNode($this->entityClassToRootNodeString($class), $this->entityClassToRootNodeHref($class), $generic);
|
||||
$root_node->setExpanded($this->rootNodeExpandedByDefault);
|
||||
$root_node->setIcon($this->entityClassToRootNodeIcon($class));
|
||||
|
||||
|
|
@ -187,6 +185,27 @@ class TreeViewGenerator
|
|||
return array_merge($head, $generic);
|
||||
}
|
||||
|
||||
protected function entityClassToRootNodeHref(string $class): ?string
|
||||
{
|
||||
//If the root node should redirect to the new entity page, we return the URL for the new entity.
|
||||
if ($this->rootNodeRedirectsToNewEntity) {
|
||||
return match ($class) {
|
||||
Category::class => $this->router->generate('category_new'),
|
||||
StorageLocation::class => $this->router->generate('store_location_new'),
|
||||
Footprint::class => $this->router->generate('footprint_new'),
|
||||
Manufacturer::class => $this->router->generate('manufacturer_new'),
|
||||
Supplier::class => $this->router->generate('supplier_new'),
|
||||
Project::class => $this->router->generate('project_new'),
|
||||
default => null,
|
||||
};
|
||||
}
|
||||
|
||||
return match ($class) {
|
||||
Project::class => $this->router->generate('project_new'),
|
||||
default => $this->router->generate('parts_show_all')
|
||||
};
|
||||
}
|
||||
|
||||
protected function entityClassToRootNodeString(string $class): string
|
||||
{
|
||||
return match ($class) {
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
<div class="carousel-item {% if loop.first %}active{% endif %}">
|
||||
<a href="{{ entity_url(pic, 'file_view') }}" data-turbo="false" target="_blank" rel="noopener">
|
||||
<img class="d-block w-100 img-fluid img-thumbnail bg-light part-info-image" src="{{ entity_url(pic, 'file_view') }}" alt="">
|
||||
{% if img_overlay %}
|
||||
<div class="mask"></div>
|
||||
<div class="carousel-caption-hover">
|
||||
<div class="carousel-caption text-white">
|
||||
|
|
@ -21,6 +22,7 @@
|
|||
<div>{{ entity_type_label(pic.element) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</a>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
|
|
|||
|
|
@ -75,8 +75,8 @@ class EntityImporterTest extends WebTestCase
|
|||
$em = self::getContainer()->get(EntityManagerInterface::class);
|
||||
$parent = $em->find(AttachmentType::class, 1);
|
||||
$results = $this->service->massCreation($lines, AttachmentType::class, $parent, $errors);
|
||||
$this->assertCount(3, $results);
|
||||
$this->assertSame($parent, $results[0]->getParent());
|
||||
$this->assertCount(4, $results);
|
||||
$this->assertSame("Test 1", $results[1]->getName());
|
||||
|
||||
//Test for addition of existing elements
|
||||
$errors = [];
|
||||
|
|
@ -113,6 +113,31 @@ EOT;
|
|||
|
||||
}
|
||||
|
||||
public function testMassCreationArrow(): void
|
||||
{
|
||||
$input = <<<EOT
|
||||
Test1 -> Test1.1
|
||||
Test1 -> Test1.2
|
||||
Test2 -> Test2.1
|
||||
Test1
|
||||
Test1.3
|
||||
EOT;
|
||||
|
||||
$errors = [];
|
||||
$results = $this->service->massCreation($input, AttachmentType::class, null, $errors);
|
||||
|
||||
//We have 6 elements, and 0 errors
|
||||
$this->assertCount(0, $errors);
|
||||
$this->assertCount(6, $results);
|
||||
|
||||
$this->assertEquals('Test1', $results[0]->getName());
|
||||
$this->assertEquals('Test1.1', $results[1]->getName());
|
||||
$this->assertEquals('Test1.2', $results[2]->getName());
|
||||
$this->assertEquals('Test2', $results[3]->getName());
|
||||
$this->assertEquals('Test2.1', $results[4]->getName());
|
||||
$this->assertEquals('Test1.3', $results[5]->getName());
|
||||
}
|
||||
|
||||
public function testMassCreationNested(): void
|
||||
{
|
||||
$input = <<<EOT
|
||||
|
|
@ -132,15 +157,15 @@ EOT;
|
|||
|
||||
//We have 7 elements, and 0 errors
|
||||
$this->assertCount(0, $errors);
|
||||
$this->assertCount(7, $results);
|
||||
$this->assertCount(8, $results);
|
||||
|
||||
$element1 = $results[0];
|
||||
$element11 = $results[1];
|
||||
$element111 = $results[2];
|
||||
$element112 = $results[3];
|
||||
$element12 = $results[4];
|
||||
$element121 = $results[5];
|
||||
$element2 = $results[6];
|
||||
$element1 = $results[1];
|
||||
$element11 = $results[2];
|
||||
$element111 = $results[3];
|
||||
$element112 = $results[4];
|
||||
$element12 = $results[5];
|
||||
$element121 = $results[6];
|
||||
$element2 = $results[7];
|
||||
|
||||
$this->assertSame('Test 1', $element1->getName());
|
||||
$this->assertSame('Test 1.1', $element11->getName());
|
||||
|
|
|
|||
|
|
@ -242,7 +242,7 @@
|
|||
</notes>
|
||||
<segment state="final">
|
||||
<source>part.info.timetravel_hint</source>
|
||||
<target>This is how the part appeared before %timestamp%. <i>Please note that this feature is experimental, so the info may not be correct.</i></target>
|
||||
<target><![CDATA[This is how the part appeared before %timestamp%. <i>Please note that this feature is experimental, so the info may not be correct.</i>]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="3exvSpl" name="standard.label">
|
||||
|
|
@ -731,10 +731,10 @@
|
|||
</notes>
|
||||
<segment state="translated">
|
||||
<source>user.edit.tfa.disable_tfa_message</source>
|
||||
<target>This will disable <b>all active two-factor authentication methods of the user</b> and delete the <b>backup codes</b>!
|
||||
<br>
|
||||
The user will have to set up all two-factor authentication methods again and print new backup codes! <br><br>
|
||||
<b>Only do this if you are absolutely sure about the identity of the user (seeking help), otherwise the account could be compromised by an attacker!</b></target>
|
||||
<target><![CDATA[This will disable <b>all active two-factor authentication methods of the user</b> and delete the <b>backup codes</b>!
|
||||
<br>
|
||||
The user will have to set up all two-factor authentication methods again and print new backup codes! <br><br>
|
||||
<b>Only do this if you are absolutely sure about the identity of the user (seeking help), otherwise the account could be compromised by an attacker!</b>]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="APsHYu0" name="user.edit.tfa.disable_tfa.btn">
|
||||
|
|
@ -885,9 +885,9 @@ The user will have to set up all two-factor authentication methods again and pri
|
|||
</notes>
|
||||
<segment state="translated">
|
||||
<source>entity.delete.message</source>
|
||||
<target>This can not be undone!
|
||||
<br>
|
||||
Sub elements will be moved upwards.</target>
|
||||
<target><![CDATA[This can not be undone!
|
||||
<br>
|
||||
Sub elements will be moved upwards.]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="2tKAqHw" name="entity.delete">
|
||||
|
|
@ -1441,7 +1441,7 @@ Sub elements will be moved upwards.</target>
|
|||
</notes>
|
||||
<segment state="final">
|
||||
<source>homepage.github.text</source>
|
||||
<target>Source, downloads, bug reports, to-do-list etc. can be found on <a href="%href%" class="link-external" target="_blank">GitHub project page</a></target>
|
||||
<target><![CDATA[Source, downloads, bug reports, to-do-list etc. can be found on <a href="%href%" class="link-external" target="_blank">GitHub project page</a>]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="D5OKsgU" name="homepage.help.caption">
|
||||
|
|
@ -1463,7 +1463,7 @@ Sub elements will be moved upwards.</target>
|
|||
</notes>
|
||||
<segment state="translated">
|
||||
<source>homepage.help.text</source>
|
||||
<target>Help and tips can be found in Wiki the <a href="%href%" class="link-external" target="_blank">GitHub page</a></target>
|
||||
<target><![CDATA[Help and tips can be found in Wiki the <a href="%href%" class="link-external" target="_blank">GitHub page</a>]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="dnirx4v" name="homepage.forum.caption">
|
||||
|
|
@ -1705,7 +1705,7 @@ Sub elements will be moved upwards.</target>
|
|||
</notes>
|
||||
<segment state="translated">
|
||||
<source>email.pw_reset.fallback</source>
|
||||
<target>If this does not work for you, go to <a href="%url%">%url%</a> and enter the following info</target>
|
||||
<target><![CDATA[If this does not work for you, go to <a href="%url%">%url%</a> and enter the following info]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="DduL9Hu" name="email.pw_reset.username">
|
||||
|
|
@ -1735,7 +1735,7 @@ Sub elements will be moved upwards.</target>
|
|||
</notes>
|
||||
<segment state="translated">
|
||||
<source>email.pw_reset.valid_unit %date%</source>
|
||||
<target>The reset token will be valid until <i>%date%</i>.</target>
|
||||
<target><![CDATA[The reset token will be valid until <i>%date%</i>.]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="8sBnjRy" name="orderdetail.delete">
|
||||
|
|
@ -3578,8 +3578,8 @@ Sub elements will be moved upwards.</target>
|
|||
</notes>
|
||||
<segment state="translated">
|
||||
<source>tfa_google.disable.confirm_message</source>
|
||||
<target>If you disable the Authenticator App, all backup codes will be deleted, so you may need to reprint them.<br>
|
||||
Also note that without two-factor authentication, your account is no longer as well protected against attackers!</target>
|
||||
<target><![CDATA[If you disable the Authenticator App, all backup codes will be deleted, so you may need to reprint them.<br>
|
||||
Also note that without two-factor authentication, your account is no longer as well protected against attackers!]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="yu9MSt5" name="tfa_google.disabled_message">
|
||||
|
|
@ -3599,7 +3599,7 @@ Also note that without two-factor authentication, your account is no longer as w
|
|||
</notes>
|
||||
<segment state="translated">
|
||||
<source>tfa_google.step.download</source>
|
||||
<target>Download an authenticator app (e.g. <a class="link-external" target="_blank" href="https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2">Google Authenticator</a> oder <a class="link-external" target="_blank" href="https://play.google.com/store/apps/details?id=org.fedorahosted.freeotp">FreeOTP Authenticator</a>)</target>
|
||||
<target><![CDATA[Download an authenticator app (e.g. <a class="link-external" target="_blank" href="https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2">Google Authenticator</a> oder <a class="link-external" target="_blank" href="https://play.google.com/store/apps/details?id=org.fedorahosted.freeotp">FreeOTP Authenticator</a>)]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="eriwJoR" name="tfa_google.step.scan">
|
||||
|
|
@ -3841,8 +3841,8 @@ Also note that without two-factor authentication, your account is no longer as w
|
|||
</notes>
|
||||
<segment state="translated">
|
||||
<source>tfa_trustedDevices.explanation</source>
|
||||
<target>When checking the second factor, the current computer can be marked as trustworthy, so no more two-factor checks on this computer are needed.
|
||||
If you have done this incorrectly or if a computer is no longer trusted, you can reset the status of <i>all </i>computers here.</target>
|
||||
<target><![CDATA[When checking the second factor, the current computer can be marked as trustworthy, so no more two-factor checks on this computer are needed.
|
||||
If you have done this incorrectly or if a computer is no longer trusted, you can reset the status of <i>all </i>computers here.]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="FZINq8z" name="tfa_trustedDevices.invalidate.confirm_title">
|
||||
|
|
@ -5313,7 +5313,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can
|
|||
</notes>
|
||||
<segment state="translated">
|
||||
<source>label_options.lines_mode.help</source>
|
||||
<target>If you select Twig here, the content field is interpreted as Twig template. See <a href="https://twig.symfony.com/doc/3.x/templates.html">Twig documentation</a> and <a href="https://docs.part-db.de/usage/labels.html#twig-mode">Wiki</a> for more information.</target>
|
||||
<target><![CDATA[If you select Twig here, the content field is interpreted as Twig template. See <a href="https://twig.symfony.com/doc/3.x/templates.html">Twig documentation</a> and <a href="https://docs.part-db.de/usage/labels.html#twig-mode">Wiki</a> for more information.]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="isvxbiX" name="label_options.page_size.label">
|
||||
|
|
@ -7157,12 +7157,15 @@ Exampletown</target>
|
|||
</notes>
|
||||
<segment state="translated">
|
||||
<source>mass_creation.lines.placeholder</source>
|
||||
<target>Element 1
|
||||
<target><![CDATA[Element 1
|
||||
Element 1.1
|
||||
Element 1.1.1
|
||||
Element 1.2
|
||||
Element 2
|
||||
Element 3</target>
|
||||
Element 3
|
||||
|
||||
Element 1 -> Element 1.1
|
||||
Element 1 -> Element 1.2]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="TWSqPFi" name="entity.mass_creation.btn">
|
||||
|
|
@ -9388,25 +9391,25 @@ Element 3</target>
|
|||
<unit id="r4vDLAt" name="filter.parameter_value_constraint.operator.<">
|
||||
<segment state="translated">
|
||||
<source>filter.parameter_value_constraint.operator.<</source>
|
||||
<target>Typ. Value <</target>
|
||||
<target><![CDATA[Typ. Value <]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="X9SA3UP" name="filter.parameter_value_constraint.operator.>">
|
||||
<segment state="translated">
|
||||
<source>filter.parameter_value_constraint.operator.></source>
|
||||
<target>Typ. Value ></target>
|
||||
<target><![CDATA[Typ. Value >]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="BQGaoQS" name="filter.parameter_value_constraint.operator.<=">
|
||||
<segment state="translated">
|
||||
<source>filter.parameter_value_constraint.operator.<=</source>
|
||||
<target>Typ. Value <=</target>
|
||||
<target><![CDATA[Typ. Value <=]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="2ha3P6g" name="filter.parameter_value_constraint.operator.>=">
|
||||
<segment state="translated">
|
||||
<source>filter.parameter_value_constraint.operator.>=</source>
|
||||
<target>Typ. Value >=</target>
|
||||
<target><![CDATA[Typ. Value >=]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="4DaBace" name="filter.parameter_value_constraint.operator.BETWEEN">
|
||||
|
|
@ -9514,7 +9517,7 @@ Element 3</target>
|
|||
<unit id="4tHhDtU" name="parts_list.search.searching_for">
|
||||
<segment state="translated">
|
||||
<source>parts_list.search.searching_for</source>
|
||||
<target>Searching parts with keyword <b>%keyword%</b></target>
|
||||
<target><![CDATA[Searching parts with keyword <b>%keyword%</b>]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="4vomKLa" name="parts_list.search_options.caption">
|
||||
|
|
@ -10174,13 +10177,13 @@ Element 3</target>
|
|||
<unit id="NdZ1t7a" name="project.builds.number_of_builds_possible">
|
||||
<segment state="translated">
|
||||
<source>project.builds.number_of_builds_possible</source>
|
||||
<target>You have enough stocked to build <b>%max_builds%</b> builds of this project.</target>
|
||||
<target><![CDATA[You have enough stocked to build <b>%max_builds%</b> builds of this project.]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="iuSpPbg" name="project.builds.check_project_status">
|
||||
<segment state="translated">
|
||||
<source>project.builds.check_project_status</source>
|
||||
<target>The current project status is <b>"%project_status%"</b>. You should check if you really want to build the project with this status!</target>
|
||||
<target><![CDATA[The current project status is <b>"%project_status%"</b>. You should check if you really want to build the project with this status!]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="Y7vSSxi" name="project.builds.following_bom_entries_miss_instock_n">
|
||||
|
|
@ -10282,7 +10285,7 @@ Element 3</target>
|
|||
<unit id="GzqIwHH" name="entity.select.add_hint">
|
||||
<segment state="translated">
|
||||
<source>entity.select.add_hint</source>
|
||||
<target>Use -> to create nested structures, e.g. "Node 1->Node 1.1"</target>
|
||||
<target><![CDATA[Use -> to create nested structures, e.g. "Node 1->Node 1.1"]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="S4CxO.T" name="entity.select.group.new_not_added_to_DB">
|
||||
|
|
@ -10306,13 +10309,13 @@ Element 3</target>
|
|||
<unit id="XLnXtsR" name="homepage.first_steps.introduction">
|
||||
<segment state="translated">
|
||||
<source>homepage.first_steps.introduction</source>
|
||||
<target>Your database is still empty. You might want to read the <a href="%url%">documentation</a> or start to creating the following data structures:</target>
|
||||
<target><![CDATA[Your database is still empty. You might want to read the <a href="%url%">documentation</a> or start to creating the following data structures:]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="Q79MOIk" name="homepage.first_steps.create_part">
|
||||
<segment state="translated">
|
||||
<source>homepage.first_steps.create_part</source>
|
||||
<target>Or you can directly <a href="%url%">create a new part</a>.</target>
|
||||
<target><![CDATA[Or you can directly <a href="%url%">create a new part</a>.]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="vplYq4f" name="homepage.first_steps.hide_hint">
|
||||
|
|
@ -10324,7 +10327,7 @@ Element 3</target>
|
|||
<unit id="MJoZl4f" name="homepage.forum.text">
|
||||
<segment state="translated">
|
||||
<source>homepage.forum.text</source>
|
||||
<target>For questions about Part-DB use the <a href="%href%" class="link-external" target="_blank">discussion forum</a></target>
|
||||
<target><![CDATA[For questions about Part-DB use the <a href="%href%" class="link-external" target="_blank">discussion forum</a>]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="YsukbnK" name="log.element_edited.changed_fields.category">
|
||||
|
|
@ -10978,7 +10981,7 @@ Element 3</target>
|
|||
<unit id="p_IxB9K" name="parts.import.help_documentation">
|
||||
<segment state="translated">
|
||||
<source>parts.import.help_documentation</source>
|
||||
<target>See the <a href="%link%">documentation</a> for more information on the file format.</target>
|
||||
<target><![CDATA[See the <a href="%link%">documentation</a> for more information on the file format.]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="awbvhVq" name="parts.import.help">
|
||||
|
|
@ -11158,7 +11161,7 @@ Element 3</target>
|
|||
<unit id="o5u.Nnz" name="part.filter.lessThanDesired">
|
||||
<segment state="translated">
|
||||
<source>part.filter.lessThanDesired</source>
|
||||
<target>In stock less than desired (total amount < min. amount)</target>
|
||||
<target><![CDATA[In stock less than desired (total amount < min. amount)]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="YN9eLcZ" name="part.filter.lotOwner">
|
||||
|
|
@ -11970,13 +11973,13 @@ Please note, that you can not impersonate a disabled user. If you try you will g
|
|||
<unit id="i68lU5x" name="part.merge.confirm.title">
|
||||
<segment state="translated">
|
||||
<source>part.merge.confirm.title</source>
|
||||
<target>Do you really want to merge <b>%other%</b> into <b>%target%</b>?</target>
|
||||
<target><![CDATA[Do you really want to merge <b>%other%</b> into <b>%target%</b>?]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="k0anzYV" name="part.merge.confirm.message">
|
||||
<segment state="translated">
|
||||
<source>part.merge.confirm.message</source>
|
||||
<target><b>%other%</b> will be deleted, and the part will be saved with the shown information.</target>
|
||||
<target><![CDATA[<b>%other%</b> will be deleted, and the part will be saved with the shown information.]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="mmW5Yl1" name="part.info.merge_modal.title">
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue