I updated the PDF Booklet project and removed Python 2 dependencies so that it will run under Ubuntu 22.04.
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.

526 lines
21 KiB

2 years ago
  1. # -*- coding: utf-8 -*-
  2. from __future__ import print_function
  3. from __future__ import unicode_literals
  4. #
  5. # Copyright � 2007-2010 Dieter Verfaillie <dieterv@optionexplicit.be>
  6. #
  7. # This file is part of elib.intl.
  8. #
  9. # elib.intl is free software: you can redistribute it and/or modify
  10. # it under the terms of the GNU Lesser General Public License as published by
  11. # the Free Software Foundation, either version 3 of the License, or
  12. # (at your option) any later version.
  13. #
  14. # elib.intl is distributed in the hope that it will be useful,
  15. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. # GNU Lesser General Public License for more details.
  18. #
  19. # You should have received a copy of the GNU Lesser General Public License
  20. # along with elib.intl. If not, see <http://www.gnu.org/licenses/>.
  21. # Update by Dysmas : added the option to explicitly define the language :
  22. # parameter "code" in the function : install , line 453
  23. '''
  24. The elib.intl module provides enhanced internationalization (I18N) services for
  25. your Python modules and applications.
  26. elib.intl wraps Python's :func:`gettext` functionality and adds the following on
  27. Microsoft Windows systems:
  28. - automatic detection of the current screen language (not necessarily the same
  29. as the installation language) provided by MUI packs,
  30. - makes sure internationalized C libraries which internally invoke gettext() or
  31. dcgettext() can properly locate their message catalogs. This fixes a known
  32. limitation in gettext's Windows support when using eg. gtk.builder or gtk.glade.
  33. See http://www.gnu.org/software/gettext/FAQ.html#windows_setenv for more
  34. information.
  35. The elib.intl module defines the following functions:
  36. '''
  37. __all__ = ['install', 'install_module']
  38. __version__ = '0.0.3'
  39. __docformat__ = 'restructuredtext'
  40. import os
  41. import sys
  42. import locale
  43. import gettext
  44. from logging import getLogger
  45. logger = getLogger('elib.intl')
  46. def _isofromlcid(lcid):
  47. '''
  48. :param lcid: Microsoft Windows LCID
  49. :returns: the ISO 639-1 language code for a given lcid. If there is no
  50. ISO 639-1 language code assigned to the language specified by lcid,
  51. the ISO 639-2 language code is returned. If the language specified
  52. by lcid is unknown in the ISO 639-x database, None is returned.
  53. More information can be found on the following websites:
  54. - List of ISO 639-1 and ISO 639-2 language codes: http://www.loc.gov/standards/iso639-2/
  55. - List of known lcid's: http://www.microsoft.com/globaldev/reference/lcid-all.mspx
  56. - List of known MUI packs: http://www.microsoft.com/globaldev/reference/win2k/setup/Langid.mspx
  57. '''
  58. mapping = {1078: 'af', #Afrikaans - South Africa
  59. 1052: 'sq', #Albanian - Albania
  60. 1118: 'am', #Amharic - Ethiopia
  61. 1025: 'ar', #Arabic - Saudi Arabia
  62. 5121: 'ar', #Arabic - Algeria
  63. 15361: 'ar', #Arabic - Bahrain
  64. 3073: 'ar', #Arabic - Egypt
  65. 2049: 'ar', #Arabic - Iraq
  66. 11265: 'ar', #Arabic - Jordan
  67. 13313: 'ar', #Arabic - Kuwait
  68. 12289: 'ar', #Arabic - Lebanon
  69. 4097: 'ar', #Arabic - Libya
  70. 6145: 'ar', #Arabic - Morocco
  71. 8193: 'ar', #Arabic - Oman
  72. 16385: 'ar', #Arabic - Qatar
  73. 10241: 'ar', #Arabic - Syria
  74. 7169: 'ar', #Arabic - Tunisia
  75. 14337: 'ar', #Arabic - U.A.E.
  76. 9217: 'ar', #Arabic - Yemen
  77. 1067: 'hy', #Armenian - Armenia
  78. 1101: 'as', #Assamese
  79. 2092: 'az', #Azeri (Cyrillic)
  80. 1068: 'az', #Azeri (Latin)
  81. 1069: 'eu', #Basque
  82. 1059: 'be', #Belarusian
  83. 1093: 'bn', #Bengali (India)
  84. 2117: 'bn', #Bengali (Bangladesh)
  85. 5146: 'bs', #Bosnian (Bosnia/Herzegovina)
  86. 1026: 'bg', #Bulgarian
  87. 1109: 'my', #Burmese
  88. 1027: 'ca', #Catalan
  89. 1116: 'chr', #Cherokee - United States
  90. 2052: 'zh', #Chinese - People's Republic of China
  91. 4100: 'zh', #Chinese - Singapore
  92. 1028: 'zh', #Chinese - Taiwan
  93. 3076: 'zh', #Chinese - Hong Kong SAR
  94. 5124: 'zh', #Chinese - Macao SAR
  95. 1050: 'hr', #Croatian
  96. 4122: 'hr', #Croatian (Bosnia/Herzegovina)
  97. 1029: 'cs', #Czech
  98. 1030: 'da', #Danish
  99. 1125: 'dv', #Divehi
  100. 1043: 'nl', #Dutch - Netherlands
  101. 2067: 'nl', #Dutch - Belgium
  102. 1126: 'bin', #Edo
  103. 1033: 'en', #English - United States
  104. 2057: 'en', #English - United Kingdom
  105. 3081: 'en', #English - Australia
  106. 10249: 'en', #English - Belize
  107. 4105: 'en', #English - Canada
  108. 9225: 'en', #English - Caribbean
  109. 15369: 'en', #English - Hong Kong SAR
  110. 16393: 'en', #English - India
  111. 14345: 'en', #English - Indonesia
  112. 6153: 'en', #English - Ireland
  113. 8201: 'en', #English - Jamaica
  114. 17417: 'en', #English - Malaysia
  115. 5129: 'en', #English - New Zealand
  116. 13321: 'en', #English - Philippines
  117. 18441: 'en', #English - Singapore
  118. 7177: 'en', #English - South Africa
  119. 11273: 'en', #English - Trinidad
  120. 12297: 'en', #English - Zimbabwe
  121. 1061: 'et', #Estonian
  122. 1080: 'fo', #Faroese
  123. 1065: None, #TODO: Farsi
  124. 1124: 'fil', #Filipino
  125. 1035: 'fi', #Finnish
  126. 1036: 'fr', #French - France
  127. 2060: 'fr', #French - Belgium
  128. 11276: 'fr', #French - Cameroon
  129. 3084: 'fr', #French - Canada
  130. 9228: 'fr', #French - Democratic Rep. of Congo
  131. 12300: 'fr', #French - Cote d'Ivoire
  132. 15372: 'fr', #French - Haiti
  133. 5132: 'fr', #French - Luxembourg
  134. 13324: 'fr', #French - Mali
  135. 6156: 'fr', #French - Monaco
  136. 14348: 'fr', #French - Morocco
  137. 58380: 'fr', #French - North Africa
  138. 8204: 'fr', #French - Reunion
  139. 10252: 'fr', #French - Senegal
  140. 4108: 'fr', #French - Switzerland
  141. 7180: 'fr', #French - West Indies
  142. 1122: 'fy', #Frisian - Netherlands
  143. 1127: None, #TODO: Fulfulde - Nigeria
  144. 1071: 'mk', #FYRO Macedonian
  145. 2108: 'ga', #Gaelic (Ireland)
  146. 1084: 'gd', #Gaelic (Scotland)
  147. 1110: 'gl', #Galician
  148. 1079: 'ka', #Georgian
  149. 1031: 'de', #German - Germany
  150. 3079: 'de', #German - Austria
  151. 5127: 'de', #German - Liechtenstein
  152. 4103: 'de', #German - Luxembourg
  153. 2055: 'de', #German - Switzerland
  154. 1032: 'el', #Greek
  155. 1140: 'gn', #Guarani - Paraguay
  156. 1095: 'gu', #Gujarati
  157. 1128: 'ha', #Hausa - Nigeria
  158. 1141: 'haw', #Hawaiian - United States
  159. 1037: 'he', #Hebrew
  160. 1081: 'hi', #Hindi
  161. 1038: 'hu', #Hungarian
  162. 1129: None, #TODO: Ibibio - Nigeria
  163. 1039: 'is', #Icelandic
  164. 1136: 'ig', #Igbo - Nigeria
  165. 1057: 'id', #Indonesian
  166. 1117: 'iu', #Inuktitut
  167. 1040: 'it', #Italian - Italy
  168. 2064: 'it', #Italian - Switzerland
  169. 1041: 'ja', #Japanese
  170. 1099: 'kn', #Kannada
  171. 1137: 'kr', #Kanuri - Nigeria
  172. 2144: 'ks', #Kashmiri
  173. 1120: 'ks', #Kashmiri (Arabic)
  174. 1087: 'kk', #Kazakh
  175. 1107: 'km', #Khmer
  176. 1111: 'kok', #Konkani
  177. 1042: 'ko', #Korean
  178. 1088: 'ky', #Kyrgyz (Cyrillic)
  179. 1108: 'lo', #Lao
  180. 1142: 'la', #Latin
  181. 1062: 'lv', #Latvian
  182. 1063: 'lt', #Lithuanian
  183. 1086: 'ms', #Malay - Malaysia
  184. 2110: 'ms', #Malay - Brunei Darussalam
  185. 1100: 'ml', #Malayalam
  186. 1082: 'mt', #Maltese
  187. 1112: 'mni', #Manipuri
  188. 1153: 'mi', #Maori - New Zealand
  189. 1102: 'mr', #Marathi
  190. 1104: 'mn', #Mongolian (Cyrillic)
  191. 2128: 'mn', #Mongolian (Mongolian)
  192. 1121: 'ne', #Nepali
  193. 2145: 'ne', #Nepali - India
  194. 1044: 'no', #Norwegian (Bokm??l)
  195. 2068: 'no', #Norwegian (Nynorsk)
  196. 1096: 'or', #Oriya
  197. 1138: 'om', #Oromo
  198. 1145: 'pap', #Papiamentu
  199. 1123: 'ps', #Pashto
  200. 1045: 'pl', #Polish
  201. 1046: 'pt', #Portuguese - Brazil
  202. 2070: 'pt', #Portuguese - Portugal
  203. 1094: 'pa', #Punjabi
  204. 2118: 'pa', #Punjabi (Pakistan)
  205. 1131: 'qu', #Quecha - Bolivia
  206. 2155: 'qu', #Quecha - Ecuador
  207. 3179: 'qu', #Quecha - Peru
  208. 1047: 'rm', #Rhaeto-Romanic
  209. 1048: 'ro', #Romanian
  210. 2072: 'ro', #Romanian - Moldava
  211. 1049: 'ru', #Russian
  212. 2073: 'ru', #Russian - Moldava
  213. 1083: 'se', #Sami (Lappish)
  214. 1103: 'sa', #Sanskrit
  215. 1132: 'nso', #Sepedi
  216. 3098: 'sr', #Serbian (Cyrillic)
  217. 2074: 'sr', #Serbian (Latin)
  218. 1113: 'sd', #Sindhi - India
  219. 2137: 'sd', #Sindhi - Pakistan
  220. 1115: 'si', #Sinhalese - Sri Lanka
  221. 1051: 'sk', #Slovak
  222. 1060: 'sl', #Slovenian
  223. 1143: 'so', #Somali
  224. 1070: 'wen', #Sorbian
  225. 3082: 'es', #Spanish - Spain (Modern Sort)
  226. 1034: 'es', #Spanish - Spain (Traditional Sort)
  227. 11274: 'es', #Spanish - Argentina
  228. 16394: 'es', #Spanish - Bolivia
  229. 13322: 'es', #Spanish - Chile
  230. 9226: 'es', #Spanish - Colombia
  231. 5130: 'es', #Spanish - Costa Rica
  232. 7178: 'es', #Spanish - Dominican Republic
  233. 12298: 'es', #Spanish - Ecuador
  234. 17418: 'es', #Spanish - El Salvador
  235. 4106: 'es', #Spanish - Guatemala
  236. 18442: 'es', #Spanish - Honduras
  237. 58378: 'es', #Spanish - Latin America
  238. 2058: 'es', #Spanish - Mexico
  239. 19466: 'es', #Spanish - Nicaragua
  240. 6154: 'es', #Spanish - Panama
  241. 15370: 'es', #Spanish - Paraguay
  242. 10250: 'es', #Spanish - Peru
  243. 20490: 'es', #Spanish - Puerto Rico
  244. 21514: 'es', #Spanish - United States
  245. 14346: 'es', #Spanish - Uruguay
  246. 8202: 'es', #Spanish - Venezuela
  247. 1072: None, #TODO: Sutu
  248. 1089: 'sw', #Swahili
  249. 1053: 'sv', #Swedish
  250. 2077: 'sv', #Swedish - Finland
  251. 1114: 'syr', #Syriac
  252. 1064: 'tg', #Tajik
  253. 1119: None, #TODO: Tamazight (Arabic)
  254. 2143: None, #TODO: Tamazight (Latin)
  255. 1097: 'ta', #Tamil
  256. 1092: 'tt', #Tatar
  257. 1098: 'te', #Telugu
  258. 1054: 'th', #Thai
  259. 2129: 'bo', #Tibetan - Bhutan
  260. 1105: 'bo', #Tibetan - People's Republic of China
  261. 2163: 'ti', #Tigrigna - Eritrea
  262. 1139: 'ti', #Tigrigna - Ethiopia
  263. 1073: 'ts', #Tsonga
  264. 1074: 'tn', #Tswana
  265. 1055: 'tr', #Turkish
  266. 1090: 'tk', #Turkmen
  267. 1152: 'ug', #Uighur - China
  268. 1058: 'uk', #Ukrainian
  269. 1056: 'ur', #Urdu
  270. 2080: 'ur', #Urdu - India
  271. 2115: 'uz', #Uzbek (Cyrillic)
  272. 1091: 'uz', #Uzbek (Latin)
  273. 1075: 've', #Venda
  274. 1066: 'vi', #Vietnamese
  275. 1106: 'cy', #Welsh
  276. 1076: 'xh', #Xhosa
  277. 1144: 'ii', #Yi
  278. 1085: 'yi', #Yiddish
  279. 1130: 'yo', #Yoruba
  280. 1077: 'zu'} #Zulu
  281. return mapping[lcid]
  282. def _getscreenlanguage():
  283. global language_code
  284. '''
  285. :returns: the ISO 639-x language code for this session.
  286. If the LANGUAGE environment variable is set, it's value overrides the
  287. screen language detection. Otherwise the screen language is determined by
  288. the currently selected Microsoft Windows MUI language pack or the Microsoft
  289. Windows installation language.
  290. Works on Microsoft Windows 2000 and up.
  291. '''
  292. if sys.platform == 'win32' or sys.platform == 'nt':
  293. # Start with nothing
  294. lang = None
  295. # Check the LANGUAGE environment variable
  296. lang = os.getenv('LANGUAGE')
  297. if language_code != "" :
  298. lang = language_code
  299. if lang is None:
  300. # Start with nothing
  301. lcid = None
  302. try:
  303. from ctypes import windll
  304. lcid = windll.kernel32.GetUserDefaultUILanguage()
  305. except:
  306. logger.debug('Failed to get current screen language with \'GetUserDefaultUILanguage\'')
  307. finally:
  308. if lcid is None:
  309. lang = 'C'
  310. else:
  311. lang = _isofromlcid(lcid)
  312. logger.debug('Windows screen language is \'%s\' (lcid %s)' % (lang, lcid))
  313. return lang
  314. def _putenv(name, value):
  315. '''
  316. :param name: environment variable name
  317. :param value: environment variable value
  318. This function ensures that changes to an environment variable are applied
  319. to each copy of the environment variables used by a process. Starting from
  320. Python 2.4, os.environ changes only apply to the copy Python keeps (os.environ)
  321. and are no longer automatically applied to the other copies for the process.
  322. On Microsoft Windows, each process has multiple copies of the environment
  323. variables, one managed by the OS and one managed by the C library. We also
  324. need to take care of the fact that the C library used by Python is not
  325. necessarily the same as the C library used by pygtk and friends. This because
  326. the latest releases of pygtk and friends are built with mingw32 and are thus
  327. linked against msvcrt.dll. The official gtk+ binaries have always been built
  328. in this way.
  329. '''
  330. if sys.platform == 'win32' or sys.platform == 'nt':
  331. from ctypes import windll
  332. from ctypes import cdll
  333. from ctypes.util import find_msvcrt
  334. # Update Python's copy of the environment variables
  335. os.environ[name] = value
  336. # Update the copy maintained by Windows (so SysInternals Process Explorer sees it)
  337. try:
  338. result = windll.kernel32.SetEnvironmentVariableW(name, value)
  339. if result == 0: raise Warning
  340. except Exception:
  341. logger.debug('Failed to set environment variable \'%s\' (\'kernel32.SetEnvironmentVariableW\')' % name)
  342. else:
  343. logger.debug('Set environment variable \'%s\' to \'%s\' (\'kernel32.SetEnvironmentVariableW\')' % (name, value))
  344. # Update the copy maintained by msvcrt (used by gtk+ runtime)
  345. try:
  346. result = cdll.msvcrt._putenv('%s=%s' % (name, value))
  347. if result !=0: raise Warning
  348. except Exception:
  349. logger.debug('Failed to set environment variable \'%s\' (\'msvcrt._putenv\')' % name)
  350. else:
  351. logger.debug('Set environment variable \'%s\' to \'%s\' (\'msvcrt._putenv\')' % (name, value))
  352. # Update the copy maintained by whatever c runtime is used by Python
  353. try:
  354. msvcrt = find_msvcrt()
  355. msvcrtname = str(msvcrt).split('.')[0] if '.' in msvcrt else str(msvcrt)
  356. result = cdll.LoadLibrary(msvcrt)._putenv('%s=%s' % (name, value))
  357. if result != 0: raise Warning
  358. except Exception:
  359. logger.debug('Failed to set environment variable \'%s\' (\'%s._putenv\')' % (name, msvcrtname))
  360. else:
  361. logger.debug('Set environment variable \'%s\' to \'%s\' (\'%s._putenv\')' % (name, value, msvcrtname))
  362. def _dugettext(domain, message):
  363. '''
  364. :param domain: translation domain
  365. :param message: message to translate
  366. :returns: the translated message
  367. Unicode version of :func:`gettext.dgettext`.
  368. '''
  369. try:
  370. t = gettext.translation(domain, gettext._localedirs.get(domain, None),
  371. codeset=gettext._localecodesets.get(domain))
  372. except IOError:
  373. return message
  374. else:
  375. return t.ugettext(message)
  376. def _install(domain, localedir, asglobal=False):
  377. '''
  378. :param domain: translation domain
  379. :param localedir: locale directory
  380. :param asglobal: if True, installs the function _() in Pythons builtin namespace. Default is False
  381. Private function doing all the work for the :func:`elib.intl.install` and
  382. :func:`elib.intl.install_module` functions.
  383. '''
  384. # prep locale system
  385. if asglobal:
  386. locale.setlocale(locale.LC_ALL, '')
  387. # on windows systems, set the LANGUAGE environment variable
  388. if sys.platform == 'win32' or sys.platform == 'nt':
  389. _putenv('LANGUAGE', _getscreenlanguage())
  390. #print "=========2>", os.getenv('LANGUAGE')
  391. #print ("=========2>",_getscreenlanguage())
  392. # The locale module on Max OS X lacks bindtextdomain so we specifically
  393. # test on linux2 here. See commit 4ae8b26fd569382ab66a9e844daa0e01de409ceb
  394. if sys.platform == 'linux2':
  395. locale.bindtextdomain(domain, localedir)
  396. locale.bind_textdomain_codeset(domain, 'UTF-8')
  397. locale.textdomain(domain)
  398. # initialize Python's gettext interface
  399. gettext.bindtextdomain(domain, localedir)
  400. gettext.bind_textdomain_codeset(domain, 'UTF-8')
  401. if asglobal:
  402. gettext.textdomain(domain)
  403. # on windows systems, initialize libintl
  404. domain = domain.encode("cp1252")
  405. localedir = localedir.encode("cp1252")
  406. if sys.platform == 'win32' or sys.platform == 'nt':
  407. from ctypes import cdll
  408. libintl = cdll.LoadLibrary("libintl-8.dll")
  409. libintl.bindtextdomain(domain, localedir)
  410. libintl.bind_textdomain_codeset(domain, 'UTF-8')
  411. if asglobal:
  412. libintl.textdomain(domain)
  413. del libintl
  414. def install(domain, localedir, code = ""):
  415. '''
  416. :param domain: translation domain
  417. :param localedir: locale directory
  418. :param code: Language code required. Default means autodetect.
  419. Installs the function _() in Pythons builtin namespace, based on
  420. domain and localedir. Codeset is always UTF-8.
  421. As seen below, you usually mark the strings in your application that are
  422. candidates for translation, by wrapping them in a call to the _() function,
  423. like this:
  424. .. sourcecode:: python
  425. import elib.intl
  426. elib.intl.install('myapplication', '/path/to/usr/share/locale')
  427. print _('This string will be translated.')
  428. Note that this is only one way, albeit the most convenient way,
  429. to make the _() function available to your application. Because it affects
  430. the entire application globally, and specifically Pythons built-in
  431. namespace, localized modules should never install _(). Instead, you should
  432. use :func:`elib.intl.install_module` to make _() available to your module.
  433. '''
  434. global language_code
  435. language_code = code
  436. _install(domain, localedir, True)
  437. gettext.install(domain, localedir)
  438. def install_module(domain, localedir):
  439. '''
  440. :param domain: translation domain
  441. :param localedir: locale directory
  442. :returns: an anonymous function object, based on domain and localedir.
  443. Codeset is always UTF-8.
  444. You may find this function usefull when writing localized modules.
  445. Use this code to make _() available to your module:
  446. .. sourcecode:: python
  447. import elib.intl
  448. _ = elib.intl.install_module('mymodule', '/path/to/usr/share/locale')
  449. print _('This string will be translated.')
  450. When writing a package, you can usually do this in the package's __init__.py
  451. file and import the _() function from the package namespace as needed.
  452. '''
  453. _install(domain, localedir, False)
  454. return lambda message: _dugettext(domain, message)
  455. def main() :
  456. language = ""
  457. if sys.platform == 'win32' or sys.platform == 'nt':
  458. install("pdfbooklet", "share/locale", language)
  459. print (_getscreenlanguage())
  460. else :
  461. install("pdfbooklet", "/usr/share/locale", language)
  462. print (_("There is no selection"))
  463. if __name__ == '__main__' :
  464. main()