Python program for update of .po files

Программа на Питоне для обновления записей в .po файлах

Програма на Пітоні для оновлення записів в .po файлах


Files :

Файлы :

Файли :

ul_gettext_update.zip

Updates present messages in .po files from .pot file.
One parameter - path/name of .pot file (default folder is "locale").

Обновляет записи в .po файлах переводов из записей главного .pot файла.
Один параметр - путь/название .pot файла (по умолчанию папка "locale").

Оновлює записи в .po файлах перекладів із записів з головного .pot файла.
Один параметр - шлях/назва .pot файла (по замовчуванню папка "locale").



## @package ul_gettext_update
##  Recursively update *.po translation files with new messages from *.pot file.


import sys, os, os.path, glob, re

## encoding of translation files
PO_ENCODING = 'UTF8'

## .po heading pattern
RE_PO_HEAD = '(.+?)\\#\\:'

## .po message pattern
RE_PO_MSG = '(\\#\\:.*?)[\\r\\n]+(msgid.*?)[\\r\\n]+(msgstr.*?)[\\r\\n]+'

## .po message id pattern
RE_PO_MSGID = '\\"(.*?)\\"'

## default locale directory
LOCALE_DIR = 'locale'



def parse_po(po_txt):
    ''' parses .po file to list of 3-element lists (description, msgid, msgstr)
        returns messages list, file heading, message ids list
    '''
    messages = [] # messages list
    msgids = [] # messages ids
    try:
        heading = re.search(RE_PO_HEAD, po_txt, re.I|re.M|re.U|re.DOTALL).group(1)
    except: heading = ''
    for msg in re.finditer(RE_PO_MSG, po_txt, re.M|re.I|re.U):
        if msg.group(1) and msg.group(2) and msg.group(3):
            messages.append([msg.group(1), msg.group(2), msg.group(3)])
            msgids.append(re.search(RE_PO_MSGID, msg.group(2), re.I|re.M|re.U|re.DOTALL).group(1))
    return messages, heading, msgids
    
    

print '.po updater.\n'
print 'Usage : ' + os.path.split(sys.argv[0])[1] + ' [locale_dir/*.pot]\n\n'

# custom locale dir given
if len(sys.argv) > 1:
    LOCALE_DIR = sys.argv[1]
    
if os.path.isdir(LOCALE_DIR):
    LOCALE_DIR = os.path.join(LOCALE_DIR, '*.pot')
    
## main .pot file
pot_files = glob.glob(LOCALE_DIR)

# no .pot found - show message, exit
if len(pot_files) == 0:
    print 'Can\'t find any .pot file'
    exit()
pot_file = pot_files[0]

print 'Reading : ' + pot_file
pot_name = os.path.splitext(os.path.split(pot_file)[1])[0] # .pot file name
pot_messages, pot_heading, pot_msgids = parse_po(open(pot_file, 'rb').read().decode(PO_ENCODING, 'ignore')) # get .pot messages

print 'Messages : ', len(pot_messages)

po_name = os.path.splitext(pot_name)[0] + '.po' # .po file name
LOCALE_DIR = os.path.split(pot_name)[0]

# search for present .po files
for root, dirs, files in os.walk(LOCALE_DIR):
    for file_in in files:
        if glob.fnmatch.fnmatch(file_in, po_name):
            po_pathname = os.path.join(root, file_in)
            po_messages, po_heading, po_msgids = parse_po(open(po_pathname, 'rb').read().decode(PO_ENCODING, 'ignore'))
            po_changes_plus = 0
            po_changes_minus = 0
            
            # create .po file text
            po_txt = po_heading
            
            # write records already present in .pot
            for msg_id in po_msgids:
                if msg_id in pot_msgids:
                    msg_index = po_msgids.index(msg_id)
                    msg = po_messages[msg_index][0] + '\n' +po_messages[msg_index][1] + '\n' +po_messages[msg_index][2] + '\n\n'
                    po_txt += msg
                else:
                    po_changes_minus += 1
            
            # append records not present in .pot
            for msg_id in pot_msgids:
                if not msg_id in po_msgids:
                    msg_index = pot_msgids.index(msg_id)
                    msg = pot_messages[msg_index][0] + '\n' +pot_messages[msg_index][1] + '\n' +pot_messages[msg_index][2] + '\n\n'
                    po_txt += msg
                    po_changes_plus += 1
            
            # if was changes, rewrite .po file
            if (po_changes_minus > 0) and (po_changes_plus > 0):
                open(po_pathname, 'wb').write(po_txt.encode(PO_ENCODING, 'ignore'))
            
            print '    ' + po_pathname + ' : -' + str(po_changes_minus) + ' +' + str(po_changes_plus)


print '\nPress ENTER to exit...',
raw_input()