diff options
Diffstat (limited to 'src/util/xmlpool/gen_xmlpool.py')
-rw-r--r-- | src/util/xmlpool/gen_xmlpool.py | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/src/util/xmlpool/gen_xmlpool.py b/src/util/xmlpool/gen_xmlpool.py new file mode 100644 index 00000000000..eb68a65174b --- /dev/null +++ b/src/util/xmlpool/gen_xmlpool.py @@ -0,0 +1,203 @@ + +# +# Usage: +# gen_xmlpool.py /path/to/t_option.h localedir lang lang lang ... +# +# For each given language, this script expects to find a .mo file at +# `{localedir}/{language}/LC_MESSAGES/options.mo`. +# + +import sys +import gettext +import re + +# Path to t_options.h +template_header_path = sys.argv[1] + +localedir = sys.argv[2] + +# List of supported languages +languages = sys.argv[3:] + +# Escape special characters in C strings +def escapeCString (s): + escapeSeqs = {'\a' : '\\a', '\b' : '\\b', '\f' : '\\f', '\n' : '\\n', + '\r' : '\\r', '\t' : '\\t', '\v' : '\\v', '\\' : '\\\\'} + # " -> '' is a hack. Quotes (") aren't possible in XML attributes. + # Better use Unicode characters for typographic quotes in option + # descriptions and translations. + i = 0 + r = '' + while i < len(s): + # Special case: escape double quote with \u201c or \u201d, depending + # on whether it's an open or close quote. This is needed because plain + # double quotes are not possible in XML attributes. + if s[i] == '"': + if i == len(s)-1 or s[i+1].isspace(): + # close quote + q = u'\u201c' + else: + # open quote + q = u'\u201d' + r = r + q + elif escapeSeqs.has_key(s[i]): + r = r + escapeSeqs[s[i]] + else: + r = r + s[i] + i = i + 1 + return r + +# Expand escape sequences in C strings (needed for gettext lookup) +def expandCString (s): + escapeSeqs = {'a' : '\a', 'b' : '\b', 'f' : '\f', 'n' : '\n', + 'r' : '\r', 't' : '\t', 'v' : '\v', + '"' : '"', '\\' : '\\'} + i = 0 + escape = False + hexa = False + octa = False + num = 0 + digits = 0 + r = '' + while i < len(s): + if not escape: + if s[i] == '\\': + escape = True + else: + r = r + s[i] + elif hexa: + if (s[i] >= '0' and s[i] <= '9') or \ + (s[i] >= 'a' and s[i] <= 'f') or \ + (s[i] >= 'A' and s[i] <= 'F'): + num = num * 16 + int(s[i],16) + digits = digits + 1 + else: + digits = 2 + if digits >= 2: + hexa = False + escape = False + r = r + chr(num) + elif octa: + if s[i] >= '0' and s[i] <= '7': + num = num * 8 + int(s[i],8) + digits = digits + 1 + else: + digits = 3 + if digits >= 3: + octa = False + escape = False + r = r + chr(num) + else: + if escapeSeqs.has_key(s[i]): + r = r + escapeSeqs[s[i]] + escape = False + elif s[i] >= '0' and s[i] <= '7': + octa = True + num = int(s[i],8) + if num <= 3: + digits = 1 + else: + digits = 2 + elif s[i] == 'x' or s[i] == 'X': + hexa = True + num = 0 + digits = 0 + else: + r = r + s[i] + escape = False + i = i + 1 + return r + +# Expand matches. The first match is always a DESC or DESC_BEGIN match. +# Subsequent matches are ENUM matches. +# +# DESC, DESC_BEGIN format: \1 \2=<lang> \3 \4=gettext(" \5=<text> \6=") \7 +# ENUM format: \1 \2=gettext(" \3=<text> \4=") \5 +def expandMatches (matches, translations, end=None): + assert len(matches) > 0 + nTranslations = len(translations) + i = 0 + # Expand the description+enums for all translations + for lang,trans in translations: + i = i + 1 + # Make sure that all but the last line of a simple description + # are extended with a backslash. + suffix = '' + if len(matches) == 1 and i < len(translations) and \ + not matches[0].expand (r'\7').endswith('\\'): + suffix = ' \\' + # Expand the description line. Need to use ugettext in order to allow + # non-ascii unicode chars in the original English descriptions. + text = escapeCString (trans.ugettext (unicode (expandCString ( + matches[0].expand (r'\5')), "utf-8"))).encode("utf-8") + print matches[0].expand (r'\1' + lang + r'\3"' + text + r'"\7') + suffix + # Expand any subsequent enum lines + for match in matches[1:]: + text = escapeCString (trans.ugettext (unicode (expandCString ( + match.expand (r'\3')), "utf-8"))).encode("utf-8") + print match.expand (r'\1"' + text + r'"\5') + + # Expand description end + if end: + print end, + +# Compile a list of translation classes to all supported languages. +# The first translation is always a NullTranslations. +translations = [("en", gettext.NullTranslations())] +for lang in languages: + try: + trans = gettext.translation ("options", localedir, [lang]) + except IOError: + sys.stderr.write ("Warning: language '%s' not found.\n" % lang) + continue + translations.append ((lang, trans)) + +# Regular expressions: +reLibintl_h = re.compile (r'#\s*include\s*<libintl.h>') +reDESC = re.compile (r'(\s*DRI_CONF_DESC\s*\(\s*)([a-z]+)(\s*,\s*)(gettext\s*\(\s*")(.*)("\s*\))(\s*\)[ \t]*\\?)$') +reDESC_BEGIN = re.compile (r'(\s*DRI_CONF_DESC_BEGIN\s*\(\s*)([a-z]+)(\s*,\s*)(gettext\s*\(\s*")(.*)("\s*\))(\s*\)[ \t]*\\?)$') +reENUM = re.compile (r'(\s*DRI_CONF_ENUM\s*\([^,]+,\s*)(gettext\s*\(\s*")(.*)("\s*\))(\s*\)[ \t]*\\?)$') +reDESC_END = re.compile (r'\s*DRI_CONF_DESC_END') + +# Print a header +print \ +"/***********************************************************************\n" \ +" *** THIS FILE IS GENERATED AUTOMATICALLY. DON'T EDIT! ***\n" \ +" ***********************************************************************/" + +# Process the options template and generate options.h with all +# translations. +template = file (template_header_path, "r") +descMatches = [] +for line in template: + if len(descMatches) > 0: + matchENUM = reENUM .match (line) + matchDESC_END = reDESC_END.match (line) + if matchENUM: + descMatches.append (matchENUM) + elif matchDESC_END: + expandMatches (descMatches, translations, line) + descMatches = [] + else: + sys.stderr.write ( + "Warning: unexpected line inside description dropped:\n%s\n" \ + % line) + continue + if reLibintl_h.search (line): + # Ignore (comment out) #include <libintl.h> + print "/* %s * commented out by gen_xmlpool.py */" % line + continue + matchDESC = reDESC .match (line) + matchDESC_BEGIN = reDESC_BEGIN.match (line) + if matchDESC: + assert len(descMatches) == 0 + expandMatches ([matchDESC], translations) + elif matchDESC_BEGIN: + assert len(descMatches) == 0 + descMatches = [matchDESC_BEGIN] + else: + print line, + +if len(descMatches) > 0: + sys.stderr.write ("Warning: unterminated description at end of file.\n") + expandMatches (descMatches, translations) |