अनुवाद प्रणाली: तीन-तंत्रज्ञान हायब्रीड दृष्टिकोण

हा लेख आमची अनुवाद प्रणाली स्पष्ट करतो जी तीन तंत्रज्ञानांना एकत्र करते—टेम्पलेट्ससाठी Flask-Babel, फ्रेझ टेबल्ससाठी TranslationManager आणि सामग्री अनुवादासाठी DeepSeek AI—व्यापक बहुभाषिक समर्थन प्रदान करण्यासाठी.

समस्या: एक जटिल वेबसाइटचे अनुवाद करणे

आमच्या वेबसाइटवर अनेक प्रकारची सामग्री आहे ज्याचे अनुवाद करणे आवश्यक आहे:

  • स्थिर टेम्पलेट्स: नेव्हिगेशन, बटणे, लेबले (५००+ स्ट्रिंग्ज)

  • डायनॅमिक सामग्री: उत्पादन नावे, वर्णने, वैशिष्ट्ये (१०,०००+ स्ट्रिंग्ज)

  • वापरकर्ता-निर्मित सामग्री: पुनरावलोकने, टिप्पण्या, समर्थन तिकिटे

  • तांत्रिक संज्ञा: ब्रँड नावे, SKU, URL (अनुवादित करू नये)

एकच अनुवाद दृष्टिकोन कार्य करत नाही:

  • यंत्र अनुवाद: जलद पण तांत्रिक संज्ञांसाठी अचूक नाही

  • मॅन्युअल अनुवाद: अचूक पण मंद आणि महाग

  • केवळ टेम्पलेट: डायनॅमिक सामग्री हाताळत नाही

आम्हाला एक हायब्रीड दृष्टिकोन आवश्यक आहे जो तिन्हीचे सर्वोत्तम एकत्र करतो.

अनुवाद आर्किटेक्चर

graph TD
    Request[वापरकर्ता विनंती
lang=hi] subgraph Templates Babel[Flask-Babel
.po फाइल्स] Static[स्थिर स्ट्रिंग्ज
बटणे, लेबले] end subgraph Dynamic TM[TranslationManager
फ्रेझ टेबल्स] Phrases[उत्पादन नावे
वैशिष्ट्ये, संज्ञा] end subgraph AI DS[DeepSeek API
AI अनुवाद] Content[वर्णने
लेख, लांब मजकूर] end Request --> Babel Request --> TM Request --> DS Babel --> Static TM --> Phrases DS --> Content Static --> Response[अनुवादित पृष्ठ] Phrases --> Response Content --> Response

तीन तंत्रज्ञाने

१. Flask-Babel: टेम्पलेट अनुवाद

Flask-Babel gettext .po फाइल्स वापरून स्थिर टेम्पलेट स्ट्रिंग्ज हाताळते.

  • वापर प्रकरण: नेव्हिगेशन, बटणे, लेबले, त्रुटी संदेश

  • उदाहरण:

# टेम्पलेट
{{ _('Add to Cart') }}

# .po फाइल (हिंदी)
msgid "Add to Cart"
msgstr "कार्ट में जोड़ें"

फायदे:

  • ✅ मानक i18n दृष्टिकोन

  • ✅ अनुवाद साधन समर्थन (Poedit, Weblate)

  • ✅ संकलन-वेळ पडताळणी

  • ✅ जलद शोध (संकलित .mo फाइल्स)

मर्यादा:

  • ❌ केवळ स्थिर स्ट्रिंग्जसाठी कार्य करते

  • ❌ नवीन स्ट्रिंग्ज जोडण्यासाठी कोड बदल आवश्यक

  • ❌ डायनॅमिक सामग्री समर्थन नाही

२. TranslationManager: फ्रेझ टेबल्स

आमची सानुकूल TranslationManager वर्ग JSON फ्रेझ टेबल्स वापरून डायनॅमिक सामग्री हाताळते.

  • वापर प्रकरण: उत्पादन नावे, वैशिष्ट्ये, तपशील, वर्णने

  • उदाहरण:

{
  "Mini PC": "मिनी पीसी",
  "Intel N100": "Intel N100",
  "8GB RAM": "8GB RAM",
  "256GB SSD": "256GB SSD"
}

फायदे:

  • ✅ डायनॅमिक सामग्री समर्थन

  • ✅ रनटाइम अद्यतने (पुन्हा सुरू करण्याची गरज नाही)

  • ✅ संरक्षण नियम (ब्रँड नावे, SKU)

  • ✅ प्रादेशिक स्वरूपण (दशांश विभाजक)

  • ✅ अनुवाद रांग (गहाळ स्ट्रिंग्ज)

मर्यादा:

  • ❌ मॅन्युअल फ्रेझ व्यवस्थापन

  • ❌ अनुवादकांसाठी संदर्भ नाही

  • ❌ प्रारंभिक अनुवाद आवश्यक

३. DeepSeek AI: सामग्री अनुवाद

DeepSeek AI मॉडेल लांब-स्वरूपातील सामग्री अनुवाद हाताळते.

  • वापर प्रकरण: ब्लॉग लेख, उत्पादन वर्णने, विपणन कॉपी

  • उदाहरण:

prompt = f"Translate to {lang}: {text}"
response = deepseek.generate(prompt)

फायदे:

  • ✅ लांब सामग्री हाताळते (१०००+ शब्द)

  • ✅ संदर्भ-जाणीव अनुवाद

  • ✅ नैसर्गिक भाषा आउटपुट

  • ✅ बॅच प्रक्रिया

मर्यादा:

  • ❌ प्रति अनुवाद API खर्च

  • ❌ इंटरनेट कनेक्शन आवश्यक

  • ❌ तांत्रिक संज्ञा चुकीच्या पद्धतीने अनुवादित करू शकते

TranslationManager आर्किटेक्चर

फ्रेझ टेबल रचना

फ्रेझ टेबल्स प्रति भाषा JSON फाइल्स म्हणून संग्रहित केल्या जातात:

app/shared/translation/phrase_tables/

प्रत्येक फाइल इंग्रजी फ्रेझेस अनुवादांशी मॅप करते:

{
  "Mini PC": "मिनी पीसी",
  "Thin Client": "थिन क्लाइंट",
  "Industrial PC": "औद्योगिक पीसी",
  "All-in-One": "ऑल-इन-वन"
}

अनुवाद शोध

get() पद्धत बहु-स्तरीय शोध करते:

१. संरक्षण तपासणी:

if self._should_skip_translation(text, lang):
    return text  # ब्रँड नावे, SKU, URL अनुवादित करू नका

२. स्वल्पविराम विभाजन (लांब स्ट्रिंग्जसाठी):

if len(text) > 150 and "," in text:
    parts = text.split(",")
    return ", ".join(self.get(p, lang) for p in parts)

३. फ्रेझ टेबल शोध:

if text in self.phrase_tables[lang]:
    return self.phrase_tables[lang][text]

४. लीगेसी कॅश प्रमोशन:

if text_hash in self.legacy_caches[lang]:
    translation = self.legacy_caches[lang][text_hash]
    self.set(text, lang, translation)  # फ्रेझ टेबलमध्ये प्रमोट करा
    return translation

५. गहाळ असल्यास रांगेत ठेवा:

if queue_if_missing:
    self.add_to_queue(text, lang)
return None  # अनुवाद सापडला नाही

संरक्षण नियम

आम्ही विशिष्ट सामग्री प्रकार जतन करतो:

ब्रँड नावे:

BRAND_NAMES_PRESERVE = [
    "Thinvent", "Intel", "AMD", "Microsoft", "Ubuntu",
    "Windows", "Linux", "WiFi", "Bluetooth"
]

तांत्रिक संज्ञा:

TECHNICAL_TERMS_PRESERVE = [
    "HDMI", "DisplayPort", "VGA", "USB", "Ethernet",
    "DDR4", "SSD", "NVMe", "PCIe", "SATA"
]

SKU (पॅटर्न-आधारित):

if not " " in text and text.count("-") >= 2:
    return True  # "Treo-N100-8-256-2H-W6-11P" जतन करा

URL:

if text.startswith(("/", "http://", "https://")):
    return True

प्रादेशिक स्वरूपण

युरोपियन स्थानिकांसाठी (जर्मन, फ्रेंच, स्पॅनिश), आम्ही प्रादेशिक स्वरूपण लागू करतो:

दशांश विभाजक:

# इंग्रजी: 34.00
# जर्मन:  34,00
text = text.replace(".", ",")

व्होल्टेज/अँपरेज:

# इंग्रजी: 12.5V
# जर्मन:  12,5V
text = re.sub(r"(\d+)\.(\d+)V", r"\1,\2V", text)

हे खात्री करते की संख्या प्रत्येक स्थानिकासाठी योग्यरित्या प्रदर्शित होतात.

अनुवाद रांग

गहाळ अनुवाद बॅच प्रक्रियेसाठी रांगेत ठेवले जातात:

[
  {
    "text": "Compact Desktop",
    "lang": "hi",
    "hash": "a1b2c3d4e5f6"
  },
  {
    "text": "Fanless Design",
    "lang": "hi",
    "hash": "f6e5d4c3b2a1"
  }
]

एक पार्श्वभूमी स्क्रिप्ट DeepSeek AI वापरून रांग प्रक्रिया करते:

for item in queue:
    translation = deepseek.translate(item["text"], item["lang"])
    translation_manager.set(item["text"], item["lang"], translation)

फाइल लॉकिंग

आम्ही एकाचवेळी लेखन टाळण्यासाठी fcntl फाइल लॉकिंग वापरतो:

with open(lock_path, "w") as lock_file:
    fcntl.flock(lock_file, fcntl.LOCK_EX)
    try:
        # फ्रेझ टेबल वाचा, सुधारा, लिहा
        with open(table_path, "r+") as f:
            data = json.load(f)
            data.update(new_translations)
            f.seek(0)
            json.dump(data, f)
            f.truncate()
    finally:
        fcntl.flock(lock_file, fcntl.LOCK_UN)

हे खात्री करते की एकाधिक प्रक्रिया फ्रेझ टेबल्स बिघडवत नाहीत.

भाषा शोधणे

आम्ही युनिकोड रेंज आणि स्टॉपवर्ड्स वापरून क्वेरी भाषा शोधतो:

युनिकोड रेंज शोधणे

देवनागरी (हिंदी, मराठी):

if 0x0900 <= ord(char) <= 0x097F:
    return "hi"

बंगाली:

if 0x0980 <= ord(char) <= 0x09FF:
    return "bn"

अरबी:

if 0x0600 <= ord(char) <= 0x06FF:
    return "ar"

सिरिलिक (रशियन):

if 0x0400 <= ord(char) <= 0x04FF:
    return "ru"

CJK (चायनीज, जपानी, कोरियन):

if 0x4E00 <= ord(char) <= 0x9FFF:  # कांजी/हँझी
    has_cjk = True
if 0x3040 <= ord(char) <= 0x30FF:  # हिरागाना/कटाकाना
    return "ja"
if 0xAC00 <= ord(char) <= 0xD7AF:  # हंगुल
    return "ko"

स्टॉपवर्ड शोधणे

लॅटिन-आधारित भाषांसाठी, आम्ही स्टॉपवर्ड्स वापरतो:

स्पॅनिश:

SPANISH_STOPWORDS = {
    "el", "la", "los", "las", "un", "una", "para", "con",
    "en", "por", "que", "es", "su", "y", "del", "al"
}

फ्रेंच:

FRENCH_STOPWORDS = {
    "le", "la", "les", "des", "du", "un", "une", "pour",
    "avec", "en", "est", "sur", "et", "au", "dans"
}

जर्मन:

GERMAN_STOPWORDS = {
    "der", "die", "das", "ein", "eine", "für", "mit",
    "ist", "und", "auf", "den", "dem", "bei", "von"
}

कोणतेही स्टॉपवर्ड जुळल्यास, आम्ही ती भाषा परत करतो.

डायनॅमिक भाषा शोधणे

वापरकर्ते खालील मार्गांनी भाषा निर्दिष्ट करू शकतात:

१. URL पॅरामीटर

/p/Treo-N100-8-256-2H-W6-11P?lang=hi

२. कुकी

response.set_cookie("lang", "hi", max_age=31536000)

३. ब्राउझर स्वीकार-भाषा हेडर

lang = request.accept_languages.best_match(["en", "hi", "es", "fr", "de"])

प्राधान्य: URL पॅराम > कुकी > स्वीकार-भाषा > ड