#!/usr/bin/env python # Version: MPL 1.1 / GPLv3+ / LGPLv3+ # # The contents of this file are subject to the Mozilla Public License Version # 1.1 (the "License"); you may not use this file except in compliance with # the License or as specified alternatively below. You may obtain a copy of # the License at http://www.mozilla.org/MPL/ # # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License # for the specific language governing rights and limitations under the # License. # # The Initial Developer of the Original Code is # Miklos Vajna # Portions created by the Initial Developer are Copyright (C) 2011 the # Initial Developer. All Rights Reserved. # # Major Contributor(s): # # For minor contributions see the git repository. # # Alternatively, the contents of this file may be used under the terms of # either the GNU General Public License Version 3 or later (the "GPLv3+"), or # the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"), # in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable # instead of those above. import getopt, sys, os, re class Options: """Options of this script.""" def __init__(self): self.input = None self.output = None self.language = None self.template = None class Entry: """Represents a single line in an SDF file.""" def __init__(self, items): self.items = items # list of 15 fields path = self.items[1].split('\\') self.po = "%s/%s/%s.po" % (options.input.replace('\\', '/'), self.items[0], "/".join(path[:-1])) prefix = "" if len(self.items[5]): prefix += "%s." % self.items[5] if len(self.items[3]): prefix += "%s." % self.items[3] self.keys = [] # 10..13 are translation types for idx in range(10, 14): try: if len(self.items[idx]): t = {10:'text', 12:'quickhelptext', 13:'title'}[idx] self.keys.append((idx, self.sdf2po("%s#%s.%s%s" % (path[-1], self.items[4], prefix, t)))) except IndexError: print("Tried to access field #%d in sdf file, but no such column! Broken sdf file?" % idx) print("Fields: %s" % self.items) sys.exit(1) def translate(self, translations): """Translates text in the entry based on translations.""" self.items[9] = options.language for idx, key in self.keys: try: self.items[idx] = translations.data[(self.po, key)] self.items[14] = "2002-02-02 02:02:02" except KeyError: pass self.items[14] = self.items[14].strip() def sdf2po(self, s): """Escapes special chars in po key names.""" return s.translate(normalizetable) class Template: """Represents a reference template in SDF format.""" def __init__(self, path): sock = xopen(path, "r", encoding='utf-8') self.lines = [] for line in sock: entry = Entry(line.split('\t')) if os.path.exists(entry.po): self.lines.append(entry) def translate(self, translations): """Translates entires in the template based on translations.""" sock = xopen(options.output, "w", encoding='utf-8') for line in self.lines: line.translate(translations) sock.write("\t".join(line.items)+"\r\n") sock.close() class Translations: """Represents a set of .po files, containing translations.""" def __init__(self): self.data = {} for root, dirs, files in os.walk(options.input): for file in files: path = "%s/%s" % (root, file) sock = xopen(path, "r", encoding='utf-8') key = None buf = [] multiline = False fuzzy = False for line in sock: if line.startswith("#: "): key = line.strip()[3:] elif line.startswith("#, fuzzy"): fuzzy = True elif line.startswith("msgstr "): trans = line.strip()[8:-1] if len(trans): if fuzzy: fuzzy = False else: self.setdata(path, key, trans) multiline = False else: buf = [] buf.append(trans) multiline = True elif multiline and line.startswith('"'): buf.append(line.strip()[1:-1]) elif multiline and not len(line.strip()) and len("".join(buf)): if fuzzy: fuzzy = False else: self.setdata(path, key, "".join(buf)) buf = [] multiline = False if multiline and len("".join(buf)) and not fuzzy: self.setdata(path, key, "".join(buf)) def setdata(self, path, key, s): """Sets the translation for a given path and key, handling (un)escaping as well.""" if key: # unescape the po special chars s = s.replace('\\"', '"') if key.split('#')[0].endswith(".xhp"): s = self.escape_help_text(s) else: s = s.replace('\\\\', '\\') self.data[(path.replace('\\', '/'), key)] = s def escape_help_text(self, text): """Escapes the help text as it would be in an SDF file.""" for tag in helptagre.findall(text): # <, >, " are only escaped in <[[:lower:]]> tags. Some HTML tags make it in in # lowercase so those are dealt with. Some LibreOffice help tags are not # escaped. escapethistag = False for escape_tag in ["ahelp", "link", "item", "emph", "defaultinline", "switchinline", "caseinline", "variable", "bookmark_value", "image", "embedvar", "alt"]: if tag.startswith("<%s" % escape_tag) or tag == "" % escape_tag: escapethistag = True if tag in ["
", ""]: escapethistag = True if escapethistag: escaped_tag = ("\\<" + tag[1:-1] + "\\>").replace('"', '\\"') text = text.replace(tag, escaped_tag) return text def xopen(path, mode, encoding): """Wrapper around open() to support both python2 and python3.""" if sys.version_info >= (3,): return open(path, mode, encoding=encoding) else: return open(path, mode) def main(): """Main function of this script.""" opts, args = getopt.getopt(sys.argv[1:], "si:o:l:t:", ["skipsource", "input=", "output=", "language=", "template="]) for opt, arg in opts: if opt in ("-s", "--skipsource"): pass elif opt in ("-i", "--input"): options.input = arg.strip('/') elif opt in ("-o", "--output"): options.output = arg elif opt in ("-l", "--language"): options.language = arg elif opt in ("-t", "--template"): options.template = arg template = Template(options.template) translations = Translations() template.translate(translations) # used by ecape_help_text helptagre = re.compile('''<[/]??[a-z_\-]+?(?:| +[a-z]+?=".*?") *[/]??>''') options = Options() # used by sdf2po() normalfilenamechars = "/#.0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" normalizetable = "" for i in map(chr, list(range(256))): if i in normalfilenamechars: normalizetable += i else: normalizetable += "_" if __name__ == "__main__": main() # vim:set filetype=python shiftwidth=4 softtabstop=4 expandtab: