Package translate :: Package convert :: Module pot2po
[hide private]
[frames] | no frames]

Source Code for Module translate.convert.pot2po

  1  #!/usr/bin/env python 
  2  # -*- coding: utf-8 -*- 
  3  # 
  4  # Copyright 2004-2009 Zuza Software Foundation 
  5  # 
  6  # This file is part of translate. 
  7  # 
  8  # This program 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. 
 12  # 
 13  # This program 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. 
 17  # 
 18  # You should have received a copy of the GNU General Public License 
 19  # along with this program; if not, see <http://www.gnu.org/licenses/>. 
 20   
 21  """Convert template files (like .pot or template .xlf files) translation files, 
 22  preserving existing translations. 
 23   
 24  See: http://translate.sourceforge.net/wiki/toolkit/pot2po for examples and 
 25  usage instructions. 
 26  """ 
 27   
 28  from translate.storage import factory 
 29  from translate.search import match 
 30  from translate.misc.multistring import multistring 
 31  from translate.tools import pretranslate 
 32  from translate.storage import poheader 
 33   
 34   
35 -def convertpot(input_file, output_file, template_file, tm=None, min_similarity=75, fuzzymatching=True, classes=factory.classes, **kwargs):
36 """Main conversion function""" 37 38 input_store = factory.getobject(input_file, classes=classes) 39 template_store = None 40 if template_file is not None: 41 template_store = factory.getobject(template_file, classes=classes) 42 output_store = convert_stores(input_store, template_store, tm, min_similarity, fuzzymatching, **kwargs) 43 output_file.write(str(output_store)) 44 return 1
45
46 -def convert_stores(input_store, template_store, tm=None, min_similarity=75, fuzzymatching=True, **kwargs):
47 """Actual conversion function, works on stores not files, returns 48 a properly initialized pretranslated output store, with structure 49 based on input_store, metadata based on template_store, migrates 50 old translations from template_store and pretranslating from tm""" 51 52 #prepare for merging 53 output_store = type(input_store)() 54 #create fuzzy matchers to be used by pretranslate.pretranslate_unit 55 matchers = [] 56 _prepare_merge(input_store, output_store, template_store) 57 if fuzzymatching: 58 if template_store: 59 matcher = match.matcher(template_store, max_candidates=1, min_similarity=min_similarity, max_length=3000, usefuzzy=True) 60 matcher.addpercentage = False 61 matchers.append(matcher) 62 if tm: 63 matcher = pretranslate.memory(tm, max_candidates=1, min_similarity=min_similarity, max_length=1000) 64 matcher.addpercentage = False 65 matchers.append(matcher) 66 67 #initialize store 68 _store_pre_merge(input_store, output_store, template_store) 69 70 # Do matching 71 for input_unit in input_store.units: 72 if input_unit.istranslatable(): 73 input_unit = pretranslate.pretranslate_unit(input_unit, template_store, matchers, mark_reused=True) 74 _unit_post_merge(input_unit, input_store, output_store, template_store) 75 output_store.addunit(input_unit) 76 77 #finalize store 78 _store_post_merge(input_store, output_store, template_store) 79 80 return output_store
81 82 83 ##dispatchers
84 -def _prepare_merge(input_store, output_store, template_store, **kwargs):
85 """Prepare stores & TM matchers before merging.""" 86 #dispatch to format specific functions 87 prepare_merge_hook = "_prepare_merge_%s" % input_store.__class__.__name__ 88 if globals().has_key(prepare_merge_hook): 89 globals()[prepare_merge_hook](input_store, output_store, template_store, **kwargs) 90 91 #generate an index so we can search by source string and location later on 92 input_store.makeindex() 93 if template_store: 94 template_store.makeindex()
95 96
97 -def _store_pre_merge(input_store, output_store, template_store, **kwargs) :
98 """Initialize the new file with things like headers and metadata.""" 99 #formats that implement poheader interface are a special case 100 if isinstance(input_store, poheader.poheader): 101 _do_poheaders(input_store, output_store, template_store) 102 103 #dispatch to format specific functions 104 store_pre_merge_hook = "_store_pre_merge_%s" % input_store.__class__.__name__ 105 if globals().has_key(store_pre_merge_hook): 106 globals()[store_pre_merge_hook](input_store, output_store, template_store, **kwargs)
107 108
109 -def _store_post_merge(input_store, output_store, template_store, **kwargs) :
110 """Close file after merging all translations, used for adding 111 statistics, obsolete messages and similar wrapup tasks.""" 112 #dispatch to format specific functions 113 store_post_merge_hook = "_store_post_merge_%s" % input_store.__class__.__name__ 114 if globals().has_key(store_post_merge_hook): 115 globals()[store_post_merge_hook](input_store, output_store, template_store, **kwargs)
116
117 -def _unit_post_merge(input_unit, input_store, output_store, template_store, **kwargs):
118 """Handle any unit level cleanup and situations not handled by the merge() 119 function.""" 120 #dispatch to format specific functions 121 unit_post_merge_hook = "_unit_post_merge_%s" % input_unit.__class__.__name__ 122 if globals().has_key(unit_post_merge_hook): 123 globals()[unit_post_merge_hook](input_unit, input_store, output_store, template_store, **kwargs)
124 125 126 ##format specific functions
127 -def _prepare_merge_pofile(input_store, output_store, template_store):
128 """PO format specific template preparation logic.""" 129 #we need to revive obsolete units to be able to consider 130 #their translation when matching 131 if template_store: 132 for unit in template_store.units: 133 if unit.isobsolete(): 134 unit.resurrect()
135 136
137 -def _unit_post_merge_pounit(input_unit, input_store, output_store, template_store):
138 """PO format specific plural string initializtion logic.""" 139 #FIXME: do we want to do that for poxliff also? 140 if input_unit.hasplural() and len(input_unit.target) == 0: 141 # untranslated plural unit; Let's ensure that we have the correct number of plural forms: 142 nplurals, plural = output_store.getheaderplural() 143 if nplurals and nplurals.isdigit() and nplurals != '2': 144 input_unit.target = multistring([""]*int(nplurals))
145 146
147 -def _store_post_merge_pofile(input_store, output_store, template_store):
148 """PO format specific: adds newly obsoleted messages to end of store.""" 149 #Let's take care of obsoleted messages 150 if template_store: 151 newlyobsoleted = [] 152 for unit in template_store.units: 153 if unit.isheader(): 154 continue 155 if unit.target and not (input_store.findunit(unit.source) or hasattr(unit, "reused")): 156 #not in .pot, make it obsolete 157 unit.makeobsolete() 158 newlyobsoleted.append(unit) 159 elif unit.isobsolete(): 160 output_store.addunit(unit) 161 for unit in newlyobsoleted: 162 output_store.addunit(unit)
163 164
165 -def _do_poheaders(input_store, output_store, template_store):
166 """Adds initialized PO headers to output store.""" 167 # header values 168 charset = "UTF-8" 169 encoding = "8bit" 170 project_id_version = None 171 pot_creation_date = None 172 po_revision_date = None 173 last_translator = None 174 language_team = None 175 mime_version = None 176 plural_forms = None 177 kwargs = {} 178 179 if template_store is not None and isinstance(template_store, poheader.poheader): 180 templateheadervalues = template_store.parseheader() 181 for key, value in templateheadervalues.iteritems(): 182 if key == "Project-Id-Version": 183 project_id_version = value 184 elif key == "Last-Translator": 185 last_translator = value 186 elif key == "Language-Team": 187 language_team = value 188 elif key == "PO-Revision-Date": 189 po_revision_date = value 190 elif key in ("POT-Creation-Date", "MIME-Version"): 191 # don't know how to handle these keys, or ignoring them 192 pass 193 elif key == "Content-Type": 194 kwargs[key] = value 195 elif key == "Content-Transfer-Encoding": 196 encoding = value 197 elif key == "Plural-Forms": 198 plural_forms = value 199 else: 200 kwargs[key] = value 201 202 inputheadervalues = input_store.parseheader() 203 for key, value in inputheadervalues.iteritems(): 204 if key in ("Project-Id-Version", "Last-Translator", "Language-Team", "PO-Revision-Date", "Content-Type", "Content-Transfer-Encoding", "Plural-Forms"): 205 # want to carry these from the template so we ignore them 206 pass 207 elif key == "POT-Creation-Date": 208 pot_creation_date = value 209 elif key == "MIME-Version": 210 mime_version = value 211 else: 212 kwargs[key] = value 213 214 output_header = output_store.init_headers(charset=charset, encoding=encoding, project_id_version=project_id_version, 215 pot_creation_date=pot_creation_date, po_revision_date=po_revision_date, last_translator=last_translator, 216 language_team=language_team, mime_version=mime_version, plural_forms=plural_forms, **kwargs) 217 218 # Get the header comments and fuzziness state 219 220 # initial values from pot file 221 input_header = input_store.header() 222 if input_header is not None: 223 if input_header.getnotes("developer"): 224 output_header.addnote(input_header.getnotes("developer"), origin="developer", position="replace") 225 if input_header.getnotes("translator"): 226 output_header.addnote(input_header.getnotes("translator"), origin="translator", position="replace") 227 output_header.markfuzzy(input_header.isfuzzy()) 228 229 # override some values from input file 230 if template_store is not None: 231 template_header = template_store.header() 232 if template_header is not None: 233 if template_header.getnotes("translator"): 234 output_header.addnote(template_header.getnotes("translator"), "translator") 235 output_header.markfuzzy(template_header.isfuzzy())
236 237
238 -def main(argv=None):
239 from translate.convert import convert 240 formats = {"pot": ("po", convertpot), ("pot", "po"): ("po", convertpot), 241 "xlf": ("xlf", convertpot), ("xlf", "xlf"): ("xlf", convertpot), 242 } 243 parser = convert.ConvertOptionParser(formats, usepots=True, usetemplates=True, 244 allowmissingtemplate=True, description=__doc__) 245 parser.add_option("", "--tm", dest="tm", default=None, 246 help="The file to use as translation memory when fuzzy matching") 247 parser.passthrough.append("tm") 248 defaultsimilarity = 75 249 parser.add_option("-s", "--similarity", dest="min_similarity", default=defaultsimilarity, 250 type="float", help="The minimum similarity for inclusion (default: %d%%)" % defaultsimilarity) 251 parser.passthrough.append("min_similarity") 252 parser.add_option("--nofuzzymatching", dest="fuzzymatching", action="store_false", 253 default=True, help="Disable fuzzy matching") 254 parser.passthrough.append("fuzzymatching") 255 parser.run(argv)
256 257 258 if __name__ == '__main__': 259 main() 260