Skip to content
This repository has been archived by the owner on Apr 24, 2019. It is now read-only.

Commit

Permalink
Add i18nstats script.
Browse files Browse the repository at this point in the history
  • Loading branch information
strichter committed Feb 24, 2008
1 parent eb291e6 commit 280e8bd
Show file tree
Hide file tree
Showing 7 changed files with 234 additions and 3 deletions.
5 changes: 5 additions & 0 deletions CHANGES.txt
Expand Up @@ -8,6 +8,11 @@ After
BIG TODO: add tests for lovely.recipe.zeo and lovely.recipe.zope to test and
to show for what this all is for.

2008/02/24 0.3.1b2:
===================

- Added ``i18nstats`` as an additional script.

2007/09/21 0.3.1b1:
===================

Expand Down
1 change: 0 additions & 1 deletion buildout.cfg
Expand Up @@ -2,7 +2,6 @@
develop = .
parts = test

find-links = http://download.zope.org/distribution

[test]
recipe = zc.recipe.testrunner
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Expand Up @@ -13,7 +13,7 @@

setup (
name='lovely.recipe',
version='0.3.1b1',
version='0.3.1b2',
author = "Lovely Systems",
author_email = "office@lovelysystems.com",
license = "ZPL 2.1",
Expand Down
23 changes: 22 additions & 1 deletion src/lovely/recipe/i18n/README.txt
Expand Up @@ -12,7 +12,7 @@ Creating The Tools
... """
... [buildout]
... parts = i18n
...
... index = http://download.zope.org/zope3.4
... offline = true
...
... [i18n]
Expand All @@ -28,12 +28,14 @@ Creating The Tools
i18n: setting up i18n tools
Generated script 'bin/i18nextract'.
Generated script 'bin/i18nmergeall'.
Generated script 'bin/i18nstats'.

>>> import os
>>> ls(os.path.join(sample_buildout, 'bin'))
- buildout
- i18nextract
- i18nmergeall
- i18nstats


The i18n Extractor
Expand Down Expand Up @@ -76,6 +78,22 @@ i18n Merge
if __name__ == '__main__':
lovely.recipe.i18n.i18nmergeall.main(['i18nmergeall', '-l', 'src/somewhere/locales'])

i18n Stats
----------

>>> cat('bin', 'i18nstats')
#!...
<BLANKLINE>
import sys
sys.path[0:0] = [
...
]
<BLANKLINE>
import lovely.recipe.i18n.i18nstats
<BLANKLINE>
if __name__ == '__main__':
lovely.recipe.i18n.i18nstats.main(['i18nstats', '-l', 'src/somewhere/locales'])


Tool Names
----------
Expand All @@ -87,6 +105,7 @@ and 'translationmergeall'.
>>> write(sample_buildout, 'buildout.cfg',
... """
... [buildout]
... index = http://download.zope.org/zope3.4
... parts = translation
...
... offline = true
Expand All @@ -105,6 +124,7 @@ and 'translationmergeall'.
translation: setting up i18n tools
Generated script 'bin/translationextract'.
Generated script 'bin/translationmergeall'.
Generated script 'bin/translationstats'.


Adding a custom configure.zcml
Expand Down Expand Up @@ -141,6 +161,7 @@ of the generated configure.zcml.
i18n: setting up i18n tools
Generated script 'bin/i18nextract'.
Generated script 'bin/i18nmergeall'.
Generated script 'bin/i18nstats'.

>>> cat('bin', 'i18nextract')
#!...
Expand Down
22 changes: 22 additions & 0 deletions src/lovely/recipe/i18n/i18n.py
Expand Up @@ -61,6 +61,8 @@ def install(self):
zcmlFilename = os.path.join(partsDir, 'configure.zcml')
file(zcmlFilename, 'w').write(zcml)

# Generate i18nextract

arguments = ['%sextract'% self.name,
'-d', self.options.get('domain', package),
'-s', zcmlFilename,
Expand All @@ -70,13 +72,16 @@ def install(self):
makers = [m for m in self.options.get('maker', '').split() if m!='']
for m in makers:
arguments.extend(['-m', m])

generated = zc.buildout.easy_install.scripts(
[('%sextract'% self.name, 'lovely.recipe.i18n.i18nextract', 'main')],
ws, self.options['executable'], 'bin',
extra_paths = [this_loc],
arguments = arguments,
)

# Generate i18nmergeall

arguments = ['%smergeall'% self.name,
'-l', os.path.join(self.options['location'],
self.options.get('output', 'locales'),
Expand All @@ -92,6 +97,23 @@ def install(self):
arguments = arguments,
))

# Generate i18nstats

arguments = ['%sstats'% self.name,
'-l', os.path.join(self.options['location'],
self.options.get('output', 'locales'),
),
]
generated.extend(
zc.buildout.easy_install.scripts(
[('%sstats'% self.name,
'lovely.recipe.i18n.i18nstats',
'main')],
ws, self.options['executable'], 'bin',
extra_paths = [this_loc],
arguments = arguments,
))

return generated


Expand Down
167 changes: 167 additions & 0 deletions src/lovely/recipe/i18n/i18nstats.py
@@ -0,0 +1,167 @@
#!/usr/bin/env python2.4
##############################################################################
#
# Copyright (c) 2004 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Translation Statistics Utility
Utility to determine the status of the translations.
Usage: i18nstats.py [options]
Options:
-h / --help
Print this message and exit.
-l / --locales-dir
Specify the 'locales' directory for which to generate the statistics.
$Id$
"""
import sys
import os
import getopt

SEARCHING = 0
COMMENT = 1
MSGID = 2
MSGSTR = 3
MSGDONE = 4

def usage(code, msg=''):
"""Display help."""
print >> sys.stderr, '\n'.join(__doc__.split('\n')[:-2])
if msg:
print >> sys.stderr, '** Error: ' + str(msg) + ' **'
sys.exit(code)


def getMessageDictionary(file):
"""Simple state machine."""

msgs = []
comment = []
msgid = []
msgstr = []
fuzzy = False
line_counter = 0
status = SEARCHING

for line in file.readlines():
line = line.strip('\n')
line_counter += 1

# Handle Events
if line.startswith('#'):
status = COMMENT

elif line.startswith('msgid'):
line = line[6:]
line_number = line_counter
status = MSGID

elif line.startswith('msgstr'):
line = line[7:]
status = MSGSTR

elif line == '':
status = MSGDONE

# Actions based on status
if status == MSGID:
msgid.append(line.strip('"'))

elif status == MSGSTR:
msgstr.append(line.strip('"'))

elif status == COMMENT:
if line.startswith('#, fuzzy'):
fuzzy = True
comment.append(line[1:].strip())

elif status == MSGDONE:
status = SEARCHING
# Avoid getting the meta-data message string
if ''.join(msgid):
msgs.append( (''.join(msgid), ''.join(msgstr),
line_number, '\n'.join(comment), fuzzy) )
comment = []
msgid = []
msgstr = []
fuzzy = False

return msgs


def main(path):
print 'Language Total Done Not Done Fuzzy Done %'
print '=========================================================='
languages = os.listdir(path)
languages.sort()
for language in languages:
lc_messages_path = os.path.join(path, language, 'LC_MESSAGES')

# Make sure we got a language directory
if not os.path.isdir(lc_messages_path):
continue

msgs = []
for domain_file in os.listdir(lc_messages_path):
if domain_file.endswith('.po'):
domain_path = os.path.join(lc_messages_path, domain_file)
file = open(domain_path, mode='r')
msgs += getMessageDictionary(file)

# We are dealing with the default language, which always has just one
# message string for the meta data (which is not recorded).
if len(msgs) == 0:
continue

total = len(msgs)
not_done = len([msg for msg in msgs if msg[1] == ''])
fuzzy = len([msg for msg in msgs if msg[4] is True])
done = total - not_done - fuzzy
percent_done = 100.0 * done/total

line = language + ' '*(8-len(language))
line += ' '*(9-len(str(total))) + str(total)
line += ' '*(8-len(str(done))) + str(done)
line += ' '*(12-len(str(not_done))) + str(not_done)
line += ' '*(9-len(str(fuzzy))) + str(fuzzy)
pd_str = '%0.2f %%' %percent_done
line += ' '*(12-len(pd_str)) + pd_str
print line


if __name__ == '__main__':
try:
opts, args = getopt.getopt(
sys.argv[1:],
'l:h',
['help', 'locals-dir='])
except getopt.error, msg:
usage(1, msg)

path = None
for opt, arg in opts:
if opt in ('-h', '--help'):
usage(0)
elif opt in ('-l', '--locales-dir'):
cwd = os.getcwd()
# This is for symlinks. Thanks to Fred for this trick.
if os.environ.has_key('PWD'):
cwd = os.environ['PWD']
path = os.path.normpath(os.path.join(cwd, arg))

if path is None:
usage(1, 'You must specify the path to the locales directory.')
main(path)
17 changes: 17 additions & 0 deletions src/lovely/recipe/testing.py
Expand Up @@ -8,6 +8,7 @@ def setUpBuildout(test):
testing.install_develop('zc.zope3recipes', test)
testing.install_develop('lovely.recipe', test)
testing.install_develop('ZODB3', test)
testing.install_develop('docutils', test)
testing.install_develop('zodbcode', test)
testing.install_develop('pytz', test)
testing.install_develop('RestrictedPython', test)
Expand All @@ -21,6 +22,7 @@ def setUpBuildout(test):
testing.install_develop('zope.copypastemove', test)
testing.install_develop('zope.deprecation', test)
testing.install_develop('zope.dublincore', test)
testing.install_develop('zope.error', test)
testing.install_develop('zope.filerepresentation', test)
testing.install_develop('zope.formlib', test)
testing.install_develop('zope.interface', test)
Expand All @@ -33,14 +35,17 @@ def setUpBuildout(test):
testing.install_develop('zope.exceptions', test)
testing.install_develop('zope.hookable', test)
testing.install_develop('zope.minmax', test)
testing.install_develop('zope.modulealias', test)
testing.install_develop('zope.pagetemplate', test)
testing.install_develop('zope.proxy', test)
testing.install_develop('zope.publisher', test)
testing.install_develop('zope.size', test)
testing.install_develop('zope.security', test)
testing.install_develop('zope.session', test)
testing.install_develop('zope.lifecycleevent', test)
testing.install_develop('zope.location', test)
testing.install_develop('zope.schema', test)
testing.install_develop('zope.structuredtext', test)
testing.install_develop('zope.tal', test)
testing.install_develop('zope.tales', test)
testing.install_develop('zope.testing', test)
Expand All @@ -52,19 +57,31 @@ def setUpBuildout(test):
testing.install_develop('zope.app.basicskin', test)
testing.install_develop('zope.app.broken', test)
testing.install_develop('zope.app.container', test)
testing.install_develop('zope.app.content', test)
testing.install_develop('zope.app.component', test)
testing.install_develop('zope.app.debug', test)
testing.install_develop('zope.app.dependable', test)
testing.install_develop('zope.app.error', test)
testing.install_develop('zope.app.exception', test)
testing.install_develop('zope.app.folder', test)
testing.install_develop('zope.app.form', test)
testing.install_develop('zope.app.generations', test)
testing.install_develop('zope.app.http', test)
testing.install_develop('zope.app.i18n', test)
testing.install_develop('zope.app.interface', test)
testing.install_develop('zope.app.locales', test)
testing.install_develop('zope.app.pagetemplate', test)
testing.install_develop('zope.app.principalannotation', test)
testing.install_develop('zope.app.publication', test)
testing.install_develop('zope.app.publisher', test)
testing.install_develop('zope.app.renderer', test)
testing.install_develop('zope.app.rotterdam', test)
testing.install_develop('zope.app.schema', test)
testing.install_develop('zope.app.security', test)
testing.install_develop('zope.app.session', test)
testing.install_develop('zope.app.testing', test)
testing.install_develop('zope.app.wsgi', test)
testing.install_develop('zope.app.zapi', test)
testing.install_develop('zope.app.zcmlfiles', test)
testing.install_develop('zope.app.zopeappgenerations', test)

0 comments on commit 280e8bd

Please sign in to comment.