Coverage for app/venv/lib/python3.14/site-packages/weblate/machinery/weblatetm.py: 36%
35 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-07 07:15 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-07 07:15 +0000
1# Copyright © Michal Čihař <michal@weblate.org>
2#
3# SPDX-License-Identifier: GPL-3.0-or-later
5from __future__ import annotations
7from typing import TYPE_CHECKING, Any
9from django.conf import settings
10from django.db.models import Value
11from django.db.models.functions import MD5, Lower
13from weblate.trans.models import Unit
14from weblate.utils.db import adjust_similarity_threshold
15from weblate.utils.state import STATE_TRANSLATED
17from .base import InternalMachineTranslation
19if TYPE_CHECKING: 19 ↛ 20line 19 didn't jump to line 20 because the condition on line 19 was never true
20 from .base import DownloadTranslations
23class WeblateTranslation(InternalMachineTranslation):
24 """Translation service using strings already translated in Weblate."""
26 name = "Weblate"
27 rank_boost = 1
28 cache_translations = True
29 # Cache results for 1 hour to avoid frequent database hits
30 cache_expiry = 3600
32 def download_translations(
33 self,
34 source_language,
35 target_language,
36 text: str,
37 unit,
38 user,
39 threshold: int = 10,
40 ) -> DownloadTranslations:
41 """Download list of possible translations from a service."""
42 # Filter based on user access
43 base = Unit.objects.filter_access(user) if user else Unit.objects.all()
45 # Use memory_db for the query in case it exists. This is supposed
46 # to be a read-only replica for offloading expensive translation
47 # queries.
48 if "memory_db" in settings.DATABASES:
49 base = base.using("memory_db")
51 # Build search query
52 lookup: dict[str, Any] = {}
53 if threshold < 100:
54 # Full text search
55 lookup["source__search"] = text
56 else:
57 # Utilize PostgreSQL index
58 lookup["source__lower__md5"] = MD5(Lower(Value(text)))
59 lookup["source"] = text
61 matching_units = (
62 base.filter(
63 translation__component__source_language=source_language,
64 translation__language=target_language,
65 state__gte=STATE_TRANSLATED,
66 **lookup,
67 )
68 .exclude(
69 # The read-only strings can be possibly blank
70 target__lower__md5=MD5(Lower(Value("")))
71 )
72 .prefetch()
73 )
75 # We want only close matches here
76 adjust_similarity_threshold(0.98)
78 for munit in matching_units:
79 source = munit.source_string
80 if "forbidden" in munit.all_flags:
81 continue
82 quality = self.comparer.similarity(text, source)
83 if quality < threshold:
84 continue
85 yield {
86 "text": munit.get_target_plurals()[0],
87 "quality": quality,
88 "show_quality": True,
89 "service": self.name,
90 "origin": str(munit.translation.component),
91 "origin_url": munit.get_absolute_url(),
92 "source": source,
93 }