def test_unknown_language_write(): catalog = Catalog(locale='sr_SP') assert catalog.locale_identifier == 'sr_SP' assert not catalog.locale buf = BytesIO() pofile.write_po(buf, catalog) assert 'sr_SP' in buf.getvalue().decode()
def extract(self, force=False): """ Extract translation strings from sources directory with extract rules then create the template catalog with finded translation strings Only proceed if the template catalog does not exists yet or if ``force`` argument is ``True`` (this will overwrite previous existing POT file) TODO: actually from the CLI usage this only update POT file when he does not exist, else it keeps untouched, even if there changes or adds in translations """ if force or not self.check_template_path(): self.logger.info('Proceeding to extraction to update the template catalog (POT)') self._catalog_template = Catalog(project=self.settings.SITE_NAME, header_comment=self.header_comment) # Follow all paths to search for pattern to extract for extract_path in self.settings.I18N_EXTRACT_SOURCES: self.logger.debug('Searching for pattern to extract in : {0}'.format(extract_path)) extracted = extract_from_dir(dirname=extract_path, method_map=self.settings.I18N_EXTRACT_MAP, options_map=self.settings.I18N_EXTRACT_OPTIONS) # Proceed to extract from given path for filename, lineno, message, comments, context in extracted: filepath = os.path.normpath(os.path.join(os.path.basename(self.settings.SOURCES_DIR), filename)) self._catalog_template.add(message, None, [(filepath, lineno)], auto_comments=comments, context=context) outfile = open(self.get_template_path(), 'wb') write_po(outfile, self._catalog_template) outfile.close() return self._catalog_template
def run(self): log.info('translating catalog %r based on %r', self.output_file, self.input_file) infile = open(self.input_file, 'r') try: # Although reading from the catalog template, read_po must be fed # the locale in order to correcly calculate plurals catalog = read_po(infile, locale=self.locale) finally: infile.close() catalog.locale = self._locale catalog.fuzzy = False for message in catalog: if message.id: # Recopie de l'id du message dans la traduction. message.string = message.id catalog[message.id] = message outfile = open(self.output_file, 'w') try: write_po(outfile, catalog) finally: outfile.close()
def run(self): mappings = self._get_mappings() with open(self.output_file, 'wb') as outfile: catalog = Catalog(project=self.project, version=self.version, msgid_bugs_address=self.msgid_bugs_address, copyright_holder=self.copyright_holder, charset=self.charset) for path, method_map, options_map in mappings: def callback(filename, method, options): if method == 'ignore': return # If we explicitly provide a full filepath, just use that. # Otherwise, path will be the directory path and filename # is the relative path from that dir to the file. # So we can join those to get the full filepath. if os.path.isfile(path): filepath = path else: filepath = os.path.normpath(os.path.join(path, filename)) optstr = '' if options: optstr = ' (%s)' % ', '.join(['%s="%s"' % (k, v) for k, v in options.items()]) self.log.info('extracting messages from %s%s', filepath, optstr) if os.path.isfile(path): current_dir = os.getcwd() extracted = check_and_call_extract_file( path, method_map, options_map, callback, self.keywords, self.add_comments, self.strip_comments, current_dir ) else: extracted = extract_from_dir( path, method_map, options_map, keywords=self.keywords, comment_tags=self.add_comments, callback=callback, strip_comment_tags=self.strip_comments ) for fname, lineno, msg, comments, context, flags in extracted: if os.path.isfile(path): filepath = fname # already normalized else: filepath = os.path.normpath(os.path.join(path, fname)) catalog.add(msg, None, [(filepath, lineno)], flags=flags, auto_comments=comments, context=context) self.log.info('writing PO template file to %s', self.output_file) write_po(outfile, catalog, width=self.width, no_location=self.no_location, omit_header=self.omit_header, sort_output=self.sort_output, sort_by_file=self.sort_by_file, include_lineno=self.include_lineno)
def test_update(self): template = Catalog() template.add("1") template.add("2") template.add("3") tmpl_file = os.path.join(self._i18n_dir(), 'temp-template.pot') with open(tmpl_file, "wb") as outfp: write_po(outfp, template) po_file = os.path.join(self._i18n_dir(), 'temp1.po') self.cli.run(sys.argv + ['init', '-l', 'fi', '-o', po_file, '-i', tmpl_file ]) with open(po_file, "r") as infp: catalog = read_po(infp) assert len(catalog) == 3 # Add another entry to the template template.add("4") with open(tmpl_file, "wb") as outfp: write_po(outfp, template) self.cli.run(sys.argv + ['update', '-l', 'fi_FI', '-o', po_file, '-i', tmpl_file]) with open(po_file, "r") as infp: catalog = read_po(infp) assert len(catalog) == 4 # Catalog was updated
def upodate_component_xl_content2pofile(component_xl_file): component_dir = os.path.dirname(component_xl_file) # TODO: delete all po files. po_dict = {} src_wb = load_workbook(component_xl_file, use_iterators=True) src_ws = src_wb.get_sheet_by_name(name='Sheet') for row in src_ws.iter_rows(): pofilename = row[0].internal_value if not po_dict.has_key(pofilename): po_dict[pofilename] = [] values = [] for cell in row[1:]: values.append(cell.internal_value) po_dict[pofilename].append(values) for pofilename in po_dict.keys(): pofilepath = os.path.join(component_dir, pofilename) contents = po_dict[pofilename] catalog = convert_xlsm_content(contents) with open(pofilepath, 'w') as f: pofile.write_po(f, catalog)
def extract(self): catalog_obj = catalog.Catalog() path = os.path.join(self.root, 'messages.pot') template = self.pod.open_file(path, mode='w') extracted = [] # Extracts messages from views. pod_files = self.pod.list_dir('/') for pod_path in pod_files: if os.path.splitext(pod_path)[-1] in _TRANSLATABLE_EXTENSIONS: content = self.pod.read_file(pod_path) import cStringIO fp = cStringIO.StringIO() fp.write(content) fp.seek(0) import tokenize try: messages = extract.extract('python', fp) for message in messages: lineno, string, comments, context = message catalog_obj.add(string, None, [(pod_path, lineno)], auto_comments=comments, context=context) except tokenize.TokenError: print 'Problem extracting: {}'.format(pod_path) raise # TODO(jeremydw): Extract messages from content. # Writes to PO template. pofile.write_po(template, catalog_obj, width=80, no_location=True, omit_header=True, sort_output=True, sort_by_file=True) logging.info('Extracted {} messages from {} files to: {}'.format(len(extracted), len(pod_files), template)) template.close() return catalog_obj
def import_file(self, locale, po_path): if locale is None: raise Error('Must specify locale.') if not os.path.exists(po_path): raise Error('Couldn\'t find PO file: {}'.format(po_path)) babel_locale = external_to_babel_locales.get(locale, locale) pod_translations_dir = os.path.join( 'translations', babel_locale, 'LC_MESSAGES') pod_po_path = os.path.join(pod_translations_dir, 'messages.po') if self.pod.file_exists(pod_po_path): existing_po_file = self.pod.open_file(pod_po_path) existing_catalog = pofile.read_po(existing_po_file, babel_locale) po_file_to_merge = open(po_path) catalog_to_merge = pofile.read_po(po_file_to_merge, babel_locale) for message in catalog_to_merge: if message.id not in existing_catalog: existing_catalog[message.id] = message else: existing_catalog[message.id].string = message.string existing_po_file = self.pod.open_file(pod_po_path, mode='w') pofile.write_po(existing_po_file, existing_catalog, width=80, omit_header=True, sort_output=True, sort_by_file=True) text = 'Imported {} translations: {}' self.pod.logger.info(text.format(len(catalog_to_merge), babel_locale)) else: abs_po_path = self.pod.abs_path(pod_po_path) abs_po_dir = os.path.dirname(abs_po_path) _mkdir(abs_po_dir) shutil.copyfile(po_path, abs_po_path) self.pod.logger.info('Imported new catalog: {}'.format(babel_locale))
def main(): # Check arguments parser = argparse.ArgumentParser() parser.add_argument('pot_filename', type=argparse.FileType('r')) parser.add_argument('po_filename', type=argparse.FileType('w')) parser.add_argument('locale') args = parser.parse_args() # read POT file pot_cat = pofile.read_po(args.pot_filename, ignore_obsolete=True) # Create the new Catalog new_cat = catalog.Catalog(locale=args.locale, last_translator="pseudo.py", charset="utf-8") num_plurals = new_cat.num_plurals # Process messages from template for msg in pot_cat: if msg.pluralizable: msg.string = [translate(u"{}:{}".format(i, msg.id[0])) for i in range(num_plurals)] else: msg.string = translate(msg.id) new_cat[msg.id] = msg # Write "translated" PO file pofile.write_po(args.po_filename, new_cat, ignore_obsolete=True)
def merge(source, target_filename): """Merges the messages from the source Catalog into a .po file at target_filename. Creates the target file if it doesn't exist.""" if os.path.exists(target_filename): target = pofile.read_po(open(target_filename)) for message in source: if message.id and message.string and not message.fuzzy: log_change(message.id in target and target[message.id], message) # This doesn't actually replace the message! It just updates # the fields other than the string. See Catalog.__setitem__. target[message.id] = message # We have to mutate the message to update the string and flags. target[message.id].string = message.string target[message.id].flags = message.flags else: for message in source: log_change(None, message) target = source target_file = create_file(target_filename) pofile.write_po(target_file, target, no_location=True, sort_output=True, ignore_obsolete=True) target_file.close()
def extract_messages(dirs): catalog = Catalog( project='Open Library', copyright_holder='Internet Archive' ) METHODS = [ ("**.py", "python"), ("**.html", "openlibrary.i18n:extract_templetor") ] COMMENT_TAGS = ["NOTE:"] for d in dirs: if '.html' in d: extracted = [(d,) + extract for extract in extract_from_file("openlibrary.i18n:extract_templetor", d)] else: extracted = extract_from_dir(d, METHODS, comment_tags=COMMENT_TAGS, strip_comment_tags=True) for filename, lineno, message, comments, context in extracted: catalog.add(message, None, [(filename, lineno)], auto_comments=comments) path = os.path.join(root, 'messages.pot') f = open(path, 'w') write_po(f, catalog) f.close() print('wrote template to', path)
def _extract(self, app): catalog = Catalog(domain="django", charset="utf8") files = {} for dirpath, dirnames, filenames in filtered_walk(app.path): for filename in filenames: filename = os.path.join(dirpath, filename) if ACCEPTABLE_FILENAMES_RE.match(filename): rel_filename = filename[len(os.path.commonprefix((app.path, filename))) + 1:].replace(os.sep, "/") files[rel_filename] = filename self.log.info("%s: %d translatable files found", app.label, len(files)) extractors = self.get_extractors() for rel_filename, filename in sorted(files.items()): extractor_tup = extractors.get(os.path.splitext(filename)[1]) if not extractor_tup: self.log.warning("Not sure how to extract messages from %s", filename) continue extractor, options = extractor_tup with open(filename, "rb") as fp: for (lineno, message, comments, context) in extract(extractor, fp, options=options): catalog.add(message, locations=[(rel_filename, 0)], auto_comments=comments) if len(catalog): pot_path = self._get_pot_path(app) with open(pot_path, "w") as outf: pofile.write_po(outf, catalog, width=1000, omit_header=True, sort_output=True) self.log.info("%s: %d messages in %s", app.label, len(catalog), pot_path) return catalog
def test_no_wrap_and_width_behaviour_on_comments(self): catalog = Catalog() catalog.add("Pretty dam long message id, which must really be big " "to test this wrap behaviour, if not it won't work.", locations=[("fake.py", n) for n in range(1, 30)]) buf = BytesIO() pofile.write_po(buf, catalog, width=None, omit_header=True) self.assertEqual(b"""\ #: fake.py:1 fake.py:2 fake.py:3 fake.py:4 fake.py:5 fake.py:6 fake.py:7 #: fake.py:8 fake.py:9 fake.py:10 fake.py:11 fake.py:12 fake.py:13 fake.py:14 #: fake.py:15 fake.py:16 fake.py:17 fake.py:18 fake.py:19 fake.py:20 fake.py:21 #: fake.py:22 fake.py:23 fake.py:24 fake.py:25 fake.py:26 fake.py:27 fake.py:28 #: fake.py:29 msgid "pretty dam long message id, which must really be big to test this wrap behaviour, if not it won't work." msgstr "" """, buf.getvalue().lower()) buf = BytesIO() pofile.write_po(buf, catalog, width=100, omit_header=True) self.assertEqual(b"""\ #: fake.py:1 fake.py:2 fake.py:3 fake.py:4 fake.py:5 fake.py:6 fake.py:7 fake.py:8 fake.py:9 fake.py:10 #: fake.py:11 fake.py:12 fake.py:13 fake.py:14 fake.py:15 fake.py:16 fake.py:17 fake.py:18 fake.py:19 #: fake.py:20 fake.py:21 fake.py:22 fake.py:23 fake.py:24 fake.py:25 fake.py:26 fake.py:27 fake.py:28 #: fake.py:29 msgid "" "pretty dam long message id, which must really be big to test this wrap behaviour, if not it won't" " work." msgstr "" """, buf.getvalue().lower())
def test_update(self): template = Catalog() template.add("1") template.add("2") template.add("3") tmpl_file = os.path.join(self._i18n_dir(), "temp-template.pot") with open(tmpl_file, "wb") as outfp: write_po(outfp, template) po_file = os.path.join(self._i18n_dir(), "temp1.po") self.cli.run(sys.argv + ["init", "-l", "fi", "-o", po_file, "-i", tmpl_file]) with open(po_file, "r") as infp: catalog = read_po(infp) assert len(catalog) == 3 # Add another entry to the template template.add("4") with open(tmpl_file, "wb") as outfp: write_po(outfp, template) self.cli.run(sys.argv + ["update", "-l", "fi_FI", "-o", po_file, "-i", tmpl_file]) with open(po_file, "r") as infp: catalog = read_po(infp) assert len(catalog) == 4 # Catalog was updated
def run(self, root): i18n_dir = self.extension.getConfig('i18n_dir') pot_path = os.path.join(i18n_dir, 'messages.pot') if os.path.exists(pot_path): with open(pot_path, 'r') as f: catalog = pofile.read_po(f) else: catalog = Catalog() lang = self.extension.getConfig('i18n_lang') mo_path = os.path.join(i18n_dir, lang, 'LC_MESSAGES', 'messages.mo') po_path = os.path.join(i18n_dir, lang, 'LC_MESSAGES', 'messages.po') if os.path.exists(po_path): with open(po_path, 'r') as f: lang_catalog = pofile.read_po(f) with open(mo_path, 'w') as mo: mofile.write_mo(mo, lang_catalog) translations = Translations.load(i18n_dir, locales=[lang]) self.translate(catalog, translations, root) with open(pot_path, 'w') as pot_file: pofile.write_po(pot_file, catalog)
def safe_write_po(self, catalog, filepath, **kwargs): """ Safely write a PO file This means that the PO file is firstly created in a temporary file, so if it fails it does not overwrite the previous one, if success the temporary file is moved over the previous one. Some part of code have been stealed from babel.messages.frontend """ tmpname = os.path.join(os.path.dirname(filepath), tempfile.gettempprefix() + os.path.basename(filepath)) tmpfile = open(tmpname, 'w') try: try: write_po(tmpfile, catalog, **kwargs) finally: tmpfile.close() except: os.remove(tmpname) raise try: os.rename(tmpname, filepath) except OSError: # We're probably on Windows, which doesn't support atomic # renames, at least not through Python # If the error is in fact due to a permissions problem, that # same error is going to be raised from one of the following # operations os.remove(filepath) shutil.copy(tmpname, filepath) os.remove(tmpname)
def test_with_context(self): buf = BytesIO(b'''# Some string in the menu #: main.py:1 msgctxt "Menu" msgid "foo" msgstr "Voh" # Another string in the menu #: main.py:2 msgctxt "Menu" msgid "bar" msgstr "Bahr" ''') catalog = pofile.read_po(buf, ignore_obsolete=True) self.assertEqual(2, len(catalog)) message = catalog.get('foo', context='Menu') self.assertEqual('Menu', message.context) message = catalog.get('bar', context='Menu') self.assertEqual('Menu', message.context) # And verify it pass through write_po out_buf = BytesIO() pofile.write_po(out_buf, catalog, omit_header=True) assert out_buf.getvalue().strip() == buf.getvalue().strip(), \ out_buf.getvalue()
def save(self, ignore_obsolete=True, include_previous=True, width=80): if not self.pod.file_exists(self.pod_path): self.pod.create_file(self.pod_path, None) outfile = self.pod.open_file(self.pod_path, mode='w') pofile.write_po(outfile, self, ignore_obsolete=ignore_obsolete, include_previous=include_previous, width=width) outfile.close()
def test_po_with_multiline_obsolete_message(self): catalog = Catalog() catalog.add(u'foo', u'Voh', locations=[('main.py', 1)]) msgid = r"""Here's a message that covers multiple lines, and should still be handled correctly. """ msgstr = r"""Here's a message that covers multiple lines, and should still be handled correctly. """ catalog.obsolete[msgid] = Message(msgid, msgstr, locations=[('utils.py', 3)]) buf = BytesIO() pofile.write_po(buf, catalog, omit_header=True) self.assertEqual(b'''#: main.py:1 msgid "foo" msgstr "Voh" #~ msgid "" #~ "Here's a message that covers\\n" #~ "multiple lines, and should still be handled\\n" #~ "correctly.\\n" #~ msgstr "" #~ "Here's a message that covers\\n" #~ "multiple lines, and should still be handled\\n" #~ "correctly.\\n"''', buf.getvalue().strip())
def import_csv_file(self, path): """Imports a CSV file formatted with locales in the header row and translations in the body rows.""" default_locale = self.pod.podspec.localization.get('default_locale', 'en') locales_to_catalogs = {} with open(path) as fp: reader = csv.DictReader(fp) for row in reader: if default_locale not in row: text = 'Locale {} not found in {}'.format(default_locale, path) raise Error(text) msgid = row[default_locale] msgid = msgid.decode('utf-8') for locale, translation in row.iteritems(): if locale == default_locale: continue translation = translation.decode('utf-8') message = catalog.Message(msgid, translation) if locale not in locales_to_catalogs: locales_to_catalogs[locale] = catalog.Catalog() locales_to_catalogs[locale][msgid] = message for locale, catalog_obj in locales_to_catalogs.iteritems(): fp = cStringIO.StringIO() pofile.write_po(fp, catalog_obj) fp.seek(0) content = fp.read() self.import_content(locale, content) fp.close()
def machine_translate(self): locale = str(self.locale) domain = 'messages' infile = self.pod.open_file(self.pod_path, 'U') try: babel_catalog = pofile.read_po(infile, locale=locale, domain=domain) finally: infile.close() # Get strings to translate. # TODO(jeremydw): Use actual string, not the msgid. Currently we assume # the msgid is the source string. messages_to_translate = [message for message in babel_catalog if not message.string] strings_to_translate = [message.id for message in messages_to_translate] if not strings_to_translate: logging.info('No untranslated strings for {}, skipping.'.format(locale)) return # Convert Python-format named placeholders to numerical placeholders # compatible with Google Translate. Ex: %(name)s => (O). placeholders = [] # Lists (#) placeholders to %(name)s placeholders. for n, string in enumerate(strings_to_translate): match = re.search('(%\([^\)]*\)\w)', string) if not match: placeholders.append(None) continue for i, group in enumerate(match.groups()): num_placeholder = '({})'.format(i) nums_to_names = {} nums_to_names[num_placeholder] = group replaced_string = string.replace(group, num_placeholder) placeholders.append(nums_to_names) strings_to_translate[n] = replaced_string machine_translator = goslate.Goslate() results = machine_translator.translate(strings_to_translate, locale) for i, string in enumerate(results): message = messages_to_translate[i] # Replace numerical placeholders with named placeholders. if placeholders[i]: for num_placeholder, name_placeholder in placeholders[i].iteritems(): string = string.replace(num_placeholder, name_placeholder) message.string = string if isinstance(string, unicode): string = string.encode('utf-8') source = message.id source = (source.encode('utf-8') if isinstance(source, unicode) else source) outfile = self.pod.open_file(self.pod_path, mode='w') try: pofile.write_po(outfile, babel_catalog, width=80) finally: outfile.close() text = 'Machine translated {} strings: {}' logging.info(text.format(len(strings_to_translate), self.pod_path))
def init_catalog(self): locale = str(self.locale) input_path = os.path.join('translations', 'messages.pot') output_path = os.path.join('translations', locale, 'LC_MESSAGES', 'messages.po') logging.info('Creating catalog %r based on %r', output_path, input_path) infile = self.pod.open_file(input_path) try: babel_catalog = pofile.read_po(infile, locale=locale) finally: infile.close() babel_locale = babel.Locale.parse(locale) babel_catalog.locale = babel_locale babel_catalog.revision_date = datetime.now(util.LOCALTZ) babel_catalog.fuzzy = False # TODO(jeremydw): Optimize. # Creates directory if it doesn't exist. path = os.path.join(output_path) if not self.pod.file_exists(path): self.pod.create_file(path, None) outfile = self.pod.open_file(output_path, mode='w') try: pofile.write_po(outfile, babel_catalog, width=80) finally: outfile.close()
def write_clean_po(filename, catalog): """Writes out a .po file in a canonical way, to minimize spurious diffs.""" catalog.creation_date = datetime.datetime(2000, 1, 1, 0, 0, 0) file = open(filename, 'w') pofile.write_po(file, catalog, no_location=True, sort_output=True, ignore_obsolete=True) file.close()
def test_sorted_po_context(self): catalog = Catalog() catalog.add((u'foo', u'foos'), (u'Voh', u'Voeh'), locations=[('main.py', 1)], context='there') catalog.add((u'foo', u'foos'), (u'Voh', u'Voeh'), locations=[('main.py', 1)]) catalog.add((u'foo', u'foos'), (u'Voh', u'Voeh'), locations=[('main.py', 1)], context='here') buf = BytesIO() pofile.write_po(buf, catalog, sort_output=True) value = buf.getvalue().strip() # We expect the foo without ctx, followed by "here" foo and "there" foo assert b'''\ #: main.py:1 msgid "foo" msgid_plural "foos" msgstr[0] "Voh" msgstr[1] "Voeh" #: main.py:1 msgctxt "here" msgid "foo" msgid_plural "foos" msgstr[0] "Voh" msgstr[1] "Voeh" #: main.py:1 msgctxt "there" msgid "foo" msgid_plural "foos" msgstr[0] "Voh" msgstr[1] "Voeh"''' in value
def test_with_context(self): buf = StringIO( r"""# Some string in the menu #: main.py:1 msgctxt "Menu" msgid "foo" msgstr "Voh" # Another string in the menu #: main.py:2 msgctxt "Menu" msgid "bar" msgstr "Bahr" """ ) catalog = pofile.read_po(buf, ignore_obsolete=True) self.assertEqual(2, len(catalog)) message = catalog.get("foo", context="Menu") self.assertEqual("Menu", message.context) message = catalog.get("bar", context="Menu") self.assertEqual("Menu", message.context) # And verify it pass through write_po out_buf = BytesIO() pofile.write_po(out_buf, catalog, omit_header=True) assert out_buf.getvalue().strip() == buf.getvalue().strip().encode("latin-1"), out_buf.getvalue()
def handle(self, *args, **options): if args: # mimics puente.management.commands.extract for a list of files outputdir = os.path.join(settings.ROOT, 'locale', 'templates', 'LC_MESSAGES') if not os.path.isdir(outputdir): os.makedirs(outputdir) catalog = Catalog( header_comment='', project=get_setting('PROJECT'), version=get_setting('VERSION'), msgid_bugs_address=get_setting('MSGID_BUGS_ADDRESS'), charset='utf-8', ) for filename, lineno, msg, cmts, ctxt in extract_from_files(args): catalog.add(msg, None, [(filename, lineno)], auto_comments=cmts, context=ctxt) with open(os.path.join(outputdir, '%s.pot' % DOMAIN), 'wb') as fp: write_po(fp, catalog, width=80) else: # This is basically a wrapper around the puente extract # command, we might want to do some things around this in the # future gettext_extract() pot_to_langfiles(DOMAIN)
def test_write_po_file_with_specified_charset(self): catalog = Catalog(charset="iso-8859-1") catalog.add("foo", "\xe4\xf6\xfc", locations=[("main.py", 1)]) buf = BytesIO() pofile.write_po(buf, catalog, omit_header=False) po_file = buf.getvalue().strip() assert br'"Content-Type: text/plain; charset=iso-8859-1\n"' in po_file assert 'msgstr "\xe4\xf6\xfc"'.encode("iso-8859-1") in po_file
def catalog2string(catalog, **kwargs): """Helper that returns a babel message catalog as a string. This is a simple shortcut around pofile.write_po(). """ sf = BytesIO() pofile.write_po(sf, catalog, **kwargs) return sf.getvalue().decode('utf-8')
def test_file_sorted_po(self): catalog = Catalog() catalog.add(u'bar', locations=[('utils.py', 3)]) catalog.add((u'foo', u'foos'), (u'Voh', u'Voeh'), locations=[('main.py', 1)]) buf = BytesIO() pofile.write_po(buf, catalog, sort_by_file=True) value = buf.getvalue().strip() assert value.find(b'main.py') < value.find(b'utils.py')
def test_write_po_file_with_specified_charset(self): catalog = Catalog(charset='iso-8859-1') catalog.add('foo', u'äöü', locations=[('main.py', 1)]) buf = BytesIO() pofile.write_po(buf, catalog, omit_header=False) po_file = buf.getvalue().strip() assert b'"Content-Type: text/plain; charset=iso-8859-1\\n"' in po_file assert u'msgstr "äöü"'.encode('iso-8859-1') in po_file
def update_translations(): pot_path = os.path.join(root, 'messages.pot') template = read_po(open(pot_path, 'rb')) for locale in get_locales(): po_path = os.path.join(root, locale, 'messages.po') mo_path = os.path.join(root, locale, 'messages.mo') if os.path.exists(po_path): catalog = read_po(open(po_path, 'rb')) catalog.update(template) f = open(po_path, 'wb') write_po(f, catalog) f.close() print('updated', po_path) compile_translations()
def test_po_with_obsolete_message(self): catalog = Catalog() catalog.add(u'foo', u'Voh', locations=[('main.py', 1)]) catalog.obsolete['bar'] = Message(u'bar', u'Bahr', locations=[('utils.py', 3)], user_comments=['User comment']) buf = BytesIO() pofile.write_po(buf, catalog, omit_header=True) self.assertEqual( b'''#: main.py:1 msgid "foo" msgstr "Voh" # User comment #~ msgid "bar" #~ msgstr "Bahr"''', buf.getvalue().strip())
def test_wrap_long_lines_in_header(self): """ Verify that long lines in the header comment are wrapped correctly. """ catalog = Catalog(project='AReallyReallyLongNameForAProject', revision_date=datetime(2007, 4, 1)) buf = BytesIO() pofile.write_po(buf, catalog) self.assertEqual( b('''\ # Translations template for AReallyReallyLongNameForAProject. # Copyright (C) 2007 ORGANIZATION # This file is distributed under the same license as the # AReallyReallyLongNameForAProject project. # FIRST AUTHOR <EMAIL@ADDRESS>, 2007. # #, fuzzy'''), b('\n').join(buf.getvalue().splitlines()[:7]))
def fake_extract_command(filename, fileobj, method, options=generate_options_map(), keywords=get_setting('KEYWORDS'), comment_tags=get_setting('COMMENT_TAGS')): catalog = Catalog(charset='utf-8') extracted = fake_extract_from_dir(filename, fileobj, method, options, keywords, comment_tags) for filename, lineno, msg, cmts, ctxt in extracted: catalog.add(msg, None, [(filename, lineno)], auto_comments=cmts, context=ctxt) po_out = StringIO() write_po(po_out, catalog, width=80, omit_header=True) return unicode(po_out.getvalue())
def write_template(self, template_path, catalog, include_obsolete=False, include_header=False): template_file = self.pod.open_file(template_path, mode='w') catalogs.Catalog.set_header_comment(self.pod, catalog) pofile.write_po(template_file, catalog, width=80, omit_header=(not include_header), sort_output=True, sort_by_file=True, ignore_obsolete=(not include_obsolete)) text = 'Saved: {} ({} messages)' self.pod.logger.info(text.format(template_path, len(catalog))) template_file.close() return catalog
def po_catalog_export(self): """ Export a catalog from a project into a PO file """ toast_path = "/home/django/Emencia/po_headquarter/dummy_po/" project = Project.objects.get(slug='dummy') catalog = Catalog.objects.get(project=project, locale='fr') #mime_dict = json.loads(catalog.mime_headers) forged_catalog = BabelCatalog( locale=catalog.locale, header_comment=catalog.header_comment, project=project.name, version="0.2.0" ) print "before add:", len(forged_catalog) for entry in catalog.translationmsg_set.all().order_by('id'): locations = [tuple(item) for item in json.loads(entry.template.locations)] forged_catalog.add(entry.template.message, string=entry.message, locations=locations, flags=entry.template.flags) print "after add:", len(forged_catalog) print "errors:", [item for item in forged_catalog.check()] print print "---------------- Original" fpw = StringIO() write_po(fpw, forged_catalog, sort_by_file=False, ignore_obsolete=True, include_previous=False) print fpw.getvalue() fpw.close() print print "---------------- Updated" fp3 = open(os.path.join(toast_path, '0-3-0.pot'), 'r') template_catalog_3 = read_po(fp3) forged_catalog.update(template_catalog_3) fpw = StringIO() write_po(fpw, forged_catalog, sort_by_file=False, ignore_obsolete=True, include_previous=False) print fpw.getvalue() fpw.close()
def extract(self, force=False): """ Extract translation strings from sources directory with extract rules then create the template catalog with finded translation strings Only proceed if the template catalog does not exists yet or if ``force`` argument is ``True`` (this will overwrite previous existing POT file) TODO: actually from the CLI usage this only update POT file when he does not exist, else it keeps untouched, even if there changes or adds in translations """ if force or not self.check_template_path(): self.logger.info( 'Proceeding to extraction to update the template catalog (POT)' ) self._catalog_template = Catalog( project=self.settings.SITE_NAME, header_comment=self.header_comment) # Follow all paths to search for pattern to extract for extract_path in self.settings.I18N_EXTRACT_SOURCES: self.logger.debug( 'Searching for pattern to extract in : {0}'.format( extract_path)) extracted = extract_from_dir( dirname=extract_path, method_map=self.settings.I18N_EXTRACT_MAP, options_map=self.settings.I18N_EXTRACT_OPTIONS) # Proceed to extract from given path for filename, lineno, message, comments, context in extracted: filepath = os.path.normpath( os.path.join( os.path.basename(self.settings.SOURCES_DIR), filename)) self._catalog_template.add(message, None, [(filepath, lineno)], auto_comments=comments, context=context) outfile = open(self.get_template_path(), 'wb') write_po(outfile, self._catalog_template) outfile.close() return self._catalog_template
def test_pot_with_translator_comments(self): catalog = Catalog() catalog.add(u'foo', locations=[('main.py', 1)], auto_comments=['Comment About `foo`']) catalog.add(u'bar', locations=[('utils.py', 3)], user_comments=['Comment About `bar` with', 'multiple lines.']) buf = BytesIO() pofile.write_po(buf, catalog, omit_header=True) self.assertEqual(b'''#. Comment About `foo` #: main.py:1 msgid "foo" msgstr "" # Comment About `bar` with # multiple lines. #: utils.py:3 msgid "bar" msgstr ""''', buf.getvalue().strip())
def safe_write_po(self, catalog, filepath, **kwargs): """ Safely write or overwrite a PO(T) file. Try to write catalog to a temporary file then move it to its final destination only writing operation did not fail. This way initial file is not overwrited when operation has failed. Original code comes from ``babel.messages.frontend``. Arguments: catalog (babel.messages.catalog.Catalog): Catalog object to write. filepath (string): Catalog file path destination. **kwargs: Additional arbitrary keyword argumentsto pass to ``write_po()`` babel function. Returns: babel.messages.catalog.Catalog: Catalog template object. """ tmpname = os.path.join( os.path.dirname(filepath), tempfile.gettempprefix() + os.path.basename(filepath), ) # Attempt to write new file to a temp file, clean temp file if it fails try: with io.open(tmpname, "wb") as tmpfile: write_po(tmpfile, catalog, **kwargs) except: # noqa os.remove(tmpname) raise # Finally overwrite file if previous job has succeeded try: os.rename(tmpname, filepath) except OSError: # We're probably on Windows, which doesn't support atomic # renames, at least not through Python # If the error is in fact due to a permissions problem, that # same error is going to be raised from one of the following # operations os.remove(filepath) shutil.copy(tmpname, filepath) os.remove(tmpname)
def write_output(self,out_path,**kwargs): # args = self.validate_arguments(kwargs,[],{}) # not used template = Catalog(domain="parts", project="BOLTS") for coll, in self.repo.itercollections(): self._coll_extract(template,coll) for cl,coll in self.repo.iterclasses(["class","collection"]): self._class_extract(template,cl,coll) for name,cl,coll in self.repo.iternames(["name","class","collection"]): self._name_extract(template,name,cl,coll) for std,cl,coll in self.repo.iterstandards(["standard","class","collection"]): self._standard_extract(template,std,cl,coll) with open(out_path,'w') as fid: write_po(fid,template)
def extract_messages(self, fid): cat = Catalog(domain='docs', project="BOLTS") for doc in self.documents: cat.add(doc["title"], auto_comments=[ 'document title', 'docs/%s/%s/%s' % (doc["version"], doc["category"], doc["filename"]) ]) for paragraph in doc["content"]: if paragraph: cat.add( paragraph, auto_comments=[ 'docs/%s/%s/%s' % (doc["version"], doc["category"], doc["filename"]) ]) write_po(fid, cat)
def run(self): log.info('creating catalog %r based on %r', self.output_file, self.input_file) infile = open(self.input_file, 'r') try: # Although reading from the catalog template, read_po must be fed # the locale in order to correcly calculate plurals catalog = read_po(infile, locale=self.locale) finally: infile.close() catalog.locale = self._locale catalog.fuzzy = False outfile = open(self.output_file, 'wb') try: write_po(outfile, catalog) finally: outfile.close()
def test_wrap_long_lines_with_long_word(self): text = """Here's some text that includesareallylongwordthatmightbutshouldnt throw us into an infinite loop """ catalog = Catalog() catalog.add(text, locations=[('main.py', 1)]) buf = BytesIO() pofile.write_po(buf, catalog, no_location=True, omit_header=True, width=32) self.assertEqual( b'''msgid "" "Here's some text that\\n" "includesareallylongwordthatmightbutshouldnt" " throw us into an infinite " "loop\\n" msgstr ""''', buf.getvalue().strip())
def test_with_context_two(self): buf = BytesIO(b'''msgctxt "Menu" msgid "foo" msgstr "Voh" msgctxt "Mannu" msgid "bar" msgstr "Bahr" ''') catalog = pofile.read_po(buf, ignore_obsolete=True) self.assertEqual(2, len(catalog)) message = catalog.get('foo', context='Menu') self.assertEqual('Menu', message.context) message = catalog.get('bar', context='Mannu') self.assertEqual('Mannu', message.context) # And verify it pass through write_po out_buf = BytesIO() pofile.write_po(out_buf, catalog, omit_header=True) assert out_buf.getvalue().strip() == buf.getvalue().strip(), out_buf.getvalue()
def test_wrap_long_lines(self): text = """Here's some text where white space and line breaks matter, and should not be removed """ catalog = Catalog() catalog.add(text, locations=[('main.py', 1)]) buf = BytesIO() pofile.write_po(buf, catalog, no_location=True, omit_header=True, width=42) self.assertEqual(b'''msgid "" "Here's some text where\\n" "white space and line breaks matter, and" " should\\n" "\\n" "not be removed\\n" "\\n" msgstr ""''', buf.getvalue().strip())
def get_pot(): result = dict() result['state'] = 'Failed' koji_session = ServerProxy(koji_url) result['branch'] = get_branch(koji_session, request.args) # Retrieve content tags = get_tags_for_fedora_branch(result['branch']) catalog = get_module_catalog_from_tags(koji_session, tags) potfile_io = BytesIO() pofile.write_po(potfile_io, catalog, sort_by_file=True) result['potfile'] = potfile_io.getvalue().decode('utf8') result['state'] = 'Succeeded' return jsonify(result)
def handle(self, *args, **options): """Handle the save_trans command.""" filename_po = load_translation_settings(settings) locale_path = settings.MODELTRANSLATION_LOCALE_PATH if not isdir(locale_path): mkdir(locale_path) for lang in [l[0] for l in list(settings.LANGUAGES)]: catalog = Catalog(locale=lang) for model in translator.get_registered_models(): opts = translator.get_options_for_model(model) for field in opts.get_field_names(): tr_field = "%s_%s" % (field, lang) en_field = "%s_%s" % (field, "en") for item in model.objects.all(): msgid = "%s.%s.%s" % (item._meta, item.pk, field) msgstr = "%s" % getattr(item, tr_field) enval = getattr(item, en_field) if enval is not None and field not in [ "slug", "url_path" ]: enstr = json.dumps(enval.stream_data) if hasattr( enval, "stream_data") else "%s" % enval catalog.add(id=enstr, string=msgstr, auto_comments=[ msgid, ]) # write catalog to file lang_path = join(locale_path, lang) if not isdir(lang_path): mkdir(lang_path) mkdir(join(lang_path, "LC_MESSAGES")) po_file = open(join(lang_path, "LC_MESSAGES", filename_po), "wb") write_po(po_file, catalog) po_file.close()
def cmd_extract(args): pkginfo = load_pkginfo(args) for cident, cmod in pkginfo['components'].iteritems(): if args.component is not None and cident not in args.component: continue module = import_module(cmod) modpath = module.__path__[0] dist = get_distribution(args.package) meta = dict(message_from_string(dist.get_metadata('PKG-INFO'))) catalog = Catalog(project=args.package, version=dist.version, copyright_holder=meta.get('Author'), msgid_bugs_address=meta.get('Author-email'), fuzzy=False, charset='utf-8') method_map, options_map = get_mappings() def log_callback(filename, method, options): if method != 'ignore': filepath = os.path.normpath(os.path.join(modpath, filename)) logger.debug('Extracting messages from %s', filepath) extracted = extract_from_dir(modpath, method_map, options_map, callback=log_callback) for filename, lineno, message, comments, context in extracted: catalog.add(message, None, [(filename, lineno)], auto_comments=comments, context=context) if len(catalog) > 0: logger.info("Component %s: %d messages", cident, len(catalog)) outfn = resource_filename(args.package, 'locale/%s.pot' % cident) with open(outfn, 'w') as outfd: write_po(outfd, catalog, ignore_obsolete=True)
def _update(self, app, template_catalog, langs): if template_catalog is None: with open(_get_pot_path(app)) as infp: template_catalog = pofile.read_po(infp, charset="utf8") for lang in langs: po_path = _get_po_path(app, language=lang) if os.path.isfile(po_path): with open(po_path) as infp: lang_catalog = pofile.read_po(infp, charset="utf8") else: lang_catalog = Catalog(locale=lang, charset="utf8") lang_catalog.update(template_catalog) if len(lang_catalog): with open(po_path, "w") as outf: pofile.write_po(outf, lang_catalog, width=1000, omit_header=True, sort_output=True) self.log.info("%s: updated %s", app.label, po_path)
def run(self): self.log.info('creating catalog %r based on %r', self.output_file, self.input_file) infile = open(self.input_file, 'rb') try: # Although reading from the catalog template, read_po must be fed # the locale in order to correctly calculate plurals catalog = read_po(infile, locale=self.locale) finally: infile.close() catalog.locale = self._locale catalog.revision_date = datetime.now(LOCALTZ) catalog.fuzzy = False outfile = open(self.output_file, 'wb') try: write_po(outfile, catalog, width=self.width) finally: outfile.close()
def _download_content(self, stat): spreadsheet_id = stat.ident values = self._download_sheet(spreadsheet_id, stat.lang) source_lang, lang, _, _ = values.pop(0) babel_catalog = catalog.Catalog(stat.lang) for row in values: source = row[0] translation = row[1] if len(row) > 1 else None babel_catalog.add(source, translation, auto_comments=[], context=None, flags=[]) updated_stat = base.TranslatorStat( url=stat.url, lang=stat.lang, downloaded=datetime.datetime.now(), source_lang=stat.source_lang, ident=stat.ident) fp = StringIO.StringIO() pofile.write_po(fp, babel_catalog) fp.seek(0) content = fp.read() return updated_stat, content
def test_po_with_obsolete_message(self): catalog = Catalog() catalog.add(u'foo', u'Voh', locations=[('main.py', 1)]) catalog.obsolete['bar'] = Message(u'bar', u'Bahr', locations=[('utils.py', 3)], flags=['fuzzy'], extracted_comments=['Developer Comment'], translator_comments=['User comment'], previous_id=u'foo', previous_context='previous context', context='context') buf = BytesIO() pofile.write_po(buf, catalog, omit_header=True) self.assertEqual(b'''#: main.py:1 msgid "foo" msgstr "Voh" # User comment #. Developer Comment #: utils.py:3 #, fuzzy #~ msgctxt "context" #~ msgid "bar" #~ msgstr "Bahr"''', buf.getvalue().strip()) buf = BytesIO() pofile.write_po(buf, catalog, omit_header=True, include_previous=True) self.assertEqual(b'''#: main.py:1 msgid "foo" msgstr "Voh" # User comment #. Developer Comment #: utils.py:3 #, fuzzy #| msgctxt "previous context" #| msgid "foo" #~ msgctxt "context" #~ msgid "bar" #~ msgstr "Bahr"''', buf.getvalue().strip())
def _update_po_files(cls, input_spreadsheet, po_filenames, output_dir, save): updated_catalogs = [] if output_dir: try: os.makedirs(output_dir) except OSError as e: if e.errno != errno.EEXIST: output_dir = None wb = openpyxl.load_workbook(input_spreadsheet, read_only=True) ws = wb.active first_row = ws[1] for filename in po_filenames: with open(filename) as f: short_filename = get_po_filename_from_path(filename) logger.debug('\n--------- Processing [{}] ---------\n'.format( short_filename)) col_index = cls._get_column_index(first_row, short_filename) if col_index: catalog = read_po(f, charset=ENCODING) new_catalog = cls._process_catalog(ws, catalog, col_index) updated_catalogs.append(new_catalog) if output_dir: file_args = (os.path.join(output_dir, short_filename), 'w+') else: file_args = (filename, 'w+') if save: with open(*file_args) as nf: write_po(nf, new_catalog, width=None) return updated_catalogs
def run(self): mappings = self._get_mappings() outfile = open(self.output_file, 'wb') try: catalog = Catalog(project=self.distribution.get_name(), version=self.distribution.get_version(), msgid_bugs_address=self.msgid_bugs_address, copyright_holder=self.copyright_holder, charset=self.charset) for dirname, (method_map, options_map) in mappings.items(): def callback(filename, method, options): if method == 'ignore': return filepath = os.path.normpath(os.path.join(dirname, filename)) optstr = '' if options: optstr = ' (%s)' % ', '.join(['%s="%s"' % (k, v) for k, v in options.items()]) log.info('extracting messages from %s%s', filepath, optstr) extracted = extract_from_dir(dirname, method_map, options_map, keywords=self._keywords, comment_tags=self._add_comments, callback=callback, strip_comment_tags= self.strip_comments) for filename, lineno, message, comments in extracted: filepath = os.path.normpath(os.path.join(dirname, filename)) catalog.add(message, None, [(filepath, lineno)], auto_comments=comments) log.info('writing PO template file to %s' % self.output_file) write_po(outfile, catalog, width=self.width, no_location=self.no_location, omit_header=self.omit_header, sort_output=self.sort_output, sort_by_file=self.sort_by_file) finally: outfile.close()
def extract_messages(dirs): catalog = Catalog( project='Open Library', copyright_holder='Internet Archive' ) METHODS = [ ("**.py", "python"), ("**.html", "openlibrary.i18n:extract_templetor") ] COMMENT_TAGS = ["NOTE:"] for d in dirs: extracted = extract_from_dir(d, METHODS, comment_tags=COMMENT_TAGS, strip_comment_tags=True) for filename, lineno, message, comments in extracted: catalog.add(message, None, [(filename, lineno)], auto_comments=comments) path = os.path.join(root, 'messages.pot') f = open(path, 'w') write_po(f, catalog) f.close() print 'wrote template to', path
def _extract(self, app): catalog = Catalog(domain="django", charset="utf8") files = {} for dirpath, dirnames, filenames in filtered_walk(app.path): for filename in filenames: filename = os.path.join(dirpath, filename) if ACCEPTABLE_FILENAMES_RE.match(filename): rel_filename = filename[ len(os.path.commonprefix((app.path, filename))) + 1:].replace(os.sep, "/") files[rel_filename] = filename self.log.info("%s: %d translatable files found", app.label, len(files)) extractors = self.get_extractors() for rel_filename, filename in sorted(files.items()): extractor_tup = extractors.get(os.path.splitext(filename)[1]) if not extractor_tup: self.log.warning("Not sure how to extract messages from %s", filename) continue extractor, options = extractor_tup with open(filename, "rb") as fp: for (lineno, message, comments, context) in extract(extractor, fp, options=options): catalog.add(message, locations=[(rel_filename, 0)], auto_comments=comments) if len(catalog): pot_path = _get_pot_path(app) with open(pot_path, "w") as outf: pofile.write_po(outf, catalog, width=1000, omit_header=True, sort_output=True) self.log.info("%s: %d messages in %s", app.label, len(catalog), pot_path) return catalog
def update_language(lang): olang = find_language(lang) print("Updating language {0} ({1})".format(olang.name, olang.code)) print("Retrieving message catalog...") cat = get_message_catalog() if not os.path.exists(olang.po_file): print("No po file found.") else: print("Reading existing file {0}".format(olang.po_file)) with open(olang.po_file, 'r') as f: ocat = pofile.read_po(f) ocat.update(cat) cat = ocat print("Writing {0}".format(olang.po_file)) with open(olang.po_file, 'wb') as f: pofile.write_po(f, cat) print("Done.")
def _download_content(self, stat, values): # Ignore the header row. values.pop(0) babel_catalog = catalog.Catalog(stat.lang) for row in values: # Skip empty rows. if not row or self._is_empty_row(row): continue source = row[0] translation = row[1] if len(row) > 1 else None babel_catalog.add(source, translation, auto_comments=[], context=None, flags=[]) updated_stat = base.TranslatorStat( url=stat.url, lang=stat.lang, downloaded=datetime.datetime.now(), source_lang=stat.source_lang, ident=stat.ident) fp = io.BytesIO() pofile.write_po(fp, babel_catalog) fp.seek(0) content = fp.read() return updated_stat, content
def test_sorted_po(self): catalog = Catalog() catalog.add(u'bar', locations=[('utils.py', 3)], user_comments=['Comment About `bar` with', 'multiple lines.']) catalog.add((u'foo', u'foos'), (u'Voh', u'Voeh'), locations=[('main.py', 1)]) buf = BytesIO() pofile.write_po(buf, catalog, sort_output=True) value = buf.getvalue().strip() assert b'''\ # Comment About `bar` with # multiple lines. #: utils.py:3 msgid "bar" msgstr "" #: main.py:1 msgid "foo" msgid_plural "foos" msgstr[0] "Voh" msgstr[1] "Voeh"''' in value assert value.find(b'msgid ""') < value.find(b'msgid "bar"') < value.find(b'msgid "foo"')
def update_translations(locales: list[str]): locales_to_update = locales or get_locales() print(f"Updating {locales_to_update}") pot_path = os.path.join(root, 'messages.pot') template = read_po(open(pot_path, 'rb')) for locale in locales_to_update: po_path = os.path.join(root, locale, 'messages.po') mo_path = os.path.join(root, locale, 'messages.mo') if os.path.exists(po_path): catalog = read_po(open(po_path, 'rb')) catalog.update(template) f = open(po_path, 'wb') write_po(f, catalog) f.close() print('updated', po_path) else: print(f"ERROR: {po_path} does not exist...") compile_translations(locales_to_update)