नमस्ते,
मैंने ऊपर दिया गया Python स्क्रिप्ट को सामान्य (general) बनाने के लिए संशोधित किया है, जिसमें शब्द सूची (word list) और लैक्सिकन (lexicon) (यदि उपलब्ध हो) के लिए एक प्रॉम्प्ट होगा और FLEx में आयात (import) करने के लिए एक SMF फ़ाइल का आउटपुट होगा।
#!/usr/bin/python3
"""
wordlist_to_sfm.py
Paratext शब्द सूची को SFM (Standard Format Markers) प्रारूप में निर्यात करता है
FLEx (FieldWorks Language Explorer) में आयात के लिए।
उपयोग:
python wordlist_to_sfm.py
स्क्रिप्ट इनके लिए प्रॉम्प्ट देगी:
- Paratext शब्द सूची XML फ़ाइल (उदाहरण के लिए, Paratext के शब्द सूची टूल से निर्यात की गई)
- वैकल्पिक रूप से, अंग्रेज़ी ग्लॉस (glosses) प्रदान करने के लिए Paratext लैक्सिकन XML फ़ाइल
- परिणामी .sfm फ़ाइल के लिए आउटपुट फ़ाइल पथ
डिफ़ॉल्ट रूप से, केवल वे शब्द निर्यात किए जाते हैं जिन्हें शब्द सूची में "Correct" के रूप में चिह्नित किया गया है।
नीचे दिए गए INCLUDE_* सेटिंग्स को संपादित करके इसे बदला जा सकता है।
आउटपुट प्रारूप MDF (Multi-Dictionary Formatter) है, जो FLEx द्वारा लैक्सिकन आयात के लिए उपयोग किया जाने वाला मानक SFM डायलैक्ट है।
"""
import codecs
import os
import xml.etree.ElementTree as etree
# --- Settings ----------------------------------------------------------------
# नियंत्रित करें कि निर्यात में किन वर्तनी श्रेणियों (spelling categories) को शामिल किया जाए।
# उस श्रेणी के शब्दों को शामिल करने के लिए True सेट करें, उन्हें बाहर रखने के लिए False सेट करें।
INCLUDE_CORRECT = True # वे शब्द जिन्हें अनुवादक ने स्वीकृत किया है
INCLUDE_UNKNOWN = False # अभी तक समीक्षा नहीं किए गए शब्द
INCLUDE_INCORRECT = False # वर्तनी त्रुटियों के रूप में चिह्नित शब्द
# शब्द की कॉर्पस आवृत्ति (corpus frequency) को एक कमेंट फ़ील्ड (\co_count) के रूप में लिखने के लिए True सेट करें
INCLUDE_COUNT = True
# -----------------------------------------------------------------------------
def prompt_path(prompt_text, default):
"""वैकल्पिक डिफ़ॉल्ट मान के साथ एक प्रॉम्प्ट दिखाएं; उपयोगकर्ता का इनपुट या डिफ़ॉल्ट लौटाएं।"""
display = f" [{default}]" if default else ""
value = input(f"{prompt_text}{display}: ").strip()
return value if value else default
def get_user_inputs():
"""निर्यात चलाने के लिए आवश्यक तीन फ़ाइल पथों के लिए उपयोगकर्ता से पूछें।"""
print("Paratext Word List to SFM Exporter")
print("-----------------------------------\n")
# शब्द सूची आवश्यक है - फ़ाइल मिलने तक पूछते रहें
wordlist_path = prompt_path("Word list file (XML)", "Notsi-WL.xml")
while not os.path.exists(wordlist_path):
print(f" Cannot find '{wordlist_path}'. Please check the path and try again.")
wordlist_path = prompt_path("Word list file (XML)", "Notsi-WL.xml")
# लैक्सिकन वैकल्पिक है - यदि नहीं मिलता है तो चुपचाप छोड़ दें
lexicon_path = prompt_path("Lexicon file for glosses (press Enter to skip)", "")
if lexicon_path and not os.path.exists(lexicon_path):
print(f" Cannot find '{lexicon_path}'. Continuing without glosses.")
lexicon_path = ""
output_path = prompt_path("Output file name", "wordlist_for_flex.sfm")
return wordlist_path, lexicon_path, output_path
def load_lexicon_glosses(lexicon_path):
"""
Paratext लैक्सिकन XML फ़ाइल से अंग्रेज़ी ग्लॉस पढ़ें।
लैक्सिम रूप (lexeme form) की कुंजी के साथ एक शब्दकोश लौटाता है, जहाँ प्रत्येक मान में लैक्सिम प्रकार (Word, Prefix, Suffix) और अंग्रेज़ी ग्लॉस स्ट्रिंग्स की सूची शामिल होती है।
यदि कोई लैक्सिकन पथ प्रदान नहीं किया गया है, तो एक खाली शब्दकोश लौटाता है।
"""
glosses = {}
if not lexicon_path:
print("No lexicon provided - entries will be exported without glosses.")
return glosses
print(f"Reading lexicon from: {lexicon_path}")
with open(lexicon_path, "rb") as f:
data = f.read()
# किसी भी BOM विविधताओं को हटाएं (मानक UTF-8 BOM, या डबल-एन्कोडेड BOM)
for bom in (b"\xef\xbb\xbf", b"\xc3\xaf\xc2\xbb\xc2\xbf"):
if data.startswith(bom):
data = data[len(bom):]
break
xmldoc = etree.fromstring(data)
for item in xmldoc.findall("Entries/item"):
lexeme = next(item.iter("Lexeme"), None)
if lexeme is None:
continue
form = lexeme.get("Form", "")
lex_type = lexeme.get("Type", "Word") # Word, Prefix, or Suffix
# इस प्रविष्टि के लिए सभी अंग्रेज़ी ग्लॉस एकत्र करें (एक से अधिक अर्थ हो सकते हैं)
entry_glosses = [
gloss.text
for gloss in item.iter("Gloss")
if gloss.get("Language") == "en" and gloss.text
]
if form and entry_glosses:
glosses[form] = {"type": lex_type, "glosses": entry_glosses}
print(f" Found {len(glosses)} entries with English glosses.")
return glosses
def build_approved_list(wordlist_path):
"""
Paratext शब्द सूची XML पढ़ें और वे शब्द लौटाएं जो INCLUDE_* फ़िल्टर से गुजरते हैं।
स्वीकृत शब्द रूपों की सूची और एक मेटाडेटा शब्दकोश लौटाता है जिसमें प्रत्येक शब्द की कॉर्पस गिनती, हाइफ़नेशन (hyphenation), और रूपांतरण (morphology) विभाजन शामिल है।
"""
wordlist = etree.parse(wordlist_path)
all_items = wordlist.getroot().findall("item")
print(f"Reading word list from: {wordlist_path}")
print(f" {len(all_items)} words found in list.")
approved = []
metadata = {}
for item in all_items:
spelling = item.attrib.get("spelling", "Unknown")
word = item.attrib.get("word", "")
include = (
(spelling == "Correct" and INCLUDE_CORRECT) or
(spelling == "Unknown" and INCLUDE_UNKNOWN) or
(spelling == "Incorrect" and INCLUDE_INCORRECT)
)
if include and word:
approved.append(word)
metadata[word] = {
"count": item.attrib.get("count", "0"),
"hyphenation": item.attrib.get("hyphenation", ""),
"morphology": item.attrib.get("morphology", ""),
"morph_approved": item.attrib.get("morphologyApproved", "False"),
"specificcase": item.attrib.get("specificcase", ""),
}
print(f" {len(approved)} words marked as correct and ready to export.")
return approved, metadata
def write_sfm_entry(outfile, word, lex_type, glosses, meta, include_count):
"""
आउटपुट फ़ाइल में एकल SFM लैक्सिकन प्रविष्टि लिखें।
पालन किए गए MDF नियम:
\\lx - लैक्सिम (मुख्य शब्द); उपसर्गों को बाध्य पक्ष पर हाइफ़न मिलता है
\\sn - अर्थ संख्या (प्रत्येक ग्लॉस के लिए एक बार लिखा जाता है)
\\ge - उस अर्थ के लिए अंग्रेज़ी ग्लॉस
\\mr - रूपांतरण स्ट्रिंग (जब अनुवादक द्वारा स्वीकृत हो)
\\co_* - मेटाडेटा के लिए कमेंट फ़ील्ड, जिनके लिए FLEx में कोई मानक मार्कर नहीं है
"""
# मुख्य शब्द लिखें, उपसर्ग संलग्नता बिंदुओं को दिखाने के लिए हाइफ़न जोड़ें
outfile.write("\n\\lx ")
if lex_type == "Suffix":
outfile.write("-")
outfile.write(word)
if lex_type == "Prefix":
outfile.write("-")
outfile.write("\n")
# FLEx आयात के दौरान बने रहने के लिए उपसर्ग प्रकार को एक कमेंट के रूप में दर्ज करें
if lex_type != "Word":
outfile.write(f"\\co_type {lex_type}\n")
# कॉर्पस आवृत्ति - शब्दकोश कार्य के दौरान प्रविष्टियों को प्राथमिकता देने के लिए उपयोगी
if include_count and meta:
outfile.write(f"\\co_count {meta['count']}\n")
# रूपांतरण: यदि विश्लेषण स्वीकृत हो गया है तो मानक \\mr मार्कर का उपयोग करें,
# अन्यथा अस्वीकृत डेटा आयात करने से बचने के लिए इसे एक कमेंट के रूप में संग्रहीत करें
if meta and meta["morphology"]:
marker = "\\mr" if meta["morph_approved"] == "True" else "\\co_morph"
outfile.write(f"{marker} {meta['morphology']}\n")
# प्रत्येक ग्लॉस के लिए एक अर्थ ब्लॉक लिखें
for sense_num, gloss_text in enumerate(glosses, start=1):
outfile.write(f"\\sn {sense_num}\n")
outfile.write(f"\\ge {gloss_text}\n")
def main():
"""
मुख्य निर्यात रूटीन।
दो-चरण दृष्टिकोण:
चरण 1 - वे प्रविष्टियां लिखें जिनमें लैक्सिकन ग्लॉस हैं (पहले समृद्ध डेटा)
चरण 2 - शेष स्वीकृत शब्द लिखें जिनमें कोई लैक्सिकन प्रविष्टि नहीं थी
यह सुनिश्चित करता है कि ग्लॉस वाली प्रविष्टियां दोहराई न जाएं।
"""
wordlist_path, lexicon_path, output_path = get_user_inputs()
print()
approved_words, metadata = build_approved_list(wordlist_path)
lexicon_glosses = load_lexicon_glosses(lexicon_path)
# आउटपुट फ़ाइल को UTF-8 के रूप में खोलें और MDF हेडर लिखें
outfile = codecs.open(output_path, mode="w", encoding="utf-8")
outfile.write("\\_sh v3.0 400 MDF\n\\_DateStampHasFourDigitYear\n\n")
remaining = list(approved_words) # चरण 1 के बाद अभी भी लिखे जाने वाले शब्द
with_glosses = 0
# चरण 1: वे प्रविष्टियां जो लैक्सिकन और स्वीकृत शब्द सूची दोनों में उपस्थित हैं
for form, lex_data in lexicon_glosses.items():
if form not in approved_words:
print(f" Skipping '{form}' (in lexicon but not marked as correct in word list)")
continue
if form in remaining:
remaining.remove(form)
write_sfm_entry(outfile, word=form, lex_type=lex_data["type"],
glosses=lex_data["glosses"], meta=metadata.get(form),
include_count=INCLUDE_COUNT)
with_glosses += 1
# चरण 2: वे स्वीकृत शब्द जिनमें कोई लैक्सिकन प्रविष्टि नहीं है - ग्लॉस के बिना निर्यात किया जाता है
for word in remaining:
write_sfm_entry(outfile, word=word, lex_type="Word", glosses=[],
meta=metadata.get(word), include_count=INCLUDE_COUNT)
total = with_glosses + len(remaining)
outfile.close()
print(f"\nExport complete.")
print(f" Total entries written : {total}")
print(f" With glosses : {with_glosses}")
print(f" Without glosses : {len(remaining)}")
print(f" Output file : {output_path}")
if __name__ == "__main__":
main()