Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/build/multilocale.py
diff options
context:
space:
mode:
Diffstat (limited to 'build/multilocale.py')
-rw-r--r--build/multilocale.py248
1 files changed, 248 insertions, 0 deletions
diff --git a/build/multilocale.py b/build/multilocale.py
new file mode 100644
index 0000000..60387b3
--- /dev/null
+++ b/build/multilocale.py
@@ -0,0 +1,248 @@
+#!/usr/bin/env python
+
+import os
+import shutil
+import fnmatch
+import json
+import re
+from optparse import OptionParser
+import logging
+
+section_line = re.compile('\[(?P<section>.*)\]')
+import_line = re.compile('@import url\((?P<filename>.*)\)')
+property_line = re.compile('(?P<id>.*)\s*[:=]\s*(?P<value>.*)')
+
+def _get_locales(filename):
+ locales_list = json.load(open(filename), encoding="utf-8")
+ return locales_list.keys()
+
+
+def find_files(dirs, pattern):
+ matches = []
+ for dir in dirs:
+ for current, dirnames, filenames in os.walk(dir):
+ for filename in fnmatch.filter(filenames, pattern):
+ matches.append(os.path.join(current, filename))
+ return matches
+
+
+def parse_manifest_properties(filename):
+ with open(filename) as f:
+ data = f.readlines()
+ strings = {
+ "default": {},
+ "entry_points": {},
+ }
+ for line in data:
+ m = property_line.search(line)
+ if not m or line.strip().startswith('#'):
+ continue
+ value = m.group('value').strip()
+ if '.' in m.group('id'):
+ entry_point, key = m.group('id').split('.',1)
+ if entry_point not in strings["entry_points"]:
+ strings["entry_points"][entry_point] = {}
+ strings["entry_points"][entry_point][key.strip()] = value
+ else:
+ key = m.group('id')
+ strings["default"][key.strip()] = value
+ return strings
+
+
+def parse_ini(filename):
+ log = logging.getLogger(__name__)
+ with open(filename) as f:
+ data = f.readlines()
+ section = 'default'
+ imports = { section: [] }
+ for line in data:
+ if line.strip() == "" or line.startswith('!') or line.startswith('#'):
+ continue
+ elif line.strip().startswith('['): # Section header
+ section = section_line.search(line).group('section')
+ imports[section] = []
+ elif '@import' in line: # Import lines
+ property_file = import_line.search(line).group('filename')
+ imports[section].append(property_file)
+ else:
+ log.warn('parse_ini - found a line with contents '
+ 'unaccounted for "%s"', line.strip())
+ return imports
+
+
+def serialize_ini(outfile, imports):
+ def _section(locale):
+ return "[%s]" % locale
+ def _import(path):
+ return "@import url(%s)" % path
+ output = []
+ for locale, paths in imports.items():
+ if locale == "default":
+ for path in paths:
+ output.insert(0, _import(path))
+ continue
+ output.append(_section(locale))
+ for path in paths:
+ output.append(_import(path))
+ with open(outfile, 'w') as o:
+ o.write("\n".join(output))
+
+
+def add_locale_imports(locales, ini_file):
+ """Recreate an ini file with all locales sections"""
+ log = logging.getLogger(__name__)
+ imports = {
+ "default": parse_ini(ini_file)["default"]
+ }
+ for locale in locales:
+ log.info("adding %s to %s" % (locale, ini_file))
+ imports[locale] = []
+ for path in imports["default"]:
+ locale_path = path.replace("en-US", locale)
+ imports[locale].append(locale_path)
+ log.debug("added %s" % locale_path)
+ serialize_ini(ini_file, imports)
+ log.info("updated %s saved" % ini_file)
+
+
+def copy_properties(source, locales, ini_file):
+ log = logging.getLogger(__name__)
+ ini_dirname = os.path.dirname(ini_file)
+ imports = parse_ini(ini_file)
+ for locale in locales:
+ log.info("copying %s files as per %s" % (locale, ini_file))
+ for path in imports[locale]:
+ target_path = os.path.join(ini_dirname, path)
+ # apps/browser/locales/browser.fr.properties becomes
+ # apps/browser/browser.properties
+ source_path = target_path.replace('/locales', '') \
+ .replace('.%s' % locale, '')
+ source_path = os.path.join(source, locale, source_path)
+ if not os.path.exists(source_path):
+ log.warn('%s does not exist' % source_path)
+ continue
+ shutil.copy(source_path, target_path)
+ log.debug("copied %s to %s" % (source_path, target_path))
+
+
+def add_locale_manifest(source, locales, manifest_file):
+ log = logging.getLogger(__name__)
+ with open(manifest_file) as f:
+ manifest = json.load(f, encoding="utf-8")
+ for locale in locales:
+ log.info("adding %s to %s" % (locale, manifest_file))
+ manifest_properties = os.path.join(source, locale,
+ os.path.dirname(manifest_file),
+ 'manifest.properties')
+ log.debug("getting strings from %s" % manifest_properties)
+ if not os.path.exists(manifest_properties):
+ log.warn("%s does not exist" % manifest_properties)
+ continue
+ strings = parse_manifest_properties(manifest_properties)
+ if "entry_points" in manifest:
+ for name, ep in manifest["entry_points"].items():
+ if "locales" not in ep:
+ continue
+ log.debug("adding to entry_points.%s.locales" % name)
+ if name not in strings["entry_points"]:
+ log.warn("%s.* strings are missing from %s" %
+ (name, manifest_properties))
+ continue
+ ep["locales"][locale] = {}
+ ep["locales"][locale].update(strings["entry_points"][name])
+ if "locales" in manifest:
+ log.debug("adding to locales")
+ manifest["locales"][locale] = {}
+ manifest["locales"][locale].update(strings["default"])
+ f.close()
+ with open(manifest_file, 'w') as o:
+ json.dump(manifest, o, encoding="utf-8", indent=2)
+ log.debug("updated %s saved" % manifest_file)
+
+
+def setup_logging(volume=1, console=True, filename=None):
+ logger = logging.getLogger(__name__)
+ levels = [logging.DEBUG,
+ logging.INFO,
+ logging.WARNING,
+ logging.ERROR,
+ logging.CRITICAL][::1]
+ if volume > len(levels):
+ volume = len(levels) - 1
+ elif volume < 0:
+ volume = 0
+ logger.setLevel(levels[len(levels)-volume])
+ if console:
+ console_handler = logging.StreamHandler()
+ console_formatter = logging.Formatter('%(levelname)s: %(message)s')
+ console_handler.setFormatter(console_formatter)
+ logger.addHandler(console_handler)
+ if filename:
+ file_handler = logging.FileHandler(filename)
+ file_formatter = logging.Formatter('%(asctime) - %(levelname)s: %(message)s')
+ file_handler.addFormatter(file_formatter)
+ logger.addHandler(file_handler)
+
+
+def main():
+ parser = OptionParser("%prog [OPTIONS] [LOCALES...] - create multilocale Gaia")
+ parser.add_option("-v", "--verbose",
+ action="count", dest="verbose", default=2,
+ help="use more to make louder")
+ parser.add_option("-i", "--ini",
+ action="store_true", dest="onlyini", default=False,
+ help=("just edit the ini files and exit; "
+ "use this with DEBUG=1 make profile"))
+ parser.add_option("--target",
+ action="append", dest="target",
+ help=("path to directory to make changes in "
+ "(more than one is fine)"))
+ parser.add_option("--source",
+ action="store", dest="source",
+ help="path to the l10n basedir")
+ parser.add_option("--config",
+ action="store", dest="config_file",
+ help=("path to the languages.json config file; "
+ "will be used instead of LOCALES"))
+
+ options, locales = parser.parse_args()
+
+ setup_logging(volume=options.verbose)
+ log = logging.getLogger(__name__)
+
+ if options.config_file is not None:
+ locales = _get_locales(options.config_file)
+ log.debug("config file specified; ignoring any locales passed as args")
+ elif len(locales) == 0:
+ parser.error("You need to specify --config or pass the list of locales")
+ if options.target is None:
+ parser.error("You need to specify at least one --target")
+ if options.source is None and not options.onlyini:
+ parser.error("You need to specify --source (unless you meant --ini)")
+
+ if "en-US" in locales:
+ locales.remove("en-US")
+ ini_files = find_files(options.target, "*.ini")
+
+ # 1. link properties files from the inis
+ for ini_file in ini_files:
+ log.info("########## adding locale import rules to %s" % ini_file)
+ add_locale_imports(locales, ini_file)
+
+ if options.onlyini:
+ parser.exit(1)
+
+ # 2. copy properties files as per the inis
+ for ini_file in ini_files:
+ log.info("########## copying locale files as per %s" % ini_file)
+ copy_properties(options.source, locales, ini_file)
+
+ # 3. edit manifests
+ manifest_files = find_files(options.target, 'manifest.webapp')
+ for manifest_file in manifest_files:
+ log.info("########## adding localized names to %s" % manifest_file)
+ add_locale_manifest(options.source, locales, manifest_file)
+
+
+if __name__ == "__main__":
+ main()