2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-06-20 22:06:28 +00:00

added more translation-strings

This commit is contained in:
2021-04-04 22:44:14 +02:00
parent c68220a597
commit 20c455384e
39 changed files with 2886 additions and 1653 deletions

View File

@ -275,7 +275,7 @@ class BomUploadManager:
elif ext in ['.xls', '.xlsx']:
raw_data = bom_file.read()
else:
raise ValidationError({'bom_file': _('Unsupported file format: {f}'.format(f=ext))})
raise ValidationError({'bom_file': _('Unsupported file format: {f}').format(f=ext)})
try:
self.data = tablib.Dataset().load(raw_data)

View File

@ -129,6 +129,7 @@ class BomDuplicateForm(HelperForm):
confirm = forms.BooleanField(
required=False, initial=False,
label=_('Confirm'),
help_text=_('Confirm BOM duplication')
)
@ -147,7 +148,7 @@ class BomValidateForm(HelperForm):
to confirm that the BOM for this part is valid
"""
validate = forms.BooleanField(required=False, initial=False, help_text=_('Confirm that the BOM is correct'))
validate = forms.BooleanField(required=False, initial=False, label=_('validate'), help_text=_('Confirm that the BOM is correct'))
class Meta:
model = Part
@ -159,7 +160,7 @@ class BomValidateForm(HelperForm):
class BomUploadSelectFile(HelperForm):
""" Form for importing a BOM. Provides a file input box for upload """
bom_file = forms.FileField(label='BOM file', required=True, help_text=_("Select BOM file to upload"))
bom_file = forms.FileField(label=_('BOM file'), required=True, help_text=_("Select BOM file to upload"))
class Meta:
model = Part
@ -336,9 +337,9 @@ class EditCategoryParameterTemplateForm(HelperForm):
class EditBomItemForm(HelperForm):
""" Form for editing a BomItem object """
quantity = RoundingDecimalFormField(max_digits=10, decimal_places=5)
quantity = RoundingDecimalFormField(max_digits=10, decimal_places=5, label=_('Quantity'))
sub_part = PartModelChoiceField(queryset=Part.objects.all())
sub_part = PartModelChoiceField(queryset=Part.objects.all(), label=_('Sub part'))
class Meta:
model = BomItem
@ -365,6 +366,7 @@ class PartPriceForm(forms.Form):
quantity = forms.IntegerField(
required=True,
initial=1,
label=_('Quantity'),
help_text=_('Input quantity for price calculation')
)
@ -380,7 +382,7 @@ class EditPartSalePriceBreakForm(HelperForm):
Form for creating / editing a sale price for a part
"""
quantity = RoundingDecimalFormField(max_digits=10, decimal_places=5)
quantity = RoundingDecimalFormField(max_digits=10, decimal_places=5, label=_('Quantity'))
class Meta:
model = PartSellPriceBreak

View File

@ -1,110 +0,0 @@
# Generated by Django 3.0.7 on 2021-04-03 12:10
import InvenTree.models
import InvenTree.validators
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import mptt.fields
class Migration(migrations.Migration):
dependencies = [
('stock', '0059_auto_20210403_1210'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('part', '0063_bomitem_inherited'),
]
operations = [
migrations.AlterField(
model_name='part',
name='bom_checked_by',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='boms_checked', to=settings.AUTH_USER_MODEL, verbose_name='BOM checked by'),
),
migrations.AlterField(
model_name='part',
name='bom_checked_date',
field=models.DateField(blank=True, null=True, verbose_name='BOM checked date'),
),
migrations.AlterField(
model_name='part',
name='bom_checksum',
field=models.CharField(blank=True, help_text='Stored BOM checksum', max_length=128, verbose_name='BOM checksum'),
),
migrations.AlterField(
model_name='part',
name='creation_date',
field=models.DateField(auto_now_add=True, null=True, verbose_name='Creation Date'),
),
migrations.AlterField(
model_name='part',
name='creation_user',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='parts_created', to=settings.AUTH_USER_MODEL, verbose_name='Creation User'),
),
migrations.AlterField(
model_name='part',
name='responsible',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='parts_responible', to=settings.AUTH_USER_MODEL, verbose_name='Responsible'),
),
migrations.AlterField(
model_name='partattachment',
name='attachment',
field=models.FileField(help_text='Select file to attach', upload_to=InvenTree.models.rename_attachment, verbose_name='Attachment'),
),
migrations.AlterField(
model_name='partattachment',
name='comment',
field=models.CharField(blank=True, help_text='File comment', max_length=100, verbose_name='Comment'),
),
migrations.AlterField(
model_name='partattachment',
name='upload_date',
field=models.DateField(auto_now_add=True, null=True, verbose_name='upload date'),
),
migrations.AlterField(
model_name='partattachment',
name='user',
field=models.ForeignKey(blank=True, help_text='User', null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='User'),
),
migrations.AlterField(
model_name='partcategory',
name='default_keywords',
field=models.CharField(blank=True, help_text='Default keywords for parts in this category', max_length=250, null=True, verbose_name='Default keywords'),
),
migrations.AlterField(
model_name='partcategory',
name='default_location',
field=mptt.fields.TreeForeignKey(blank=True, help_text='Default location for parts in this category', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='default_categories', to='stock.StockLocation', verbose_name='Default Location'),
),
migrations.AlterField(
model_name='partcategory',
name='description',
field=models.CharField(blank=True, help_text='Description (optional)', max_length=250, verbose_name='Description'),
),
migrations.AlterField(
model_name='partcategory',
name='name',
field=models.CharField(help_text='Name', max_length=100, validators=[InvenTree.validators.validate_tree_name], verbose_name='Name'),
),
migrations.AlterField(
model_name='partcategory',
name='parent',
field=mptt.fields.TreeForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='children', to='part.PartCategory', verbose_name='parent'),
),
migrations.AlterField(
model_name='partparameter',
name='data',
field=models.CharField(help_text='Parameter Value', max_length=500, verbose_name='Data'),
),
migrations.AlterField(
model_name='partparameter',
name='part',
field=models.ForeignKey(help_text='Parent Part', on_delete=django.db.models.deletion.CASCADE, related_name='parameters', to='part.Part', verbose_name='Part'),
),
migrations.AlterField(
model_name='partparameter',
name='template',
field=models.ForeignKey(help_text='Parameter Template', on_delete=django.db.models.deletion.CASCADE, related_name='instances', to='part.PartParameterTemplate', verbose_name='Template'),
),
]

View File

@ -0,0 +1,218 @@
# Generated by Django 3.0.7 on 2021-04-04 20:16
import InvenTree.models
import InvenTree.validators
from django.conf import settings
import django.core.validators
from django.db import migrations, models
import django.db.models.deletion
import mptt.fields
import part.models
import stdimage.models
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('stock', '0058_stockitem_packaging'),
('part', '0063_bomitem_inherited'),
]
operations = [
migrations.AlterField(
model_name='bomitem',
name='checksum',
field=models.CharField(blank=True, help_text='BOM line checksum', max_length=128, verbose_name='Checksum'),
),
migrations.AlterField(
model_name='bomitem',
name='note',
field=models.CharField(blank=True, help_text='BOM item notes', max_length=500, verbose_name='Note'),
),
migrations.AlterField(
model_name='bomitem',
name='optional',
field=models.BooleanField(default=False, help_text='This BOM item is optional', verbose_name='Optional'),
),
migrations.AlterField(
model_name='bomitem',
name='overage',
field=models.CharField(blank=True, help_text='Estimated build wastage quantity (absolute or percentage)', max_length=24, validators=[InvenTree.validators.validate_overage], verbose_name='Overage'),
),
migrations.AlterField(
model_name='bomitem',
name='part',
field=models.ForeignKey(help_text='Select parent part', limit_choices_to={'assembly': True}, on_delete=django.db.models.deletion.CASCADE, related_name='bom_items', to='part.Part', verbose_name='Part'),
),
migrations.AlterField(
model_name='bomitem',
name='quantity',
field=models.DecimalField(decimal_places=5, default=1.0, help_text='BOM quantity for this BOM item', max_digits=15, validators=[django.core.validators.MinValueValidator(0)], verbose_name='Quantity'),
),
migrations.AlterField(
model_name='bomitem',
name='reference',
field=models.CharField(blank=True, help_text='BOM item reference', max_length=500, verbose_name='Reference'),
),
migrations.AlterField(
model_name='bomitem',
name='sub_part',
field=models.ForeignKey(help_text='Select part to be used in BOM', limit_choices_to={'component': True}, on_delete=django.db.models.deletion.CASCADE, related_name='used_in', to='part.Part', verbose_name='Sub part'),
),
migrations.AlterField(
model_name='part',
name='bom_checked_by',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='boms_checked', to=settings.AUTH_USER_MODEL, verbose_name='BOM checked by'),
),
migrations.AlterField(
model_name='part',
name='bom_checked_date',
field=models.DateField(blank=True, null=True, verbose_name='BOM checked date'),
),
migrations.AlterField(
model_name='part',
name='bom_checksum',
field=models.CharField(blank=True, help_text='Stored BOM checksum', max_length=128, verbose_name='BOM checksum'),
),
migrations.AlterField(
model_name='part',
name='creation_date',
field=models.DateField(auto_now_add=True, null=True, verbose_name='Creation Date'),
),
migrations.AlterField(
model_name='part',
name='creation_user',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='parts_created', to=settings.AUTH_USER_MODEL, verbose_name='Creation User'),
),
migrations.AlterField(
model_name='part',
name='image',
field=stdimage.models.StdImageField(blank=True, null=True, upload_to=part.models.rename_part_image, verbose_name='Image'),
),
migrations.AlterField(
model_name='part',
name='responsible',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='parts_responible', to=settings.AUTH_USER_MODEL, verbose_name='Responsible'),
),
migrations.AlterField(
model_name='partattachment',
name='attachment',
field=models.FileField(help_text='Select file to attach', upload_to=InvenTree.models.rename_attachment, verbose_name='Attachment'),
),
migrations.AlterField(
model_name='partattachment',
name='comment',
field=models.CharField(blank=True, help_text='File comment', max_length=100, verbose_name='Comment'),
),
migrations.AlterField(
model_name='partattachment',
name='part',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='attachments', to='part.Part', verbose_name='Part'),
),
migrations.AlterField(
model_name='partattachment',
name='upload_date',
field=models.DateField(auto_now_add=True, null=True, verbose_name='upload date'),
),
migrations.AlterField(
model_name='partattachment',
name='user',
field=models.ForeignKey(blank=True, help_text='User', null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='User'),
),
migrations.AlterField(
model_name='partcategory',
name='default_keywords',
field=models.CharField(blank=True, help_text='Default keywords for parts in this category', max_length=250, null=True, verbose_name='Default keywords'),
),
migrations.AlterField(
model_name='partcategory',
name='default_location',
field=mptt.fields.TreeForeignKey(blank=True, help_text='Default location for parts in this category', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='default_categories', to='stock.StockLocation', verbose_name='Default Location'),
),
migrations.AlterField(
model_name='partcategory',
name='description',
field=models.CharField(blank=True, help_text='Description (optional)', max_length=250, verbose_name='Description'),
),
migrations.AlterField(
model_name='partcategory',
name='name',
field=models.CharField(help_text='Name', max_length=100, validators=[InvenTree.validators.validate_tree_name], verbose_name='Name'),
),
migrations.AlterField(
model_name='partcategory',
name='parent',
field=mptt.fields.TreeForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='children', to='part.PartCategory', verbose_name='parent'),
),
migrations.AlterField(
model_name='partcategoryparametertemplate',
name='category',
field=models.ForeignKey(help_text='Part Category', on_delete=django.db.models.deletion.CASCADE, related_name='parameter_templates', to='part.PartCategory', verbose_name='Category'),
),
migrations.AlterField(
model_name='partcategoryparametertemplate',
name='default_value',
field=models.CharField(blank=True, help_text='Default Parameter Value', max_length=500, verbose_name='Default Value'),
),
migrations.AlterField(
model_name='partcategoryparametertemplate',
name='parameter_template',
field=models.ForeignKey(help_text='Parameter Template', on_delete=django.db.models.deletion.CASCADE, related_name='part_categories', to='part.PartParameterTemplate', verbose_name='Parameter Template'),
),
migrations.AlterField(
model_name='partparameter',
name='data',
field=models.CharField(help_text='Parameter Value', max_length=500, verbose_name='Data'),
),
migrations.AlterField(
model_name='partparameter',
name='part',
field=models.ForeignKey(help_text='Parent Part', on_delete=django.db.models.deletion.CASCADE, related_name='parameters', to='part.Part', verbose_name='Part'),
),
migrations.AlterField(
model_name='partparameter',
name='template',
field=models.ForeignKey(help_text='Parameter Template', on_delete=django.db.models.deletion.CASCADE, related_name='instances', to='part.PartParameterTemplate', verbose_name='Template'),
),
migrations.AlterField(
model_name='partparametertemplate',
name='name',
field=models.CharField(help_text='Parameter Name', max_length=100, unique=True, verbose_name='Name'),
),
migrations.AlterField(
model_name='partparametertemplate',
name='units',
field=models.CharField(blank=True, help_text='Parameter Units', max_length=25, verbose_name='Units'),
),
migrations.AlterField(
model_name='partrelated',
name='part_1',
field=models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, related_name='related_parts_1', to='part.Part', verbose_name='Part 1'),
),
migrations.AlterField(
model_name='partrelated',
name='part_2',
field=models.ForeignKey(help_text='Select Related Part', on_delete=django.db.models.deletion.DO_NOTHING, related_name='related_parts_2', to='part.Part', verbose_name='Part 2'),
),
migrations.AlterField(
model_name='partsellpricebreak',
name='part',
field=models.ForeignKey(limit_choices_to={'salable': True}, on_delete=django.db.models.deletion.CASCADE, related_name='salepricebreaks', to='part.Part', verbose_name='Part'),
),
migrations.AlterField(
model_name='partstar',
name='part',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='starred_users', to='part.Part', verbose_name='Part'),
),
migrations.AlterField(
model_name='partstar',
name='user',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='starred_parts', to=settings.AUTH_USER_MODEL, verbose_name='User'),
),
migrations.AlterField(
model_name='parttesttemplate',
name='part',
field=models.ForeignKey(limit_choices_to={'trackable': True}, on_delete=django.db.models.deletion.CASCADE, related_name='test_templates', to='part.Part', verbose_name='Part'),
),
]

View File

@ -443,10 +443,10 @@ class Part(MPTTModel):
return
if self.pk == parent.pk:
raise ValidationError({'sub_part': _("Part '{p1}' is used in BOM for '{p2}' (recursive)".format(
raise ValidationError({'sub_part': _("Part '{p1}' is used in BOM for '{p2}' (recursive)").format(
p1=str(self),
p2=str(parent)
))})
)})
bom_items = self.get_bom_items()
@ -455,10 +455,10 @@ class Part(MPTTModel):
# Check for simple match
if item.sub_part == parent:
raise ValidationError({'sub_part': _("Part '{p1}' is used in BOM for '{p2}' (recursive)".format(
raise ValidationError({'sub_part': _("Part '{p1}' is used in BOM for '{p2}' (recursive)").format(
p1=str(parent),
p2=str(self)
))})
)})
# And recursively check too
item.sub_part.checkAddToBOM(parent)
@ -750,6 +750,7 @@ class Part(MPTTModel):
blank=True,
variations={'thumbnail': (128, 128)},
delete_orphans=False,
verbose_name=_('Image'),
)
default_location = TreeForeignKey(
@ -1852,7 +1853,7 @@ class PartAttachment(InvenTreeAttachment):
return os.path.join("part_files", str(self.part.id))
part = models.ForeignKey(Part, on_delete=models.CASCADE,
related_name='attachments')
verbose_name=_('Part'), related_name='attachments')
class PartSellPriceBreak(common.models.PriceBreak):
@ -1863,7 +1864,8 @@ class PartSellPriceBreak(common.models.PriceBreak):
part = models.ForeignKey(
Part, on_delete=models.CASCADE,
related_name='salepricebreaks',
limit_choices_to={'salable': True}
limit_choices_to={'salable': True},
verbose_name=_('Part')
)
class Meta:
@ -1881,9 +1883,9 @@ class PartStar(models.Model):
user: Link to a User object
"""
part = models.ForeignKey(Part, on_delete=models.CASCADE, related_name='starred_users')
part = models.ForeignKey(Part, on_delete=models.CASCADE, verbose_name=_('Part'), related_name='starred_users')
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='starred_parts')
user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name=_('User'), related_name='starred_parts')
class Meta:
unique_together = ['part', 'user']
@ -1956,6 +1958,7 @@ class PartTestTemplate(models.Model):
on_delete=models.CASCADE,
related_name='test_templates',
limit_choices_to={'trackable': True},
verbose_name=_('Part'),
)
test_name = models.CharField(
@ -2023,9 +2026,9 @@ class PartParameterTemplate(models.Model):
except PartParameterTemplate.DoesNotExist:
pass
name = models.CharField(max_length=100, help_text=_('Parameter Name'), unique=True)
name = models.CharField(max_length=100, verbose_name=_('Name'), help_text=_('Parameter Name'), unique=True)
units = models.CharField(max_length=25, help_text=_('Parameter Units'), blank=True)
units = models.CharField(max_length=25, verbose_name=_('Units'), help_text=_('Parameter Units'), blank=True)
class PartParameter(models.Model):
@ -2096,15 +2099,18 @@ class PartCategoryParameterTemplate(models.Model):
category = models.ForeignKey(PartCategory,
on_delete=models.CASCADE,
related_name='parameter_templates',
verbose_name=_('Category'),
help_text=_('Part Category'))
parameter_template = models.ForeignKey(PartParameterTemplate,
on_delete=models.CASCADE,
related_name='part_categories',
verbose_name=_('Parameter Template'),
help_text=_('Parameter Template'))
default_value = models.CharField(max_length=500,
blank=True,
verbose_name=_('Default Value'),
help_text=_('Default Parameter Value'))
@ -2133,6 +2139,7 @@ class BomItem(models.Model):
# A link to the parent part
# Each part will get a reverse lookup field 'bom_items'
part = models.ForeignKey(Part, on_delete=models.CASCADE, related_name='bom_items',
verbose_name=_('Part'),
help_text=_('Select parent part'),
limit_choices_to={
'assembly': True,
@ -2141,26 +2148,28 @@ class BomItem(models.Model):
# A link to the child item (sub-part)
# Each part will get a reverse lookup field 'used_in'
sub_part = models.ForeignKey(Part, on_delete=models.CASCADE, related_name='used_in',
verbose_name=_('Sub part'),
help_text=_('Select part to be used in BOM'),
limit_choices_to={
'component': True,
})
# Quantity required
quantity = models.DecimalField(default=1.0, max_digits=15, decimal_places=5, validators=[MinValueValidator(0)], help_text=_('BOM quantity for this BOM item'))
quantity = models.DecimalField(default=1.0, max_digits=15, decimal_places=5, validators=[MinValueValidator(0)], verbose_name=_('Quantity'), help_text=_('BOM quantity for this BOM item'))
optional = models.BooleanField(default=False, help_text=_("This BOM item is optional"))
optional = models.BooleanField(default=False, verbose_name=_('Optional'), help_text=_("This BOM item is optional"))
overage = models.CharField(max_length=24, blank=True, validators=[validators.validate_overage],
verbose_name=_('Overage'),
help_text=_('Estimated build wastage quantity (absolute or percentage)')
)
reference = models.CharField(max_length=500, blank=True, help_text=_('BOM item reference'))
reference = models.CharField(max_length=500, blank=True, verbose_name=_('Reference'), help_text=_('BOM item reference'))
# Note attached to this BOM line item
note = models.CharField(max_length=500, blank=True, help_text=_('BOM item notes'))
note = models.CharField(max_length=500, blank=True, verbose_name=_('Note'), help_text=_('BOM item notes'))
checksum = models.CharField(max_length=128, blank=True, help_text=_('BOM line checksum'))
checksum = models.CharField(max_length=128, blank=True, verbose_name=_('Checksum'), help_text=_('BOM line checksum'))
inherited = models.BooleanField(
default=False,
@ -2372,11 +2381,11 @@ class PartRelated(models.Model):
""" Store and handle related parts (eg. mating connector, crimps, etc.) """
part_1 = models.ForeignKey(Part, related_name='related_parts_1',
on_delete=models.DO_NOTHING)
verbose_name=_('Part 1'), on_delete=models.DO_NOTHING)
part_2 = models.ForeignKey(Part, related_name='related_parts_2',
on_delete=models.DO_NOTHING,
help_text=_('Select Related Part'))
verbose_name=_('Part 2'), help_text=_('Select Related Part'))
def __str__(self):
return f'{self.part_1} <--> {self.part_2}'

View File

@ -16,13 +16,13 @@
<div class='alert alert-block alert-info'>
{% else %}
<div class='alert alert-block alert-danger'>
The BOM for <i>{{ part.full_name }}</i> has changed, and must be validated.<br>
{% blocktrans with part=part.full_name %}The BOM for <i>{{ part }}</i> has changed, and must be validated.<br>{% endblocktrans %}
{% endif %}
The BOM for <i>{{ part.full_name }}</i> was last checked by {{ part.bom_checked_by }} on {{ part.bom_checked_date }}
{% blocktrans with part=part.full_name checker=part.bom_checked_by check_date=part.bom_checked_date %}The BOM for <i>{{ part }}</i> was last checked by {{ checker }} on {{ check_date }}{% endblocktrans %}
</div>
{% else %}
<div class='alert alert-danger alert-block'>
<b>The BOM for <i>{{ part.full_name }}</i> has not been validated.</b>
<b>{% blocktrans with part=part.full_name %}The BOM for <i>{{ part }}</i> has not been validated.{% endblocktrans %}</b>
</div>
{% endif %}

View File

@ -24,7 +24,7 @@
</div>
<form method="post" action='' class='js-modal-form' enctype="multipart/form-data">
<button type="submit" class="save btn btn-default">Upload File</button>
<button type="submit" class="save btn btn-default">{% trans 'Upload File' %}</button>
{% csrf_token %}
{% load crispy_forms_tags %}

View File

@ -1,10 +1,12 @@
{% extends "modal_form.html" %}
{% load i18n %}
{% block pre_form_content %}
Confirm that the Bill of Materials (BOM) is valid for:<br><i>{{ part.full_name }}</i>
{% blocktrans with part.full_name as part %}Confirm that the Bill of Materials (BOM) is valid for:<br><i>{{ part }}</i>{% endblocktrans %}
<div class='alert alert-warning alert-block'>
This will validate each line in the BOM.
{% trans 'This will validate each line in the BOM.' %}
</div>
{% endblock %}

View File

@ -342,7 +342,7 @@ class PartSetCategory(AjaxUpdateView):
data = {
'form_valid': valid,
'success': _('Set category for {n} parts'.format(n=len(self.parts)))
'success': _('Set category for {n} parts').format(n=len(self.parts))
}
if valid: