1 # This file is part of the Enkel web programming library.
3 # Copyright (C) 2007 Espen Angell Kristiansen (espeak@users.sourceforge.net)
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; either version 2
8 # of the License, or (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 """ Internationalization.
21 @var BUILTIN_LOCALEDIR: The folder containing the translations
23 @var BUILTIN_DOMAIN: The domain used for the library translations.
25 from gettext
import translation
, NullTranslations
26 from os
.path
import split
, join
, dirname
28 from enkel
.settings
import encoding
31 BUILTIN_LOCALEDIR
= join(dirname(__file__
), "translations")
32 BUILTIN_DOMAIN
= "default"
33 I18N_LANG_ENV
= "enkel.i18n.lang"
34 I18N_ENV
= "enkel.i18n"
37 class DomainBoxInterface(object):
38 """ A DomainBox is a threadsafe interface to a gettext domain. """
39 def __init__(self
, domain
, localedir
,
43 All parameters are forwarded to gettext.translations() when
44 the gettext dictionary is loaded.
47 self
.localedir
= localedir
48 self
.codeset
= codeset
49 self
.fallback
= fallback
52 def add(self
, langcode
, *fallback_langcodes
):
53 """ Add a language to the box.
54 @param langcode: The primary language.
55 @param fallback_langcodes: Other languages that can be
56 used when translations for "langcode" is not
59 raise NotImplementedError()
61 def get(self
, langcode
, fallback
=NullTranslations()):
62 """ Get the gettext dictionary for a language.
63 @param langcode: A langcode added with L{add}.
64 @param fallback: A gettext.NullTranslations compatible
65 object to use as fallback if no dictionary for
68 raise NotImplementedError()
72 class CacheDomainBox(DomainBoxInterface
):
73 """ A DomainBoxInterface implementation that loads all
74 dictionaries into memory once. This gives very fast lookup,
75 but uses alot of memory if you wish to support many
78 >>> d = CacheDomainBox(BUILTIN_DOMAIN, BUILTIN_LOCALEDIR)
80 >>> d.get("nb").ugettext("Delete")
82 >>> d.get("null").ugettext("Delete")
85 def add(self
, langcode
, *fallback_langcodes
):
86 self
.trans
[langcode
] = translation(
87 self
.domain
, self
.localedir
,
88 [langcode
] + list(fallback_langcodes
),
89 fallback
=self
.fallback
, codeset
=self
.codeset
)
91 def get(self
, langcode
, fallback
=NullTranslations()):
93 return self
.trans
[langcode
]
98 class OnDemandDomainBox(DomainBoxInterface
):
99 """ A DomainBoxInterface implementation that loads
100 dictionaries on demand, everytime L{get} is invoked.
101 This only uses memory when the dictionary is loaded,
102 and might be more effective than L{CacheDomainBox} when
103 using lots of languages.
105 >>> d = CacheDomainBox(BUILTIN_DOMAIN, BUILTIN_LOCALEDIR)
107 >>> d.get("nb").ugettext("Delete")
109 >>> d.get("null").ugettext("Delete")
112 def add(self
, langcode
, *fallback_langcodes
):
113 self
.trans
[langcode
] = fallback_langcodes
115 def get(self
, langcode
, fallback
=NullTranslations()):
117 fallback_langcodes
= self
.trans
[langcode
]
122 self
.domain
, self
.localedir
,
123 [langcode
] + list(fallback_langcodes
),
124 fallback
=self
.fallback
, codeset
=self
.codeset
)
130 return doctest
.DocTestSuite()
132 if __name__
== "__main__":
133 from enkel
.wansgli
.testhelpers
import run_suite