• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

zopefoundation / zope.i18n / 16399678496

27 Sep 2024 06:55AM UTC coverage: 98.997% (-0.02%) from 99.018%
16399678496

push

github

icemac
Back to development: 5.3

747 of 784 branches covered (95.28%)

Branch coverage included in aggregate %.

3203 of 3206 relevant lines covered (99.91%)

1.0 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.78
/src/zope/i18n/zcml.py
1
# ##############################################################################
2
#
3
# Copyright (c) 2001, 2002 Zope Foundation and Contributors.
4
# All Rights Reserved.
5
#
6
# This software is subject to the provisions of the Zope Public License,
7
# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
8
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
9
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
10
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
11
# FOR A PARTICULAR PURPOSE.
12
#
13
##############################################################################
14
"""This module handles the 'i18n' namespace directives.
15
"""
16
__docformat__ = 'restructuredtext'
1✔
17

18
import logging
1✔
19
import os
1✔
20
from glob import glob
1✔
21

22
from zope.component import getSiteManager
1✔
23
from zope.component import queryUtility
1✔
24
from zope.component.interface import provideInterface
1✔
25
from zope.configuration.fields import Path
1✔
26
from zope.interface import Interface
1✔
27
from zope.schema import TextLine
1✔
28

29
from zope.i18n import config
1✔
30
from zope.i18n.compile import compile_mo_file
1✔
31
from zope.i18n.gettextmessagecatalog import GettextMessageCatalog
1✔
32
from zope.i18n.interfaces import ITranslationDomain
1✔
33
from zope.i18n.testmessagecatalog import TestMessageCatalog
1✔
34
from zope.i18n.translationdomain import TranslationDomain
1✔
35

36

37
logger = logging.getLogger("zope.i18n")
1✔
38

39

40
class IRegisterTranslationsDirective(Interface):
1✔
41
    """Register translations with the global site manager."""
42

43
    directory = Path(
1✔
44
        title="Directory",
45
        description="Directory containing the translations",
46
        required=True
47
    )
48

49
    domain = TextLine(
1✔
50
        title="Domain",
51
        description=("Translation domain to register.  If not specified, "
52
                     "all domains found in the directory are registered"),
53
        required=False
54
    )
55

56

57
def allow_language(lang):
1✔
58
    if config.ALLOWED_LANGUAGES is None:
1✔
59
        return True
1✔
60
    return lang in config.ALLOWED_LANGUAGES
1✔
61

62

63
def handler(catalogs, name):
1✔
64
    """ special handler handling the merging of two message catalogs """
65
    gsm = getSiteManager()
1✔
66
    # Try to get an existing domain and add the given catalogs to it
67
    domain = queryUtility(ITranslationDomain, name)
1✔
68
    if domain is None:
1✔
69
        domain = TranslationDomain(name)
1✔
70
        gsm.registerUtility(domain, ITranslationDomain, name=name)
1✔
71
    for catalog in catalogs:
1✔
72
        domain.addCatalog(catalog)
1✔
73
    # make sure we have a TEST catalog for each domain:
74
    domain.addCatalog(TestMessageCatalog(name))
1✔
75

76

77
def registerTranslations(_context, directory, domain='*'):
1✔
78
    path = os.path.normpath(directory)
1✔
79
    domains = {}
1✔
80

81
    loaded = False
1✔
82
    # Gettext has the domain-specific catalogs inside the language directory,
83
    # which is exactly the opposite as we need it. So create a dictionary that
84
    # reverses the nesting.
85
    for language in os.listdir(path):
1✔
86
        if not allow_language(language):
1✔
87
            continue
1✔
88
        lc_messages_path = os.path.join(path, language, 'LC_MESSAGES')
1✔
89
        if os.path.isdir(lc_messages_path):
1✔
90
            # Preprocess files and update or compile the mo files
91
            setting_unset = (
1✔
92
                config.COMPILE_MO_FILES == config.COMPILE_MO_FILES_UNSET
93
            )
94
            if (
1!
95
                (setting_unset
96
                 and os.environ.get(config.COMPILE_MO_FILES_KEY, False))
97
                or (not setting_unset and config.COMPILE_MO_FILES)
98
            ):
99
                for domain_path in glob(os.path.join(lc_messages_path,
1✔
100
                                                     '%s.po' % domain)):
101
                    domain_file = os.path.basename(domain_path)
1✔
102
                    name = domain_file[:-3]
1✔
103
                    compile_mo_file(name, lc_messages_path)
1✔
104
            for domain_path in glob(os.path.join(lc_messages_path,
1✔
105
                                                 '%s.mo' % domain)):
106
                loaded = True
1✔
107
                domain_file = os.path.basename(domain_path)
1✔
108
                name = domain_file[:-3]
1✔
109
                if name not in domains:
1✔
110
                    domains[name] = {}
1✔
111
                domains[name][language] = domain_path
1✔
112
    if loaded:
1!
113
        logger.debug('register directory %s', directory)
1✔
114

115
    # Now create TranslationDomain objects and add them as utilities
116
    for name, langs in domains.items():
1✔
117
        catalogs = []
1✔
118
        for lang, file in langs.items():
1✔
119
            catalogs.append(GettextMessageCatalog(lang, name, file))
1✔
120
        # register the necessary actions directly (as opposed to using
121
        # `zope.component.zcml.utility`) since we need the actual utilities
122
        # in place before the merging can be done...
123
        _context.action(
1✔
124
            discriminator=None,
125
            callable=handler,
126
            args=(catalogs, name))
127

128
    # also register the interface for the translation utilities
129
    provides = ITranslationDomain
1✔
130
    _context.action(
1✔
131
        discriminator=None,
132
        callable=provideInterface,
133
        args=(provides.__module__ + '.' + provides.getName(), provides))
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc