2019-06-06 11:52:23 -05:00
|
|
|
from __future__ import unicode_literals
|
|
|
|
from future import standard_library
|
|
|
|
standard_library.install_aliases()
|
|
|
|
from builtins import zip
|
|
|
|
from builtins import str
|
|
|
|
import builtins
|
2014-10-27 16:29:04 -06:00
|
|
|
import os
|
|
|
|
import sys
|
|
|
|
import ctypes
|
|
|
|
import locale
|
|
|
|
import gettext
|
|
|
|
import paths
|
|
|
|
import platform
|
2019-06-06 11:52:23 -05:00
|
|
|
import application
|
2021-06-16 16:18:41 -05:00
|
|
|
|
2014-10-27 16:29:04 -06:00
|
|
|
#a few Windows locale constants
|
|
|
|
LOCALE_SLANGUAGE=0x2
|
|
|
|
LOCALE_SLANGDISPLAYNAME=0x6f
|
|
|
|
|
|
|
|
curLang="en"
|
|
|
|
|
|
|
|
def localeNameToWindowsLCID(localeName):
|
2021-06-16 16:18:41 -05:00
|
|
|
"""Retreave the Windows locale identifier (LCID) for the given locale name
|
|
|
|
@param localeName: a string of 2letterLanguage_2letterCountry or or just 2letterLanguage
|
|
|
|
@type localeName: string
|
|
|
|
@returns: a Windows LCID
|
|
|
|
@rtype: integer
|
|
|
|
"""
|
|
|
|
#Windows Vista is able to convert locale names to LCIDs
|
|
|
|
func_LocaleNameToLCID=getattr(ctypes.windll.kernel32,'LocaleNameToLCID',None)
|
|
|
|
if func_LocaleNameToLCID is not None:
|
|
|
|
localeName=localeName.replace('_','-')
|
|
|
|
LCID=func_LocaleNameToLCID(str(localeName),0)
|
|
|
|
else: #Windows doesn't have this functionality, manually search Python's windows_locale dictionary for the LCID
|
|
|
|
localeName=locale.normalize(localeName)
|
|
|
|
if '.' in localeName:
|
|
|
|
localeName=localeName.split('.')[0]
|
|
|
|
LCList=[x[0] for x in locale.windows_locale.items() if x[1]==localeName]
|
|
|
|
if len(LCList)>0:
|
|
|
|
LCID=LCList[0]
|
|
|
|
else:
|
|
|
|
LCID=0
|
|
|
|
return LCID
|
2014-10-27 16:29:04 -06:00
|
|
|
|
|
|
|
def getLanguageDescription(language):
|
2021-06-16 16:18:41 -05:00
|
|
|
"""Finds out the description (localized full name) of a given local name"""
|
|
|
|
desc=None
|
|
|
|
if platform.system() == "Windows":
|
|
|
|
LCID=localeNameToWindowsLCID(language)
|
|
|
|
if LCID!=0:
|
|
|
|
buf=ctypes.create_unicode_buffer(1024)
|
|
|
|
if '_' not in language:
|
|
|
|
res=ctypes.windll.kernel32.GetLocaleInfoW(LCID,LOCALE_SLANGDISPLAYNAME,buf,1024)
|
|
|
|
else:
|
|
|
|
res=0
|
|
|
|
if res==0:
|
|
|
|
res=ctypes.windll.kernel32.GetLocaleInfoW(LCID,LOCALE_SLANGUAGE,buf,1024)
|
|
|
|
desc=buf.value
|
|
|
|
elif platform.system() == "Linux" or not desc:
|
|
|
|
desc={
|
|
|
|
"am":pgettext("languageName","Amharic"),
|
|
|
|
"an":pgettext("languageName","Aragonese"),
|
|
|
|
"es":pgettext("languageName","Spanish"),
|
|
|
|
"pt":pgettext("languageName","Portuguese"),
|
|
|
|
"ru":pgettext("languageName","Russian"),
|
|
|
|
"it":pgettext("languageName","italian"),
|
|
|
|
"tr":pgettext("languageName","Turkey"),
|
|
|
|
"gl":pgettext("languageName","Galician"),
|
|
|
|
"ca":pgettext("languageName","Catala"),
|
|
|
|
"eu":pgettext("languageName","Vasque"),
|
|
|
|
"pl":pgettext("languageName","polish"),
|
|
|
|
"ar":pgettext("languageName","Arabic"),
|
|
|
|
"ne":pgettext("languageName","Nepali"),
|
|
|
|
"sr":pgettext("languageName","Serbian (Latin)"),
|
|
|
|
"ja":pgettext("languageName","Japanese"),
|
|
|
|
}.get(language,None)
|
|
|
|
return desc
|
2014-10-27 16:29:04 -06:00
|
|
|
|
|
|
|
def getAvailableLanguages():
|
2021-06-16 16:18:41 -05:00
|
|
|
"""generates a list of locale names, plus their full localized language and country names.
|
|
|
|
@rtype: list of tuples
|
|
|
|
"""
|
|
|
|
#Make a list of all the locales found in NVDA's locale dir
|
|
|
|
l=[x for x in os.listdir(paths.locale_path()) if not x.startswith('.')]
|
|
|
|
l=[x for x in l if os.path.isfile(os.path.join(paths.locale_path(), '%s/LC_MESSAGES/%s.po' % (x, application.short_name)))]
|
|
|
|
#Make sure that en (english) is in the list as it may not have any locale files, but is default
|
|
|
|
if 'en' not in l:
|
|
|
|
l.append('en')
|
|
|
|
l.sort()
|
|
|
|
#For each locale, ask Windows for its human readable display name
|
|
|
|
d=[]
|
|
|
|
for i in l:
|
|
|
|
desc=getLanguageDescription(i)
|
|
|
|
label="%s, %s"%(desc,i) if desc else i
|
|
|
|
d.append(label)
|
|
|
|
#include a 'user default, windows' language, which just represents the default language for this user account
|
|
|
|
l.append("system")
|
|
|
|
# Translators: the label for the Windows default NVDA interface language.
|
|
|
|
d.append(_("User default"))
|
|
|
|
#return a zipped up version of both the lists (a list with tuples of locale,label)
|
|
|
|
return list(zip(l,d))
|
2014-10-27 16:29:04 -06:00
|
|
|
|
|
|
|
def makePgettext(translations):
|
2021-06-16 16:18:41 -05:00
|
|
|
"""Obtaina pgettext function for use with a gettext translations instance.
|
|
|
|
pgettext is used to support message contexts,
|
|
|
|
but Python 2.7's gettext module doesn't support this,
|
|
|
|
so NVDA must provide its own implementation.
|
|
|
|
"""
|
|
|
|
if isinstance(translations, gettext.GNUTranslations):
|
|
|
|
def pgettext(context, message):
|
|
|
|
message = str(message)
|
|
|
|
try:
|
|
|
|
# Look up the message with its context.
|
|
|
|
return translations._catalog["%s\x04%s" % (context, message)]
|
|
|
|
except KeyError:
|
|
|
|
return message
|
|
|
|
else:
|
|
|
|
def pgettext(context, message):
|
|
|
|
return str(message)
|
|
|
|
return pgettext
|
2014-10-27 16:29:04 -06:00
|
|
|
|
|
|
|
def setLanguage(lang):
|
2021-06-16 16:18:41 -05:00
|
|
|
system = platform.system()
|
|
|
|
global curLang
|
|
|
|
try:
|
|
|
|
if lang=="system":
|
|
|
|
if system == "Windows":
|
|
|
|
windowsLCID=ctypes.windll.kernel32.GetUserDefaultUILanguage()
|
|
|
|
localeName=locale.windows_locale[windowsLCID]
|
|
|
|
elif system == "Darwin":
|
|
|
|
import Foundation
|
|
|
|
localeName = Foundation.NSLocale.currentLocale().identifier()
|
|
|
|
elif system == "Linux":
|
|
|
|
localeName = locale.getdefaultlocale()[0]
|
|
|
|
trans=gettext.translation(application.short_name, localedir=paths.locale_path(), languages=[localeName])
|
|
|
|
curLang=localeName
|
2015-04-22 15:34:44 -05:00
|
|
|
# else:
|
|
|
|
# localeName=locale.getdefaultlocale()[0]
|
2015-01-05 06:05:31 -06:00
|
|
|
# trans=gettext.translation('twblue', localedir=paths.locale_path(), languages=[localeName])
|
|
|
|
# curLang=localeName
|
2014-10-27 16:29:04 -06:00
|
|
|
|
2021-06-16 16:18:41 -05:00
|
|
|
else:
|
|
|
|
trans=gettext.translation(application.short_name, localedir=paths.locale_path(), languages=[lang])
|
|
|
|
curLang=lang
|
|
|
|
localeChanged=False
|
|
|
|
#Try setting Python's locale to lang
|
2015-01-05 06:05:31 -06:00
|
|
|
# try:
|
2021-06-16 16:18:41 -05:00
|
|
|
if system == "Windows":
|
|
|
|
locale.setlocale(locale.LC_ALL, langToWindowsLocale(lang))
|
|
|
|
localeChanged=True
|
|
|
|
else:
|
|
|
|
locale.setlocale(locale.LC_ALL, lang)
|
|
|
|
localeChanged=True
|
2015-01-05 06:05:31 -06:00
|
|
|
# except:
|
|
|
|
# pass
|
2021-06-16 16:18:41 -05:00
|
|
|
if not localeChanged and '_' in lang:
|
|
|
|
#Python couldn'tsupport the language_country locale, just try language.
|
|
|
|
try:
|
|
|
|
locale.setlocale(locale.LC_ALL, lang.split('_')[0])
|
|
|
|
except:
|
|
|
|
pass
|
|
|
|
#Set the windows locale for this thread (NVDA core) to this locale.
|
|
|
|
if system == "Windows":
|
|
|
|
LCID=localeNameToWindowsLCID(lang)
|
|
|
|
ctypes.windll.kernel32.SetThreadLocale(LCID)
|
|
|
|
except IOError:
|
|
|
|
trans=gettext.translation(application.short_name, fallback=True)
|
|
|
|
curLang="en"
|
|
|
|
if sys.version[0] == "3":
|
|
|
|
trans.install()
|
|
|
|
else:
|
|
|
|
trans.install(unicode=True)
|
|
|
|
# Install our pgettext function.
|
2015-01-05 06:05:31 -06:00
|
|
|
# __builtin__.__dict__["pgettext"] = makePgettext(trans)
|
2014-10-27 16:29:04 -06:00
|
|
|
|
|
|
|
def getLanguage():
|
2021-06-16 16:18:41 -05:00
|
|
|
return curLang
|
2014-10-27 16:29:04 -06:00
|
|
|
|
|
|
|
def normalizeLanguage(lang):
|
2021-06-16 16:18:41 -05:00
|
|
|
"""
|
|
|
|
Normalizes a language-dialect string in to a standard form we can deal with.
|
|
|
|
Converts any dash to underline, and makes sure that language is lowercase and dialect is upercase.
|
|
|
|
"""
|
|
|
|
lang=lang.replace('-','_')
|
|
|
|
ld=lang.split('_')
|
|
|
|
ld[0]=ld[0].lower()
|
|
|
|
#Filter out meta languages such as x-western
|
|
|
|
if ld[0]=='x':
|
|
|
|
return None
|
|
|
|
if len(ld)>=2:
|
|
|
|
ld[1]=ld[1].upper()
|
|
|
|
return "_".join(ld)
|
2014-10-27 16:29:04 -06:00
|
|
|
|
2015-01-05 06:05:31 -06:00
|
|
|
def langToWindowsLocale(lang):
|
2021-06-16 16:18:41 -05:00
|
|
|
languages = {"en": "eng",
|
|
|
|
"ar": "ara",
|
|
|
|
"ca": "cat",
|
|
|
|
"de": "deu",
|
|
|
|
"es": "esp",
|
|
|
|
"fi": "fin",
|
|
|
|
"fr": "fre_FRA",
|
|
|
|
"gl": "glc",
|
|
|
|
"eu": "euq",
|
|
|
|
"hu": "hun",
|
|
|
|
"hr": "hrv",
|
|
|
|
"it": "ita",
|
|
|
|
"ja": "jpn",
|
|
|
|
"pl": "plk",
|
|
|
|
"pt": "ptb",
|
|
|
|
"ru": "rus",
|
|
|
|
"tr": "trk",
|
|
|
|
"sr": "eng",
|
|
|
|
}
|
|
|
|
return languages[lang]
|