cubicweb/i18n.py
changeset 11057 0b59724cb3f2
parent 10776 b1834143fec8
child 11767 432f87a63057
equal deleted inserted replaced
11052:058bb3dc685f 11057:0b59724cb3f2
       
     1 # copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
       
     2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
       
     3 #
       
     4 # This file is part of CubicWeb.
       
     5 #
       
     6 # CubicWeb is free software: you can redistribute it and/or modify it under the
       
     7 # terms of the GNU Lesser General Public License as published by the Free
       
     8 # Software Foundation, either version 2.1 of the License, or (at your option)
       
     9 # any later version.
       
    10 #
       
    11 # CubicWeb is distributed in the hope that it will be useful, but WITHOUT
       
    12 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
       
    13 # FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
       
    14 # details.
       
    15 #
       
    16 # You should have received a copy of the GNU Lesser General Public License along
       
    17 # with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
       
    18 """Some i18n/gettext utilities."""
       
    19 from __future__ import print_function
       
    20 
       
    21 __docformat__ = "restructuredtext en"
       
    22 
       
    23 import re
       
    24 import os
       
    25 from os.path import join, basename, splitext, exists
       
    26 from glob import glob
       
    27 
       
    28 from six import PY2
       
    29 
       
    30 from cubicweb.toolsutils import create_dir
       
    31 
       
    32 def extract_from_tal(files, output_file):
       
    33     """extract i18n strings from tal and write them into the given output file
       
    34     using standard python gettext marker (_)
       
    35     """
       
    36     output = open(output_file, 'w')
       
    37     for filepath in files:
       
    38         for match in re.finditer('i18n:(content|replace)="([^"]+)"', open(filepath).read()):
       
    39             output.write('_("%s")' % match.group(2))
       
    40     output.close()
       
    41 
       
    42 
       
    43 def add_msg(w, msgid, msgctx=None):
       
    44     """write an empty pot msgid definition"""
       
    45     if PY2 and isinstance(msgid, unicode):
       
    46         msgid = msgid.encode('utf-8')
       
    47     if msgctx:
       
    48         if PY2 and isinstance(msgctx, unicode):
       
    49             msgctx = msgctx.encode('utf-8')
       
    50         w('msgctxt "%s"\n' % msgctx)
       
    51     msgid = msgid.replace('"', r'\"').splitlines()
       
    52     if len(msgid) > 1:
       
    53         w('msgid ""\n')
       
    54         for line in msgid:
       
    55             w('"%s"' % line.replace('"', r'\"'))
       
    56     else:
       
    57         w('msgid "%s"\n' % msgid[0])
       
    58     w('msgstr ""\n\n')
       
    59 
       
    60 def execute2(args):
       
    61     # XXX replace this with check_output in Python 2.7
       
    62     from subprocess import Popen, PIPE, CalledProcessError
       
    63     p = Popen(args, stdout=PIPE, stderr=PIPE)
       
    64     out, err = p.communicate()
       
    65     if p.returncode != 0:
       
    66         exc = CalledProcessError(p.returncode, args[0])
       
    67         exc.cmd = args
       
    68         exc.data = (out, err)
       
    69         raise exc
       
    70 
       
    71 def available_catalogs(i18ndir=None):
       
    72     if i18ndir is None:
       
    73         wildcard = '*.po'
       
    74     else:
       
    75         wildcard = join(i18ndir, '*.po')
       
    76     for popath in glob(wildcard):
       
    77         lang = splitext(basename(popath))[0]
       
    78         yield lang, popath
       
    79 
       
    80 
       
    81 def compile_i18n_catalogs(sourcedirs, destdir, langs):
       
    82     """generate .mo files for a set of languages into the `destdir` i18n directory
       
    83     """
       
    84     from subprocess import CalledProcessError
       
    85     from logilab.common.fileutils import ensure_fs_mode
       
    86     print('-> compiling message catalogs to %s' % destdir)
       
    87     errors = []
       
    88     for lang in langs:
       
    89         langdir = join(destdir, lang, 'LC_MESSAGES')
       
    90         if not exists(langdir):
       
    91             create_dir(langdir)
       
    92         pofiles = [join(path, '%s.po' % lang) for path in sourcedirs]
       
    93         pofiles = [pof for pof in pofiles if exists(pof)]
       
    94         mergedpo = join(destdir, '%s_merged.po' % lang)
       
    95         try:
       
    96             # merge instance/cubes messages catalogs with the stdlib's one
       
    97             cmd = ['msgcat', '--use-first', '--sort-output', '--strict',
       
    98                    '-o', mergedpo] + pofiles
       
    99             execute2(cmd)
       
   100             # make sure the .mo file is writeable and compiles with *msgfmt*
       
   101             applmo = join(destdir, lang, 'LC_MESSAGES', 'cubicweb.mo')
       
   102             try:
       
   103                 ensure_fs_mode(applmo)
       
   104             except OSError:
       
   105                 pass # suppose not exists
       
   106             execute2(['msgfmt', mergedpo, '-o', applmo])
       
   107         except CalledProcessError as exc:
       
   108             errors.append(u'while handling language %s:\ncmd:\n%s\nstdout:\n%s\nstderr:\n%s\n' %
       
   109                           (lang, exc.cmd, repr(exc.data[0]), repr(exc.data[1])))
       
   110         except Exception as exc:
       
   111             errors.append(u'while handling language %s: %s' % (lang, exc))
       
   112         try:
       
   113             # clean everything
       
   114             os.unlink(mergedpo)
       
   115         except Exception:
       
   116             continue
       
   117     return errors