You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
527 lines
21 KiB
527 lines
21 KiB
# -*- coding: utf-8 -*-
|
|
|
|
from __future__ import print_function
|
|
from __future__ import unicode_literals
|
|
|
|
#
|
|
# Copyright � 2007-2010 Dieter Verfaillie <dieterv@optionexplicit.be>
|
|
#
|
|
# This file is part of elib.intl.
|
|
#
|
|
# elib.intl is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU Lesser General Public License as published by
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# elib.intl is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU Lesser General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU Lesser General Public License
|
|
# along with elib.intl. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
# Update by Dysmas : added the option to explicitly define the language :
|
|
# parameter "code" in the function : install , line 453
|
|
|
|
|
|
|
|
'''
|
|
The elib.intl module provides enhanced internationalization (I18N) services for
|
|
your Python modules and applications.
|
|
|
|
elib.intl wraps Python's :func:`gettext` functionality and adds the following on
|
|
Microsoft Windows systems:
|
|
|
|
- automatic detection of the current screen language (not necessarily the same
|
|
as the installation language) provided by MUI packs,
|
|
- makes sure internationalized C libraries which internally invoke gettext() or
|
|
dcgettext() can properly locate their message catalogs. This fixes a known
|
|
limitation in gettext's Windows support when using eg. gtk.builder or gtk.glade.
|
|
|
|
See http://www.gnu.org/software/gettext/FAQ.html#windows_setenv for more
|
|
information.
|
|
|
|
The elib.intl module defines the following functions:
|
|
'''
|
|
|
|
|
|
__all__ = ['install', 'install_module']
|
|
__version__ = '0.0.3'
|
|
__docformat__ = 'restructuredtext'
|
|
|
|
|
|
import os
|
|
import sys
|
|
import locale
|
|
import gettext
|
|
|
|
from logging import getLogger
|
|
|
|
|
|
logger = getLogger('elib.intl')
|
|
|
|
|
|
def _isofromlcid(lcid):
|
|
'''
|
|
:param lcid: Microsoft Windows LCID
|
|
:returns: the ISO 639-1 language code for a given lcid. If there is no
|
|
ISO 639-1 language code assigned to the language specified by lcid,
|
|
the ISO 639-2 language code is returned. If the language specified
|
|
by lcid is unknown in the ISO 639-x database, None is returned.
|
|
|
|
More information can be found on the following websites:
|
|
- List of ISO 639-1 and ISO 639-2 language codes: http://www.loc.gov/standards/iso639-2/
|
|
- List of known lcid's: http://www.microsoft.com/globaldev/reference/lcid-all.mspx
|
|
- List of known MUI packs: http://www.microsoft.com/globaldev/reference/win2k/setup/Langid.mspx
|
|
'''
|
|
mapping = {1078: 'af', #Afrikaans - South Africa
|
|
1052: 'sq', #Albanian - Albania
|
|
1118: 'am', #Amharic - Ethiopia
|
|
1025: 'ar', #Arabic - Saudi Arabia
|
|
5121: 'ar', #Arabic - Algeria
|
|
15361: 'ar', #Arabic - Bahrain
|
|
3073: 'ar', #Arabic - Egypt
|
|
2049: 'ar', #Arabic - Iraq
|
|
11265: 'ar', #Arabic - Jordan
|
|
13313: 'ar', #Arabic - Kuwait
|
|
12289: 'ar', #Arabic - Lebanon
|
|
4097: 'ar', #Arabic - Libya
|
|
6145: 'ar', #Arabic - Morocco
|
|
8193: 'ar', #Arabic - Oman
|
|
16385: 'ar', #Arabic - Qatar
|
|
10241: 'ar', #Arabic - Syria
|
|
7169: 'ar', #Arabic - Tunisia
|
|
14337: 'ar', #Arabic - U.A.E.
|
|
9217: 'ar', #Arabic - Yemen
|
|
1067: 'hy', #Armenian - Armenia
|
|
1101: 'as', #Assamese
|
|
2092: 'az', #Azeri (Cyrillic)
|
|
1068: 'az', #Azeri (Latin)
|
|
1069: 'eu', #Basque
|
|
1059: 'be', #Belarusian
|
|
1093: 'bn', #Bengali (India)
|
|
2117: 'bn', #Bengali (Bangladesh)
|
|
5146: 'bs', #Bosnian (Bosnia/Herzegovina)
|
|
1026: 'bg', #Bulgarian
|
|
1109: 'my', #Burmese
|
|
1027: 'ca', #Catalan
|
|
1116: 'chr', #Cherokee - United States
|
|
2052: 'zh', #Chinese - People's Republic of China
|
|
4100: 'zh', #Chinese - Singapore
|
|
1028: 'zh', #Chinese - Taiwan
|
|
3076: 'zh', #Chinese - Hong Kong SAR
|
|
5124: 'zh', #Chinese - Macao SAR
|
|
1050: 'hr', #Croatian
|
|
4122: 'hr', #Croatian (Bosnia/Herzegovina)
|
|
1029: 'cs', #Czech
|
|
1030: 'da', #Danish
|
|
1125: 'dv', #Divehi
|
|
1043: 'nl', #Dutch - Netherlands
|
|
2067: 'nl', #Dutch - Belgium
|
|
1126: 'bin', #Edo
|
|
1033: 'en', #English - United States
|
|
2057: 'en', #English - United Kingdom
|
|
3081: 'en', #English - Australia
|
|
10249: 'en', #English - Belize
|
|
4105: 'en', #English - Canada
|
|
9225: 'en', #English - Caribbean
|
|
15369: 'en', #English - Hong Kong SAR
|
|
16393: 'en', #English - India
|
|
14345: 'en', #English - Indonesia
|
|
6153: 'en', #English - Ireland
|
|
8201: 'en', #English - Jamaica
|
|
17417: 'en', #English - Malaysia
|
|
5129: 'en', #English - New Zealand
|
|
13321: 'en', #English - Philippines
|
|
18441: 'en', #English - Singapore
|
|
7177: 'en', #English - South Africa
|
|
11273: 'en', #English - Trinidad
|
|
12297: 'en', #English - Zimbabwe
|
|
1061: 'et', #Estonian
|
|
1080: 'fo', #Faroese
|
|
1065: None, #TODO: Farsi
|
|
1124: 'fil', #Filipino
|
|
1035: 'fi', #Finnish
|
|
1036: 'fr', #French - France
|
|
2060: 'fr', #French - Belgium
|
|
11276: 'fr', #French - Cameroon
|
|
3084: 'fr', #French - Canada
|
|
9228: 'fr', #French - Democratic Rep. of Congo
|
|
12300: 'fr', #French - Cote d'Ivoire
|
|
15372: 'fr', #French - Haiti
|
|
5132: 'fr', #French - Luxembourg
|
|
13324: 'fr', #French - Mali
|
|
6156: 'fr', #French - Monaco
|
|
14348: 'fr', #French - Morocco
|
|
58380: 'fr', #French - North Africa
|
|
8204: 'fr', #French - Reunion
|
|
10252: 'fr', #French - Senegal
|
|
4108: 'fr', #French - Switzerland
|
|
7180: 'fr', #French - West Indies
|
|
1122: 'fy', #Frisian - Netherlands
|
|
1127: None, #TODO: Fulfulde - Nigeria
|
|
1071: 'mk', #FYRO Macedonian
|
|
2108: 'ga', #Gaelic (Ireland)
|
|
1084: 'gd', #Gaelic (Scotland)
|
|
1110: 'gl', #Galician
|
|
1079: 'ka', #Georgian
|
|
1031: 'de', #German - Germany
|
|
3079: 'de', #German - Austria
|
|
5127: 'de', #German - Liechtenstein
|
|
4103: 'de', #German - Luxembourg
|
|
2055: 'de', #German - Switzerland
|
|
1032: 'el', #Greek
|
|
1140: 'gn', #Guarani - Paraguay
|
|
1095: 'gu', #Gujarati
|
|
1128: 'ha', #Hausa - Nigeria
|
|
1141: 'haw', #Hawaiian - United States
|
|
1037: 'he', #Hebrew
|
|
1081: 'hi', #Hindi
|
|
1038: 'hu', #Hungarian
|
|
1129: None, #TODO: Ibibio - Nigeria
|
|
1039: 'is', #Icelandic
|
|
1136: 'ig', #Igbo - Nigeria
|
|
1057: 'id', #Indonesian
|
|
1117: 'iu', #Inuktitut
|
|
1040: 'it', #Italian - Italy
|
|
2064: 'it', #Italian - Switzerland
|
|
1041: 'ja', #Japanese
|
|
1099: 'kn', #Kannada
|
|
1137: 'kr', #Kanuri - Nigeria
|
|
2144: 'ks', #Kashmiri
|
|
1120: 'ks', #Kashmiri (Arabic)
|
|
1087: 'kk', #Kazakh
|
|
1107: 'km', #Khmer
|
|
1111: 'kok', #Konkani
|
|
1042: 'ko', #Korean
|
|
1088: 'ky', #Kyrgyz (Cyrillic)
|
|
1108: 'lo', #Lao
|
|
1142: 'la', #Latin
|
|
1062: 'lv', #Latvian
|
|
1063: 'lt', #Lithuanian
|
|
1086: 'ms', #Malay - Malaysia
|
|
2110: 'ms', #Malay - Brunei Darussalam
|
|
1100: 'ml', #Malayalam
|
|
1082: 'mt', #Maltese
|
|
1112: 'mni', #Manipuri
|
|
1153: 'mi', #Maori - New Zealand
|
|
1102: 'mr', #Marathi
|
|
1104: 'mn', #Mongolian (Cyrillic)
|
|
2128: 'mn', #Mongolian (Mongolian)
|
|
1121: 'ne', #Nepali
|
|
2145: 'ne', #Nepali - India
|
|
1044: 'no', #Norwegian (Bokm??l)
|
|
2068: 'no', #Norwegian (Nynorsk)
|
|
1096: 'or', #Oriya
|
|
1138: 'om', #Oromo
|
|
1145: 'pap', #Papiamentu
|
|
1123: 'ps', #Pashto
|
|
1045: 'pl', #Polish
|
|
1046: 'pt', #Portuguese - Brazil
|
|
2070: 'pt', #Portuguese - Portugal
|
|
1094: 'pa', #Punjabi
|
|
2118: 'pa', #Punjabi (Pakistan)
|
|
1131: 'qu', #Quecha - Bolivia
|
|
2155: 'qu', #Quecha - Ecuador
|
|
3179: 'qu', #Quecha - Peru
|
|
1047: 'rm', #Rhaeto-Romanic
|
|
1048: 'ro', #Romanian
|
|
2072: 'ro', #Romanian - Moldava
|
|
1049: 'ru', #Russian
|
|
2073: 'ru', #Russian - Moldava
|
|
1083: 'se', #Sami (Lappish)
|
|
1103: 'sa', #Sanskrit
|
|
1132: 'nso', #Sepedi
|
|
3098: 'sr', #Serbian (Cyrillic)
|
|
2074: 'sr', #Serbian (Latin)
|
|
1113: 'sd', #Sindhi - India
|
|
2137: 'sd', #Sindhi - Pakistan
|
|
1115: 'si', #Sinhalese - Sri Lanka
|
|
1051: 'sk', #Slovak
|
|
1060: 'sl', #Slovenian
|
|
1143: 'so', #Somali
|
|
1070: 'wen', #Sorbian
|
|
3082: 'es', #Spanish - Spain (Modern Sort)
|
|
1034: 'es', #Spanish - Spain (Traditional Sort)
|
|
11274: 'es', #Spanish - Argentina
|
|
16394: 'es', #Spanish - Bolivia
|
|
13322: 'es', #Spanish - Chile
|
|
9226: 'es', #Spanish - Colombia
|
|
5130: 'es', #Spanish - Costa Rica
|
|
7178: 'es', #Spanish - Dominican Republic
|
|
12298: 'es', #Spanish - Ecuador
|
|
17418: 'es', #Spanish - El Salvador
|
|
4106: 'es', #Spanish - Guatemala
|
|
18442: 'es', #Spanish - Honduras
|
|
58378: 'es', #Spanish - Latin America
|
|
2058: 'es', #Spanish - Mexico
|
|
19466: 'es', #Spanish - Nicaragua
|
|
6154: 'es', #Spanish - Panama
|
|
15370: 'es', #Spanish - Paraguay
|
|
10250: 'es', #Spanish - Peru
|
|
20490: 'es', #Spanish - Puerto Rico
|
|
21514: 'es', #Spanish - United States
|
|
14346: 'es', #Spanish - Uruguay
|
|
8202: 'es', #Spanish - Venezuela
|
|
1072: None, #TODO: Sutu
|
|
1089: 'sw', #Swahili
|
|
1053: 'sv', #Swedish
|
|
2077: 'sv', #Swedish - Finland
|
|
1114: 'syr', #Syriac
|
|
1064: 'tg', #Tajik
|
|
1119: None, #TODO: Tamazight (Arabic)
|
|
2143: None, #TODO: Tamazight (Latin)
|
|
1097: 'ta', #Tamil
|
|
1092: 'tt', #Tatar
|
|
1098: 'te', #Telugu
|
|
1054: 'th', #Thai
|
|
2129: 'bo', #Tibetan - Bhutan
|
|
1105: 'bo', #Tibetan - People's Republic of China
|
|
2163: 'ti', #Tigrigna - Eritrea
|
|
1139: 'ti', #Tigrigna - Ethiopia
|
|
1073: 'ts', #Tsonga
|
|
1074: 'tn', #Tswana
|
|
1055: 'tr', #Turkish
|
|
1090: 'tk', #Turkmen
|
|
1152: 'ug', #Uighur - China
|
|
1058: 'uk', #Ukrainian
|
|
1056: 'ur', #Urdu
|
|
2080: 'ur', #Urdu - India
|
|
2115: 'uz', #Uzbek (Cyrillic)
|
|
1091: 'uz', #Uzbek (Latin)
|
|
1075: 've', #Venda
|
|
1066: 'vi', #Vietnamese
|
|
1106: 'cy', #Welsh
|
|
1076: 'xh', #Xhosa
|
|
1144: 'ii', #Yi
|
|
1085: 'yi', #Yiddish
|
|
1130: 'yo', #Yoruba
|
|
1077: 'zu'} #Zulu
|
|
|
|
return mapping[lcid]
|
|
|
|
def _getscreenlanguage():
|
|
global language_code
|
|
'''
|
|
:returns: the ISO 639-x language code for this session.
|
|
|
|
If the LANGUAGE environment variable is set, it's value overrides the
|
|
screen language detection. Otherwise the screen language is determined by
|
|
the currently selected Microsoft Windows MUI language pack or the Microsoft
|
|
Windows installation language.
|
|
|
|
Works on Microsoft Windows 2000 and up.
|
|
'''
|
|
if sys.platform == 'win32' or sys.platform == 'nt':
|
|
# Start with nothing
|
|
lang = None
|
|
|
|
# Check the LANGUAGE environment variable
|
|
lang = os.getenv('LANGUAGE')
|
|
if language_code != "" :
|
|
lang = language_code
|
|
if lang is None:
|
|
# Start with nothing
|
|
lcid = None
|
|
|
|
try:
|
|
from ctypes import windll
|
|
lcid = windll.kernel32.GetUserDefaultUILanguage()
|
|
except:
|
|
logger.debug('Failed to get current screen language with \'GetUserDefaultUILanguage\'')
|
|
finally:
|
|
if lcid is None:
|
|
lang = 'C'
|
|
else:
|
|
lang = _isofromlcid(lcid)
|
|
|
|
logger.debug('Windows screen language is \'%s\' (lcid %s)' % (lang, lcid))
|
|
|
|
return lang
|
|
|
|
def _putenv(name, value):
|
|
'''
|
|
:param name: environment variable name
|
|
:param value: environment variable value
|
|
|
|
This function ensures that changes to an environment variable are applied
|
|
to each copy of the environment variables used by a process. Starting from
|
|
Python 2.4, os.environ changes only apply to the copy Python keeps (os.environ)
|
|
and are no longer automatically applied to the other copies for the process.
|
|
|
|
On Microsoft Windows, each process has multiple copies of the environment
|
|
variables, one managed by the OS and one managed by the C library. We also
|
|
need to take care of the fact that the C library used by Python is not
|
|
necessarily the same as the C library used by pygtk and friends. This because
|
|
the latest releases of pygtk and friends are built with mingw32 and are thus
|
|
linked against msvcrt.dll. The official gtk+ binaries have always been built
|
|
in this way.
|
|
'''
|
|
|
|
if sys.platform == 'win32' or sys.platform == 'nt':
|
|
from ctypes import windll
|
|
from ctypes import cdll
|
|
from ctypes.util import find_msvcrt
|
|
|
|
# Update Python's copy of the environment variables
|
|
os.environ[name] = value
|
|
|
|
# Update the copy maintained by Windows (so SysInternals Process Explorer sees it)
|
|
try:
|
|
result = windll.kernel32.SetEnvironmentVariableW(name, value)
|
|
if result == 0: raise Warning
|
|
except Exception:
|
|
logger.debug('Failed to set environment variable \'%s\' (\'kernel32.SetEnvironmentVariableW\')' % name)
|
|
else:
|
|
logger.debug('Set environment variable \'%s\' to \'%s\' (\'kernel32.SetEnvironmentVariableW\')' % (name, value))
|
|
|
|
# Update the copy maintained by msvcrt (used by gtk+ runtime)
|
|
try:
|
|
result = cdll.msvcrt._putenv('%s=%s' % (name, value))
|
|
if result !=0: raise Warning
|
|
except Exception:
|
|
logger.debug('Failed to set environment variable \'%s\' (\'msvcrt._putenv\')' % name)
|
|
else:
|
|
logger.debug('Set environment variable \'%s\' to \'%s\' (\'msvcrt._putenv\')' % (name, value))
|
|
|
|
# Update the copy maintained by whatever c runtime is used by Python
|
|
try:
|
|
msvcrt = find_msvcrt()
|
|
msvcrtname = str(msvcrt).split('.')[0] if '.' in msvcrt else str(msvcrt)
|
|
result = cdll.LoadLibrary(msvcrt)._putenv('%s=%s' % (name, value))
|
|
if result != 0: raise Warning
|
|
except Exception:
|
|
logger.debug('Failed to set environment variable \'%s\' (\'%s._putenv\')' % (name, msvcrtname))
|
|
else:
|
|
logger.debug('Set environment variable \'%s\' to \'%s\' (\'%s._putenv\')' % (name, value, msvcrtname))
|
|
|
|
def _dugettext(domain, message):
|
|
'''
|
|
:param domain: translation domain
|
|
:param message: message to translate
|
|
:returns: the translated message
|
|
|
|
Unicode version of :func:`gettext.dgettext`.
|
|
'''
|
|
try:
|
|
t = gettext.translation(domain, gettext._localedirs.get(domain, None),
|
|
codeset=gettext._localecodesets.get(domain))
|
|
except IOError:
|
|
return message
|
|
else:
|
|
return t.ugettext(message)
|
|
|
|
def _install(domain, localedir, asglobal=False):
|
|
'''
|
|
:param domain: translation domain
|
|
:param localedir: locale directory
|
|
:param asglobal: if True, installs the function _() in Python�s builtin namespace. Default is False
|
|
|
|
Private function doing all the work for the :func:`elib.intl.install` and
|
|
:func:`elib.intl.install_module` functions.
|
|
'''
|
|
# prep locale system
|
|
if asglobal:
|
|
locale.setlocale(locale.LC_ALL, '')
|
|
|
|
# on windows systems, set the LANGUAGE environment variable
|
|
if sys.platform == 'win32' or sys.platform == 'nt':
|
|
_putenv('LANGUAGE', _getscreenlanguage())
|
|
#print "=========2>", os.getenv('LANGUAGE')
|
|
#print ("=========2>",_getscreenlanguage())
|
|
|
|
|
|
# The locale module on Max OS X lacks bindtextdomain so we specifically
|
|
# test on linux2 here. See commit 4ae8b26fd569382ab66a9e844daa0e01de409ceb
|
|
if sys.platform == 'linux2':
|
|
locale.bindtextdomain(domain, localedir)
|
|
locale.bind_textdomain_codeset(domain, 'UTF-8')
|
|
locale.textdomain(domain)
|
|
|
|
# initialize Python's gettext interface
|
|
gettext.bindtextdomain(domain, localedir)
|
|
gettext.bind_textdomain_codeset(domain, 'UTF-8')
|
|
|
|
if asglobal:
|
|
gettext.textdomain(domain)
|
|
|
|
# on windows systems, initialize libintl
|
|
domain = domain.encode("cp1252")
|
|
localedir = localedir.encode("cp1252")
|
|
if sys.platform == 'win32' or sys.platform == 'nt':
|
|
from ctypes import cdll
|
|
libintl = cdll.LoadLibrary("libintl-8.dll")
|
|
libintl.bindtextdomain(domain, localedir)
|
|
libintl.bind_textdomain_codeset(domain, 'UTF-8')
|
|
|
|
if asglobal:
|
|
libintl.textdomain(domain)
|
|
|
|
del libintl
|
|
|
|
def install(domain, localedir, code = ""):
|
|
'''
|
|
:param domain: translation domain
|
|
:param localedir: locale directory
|
|
:param code: Language code required. Default means autodetect.
|
|
|
|
Installs the function _() in Python�s builtin namespace, based on
|
|
domain and localedir. Codeset is always UTF-8.
|
|
|
|
As seen below, you usually mark the strings in your application that are
|
|
candidates for translation, by wrapping them in a call to the _() function,
|
|
like this:
|
|
|
|
.. sourcecode:: python
|
|
|
|
import elib.intl
|
|
elib.intl.install('myapplication', '/path/to/usr/share/locale')
|
|
print _('This string will be translated.')
|
|
|
|
Note that this is only one way, albeit the most convenient way,
|
|
to make the _() function available to your application. Because it affects
|
|
the entire application globally, and specifically Python�s built-in
|
|
namespace, localized modules should never install _(). Instead, you should
|
|
use :func:`elib.intl.install_module` to make _() available to your module.
|
|
'''
|
|
|
|
global language_code
|
|
language_code = code
|
|
|
|
_install(domain, localedir, True)
|
|
gettext.install(domain, localedir)
|
|
|
|
def install_module(domain, localedir):
|
|
'''
|
|
:param domain: translation domain
|
|
:param localedir: locale directory
|
|
:returns: an anonymous function object, based on domain and localedir.
|
|
Codeset is always UTF-8.
|
|
|
|
You may find this function usefull when writing localized modules.
|
|
Use this code to make _() available to your module:
|
|
|
|
.. sourcecode:: python
|
|
|
|
import elib.intl
|
|
_ = elib.intl.install_module('mymodule', '/path/to/usr/share/locale')
|
|
print _('This string will be translated.')
|
|
|
|
When writing a package, you can usually do this in the package's __init__.py
|
|
file and import the _() function from the package namespace as needed.
|
|
'''
|
|
_install(domain, localedir, False)
|
|
return lambda message: _dugettext(domain, message)
|
|
|
|
|
|
def main() :
|
|
language = ""
|
|
if sys.platform == 'win32' or sys.platform == 'nt':
|
|
install("pdfbooklet", "share/locale", language)
|
|
print (_getscreenlanguage())
|
|
else :
|
|
install("pdfbooklet", "/usr/share/locale", language)
|
|
print (_("There is no selection"))
|
|
if __name__ == '__main__' :
|
|
main()
|