mirror of
https://github.com/Part-DB/Part-DB-server.git
synced 2026-01-11 20:59:36 +00:00
Füge Option für lesbares CSV beim Export hinzu (APS-3)
This commit is contained in:
parent
b823d7d613
commit
c79fc47c1e
17 changed files with 434 additions and 16 deletions
52
assets/controllers/elements/toggle_visibility_controller.js
Normal file
52
assets/controllers/elements/toggle_visibility_controller.js
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
import { Controller } from "@hotwired/stimulus";
|
||||
|
||||
export default class extends Controller {
|
||||
|
||||
static values = {
|
||||
classes: Array
|
||||
};
|
||||
|
||||
connect() {
|
||||
this.readableCheckbox = this.element.querySelector("#readable");
|
||||
|
||||
if (!this.readableCheckbox) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Apply the initial visibility state based on the checkbox being checked or not
|
||||
this.toggleContainers(this.readableCheckbox.checked);
|
||||
|
||||
// Add a change event listener to the 'readable' checkbox
|
||||
this.readableCheckbox.addEventListener("change", (event) => {
|
||||
// Toggle container visibility when the checkbox value changes
|
||||
this.toggleContainers(event.target.checked);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles the visibility of containers based on the checkbox state.
|
||||
* Hides specified containers if the checkbox is checked and shows them otherwise.
|
||||
*
|
||||
* @param {boolean} isChecked - The current state of the checkbox:
|
||||
* true if checked (hide elements), false if unchecked (show them).
|
||||
*/
|
||||
toggleContainers(isChecked) {
|
||||
if (!Array.isArray(this.classesValue) || this.classesValue.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.classesValue.forEach((cssClass) => {
|
||||
const elements = document.querySelectorAll(`.${cssClass}`);
|
||||
|
||||
if (!elements.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the visibility for each selected element
|
||||
elements.forEach((element) => {
|
||||
// If the checkbox is checked, hide the container; otherwise, show it
|
||||
element.style.display = isChecked ? "none" : "";
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -124,7 +124,7 @@ class AssemblyBOMEntry extends AbstractDBElement implements UniqueValidatableInt
|
|||
*/
|
||||
#[ORM\ManyToOne(targetEntity: Assembly::class, inversedBy: 'bom_entries')]
|
||||
#[ORM\JoinColumn(name: 'id_assembly', nullable: true)]
|
||||
#[Groups(['bom_entry:read', 'bom_entry:write', ])]
|
||||
#[Groups(['bom_entry:read', 'bom_entry:write'])]
|
||||
protected ?Assembly $assembly = null;
|
||||
|
||||
/**
|
||||
|
|
@ -146,7 +146,7 @@ class AssemblyBOMEntry extends AbstractDBElement implements UniqueValidatableInt
|
|||
#[AssemblyInvalidBomEntry]
|
||||
#[ORM\ManyToOne(targetEntity: Assembly::class)]
|
||||
#[ORM\JoinColumn(name: 'id_referenced_assembly', nullable: true, onDelete: 'SET NULL')]
|
||||
#[Groups(['bom_entry:read', 'bom_entry:write', ])]
|
||||
#[Groups(['bom_entry:read', 'bom_entry:write'])]
|
||||
protected ?Assembly $referencedAssembly = null;
|
||||
|
||||
/**
|
||||
|
|
@ -158,7 +158,7 @@ class AssemblyBOMEntry extends AbstractDBElement implements UniqueValidatableInt
|
|||
)]
|
||||
#[ORM\ManyToOne(targetEntity: Project::class)]
|
||||
#[ORM\JoinColumn(name: 'id_project', nullable: true)]
|
||||
#[Groups(['bom_entry:read', 'bom_entry:write', ])]
|
||||
#[Groups(['bom_entry:read', 'bom_entry:write'])]
|
||||
protected ?Project $project = null;
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -22,8 +22,19 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Services\ImportExportSystem;
|
||||
|
||||
use App\Entity\AssemblySystem\Assembly;
|
||||
use App\Entity\Attachments\AttachmentType;
|
||||
use App\Entity\Base\AbstractNamedDBElement;
|
||||
use App\Entity\Base\AbstractStructuralDBElement;
|
||||
use App\Entity\LabelSystem\LabelProfile;
|
||||
use App\Entity\Parts\Category;
|
||||
use App\Entity\Parts\Footprint;
|
||||
use App\Entity\Parts\Manufacturer;
|
||||
use App\Entity\Parts\MeasurementUnit;
|
||||
use App\Entity\Parts\StorageLocation;
|
||||
use App\Entity\Parts\Supplier;
|
||||
use App\Entity\PriceInformations\Currency;
|
||||
use App\Entity\ProjectSystem\Project;
|
||||
use App\Helpers\FilenameSanatizer;
|
||||
use App\Serializer\APIPlatform\SkippableItemNormalizer;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
|
@ -65,6 +76,9 @@ class EntityExporter
|
|||
|
||||
$resolver->setDefault('include_children', false);
|
||||
$resolver->setAllowedTypes('include_children', 'bool');
|
||||
|
||||
$resolver->setDefault('readable', false);
|
||||
$resolver->setAllowedTypes('readable', 'bool');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -222,15 +236,50 @@ class EntityExporter
|
|||
$entities = [$entities];
|
||||
}
|
||||
|
||||
//Do the serialization with the given options
|
||||
$serialized_data = $this->exportEntities($entities, $options);
|
||||
if ($request->get('readable', false)) {
|
||||
// Map entity classes to export functions
|
||||
$entityExportMap = [
|
||||
AttachmentType::class => fn($entities) => $this->exportReadable($entities, AttachmentType::class),
|
||||
Category::class => fn($entities) => $this->exportReadable($entities, Category::class),
|
||||
Project::class => fn($entities) => $this->exportReadable($entities, Project::class),
|
||||
Assembly::class => fn($entities) => $this->exportReadable($entities, Assembly::class),
|
||||
Supplier::class => fn($entities) => $this->exportReadable($entities, Supplier::class),
|
||||
Manufacturer::class => fn($entities) => $this->exportReadable($entities, Manufacturer::class),
|
||||
StorageLocation::class => fn($entities) => $this->exportReadable($entities, StorageLocation::class),
|
||||
Footprint::class => fn($entities) => $this->exportReadable($entities, Footprint::class),
|
||||
Currency::class => fn($entities) => $this->exportReadable($entities, Currency::class),
|
||||
MeasurementUnit::class => fn($entities) => $this->exportReadable($entities, MeasurementUnit::class),
|
||||
LabelProfile::class => fn($entities) => $this->exportReadable($entities, LabelProfile::class, false),
|
||||
];
|
||||
|
||||
$response = new Response($serialized_data);
|
||||
// Determine the type of the entity
|
||||
$type = null;
|
||||
foreach ($entities as $entity) {
|
||||
$entityClass = get_class($entity);
|
||||
if (isset($entityExportMap[$entityClass])) {
|
||||
$type = $entityClass;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//Resolve the format
|
||||
$optionsResolver = new OptionsResolver();
|
||||
$this->configureOptions($optionsResolver);
|
||||
$options = $optionsResolver->resolve($options);
|
||||
// Generate the response
|
||||
$response = isset($entityExportMap[$type])
|
||||
? new Response($entityExportMap[$type]($entities))
|
||||
: new Response('');
|
||||
|
||||
$options['format'] = 'csv';
|
||||
$options['level'] = 'readable';
|
||||
} else {
|
||||
//Do the serialization with the given options
|
||||
$serialized_data = $this->exportEntities($entities, $options);
|
||||
|
||||
$response = new Response($serialized_data);
|
||||
|
||||
//Resolve the format
|
||||
$optionsResolver = new OptionsResolver();
|
||||
$this->configureOptions($optionsResolver);
|
||||
$options = $optionsResolver->resolve($options);
|
||||
}
|
||||
|
||||
//Determine the content type for the response
|
||||
|
||||
|
|
@ -277,4 +326,232 @@ class EntityExporter
|
|||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exports data for multiple entity types in a readable CSV format.
|
||||
*
|
||||
* @param array $entities The entities to export.
|
||||
* @param string $type The type of entities ('category', 'project', 'assembly', 'attachmentType', 'supplier').
|
||||
* @return string The generated CSV content as a string.
|
||||
*/
|
||||
public function exportReadable(array $entities, string $type, bool $isHierarchical = true): string
|
||||
{
|
||||
//Define headers and entity-specific processing logic
|
||||
$defaultProcessEntity = fn($entity, $depth) => [
|
||||
'Id' => $entity->getId(),
|
||||
'ParentId' => $entity->getParent()?->getId() ?? '',
|
||||
'NameHierarchical' => str_repeat('--', $depth) . ' ' . $entity->getName(),
|
||||
'Name' => $entity->getName(),
|
||||
'FullName' => $this->getFullName($entity),
|
||||
];
|
||||
|
||||
$config = [
|
||||
AttachmentType::class => [
|
||||
'header' => ['Id', 'ParentId', 'NameHierarchical', 'Name', 'FullName'],
|
||||
'processEntity' => $defaultProcessEntity,
|
||||
],
|
||||
Category::class => [
|
||||
'header' => ['Id', 'ParentId', 'NameHierarchical', 'Name', 'FullName'],
|
||||
'processEntity' => $defaultProcessEntity,
|
||||
],
|
||||
Project::class => [
|
||||
'header' => [
|
||||
'Id', 'ParentId', 'Type', 'ProjectNameHierarchical', 'ProjectName', 'ProjectFullName',
|
||||
'BomQuantity', 'BomPartId', 'BomPartIpn', 'BomPartName', 'BomName', 'BomPartDescription', 'BomMountNames'
|
||||
],
|
||||
'processEntity' => fn($entity, $depth) => [
|
||||
'ProjectId' => $entity->getId(),
|
||||
'ParentProjectId' => $entity->getParent()?->getId() ?? '',
|
||||
'Type' => 'project',
|
||||
'ProjectNameHierarchical' => str_repeat('--', $depth) . ' ' . $entity->getName(),
|
||||
'ProjectName' => $entity->getName(),
|
||||
'ProjectFullName' => $this->getFullName($entity),
|
||||
'BomQuantity' => '-',
|
||||
'BomPartId' => '-',
|
||||
'BomPartIpn' => '-',
|
||||
'BomPartName' => '-',
|
||||
'BomName' => '-',
|
||||
'BomPartDescription' => '-',
|
||||
'BomMountNames' => '-',
|
||||
],
|
||||
'processBomEntries' => fn($entity, $depth) => array_map(fn($bomEntry) => [
|
||||
'Id' => $entity->getId(),
|
||||
'ParentId' => '',
|
||||
'Type' => 'project_bom_entry',
|
||||
'ProjectNameHierarchical' => str_repeat('--', $depth) . '> ' . $entity->getName(),
|
||||
'ProjectName' => $entity->getName(),
|
||||
'ProjectFullName' => $this->getFullName($entity),
|
||||
'BomQuantity' => $bomEntry->getQuantity() ?? '',
|
||||
'BomPartId' => $bomEntry->getPart()?->getId() ?? '',
|
||||
'BomPartIpn' => $bomEntry->getPart()?->getIpn() ?? '',
|
||||
'BomPartName' => $bomEntry->getPart()?->getName() ?? '',
|
||||
'BomName' => $bomEntry->getName() ?? '',
|
||||
'BomPartDescription' => $bomEntry->getPart()?->getDescription() ?? '',
|
||||
'BomMountNames' => $bomEntry->getMountNames(),
|
||||
], $entity->getBomEntries()->toArray()),
|
||||
],
|
||||
Assembly::class => [
|
||||
'header' => [
|
||||
'Id', 'ParentId', 'Type', 'AssemblyIpn', 'AssemblyNameHierarchical', 'AssemblyName',
|
||||
'AssemblyFullName', 'BomQuantity', 'BomPartId', 'BomPartIpn', 'BomPartName', 'BomName', 'BomPartDescription',
|
||||
'BomMountNames', 'BomReferencedAssemblyId', 'BomReferencedAssemblyIpn', 'BomReferencedAssemblyFullName'
|
||||
],
|
||||
'processEntity' => fn($entity, $depth) => [
|
||||
'Id' => $entity->getId(),
|
||||
'ParentId' => $entity->getParent()?->getId() ?? '',
|
||||
'Type' => 'assembly',
|
||||
'AssemblyIpn' => $entity->getIpn(),
|
||||
'AssemblyNameHierarchical' => str_repeat('--', $depth) . ' ' . $entity->getName(),
|
||||
'AssemblyName' => $entity->getName(),
|
||||
'AssemblyFullName' => $this->getFullName($entity),
|
||||
'BomQuantity' => '-',
|
||||
'BomPartId' => '-',
|
||||
'BomPartIpn' => '-',
|
||||
'BomPartName' => '-',
|
||||
'BomName' => '-',
|
||||
'BomPartDescription' => '-',
|
||||
'BomMountNames' => '-',
|
||||
'BomReferencedAssemblyId' => '-',
|
||||
'BomReferencedAssemblyIpn' => '-',
|
||||
'BomReferencedAssemblyFullName' => '-',
|
||||
],
|
||||
'processBomEntries' => fn($entity, $depth) => array_map(fn($bomEntry) => [
|
||||
'Id' => $entity->getId(),
|
||||
'ParentId' => '',
|
||||
'Type' => 'assembly_bom_entry',
|
||||
'AssemblyIpn' => $entity->getIpn(),
|
||||
'AssemblyNameHierarchical' => str_repeat('--', $depth) . '> ' . $entity->getName(),
|
||||
'AssemblyName' => $entity->getName(),
|
||||
'AssemblyFullName' => $this->getFullName($entity),
|
||||
'BomQuantity' => $bomEntry->getQuantity() ?? '',
|
||||
'BomPartId' => $bomEntry->getPart()?->getId() ?? '',
|
||||
'BomPartIpn' => $bomEntry->getPart()?->getIpn() ?? '',
|
||||
'BomPartName' => $bomEntry->getPart()?->getName() ?? '',
|
||||
'BomName' => $bomEntry->getName() ?? '',
|
||||
'BomPartDescription' => $bomEntry->getPart()?->getDescription() ?? '',
|
||||
'BomMountNames' => $bomEntry->getMountNames(),
|
||||
'BomReferencedAssemblyId' => $bomEntry->getReferencedAssembly()?->getId() ?? '',
|
||||
'BomReferencedAssemblyIpn' => $bomEntry->getReferencedAssembly()?->getIpn() ?? '',
|
||||
'BomReferencedAssemblyFullName' => $this->getFullName($bomEntry->getReferencedAssembly() ?? null),
|
||||
], $entity->getBomEntries()->toArray()),
|
||||
],
|
||||
Supplier::class => [
|
||||
'header' => ['Id', 'ParentId', 'NameHierarchical', 'Name', 'FullName'],
|
||||
'processEntity' => $defaultProcessEntity,
|
||||
],
|
||||
Manufacturer::class => [
|
||||
'header' => ['Id', 'ParentId', 'NameHierarchical', 'Name', 'FullName'],
|
||||
'processEntity' => $defaultProcessEntity,
|
||||
],
|
||||
StorageLocation::class => [
|
||||
'header' => ['Id', 'ParentId', 'NameHierarchical', 'Name', 'FullName'],
|
||||
'processEntity' => $defaultProcessEntity,
|
||||
],
|
||||
Footprint::class => [
|
||||
'header' => ['Id', 'ParentId', 'NameHierarchical', 'Name', 'FullName'],
|
||||
'processEntity' => $defaultProcessEntity,
|
||||
],
|
||||
Currency::class => [
|
||||
'header' => ['Id', 'ParentId', 'NameHierarchical', 'Name', 'FullName'],
|
||||
'processEntity' => $defaultProcessEntity,
|
||||
],
|
||||
MeasurementUnit::class => [
|
||||
'header' => ['Id', 'ParentId', 'NameHierarchical', 'Name', 'FullName'],
|
||||
'processEntity' => $defaultProcessEntity,
|
||||
],
|
||||
LabelProfile::class => [
|
||||
'header' => ['Id', 'SupportedElement', 'Name'],
|
||||
'processEntity' => fn(LabelProfile $entity, $depth) => [
|
||||
'Id' => $entity->getId(),
|
||||
'SupportedElement' => $entity->getOptions()->getSupportedElement()->name,
|
||||
'Name' => $entity->getName(),
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
//Get configuration for the entity type
|
||||
$entityConfig = $config[$type] ?? null;
|
||||
|
||||
if (!$entityConfig) {
|
||||
return '';
|
||||
}
|
||||
|
||||
//Initialize CSV data with the header
|
||||
$csvData = [];
|
||||
$csvData[] = $entityConfig['header'];
|
||||
|
||||
$relevantEntities = $entities;
|
||||
|
||||
if ($isHierarchical) {
|
||||
//Filter root entities (those without parents)
|
||||
$relevantEntities = array_filter($entities, fn($entity) => $entity->getParent() === null);
|
||||
|
||||
if (count($relevantEntities) === 0 && count($entities) > 0) {
|
||||
//If no root entities are found, then we need to add all entities
|
||||
|
||||
$relevantEntities = $entities;
|
||||
}
|
||||
}
|
||||
|
||||
//Sort root entities alphabetically by `name`
|
||||
usort($relevantEntities, fn($a, $b) => strnatcasecmp($a->getName(), $b->getName()));
|
||||
|
||||
//Recursive function to process an entity and its children
|
||||
$processEntity = function ($entity, &$csvData, $depth = 0) use (&$processEntity, $entityConfig, $isHierarchical) {
|
||||
//Add main entity data to CSV
|
||||
$csvData[] = $entityConfig['processEntity']($entity, $depth);
|
||||
|
||||
//Process BOM entries if applicable
|
||||
if (isset($entityConfig['processBomEntries'])) {
|
||||
$bomRows = $entityConfig['processBomEntries']($entity, $depth);
|
||||
foreach ($bomRows as $bomRow) {
|
||||
$csvData[] = $bomRow;
|
||||
}
|
||||
}
|
||||
|
||||
if ($isHierarchical) {
|
||||
//Retrieve children, sort alphabetically, then process them
|
||||
$children = $entity->getChildren()->toArray();
|
||||
usort($children, fn($a, $b) => strnatcasecmp($a->getName(), $b->getName()));
|
||||
foreach ($children as $childEntity) {
|
||||
$processEntity($childEntity, $csvData, $depth + 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//Start processing with root entities
|
||||
foreach ($relevantEntities as $rootEntity) {
|
||||
$processEntity($rootEntity, $csvData);
|
||||
}
|
||||
|
||||
//Generate CSV string
|
||||
$output = '';
|
||||
foreach ($csvData as $line) {
|
||||
$output .= implode(';', $line) . "\n"; // Use a semicolon as the delimiter
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs the full hierarchical name of an object by traversing
|
||||
* through its parent objects and concatenating their names using
|
||||
* a specified separator.
|
||||
*
|
||||
* @param AttachmentType|Category|Project|Assembly|Supplier|Manufacturer|StorageLocation|Footprint|Currency|MeasurementUnit|LabelProfile|null $object The object whose full name is to be constructed. If null, the result will be an empty string.
|
||||
* @param string $separator The string used to separate the names of the objects in the full hierarchy.
|
||||
*
|
||||
* @return string The full hierarchical name constructed by concatenating the names of the object and its parents.
|
||||
*/
|
||||
private function getFullName(AttachmentType|Category|Project|Assembly|Supplier|Manufacturer|StorageLocation|Footprint|Currency|MeasurementUnit|LabelProfile|null $object, string $separator = '->'): string
|
||||
{
|
||||
$fullNameParts = [];
|
||||
|
||||
while ($object !== null) {
|
||||
array_unshift($fullNameParts, $object->getName());
|
||||
$object = $object->getParent();
|
||||
}
|
||||
|
||||
return implode($separator, $fullNameParts);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<form class="form-horizontal" method="post" action="{{ path }}" data-turbo="false" data-turbo-frame="_top">
|
||||
<form class="form-horizontal" method="post" action="{{ path }}" data-turbo="false" data-turbo-frame="_top" {{ stimulus_controller('elements/toggle_visibility', {classes: ['format', 'level', 'include_children']}) }}>
|
||||
|
||||
<div class="row">
|
||||
<div class="row format">
|
||||
<label class="col-form-label col-md-3">{% trans %}export.format{% endtrans %}</label>
|
||||
<div class="col-md-9">
|
||||
<select class="form-select" name="format">
|
||||
|
|
@ -12,7 +12,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mt-2">
|
||||
<div class="row mt-2 level">
|
||||
<label class="col-form-label col-md-3">{% trans %}export.level{% endtrans %}</label>
|
||||
<div class="col-md-9">
|
||||
<select class="form-select" name="level">
|
||||
|
|
@ -23,7 +23,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mt-2">
|
||||
<div class="row mt-2 include_children">
|
||||
<div class="offset-md-3 col-sm">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input form-check-input" name="include_children" id="include_children" type="checkbox" checked>
|
||||
|
|
@ -34,6 +34,17 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mt-2">
|
||||
<div class="offset-md-3 col-sm">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input form-check-input" name="readable" id="readable" type="checkbox" data-action="change->toggle-visibility#toggle">
|
||||
<label class="form-check-label form-check-label" for="readable">
|
||||
{% trans %}export.readable{% endtrans %}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mt-2">
|
||||
<div class="offset-sm-3 col-sm">
|
||||
<button type="submit" class="btn btn-primary">{% trans %}export.btn{% endtrans %}</button>
|
||||
|
|
|
|||
|
|
@ -351,6 +351,12 @@
|
|||
<target>Exportovat všechny prvky</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a5h8ltP" name="export.readable">
|
||||
<segment state="translated">
|
||||
<source>export.readable</source>
|
||||
<target>Čitelné CSV</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="M.rXmnA" name="mass_creation.help">
|
||||
<notes>
|
||||
<note category="file-source" priority="1">Part-DB1\templates\AdminPages\EntityAdminBase.html.twig:185</note>
|
||||
|
|
|
|||
|
|
@ -351,6 +351,12 @@
|
|||
<target>Eksportér alle elementer</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a5h8ltP" name="export.readable">
|
||||
<segment state="translated">
|
||||
<source>export.readable</source>
|
||||
<target>Læsbar CSV</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="zPSdxU4" name="mass_creation.help">
|
||||
<notes>
|
||||
<note category="file-source" priority="1">Part-DB1\templates\AdminPages\EntityAdminBase.html.twig:185</note>
|
||||
|
|
|
|||
|
|
@ -1010,6 +1010,12 @@ Subelemente werden beim Löschen nach oben verschoben.</target>
|
|||
<target>Unterelemente auch exportieren</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a5h8ltP" name="export.readable">
|
||||
<segment state="translated">
|
||||
<source>export.readable</source>
|
||||
<target>Lesbares CSV</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="Pdmfku8" name="export.btn">
|
||||
<notes>
|
||||
<note category="file-source" priority="1">Part-DB1\templates\AdminPages\_export_form.html.twig:39</note>
|
||||
|
|
|
|||
|
|
@ -228,6 +228,12 @@
|
|||
<target>Εξαγωγή όλων των στοιχείων</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a5h8ltP" name="export.readable">
|
||||
<segment state="translated">
|
||||
<source>export.readable</source>
|
||||
<target>Αναγνώσιμο CSV</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="zPSdxU4" name="mass_creation.help">
|
||||
<notes>
|
||||
<note category="file-source" priority="1">Part-DB1\templates\AdminPages\EntityAdminBase.html.twig:185</note>
|
||||
|
|
|
|||
|
|
@ -351,6 +351,12 @@
|
|||
<target>Export all elements</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a5h8ltP" name="export.readable">
|
||||
<segment state="translated">
|
||||
<source>export.readable</source>
|
||||
<target>Readable CSV</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="M.rXmnA" name="mass_creation.help">
|
||||
<notes>
|
||||
<note category="file-source" priority="1">Part-DB1\templates\AdminPages\EntityAdminBase.html.twig:185</note>
|
||||
|
|
|
|||
|
|
@ -351,6 +351,12 @@
|
|||
<target>Exportar todos los elementos</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a5h8ltP" name="export.readable">
|
||||
<segment state="translated">
|
||||
<source>export.readable</source>
|
||||
<target>CSV legible</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="M.rXmnA" name="mass_creation.help">
|
||||
<notes>
|
||||
<note category="file-source" priority="1">Part-DB1\templates\AdminPages\EntityAdminBase.html.twig:185</note>
|
||||
|
|
|
|||
|
|
@ -320,6 +320,12 @@
|
|||
<target>Exporter tous les éléments</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a5h8ltP" name="export.readable">
|
||||
<segment state="translated">
|
||||
<source>export.readable</source>
|
||||
<target>CSV lisible</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="zPSdxU4" name="mass_creation.help">
|
||||
<notes>
|
||||
<note category="file-source" priority="1">Part-DB1\templates\AdminPages\EntityAdminBase.html.twig:185</note>
|
||||
|
|
@ -9822,13 +9828,13 @@ exemple de ville</target>
|
|||
</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="bH5Qi1Z" name="assembly.bom_import.template.csv.exptected_columns">
|
||||
<unit id="aK4i2aT" name="assembly.bom_import.template.csv.exptected_columns">
|
||||
<segment>
|
||||
<source>assembly.bom_import.template.csv.exptected_columns</source>
|
||||
<target>Colonnes possibles :</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="NIcfgj84" name="assembly.bom_import.template.csv.table">
|
||||
<unit id="a8UhiwR" name="assembly.bom_import.template.csv.table">
|
||||
<segment>
|
||||
<source>assembly.bom_import.template.csv.table</source>
|
||||
<target>
|
||||
|
|
|
|||
|
|
@ -351,6 +351,12 @@
|
|||
<target>Esportare tutti gli elementi</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a5h8ltP" name="export.readable">
|
||||
<segment state="translated">
|
||||
<source>export.readable</source>
|
||||
<target>CSV leggibile</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="M.rXmnA" name="mass_creation.help">
|
||||
<notes>
|
||||
<note category="file-source" priority="1">Part-DB1\templates\AdminPages\EntityAdminBase.html.twig:185</note>
|
||||
|
|
|
|||
|
|
@ -320,6 +320,12 @@
|
|||
<target>すべてエクスポートする</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a5h8ltP" name="export.readable">
|
||||
<segment state="translated">
|
||||
<source>export.readable</source>
|
||||
<target>読みやすいCSV</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="zPSdxU4" name="mass_creation.help">
|
||||
<notes>
|
||||
<note category="file-source" priority="1">Part-DB1\templates\AdminPages\EntityAdminBase.html.twig:185</note>
|
||||
|
|
|
|||
|
|
@ -351,6 +351,12 @@
|
|||
<target>Exporteer alle elementen</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a5h8ltP" name="export.readable">
|
||||
<segment state="translated">
|
||||
<source>export.readable</source>
|
||||
<target>Leesbare CSV</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="zPSdxU4" name="mass_creation.help">
|
||||
<notes>
|
||||
<note category="file-source" priority="1">Part-DB1\templates\AdminPages\EntityAdminBase.html.twig:185</note>
|
||||
|
|
|
|||
|
|
@ -351,6 +351,12 @@
|
|||
<target>Eksportuj wszystkie elementy</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a5h8ltP" name="export.readable">
|
||||
<segment state="translated">
|
||||
<source>export.readable</source>
|
||||
<target>Czytelny CSV</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="M.rXmnA" name="mass_creation.help">
|
||||
<notes>
|
||||
<note category="file-source" priority="1">Part-DB1\templates\AdminPages\EntityAdminBase.html.twig:185</note>
|
||||
|
|
|
|||
|
|
@ -351,6 +351,12 @@
|
|||
<target>Экспортировать всё</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a5h8ltP" name="export.readable">
|
||||
<segment state="translated">
|
||||
<source>export.readable</source>
|
||||
<target>Читаемый CSV</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="M.rXmnA" name="mass_creation.help">
|
||||
<notes>
|
||||
<note category="file-source" priority="1">Part-DB1\templates\AdminPages\EntityAdminBase.html.twig:185</note>
|
||||
|
|
|
|||
|
|
@ -351,6 +351,12 @@
|
|||
<target>导出所有元素</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="a5h8ltP" name="export.readable">
|
||||
<segment state="translated">
|
||||
<source>export.readable</source>
|
||||
<target>可读的 CSV</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="zPSdxU4" name="mass_creation.help">
|
||||
<notes>
|
||||
<note category="file-source" priority="1">Part-DB1\templates\AdminPages\EntityAdminBase.html.twig:185</note>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue