2 # -*- coding: utf-8 -*-
4 # Copyright 2003-2008 Zuza Software Foundation
6 # This file is part of translate.
8 # translate is free software; you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation; either version 2 of the License, or
11 # (at your option) any later version.
13 # translate is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
18 # You should have received a copy of the GNU General Public License
19 # along with translate; if not, write to the Free Software
20 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 """convert an OpenOffice.org (SDF) localization file to Gettext PO localization files
25 See: http://translate.sourceforge.net/wiki/toolkit/oo2po for examples and
31 from translate
.storage
import po
32 from translate
.storage
import oo
34 # TODO: support using one GSI file as template, another as input (for when English is in one and translation in another)
37 def __init__(self
, sourcelanguage
, targetlanguage
, blankmsgstr
=False, long_keys
=False):
38 """construct an oo2po converter for the specified languages"""
39 self
.sourcelanguage
= sourcelanguage
40 self
.targetlanguage
= targetlanguage
41 self
.blankmsgstr
= blankmsgstr
42 self
.long_keys
= long_keys
44 def maketargetunit(self
, part1
, part2
, translators_comment
, key
, subkey
):
45 """makes a base unit (.po or XLIFF) out of a subkey of two parts"""
47 text1
= getattr(part1
, subkey
)
50 text2
= getattr(part2
, subkey
)
52 unit
= po
.pounit(text1
.decode('utf-8'), encoding
="UTF-8")
53 unit
.target
= text2
.decode('utf-8')
54 unit
.addlocation(key
+ "." + subkey
)
55 if getattr(translators_comment
, subkey
).strip() != "":
56 unit
.addnote(getattr(translators_comment
, subkey
), origin
="developer")
59 def makekey(self
, ookey
):
60 """converts an oo key tuple into a key identifier for the base class file (.po or XLIFF)"""
61 project
, sourcefile
, resourcetype
, groupid
, localid
, platform
= ookey
62 sourcefile
= sourcefile
.replace('\\','/')
64 sourcebase
= os
.path
.join(project
, sourcefile
)
66 sourceparts
= sourcefile
.split('/')
67 sourcebase
= "".join(sourceparts
[-1:])
68 if (groupid
) == 0 or len(localid
) == 0:
69 ooid
= groupid
+ localid
71 ooid
= groupid
+ "." + localid
73 ooid
= ooid
+ "." + resourcetype
74 key
= "%s#%s" % (sourcebase
, ooid
)
75 return oo
.normalizefilename(key
)
77 def convertelement(self
, theoo
):
78 """convert an oo element into a list of base units (.po or XLIFF)"""
79 if self
.sourcelanguage
in theoo
.languages
:
80 part1
= theoo
.languages
[self
.sourcelanguage
]
82 print >> sys
.stderr
, "/".join(theoo
.lines
[0].getkey()), "language not found: %s" % (self
.sourcelanguage
)
88 if self
.targetlanguage
in theoo
.languages
:
89 part2
= theoo
.languages
[self
.targetlanguage
]
91 # if the language doesn't exist, the translation is missing ... so make it blank
93 if "x-comment" in theoo
.languages
:
94 translators_comment
= theoo
.languages
["x-comment"]
96 translators_comment
= oo
.ooline()
97 key
= self
.makekey(part1
.getkey())
99 for subkey
in ("text", "quickhelptext", "title"):
100 unit
= self
.maketargetunit(part1
, part2
, translators_comment
, key
, subkey
)
102 unitlist
.append(unit
)
105 def convertstore(self
, theoofile
, duplicatestyle
="msgctxt"):
106 """converts an entire oo file to a base class format (.po or XLIFF)"""
107 thetargetfile
= po
.pofile()
108 # create a header for the file
109 bug_url
= 'http://qa.openoffice.org/issues/enter_bug.cgi' + ('''?subcomponent=ui&comment=&short_desc=Localization issue in file: %(filename)s&component=l10n&form_name=enter_issue''' % {"filename": theoofile
.filename
}).replace(" ", "%20").replace(":", "%3A")
110 targetheader
= thetargetfile
.makeheader(charset
="UTF-8", encoding
="8bit", x_accelerator_marker
="~", report_msgid_bugs_to
=bug_url
)
111 targetheader
.addnote("extracted from %s" % theoofile
.filename
, "developer")
112 thetargetfile
.addunit(targetheader
)
113 # go through the oo and convert each element
114 for theoo
in theoofile
.units
:
115 unitlist
= self
.convertelement(theoo
)
116 for unit
in unitlist
:
117 thetargetfile
.addunit(unit
)
118 thetargetfile
.removeduplicates(duplicatestyle
)
121 def verifyoptions(options
):
122 """verifies the commandline options"""
123 if not options
.pot
and not options
.targetlanguage
:
124 raise ValueError("You must specify the target language unless generating POT files (-P)")
126 def convertoo(inputfile
, outputfile
, templates
, pot
=False, sourcelanguage
=None, targetlanguage
=None, duplicatestyle
="msgid_comment", multifilestyle
="single"):
127 """reads in stdin using inputstore class, converts using convertorclass, writes to stdout"""
128 inputstore
= oo
.oofile()
129 if hasattr(inputfile
, "filename"):
130 inputfilename
= inputfile
.filename
132 inputfilename
= "(input file name not known)"
133 inputstore
.filename
= inputfilename
134 inputstore
.parse(inputfile
.read())
135 if not sourcelanguage
:
136 testlangtype
= targetlanguage
or (inputstore
and inputstore
.languages
[0]) or ""
137 if testlangtype
.isdigit():
138 sourcelanguage
= "01"
140 sourcelanguage
= "en-US"
141 if not sourcelanguage
in inputstore
.languages
:
142 print >> sys
.stderr
, "Warning: sourcelanguage '%s' not found in inputfile '%s' (contains %s)" % (sourcelanguage
, inputfilename
, ", ".join(inputstore
.languages
))
143 if targetlanguage
and targetlanguage
not in inputstore
.languages
:
144 print >> sys
.stderr
, "Warning: targetlanguage '%s' not found in inputfile '%s' (contains %s)" % (targetlanguage
, inputfilename
, ", ".join(inputstore
.languages
))
145 convertor
= oo2po(sourcelanguage
, targetlanguage
, blankmsgstr
=pot
, long_keys
=multifilestyle
!="single")
146 outputstore
= convertor
.convertstore(inputstore
, duplicatestyle
)
147 if outputstore
.isempty():
149 outputfile
.write(str(outputstore
))
153 from translate
.convert
import convert
154 formats
= {"oo":("po", convertoo
), "sdf":("po", convertoo
)}
155 # always treat the input as an archive unless it is a directory
156 archiveformats
= {(None, "input"): oo
.oomultifile
}
157 parser
= convert
.ArchiveConvertOptionParser(formats
, usepots
=True, description
=__doc__
, archiveformats
=archiveformats
)
158 parser
.add_option("-l", "--language", dest
="targetlanguage", default
=None,
159 help="set target language to extract from oo file (e.g. af-ZA)", metavar
="LANG")
160 parser
.add_option("", "--source-language", dest
="sourcelanguage", default
=None,
161 help="set source language code (default en-US)", metavar
="LANG")
162 parser
.add_option("", "--nonrecursiveinput", dest
="allowrecursiveinput", default
=True, action
="store_false", help="don't treat the input oo as a recursive store")
163 parser
.add_duplicates_option()
164 parser
.add_multifile_option()
165 parser
.passthrough
.append("pot")
166 parser
.passthrough
.append("sourcelanguage")
167 parser
.passthrough
.append("targetlanguage")
168 parser
.verifyoptions
= verifyoptions
171 if __name__
== '__main__':