pylons.i18n.translation
Covered: 27 lines
Missed: 117 lines
Skipped 57 lines
Percent: 18 %

      1

    """Translation/Localization functions.

      2

      3

    Provides :mod:`gettext` translation functions via an app's

      4

    ``pylons.translator`` and get/set_lang for changing the language

      5

    translated to.

      6

      7

    """

      8

    import os

      9

    from gettext import NullTranslations, translation

     10

     11

    import pylons

     12

     13

    __all__ = ['_', 'add_fallback', 'get_lang', 'gettext', 'gettext_noop',

     14

               'lazy_gettext', 'lazy_ngettext', 'lazy_ugettext', 'lazy_ungettext',

     15

               'ngettext', 'set_lang', 'ugettext', 'ungettext', 'LanguageError',

     16

               'N_']

     17

     18

    class LanguageError(Exception):

     19

        """Exception raised when a problem occurs with changing languages"""

     20

        pass

     21

     22

     23

    class LazyString(object):

     24

        """Has a number of lazily evaluated functions replicating a

     25

        string. Just override the eval() method to produce the actual value.

     26

     27

        This method copied from TurboGears.

     28

     29

        """

     30

        def __init__(self, func, *args, **kwargs):

     31

            self.func = func

     32

            self.args = args

     33

            self.kwargs = kwargs

     34

     35

        def eval(self):

     36

            return self.func(*self.args, **self.kwargs)

     37

     38

        def __unicode__(self):

     39

            return unicode(self.eval())

     40

     41

        def __str__(self):

     42

            return str(self.eval())

     43

     44

        def __mod__(self, other):

     45

            return self.eval() % other

     46

     47

        def format(self, other):

     48

            return self.eval().format(other)

     49

     50

     51

    def lazify(func):

     52

        """Decorator to return a lazy-evaluated version of the original"""

     53

        def newfunc(*args, **kwargs):

     54

            return LazyString(func, *args, **kwargs)

     55

        newfunc.__name__ = 'lazy_%s' % func.__name__

     56

        newfunc.__doc__ = 'Lazy-evaluated version of the %s function\n\n%s' % \

     57

            (func.__name__, func.__doc__)

     58

        return newfunc

     59

     60

     61

    def gettext_noop(value):

     62

        """Mark a string for translation without translating it. Returns

     63

        value.

     64

     65

        Used for global strings, e.g.::

     66

     67

            foo = N_('Hello')

     68

     69

            class Bar:

     70

                def __init__(self):

     71

                    self.local_foo = _(foo)

     72

     73

            h.set_lang('fr')

     74

            assert Bar().local_foo == 'Bonjour'

     75

            h.set_lang('es')

     76

            assert Bar().local_foo == 'Hola'

     77

            assert foo == 'Hello'

     78

     79

        """

     80

        return value

     81

    N_ = gettext_noop

     82

     83

     84

    def gettext(value):

     85

        """Mark a string for translation. Returns the localized string of

     86

        value.

     87

     88

        Mark a string to be localized as follows::

     89

     90

            gettext('This should be in lots of languages')

     91

     92

        """

     93

        return pylons.translator.gettext(value)

     94

    lazy_gettext = lazify(gettext)

     95

     96

     97

    def ugettext(value):

     98

        """Mark a string for translation. Returns the localized unicode

     99

        string of value.

    100

    101

        Mark a string to be localized as follows::

    102

    103

            _('This should be in lots of languages')

    104

    105

        """

    106

        return pylons.translator.ugettext(value)

    107

    _ = ugettext

    108

    lazy_ugettext = lazify(ugettext)

    109

    110

    111

    def ngettext(singular, plural, n):

    112

        """Mark a string for translation. Returns the localized string of

    113

        the pluralized value.

    114

    115

        This does a plural-forms lookup of a message id. ``singular`` is

    116

        used as the message id for purposes of lookup in the catalog, while

    117

        ``n`` is used to determine which plural form to use. The returned

    118

        message is a string.

    119

    120

        Mark a string to be localized as follows::

    121

    122

            ngettext('There is %(num)d file here', 'There are %(num)d files here',

    123

                     n) % {'num': n}

    124

    125

        """

    126

        return pylons.translator.ngettext(singular, plural, n)

    127

    lazy_ngettext = lazify(ngettext)

    128

    129

    130

    def ungettext(singular, plural, n):

    131

        """Mark a string for translation. Returns the localized unicode

    132

        string of the pluralized value.

    133

    134

        This does a plural-forms lookup of a message id. ``singular`` is

    135

        used as the message id for purposes of lookup in the catalog, while

    136

        ``n`` is used to determine which plural form to use. The returned

    137

        message is a Unicode string.

    138

    139

        Mark a string to be localized as follows::

    140

    141

            ungettext('There is %(num)d file here', 'There are %(num)d files here',

    142

                      n) % {'num': n}

    143

    144

        """

    145

        return pylons.translator.ungettext(singular, plural, n)

    146

    lazy_ungettext = lazify(ungettext)

    147

    148

    149

    def _get_translator(lang, **kwargs):

    150

        """Utility method to get a valid translator object from a language

    151

        name"""

    152

        if not lang:

    153

            return NullTranslations()

    154

        if 'pylons_config' in kwargs:

    155

            conf = kwargs.pop('pylons_config')

    156

        else:

    157

            conf = pylons.config.current_conf()

    158

        localedir = os.path.join(conf['pylons.paths']['root'], 'i18n')

    159

        if not isinstance(lang, list):

    160

            lang = [lang]

    161

        try:

    162

            translator = translation(conf['pylons.package'], localedir,

    163

                                     languages=lang, **kwargs)

    164

        except IOError, ioe:

    165

            raise LanguageError('IOError: %s' % ioe)

    166

        translator.pylons_lang = lang

    167

        return translator

    168

    169

    170

    def set_lang(lang, **kwargs):

    171

        """Set the current language used for translations.

    172

    173

        ``lang`` should be a string or a list of strings. If a list of

    174

        strings, the first language is set as the main and the subsequent

    175

        languages are added as fallbacks.

    176

        """

    177

        translator = _get_translator(lang, **kwargs)

    178

        environ = pylons.request.environ

    179

        environ['pylons.pylons'].translator = translator

    180

        if 'paste.registry' in environ:

    181

            environ['paste.registry'].replace(pylons.translator, translator)

    182

    183

    184

    def get_lang():

    185

        """Return the current i18n language used"""

    186

        return getattr(pylons.translator, 'pylons_lang', None)

    187

    188

    189

    def add_fallback(lang, **kwargs):

    190

        """Add a fallback language from which words not matched in other

    191

        languages will be translated to.

    192

    193

        This fallback will be associated with the currently selected

    194

        language -- that is, resetting the language via set_lang() resets

    195

        the current fallbacks.

    196

    197

        This function can be called multiple times to add multiple

    198

        fallbacks.

    199

        """

    200

        return pylons.translator.add_fallback(_get_translator(lang, **kwargs))

    201