Skip to content

Instantly share code, notes, and snippets.

@yoloseem
Last active December 21, 2015 04:39
Show Gist options
  • Save yoloseem/6251469 to your computer and use it in GitHub Desktop.
Save yoloseem/6251469 to your computer and use it in GitHub Desktop.
PO-to-JSON Distutils/Setuptools Command Integration
""" :mod:`po2json`
~~~~~~~~~~~~~~
Convert PO files to JSON-serialized files.
By Hyunjun Kim <[email protected]> for StyleShare.
Skeleton source code from `babel.messages.frontend.compile_catalog` that does compiling PO to MO files.
"""
try:
import omnijson as json
except ImportError:
import json
import os
from babel.messages.pofile import read_po
from distutils import log
from distutils.cmd import Command
from distutils.errors import DistutilsOptionError
class po2json(Command):
"""Catalog to-json conversion command for use in ``setup.py`` scripts. """
description = 'convert message catalogs to JSON-serialized format files'
user_options = [
('domain=', 'D',
"domain of PO file (default 'messages')"),
('input-dir=', None,
'path to base directory containing the catalogs'),
('input-file=', 'i',
'name of the input file'),
('output-dir=', None,
'path to base directory for creating output files'),
('output-file=', 'o',
"name of the output file (default "
"'<output_dir>/<locale>/LC_MESSAGES/<domain>.json')"),
('locale=', 'l',
'locale of the catalog to compile'),
('statistics', None,
'print statistics about translations')
]
boolean_options = ['statistics']
def initialize_options(self):
self.domain = 'messages'
self.input_dir = None
self.input_file = None
self.output_dir = None
self.output_file = None
self.locale = None
self.statistics = False
def finalize_options(self):
if not self.input_file and not self.input_dir:
raise DistutilsOptionError('you must specify either the input file '
'or the base directory')
if not self.output_file and not self.output_dir:
raise DistutilsOptionError('you must specify either the output file '
'or the base directory')
def run(self):
po_files = []
json_files = []
if not self.input_file:
if self.locale:
po_files.append((self.locale,
os.path.join(self.input_dir, 'LC_MESSAGES',
self.domain + '.po')))
json_files.append((self.locale,
os.path.join(self.output_dir,
self.locale,
'LC_MESSAGES',
self.domain + '.json')))
else:
for locale in os.listdir(self.input_dir):
po_file = os.path.join(self.input_dir, locale,
'LC_MESSAGES',
self.domain + '.po')
if os.path.exists(po_file):
po_files.append((locale, po_file))
json_files.append(os.path.join(self.output_dir,
locale,
'LC_MESSAGES',
self.domain + '.json'))
else:
po_files.append((self.locale, self.input_file))
if self.output_file:
json_files.append(self.output_file)
else:
json_files.append(os.path.join(self.output_dir,
self.locale,
'LC_MESSAGES',
self.domain + '.json'))
if not po_files:
raise DistutilsOptionError('no message catalogs found')
for idx, (locale, po_file) in enumerate(po_files):
json_file = json_files[idx]
with open(po_file, 'r') as infile:
catalog = read_po(infile, locale)
if self.statistics:
translated = 0
for message in list(catalog)[1:]:
if message.string:
translated += 1
percentage = 0
if len(catalog):
percentage = translated * 100 // len(catalog)
log.info("%d of %d messages (%d%%) translated in %r",
translated, len(catalog), percentage, po_file)
for message, errors in catalog.check():
for error in errors:
log.error('error: %s:%d: %s', po_file, message.lineno,
error)
log.info('compiling catalog %r to %r', po_file, json_file)
messages = {}
for message in catalog:
msgid = message.id
if isinstance(msgid, (list, tuple)):
msgid = msgid[0]
messages[msgid] = message.string
json_compiled = json.dumps({
'messages': messages,
'plural_expr': catalog.plural_expr,
'locale': str(locale),
'domain': self.domain,
})
if not os.path.exists(os.path.dirname(json_file)):
os.makedirs(os.path.dirname(json_file))
with open(json_file, 'wb') as outfile:
outfile.write(json_compiled)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment