1
0
mirror of https://github.com/gryf/pygtktalog.git synced 2025-12-17 11:30:19 +01:00
Files
pygtktalog/generate_pot.py

164 lines
4.7 KiB
Python
Executable File

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Generate POT
~~~~~~~~~~~~
Generate a pot file with all translations for PyGTK applications
based on the organization idea I shared in my article about i18n
in PyGTK applications.
:copyright: 2006-2007 by Armin Ronacher.
:license: GNU GPL, see LICENSE for more details.
"""
import os
import sys
from xml.dom import minidom
from compiler import parse, ast
from datetime import datetime
PO_HEADER = """#
# %(name)s Language File
#
msgid ""
msgstr ""
"Project-Id-Version: %(name)s\\n"
"POT-Creation-Date: %(time)s\\n"
"Last-Translator: Roman Dobosz <gryf73@gmail.com>\\n"
"MIME-Version: 1.0\\n"
"Content-Type: text/plain; charset=utf-8\\n"
"Content-Transfer-Encoding: utf-8\\n"
"Generated-By: %(filename)s\\n"\
"""
EMPTY_STRING = ''
EMPTY_LINE = ['""\n']
LINE_SHIFT = ['\\n"\n"']
class StringCollection(object):
"""Class for collecting strings."""
def __init__(self, basename):
self.db = {}
self.order = []
self.offset = len(basename)
def feed(self, file, line, string):
name = file[self.offset:].lstrip('/')
if string not in self.db:
self.db[string] = [(name, line)]
self.order.append(string)
else:
self.db[string].append((name, line))
def __iter__(self):
for string in self.order:
yield string, self.db[string]
def quote(s):
"""Quotes a given string so that it is useable in a .po file."""
result = ['"']
firstmatch = True
for char in s:
if char == '\n':
if firstmatch:
result = EMPTY_LINE + result
firstmatch = False
result += LINE_SHIFT
continue
if char in '\t"':
result.append('\\')
result.append(char)
result.append('"')
return EMPTY_STRING.join(result)
def scan_python_file(filename, calls):
"""Scan a python file for gettext calls."""
def scan(nodelist):
for node in nodelist:
if isinstance(node, ast.CallFunc):
handle = False
for pos, n in enumerate(node):
if pos == 0:
if isinstance(n, ast.Name) and n.name in calls:
handle = True
elif pos == 1:
if handle:
if n.__class__ is ast.Const and \
isinstance(n.value, basestring):
yield n.lineno, n.value
break
else:
for line in scan([n]):
yield line
elif hasattr(node, '__iter__'):
for n in scan(node):
yield n
fp = file(filename)
try:
try:
return scan(parse(fp.read()))
except:
print >> sys.stderr, 'Syntax Error in file %r' % filename
finally:
fp.close()
def scan_glade_file(filename):
"""Scan a glade file for translatable strings."""
try:
doc = minidom.parse(filename)
except:
print >> sys.stderr, 'Syntax Error in file %r' % filename
for element in doc.getElementsByTagName('property'):
if element.getAttribute('translatable') == 'yes':
data = element.firstChild.nodeValue
if data and not data.startswith('gtk-'):
yield data
def scan_tree(pathname, calls=['_']):
"""Scans a tree for translatable strings."""
out = StringCollection(pathname)
for folder, _, files in os.walk(pathname):
for filename in files:
filename = os.path.join(folder, filename)
if filename.endswith('.py'):
result = scan_python_file(filename, calls)
if result is not None:
for lineno, string in result:
out.feed(filename, lineno, string)
elif filename.endswith('.glade'):
result = scan_glade_file(filename)
if result is not None:
for string in result:
out.feed(filename, None, string)
for line in out:
yield line
def run():
if len(sys.argv) != 3:
print 'usage: %s <basefolder> <name>' % sys.argv[0]
sys.exit()
print PO_HEADER % {
'time': datetime.now(),
'filename': sys.argv[0],
'name': sys.argv[2],
}
basepath = sys.argv[1]
for string, occurrences in scan_tree(basepath):
print
for path, lineno in occurrences:
print '#. file %r, line %s' % (path, lineno or '?')
print 'msgid %s' % quote(string)
print 'msgstr ""'
if __name__ == '__main__':
run()