From c00d71d422c27e84992b2eb157941b3375b44951 Mon Sep 17 00:00:00 2001
From: Steve Strassmann <steve@strassmann.com>
Date: Mon, 29 Apr 2013 11:32:22 -0400
Subject: [PATCH] integrate dummy string tools; added rake tasks and unit tests

---
 i18n/dummy.py         |   6 +--
 i18n/make_dummy.py    |  49 +++++++++----------
 i18n/test/__init__.py |   2 +
 i18n/update.py        | 110 ------------------------------------------
 rakefile              |  10 ++++
 requirements.txt      |   5 +-
 6 files changed, 43 insertions(+), 139 deletions(-)
 delete mode 100755 i18n/update.py

diff --git a/i18n/dummy.py b/i18n/dummy.py
index 798ee525b5d..78bfdc3b58f 100644
--- a/i18n/dummy.py
+++ b/i18n/dummy.py
@@ -86,7 +86,7 @@ class Dummy (Converter):
     def init_msgs(self, msgs):
         """
         Make sure the first msg in msgs has a plural property.
-        msgs is list of instances of pofile.Msg
+        msgs is list of instances of polib.POEntry
         """
         if len(msgs)==0:
             return
@@ -100,8 +100,8 @@ class Dummy (Converter):
 
     def convert_msg(self, msg):
         """
-        Takes one Msg object and converts it (adds a dummy translation to it)
-        msg is an instance of pofile.Msg
+        Takes one POEntry object and converts it (adds a dummy translation to it)
+        msg is an instance of polib.POEntry
         """
         source = msg.msgid
         if len(source)==0:
diff --git a/i18n/make_dummy.py b/i18n/make_dummy.py
index 4ccfb0d5f17..c8dcde861a7 100755
--- a/i18n/make_dummy.py
+++ b/i18n/make_dummy.py
@@ -18,20 +18,12 @@
 import os, sys
 import polib
 from dummy import Dummy
+from execute import create_dir_if_necessary
 
-# Dummy language 
-# two letter language codes reference:
-# see http://www.loc.gov/standards/iso639-2/php/code_list.php
-#
-# Django will not localize in languages that django itself has not been
-# localized for. So we are using a well-known language: 'fr'.
-
-OUT_LANG = 'fr'
-
-def main(file):
+def main(file, locale):
     """
     Takes a source po file, reads it, and writes out a new po file
-    containing a dummy translation.
+    in :param locale: containing a dummy translation.
     """
     if not os.path.exists(file):
         raise IOError('File does not exist: %s' % file)
@@ -40,29 +32,36 @@ def main(file):
     converter.init_msgs(pofile.translated_entries())
     for msg in pofile:
         converter.convert_msg(msg)
-    new_file = new_filename(file, OUT_LANG)
+    new_file = new_filename(file, locale)
     create_dir_if_necessary(new_file)
     pofile.save(new_file)
-    
-
 
-def new_filename(original_filename, new_lang):
-    """Returns a filename derived from original_filename, using new_lang as the locale"""
+def new_filename(original_filename, new_locale):
+    """Returns a filename derived from original_filename, using new_locale as the locale"""
     orig_dir = os.path.dirname(original_filename)
     msgs_dir = os.path.basename(orig_dir)
     orig_file = os.path.basename(original_filename)
-    return '%s/%s/%s/%s' % (os.path.abspath(orig_dir + '/../..'),
-                            new_lang,
-                            msgs_dir,
-                            orig_file)
+    return os.path.join(orig_dir,
+                        '/../..',
+                        new_locale,
+                        msgs_dir,
+                        orig_file)
 
 
-def create_dir_if_necessary(pathname):
-    dirname = os.path.dirname(pathname)
-    if not os.path.exists(dirname):
-        os.makedirs(dirname)
+# Dummy language 
+# two letter language codes reference:
+# see http://www.loc.gov/standards/iso639-2/php/code_list.php
+#
+# Django will not localize in languages that django itself has not been
+# localized for. So we are using a well-known language: 'fr'.
+
+DEFAULT_LOCALE = 'fr'
 
 if __name__ == '__main__':
     if len(sys.argv)<2:
         raise Exception("missing file argument")
-    main(sys.argv[1])
+    if len(sys.argv)<2:
+        locale = DEFAULT_LOCALE
+    else:
+        locale = sys.argv[2]
+    main(sys.argv[1], locale)
diff --git a/i18n/test/__init__.py b/i18n/test/__init__.py
index 65100a18d99..d60515c7125 100644
--- a/i18n/test/__init__.py
+++ b/i18n/test/__init__.py
@@ -1,2 +1,4 @@
 from test_extract import TestExtract
 from test_generate import TestGenerate
+from test_converter import TestConverter
+from test_dummy import TestDummy
diff --git a/i18n/update.py b/i18n/update.py
deleted file mode 100755
index 447dcf71d5a..00000000000
--- a/i18n/update.py
+++ /dev/null
@@ -1,110 +0,0 @@
-#!/usr/bin/python
-
-import os, subprocess, logging, json
-from make_dummy import create_dir_if_necessary, main as dummy_main
-
-'''
-Generate or update all translation files
- Usage:
-    $ update.py
-
-
- 1. extracts files from mako templates
- 2. extracts files from django templates and python source files
- 3. extracts files from django javascript files
- 4. generates dummy text translations
- 5. compiles po files to mo files
-
- Configuration (e.g. known languages) declared in mitx/conf/locale/config
-'''
-
-# -----------------------------------
-# BASE_DIR is the working directory to execute django-admin commands from.
-# Typically this should be the 'mitx' directory.
-BASE_DIR = os.path.abspath(os.path.dirname(os.path.abspath(__file__))+'/..')
-
-# LOCALE_DIR contains the locale files.
-# Typically this should be 'mitx/conf/locale'
-LOCALE_DIR = BASE_DIR + '/conf/locale'
-
-# MSGS_DIR contains the English po files
-MSGS_DIR = LOCALE_DIR + '/en/LC_MESSAGES'
-
-# CONFIG_FILENAME contains localization configuration in json format
-CONFIG_FILENAME = LOCALE_DIR + '/config'
-
-# BABEL_CONFIG contains declarations for Babel to extract strings from mako template files
-BABEL_CONFIG = LOCALE_DIR + '/babel.cfg'
-
-# Strings from mako template files are written to BABEL_OUT
-BABEL_OUT = MSGS_DIR + '/mako.po'
-
-# These are the shell commands invoked by main()
-COMMANDS = {
-    'babel_mako': 'pybabel extract -F %s -c "TRANSLATORS:" . -o %s' % (BABEL_CONFIG, BABEL_OUT),
-    'make_django': 'django-admin.py makemessages --all --ignore=src/* --extension html -l en',
-    'make_djangojs': 'django-admin.py makemessages --all -d djangojs --ignore=src/* --extension js -l en',
-    'msgcat' : 'msgcat -o merged.po django.po %s' % BABEL_OUT,
-    'rename_django' : 'mv django.po django_old.po',
-    'rename_merged' : 'mv merged.po django.po',
-    'compile': 'django-admin.py compilemessages'
-    
-    }
-
-def execute (command_kwd, log, working_directory=BASE_DIR):
-    '''
-    Executes command_kwd, which references a shell command in COMMANDS.
-    '''
-    full_cmd = COMMANDS[command_kwd]
-    log.info('%s' % full_cmd)
-    subprocess.call(full_cmd.split(' '), cwd=working_directory)
-    
-def make_log ():
-    '''returns a logger'''
-    log = logging.getLogger(__name__)
-    log.setLevel(logging.INFO)
-    log_handler = logging.StreamHandler()
-    log_handler.setFormatter(logging.Formatter('%(asctime)s [%(levelname)s] %(message)s'))
-    log.addHandler(log_handler)
-    return log
-
-def get_config ():
-    '''Returns data found in config file, or returns None if file not found'''
-    config_path = os.path.abspath(CONFIG_FILENAME)
-    if not os.path.exists(config_path):
-        return None
-    with open(config_path) as stream:
-        return json.load(stream)
-
-def main ():
-    log = make_log()
-    create_dir_if_necessary(LOCALE_DIR)
-    log.info('Executing all commands from %s' % BASE_DIR)
-
-    remove_files = ['django.po', 'djangojs.po', 'nonesuch']
-    for filename in remove_files:
-        path = MSGS_DIR + '/' + filename
-        log.info('Deleting file %s' % path)
-        if not os.path.exists(path):
-            log.warn("File does not exist: %s" % path)
-        else:
-            os.remove(path)
-
-    # Generate or update human-readable .po files from all source code.
-    execute('babel_mako', log=log)
-    execute('make_django', log=log)
-    execute('make_djangojs', log=log)
-    execute('msgcat', log=log, working_directory=MSGS_DIR)
-    execute('rename_django', log=log, working_directory=MSGS_DIR)
-    execute('rename_merged', log=log, working_directory=MSGS_DIR)
-
-    # Generate dummy text files from the English .po files
-    log.info('Generating dummy text.')
-    dummy_main(LOCALE_DIR + '/en/LC_MESSAGES/django.po')
-    dummy_main(LOCALE_DIR + '/en/LC_MESSAGES/djangojs.po')
-
-    # Generate machine-readable .mo files
-    execute('compile', log)
-
-if __name__ == '__main__':
-    main()
diff --git a/rakefile b/rakefile
index 537a081471b..61fc1b26980 100644
--- a/rakefile
+++ b/rakefile
@@ -516,6 +516,16 @@ task :generate_i18n do
   sh(File.join(REPO_ROOT, "i18n", "generate.py"))
 end
 
+desc "Simulate international translation by generating dummy strings corresponding to source strings."
+task :dummy_i18n do
+  source_files = Dir["#{REPO_ROOT}/conf/locale/en/LC_MESSAGES/*.po"]
+  dummy_locale = 'fr'
+  cmd = File.join(REPO_ROOT, "i18n", "make_dummy.py")
+  for file in source_files do
+    sh("#{cmd} #{file} #{dummy_locale}")
+  end
+end
+
 # --- Develop and public documentation ---
 desc "Invoke sphinx 'make build' to generate docs."
 task :builddocs, [:options] do |t, args|
diff --git a/requirements.txt b/requirements.txt
index 77239a4d502..d3fdd46b816 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,5 +1,4 @@
 -r repo-requirements.txt
-Babel==0.9.6
 beautifulsoup4==4.1.3
 beautifulsoup==3.2.1
 boto==2.6.0
@@ -62,6 +61,10 @@ newrelic==1.8.0.13
 # Used for documentation gathering
 sphinx==1.1.3
 
+# Used for Internationalization and localization
+Babel==0.9.6
+transifex-client==0.8
+
 # Used for testing
 coverage==3.6
 factory_boy==2.0.2
-- 
GitLab