summaryrefslogtreecommitdiff
path: root/sphinx/util/i18n.py
blob: 8e61c12b1a74ba9af9d26c8f01c1759ab8514181 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# -*- coding: utf-8 -*-
"""
    sphinx.util.i18n
    ~~~~~~~~~~~~~~~~

    Builder superclass for all builders.

    :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
    :license: BSD, see LICENSE for details.
"""

from os import path
from collections import namedtuple

from babel.messages.pofile import read_po
from babel.messages.mofile import write_mo

from sphinx.util.osutil import walk


LocaleFileInfoBase = namedtuple('CatalogInfo', 'base_dir,domain')


class CatalogInfo(LocaleFileInfoBase):

    @property
    def po_file(self):
        return self.domain + '.po'

    @property
    def mo_file(self):
        return self.domain + '.mo'

    @property
    def po_path(self):
        return path.join(self.base_dir, self.po_file)

    @property
    def mo_path(self):
        return path.join(self.base_dir, self.mo_file)

    def is_outdated(self):
        return (
            not path.exists(self.mo_path) or
            path.getmtime(self.mo_path) < path.getmtime(self.po_path))

    def write_mo(self, locale):
        with open(self.po_path, 'rt') as po:
            with open(self.mo_path, 'wb') as mo:
                write_mo(mo, read_po(po, locale))


def get_catalogs(locale_dirs, locale, gettext_compact=False, force_all=False):
    """
    :param list locale_dirs:
       list of path as `['locale_dir1', 'locale_dir2', ...]` to find
       translation catalogs. Each path contains a structure such as
       `<locale>/LC_MESSAGES/domain.po`.
    :param str locale: a language as `'en'`
    :param boolean gettext_compact:
       * False: keep domains directory structure (default).
       * True: domains in the sub directory will be merged into 1 file.
    :param boolean force_all:
       Set True if you want to get all catalogs rather than updated catalogs.
       default is False.
    :return: [CatalogInfo(), ...]
    """
    if not locale:
        return []  # locale is not specified

    catalogs = set()
    for locale_dir in locale_dirs:
        base_dir = path.join(locale_dir, locale, 'LC_MESSAGES')

        if not path.exists(base_dir):
            continue  # locale path is not found

        for dirpath, dirnames, filenames in walk(base_dir, followlinks=True):
            filenames = [f for f in filenames if f.endswith('.po')]
            for filename in filenames:
                base = path.splitext(filename)[0]
                domain = path.relpath(path.join(dirpath, base), base_dir)
                if gettext_compact and path.sep in domain:
                    domain = path.split(domain)[0]
                cat = CatalogInfo(base_dir, domain)
                if force_all or cat.is_outdated():
                    catalogs.add(cat)

    return catalogs