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)
|
||||
class AttributeGroupAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||
class AttributeGroupAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||
# noinspection PyClassVar
|
||||
model = AttributeGroup # type: ignore [misc]
|
||||
list_display = ("name", "modified")
|
||||
|
|
@ -182,7 +182,7 @@ class AttributeGroupAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
|||
|
||||
|
||||
@register(Attribute)
|
||||
class AttributeAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||
class AttributeAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||
# noinspection PyClassVar
|
||||
model = Attribute # type: ignore [misc]
|
||||
list_display = ("name", "group", "value_type", "modified")
|
||||
|
|
@ -196,7 +196,7 @@ class AttributeAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
|||
|
||||
|
||||
@register(AttributeValue)
|
||||
class AttributeValueAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||
class AttributeValueAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||
# noinspection PyClassVar
|
||||
model = AttributeValue # type: ignore [misc]
|
||||
list_display = ("attribute", "value", "modified")
|
||||
|
|
@ -226,7 +226,7 @@ class CategoryAdmin(FieldsetsMixin, ActivationActionsMixin, DraggableMPTTAdmin):
|
|||
|
||||
|
||||
@register(Brand)
|
||||
class BrandAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||
class BrandAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||
# noinspection PyClassVar
|
||||
model = Brand # type: ignore [misc]
|
||||
list_display = ("name",)
|
||||
|
|
@ -239,7 +239,7 @@ class BrandAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
|||
|
||||
|
||||
@register(Product)
|
||||
class ProductAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||
class ProductAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||
# noinspection PyClassVar
|
||||
model = Product # type: ignore [misc]
|
||||
list_display = (
|
||||
|
|
@ -279,7 +279,7 @@ class ProductAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
|||
|
||||
|
||||
@register(ProductTag)
|
||||
class ProductTagAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||
class ProductTagAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||
# noinspection PyClassVar
|
||||
model = ProductTag # type: ignore [misc]
|
||||
list_display = ("tag_name",)
|
||||
|
|
@ -291,7 +291,7 @@ class ProductTagAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
|||
|
||||
|
||||
@register(CategoryTag)
|
||||
class CategoryTagAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||
class CategoryTagAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||
# noinspection PyClassVar
|
||||
model = CategoryTag # type: ignore [misc]
|
||||
list_display = ("tag_name",)
|
||||
|
|
@ -303,7 +303,7 @@ class CategoryTagAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
|||
|
||||
|
||||
@register(Vendor)
|
||||
class VendorAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||
class VendorAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||
# noinspection PyClassVar
|
||||
model = Vendor # type: ignore [misc]
|
||||
list_display = ("name", "markup_percent", "modified")
|
||||
|
|
@ -317,7 +317,7 @@ class VendorAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
|||
|
||||
|
||||
@register(Feedback)
|
||||
class FeedbackAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||
class FeedbackAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||
# noinspection PyClassVar
|
||||
model = Feedback # type: ignore [misc]
|
||||
list_display = ("order_product", "rating", "comment", "modified")
|
||||
|
|
@ -330,7 +330,7 @@ class FeedbackAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
|||
|
||||
|
||||
@register(Order)
|
||||
class OrderAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||
class OrderAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||
# noinspection PyClassVar
|
||||
model = Order # type: ignore [misc]
|
||||
list_display = (
|
||||
|
|
@ -359,7 +359,7 @@ class OrderAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
|||
|
||||
|
||||
@register(OrderProduct)
|
||||
class OrderProductAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||
class OrderProductAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||
# noinspection PyClassVar
|
||||
model = OrderProduct # type: ignore [misc]
|
||||
list_display = ("order", "product", "quantity", "buy_price", "status", "modified")
|
||||
|
|
@ -373,7 +373,7 @@ class OrderProductAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
|||
|
||||
|
||||
@register(PromoCode)
|
||||
class PromoCodeAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||
class PromoCodeAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||
# noinspection PyClassVar
|
||||
model = PromoCode # type: ignore [misc]
|
||||
list_display = (
|
||||
|
|
@ -402,7 +402,7 @@ class PromoCodeAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
|||
|
||||
|
||||
@register(Promotion)
|
||||
class PromotionAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||
class PromotionAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||
# noinspection PyClassVar
|
||||
model = Promotion # type: ignore [misc]
|
||||
list_display = ("name", "discount_percent", "modified")
|
||||
|
|
@ -415,7 +415,7 @@ class PromotionAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
|||
|
||||
|
||||
@register(Stock)
|
||||
class StockAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||
class StockAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||
# noinspection PyClassVar
|
||||
model = Stock # type: ignore [misc]
|
||||
list_display = ("product", "vendor", "sku", "quantity", "price", "modified")
|
||||
|
|
@ -436,7 +436,7 @@ class StockAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
|||
|
||||
|
||||
@register(Wishlist)
|
||||
class WishlistAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||
class WishlistAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||
# noinspection PyClassVar
|
||||
model = Wishlist # type: ignore [misc]
|
||||
list_display = ("user", "modified")
|
||||
|
|
@ -448,7 +448,7 @@ class WishlistAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
|||
|
||||
|
||||
@register(ProductImage)
|
||||
class ProductImageAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||
class ProductImageAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||
# noinspection PyClassVar
|
||||
model = ProductImage # type: ignore [misc]
|
||||
list_display = ("alt", "product", "priority", "modified")
|
||||
|
|
|
|||
|
|
@ -126,11 +126,11 @@ class Command(BaseCommand):
|
|||
if not auth_key:
|
||||
raise CommandError("DEEPL_AUTH_KEY not set")
|
||||
|
||||
# attempt to import readline for interactive prefill
|
||||
# attempt to import readline for interactive fill
|
||||
try:
|
||||
import readline
|
||||
except ImportError:
|
||||
readline = None # fallback
|
||||
readline = None # type: ignore [assignment]
|
||||
|
||||
for target_lang in target_langs:
|
||||
api_code = DEEPL_TARGET_LANGUAGES_MAPPING.get(target_lang)
|
||||
|
|
@ -159,7 +159,6 @@ class Command(BaseCommand):
|
|||
if not en_po:
|
||||
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]
|
||||
if missing:
|
||||
self.stdout.write(self.style.NOTICE(f"⚠️ {len(missing)} missing in en_GB"))
|
||||
|
|
@ -168,16 +167,16 @@ class Command(BaseCommand):
|
|||
if readline:
|
||||
|
||||
def hook():
|
||||
readline.insert_text(default)
|
||||
readline.insert_text(default) # noqa: B023
|
||||
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}': "
|
||||
user_in = input(prompt).strip()
|
||||
|
||||
if readline:
|
||||
readline.set_pre_input_hook(None)
|
||||
readline.set_pre_input_hook(None) # type: ignore [attr-defined]
|
||||
|
||||
if user_in:
|
||||
e.msgstr = user_in
|
||||
|
|
@ -187,7 +186,76 @@ class Command(BaseCommand):
|
|||
en_po.save(en_path)
|
||||
self.stdout.write(self.style.SUCCESS("Updated en_GB PO"))
|
||||
|
||||
# … rest of your DeepL logic unchanged …
|
||||
# build new_po, translate missing entries, save target PO, etc.
|
||||
entries = [e for e in en_po if e.msgid and not e.obsolete]
|
||||
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."))
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
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:
|
||||
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"
|
||||
|
||||
|
||||
class UserAdmin(ActivationActionsMixin, BaseUserAdmin):
|
||||
class UserAdmin(ActivationActionsMixin, BaseUserAdmin): # type: ignore [misc]
|
||||
inlines = (BalanceInline, OrderInline)
|
||||
fieldsets = (
|
||||
(None, {"fields": ("email", "password")}),
|
||||
|
|
|
|||
Loading…
Reference in a new issue