Features: 1) Add detailed translation logic in deepl_translate command with placeholder mapping and DeepL API integration; 2) Enhance deepl_translate with better PO handling and dynamic saving.
Fixes: 1) Correct incorrect type annotations and imports for `readline` in `deepl_translate` command; 2) Remove unused variables `billing_address` and `shipping_address` in address application logic. Extra: Add `# type: ignore` comments to suppress type-checking errors across admin classes.
This commit is contained in:
parent
e49c942a1b
commit
c149adb0a8
4 changed files with 93 additions and 27 deletions
|
|
@ -170,7 +170,7 @@ class CategoryChildrenInline(TabularInline):
|
||||||
|
|
||||||
|
|
||||||
@register(AttributeGroup)
|
@register(AttributeGroup)
|
||||||
class AttributeGroupAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
class AttributeGroupAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||||
# noinspection PyClassVar
|
# noinspection PyClassVar
|
||||||
model = AttributeGroup # type: ignore [misc]
|
model = AttributeGroup # type: ignore [misc]
|
||||||
list_display = ("name", "modified")
|
list_display = ("name", "modified")
|
||||||
|
|
@ -182,7 +182,7 @@ class AttributeGroupAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||||
|
|
||||||
|
|
||||||
@register(Attribute)
|
@register(Attribute)
|
||||||
class AttributeAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
class AttributeAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||||
# noinspection PyClassVar
|
# noinspection PyClassVar
|
||||||
model = Attribute # type: ignore [misc]
|
model = Attribute # type: ignore [misc]
|
||||||
list_display = ("name", "group", "value_type", "modified")
|
list_display = ("name", "group", "value_type", "modified")
|
||||||
|
|
@ -196,7 +196,7 @@ class AttributeAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||||
|
|
||||||
|
|
||||||
@register(AttributeValue)
|
@register(AttributeValue)
|
||||||
class AttributeValueAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
class AttributeValueAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||||
# noinspection PyClassVar
|
# noinspection PyClassVar
|
||||||
model = AttributeValue # type: ignore [misc]
|
model = AttributeValue # type: ignore [misc]
|
||||||
list_display = ("attribute", "value", "modified")
|
list_display = ("attribute", "value", "modified")
|
||||||
|
|
@ -226,7 +226,7 @@ class CategoryAdmin(FieldsetsMixin, ActivationActionsMixin, DraggableMPTTAdmin):
|
||||||
|
|
||||||
|
|
||||||
@register(Brand)
|
@register(Brand)
|
||||||
class BrandAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
class BrandAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||||
# noinspection PyClassVar
|
# noinspection PyClassVar
|
||||||
model = Brand # type: ignore [misc]
|
model = Brand # type: ignore [misc]
|
||||||
list_display = ("name",)
|
list_display = ("name",)
|
||||||
|
|
@ -239,7 +239,7 @@ class BrandAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||||
|
|
||||||
|
|
||||||
@register(Product)
|
@register(Product)
|
||||||
class ProductAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
class ProductAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||||
# noinspection PyClassVar
|
# noinspection PyClassVar
|
||||||
model = Product # type: ignore [misc]
|
model = Product # type: ignore [misc]
|
||||||
list_display = (
|
list_display = (
|
||||||
|
|
@ -279,7 +279,7 @@ class ProductAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||||
|
|
||||||
|
|
||||||
@register(ProductTag)
|
@register(ProductTag)
|
||||||
class ProductTagAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
class ProductTagAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||||
# noinspection PyClassVar
|
# noinspection PyClassVar
|
||||||
model = ProductTag # type: ignore [misc]
|
model = ProductTag # type: ignore [misc]
|
||||||
list_display = ("tag_name",)
|
list_display = ("tag_name",)
|
||||||
|
|
@ -291,7 +291,7 @@ class ProductTagAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||||
|
|
||||||
|
|
||||||
@register(CategoryTag)
|
@register(CategoryTag)
|
||||||
class CategoryTagAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
class CategoryTagAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||||
# noinspection PyClassVar
|
# noinspection PyClassVar
|
||||||
model = CategoryTag # type: ignore [misc]
|
model = CategoryTag # type: ignore [misc]
|
||||||
list_display = ("tag_name",)
|
list_display = ("tag_name",)
|
||||||
|
|
@ -303,7 +303,7 @@ class CategoryTagAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||||
|
|
||||||
|
|
||||||
@register(Vendor)
|
@register(Vendor)
|
||||||
class VendorAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
class VendorAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||||
# noinspection PyClassVar
|
# noinspection PyClassVar
|
||||||
model = Vendor # type: ignore [misc]
|
model = Vendor # type: ignore [misc]
|
||||||
list_display = ("name", "markup_percent", "modified")
|
list_display = ("name", "markup_percent", "modified")
|
||||||
|
|
@ -317,7 +317,7 @@ class VendorAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||||
|
|
||||||
|
|
||||||
@register(Feedback)
|
@register(Feedback)
|
||||||
class FeedbackAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
class FeedbackAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||||
# noinspection PyClassVar
|
# noinspection PyClassVar
|
||||||
model = Feedback # type: ignore [misc]
|
model = Feedback # type: ignore [misc]
|
||||||
list_display = ("order_product", "rating", "comment", "modified")
|
list_display = ("order_product", "rating", "comment", "modified")
|
||||||
|
|
@ -330,7 +330,7 @@ class FeedbackAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||||
|
|
||||||
|
|
||||||
@register(Order)
|
@register(Order)
|
||||||
class OrderAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
class OrderAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||||
# noinspection PyClassVar
|
# noinspection PyClassVar
|
||||||
model = Order # type: ignore [misc]
|
model = Order # type: ignore [misc]
|
||||||
list_display = (
|
list_display = (
|
||||||
|
|
@ -359,7 +359,7 @@ class OrderAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||||
|
|
||||||
|
|
||||||
@register(OrderProduct)
|
@register(OrderProduct)
|
||||||
class OrderProductAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
class OrderProductAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||||
# noinspection PyClassVar
|
# noinspection PyClassVar
|
||||||
model = OrderProduct # type: ignore [misc]
|
model = OrderProduct # type: ignore [misc]
|
||||||
list_display = ("order", "product", "quantity", "buy_price", "status", "modified")
|
list_display = ("order", "product", "quantity", "buy_price", "status", "modified")
|
||||||
|
|
@ -373,7 +373,7 @@ class OrderProductAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||||
|
|
||||||
|
|
||||||
@register(PromoCode)
|
@register(PromoCode)
|
||||||
class PromoCodeAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
class PromoCodeAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||||
# noinspection PyClassVar
|
# noinspection PyClassVar
|
||||||
model = PromoCode # type: ignore [misc]
|
model = PromoCode # type: ignore [misc]
|
||||||
list_display = (
|
list_display = (
|
||||||
|
|
@ -402,7 +402,7 @@ class PromoCodeAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||||
|
|
||||||
|
|
||||||
@register(Promotion)
|
@register(Promotion)
|
||||||
class PromotionAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
class PromotionAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||||
# noinspection PyClassVar
|
# noinspection PyClassVar
|
||||||
model = Promotion # type: ignore [misc]
|
model = Promotion # type: ignore [misc]
|
||||||
list_display = ("name", "discount_percent", "modified")
|
list_display = ("name", "discount_percent", "modified")
|
||||||
|
|
@ -415,7 +415,7 @@ class PromotionAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||||
|
|
||||||
|
|
||||||
@register(Stock)
|
@register(Stock)
|
||||||
class StockAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
class StockAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||||
# noinspection PyClassVar
|
# noinspection PyClassVar
|
||||||
model = Stock # type: ignore [misc]
|
model = Stock # type: ignore [misc]
|
||||||
list_display = ("product", "vendor", "sku", "quantity", "price", "modified")
|
list_display = ("product", "vendor", "sku", "quantity", "price", "modified")
|
||||||
|
|
@ -436,7 +436,7 @@ class StockAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||||
|
|
||||||
|
|
||||||
@register(Wishlist)
|
@register(Wishlist)
|
||||||
class WishlistAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
class WishlistAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||||
# noinspection PyClassVar
|
# noinspection PyClassVar
|
||||||
model = Wishlist # type: ignore [misc]
|
model = Wishlist # type: ignore [misc]
|
||||||
list_display = ("user", "modified")
|
list_display = ("user", "modified")
|
||||||
|
|
@ -448,7 +448,7 @@ class WishlistAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||||
|
|
||||||
|
|
||||||
@register(ProductImage)
|
@register(ProductImage)
|
||||||
class ProductImageAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
class ProductImageAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||||
# noinspection PyClassVar
|
# noinspection PyClassVar
|
||||||
model = ProductImage # type: ignore [misc]
|
model = ProductImage # type: ignore [misc]
|
||||||
list_display = ("alt", "product", "priority", "modified")
|
list_display = ("alt", "product", "priority", "modified")
|
||||||
|
|
|
||||||
|
|
@ -126,11 +126,11 @@ class Command(BaseCommand):
|
||||||
if not auth_key:
|
if not auth_key:
|
||||||
raise CommandError("DEEPL_AUTH_KEY not set")
|
raise CommandError("DEEPL_AUTH_KEY not set")
|
||||||
|
|
||||||
# attempt to import readline for interactive prefill
|
# attempt to import readline for interactive fill
|
||||||
try:
|
try:
|
||||||
import readline
|
import readline
|
||||||
except ImportError:
|
except ImportError:
|
||||||
readline = None # fallback
|
readline = None # type: ignore [assignment]
|
||||||
|
|
||||||
for target_lang in target_langs:
|
for target_lang in target_langs:
|
||||||
api_code = DEEPL_TARGET_LANGUAGES_MAPPING.get(target_lang)
|
api_code = DEEPL_TARGET_LANGUAGES_MAPPING.get(target_lang)
|
||||||
|
|
@ -159,7 +159,6 @@ class Command(BaseCommand):
|
||||||
if not en_po:
|
if not en_po:
|
||||||
raise CommandError(f"Failed to load en_GB PO for {app_conf.label}")
|
raise CommandError(f"Failed to load en_GB PO for {app_conf.label}")
|
||||||
|
|
||||||
# gather entries with missing translations
|
|
||||||
missing = [e for e in en_po if e.msgid and not e.msgstr and not e.obsolete]
|
missing = [e for e in en_po if e.msgid and not e.msgstr and not e.obsolete]
|
||||||
if missing:
|
if missing:
|
||||||
self.stdout.write(self.style.NOTICE(f"⚠️ {len(missing)} missing in en_GB"))
|
self.stdout.write(self.style.NOTICE(f"⚠️ {len(missing)} missing in en_GB"))
|
||||||
|
|
@ -168,16 +167,16 @@ class Command(BaseCommand):
|
||||||
if readline:
|
if readline:
|
||||||
|
|
||||||
def hook():
|
def hook():
|
||||||
readline.insert_text(default)
|
readline.insert_text(default) # noqa: B023
|
||||||
readline.redisplay()
|
readline.redisplay()
|
||||||
|
|
||||||
readline.set_pre_input_hook(hook)
|
readline.set_pre_input_hook(hook) # type: ignore [attr-defined]
|
||||||
|
|
||||||
prompt = f"Enter translation for '{e.msgid}': "
|
prompt = f"Enter translation for '{e.msgid}': "
|
||||||
user_in = input(prompt).strip()
|
user_in = input(prompt).strip()
|
||||||
|
|
||||||
if readline:
|
if readline:
|
||||||
readline.set_pre_input_hook(None)
|
readline.set_pre_input_hook(None) # type: ignore [attr-defined]
|
||||||
|
|
||||||
if user_in:
|
if user_in:
|
||||||
e.msgstr = user_in
|
e.msgstr = user_in
|
||||||
|
|
@ -187,7 +186,76 @@ class Command(BaseCommand):
|
||||||
en_po.save(en_path)
|
en_po.save(en_path)
|
||||||
self.stdout.write(self.style.SUCCESS("Updated en_GB PO"))
|
self.stdout.write(self.style.SUCCESS("Updated en_GB PO"))
|
||||||
|
|
||||||
# … rest of your DeepL logic unchanged …
|
entries = [e for e in en_po if e.msgid and not e.obsolete]
|
||||||
# build new_po, translate missing entries, save target PO, etc.
|
source_map = {e.msgid: e.msgstr for e in entries}
|
||||||
|
|
||||||
|
tgt_dir = os.path.join(
|
||||||
|
app_conf.path,
|
||||||
|
"locale",
|
||||||
|
target_lang.replace("-", "_"),
|
||||||
|
"LC_MESSAGES",
|
||||||
|
)
|
||||||
|
os.makedirs(tgt_dir, exist_ok=True)
|
||||||
|
tgt_path = os.path.join(str(tgt_dir), "django.po")
|
||||||
|
|
||||||
|
old_tgt = None
|
||||||
|
if os.path.exists(tgt_path):
|
||||||
|
self.stdout.write(f" loading existing {target_lang} PO…")
|
||||||
|
try:
|
||||||
|
old_tgt = load_po_sanitized(str(tgt_path))
|
||||||
|
except Exception as e:
|
||||||
|
self.stdout.write(self.style.WARNING(f"Existing PO parse error({e!s}), starting fresh"))
|
||||||
|
|
||||||
|
new_po = polib.POFile()
|
||||||
|
new_po.metadata = en_po.metadata.copy()
|
||||||
|
new_po.metadata["Language"] = target_lang
|
||||||
|
|
||||||
|
for entry in entries:
|
||||||
|
prev = old_tgt.find(entry.msgid) if old_tgt else None
|
||||||
|
new_po.append(
|
||||||
|
polib.POEntry(
|
||||||
|
msgid=entry.msgid,
|
||||||
|
msgstr=prev.msgstr if prev and prev.msgstr else "",
|
||||||
|
msgctxt=entry.msgctxt,
|
||||||
|
comment=entry.comment,
|
||||||
|
tcomment=entry.tcomment,
|
||||||
|
occurrences=entry.occurrences,
|
||||||
|
flags=entry.flags,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
to_trans = [e for e in new_po if not e.msgstr]
|
||||||
|
if not to_trans:
|
||||||
|
self.stdout.write(self.style.WARNING(f"All done for {app_conf.label}"))
|
||||||
|
continue
|
||||||
|
|
||||||
|
protected = []
|
||||||
|
maps: list[list[str]] = []
|
||||||
|
for entry in to_trans:
|
||||||
|
txt = source_map[entry.msgid]
|
||||||
|
p_txt, p_map = placeholderize(txt)
|
||||||
|
protected.append(p_txt)
|
||||||
|
maps.append(p_map)
|
||||||
|
|
||||||
|
data = [
|
||||||
|
("auth_key", auth_key),
|
||||||
|
("target_lang", api_code),
|
||||||
|
] + [("text", t) for t in protected]
|
||||||
|
resp = requests.post("https://api.deepl.com/v2/translate", data=data)
|
||||||
|
try:
|
||||||
|
resp.raise_for_status()
|
||||||
|
result = resp.json()
|
||||||
|
except Exception as exc:
|
||||||
|
raise CommandError(f"DeepL error: {exc} – {resp.text}") from exc
|
||||||
|
|
||||||
|
trans = result.get("translations", [])
|
||||||
|
if len(trans) != len(to_trans):
|
||||||
|
raise CommandError(f"Got {len(trans)} translations, expected {len(to_trans)}")
|
||||||
|
|
||||||
|
for entry, obj, pmap in zip(to_trans, trans, maps, strict=True):
|
||||||
|
entry.msgstr = deplaceholderize(obj["text"], pmap)
|
||||||
|
|
||||||
|
new_po.save(str(tgt_path))
|
||||||
|
self.stdout.write(self.style.SUCCESS(f"Saved {tgt_path}"))
|
||||||
|
|
||||||
self.stdout.write(self.style.SUCCESS("Done."))
|
self.stdout.write(self.style.SUCCESS("Done."))
|
||||||
|
|
|
||||||
|
|
@ -1543,8 +1543,6 @@ class Order(ExportModelOperationsMixin("order"), NiceModel): # type: ignore [mi
|
||||||
|
|
||||||
def apply_addresses(self, billing_address_uuid: str | None = None, shipping_address_uuid: str | None = None):
|
def apply_addresses(self, billing_address_uuid: str | None = None, shipping_address_uuid: str | None = None):
|
||||||
try:
|
try:
|
||||||
billing_address = Address.objects.none()
|
|
||||||
shipping_address = Address.objects.none()
|
|
||||||
|
|
||||||
if not any([shipping_address_uuid, billing_address_uuid]) and not self.is_whole_digital:
|
if not any([shipping_address_uuid, billing_address_uuid]) and not self.is_whole_digital:
|
||||||
raise ValueError(_("you can only buy physical products with shipping address specified"))
|
raise ValueError(_("you can only buy physical products with shipping address specified"))
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ class OrderInline(admin.TabularInline):
|
||||||
icon = "fa-solid fa-cart-shopping"
|
icon = "fa-solid fa-cart-shopping"
|
||||||
|
|
||||||
|
|
||||||
class UserAdmin(ActivationActionsMixin, BaseUserAdmin):
|
class UserAdmin(ActivationActionsMixin, BaseUserAdmin): # type: ignore [misc]
|
||||||
inlines = (BalanceInline, OrderInline)
|
inlines = (BalanceInline, OrderInline)
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, {"fields": ("email", "password")}),
|
(None, {"fields": ("email", "password")}),
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue